# HIRO Graph API Client
This is a client library to access data of the [HIRO Graph](#graph-client-hirograph).
This library also contains classes for handling the [WebSockets](#websockets) `event-ws` and `action-ws` API.
To process large batches of data, take a look at "hiro-batch-client". - (
PyPI: [hiro-batch-client](https://pypi.org/project/hiro-batch-client/),
GitHub: [hiro-batch-client-python](https://github.com/arago/hiro-batch-client-python))
For more information about HIRO Automation, look at https://www.almato.com/de/loesungen/hiro-ai.
For more information about the APIs this library covers, see https://dev-portal.engine.datagroup.de/7.0/.
Currently, implemented are
* `HiroApp` for `app`
* `HiroAuth` for `auth`
* `HiroGraph` for `graph`
* `HiroIam` for `iam`
* `HiroKi` for `ki`
* `HiroAuthz` for `authz`
* `HiroVariables` for `variables`
and for the websockets
* `AbstractEventWebSocketHandler` for `event-ws`
* `AbstractActionWebSocketHandler` for `action-ws`
## Quickstart
To use this library, you will need an account at https://desktop.engine.datagroup.de/ and access to an OAuth Client-Id and Client-Secret
to access the HIRO Graph. See also https://dev-portal.engine.datagroup.de/7.0/.
Most of the documentation is done in the sourcecode.
### HiroGraph Example
Example to use the straightforward graph api client:
```python
from hiro_graph_client import PasswordAuthTokenApiHandler, HiroGraph
hiro_client: HiroGraph = HiroGraph(
api_handler=PasswordAuthTokenApiHandler(
root_url="https://core.engine.datagroup.de",
username='',
password='',
client_id='',
client_secret=''
)
)
# The commands of the Graph API are methods of the class HIROGraph.
# The next line executes a vertex query for instance.
query_result = hiro_client.query('ogit\\/_type:"ogit/MARS/Machine"')
print(query_result)
```
## TokenApiHandler
Authorization against the HIRO Graph is done via tokens. These tokens are handled by classes of
type `AbstractTokenApiHandler` in this library. Each of the Hiro-Client-Object (`HiroGraph`, , `HiroApp`, etc.) need to
have some kind of TokenApiHandler at construction.
This TokenApiHandler is also responsible to determine the most up-to-date endpoints for the API calls. You can supply a
custom list of endpoints by using the dict parameter `custom_endpoints=` on construction.
A custom list of headers can also be set via the dict parameter `headers=` in the constructor. These would update the
internal headers. Header names can be supplied in any upper/lower-case.
This library supplies the following TokenApiHandlers:
---
### FixedTokenApiHandler
A simple TokenApiHandler that is generated with a preset-token at construction. Cannot update its token.
---
### EnvironmentTokenApiHandler
A TokenApiHandler that reads an environment variable (default is `HIRO_TOKEN`) from the runtime environment. Will only
update its token when the environment variable changes externally.
---
### PasswordAuthTokenApiHandler
This TokenApiHandler logs into the HiroAuth backend and obtains a token from login credentials. This is also the only
TokenApiHandler (so far) that automatically tries to renew a token from the backend when it has expired.
---
All code examples in this documentation can use these TokenApiHandlers interchangeably, depending on how such a token is
provided.
The HiroGraph example from above with another customized TokenApiHandler:
```python
from hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph
hiro_client: HiroGraph = HiroGraph(
api_handler=EnvironmentTokenApiHandler(
root_url="https://core.engine.datagroup.de"
)
)
# The commands of the Graph API are methods of the class HIROGraph.
# The next line executes a vertex query for instance.
query_result = hiro_client.query('ogit\\/_type:"ogit/MARS/Machine"')
print(query_result)
```
Example with additional parameters:
```python
from hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph
hiro_client: HiroGraph = HiroGraph(
api_handler=EnvironmentTokenApiHandler(
root_url="https://core.engine.datagroup.de",
env_var='_TOKEN',
headers={
'X-Custom-Header': 'My custom value'
},
custom_endpoints={
"graph": "/api/graph/7.2",
"auth": "/api/auth/6.2"
},
client_name="HiroGraph (testing)" # Will be used in the header 'User-Agent'
)
)
# The commands of the Graph API are methods of the class HIROGraph.
# The next line executes a vertex query for instance.
query_result = hiro_client.query('ogit\\/_type:"ogit/MARS/Machine"')
print(query_result)
```
## Token Handler sharing
When you need to access multiple APIs of HIRO, share the TokenApiHandler between the API objects to avoid unnecessary
requests for token- and version-information against HIRO. The TokenApiHandler will share a `requests.Session`, token-
and version-request-handling, and the token string itself between them.
```python
from hiro_graph_client import HiroGraph, HiroApp, PasswordAuthTokenApiHandler
hiro_api_handler = PasswordAuthTokenApiHandler(
root_url="https://core.engine.datagroup.de",
username='',
password='',
client_id='',
client_secret=''
)
hiro_client: HiroGraph = HiroGraph(
api_handler=hiro_api_handler
)
hiro_app_client: HiroApp = HiroApp(
api_handler=hiro_api_handler
)
```
## Connection sharing
You can also let TokenApiHandlers share a common connection session instead of letting each of them create their own.
This might prove useful in a multithreading environment where tokens have to be set externally or change often (i.e.
one token per user per thread). This also ensures, that version-requests happen only once when the connection is
initialized.
Use the parameters `pool_maxsize` and `pool_block` to further tune the connection parameters for parallel access to
the backend. See [requests Session Objects](https://docs.python-requests.org/en/latest/user/advanced/#session-objects)
and the Python documentation of `requests.adapters.HTTPAdapter` and `GraphConnectionHandler`.
```python
from hiro_graph_client import HiroGraph, HiroApp, FixedTokenApiHandler, GraphConnectionHandler
connection_handler = GraphConnectionHandler(
root_url="https://core.engine.datagroup.de",
pool_maxsize=200, # Optional: Max pool of cached connections for this connection session
pool_block=True, # Optional: Do not allow more parallel connections than pool_maxsize
client_name="Your Graph Client 0.0.1" # Optional: Will be used in the header 'User-Agent'
)
# Work with token of user 1
user1_client: HiroGraph = HiroGraph(
api_handler=FixedTokenApiHandler(
connection_handler=connection_handler,
token='token user 1'
)
)
# Work with token of user 2 (Shared Token Handler)
user2_api_handler = FixedTokenApiHandler(
connection_handler=connection_handler,
token='token user 2'
)
user2_client: HiroGraph = HiroGraph(
api_handler=user2_api_handler
)
hiro_app_client: HiroApp = HiroApp(
api_handler=user2_api_handler
)
```
Everything written in [Token Handler Sharing](#token-handler-sharing) still applies.
## SSL Configuration
SSL parameters are configured using the class `SSLConfig`. This class translates the parameters given to the required
fields for the `requests` library of Python (parameters `cert` and `verify` there). This configuration is given to the
TokenApiHandlers and will be used by the clients attached to it as well.
If this is not set, the default settings of the library `requests` will be used, which is to verify any server
certificates by using system defaults.
#### Example: Disable verification
```python
from hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph, SSLConfig
hiro_client: HiroGraph = HiroGraph(
api_handler=EnvironmentTokenApiHandler(
root_url="https://core.engine.datagroup.de",
# Disable any verification.
ssl_config=SSLConfig(verify=False)
)
)
query_result = hiro_client.query('ogit\\/_type:"ogit/MARS/Machine"')
print(query_result)
```
#### Example: Set custom SSL certificates
```python
from hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph, SSLConfig
hiro_client: HiroGraph = HiroGraph(
api_handler=EnvironmentTokenApiHandler(
root_url="https://core.engine.datagroup.de",
# Set custom certification files. If any of them are omitted, system defaults will be used.
ssl_config=SSLConfig(
cert_file="<path to client certificate file>",
key_file="<path to key file for the client certificate>",
ca_bundle_file="<path to the ca_bundle to verify the server certificate>"
)
)
)
query_result = hiro_client.query('ogit\\/_type:"ogit/MARS/Machine"')
print(query_result)
```
## Graph Client "HiroGraph"
The Graph Client is mostly straightforward to use, since all public methods of this class represent an API call in the
[Graph API](https://core.engine.datagroup.de/help/specs/?url=definitions/graph.yaml). Documentation is available in source code as
well. Some calls are a bit more complicated though and explained in more detail below:
### Attachments
To upload data to such a vertex, use `HiroGraph.post_attachment(data=...)`. The parameter `data=` will be given directly
to the call of the Python library `requests` as `requests.post(data=...)`. To stream data, set `data` to an object of
type `IO`. See the documentation of the Python library `requests` for more details.
Downloading an attachment is done in chunks, so huge blobs of data in memory can be avoided when streaming this data.
Each chunk is 64k by default.
To stream such an attachment to a file, see the example below:
```python
ogit_id = '<ogit/_id of a vertex>'
data_iter = hiro_client.get_attachment(ogit_id)
with io.start("attachment.bin", "wb") as file:
for chunk in data_iter:
file.write(chunk)
```
To read the complete data in memory, see this example:
```python
ogit_id = '<ogit/_id of a vertex>'
data_iter = hiro_client.get_attachment(ogit_id)
attachment = b''.join(data_iter)
```
## WebSockets
This library contains classes that make using HIRO WebSocket protocols easier. They handle authentication, exceptions
and much more.
The classes do not handle buffering of messages, so it is the duty of the programmer to ensure, that incoming messages
are either handled quickly or being buffered to avoid clogging the websocket. The classes are thread-safe, so it is
possible to handle each incoming message asynchronously in its own thread and have those threads send results back if
needed (See multithreaded example in [Action WebSocket](#action-websocket)).
### Closing WebSockets
To shut these WebSockets (_ws_) down cleanly, please consider these scenarios:
#### Default behaviour
The library reacts on *KeyboardInterrupt* (SIGINT) and closes the WebSocket cleanly with closing message to the sever
when such an interrupt is received. If another signal (like SIGTERM) is received, the program will stop immediately
without any closing message back to the server.
#### Signal handling
When installing signal handlers, you need to use *ws.signal_stop()* to shut the WebSocket down. Do NOT use
*ws.stop()* or the closing process will deadlock. This is because the signal interrupt is executed in the same thread
as *ws.run_forever()*.
Example:
```python
import signal
[...]
with ActionWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN')) as ws:
def signal_handler(signum, handler):
ws.signal_stop()
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGHUP, signal_handler) # This signal might not be available on MS Windows
ws.run_forever()
```
#### Closing from a separate thread
When closing the WebSocket from another thread than the one running *ws.run_forever()*, you should use *ws.stop()*. This
ensures, that the shutdown is synchronized and *ws.stop()* will return after the WebSocket has been closed.
### Event WebSocket
This websocket receives notifications about changes to vertices that match a certain filter.
See also [API description of event-ws](https://core.engine.datagroup.de/help/specs/?url=definitions/events-ws.yaml)
Example:
```python
import threading
from hiro_graph_client.clientlib import FixedTokenApiHandler
from hiro_graph_client.eventswebsocket import AbstractEventsWebSocketHandler, EventMessage, EventsFilter
class EventsWebSocket(AbstractEventsWebSocketHandler):
def on_create(self, message: EventMessage):
""" Vertex has been created """
print("Create:\n" + str(message))
def on_update(self, message: EventMessage):
""" Vertex has been updated """
print("Update:\n" + str(message))
def on_delete(self, message: EventMessage):
""" Vertex has been removed """
print("Delete:\n" + str(message))
events_filter = EventsFilter(filter_id='testfilter', filter_content="(element.ogit/_type=ogit/MARS/Machine)")
with EventsWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN'),
events_filters=[events_filter],
query_params={"allscopes": "false", "delta": "false"}) as ws:
ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit.
```
If you do not set the parameter `scope=`, the default scope of your account will be used. If you need to set the scope
by hand, use the following:
```python
[...]
api_handler = FixedTokenApiHandler('HIRO_TOKEN')
default_scope = api_handler.decode_token()['data']['default-scope']
with EventsWebSocket(api_handler=api_handler,
events_filters=[events_filter],
scopes=[default_scope],
query_params={"allscopes": "false", "delta": "false"}) as ws:
ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit.
```
### Action WebSocket
This websocket receives notifications about actions that have been triggered within a KI. Use this to write your own
custom action handler.
See also [API description of action-ws](https://core.engine.datagroup.de/help/specs/?url=definitions/action-ws.yaml)
Simple example:
```python
import threading
from hiro_graph_client.actionwebsocket import AbstractActionWebSocketHandler
from hiro_graph_client.clientlib import FixedTokenApiHandler
class ActionWebSocket(AbstractActionWebSocketHandler):
def on_submit_action(self, action_id: str, capability: str, parameters: dict):
""" Message *submitAction* has been received """
# Handle the message
print(f"ID: {action_id}, Capability: {capability}, Parameters: {str(parameters)}")
# Send back message *sendActionResult*
self.send_action_result(action_id, "Everything went fine.")
def on_config_changed(self):
""" The configuration of the ActionHandler has changed """
pass
with ActionWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN')) as ws:
ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit.
```
Multithreading example using a thread executor:
```python
import threading
import concurrent.futures
from hiro_graph_client.actionwebsocket import AbstractActionWebSocketHandler
from hiro_graph_client.clientlib import FixedTokenApiHandler, AbstractTokenApiHandler
class ActionWebSocket(AbstractActionWebSocketHandler):
def __init__(self, api_handler: AbstractTokenApiHandler):
""" Initialize properties """
super().__init__(api_handler)
self._executor = None
def start(self) -> None:
""" Initialize the executor """
super().start()
self._executor = concurrent.futures.ThreadPoolExecutor()
def stop(self, timeout: int = None) -> None:
""" Shut the executor down """
if self._executor:
self._executor.shutdown()
self._executor = None
super().stop(timeout)
def handle_submit_action(self, action_id: str, capability: str, parameters: dict):
""" Runs asynchronously in its own thread. """
print(f"ID: {action_id}, Capability: {capability}, Parameters: {str(parameters)}")
self.send_action_result(action_id, "Everything went fine.")
def on_submit_action(self, action_id: str, capability: str, parameters: dict):
""" Message *submitAction* has been received. Message is handled in thread executor. """
if not self._executor:
raise RuntimeError('ActionWebSocket has not been started.')
self._executor.submit(ActionWebSocket.handle_submit_action, self, action_id, capability, parameters)
def on_config_changed(self):
""" The configuration of the ActionHandler has changed """
pass
with ActionWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN')) as ws:
ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit.
```
---
# CHANGELOG
---
# v5.3.2
* Point to https://core.engine.datagroup.de instead of https://core.arago.co.
* Add `HiroGraph.escaped_query` method.
# v5.3.0
* Decode any token via static `decode_token_ext()`.
Changes for /api/auth/6.6:
* Ability to revoke a token.
* Recognize `access_token` and `_TOKEN` in token results.
* Remove obsolete method `fresh()` from class TokenInfo because each token refresh issues a new refresh_token by default
now.
# v5.2.5
* [bugfix] Calculation within *clientlib.TokenInfo.expired()* now returns *False* as expected when no *expires_at*
is available for a token. Previous versions would raise an exception.
# v5.2.4
* Merge headers in AbstractAPI instead of replacing them.
# v5.2.3
* Remove accept_all_certs for good. Directly use the flag in SSLConfig.
# v5.2.2
* Debugged python code documentation.
* Fixed copyright notices.
# v5.2.1
* Update because of wrong documentation on https://pypi.org/project/hiro-graph-client/
# v5.2.0
* Separate connection sessions from token handlers. Introducing class `GraphConnectonHandler` which can be shared
between `TokenApiHandler`s and API-Classes.
* Updated documentation.
# v5.1.0
* Use connection pooling via requests.Session.
* Set `pool_connections=1`, `pool_maxsize=10` by default (the latter can be changed).
* Option `pool_block` to block any connections that would exceed the `pool_maxsize`.
* Removed obsolete `accept_all_certs()`.
* Fixed pytest in Makefile target.
* Added information about `requests.Session` and the `pool_maxsize` to documentation.
# v5.0.0
* Externalize `batchclient.py` as its own project at https://github.com/arago/hiro-batch-client-python.
# v4.9.0
* Added batch handling of issues. `handle_vertices_combined` recognizes `_issue_data` now for issues directly linked to
vertices.
* Updated documentation.
# v4.8.0
* Refactoring of `websocketlib.py`:
* Removed unnecessary extra thread.
* Debugged shutdown of WebSockets via signals and threads.
* Updated documentation:
* On signal handling.
* On clean shutdown of WebSockets.
* Adjusted the example code for WebSockets.
* Allow `-` or `_` as build number separator on test tags, i.e. `t4.8.0_0` and `t4.8.0-0` are handled identical now.
# v4.7.5
* [budgfix] Handle `self.submitStore` and `self.resultStore` properly on shutdown in AbstractActionWebSocketHandler.
They might not have been initialized at all when startup fails.
# v4.7.4
* [bugfix] Catch 401 when using PasswordAuthTokenHandler and refresh_token. Raise TokenUnauthorizedError when this
happens to trigger a retry.
# v4.7.3
* Refactoring of `HiroGraphBatch`. Removed obsolete methods.
# v4.7.2
* Fixed bad call of patch() methods in IAM API.
# v4.7.1
* Updated some code documentation in `HiroGraph` that became obsolete.
* Updated graph queries in `HiroGraph`:
* For vertex and gremlin queries: Skip unnecessary fields in query payload.
* Add parameter `count` to vertex query.
* Renamed default _client_name to `hiro-graph-client` (name of the lib on PyPI).
# v4.7.0
* Content- / Media-Type handling
* Throw `WrongContentTypeError` when an unexpected (or missing) Content-Type is returned.
* Check for Content-Type of error results for constructing HTTPError.
* Error handling
* Separate error message extraction, so it can be overwritten per API.
* Try to handle different message formats by guessing, where their error message might be.
* Intercept special error messages for API `ki`.
* Flag `log_communication_on_error` to enable logging of communication when an error is detected in the response.
* Add parameter `max_tries` to TokenHandlers.
# v4.6.2
* Added documentation of new APIs
# v4.6.1
* Updated CHANGELOG.md
# v4.6.0
* Added the following APIS:
* KI
* AuthZ
* Variables
* Adjust return value typing with API methods that return lists of dicts.
# v4.5.2
BUGFIX
* Previous versions incorrectly translated True and False to "True" and
"False" whereas "true" and "false" (lowercase) are needed in URL queries. Fixed.
# v4.5.1
* Add `decode_token()` to decode the information embedded in a HIRO token.
# v4.5.0
* GitHub repository got renamed from `python-hiro-clients` to `hiro-client-python`. No other technical changes.
# v4.4.0
* Added IAM client
* Updated Graph client and Auth client
* put_binary is allowed to return simple strings now. (i.e. for avatar image updates).
# v4.3.0
* Adding SSL configuration
# v4.2.14
* Removed bug with reversed operator in websocketlib.
* Updated installation instructions in README.md.
# v4.2.13
* You need to explicitly set `query_params={'allscopes': 'true'}` if you want to enable it for EventWebSockets. If this
is left out of the query_params, it will be added as 'allscopes': 'false'.
# v4.2.12
* Use typing to make sure, that `query_params=` for WebSockets is of type `Dict[str, str]`.
* Set `query_params={'allscopes': 'false'}` as default for the EventWebSocket.
# v4.2.11
* Debugged EventWebSocket handling.
* Abort connection when setting scope or filters failed.
# v4.2.10
* Adding scopes to EventWebSockets.
# v4.2.9
* Documentation of feature in v4.2.8
# v4.2.8
* WebSockets have new option `query_params` to add arbitrary query parameters to the initial websocket request.
# v4.2.7
Changes to `AbstractAuthenticatedWebSocketHandler`:
* Introducing `run_forever()` which will return after the reader thread has been joined. This can happen when another
thread calls `stop()` (normal exit) or an internal error occurs, either directly when the connection is attempted, a
token got invalid and could not be refreshed, or any other exception that has been thrown in the internal reader
thread.
This ensures, that the main thread does not continue when the websocket reader thread is not there.
* Enable parallel executions of `send()` across multiple threads.
* Make sure, that only one thread triggers a restart by a call to `restart()`.
* Check for active websocket reader thread via `is_active()`.
* Update examples for websockets in README.md.
Generic
* Update README.md to show usage of `client_name`.
# v4.2.6
* Do not require package uuid - it is already supplied with python
# v4.2.5
* Send valid close messages to backend.
* Introduced parameter `client_name` to give connections a name and also set header `User-Agent` more easily.
# v4.2.4
* Updated CHANGELOG.md.
# v4.2.3
* Hardening of clientlib. Removed some None-Value-Errors.
# v4.2.2
* Introduce parameter `remote_exit_codes` to `AbstractAuthenticatedWebSocketHandler`.
# v4.2.1
* Avoid blocking thread in `_backoff()` by not using `sleep()` but `threading.Condition.wait()`.
# v4.2.0
* Implement websocket protocols
* event-ws
* action-ws
# v4.1.3
* Use yield from instead of return
# v4.1.2
* Removed a bug with double yields on binary data
# v4.1.1
* Only log request/responses when logging.DEBUG is enabled
# v4.1.0
* Added timeseries handling to command `handle_vertices_combined`
# v4.0.0
* `AbstractTokenApiHandler`
* Better token handling.
* Resolve graph api endpoints via calling /api/version.
* Ability to customize headers. Headers are handled case-insensitively and are submitted to requests
capitalized.
* Ability to override internal endpoints.
* AbstractIOCarrier works with `with` statements now.
* Added `BasicFileIOCarrier`.
* Removed `ApiConfig`.
* Renamed several internal classes.
* Better error messages.
* HTTP secure protocol logging.
* Fixed timestamp creation for tokens.
* Joe's suggestions - thanks Joe!
# v3.1.0
* Separation of APIs in client libraries. Currently, supported APIs are:
* HiroGraph: https://core.arago.co/help/specs/?url=definitions/graph.yaml
* HiroAuth: https://core.arago.co/help/specs/?url=definitions/auth.yaml
* HiroApp: https://core.arago.co/help/specs/?url=definitions/app.yaml
* Use correct headers with binary transfers.
* Added gremlin and multi-id queries to HiroGraph.
# v3.0.0
* Renamed classes to match documentation elsewhere (i.e. Graphit -> HiroGraph, GraphitBatch -> HiroGraphBatch).
* Catch token expired error when refresh_token has expired.
* Documentation with examples
# v2.4.2
Added VERSION to package_data in setup.py
# v2.4.1
Added documentation for PyPI
# v2.4.0
Initial release after split from https://github.com/arago/hiro-clients
Raw data
{
"_id": null,
"home_page": "https://github.com/arago/hiro-client-python",
"name": "hiro-graph-client",
"maintainer": "Wolfgang H\u00fcbner",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "arago HIRO7 API REST WebSocket",
"author": "arago GmbH",
"author_email": "info@arago.co",
"download_url": "https://files.pythonhosted.org/packages/76/5a/71887c9a9495ce15954edee7b73d363568715e19c8fb25127e35de185d1f/hiro_graph_client-5.3.3.tar.gz",
"platform": null,
"description": "# HIRO Graph API Client\n\nThis is a client library to access data of the [HIRO Graph](#graph-client-hirograph).\n\nThis library also contains classes for handling the [WebSockets](#websockets) `event-ws` and `action-ws` API.\n\nTo process large batches of data, take a look at \"hiro-batch-client\". - (\nPyPI: [hiro-batch-client](https://pypi.org/project/hiro-batch-client/),\nGitHub: [hiro-batch-client-python](https://github.com/arago/hiro-batch-client-python))\n\nFor more information about HIRO Automation, look at https://www.almato.com/de/loesungen/hiro-ai.\n\nFor more information about the APIs this library covers, see https://dev-portal.engine.datagroup.de/7.0/.\n\nCurrently, implemented are\n\n* `HiroApp` for `app`\n* `HiroAuth` for `auth`\n* `HiroGraph` for `graph`\n* `HiroIam` for `iam`\n* `HiroKi` for `ki`\n* `HiroAuthz` for `authz`\n* `HiroVariables` for `variables`\n\nand for the websockets\n\n* `AbstractEventWebSocketHandler` for `event-ws`\n* `AbstractActionWebSocketHandler` for `action-ws`\n\n## Quickstart\n\nTo use this library, you will need an account at https://desktop.engine.datagroup.de/ and access to an OAuth Client-Id and Client-Secret\nto access the HIRO Graph. See also https://dev-portal.engine.datagroup.de/7.0/.\n\nMost of the documentation is done in the sourcecode.\n\n### HiroGraph Example\n\nExample to use the straightforward graph api client:\n\n```python\nfrom hiro_graph_client import PasswordAuthTokenApiHandler, HiroGraph\n\nhiro_client: HiroGraph = HiroGraph(\n api_handler=PasswordAuthTokenApiHandler(\n root_url=\"https://core.engine.datagroup.de\",\n username='',\n password='',\n client_id='',\n client_secret=''\n )\n)\n\n# The commands of the Graph API are methods of the class HIROGraph.\n# The next line executes a vertex query for instance. \nquery_result = hiro_client.query('ogit\\\\/_type:\"ogit/MARS/Machine\"')\n\nprint(query_result)\n```\n\n## TokenApiHandler\n\nAuthorization against the HIRO Graph is done via tokens. These tokens are handled by classes of\ntype `AbstractTokenApiHandler` in this library. Each of the Hiro-Client-Object (`HiroGraph`, , `HiroApp`, etc.) need to\nhave some kind of TokenApiHandler at construction.\n\nThis TokenApiHandler is also responsible to determine the most up-to-date endpoints for the API calls. You can supply a\ncustom list of endpoints by using the dict parameter `custom_endpoints=` on construction.\n\nA custom list of headers can also be set via the dict parameter `headers=` in the constructor. These would update the\ninternal headers. Header names can be supplied in any upper/lower-case.\n\nThis library supplies the following TokenApiHandlers:\n\n---\n\n### FixedTokenApiHandler\n\nA simple TokenApiHandler that is generated with a preset-token at construction. Cannot update its token.\n\n---\n\n### EnvironmentTokenApiHandler\n\nA TokenApiHandler that reads an environment variable (default is `HIRO_TOKEN`) from the runtime environment. Will only\nupdate its token when the environment variable changes externally.\n\n---\n\n### PasswordAuthTokenApiHandler\n\nThis TokenApiHandler logs into the HiroAuth backend and obtains a token from login credentials. This is also the only\nTokenApiHandler (so far) that automatically tries to renew a token from the backend when it has expired.\n\n---\n\nAll code examples in this documentation can use these TokenApiHandlers interchangeably, depending on how such a token is\nprovided.\n\nThe HiroGraph example from above with another customized TokenApiHandler:\n\n```python\nfrom hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph\n\nhiro_client: HiroGraph = HiroGraph(\n api_handler=EnvironmentTokenApiHandler(\n root_url=\"https://core.engine.datagroup.de\"\n )\n)\n\n# The commands of the Graph API are methods of the class HIROGraph.\n# The next line executes a vertex query for instance. \nquery_result = hiro_client.query('ogit\\\\/_type:\"ogit/MARS/Machine\"')\n\nprint(query_result)\n```\n\nExample with additional parameters:\n\n```python\nfrom hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph\n\nhiro_client: HiroGraph = HiroGraph(\n api_handler=EnvironmentTokenApiHandler(\n root_url=\"https://core.engine.datagroup.de\",\n env_var='_TOKEN',\n headers={\n 'X-Custom-Header': 'My custom value'\n },\n custom_endpoints={\n \"graph\": \"/api/graph/7.2\",\n \"auth\": \"/api/auth/6.2\"\n },\n client_name=\"HiroGraph (testing)\" # Will be used in the header 'User-Agent'\n )\n)\n\n# The commands of the Graph API are methods of the class HIROGraph.\n# The next line executes a vertex query for instance. \nquery_result = hiro_client.query('ogit\\\\/_type:\"ogit/MARS/Machine\"')\n\nprint(query_result)\n```\n\n## Token Handler sharing\n\nWhen you need to access multiple APIs of HIRO, share the TokenApiHandler between the API objects to avoid unnecessary\nrequests for token- and version-information against HIRO. The TokenApiHandler will share a `requests.Session`, token-\nand version-request-handling, and the token string itself between them.\n\n```python\nfrom hiro_graph_client import HiroGraph, HiroApp, PasswordAuthTokenApiHandler\n\nhiro_api_handler = PasswordAuthTokenApiHandler(\n root_url=\"https://core.engine.datagroup.de\",\n username='',\n password='',\n client_id='',\n client_secret=''\n)\n\nhiro_client: HiroGraph = HiroGraph(\n api_handler=hiro_api_handler\n)\n\nhiro_app_client: HiroApp = HiroApp(\n api_handler=hiro_api_handler\n)\n```\n\n## Connection sharing\n\nYou can also let TokenApiHandlers share a common connection session instead of letting each of them create their own.\nThis might prove useful in a multithreading environment where tokens have to be set externally or change often (i.e.\none token per user per thread). This also ensures, that version-requests happen only once when the connection is\ninitialized.\n\nUse the parameters `pool_maxsize` and `pool_block` to further tune the connection parameters for parallel access to \nthe backend. See [requests Session Objects](https://docs.python-requests.org/en/latest/user/advanced/#session-objects)\nand the Python documentation of `requests.adapters.HTTPAdapter` and `GraphConnectionHandler`.\n\n```python\nfrom hiro_graph_client import HiroGraph, HiroApp, FixedTokenApiHandler, GraphConnectionHandler\n\nconnection_handler = GraphConnectionHandler(\n root_url=\"https://core.engine.datagroup.de\",\n pool_maxsize=200, # Optional: Max pool of cached connections for this connection session\n pool_block=True, # Optional: Do not allow more parallel connections than pool_maxsize\n client_name=\"Your Graph Client 0.0.1\" # Optional: Will be used in the header 'User-Agent'\n)\n\n# Work with token of user 1\n\nuser1_client: HiroGraph = HiroGraph(\n api_handler=FixedTokenApiHandler(\n connection_handler=connection_handler,\n token='token user 1'\n )\n)\n\n# Work with token of user 2 (Shared Token Handler)\n\nuser2_api_handler = FixedTokenApiHandler(\n connection_handler=connection_handler,\n token='token user 2'\n)\n\nuser2_client: HiroGraph = HiroGraph(\n api_handler=user2_api_handler\n)\n\nhiro_app_client: HiroApp = HiroApp(\n api_handler=user2_api_handler\n)\n\n```\n\nEverything written in [Token Handler Sharing](#token-handler-sharing) still applies.\n\n## SSL Configuration\n\nSSL parameters are configured using the class `SSLConfig`. This class translates the parameters given to the required\nfields for the `requests` library of Python (parameters `cert` and `verify` there). This configuration is given to the\nTokenApiHandlers and will be used by the clients attached to it as well.\n\nIf this is not set, the default settings of the library `requests` will be used, which is to verify any server\ncertificates by using system defaults.\n\n#### Example: Disable verification\n\n```python\nfrom hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph, SSLConfig\n\nhiro_client: HiroGraph = HiroGraph(\n api_handler=EnvironmentTokenApiHandler(\n root_url=\"https://core.engine.datagroup.de\",\n # Disable any verification.\n ssl_config=SSLConfig(verify=False)\n )\n)\n\nquery_result = hiro_client.query('ogit\\\\/_type:\"ogit/MARS/Machine\"')\n\nprint(query_result)\n```\n\n#### Example: Set custom SSL certificates\n\n```python\nfrom hiro_graph_client import EnvironmentTokenApiHandler, HiroGraph, SSLConfig\n\nhiro_client: HiroGraph = HiroGraph(\n api_handler=EnvironmentTokenApiHandler(\n root_url=\"https://core.engine.datagroup.de\",\n # Set custom certification files. If any of them are omitted, system defaults will be used.\n ssl_config=SSLConfig(\n cert_file=\"<path to client certificate file>\",\n key_file=\"<path to key file for the client certificate>\",\n ca_bundle_file=\"<path to the ca_bundle to verify the server certificate>\"\n )\n )\n)\n\nquery_result = hiro_client.query('ogit\\\\/_type:\"ogit/MARS/Machine\"')\n\nprint(query_result)\n```\n\n## Graph Client \"HiroGraph\"\n\nThe Graph Client is mostly straightforward to use, since all public methods of this class represent an API call in the\n[Graph API](https://core.engine.datagroup.de/help/specs/?url=definitions/graph.yaml). Documentation is available in source code as\nwell. Some calls are a bit more complicated though and explained in more detail below:\n\n### Attachments\n\nTo upload data to such a vertex, use `HiroGraph.post_attachment(data=...)`. The parameter `data=` will be given directly\nto the call of the Python library `requests` as `requests.post(data=...)`. To stream data, set `data` to an object of\ntype `IO`. See the documentation of the Python library `requests` for more details.\n\nDownloading an attachment is done in chunks, so huge blobs of data in memory can be avoided when streaming this data.\nEach chunk is 64k by default.\n\nTo stream such an attachment to a file, see the example below:\n\n```python\nogit_id = '<ogit/_id of a vertex>'\ndata_iter = hiro_client.get_attachment(ogit_id)\n\nwith io.start(\"attachment.bin\", \"wb\") as file:\n for chunk in data_iter:\n file.write(chunk)\n```\n\nTo read the complete data in memory, see this example:\n\n```python\nogit_id = '<ogit/_id of a vertex>'\ndata_iter = hiro_client.get_attachment(ogit_id)\n\nattachment = b''.join(data_iter)\n```\n\n## WebSockets\n\nThis library contains classes that make using HIRO WebSocket protocols easier. They handle authentication, exceptions\nand much more.\n\nThe classes do not handle buffering of messages, so it is the duty of the programmer to ensure, that incoming messages\nare either handled quickly or being buffered to avoid clogging the websocket. The classes are thread-safe, so it is\npossible to handle each incoming message asynchronously in its own thread and have those threads send results back if\nneeded (See multithreaded example in [Action WebSocket](#action-websocket)).\n\n### Closing WebSockets\n\nTo shut these WebSockets (_ws_) down cleanly, please consider these scenarios:\n\n#### Default behaviour\n\nThe library reacts on *KeyboardInterrupt* (SIGINT) and closes the WebSocket cleanly with closing message to the sever\nwhen such an interrupt is received. If another signal (like SIGTERM) is received, the program will stop immediately\nwithout any closing message back to the server.\n\n#### Signal handling\n\nWhen installing signal handlers, you need to use *ws.signal_stop()* to shut the WebSocket down. Do NOT use\n*ws.stop()* or the closing process will deadlock. This is because the signal interrupt is executed in the same thread\nas *ws.run_forever()*.\n\nExample:\n\n```python\nimport signal\n\n[...]\n\nwith ActionWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN')) as ws:\n def signal_handler(signum, handler):\n ws.signal_stop()\n\n\n signal.signal(signal.SIGINT, signal_handler)\n signal.signal(signal.SIGTERM, signal_handler)\n signal.signal(signal.SIGHUP, signal_handler) # This signal might not be available on MS Windows \n\n ws.run_forever()\n```\n\n#### Closing from a separate thread\n\nWhen closing the WebSocket from another thread than the one running *ws.run_forever()*, you should use *ws.stop()*. This\nensures, that the shutdown is synchronized and *ws.stop()* will return after the WebSocket has been closed.\n\n### Event WebSocket\n\nThis websocket receives notifications about changes to vertices that match a certain filter.\n\nSee also [API description of event-ws](https://core.engine.datagroup.de/help/specs/?url=definitions/events-ws.yaml)\n\nExample:\n\n```python\nimport threading\n\nfrom hiro_graph_client.clientlib import FixedTokenApiHandler\nfrom hiro_graph_client.eventswebsocket import AbstractEventsWebSocketHandler, EventMessage, EventsFilter\n\n\nclass EventsWebSocket(AbstractEventsWebSocketHandler):\n\n def on_create(self, message: EventMessage):\n \"\"\" Vertex has been created \"\"\"\n print(\"Create:\\n\" + str(message))\n\n def on_update(self, message: EventMessage):\n \"\"\" Vertex has been updated \"\"\"\n print(\"Update:\\n\" + str(message))\n\n def on_delete(self, message: EventMessage):\n \"\"\" Vertex has been removed \"\"\"\n print(\"Delete:\\n\" + str(message))\n\n\nevents_filter = EventsFilter(filter_id='testfilter', filter_content=\"(element.ogit/_type=ogit/MARS/Machine)\")\n\nwith EventsWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN'),\n events_filters=[events_filter],\n query_params={\"allscopes\": \"false\", \"delta\": \"false\"}) as ws:\n ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit. \n\n```\n\nIf you do not set the parameter `scope=`, the default scope of your account will be used. If you need to set the scope\nby hand, use the following:\n\n```python\n[...]\n\napi_handler = FixedTokenApiHandler('HIRO_TOKEN')\n\ndefault_scope = api_handler.decode_token()['data']['default-scope']\n\nwith EventsWebSocket(api_handler=api_handler,\n events_filters=[events_filter],\n scopes=[default_scope],\n query_params={\"allscopes\": \"false\", \"delta\": \"false\"}) as ws:\n ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit. \n\n```\n\n### Action WebSocket\n\nThis websocket receives notifications about actions that have been triggered within a KI. Use this to write your own\ncustom action handler.\n\nSee also [API description of action-ws](https://core.engine.datagroup.de/help/specs/?url=definitions/action-ws.yaml)\n\nSimple example:\n\n```python\nimport threading\n\nfrom hiro_graph_client.actionwebsocket import AbstractActionWebSocketHandler\nfrom hiro_graph_client.clientlib import FixedTokenApiHandler\n\n\nclass ActionWebSocket(AbstractActionWebSocketHandler):\n\n def on_submit_action(self, action_id: str, capability: str, parameters: dict):\n \"\"\" Message *submitAction* has been received \"\"\"\n\n # Handle the message\n print(f\"ID: {action_id}, Capability: {capability}, Parameters: {str(parameters)}\")\n\n # Send back message *sendActionResult*\n self.send_action_result(action_id, \"Everything went fine.\")\n\n def on_config_changed(self):\n \"\"\" The configuration of the ActionHandler has changed \"\"\"\n pass\n\n\nwith ActionWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN')) as ws:\n ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit. \n\n```\n\nMultithreading example using a thread executor:\n\n```python\nimport threading\nimport concurrent.futures\n\nfrom hiro_graph_client.actionwebsocket import AbstractActionWebSocketHandler\nfrom hiro_graph_client.clientlib import FixedTokenApiHandler, AbstractTokenApiHandler\n\n\nclass ActionWebSocket(AbstractActionWebSocketHandler):\n\n def __init__(self, api_handler: AbstractTokenApiHandler):\n \"\"\" Initialize properties \"\"\"\n super().__init__(api_handler)\n self._executor = None\n\n def start(self) -> None:\n \"\"\" Initialize the executor \"\"\"\n super().start()\n self._executor = concurrent.futures.ThreadPoolExecutor()\n\n def stop(self, timeout: int = None) -> None:\n \"\"\" Shut the executor down \"\"\"\n if self._executor:\n self._executor.shutdown()\n self._executor = None\n super().stop(timeout)\n\n def handle_submit_action(self, action_id: str, capability: str, parameters: dict):\n \"\"\" Runs asynchronously in its own thread. \"\"\"\n print(f\"ID: {action_id}, Capability: {capability}, Parameters: {str(parameters)}\")\n self.send_action_result(action_id, \"Everything went fine.\")\n\n def on_submit_action(self, action_id: str, capability: str, parameters: dict):\n \"\"\" Message *submitAction* has been received. Message is handled in thread executor. \"\"\"\n if not self._executor:\n raise RuntimeError('ActionWebSocket has not been started.')\n self._executor.submit(ActionWebSocket.handle_submit_action, self, action_id, capability, parameters)\n\n def on_config_changed(self):\n \"\"\" The configuration of the ActionHandler has changed \"\"\"\n pass\n\n\nwith ActionWebSocket(api_handler=FixedTokenApiHandler('HIRO_TOKEN')) as ws:\n ws.run_forever() # Use KeyboardInterrupt (Ctrl-C) to exit. \n\n```\n\n---\n# CHANGELOG\n---\n# v5.3.2\n\n* Point to https://core.engine.datagroup.de instead of https://core.arago.co.\n* Add `HiroGraph.escaped_query` method.\n\n# v5.3.0\n\n* Decode any token via static `decode_token_ext()`.\n\nChanges for /api/auth/6.6:\n\n* Ability to revoke a token.\n* Recognize `access_token` and `_TOKEN` in token results.\n* Remove obsolete method `fresh()` from class TokenInfo because each token refresh issues a new refresh_token by default\n now.\n\n# v5.2.5\n\n* [bugfix] Calculation within *clientlib.TokenInfo.expired()* now returns *False* as expected when no *expires_at* \n is available for a token. Previous versions would raise an exception.\n\n# v5.2.4\n\n* Merge headers in AbstractAPI instead of replacing them.\n\n# v5.2.3\n\n* Remove accept_all_certs for good. Directly use the flag in SSLConfig.\n\n# v5.2.2\n\n* Debugged python code documentation.\n* Fixed copyright notices.\n\n# v5.2.1\n\n* Update because of wrong documentation on https://pypi.org/project/hiro-graph-client/\n\n# v5.2.0\n\n* Separate connection sessions from token handlers. Introducing class `GraphConnectonHandler` which can be shared\n between `TokenApiHandler`s and API-Classes.\n* Updated documentation.\n\n# v5.1.0\n\n* Use connection pooling via requests.Session.\n * Set `pool_connections=1`, `pool_maxsize=10` by default (the latter can be changed).\n * Option `pool_block` to block any connections that would exceed the `pool_maxsize`.\n* Removed obsolete `accept_all_certs()`.\n* Fixed pytest in Makefile target.\n* Added information about `requests.Session` and the `pool_maxsize` to documentation.\n\n# v5.0.0\n\n* Externalize `batchclient.py` as its own project at https://github.com/arago/hiro-batch-client-python.\n\n# v4.9.0\n\n* Added batch handling of issues. `handle_vertices_combined` recognizes `_issue_data` now for issues directly linked to\n vertices.\n* Updated documentation.\n\n# v4.8.0\n\n* Refactoring of `websocketlib.py`:\n\n * Removed unnecessary extra thread.\n * Debugged shutdown of WebSockets via signals and threads.\n * Updated documentation:\n * On signal handling.\n * On clean shutdown of WebSockets.\n * Adjusted the example code for WebSockets.\n\n\n* Allow `-` or `_` as build number separator on test tags, i.e. `t4.8.0_0` and `t4.8.0-0` are handled identical now.\n\n# v4.7.5\n\n* [budgfix] Handle `self.submitStore` and `self.resultStore` properly on shutdown in AbstractActionWebSocketHandler.\n They might not have been initialized at all when startup fails.\n\n# v4.7.4\n\n* [bugfix] Catch 401 when using PasswordAuthTokenHandler and refresh_token. Raise TokenUnauthorizedError when this\n happens to trigger a retry.\n\n# v4.7.3\n\n* Refactoring of `HiroGraphBatch`. Removed obsolete methods.\n\n# v4.7.2\n\n* Fixed bad call of patch() methods in IAM API.\n\n# v4.7.1\n\n* Updated some code documentation in `HiroGraph` that became obsolete.\n\n* Updated graph queries in `HiroGraph`:\n\n * For vertex and gremlin queries: Skip unnecessary fields in query payload.\n * Add parameter `count` to vertex query.\n\n* Renamed default _client_name to `hiro-graph-client` (name of the lib on PyPI).\n\n# v4.7.0\n\n* Content- / Media-Type handling\n\n * Throw `WrongContentTypeError` when an unexpected (or missing) Content-Type is returned.\n * Check for Content-Type of error results for constructing HTTPError.\n\n* Error handling\n\n * Separate error message extraction, so it can be overwritten per API.\n * Try to handle different message formats by guessing, where their error message might be.\n * Intercept special error messages for API `ki`.\n * Flag `log_communication_on_error` to enable logging of communication when an error is detected in the response.\n\n* Add parameter `max_tries` to TokenHandlers.\n\n# v4.6.2\n\n* Added documentation of new APIs\n\n# v4.6.1\n\n* Updated CHANGELOG.md\n\n# v4.6.0\n\n* Added the following APIS:\n * KI\n * AuthZ\n * Variables\n* Adjust return value typing with API methods that return lists of dicts.\n\n# v4.5.2\n\nBUGFIX\n\n* Previous versions incorrectly translated True and False to \"True\" and\n \"False\" whereas \"true\" and \"false\" (lowercase) are needed in URL queries. Fixed.\n\n# v4.5.1\n\n* Add `decode_token()` to decode the information embedded in a HIRO token.\n\n# v4.5.0\n\n* GitHub repository got renamed from `python-hiro-clients` to `hiro-client-python`. No other technical changes.\n\n# v4.4.0\n\n* Added IAM client\n* Updated Graph client and Auth client\n* put_binary is allowed to return simple strings now. (i.e. for avatar image updates).\n\n# v4.3.0\n\n* Adding SSL configuration\n\n# v4.2.14\n\n* Removed bug with reversed operator in websocketlib.\n* Updated installation instructions in README.md.\n\n# v4.2.13\n\n* You need to explicitly set `query_params={'allscopes': 'true'}` if you want to enable it for EventWebSockets. If this\n is left out of the query_params, it will be added as 'allscopes': 'false'.\n\n# v4.2.12\n\n* Use typing to make sure, that `query_params=` for WebSockets is of type `Dict[str, str]`.\n* Set `query_params={'allscopes': 'false'}` as default for the EventWebSocket.\n\n# v4.2.11\n\n* Debugged EventWebSocket handling.\n* Abort connection when setting scope or filters failed.\n\n# v4.2.10\n\n* Adding scopes to EventWebSockets.\n\n# v4.2.9\n\n* Documentation of feature in v4.2.8\n\n# v4.2.8\n\n* WebSockets have new option `query_params` to add arbitrary query parameters to the initial websocket request.\n\n# v4.2.7\n\nChanges to `AbstractAuthenticatedWebSocketHandler`:\n\n* Introducing `run_forever()` which will return after the reader thread has been joined. This can happen when another\n thread calls `stop()` (normal exit) or an internal error occurs, either directly when the connection is attempted, a\n token got invalid and could not be refreshed, or any other exception that has been thrown in the internal reader\n thread.\n\n This ensures, that the main thread does not continue when the websocket reader thread is not there.\n\n* Enable parallel executions of `send()` across multiple threads.\n\n* Make sure, that only one thread triggers a restart by a call to `restart()`.\n\n* Check for active websocket reader thread via `is_active()`.\n\n* Update examples for websockets in README.md.\n\nGeneric\n\n* Update README.md to show usage of `client_name`.\n\n# v4.2.6\n\n* Do not require package uuid - it is already supplied with python\n\n# v4.2.5\n\n* Send valid close messages to backend.\n* Introduced parameter `client_name` to give connections a name and also set header `User-Agent` more easily.\n\n# v4.2.4\n\n* Updated CHANGELOG.md.\n\n# v4.2.3\n\n* Hardening of clientlib. Removed some None-Value-Errors.\n\n# v4.2.2\n\n* Introduce parameter `remote_exit_codes` to `AbstractAuthenticatedWebSocketHandler`.\n\n# v4.2.1\n\n* Avoid blocking thread in `_backoff()` by not using `sleep()` but `threading.Condition.wait()`.\n\n# v4.2.0\n\n* Implement websocket protocols\n * event-ws\n * action-ws\n\n# v4.1.3\n\n* Use yield from instead of return\n\n# v4.1.2\n\n* Removed a bug with double yields on binary data\n\n# v4.1.1\n\n* Only log request/responses when logging.DEBUG is enabled\n\n# v4.1.0\n\n* Added timeseries handling to command `handle_vertices_combined`\n\n# v4.0.0\n\n* `AbstractTokenApiHandler`\n * Better token handling.\n * Resolve graph api endpoints via calling /api/version.\n * Ability to customize headers. Headers are handled case-insensitively and are submitted to requests\n capitalized.\n * Ability to override internal endpoints.\n\n\n* AbstractIOCarrier works with `with` statements now.\n* Added `BasicFileIOCarrier`.\n\n\n* Removed `ApiConfig`.\n* Renamed several internal classes.\n* Better error messages.\n* HTTP secure protocol logging.\n* Fixed timestamp creation for tokens.\n\n\n* Joe's suggestions - thanks Joe!\n\n# v3.1.0\n\n* Separation of APIs in client libraries. Currently, supported APIs are:\n * HiroGraph: https://core.arago.co/help/specs/?url=definitions/graph.yaml\n * HiroAuth: https://core.arago.co/help/specs/?url=definitions/auth.yaml\n * HiroApp: https://core.arago.co/help/specs/?url=definitions/app.yaml\n* Use correct headers with binary transfers.\n* Added gremlin and multi-id queries to HiroGraph.\n\n# v3.0.0\n\n* Renamed classes to match documentation elsewhere (i.e. Graphit -> HiroGraph, GraphitBatch -> HiroGraphBatch).\n* Catch token expired error when refresh_token has expired.\n* Documentation with examples\n\n# v2.4.2\n\nAdded VERSION to package_data in setup.py\n\n# v2.4.1\n\nAdded documentation for PyPI\n\n# v2.4.0\n\nInitial release after split from https://github.com/arago/hiro-clients\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Hiro Client for Graph REST API of HIRO 7",
"version": "5.3.3",
"project_urls": {
"Changelog": "https://github.com/arago/hiro-client-python/blob/master/CHANGELOG.md",
"Documentation": "https://github.com/arago/hiro-client-python/blob/master/src/README.md",
"GitHub": "https://github.com/arago/hiro-client-python",
"Homepage": "https://github.com/arago/hiro-client-python"
},
"split_keywords": [
"arago",
"hiro7",
"api",
"rest",
"websocket"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "aa54eec95d39caa488e495c5f69891ef4960e949df8a912d2d05e1bcce92b7d4",
"md5": "90bdebfd4c755d2885bdc62b71deea8f",
"sha256": "ebda9713fc68253fd6dbb1eaf1605508d7ddba5a0aab9c02bb96e42f113fc57c"
},
"downloads": -1,
"filename": "hiro_graph_client-5.3.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "90bdebfd4c755d2885bdc62b71deea8f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 47196,
"upload_time": "2025-04-09T14:41:35",
"upload_time_iso_8601": "2025-04-09T14:41:35.368911Z",
"url": "https://files.pythonhosted.org/packages/aa/54/eec95d39caa488e495c5f69891ef4960e949df8a912d2d05e1bcce92b7d4/hiro_graph_client-5.3.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "765a71887c9a9495ce15954edee7b73d363568715e19c8fb25127e35de185d1f",
"md5": "5370ce31231e4abbed316076a66edf4d",
"sha256": "880cf3af8abbfbc7b88351154a711f2c1544e2cb6f0ce5743f10e2355809f831"
},
"downloads": -1,
"filename": "hiro_graph_client-5.3.3.tar.gz",
"has_sig": false,
"md5_digest": "5370ce31231e4abbed316076a66edf4d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 50168,
"upload_time": "2025-04-09T14:41:37",
"upload_time_iso_8601": "2025-04-09T14:41:37.232329Z",
"url": "https://files.pythonhosted.org/packages/76/5a/71887c9a9495ce15954edee7b73d363568715e19c8fb25127e35de185d1f/hiro_graph_client-5.3.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-04-09 14:41:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "arago",
"github_project": "hiro-client-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "hiro-graph-client"
}