Skip to main content

HTTP client for interacting with FLAME Hub services.

Project description

This repository contains the source code for a Python client which wraps the endpoints of the FLAME Hub API.

Installation

python -m pip install flame_hub_client

Example usage

The FLAME Hub Python Client offers functions for the Core, Storage and Auth Hub endpoints. It is capable of authenticating against the API using the two main flows: password and robot authentication. Pick one, provide your credentials and plug them into the class for the service you want to use.

import flame_hub

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
auth_client = flame_hub.AuthClient(base_url="http://localhost:3000/auth/", auth=auth)

Now you're ready to use the library's functions. The client will automatically reauthenticate if necessary.

The library offers "get" and "find" functions for most resources. Functions prefixed with "get" will return a list of the first 50 matching resources. If you want tighter control over your results, use the "find" functions and provide optional pagination and filter arguments.

import flame_hub

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
auth_client = flame_hub.AuthClient(base_url="http://localhost:3000/auth/", auth=auth)

# To get the master realm, you could call auth_client.get_realms() and hope that it's among the first
# 50 realms. But you could use auth_client.find_realms() instead and include specific search criteria.
master_realms = auth_client.find_realms(filter={"name": "master"})

# This check should pass since there's always a single master realm.
assert len(master_realms) == 1

master_realm = master_realms.pop()
print(master_realm.id)
# => 2fdb6035-87d1-4abb-a4b1-941be2d06137

Creation, update and deletion is available for most resources. Always check which functions are available.

import flame_hub

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)

# This is the ID from the previous snippet.
master_realm_id = "2fdb6035-87d1-4abb-a4b1-941be2d06137"

# Now we're going to create a Node. This function requires a name and the ID of the realm to assign the node to.
my_node = core_client.create_node(name="my-node", realm_id=master_realm_id)

# The resulting objects are Pydantic models, so we can use them as we please.
print(my_node.model_dump_json(indent=2))
# => {
# =>   "external_name": null,
# =>   "hidden": false,
# =>   "name": "my-node",
# =>   "realm_id": "2fdb6035-87d1-4abb-a4b1-941be2d06137",
# =>   "registry_id": null,
# =>   "type": "default",
# =>   "id": "15b00353-f5b3-47a1-91a5-6df225cd00cc",
# =>   "public_key": null,
# =>   "online": false,
# =>   "registry_project_id": null,
# =>   "robot_id": "cb8a7277-4a7e-4b07-8e88-2d2017c3ec8c",
# =>   "created_at": "2025-02-27T14:09:48.034000Z",
# =>   "updated_at": "2025-02-27T14:09:48.034000Z"
# => }

# Maybe making the Node public wasn't such a good idea, so let's update it by hiding it.
core_client.update_node(my_node, hidden=True)

# Retrieving the Node by its ID should now show that it's hidden.
print(core_client.get_node(my_node.id).hidden)
# => True

# Attempting to fetch a Node that doesn't exist will simply return None.
print(core_client.get_node("497dcba3-ecbf-4587-a2dd-5eb0665e6880"))
# => None

# That was fun! Let's delete the Node.
core_client.delete_node(my_node)

# ...and just to make sure that it's gone!
print(core_client.get_node(my_node.id))
# => None

Module contents

Module flame_hub

The flame_hub module is the main module. It contains the AuthClient, CoreClient classes and StorageClient which can be used to access the endpoints of the Hub auth, core and storage APIs respectively. The signature of the class constructors is always the same and takes three optional arguments.

Argument Type Description
auth httpx.Auth (Optional) Instance of subclass of httpx.Auth.
base_url str (Optional) Base URL of the Hub service.
client httpx.Client (Optional) Instance of httpx.Client to use for requests. Overrides base_url and auth.

There are some things to keep in mind regarding these arguments.

  • You should provide an instance of either flame_hub.auth.PasswordAuth or flame_hub.auth.RobotAuth to auth as these are the two main authentication schemes supported by the FLAME Hub.
  • You can provide a custom base_url if you're hosting your own instance of the FLAME Hub, otherwise the client will use the default publicly available Hub instance to connect to.
  • You shouldn't set client explicitly unless you know what you're doing. When providing any of the previous two arguments, a suitable client instance will be generated automatically.

Finding resources

All clients offer functions for creating, reading, updating and deleting resources managed by the FLAME Hub. To find multiple resources matching certain criteria, the find_* functions support optional pagination, filtering and sorting parameters. In almost all scenarios, you will want to use find_* over get_* functions.

import flame_hub

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)

# core.find_nodes(page={"limit": 50, "offset": 0}) and core.get_nodes() are functionally equivalent.
nodes_lst_find = core_client.find_nodes(page={"limit": 50, "offset": 0})
nodes_lst_get = core_client.get_nodes()

print(nodes_lst_find == nodes_lst_get)
# => True

The page parameter enables control over the amount of returned results. You can define the limit and offset which affects pagination. Both default to 50 and zero respectively if unset.

import flame_hub

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)

# nodes_next_10 is a subset of the results in nodes_first_25.
nodes_first_25 = core_client.find_nodes(page={"limit": 25})
nodes_next_10 = core_client.find_nodes(page={"limit": 10, "offset": 10})

print(nodes_first_25[10:20] == nodes_next_10)
# => True

The filter parameter allows you to filter by any fields. You can perform exact matching, but also any other operation supported by the FLAME Hub, including "like" and "not" queries and numeric "greater than" and "less than" comparisons.

