feat: initial Python SDK workspace - #1
Conversation
First PR for this repo. Moves the Python Platform SDK out of the
firstlanding monorepo and wires it to regenerate via the now-standalone
@archastro/sdk-generator and @archastro/channel-harness tools published
on npmjs.com.
Layout:
src/archastro/ Generated SDK: Pydantic models, resources,
channel classes, auth helpers. Produced by
scripts/regenerate_sdk.sh — DO NOT hand-edit.
src/phx_channel/ Hand-written Phoenix Channels client the
generated channel classes run on top of:
Socket, Channel, HarnessServiceClient, plus
pure-unit tests.
specs/ Local copy of platform-openapi.json pulled
from ArchAstro/archastro-openapi.
tests/ test_http_client.py (unit), harness/ (drives
@archastro/channel-harness with the LiveDoc
fixture), contract/ (generated REST + channel
contract suites).
Regeneration
scripts/regenerate_sdk.sh curls the spec from archastro-openapi@main
(overridable with ARCHASTRO_OPENAPI_REF) and runs npx
@archastro/sdk-generator for both the SDK and contract-test tree,
then applies ruff --fix + ruff format so the committed output matches
CI's style gate. Tool version overridable via ARCHASTRO_SDK_GENERATOR.
JS tooling deps (for contract tests to spawn the harness and Prism):
@archastro/channel-harness@^0.1.0
@stoplight/prism-cli@5.14.2 (pinned — 5.15.x ships broken tarballs)
overrides pin the prism-core / prism-http trio to working versions so
a fresh `npm ci` doesn't pull the broken 5.15 deps.
CI (Python 3.11 + 3.12 matrix): ruff check, ruff format --check, unit
tests, harness-client integration tests, REST+channel contract tests
over a real channel-harness subprocess.
Dropped from the firstlanding copy
- tests/test_synthetic.py and tests/conftest.py — depended on a
running local platform-rs for credentials bootstrap.
- src/phx_channel/tests/test_channel.py and its conftest — depended
on an Elixir Phoenix test server at src/elixir/test/channel_test_server.
The same channel wire contract is exercised by tests/harness/ and
tests/contract/channels/ through the npm-installed channel-harness.
- aster.toml — firstlanding-internal.
Local verification
49 non-contract tests pass (http_client unit, phx_channel unit,
harness-client integration); 641 contract tests pass including the
three channel contract suites over a real WebSocket + HTTP harness
subprocess; ruff clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|
||
| self._state = "joining" | ||
| ref = self._socket._make_ref() | ||
| self._join_ref = ref |
There was a problem hiding this comment.
asyncio.get_event_loop().create_future() is deprecated since Python 3.10 and raises a DeprecationWarning (eventually a hard error) when called outside a running loop — which can happen in certain test runners and Python 3.12 edge cases; use asyncio.get_running_loop().create_future() here and on the identical call sites at lines 108 and 139.
| return await self._on_refresh_token() # type: ignore[misc] | ||
| finally: | ||
| self._refresh_task = None | ||
|
|
There was a problem hiding this comment.
_refresh_task is nulled in the finally block before all concurrent waiters have latched the result: waiter A and B both await self._refresh_task, but a waiter C that gets a 401 after the finally fires but before A/B retry will see _refresh_task is None and start a second refresh call — defeating the "one refresh at a time" invariant the test suite verifies. Fix: clear _refresh_task only after every pending waiter has resolved (e.g. clear it at the callsite after await self._refresh_task completes, protected by a lock, or store the result before nulling the task).
| .pytest_cache/ | ||
| .ruff_cache/ | ||
| .venv/ | ||
| uv.lock |
There was a problem hiding this comment.
uv.lock is gitignored — every CI run resolves fresh deps, meaning two matrix jobs on the same commit can install different transitive versions and you lose the reproducibility that's the whole point of using uv; commit the lockfile and remove this line.
| uv sync # Python deps + dev deps (pytest, ruff) | ||
| ``` | ||
|
|
||
| ### Running tests |
There was a problem hiding this comment.
src/phx_channel/tests/unit.test.py doesn't exist — the actual file is src/phx_channel/tests/test_unit.py; this command will fail for anyone who copies it.
The `setup-uv` action's default cache key is `**/uv.lock`; without a committed lockfile the first step fails with "No matches found for glob". Committing the lock is also standard practice for a uv-managed library repo — CI gets reproducible installs and dep changes show up in PR diffs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fresh-start rename — ship as archastro-sdk 0.1.0 rather than inheriting archastro-platform-sdk 0.77.0 from the firstlanding import. These changes were on feat/initial-setup but got left behind when PR #1 merged; rebasing onto main now that PR #2's flake fix is in. - pyproject.toml: name → archastro-sdk, version → 0.1.0 - scripts/sdk-generator-config.json: matches - README: pip install archastro-sdk - src/archastro/platform/__init__.py: patched to look up \"archastro-sdk\" via importlib.metadata. This file is auto-generated; the generator fix that will make this automatic is ArchAstro/archastro-openapi#4 — once that ships in @archastro/sdk-generator@0.1.1+, future regens produce the right output without patching. - uv.lock: regenerated The Python import path (`archastro`) is unchanged — only the pip-install name and the __version__ lookup key change. Local verification uv run python -c \"import archastro.platform; print(archastro.platform.__version__)\" → 0.1.0 Test suite: 51 non-contract tests + 641 contract tests (incl. channel suites over a real @archastro/channel-harness subprocess) all pass; ruff check + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
First PR for this repo. Moves the Python Platform SDK out of
firstlanding-wt5/src/python/platform-sdkand wires it to regenerate via the now-standalone@archastro/sdk-generatorand@archastro/channel-harnesstools on npmjs.com. Same pattern we landed inarchastro-js.Layout
src/archastro/scripts/regenerate_sdk.sh.src/phx_channel/Socket,Channel,HarnessServiceClient) + unit tests.specs/platform-openapi.jsonArchAstro/archastro-openapi.tests/test_http_client.pyHttpClient401 auto-refresh.tests/harness/HarnessServiceClientagainst a real@archastro/channel-harnesssubprocess using the LiveDoc fixture spec.tests/contract/Regeneration flow
scripts/regenerate_sdk.shcurls the spec fromarchastro-openapi@main(override withARCHASTRO_OPENAPI_REF), runsnpx @archastro/sdk-generator@latestfor both--lang pythonand--lang contract-tests-py, then appliesruff --fix+ruff formatso the committed output matches CI's style gate.ARCHASTRO_SDK_GENERATORenv var pins the generator version for release branches.JS tooling deps
Contract tests spawn Node subprocesses, so the repo carries a
package.json:@archastro/channel-harness@^0.1.0— the harness subprocess@stoplight/prism-cli@5.14.2— Prism mock server for REST contract tests. Pinned to 5.14.2 because 5.15.x ships broken tarballs withoutdist/. Also usesoverridesto pin@stoplight/prism-core/prism-http/prism-http-serverto known-good versions so a freshnpm cidoesn't pull the broken 5.15 peers.CI
Matrix on Python 3.11 + 3.12:
npm ci(channel-harness + prism)uv sync --all-extrasruff checkruff format --checkARCHASTRO_RUN_CHANNEL_CONTRACT_TESTS=1— real harness subprocess over WebSocket + HTTPDropped from the firstlanding copy
tests/test_synthetic.pyandtests/conftest.py— needed a running localplatform-rsfor credentials bootstrap.src/phx_channel/tests/test_channel.pyand its conftest — needed an Elixir Phoenix test server atsrc/elixir/test/channel_test_server. The same wire contract is exercised bytests/harness/andtests/contract/channels/through the published@archastro/channel-harness.aster.toml— firstlanding-internal.Scope / risk
Full-stack new repo, no consumers yet. Low risk. The firstlanding copy is untouched; when the consumer cutover lands, the old tree can be retired.
Testing
uv run pytest tests/test_http_client.py src/phx_channel/tests/test_unit.py tests/harness→ 49 passedARCHASTRO_RUN_CHANNEL_CONTRACT_TESTS=1 uv run pytest tests/contract→ 641 passed (incl. all 3 channel contract suites over a real harness subprocess)uv run ruff check && uv run ruff format --check→ cleanFollow-ups
archastro-platform-sdkto PyPI (first release from this repo:0.77.0).src/python/platform-sdk/in firstlanding-wt5 once downstream consumers are cut over.🤖 Generated with Claude Code