# TreeTop Client
Dataclass-based HTTPX client for the [Treetop REST API](https://github.com/terjekv/treetop-rest).
Python ≥ 3.11, zero runtime deps beyond HTTPX.
## Example
```python
from treetop_client.client import TreeTopClient
from treetop_client.models import Action, Request, Resource, User
client = TreeTopClient(base_url=f"http://localhost:{PORT}")
req = Request(
principal=User.new("myuser", "mynamespace", ["mygroup"]),
action=Action.new("myaction", ["mynamespace"]),
resource=Resource.new("Host", {"name": "myhost.example.com", "ip": "10.0.0.1"}),
)
resp = client.check(req)
assert resp.is_allowed()
assert resp.decision == "Allow"
# The other possible value for decision is "Deny" which makes `is_denied()` True
# (and `is_allowed()` False).
```
You can also use the `check_detailed` method to get more information about the decision:
```python
from treetop_client.client import TreeTopClient
from treetop_client.models import Action, Request, Resource, User
client = TreeTopClient(base_url=f"http://localhost:{PORT}")
req = Request(
principal=User.new("myuser", "mynamespace", ["mygroup"]),
action=Action.new("myaction", ["mynamespace"]),
resource=Resource.new("Host", {"name": "myhost.example.com", "ip": "10.0.0.1"}),
)
resp = client.check_detailed(req)
assert resp.is_allowed()
assert resp.decision == "Allow"
# This will contain the policy that was matched, in cedar format
assert resp.policy_literal() is not None
# This will contain the policy that was matched, in JSON format
assert resp.policy_json() is not None
```
Note that for `User` the namespace and groups are optional, and for `Action` the namespace is optional. If you don't provide a namespace, it will default to the root namespace.
## Correlation ID
You can pass a correlation ID to the `check` and `check_detailed` methods. This ID will be included in the request headers and can be used on the server side
to trace requests across queries or services. The value is a string of the client's choosing.
```python
from treetop_client.client import TreeTopClient
from treetop_client.models import Action, Request, Resource, User
client = TreeTopClient(base_url=f"http://localhost:{PORT}")
req = Request(
principal=User.new("myuser", "mynamespace", ["mygroup"]),
action=Action.new("myaction", ["mynamespace"]),
resource=Resource.new("Host", {"name": "myhost.example.com", "ip": "10.0.0.1"}),
)
resp = client.check(req, correlation_id="my-correlation-id")
```
## Integration tests
Make sure you have Docker & Docker Compose installed.
```bash
# Run only unit tests:
pytest
# Run integration tests (will spin up Docker Compose):
pytest -m integration
```
Raw data
{
"_id": null,
"home_page": "https://github.com/terjekv/treetop-client-python",
"name": "treetop-client",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": null,
"author": "Terje Kvernes",
"author_email": "terje@kvernes.no",
"download_url": "https://files.pythonhosted.org/packages/fa/a1/ae06eb362cdc44ccf2bea1c2af6856e038cebac63ceb4908434482e1323a/treetop_client-0.0.2.tar.gz",
"platform": null,
"description": "# TreeTop Client\n\nDataclass-based HTTPX client for the [Treetop REST API](https://github.com/terjekv/treetop-rest).\nPython \u2265 3.11, zero runtime deps beyond HTTPX.\n\n## Example\n\n```python\nfrom treetop_client.client import TreeTopClient\nfrom treetop_client.models import Action, Request, Resource, User\n\n\nclient = TreeTopClient(base_url=f\"http://localhost:{PORT}\")\n\nreq = Request(\n principal=User.new(\"myuser\", \"mynamespace\", [\"mygroup\"]),\n action=Action.new(\"myaction\", [\"mynamespace\"]),\n resource=Resource.new(\"Host\", {\"name\": \"myhost.example.com\", \"ip\": \"10.0.0.1\"}),\n)\nresp = client.check(req)\nassert resp.is_allowed() \nassert resp.decision == \"Allow\"\n\n# The other possible value for decision is \"Deny\" which makes `is_denied()` True\n# (and `is_allowed()` False).\n```\n\nYou can also use the `check_detailed` method to get more information about the decision:\n\n```python\nfrom treetop_client.client import TreeTopClient\nfrom treetop_client.models import Action, Request, Resource, User\n\nclient = TreeTopClient(base_url=f\"http://localhost:{PORT}\")\n\nreq = Request(\n principal=User.new(\"myuser\", \"mynamespace\", [\"mygroup\"]),\n action=Action.new(\"myaction\", [\"mynamespace\"]),\n resource=Resource.new(\"Host\", {\"name\": \"myhost.example.com\", \"ip\": \"10.0.0.1\"}),\n)\n\nresp = client.check_detailed(req)\nassert resp.is_allowed()\nassert resp.decision == \"Allow\"\n # This will contain the policy that was matched, in cedar format\nassert resp.policy_literal() is not None\n # This will contain the policy that was matched, in JSON format\nassert resp.policy_json() is not None\n```\n\nNote that for `User` the namespace and groups are optional, and for `Action` the namespace is optional. If you don't provide a namespace, it will default to the root namespace.\n\n## Correlation ID\n\nYou can pass a correlation ID to the `check` and `check_detailed` methods. This ID will be included in the request headers and can be used on the server side\nto trace requests across queries or services. The value is a string of the client's choosing.\n\n```python\nfrom treetop_client.client import TreeTopClient\nfrom treetop_client.models import Action, Request, Resource, User\n\nclient = TreeTopClient(base_url=f\"http://localhost:{PORT}\")\n\nreq = Request(\n principal=User.new(\"myuser\", \"mynamespace\", [\"mygroup\"]),\n action=Action.new(\"myaction\", [\"mynamespace\"]),\n resource=Resource.new(\"Host\", {\"name\": \"myhost.example.com\", \"ip\": \"10.0.0.1\"}),\n)\n\nresp = client.check(req, correlation_id=\"my-correlation-id\")\n```\n\n## Integration tests\n\nMake sure you have Docker & Docker Compose installed. \n\n```bash\n# Run only unit tests:\npytest\n\n# Run integration tests (will spin up Docker Compose):\npytest -m integration\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python client library for the Treetop policy server",
"version": "0.0.2",
"project_urls": {
"Homepage": "https://github.com/terjekv/treetop-client-python",
"Issues": "https://github.com/terjekv/treetop-client-python/issues"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "98e49587921902ece105f616310b66cae9e4f40e38c8673d5e74ff2a66b61d57",
"md5": "08ef16f55581c5bf231f5cb84b6bc50b",
"sha256": "af08d71d9d74a3913c7655fe3a5e1dc579e335ddecf562710ca2443b5227d16a"
},
"downloads": -1,
"filename": "treetop_client-0.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "08ef16f55581c5bf231f5cb84b6bc50b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 6108,
"upload_time": "2025-07-28T19:34:35",
"upload_time_iso_8601": "2025-07-28T19:34:35.405805Z",
"url": "https://files.pythonhosted.org/packages/98/e4/9587921902ece105f616310b66cae9e4f40e38c8673d5e74ff2a66b61d57/treetop_client-0.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "faa1ae06eb362cdc44ccf2bea1c2af6856e038cebac63ceb4908434482e1323a",
"md5": "985046324c6c94255a7f69c46169ff40",
"sha256": "c89794d09fc9c31d39cb0e13ee03f1559bbe2ec893a0647698f48747a1759f8f"
},
"downloads": -1,
"filename": "treetop_client-0.0.2.tar.gz",
"has_sig": false,
"md5_digest": "985046324c6c94255a7f69c46169ff40",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 5103,
"upload_time": "2025-07-28T19:34:36",
"upload_time_iso_8601": "2025-07-28T19:34:36.677102Z",
"url": "https://files.pythonhosted.org/packages/fa/a1/ae06eb362cdc44ccf2bea1c2af6856e038cebac63ceb4908434482e1323a/treetop_client-0.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-28 19:34:36",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "terjekv",
"github_project": "treetop-client-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "treetop-client"
}