import flame_hub

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)

# Search using strict equals.
print(core_client.find_nodes(filter={"name": "my-node-42"}).pop().model_dump(mode="json"))
# => {
# =>   "name": "my-node-42",
# =>   "id": "2f8fc7df-d5ff-484c-bfed-76b8f3c43afd",
# =>   ... shortened for brevity ...
# => }

# These two functions return the same result. One is a bit more verbose than the other.
nodes_with_4_in_name = core_client.find_nodes(filter={"name": "~my-node-4"})
nodes_with_4_in_name_but_different = core_client.find_nodes(filter={"name": (flame_hub.types.FilterOperator.like, "my-node-4")})

print(nodes_with_4_in_name == nodes_with_4_in_name_but_different)
# => True

The sort parameter allows you to define a field to sort by in either ascending or descending order. If order is left unset, the client will sort in ascending order by default.

import flame_hub

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)

nodes = core_client.find_nodes(sort={"by": "created_at"})  # Ascending order is applied by default.
sedon = core_client.find_nodes(sort={"by": "created_at", "order": "descending"})

# Reversing the second list will equal the first list.
print(nodes == sedon[::-1])
# => True

Handling exceptions

The main module exports HubAPIError which is a general error that is raised whenever the FLAME Hub responds with an unexpected status code. All clients will try and put as much information into the raised error as possible, including status code and additional information in the response body.

import flame_hub
import uuid

auth = flame_hub.auth.PasswordAuth(username="admin", password="start123", base_url="http://localhost:3000/auth/")
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)

try:
    # Let's try guessing the ID of the realm.
    core_client.create_node(name="my-new-node", realm_id=f"{uuid.uuid4()}")
except flame_hub.HubAPIError as e:
    # Whoops!
    print(e)
    # => received status code 400 (undefined): Can't find realm entity by realm_id

    # If the response body contains an error, it can be accessed with the error_response property.
    # Some errors may also add additional fields which can also be accessed like this.
    print(e.error_response.model_dump_json(indent=2))  
    # => {
    # =>   "status_code": 400,
    # =>   "code": "undefined",
    # =>   "message": "Can't find realm entity by realm_id"
    # => }

Module flame_hub.auth

The flame_hub.auth module contains implementations of httpx.Auth supporting the password and robot authentication flows that are recognized by the FLAME Hub. These are meant for use with the clients provided by this package.

Class flame_hub.auth.PasswordAuth

Argument Type Description
username str Username to authenticate with.
password str Password to authenticate with.
base_url str (Optional) Base URL of the Hub Auth service.
client httpx.Client (Optional) Instance of httpx.Client to use for requests. Overrides base_url.

Class flame_hub.auth.RobotAuth

Argument Type Description
robot_id str ID of robot account to authenticate with.
robot_secret str Secret of robot account to authenticate with.
base_url str (Optional) Base URL of the Hub Auth service.
client httpx.Client (Optional) Instance of httpx.Client to use for requests. Overrides base_url.

Module flame_hub.types

The flame_hub.types module contains type annotations that you might find useful when writing your own code. At this time, it only contains annotations for optional keyword parameters for find_* functions.

Running tests

Tests require access to a FLAME Hub instance. There are two ways of accomplishing this: by using testcontainers or by deploying your own instance.

Using testcontainers

Running pytest will spin up all necessary testcontainers. This process can take about a minute. The obvious downsides are that this process takes up significant computational resources and that this is necessary every time you want to run tests. On the other hand, you can rest assured that all tests are always run against a fresh Hub instance. For quick development, it is highly recommended to set up your own Hub instance instead.

Deploying your own Hub instance

Grab the Docker Compose file from the Hub repository and store it somewhere warm and comfy. For the core, messenger, analysis-manager, storage and ui services, remove the build property and replace it with image: ghcr.io/privateaim/hub:0.8.5. Now you can run docker compose up -d and, after a few minutes, you will be able to access the UI at http://localhost:3000.

In order for pytest to pick up on the locally deployed instance, run cp .env.test .env and modify the .env file such that PYTEST_USE_TESTCONTAINERS=0. This will skip the creation of all testcontainers and make test setup much faster.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flame_hub_client-0.1.0.tar.gz (20.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flame_hub_client-0.1.0-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file flame_hub_client-0.1.0.tar.gz.

File metadata

  • Download URL: flame_hub_client-0.1.0.tar.gz
  • Upload date:
  • Size: 20.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.0 CPython/3.12.3 Linux/6.8.0-1021-azure

File hashes

Hashes for flame_hub_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bd86d8621c37d228f22ccc35011119d1b09db1a7ac9d2f3fdbee404d32acb35d
MD5 03dc9c4bdde580c2afb421077de969c9
BLAKE2b-256 5f727c717c5b2006a7e7931c8b36209791c34f188ab11267637ccfda3bc4a26d

See more details on using hashes here.

File details

Details for the file flame_hub_client-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: flame_hub_client-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.0 CPython/3.12.3 Linux/6.8.0-1021-azure

File hashes

Hashes for flame_hub_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5fa6bf5a140aa173d04038c47253e590e6833be9bb0daa35e36765ce09caae9b
MD5 a20539a81c01a10c33049f7a4d5ca8a0
BLAKE2b-256 612678a40a9bf1f22c172e8fc238e2cd9d1b4e8c5ac923d258d405a28550d79d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page