refactor!: generate the Client API models from the OpenAPI spec#2
Merged
Conversation
…t_id} Every authenticated Lunogram Client API endpoint is now scoped to a project. The project UUID is supplied once when constructing the client and is injected into every Client API path as a `/projects/<project_id>/` segment; callers no longer pass it per request. BREAKING CHANGE: `Lunogram(api_key)` becomes `Lunogram(api_key, project_id)`. Auth is unchanged (same API key / token); only the URL gains the project. - client.py: add required `project_id`, build a project-scoped reference and thread it through `user`/`organization`. - utils/reference.py: turn the path reference into a project-scoped factory (validates non-empty UUID); add inbox/devices/push/auth-method-session paths. - app/objects.py and app/models/**: accept and use the injected reference. - README: document construction with the project and the new URLs.
Migrate the SDK to spec-driven code generation with a layered design: the low-level model layer is generated from the vendored OpenAPI spec, while the public facade (Lunogram, the project-scoped path factory, UUID validation, auth header, transport) stays hand-written and unchanged. - Vendor spec/client.yaml from the platform repo at a pinned commit; spec/SOURCE.md records repo, path and ref. - Generate src/lunogram/gen/models.py with datamodel-code-generator (Pydantic v2). scripts/generate.sh + `make generate` are the single source of truth for generator flags; the generator is pinned in the dev extra. - Wire the generated models into the facade as request-body types; Python is snake_case end-to-end so models flow through with no key-mapping layer. Methods accept a model or a plain dict. - Remove the dead, broken hand-written app/types/** and app/models/** duplicates that the generated models replace. - CI: ci.yml regenerates + drift-checks src/lunogram/gen, builds the wheel, import-smoke-tests and runs pytest; spec-sync.yml re-fetches the spec weekly and opens a PR on change. - Add pytest smoke tests for the path factory, UUID validation and model serialization. The public API is unchanged from the project-in-URL PR.
…cade Wire the remaining Client API endpoints into the hand-written facade on top of the generated models: - user & organization inbox (create, query, count, mark_read, mark_archived) - user device registration for push subscriptions - project VAPID public key (client.push) - end-user session token minting (client.sessions) - organization membership (organization.add_user / remove_user) Also fix two transport bugs surfaced by the wider surface: - send the Authorization header as a Bearer token (was the bare key) - treat an empty 2xx body (202/204) as success instead of a JSON error Pin the vendored spec to the v0.1.0-rc.1 release asset and drop the spec-sync workflow.
Mirror the JS SDK's e2e coverage (users, organizations, events, scheduled, membership, cleanup) against a real Client API. The suite is skipped unless LUNOGRAM_API_KEY + LUNOGRAM_PROJECT_ID are set, so the offline unit run stays green; the new e2e.yml workflow supplies the secrets on push. Add an optional `url_endpoint` override (Lunogram(api_key, project_id, url_endpoint=...)) so the suite can target the configured environment — the same role as the JS SDK's `urlEndpoint`. Building the base URL from it also removes the long-standing double slash after the host.
Accept url_endpoint with or without a trailing /api and always re-add it, matching the JS SDK. Without this, an endpoint lacking /api built paths that missed the API prefix and hit the frontend catch-all (200 HTML), which the e2e suite surfaced.
Extend test_facade.py with mocked coverage for the core methods that were only exercised live (user/org CRUD, events, scheduled, org inbox writes), plus model-vs-dict body acceptance and the empty-2xx (202/204) success path so it is not mistaken for an error tuple.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Migrates the Python SDK to the spec-driven pattern shared across the Lunogram SDKs (mirrors
go-sdk/js-sdk): the model layer is generated from the platform's OpenAPI spec and a thin hand-written facade keeps the ergonomic, namespaced API.This PR supersedes and folds in #1 (require
project_id+ move the Client API under/projects/{project_id}).What's here
spec/client.yamlis vendored from the platformv0.1.0-rc.1release asset;src/lunogram/gen/models.pyis generated from it withdatamodel-code-generator(Pydantic v2) viamake generate. Python is snake_case end-to-end, matching the spec, so models flow straight to the request body with no key-mapping layer. Every method accepts either a generated model or a plain dict.project_id—Lunogram(api_key, project_id); the UUID is validated and injected into every path under/api/client/projects/{project_id}/....client.user.devices.register)client.push.get_vapid_public_key)client.sessions.create)organization.add_user/remove_user)Authorization: Bearer <token>(was the bare key — would have 401'd)Supersedes
Notes
spec-syncbot workflow is included; bumping the spec is a manual edit tospec/SOURCE.md+make generate.make generate(no drift),python -m build, andpytest(36 tests) all pass.