norbix 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- norbix-1.1.0/.github/workflows/ci.yml +26 -0
- norbix-1.1.0/.github/workflows/release.yml +61 -0
- norbix-1.1.0/.gitignore +9 -0
- norbix-1.1.0/ArchitectOverview.md +142 -0
- norbix-1.1.0/CHANGELOG.md +58 -0
- norbix-1.1.0/LICENSE +21 -0
- norbix-1.1.0/Makefile +37 -0
- norbix-1.1.0/PKG-INFO +181 -0
- norbix-1.1.0/README.md +165 -0
- norbix-1.1.0/docs/README.md +4 -0
- norbix-1.1.0/docs/api/_index.md +8 -0
- norbix-1.1.0/docs/api/chat.md +7 -0
- norbix-1.1.0/docs/api/database.md +24 -0
- norbix-1.1.0/docs/api/echo.md +7 -0
- norbix-1.1.0/docs/api/membership.md +24 -0
- norbix-1.1.0/docs/hub/_index.md +17 -0
- norbix-1.1.0/docs/hub/account.md +43 -0
- norbix-1.1.0/docs/hub/ai.md +20 -0
- norbix-1.1.0/docs/hub/database.md +47 -0
- norbix-1.1.0/docs/hub/echo.md +7 -0
- norbix-1.1.0/docs/hub/email.md +7 -0
- norbix-1.1.0/docs/hub/files.md +21 -0
- norbix-1.1.0/docs/hub/internal.md +7 -0
- norbix-1.1.0/docs/hub/logs.md +15 -0
- norbix-1.1.0/docs/hub/membership.md +31 -0
- norbix-1.1.0/docs/hub/notifications.md +74 -0
- norbix-1.1.0/docs/hub/payments.md +22 -0
- norbix-1.1.0/docs/hub/scheduler.md +14 -0
- norbix-1.1.0/docs/hub/webhooks.md +14 -0
- norbix-1.1.0/pyproject.toml +83 -0
- norbix-1.1.0/references/api2.dtos.ts +4855 -0
- norbix-1.1.0/references/api_dtos.py +1727 -0
- norbix-1.1.0/references/hub2.dtos.ts +12211 -0
- norbix-1.1.0/references/hub_dtos.py +8617 -0
- norbix-1.1.0/scripts/generate_endpoints.py +511 -0
- norbix-1.1.0/src/norbix_python/__init__.py +27 -0
- norbix-1.1.0/src/norbix_python/api/__init__.py +23 -0
- norbix-1.1.0/src/norbix_python/api/chat.py +41 -0
- norbix-1.1.0/src/norbix_python/api/database.py +483 -0
- norbix-1.1.0/src/norbix_python/api/echo.py +41 -0
- norbix-1.1.0/src/norbix_python/api/membership.py +483 -0
- norbix-1.1.0/src/norbix_python/client.py +318 -0
- norbix-1.1.0/src/norbix_python/errors.py +98 -0
- norbix-1.1.0/src/norbix_python/hub/__init__.py +50 -0
- norbix-1.1.0/src/norbix_python/hub/account.py +977 -0
- norbix-1.1.0/src/norbix_python/hub/ai.py +379 -0
- norbix-1.1.0/src/norbix_python/hub/database.py +1081 -0
- norbix-1.1.0/src/norbix_python/hub/echo.py +41 -0
- norbix-1.1.0/src/norbix_python/hub/email.py +41 -0
- norbix-1.1.0/src/norbix_python/hub/files.py +405 -0
- norbix-1.1.0/src/norbix_python/hub/internal.py +41 -0
- norbix-1.1.0/src/norbix_python/hub/logs.py +249 -0
- norbix-1.1.0/src/norbix_python/hub/membership.py +665 -0
- norbix-1.1.0/src/norbix_python/hub/notifications.py +1783 -0
- norbix-1.1.0/src/norbix_python/hub/payments.py +431 -0
- norbix-1.1.0/src/norbix_python/hub/scheduler.py +223 -0
- norbix-1.1.0/src/norbix_python/hub/webhooks.py +223 -0
- norbix-1.1.0/src/norbix_python/models.py +21 -0
- norbix-1.1.0/src/norbix_python/transport.py +325 -0
- norbix-1.1.0/tests/__init__.py +1 -0
- norbix-1.1.0/tests/api/__init__.py +1 -0
- norbix-1.1.0/tests/api/test_chat.py +18 -0
- norbix-1.1.0/tests/api/test_database.py +154 -0
- norbix-1.1.0/tests/api/test_echo.py +18 -0
- norbix-1.1.0/tests/api/test_membership.py +154 -0
- norbix-1.1.0/tests/helpers.py +48 -0
- norbix-1.1.0/tests/hub/__init__.py +1 -0
- norbix-1.1.0/tests/hub/test_account.py +639 -0
- norbix-1.1.0/tests/hub/test_ai.py +122 -0
- norbix-1.1.0/tests/hub/test_database.py +338 -0
- norbix-1.1.0/tests/hub/test_echo.py +18 -0
- norbix-1.1.0/tests/hub/test_email.py +18 -0
- norbix-1.1.0/tests/hub/test_files.py +130 -0
- norbix-1.1.0/tests/hub/test_internal.py +18 -0
- norbix-1.1.0/tests/hub/test_logs.py +82 -0
- norbix-1.1.0/tests/hub/test_membership.py +210 -0
- norbix-1.1.0/tests/hub/test_notifications.py +563 -0
- norbix-1.1.0/tests/hub/test_payments.py +138 -0
- norbix-1.1.0/tests/hub/test_scheduler.py +74 -0
- norbix-1.1.0/tests/hub/test_webhooks.py +74 -0
- norbix-1.1.0/tests/test_async_client_smoke.py +13 -0
- norbix-1.1.0/tests/test_client.py +61 -0
- norbix-1.1.0/uv.lock +1217 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main, next, beta]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-22.04
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: astral-sh/setup-uv@v5
|
|
14
|
+
with:
|
|
15
|
+
version: "latest"
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: uv sync --all-groups
|
|
21
|
+
- name: Lint
|
|
22
|
+
run: uv run ruff check .
|
|
23
|
+
- name: Typecheck
|
|
24
|
+
run: uv run mypy src
|
|
25
|
+
- name: Test
|
|
26
|
+
run: uv run pytest
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, next, beta]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
issues: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
release:
|
|
16
|
+
runs-on: ubuntu-22.04
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
|
|
22
|
+
- uses: astral-sh/setup-uv@v5
|
|
23
|
+
with:
|
|
24
|
+
version: "latest"
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: uv sync --all-groups
|
|
31
|
+
|
|
32
|
+
- name: Test before release
|
|
33
|
+
run: |
|
|
34
|
+
uv run pytest
|
|
35
|
+
|
|
36
|
+
- name: Bootstrap initial semantic-release tag
|
|
37
|
+
env:
|
|
38
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
39
|
+
run: |
|
|
40
|
+
if ! git tag -l "v*" | grep -q .; then
|
|
41
|
+
echo "No semantic-release tags found. Bootstrapping v0.0.0"
|
|
42
|
+
git tag v0.0.0
|
|
43
|
+
git push origin v0.0.0
|
|
44
|
+
else
|
|
45
|
+
echo "Existing semantic-release tags found. Skipping bootstrap."
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
- name: Semantic release version
|
|
49
|
+
env:
|
|
50
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
51
|
+
run: uv run semantic-release version
|
|
52
|
+
|
|
53
|
+
- name: Publish to PyPI
|
|
54
|
+
env:
|
|
55
|
+
PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
56
|
+
run: |
|
|
57
|
+
if ls dist/*.whl >/dev/null 2>&1; then
|
|
58
|
+
uv publish --token "$PYPI_TOKEN" dist/*
|
|
59
|
+
else
|
|
60
|
+
echo "No new release artifacts produced; skipping PyPI publish."
|
|
61
|
+
fi
|
norbix-1.1.0/.gitignore
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Architect Overview — norbix-python SDK
|
|
2
|
+
|
|
3
|
+
> Author role: Python Architect (20+ years).
|
|
4
|
+
> Scope: developer UX of the Python SDK — how config is initiated, how the library feels when imported and used in real scripts.
|
|
5
|
+
> Reviewed paths: `src/norbix_python/__init__.py`, `src/norbix_python/client.py`, `src/norbix_python/transport.py`, `src/norbix_python/errors.py`, `src/norbix_python/api/*.py`, `src/norbix_python/hub/*.py`, `tests/*.py`, `pyproject.toml`, `README.md`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Suggestions list (sorted by impact)
|
|
10
|
+
|
|
11
|
+
### Naming and Python idioms
|
|
12
|
+
|
|
13
|
+
1. **Method names are camelCase, not snake_case.** `findOne`, `getDatabaseSchemas`, `deleteMany` look like JavaScript / C#. Python community uses `find_one`, `get_database_schemas`, `delete_many`. PyMongo, boto3, requests, stripe, openai — all use snake_case. This is the single biggest UX issue.
|
|
14
|
+
2. **`LoginCredentials` fields use camelCase (`userName`).** Should be `user_name` with a serialization alias for the wire format.
|
|
15
|
+
3. **Module class names like `DatabaseModule` are noisy.** `Database`, `Files`, `Ai` is enough. Users do not write these names anyway.
|
|
16
|
+
|
|
17
|
+
### API ergonomics — the "import and use" feeling
|
|
18
|
+
|
|
19
|
+
4. **Every method takes one big `dict[str, Any]`.** No autocomplete, no type hints, no IDE help. User cannot tell which keys are path parameters, which are query, which are body.
|
|
20
|
+
- Now: `db.findOne({"collectionName": "orders", "id": "123"})`
|
|
21
|
+
- Better: `db.find_one("orders", id="123")` or `db.collection("orders").find_one("123")`
|
|
22
|
+
5. **No fluent / resource-oriented API.** Best Python SDKs feel like: `s3.objects("bucket").list()`, `db["orders"].find_one(id)`. Norbix forces you to build a dict every call.
|
|
23
|
+
6. **Return type is always `Any`.** README itself shows the pain:
|
|
24
|
+
```python
|
|
25
|
+
items = response.get("results", []) if isinstance(response, dict) else []
|
|
26
|
+
```
|
|
27
|
+
This is a code smell. Return Pydantic models or at minimum `TypedDict`.
|
|
28
|
+
7. **No `download()` / `upload()` / `execute()` style methods.** The `db.FindAll()`, `files.Download()`, `code.Execute()` style is missing. `hub/files.py` only has trigger and integration management (`enableFiles`, `saveFilesIntegration`). There is no real file upload / download / list. There is no `code.execute()` module at all.
|
|
29
|
+
|
|
30
|
+
### Configuration / initialization UX
|
|
31
|
+
|
|
32
|
+
8. **Env variables are supported (good).** `NORBIX_PROJECT_ID`, `NORBIX_API_KEY`, etc. are read in `src/norbix_python/client.py` lines 42–54. This part is solid.
|
|
33
|
+
9. **No `.env` auto-loading.** Most modern SDKs (or their docs) suggest `python-dotenv`. The README does not mention it.
|
|
34
|
+
10. **No global / default client pattern.** OpenAI and stripe let you do `stripe.api_key = "..."` then `stripe.Customer.list()`. Norbix forces explicit `Norbix(...)` every time. For scripts, a module-level client is friendlier.
|
|
35
|
+
11. **`project_id` always required.** Even for endpoints that don't need it (`/auth`). This forces users to set it before login is even possible, which is strange.
|
|
36
|
+
12. **API key and bearer token are mixed under one `Authorization: Bearer` header** (`transport.py` line 74). Most APIs use `Authorization: ApiKey ...` or a separate header for API keys. Mixing them is unclear and risky.
|
|
37
|
+
|
|
38
|
+
### Architecture / safety
|
|
39
|
+
|
|
40
|
+
13. **Path parameters are extracted from the request dict by string matching** (`_build_url_and_body`, `transport.py` lines 115–144). This is "magic" — caller does not know which keys vanish from the body. Case-insensitive lookup (`_lookup_case_insensitive`, lines 147–154) makes it worse: `id` and `Id` collide silently.
|
|
41
|
+
14. **Private attribute mutation.** `client.py` line 81 does `self._transport._cfg.bearer_token = str(...)` — touching a private field. The `set_bearer_token()` method already exists (line 87) but `login()` does not use it. Inconsistent.
|
|
42
|
+
15. **`NorbixError` is a `@dataclass` AND an `Exception`.** This works in Python 3.10+ but is fragile — `Exception.__init__` is bypassed. A normal class with `__init__` calling `super().__init__(message)` is safer.
|
|
43
|
+
16. **No `__enter__` / `__exit__`** on `Norbix`. Should support `with Norbix(...) as client:` so the underlying `httpx.Client` is closed automatically.
|
|
44
|
+
17. **No async client.** `httpx` already gives you `AsyncClient`. Modern Python SDKs ship `AsyncNorbix` for free.
|
|
45
|
+
18. **No retries, no backoff, no rate-limit handling.** Stripe's SDK retries idempotent calls automatically.
|
|
46
|
+
19. **No pagination helper.** `find()` returns `{"results": [...]}` but the user has to handle `skip`/`take` themselves. An iterator (`for order in db.orders.iter_all()`) is the standard.
|
|
47
|
+
|
|
48
|
+
### Tests / docs
|
|
49
|
+
|
|
50
|
+
20. **Only 3 tests in `tests/test_client.py`.** Coverage of modules (`database`, `files`, `ai`) is zero. The boilerplate of every method is identical — one parametrized test would cover all of them.
|
|
51
|
+
21. **README example uses `getCurrentUser({})`** but this method is not in `src/norbix_python/api/membership.py`. Either the doc is stale or the method is missing.
|
|
52
|
+
22. **`per-file-ignores` in `pyproject.toml`** (lines 47–50) disables `E501` and `I001` for all generated modules. This hides real issues. Generated code should still be linted.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Summary
|
|
57
|
+
|
|
58
|
+
The SDK is a thin, generated wrapper over the HTTP API. The transport layer (`src/norbix_python/transport.py`) is clean and the env-variable support in `src/norbix_python/client.py` (lines 42–54) is well done. The **biggest weakness is developer UX** — the SDK feels like a TypeScript library translated to Python rather than a Python library. A senior Python developer using this for the first time will not feel "at home".
|
|
59
|
+
|
|
60
|
+
### Where it hurts most — config initiation
|
|
61
|
+
|
|
62
|
+
The env-variable story is fine, but the constructor surface in `src/norbix_python/client.py` (lines 27–65) is wide (10+ parameters). A user who only wants `Norbix()` from `.env` is fine, but a user who wants explicit credentials has to pass several keyword arguments. Splitting into `Norbix.from_env()` and `Norbix(api_key=..., project_id=...)` would clarify intent. Adding a top-level helper like:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import norbix
|
|
66
|
+
norbix.configure(api_key="sk_live_...", project_id="proj_123")
|
|
67
|
+
norbix.db.find_all("orders")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
would match the OpenAI / stripe style users expect.
|
|
71
|
+
|
|
72
|
+
### Where it hurts most — calling style
|
|
73
|
+
|
|
74
|
+
The request style `db.FindAll()`, `files.Download()`, `code.Execute()` is not possible today.
|
|
75
|
+
|
|
76
|
+
Today (from `README.md` lines 46–53):
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
response = norbix.api.database.find(
|
|
80
|
+
{"collectionName": "orders", "take": 20, "skip": 0,
|
|
81
|
+
"orderBy": [{"field": "createdAt", "direction": "desc"}]}
|
|
82
|
+
)
|
|
83
|
+
items = response.get("results", []) if isinstance(response, dict) else []
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
What it should look like (PyMongo / stripe style):
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
orders = norbix.db("orders").find_all(take=20, order_by="-createdAt")
|
|
90
|
+
for order in orders:
|
|
91
|
+
print(order.id)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The current style is caused by `src/norbix_python/api/database.py` lines 143–153 where `find` accepts only a dict and returns `Any`. The dict-only signature comes from the code generator. To fix this without rewriting the generator, add a thin **hand-written facade layer** on top of the generated modules — for example `src/norbix_python/db.py` exposing `Collection.find_all()`, `find_one()`, `insert_one()` with typed kwargs, calling the generated `database.find(...)` underneath.
|
|
95
|
+
|
|
96
|
+
### File operations are missing
|
|
97
|
+
|
|
98
|
+
`src/norbix_python/hub/files.py` only manages triggers and integrations (`enableFiles`, `saveFilesIntegration`, lines 23–177). There is no `upload()`, `download()`, `list()`, `delete_object()`. If the backend supports file storage, the SDK is not exposing it. If it does not, then the module name `files` is misleading.
|
|
99
|
+
|
|
100
|
+
### Path parameter handling is magical
|
|
101
|
+
|
|
102
|
+
`transport.py` lines 121–134 walks the URL template and pulls keys from the request dict — case-insensitive (`_lookup_case_insensitive`, lines 147–154). The user has no way to tell from the method signature `database.findOne(request)` which dict keys are path parameters (`collectionName`, `id`) and which are body. Promote them to explicit positional arguments in the generated code:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
def find_one(self, collection_name: str, id: str, *, timeout: float | None = None) -> Any:
|
|
106
|
+
...
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Auth state is leaky
|
|
110
|
+
|
|
111
|
+
`client.py` line 81 writes directly to `self._transport._cfg.bearer_token` — bypassing `set_bearer_token()` (line 87) which exists for exactly this. Replace with `self.set_bearer_token(str(result["bearerToken"]))`. Also, `transport.py` line 74 sends `api_key` as `Authorization: Bearer ...` together with JWT tokens — most APIs separate these. Add a clear header strategy.
|
|
112
|
+
|
|
113
|
+
### Errors swallow detail
|
|
114
|
+
|
|
115
|
+
`NorbixError` (`src/norbix_python/errors.py`) is a `@dataclass(Exception)`. It works but is fragile. Convert to a normal exception class with `super().__init__(message)`, keep `code`, `status`, `details` as attributes, and add subclasses (`AuthenticationError`, `RateLimitError`, `NotFoundError`, `ValidationError`) so users can write:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
try:
|
|
119
|
+
norbix.db.find_one("orders", id="123")
|
|
120
|
+
except NotFoundError:
|
|
121
|
+
...
|
|
122
|
+
except RateLimitError:
|
|
123
|
+
...
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
like in stripe and openai SDKs.
|
|
127
|
+
|
|
128
|
+
### Quality of the plan / generation pipeline
|
|
129
|
+
|
|
130
|
+
The architecture (one `Transport` + one module per resource + namespaces `api` / `hub`) is reasonable and extendable. The `pyproject.toml` is professional — `ruff`, `mypy --strict`, `pytest`, semantic-release. But `tool.ruff.lint.per-file-ignores` (lines 47–50) silences linting for the generated modules — that hides bugs in the very code most users will read.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Top 5 actions, in order
|
|
135
|
+
|
|
136
|
+
1. **Rename methods to snake_case in the generator.** This alone removes 80% of the "this feels foreign" feeling.
|
|
137
|
+
2. **Promote path parameters to explicit function arguments.** Stop reading them out of the request dict.
|
|
138
|
+
3. **Add a hand-written facade** for the most-used resources: `db.collection("orders").find_all()`, `files.upload(path)`, etc. — backed by the generated code.
|
|
139
|
+
4. **Return typed objects (Pydantic v2 models)**, since you already require Python 3.10+. Stop returning `Any`.
|
|
140
|
+
5. **Add `__enter__`/`__exit__`, an `AsyncNorbix`, and basic retries on idempotent verbs.**
|
|
141
|
+
|
|
142
|
+
If you do these five, the SDK will feel like a first-class Python library and not a generated transport.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
<!-- version list -->
|
|
4
|
+
|
|
5
|
+
## v1.1.0 (2026-04-28)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- **pypi**: Rename distribution package to norbix
|
|
10
|
+
([`2ab5e75`](https://github.com/norbix-code/sdk-python/commit/2ab5e7508f5b465f1b81add49191213c9440a252))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v1.0.2 (2026-04-28)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- **ci**: Publish python package to pypi via uv
|
|
18
|
+
([`3ec7ba5`](https://github.com/norbix-code/sdk-python/commit/3ec7ba58c5c0e2ee27330696f022cc251e2068cd))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## v1.0.1 (2026-04-28)
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
- **ci**: Run semantic-release publish after version
|
|
26
|
+
([`6deb16d`](https://github.com/norbix-code/sdk-python/commit/6deb16dec02d2c739e216c5a82b72078acdebf7a))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## v1.0.0 (2026-04-28)
|
|
30
|
+
|
|
31
|
+
### Bug Fixes
|
|
32
|
+
|
|
33
|
+
- Normalize generated python imports for ruff
|
|
34
|
+
([`3bb658a`](https://github.com/norbix-code/sdk-python/commit/3bb658a47c96df81825e0cd38cbd418adbcab3e3))
|
|
35
|
+
|
|
36
|
+
- Trigger initial pypi publish
|
|
37
|
+
([`9d32ddc`](https://github.com/norbix-code/sdk-python/commit/9d32ddcf604920b2ecac84d59f5b5d574071f7c6))
|
|
38
|
+
|
|
39
|
+
- **ci**: Use semantic-release version for pypi publishing
|
|
40
|
+
([`d2a4a81`](https://github.com/norbix-code/sdk-python/commit/d2a4a816b33ad0c0144fdeacee556a74f35efece))
|
|
41
|
+
|
|
42
|
+
### Continuous Integration
|
|
43
|
+
|
|
44
|
+
- Normalize generated python modules before drift check
|
|
45
|
+
([`4e8d920`](https://github.com/norbix-code/sdk-python/commit/4e8d9200d8792b6c5569f71bb18b18267b41e071))
|
|
46
|
+
|
|
47
|
+
- Remove endpoint generation from python pipeline
|
|
48
|
+
([`aae4e66`](https://github.com/norbix-code/sdk-python/commit/aae4e66d47380c476f79f139f78658642bd8257e))
|
|
49
|
+
|
|
50
|
+
### Features
|
|
51
|
+
|
|
52
|
+
- Split python clients into api and hub surfaces
|
|
53
|
+
([`3864f46`](https://github.com/norbix-code/sdk-python/commit/3864f4623ed33c959785cf757c0588eac305ddf1))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## v0.0.0 (2026-04-28)
|
|
57
|
+
|
|
58
|
+
- Initial Release
|
norbix-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UAB Isidos
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
norbix-1.1.0/Makefile
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
PYTHON := python
|
|
2
|
+
UV := uv
|
|
3
|
+
|
|
4
|
+
.PHONY: help sync install lint typecheck test check build release-dry
|
|
5
|
+
|
|
6
|
+
help:
|
|
7
|
+
@echo "Available targets:"
|
|
8
|
+
@echo " make install - install all dependencies with uv"
|
|
9
|
+
@echo " make sync - alias for install"
|
|
10
|
+
@echo " make lint - run ruff"
|
|
11
|
+
@echo " make typecheck - run mypy"
|
|
12
|
+
@echo " make test - run pytest"
|
|
13
|
+
@echo " make check - run lint + typecheck + tests"
|
|
14
|
+
@echo " make build - build wheel/sdist"
|
|
15
|
+
@echo " make release-dry - semantic-release dry run (no publish)"
|
|
16
|
+
|
|
17
|
+
install:
|
|
18
|
+
$(UV) sync --all-groups
|
|
19
|
+
|
|
20
|
+
sync: install
|
|
21
|
+
|
|
22
|
+
lint:
|
|
23
|
+
$(UV) run ruff check .
|
|
24
|
+
|
|
25
|
+
typecheck:
|
|
26
|
+
$(UV) run mypy src
|
|
27
|
+
|
|
28
|
+
test:
|
|
29
|
+
$(UV) run pytest
|
|
30
|
+
|
|
31
|
+
check: lint typecheck test
|
|
32
|
+
|
|
33
|
+
build:
|
|
34
|
+
$(UV) build
|
|
35
|
+
|
|
36
|
+
release-dry:
|
|
37
|
+
$(UV) run semantic-release --noop version
|
norbix-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: norbix
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Official Python SDK for Norbix — split API and Hub clients with flat module access.
|
|
5
|
+
Project-URL: Homepage, https://norbix.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/norbix-dev/norbix-python
|
|
7
|
+
Project-URL: Issues, https://github.com/norbix-dev/norbix-python/issues
|
|
8
|
+
Author: UAB Isidos
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: api,baas,hub,norbix,python,sdk
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Requires-Dist: httpx>=0.27.0
|
|
14
|
+
Requires-Dist: pydantic>=2.0
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# norbix-python
|
|
18
|
+
|
|
19
|
+
[](https://github.com/norbix-dev/norbix-python/actions/workflows/ci.yml)
|
|
20
|
+
[](https://pypi.org/project/norbix/)
|
|
21
|
+
[](https://python.org)
|
|
22
|
+
[](./LICENSE)
|
|
23
|
+
|
|
24
|
+
Official Python SDK for [Norbix](https://norbix.dev).
|
|
25
|
+
Use split clients with flat module access:
|
|
26
|
+
|
|
27
|
+
- `NorbixApi` for API scope (`client.database`, `client.membership`, ...)
|
|
28
|
+
- `NorbixHub` for Hub scope (`client.database`, `client.account`, ...)
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv add norbix
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Optional: load `.env` in apps with `python-dotenv` (`load_dotenv()` before constructing `Norbix()`).
|
|
37
|
+
|
|
38
|
+
## Quickstart
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from norbix_python import NorbixApi
|
|
42
|
+
|
|
43
|
+
# Service mode
|
|
44
|
+
norbix = NorbixApi(api_key="<api_key>", project_id="proj_123")
|
|
45
|
+
|
|
46
|
+
norbix.database.find("orders", take=20, skip=0, orderBy=[{"field": "createdAt", "direction": "desc"}])
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
# User mode
|
|
51
|
+
from norbix_python import LoginCredentials, NorbixApi
|
|
52
|
+
|
|
53
|
+
norbix = NorbixApi(project_id="proj_123")
|
|
54
|
+
norbix.login(LoginCredentials(user_name="alice@team.io", password="secret"))
|
|
55
|
+
norbix.database.find("orders", take=10)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Async client
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from norbix_python import AsyncNorbix
|
|
62
|
+
|
|
63
|
+
async def main() -> None:
|
|
64
|
+
async with AsyncNorbix(api_key="...", project_id="proj_123") as client:
|
|
65
|
+
await client.api.echo.echo()
|
|
66
|
+
|
|
67
|
+
# asyncio.run(main())
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Real-world examples
|
|
71
|
+
|
|
72
|
+
### 1) List recent orders (API scope)
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from norbix_python import DatabaseFindResult, NorbixApi, NorbixError
|
|
76
|
+
|
|
77
|
+
norbix = NorbixApi(api_key="sk_live_xxx", project_id="proj_123")
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
raw = norbix.database.find("orders", take=20, skip=0, orderBy=[{"field": "createdAt", "direction": "desc"}])
|
|
81
|
+
typed = DatabaseFindResult.model_validate(raw) if isinstance(raw, dict) else DatabaseFindResult()
|
|
82
|
+
items = typed.results
|
|
83
|
+
print(f"Fetched {len(items)} orders")
|
|
84
|
+
except NorbixError as exc:
|
|
85
|
+
print(exc.code, exc.status, exc.message)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2) Login as user and load profile
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from norbix_python import LoginCredentials, NorbixApi
|
|
92
|
+
|
|
93
|
+
norbix = NorbixApi(project_id="proj_123")
|
|
94
|
+
|
|
95
|
+
auth = norbix.login(LoginCredentials(user_name="alice@team.io", password="secret"))
|
|
96
|
+
print("Logged in, token prefix:", str(auth.get("bearerToken", ""))[:16])
|
|
97
|
+
|
|
98
|
+
users = norbix.membership.get_users()
|
|
99
|
+
print("Users response:", users)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3) Account-scoped Hub call (requires account_id)
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from norbix_python import NorbixHub
|
|
106
|
+
|
|
107
|
+
norbix = NorbixHub(
|
|
108
|
+
api_key="sk_live_xxx",
|
|
109
|
+
project_id="proj_123",
|
|
110
|
+
account_id="acc_456", # required for account-scoped endpoints
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
account = norbix.hub.account.get_account_profile()
|
|
114
|
+
print(account)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Breaking changes (recent major-style refresh)
|
|
118
|
+
|
|
119
|
+
- Methods use **snake_case** (`find_one`, `get_database_schemas`) instead of camelCase.
|
|
120
|
+
- Path parameters are **positional or keyword** arguments (for example `find("orders", ...)`,
|
|
121
|
+
`find_one("orders", id)`). Remaining query/body fields are passed as keyword args.
|
|
122
|
+
- Use **typed errors** where helpful: `AuthenticationError`, `NotFoundError`, `RateLimitError`,
|
|
123
|
+
`ValidationError` (all subclass `NorbixError`).
|
|
124
|
+
|
|
125
|
+
## Authentication
|
|
126
|
+
|
|
127
|
+
- API key: set `api_key` or `NORBIX_API_KEY`
|
|
128
|
+
- JWT bearer: set `bearer_token`, `NORBIX_BEARER_TOKEN`, or call `norbix.login(...)`
|
|
129
|
+
- If both are configured, bearer token wins
|
|
130
|
+
- If neither is configured, SDK raises `NORBIX_NOT_AUTHENTICATED`
|
|
131
|
+
|
|
132
|
+
API keys and JWTs are sent as `Authorization: Bearer ...` (document your backend expectations).
|
|
133
|
+
|
|
134
|
+
## Configuration from environment
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
NORBIX_API_KEY=sk_live_...
|
|
138
|
+
NORBIX_PROJECT_ID=proj_123
|
|
139
|
+
NORBIX_ACCOUNT_ID=acc_456
|
|
140
|
+
NORBIX_API_URL=https://api.norbix.ai
|
|
141
|
+
NORBIX_HUB_URL=https://hub.norbix.ai
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
norbix = NorbixApi() # reads from environment when values omitted
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Project vs account scope
|
|
149
|
+
|
|
150
|
+
- `project_id` is required (set explicitly or via env).
|
|
151
|
+
- `account_id` is optional
|
|
152
|
+
- Account-scoped Hub methods raise `NORBIX_ACCOUNT_SCOPE_REQUIRED` if `account_id` is not configured
|
|
153
|
+
|
|
154
|
+
## SDK maintenance
|
|
155
|
+
|
|
156
|
+
Regenerate API and Hub modules from DTO stubs:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
uv run python scripts/generate_endpoints.py
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This refreshes `src/norbix_python/api/`, `hub/`, matching tests under `tests/api` and `tests/hub`, and docs under `docs/`.
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
uv sync
|
|
168
|
+
uv run ruff check .
|
|
169
|
+
uv run mypy src
|
|
170
|
+
uv run pytest
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Releases
|
|
174
|
+
|
|
175
|
+
Pushes to `main`, `next`, and `beta` run
|
|
176
|
+
[python-semantic-release](https://python-semantic-release.readthedocs.io/)
|
|
177
|
+
and publish to PyPI.
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT
|