fastapi-streams 0.0.1__tar.gz → 0.2.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.
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.github/workflows/ci.yml +10 -5
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.github/workflows/compatibility.yml +9 -5
- fastapi_streams-0.2.0/.github/workflows/release.yml +115 -0
- fastapi_streams-0.2.0/CHANGELOG.md +136 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/PKG-INFO +13 -8
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/README.md +9 -4
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/README.md +2 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/clients.md +52 -2
- fastapi_streams-0.2.0/docs/codegen.md +156 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/development.md +1 -0
- fastapi_streams-0.2.0/docs/native-transports.md +49 -0
- fastapi_streams-0.2.0/docs/releasing.md +13 -0
- fastapi_streams-0.2.0/examples/agent_runs/errors.py +37 -0
- fastapi_streams-0.2.0/examples/agent_runs/errors.ts +44 -0
- fastapi_streams-0.2.0/examples/agent_runs/generated/agent-runs/api.ts +89 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/index.ts +1 -1
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/transport/errors.ts +11 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/types.ts +16 -16
- fastapi_streams-0.2.0/examples/agent_runs/generated_python/agent_runs/api.py +92 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/models.py +7 -1
- {fastapi_streams-0.0.1/tests/fixtures → fastapi_streams-0.2.0/examples/agent_runs}/generated_python/runtime.py +27 -0
- fastapi_streams-0.2.0/examples/native_proxy.py +99 -0
- fastapi_streams-0.2.0/examples/rest_codegen.py +76 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/__init__.py +1 -1
- fastapi_streams-0.2.0/fastapi_streams/codegen/diagnostics.py +83 -0
- fastapi_streams-0.2.0/fastapi_streams/codegen/documentation.py +66 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/enums.py +4 -4
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/ir.py +83 -5
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/python.py +63 -8
- {fastapi_streams-0.0.1/tests/fixtures/generated/transport → fastapi_streams-0.2.0/fastapi_streams/codegen/templates}/errors.ts +11 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/python/api.py.j2 +5 -0
- {fastapi_streams-0.0.1/examples/agent_runs/generated_python → fastapi_streams-0.2.0/fastapi_streams/codegen/templates/python}/runtime.py +27 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/typescript/api.ts.j2 +9 -1
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/typescript.py +23 -11
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/pyproject.toml +6 -5
- fastapi_streams-0.2.0/scripts/check_release.py +69 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/smoke_package.py +38 -6
- fastapi_streams-0.2.0/tests/codegen/test_diagnostics.py +64 -0
- fastapi_streams-0.2.0/tests/codegen/test_documentation.py +52 -0
- fastapi_streams-0.2.0/tests/codegen/test_error_contracts.py +149 -0
- fastapi_streams-0.2.0/tests/codegen/test_literal_fields.py +103 -0
- fastapi_streams-0.2.0/tests/codegen/test_native_contract.py +56 -0
- fastapi_streams-0.2.0/tests/codegen/test_scalar_constraints.py +65 -0
- fastapi_streams-0.2.0/tests/codegen/test_unknown_events.py +83 -0
- fastapi_streams-0.2.0/tests/fixtures/generated/fixtures/api.ts +51 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/index.ts +1 -1
- {fastapi_streams-0.0.1/fastapi_streams/codegen/templates → fastapi_streams-0.2.0/tests/fixtures/generated/transport}/errors.ts +11 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/types.ts +16 -16
- fastapi_streams-0.2.0/tests/fixtures/generated_python/fixtures/api.py +54 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/models.py +2 -0
- {fastapi_streams-0.0.1/fastapi_streams/codegen/templates/python → fastapi_streams-0.2.0/tests/fixtures/generated_python}/runtime.py +27 -0
- fastapi_streams-0.2.0/tests/test_release.py +119 -0
- fastapi_streams-0.2.0/tests/typescript/errors.test.ts +69 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/tsconfig.json +1 -1
- fastapi_streams-0.0.1/docs/codegen.md +0 -80
- fastapi_streams-0.0.1/examples/agent_runs/generated/agent-runs/api.ts +0 -49
- fastapi_streams-0.0.1/examples/agent_runs/generated_python/agent_runs/api.py +0 -54
- fastapi_streams-0.0.1/tests/fixtures/generated/fixtures/api.ts +0 -31
- fastapi_streams-0.0.1/tests/fixtures/generated_python/fixtures/api.py +0 -35
- fastapi_streams-0.0.1/uv.lock +0 -1218
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.gitattributes +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.gitignore +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.pre-commit-config.yaml +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/AGENTS.md +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/LICENSE +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/architecture.md +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/quickstart.md +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/consume.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/consume.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/.fastapi-streams.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/agent-runs/index.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/client.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/transport/sse.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/.fastapi-streams.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/agent_runs/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/client.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/py.typed +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/cli.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/names.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/openapi.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/schemas/LICENSE +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/schemas/README.md +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/schemas/openapi-3.2.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/python/client.py.j2 +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/sse.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/typescript/client.ts.j2 +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templating.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/writer.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/py.typed +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/router.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/package-lock.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/package.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/check_package.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/codegen.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/test_compat.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/helpers.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_additional_properties.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_codegen.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_contract_boundaries.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_discriminators.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_field_names.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_http_backends.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_intersections.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_nested_models.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_python_client.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_python_typing.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_required_properties.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_schema_matrix.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/contracts/test_openapi.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/README.md +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/agent_runs.openapi.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/compat-client.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/.fastapi-streams.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/client.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/fixtures/index.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/transport/sse.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/.fastapi-streams.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/client.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/fixtures/__init__.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/py.typed +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/integration_app.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/models.openapi.json +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/models_app.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/integration/test_end_to_end.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/router/test_router.py +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/live-client.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/models.test.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/narrowing.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/sse.test.ts +0 -0
- {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typing/client_usage.py +0 -0
|
@@ -2,7 +2,9 @@ name: CI
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
+
branches: ["**"]
|
|
5
6
|
pull_request:
|
|
7
|
+
workflow_call:
|
|
6
8
|
|
|
7
9
|
permissions:
|
|
8
10
|
contents: read
|
|
@@ -16,15 +18,17 @@ jobs:
|
|
|
16
18
|
matrix:
|
|
17
19
|
python: ["3.12", "3.13", "3.14"]
|
|
18
20
|
steps:
|
|
19
|
-
- uses: actions/checkout@v4
|
|
20
|
-
|
|
21
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
21
25
|
with:
|
|
22
26
|
python-version: ${{ matrix.python }}
|
|
23
|
-
- uses: actions/setup-node@v4
|
|
27
|
+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
24
28
|
with:
|
|
25
29
|
node-version: "24"
|
|
26
30
|
cache: npm
|
|
27
|
-
- uses: astral-sh/setup-uv@v6
|
|
31
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
|
|
28
32
|
with:
|
|
29
33
|
version: "0.9.2"
|
|
30
34
|
enable-cache: true
|
|
@@ -38,7 +42,7 @@ jobs:
|
|
|
38
42
|
- run: npm run typecheck
|
|
39
43
|
- run: npm run test:coverage
|
|
40
44
|
- run: uv run pytest -q --cov --cov-report=term-missing --cov-report=xml:coverage-python.xml
|
|
41
|
-
- uses: actions/upload-artifact@v4
|
|
45
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
42
46
|
if: always()
|
|
43
47
|
with:
|
|
44
48
|
name: coverage-python-${{ matrix.python }}
|
|
@@ -47,4 +51,5 @@ jobs:
|
|
|
47
51
|
coverage-typescript.lcov
|
|
48
52
|
- run: uv run python scripts/codegen.py --check
|
|
49
53
|
- run: uv build
|
|
54
|
+
- run: uv run --frozen twine check --strict dist/*
|
|
50
55
|
- run: uv run python scripts/check_package.py
|
|
@@ -2,7 +2,9 @@ name: Dependency compatibility
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
+
branches: ['**']
|
|
5
6
|
pull_request:
|
|
7
|
+
workflow_call:
|
|
6
8
|
workflow_dispatch:
|
|
7
9
|
schedule:
|
|
8
10
|
- cron: '17 7 * * 1'
|
|
@@ -22,22 +24,24 @@ jobs:
|
|
|
22
24
|
python: ['3.12', '3.13', '3.14']
|
|
23
25
|
dependencies: [lowest, latest]
|
|
24
26
|
steps:
|
|
25
|
-
- uses: actions/checkout@v4
|
|
26
|
-
|
|
27
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
28
|
+
with:
|
|
29
|
+
persist-credentials: false
|
|
30
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
27
31
|
with:
|
|
28
32
|
python-version: ${{ matrix.python }}
|
|
29
|
-
- uses: actions/setup-node@v4
|
|
33
|
+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
30
34
|
with:
|
|
31
35
|
node-version: '24'
|
|
32
36
|
cache: npm
|
|
33
|
-
- uses: astral-sh/setup-uv@v6
|
|
37
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
|
|
34
38
|
with:
|
|
35
39
|
version: '0.9.2'
|
|
36
40
|
enable-cache: true
|
|
37
41
|
- run: npm ci --ignore-scripts
|
|
38
42
|
- name: Resolve dependencies and run native FastAPI and client integration tests
|
|
39
43
|
run: python scripts/test_compat.py --python ${{ matrix.python }} --dependencies ${{ matrix.dependencies }}
|
|
40
|
-
- uses: actions/upload-artifact@v4
|
|
44
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
41
45
|
if: always()
|
|
42
46
|
with:
|
|
43
47
|
name: compatibility-${{ matrix.os }}-${{ matrix.python }}-${{ matrix.dependencies }}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ['v*']
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: release-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
validate:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
timeout-minutes: 5
|
|
18
|
+
outputs:
|
|
19
|
+
version: ${{ steps.version.outputs.version }}
|
|
20
|
+
prerelease: ${{ steps.version.outputs.prerelease }}
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: '3.12'
|
|
29
|
+
- name: Validate tag, versions and main ancestry
|
|
30
|
+
id: version
|
|
31
|
+
env:
|
|
32
|
+
RELEASE_TAG: ${{ github.ref_name }}
|
|
33
|
+
run: python scripts/check_release.py "$RELEASE_TAG" >> "$GITHUB_OUTPUT"
|
|
34
|
+
|
|
35
|
+
ci:
|
|
36
|
+
needs: validate
|
|
37
|
+
uses: ./.github/workflows/ci.yml
|
|
38
|
+
|
|
39
|
+
compatibility:
|
|
40
|
+
needs: validate
|
|
41
|
+
uses: ./.github/workflows/compatibility.yml
|
|
42
|
+
|
|
43
|
+
build:
|
|
44
|
+
needs: [validate, ci, compatibility]
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
timeout-minutes: 15
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
49
|
+
with:
|
|
50
|
+
persist-credentials: false
|
|
51
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
52
|
+
with:
|
|
53
|
+
python-version: '3.12'
|
|
54
|
+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
55
|
+
with:
|
|
56
|
+
node-version: '24'
|
|
57
|
+
cache: npm
|
|
58
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
|
|
59
|
+
with:
|
|
60
|
+
version: '0.9.2'
|
|
61
|
+
- run: uv sync --locked --all-extras
|
|
62
|
+
- run: npm ci --ignore-scripts
|
|
63
|
+
# Build the wheel from the sdist, including packaged templates and schemas.
|
|
64
|
+
- run: uv build --no-sources
|
|
65
|
+
- run: uv run --frozen twine check --strict dist/*
|
|
66
|
+
- run: uv run --frozen python scripts/check_package.py
|
|
67
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
68
|
+
with:
|
|
69
|
+
name: release-distributions
|
|
70
|
+
path: |
|
|
71
|
+
dist/*.whl
|
|
72
|
+
dist/*.tar.gz
|
|
73
|
+
if-no-files-found: error
|
|
74
|
+
retention-days: 30
|
|
75
|
+
|
|
76
|
+
publish:
|
|
77
|
+
needs: build
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
timeout-minutes: 10
|
|
80
|
+
environment:
|
|
81
|
+
name: pypi
|
|
82
|
+
url: https://pypi.org/p/fastapi-streams
|
|
83
|
+
permissions:
|
|
84
|
+
id-token: write
|
|
85
|
+
steps:
|
|
86
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
87
|
+
with:
|
|
88
|
+
name: release-distributions
|
|
89
|
+
path: dist/
|
|
90
|
+
- name: Publish to PyPI with Trusted Publishing and attestations
|
|
91
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
92
|
+
with:
|
|
93
|
+
attestations: true
|
|
94
|
+
|
|
95
|
+
github-release:
|
|
96
|
+
needs: [validate, publish]
|
|
97
|
+
runs-on: ubuntu-latest
|
|
98
|
+
timeout-minutes: 5
|
|
99
|
+
permissions:
|
|
100
|
+
contents: write
|
|
101
|
+
steps:
|
|
102
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
103
|
+
with:
|
|
104
|
+
name: release-distributions
|
|
105
|
+
path: dist/
|
|
106
|
+
- name: Create GitHub Release with the published distributions
|
|
107
|
+
env:
|
|
108
|
+
GH_TOKEN: ${{ github.token }}
|
|
109
|
+
GH_REPO: ${{ github.repository }}
|
|
110
|
+
RELEASE_TAG: ${{ github.ref_name }}
|
|
111
|
+
PRERELEASE: ${{ needs.validate.outputs.prerelease }}
|
|
112
|
+
run: |
|
|
113
|
+
gh release create "$RELEASE_TAG" dist/* \
|
|
114
|
+
--verify-tag --generate-notes --title "$RELEASE_TAG" \
|
|
115
|
+
--prerelease="$PRERELEASE"
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes and consumer upgrade steps are recorded here. Entries marked
|
|
4
|
+
unreleased describe prepared source versions that have not been published.
|
|
5
|
+
|
|
6
|
+
## 0.2.0 - 2026-10-18
|
|
7
|
+
|
|
8
|
+
- Source preparation passed workspace CI, independent wheel matrices and the
|
|
9
|
+
package release dry run. See the [release preparation evidence](../../docs/releases.md#verified-follow-up-preparation-2026-10-18).
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Preserve supported string patterns/lengths and numeric bounds/multiples in the
|
|
14
|
+
codegen IR and generated Python Pydantic annotations, including nested and
|
|
15
|
+
referenced scalars. Diagnose unsupported constraints and regex expressions.
|
|
16
|
+
- Add `RequestOptions(unknown_events="ignore")` to generated Python SDKs. It
|
|
17
|
+
skips unknown string tags in a top-level discriminated event union; the default
|
|
18
|
+
remains an error. Malformed known events, missing tags and invalid JSON fail.
|
|
19
|
+
Both HTTPX backends retain their validation and transport behavior.
|
|
20
|
+
- Add tested contract-first native proxy and private OpenAPI 3.1 REST-codegen
|
|
21
|
+
recipes. The authoritative OpenAPI 3.2 artifact remains unchanged.
|
|
22
|
+
|
|
23
|
+
### Breaking generated-code changes
|
|
24
|
+
|
|
25
|
+
- Regenerated Python models enforce scalar rules that 0.1.0 silently dropped.
|
|
26
|
+
Fix invalid payloads before adopting the new SDK. Unsupported constraints emit
|
|
27
|
+
`UnsupportedConstraintWarning`; constraints alongside enum/const/composition
|
|
28
|
+
and unsupported Python regex patterns fail explicitly. Move supported scalar
|
|
29
|
+
constraints onto scalar branches where possible. This is not full JSON Schema
|
|
30
|
+
validation. TypeScript remains static-only.
|
|
31
|
+
- Regenerate committed SDKs and run consumer validation tests. Pass HTTPX2
|
|
32
|
+
generation/check options consistently if used. No wire names change.
|
|
33
|
+
|
|
34
|
+
### Upgrade from 0.1.0
|
|
35
|
+
|
|
36
|
+
1. Update `fastapi-streams[codegen]` to 0.2.0 and regenerate both SDKs from the
|
|
37
|
+
authoritative OpenAPI document. Keep the selected Python HTTP backend on
|
|
38
|
+
generation and check commands.
|
|
39
|
+
2. Fix data violating preserved scalar constraints and review all unsupported-rule
|
|
40
|
+
diagnostics. Re-run consuming client validation and stream tests.
|
|
41
|
+
3. Keep the default unknown-event error policy, or opt in per request only where
|
|
42
|
+
the upstream intentionally emits additional top-level discriminator values.
|
|
43
|
+
|
|
44
|
+
### Release verification
|
|
45
|
+
|
|
46
|
+
- Extend installed-wheel HTTPX/HTTPX2 smoke consumers to verify scalar constraints,
|
|
47
|
+
default unknown-event rejection, opt-in skipping and malformed known events.
|
|
48
|
+
|
|
49
|
+
### Documentation
|
|
50
|
+
|
|
51
|
+
- Fix PyPI installation instructions and supported-scope wording. Replace the
|
|
52
|
+
predecessor release guide with the workspace release process.
|
|
53
|
+
|
|
54
|
+
## 0.1.0 - 2026-10-17
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- Generated TypeScript JSDoc and Python method docstrings include OpenAPI
|
|
59
|
+
summaries, descriptions, deprecation, and SDK-specific iteration, cancellation,
|
|
60
|
+
validation, and error behavior. Endpoint descriptions remain the source for
|
|
61
|
+
business guarantees such as retention or job lifetime after disconnect.
|
|
62
|
+
- `OptionalDiscriminatorWarning` identifies optional discriminator fields in
|
|
63
|
+
stream event unions, including nested and referenced events. Diagnostics name
|
|
64
|
+
the operation, route, model, and field; generation preserves schema requiredness.
|
|
65
|
+
- Explicit `OperationErrorBody` aliases in both SDKs distinguish declared HTTP
|
|
66
|
+
response bodies from thrown exceptions. Existing `OperationError` aliases remain
|
|
67
|
+
available; TypeScript marks them deprecated. Method documentation lists the
|
|
68
|
+
declared HTTP statuses and media types. Existing Python anonymous error-model
|
|
69
|
+
imports such as `OperationError0` retain their names.
|
|
70
|
+
- TypeScript `isHttpError(error, isDetails)` narrows `HttpError.details` only after
|
|
71
|
+
a caller-supplied type guard succeeds. It adds no runtime dependencies or assumed
|
|
72
|
+
problem format. HTTP status and operation provenance remain caller checks.
|
|
73
|
+
- Checked TypeScript and Python error-handling consumer examples, plus a
|
|
74
|
+
standalone FastAPI dependency/problem-response regression without an error
|
|
75
|
+
framework. Public generated error-alias name collisions now fail explicitly.
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
- Develop in `mathisarends/canon`; package source, documentation, and issue URLs
|
|
80
|
+
now point to the monorepo.
|
|
81
|
+
- Single-value string fields now use TypeScript/Python literals instead of
|
|
82
|
+
synthesizing a separate public constant object or `StrEnum` for every field.
|
|
83
|
+
Explicitly named enums, multi-value field enums, and shared event discriminator
|
|
84
|
+
enums remain available. TypeScript also omits unnecessary property quotes and
|
|
85
|
+
union parentheses while preserving intersection grouping and extra-field types.
|
|
86
|
+
|
|
87
|
+
### Breaking generated-code changes
|
|
88
|
+
|
|
89
|
+
- Synthesized single-field constants such as `InvalidCredentialsProblemTitle`
|
|
90
|
+
and `InvalidCredentialsProblemType` are no longer exported. Replace usages like
|
|
91
|
+
`InvalidCredentialsProblemTitle.INVALID_CREDENTIALS` with the wire literal
|
|
92
|
+
`"Invalid credentials"`, then remove unused imports. Python singleton fields
|
|
93
|
+
now contain plain strings instead of generated `StrEnum` members; replace
|
|
94
|
+
identity checks with value comparisons. Shared discriminator values such as
|
|
95
|
+
`RunEventType.RUN_STARTED` and explicit schema enums are unchanged.
|
|
96
|
+
- Generated `OperationError`/`OperationErrorBody` names are reserved in both
|
|
97
|
+
SDKs. Python now reports collisions explicitly too. If a schema uses one of
|
|
98
|
+
these names, rename the colliding model or choose a distinct `operation_id`.
|
|
99
|
+
|
|
100
|
+
### Upgrade from 0.0.1
|
|
101
|
+
|
|
102
|
+
1. Update `fastapi-streams[codegen]` to `0.1.0`, using the same version for schema
|
|
103
|
+
export and both SDKs.
|
|
104
|
+
2. Regenerate committed clients from the application's OpenAPI document. Existing
|
|
105
|
+
method names and call signatures are unchanged:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
uv run fastapi-streams schema --app your_app:app --output openapi.json
|
|
109
|
+
uv run fastapi-streams generate --schema openapi.json --language typescript --output generated/typescript
|
|
110
|
+
uv run fastapi-streams generate --schema openapi.json --language python --output generated/python
|
|
111
|
+
uv run fastapi-streams check --app your_app:app --schema openapi.json --language typescript --output generated/typescript
|
|
112
|
+
uv run fastapi-streams check --app your_app:app --schema openapi.json --language python --output generated/python
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Substitute the application's existing module and output paths. Preserve
|
|
116
|
+
`--python-http-client httpx2` on generation and checks if it is already used.
|
|
117
|
+
3. Review optional discriminator warnings. For output-only Pydantic event models
|
|
118
|
+
whose defaults are always serialized, see the serialization configuration in
|
|
119
|
+
[the codegen guide](docs/codegen.md#event-discriminators). Do not make optional
|
|
120
|
+
request fields required merely because they have Python defaults. Add
|
|
121
|
+
endpoint-specific guarantees to OpenAPI descriptions. Export and regenerate
|
|
122
|
+
again after changing models or descriptions.
|
|
123
|
+
4. Apply the single-field constant migration above if the application imported
|
|
124
|
+
these generated names. HTTP payloads, method names, and signatures are unchanged.
|
|
125
|
+
5. Prefer `OperationErrorBody` over `OperationError` when referring to response
|
|
126
|
+
bodies. Keep caught errors unknown until checked; validate `HttpError.details`
|
|
127
|
+
with a body guard in TypeScript or Pydantic `TypeAdapter` in Python. See
|
|
128
|
+
[HTTP error contracts](docs/clients.md#http-error-contracts). Unexpected proxy
|
|
129
|
+
responses must continue through the generic `HttpError` fallback.
|
|
130
|
+
6. Run the consuming project's TypeScript/Python type checks and stream tests.
|
|
131
|
+
Commit the exported schema and regenerated SDKs together with call-site updates.
|
|
132
|
+
|
|
133
|
+
## 0.0.1
|
|
134
|
+
|
|
135
|
+
- Initial typed GET/POST JSON SSE routers, OpenAPI export, TypeScript and Python
|
|
136
|
+
generators, shared transports, and contract/client drift checks.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: fastapi-streams
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Typed FastAPI streams with generated TypeScript and Python clients.
|
|
5
|
-
Project-URL: Documentation, https://github.com/mathisarends/
|
|
6
|
-
Project-URL: Source, https://github.com/mathisarends/fastapi-streams
|
|
7
|
-
Project-URL: Issues, https://github.com/mathisarends/
|
|
5
|
+
Project-URL: Documentation, https://github.com/mathisarends/canon/tree/main/packages/fastapi-streams/docs
|
|
6
|
+
Project-URL: Source, https://github.com/mathisarends/canon/tree/main/packages/fastapi-streams
|
|
7
|
+
Project-URL: Issues, https://github.com/mathisarends/canon/issues
|
|
8
8
|
Author: Mathis Arends
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
@@ -45,10 +45,10 @@ A CI check catches drift between the Python app, the contract, and generated cod
|
|
|
45
45
|
|
|
46
46
|
## 1. Decorate your FastAPI endpoint
|
|
47
47
|
|
|
48
|
-
Install from
|
|
48
|
+
Install from PyPI with the optional codegen extra:
|
|
49
49
|
|
|
50
50
|
```sh
|
|
51
|
-
uv add 'fastapi-streams[codegen]
|
|
51
|
+
uv add 'fastapi-streams[codegen]'
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
Save this as `app.py`:
|
|
@@ -224,6 +224,9 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
|
|
|
224
224
|
|
|
225
225
|
## Documentation
|
|
226
226
|
|
|
227
|
+
See the [changelog and upgrade steps](CHANGELOG.md) when updating the library
|
|
228
|
+
and regenerating committed clients.
|
|
229
|
+
|
|
227
230
|
| Guide | Topics |
|
|
228
231
|
| --- | --- |
|
|
229
232
|
| [Quickstart](docs/quickstart.md) | Setup, event models, and FastAPI integration. |
|
|
@@ -231,8 +234,10 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
|
|
|
231
234
|
| [Client usage](docs/clients.md) | Enums, authentication, cancellation, and errors. |
|
|
232
235
|
| [Architecture](docs/architecture.md) | Native SSE, shared IR, templates, and transports. |
|
|
233
236
|
| [Development](docs/development.md) | Tests, supported scope, and roadmap. |
|
|
237
|
+
| [Releasing](docs/releasing.md) | Tag-based releases and credential-free PyPI publishing. |
|
|
234
238
|
|
|
235
|
-
|
|
236
|
-
contract for your existing REST SDK. See the
|
|
239
|
+
The current release supports GET/POST JSON SSE streams. Ordinary REST endpoints
|
|
240
|
+
stay in the contract for your existing REST SDK. See the
|
|
241
|
+
[supported scope](docs/development.md#supported-scope-and-roadmap).
|
|
237
242
|
|
|
238
243
|
Python 3.12+ · FastAPI 0.143.3+ · Pydantic v2 · [MIT](LICENSE)
|
|
@@ -27,10 +27,10 @@ A CI check catches drift between the Python app, the contract, and generated cod
|
|
|
27
27
|
|
|
28
28
|
## 1. Decorate your FastAPI endpoint
|
|
29
29
|
|
|
30
|
-
Install from
|
|
30
|
+
Install from PyPI with the optional codegen extra:
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
|
-
uv add 'fastapi-streams[codegen]
|
|
33
|
+
uv add 'fastapi-streams[codegen]'
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Save this as `app.py`:
|
|
@@ -206,6 +206,9 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
|
|
|
206
206
|
|
|
207
207
|
## Documentation
|
|
208
208
|
|
|
209
|
+
See the [changelog and upgrade steps](CHANGELOG.md) when updating the library
|
|
210
|
+
and regenerating committed clients.
|
|
211
|
+
|
|
209
212
|
| Guide | Topics |
|
|
210
213
|
| --- | --- |
|
|
211
214
|
| [Quickstart](docs/quickstart.md) | Setup, event models, and FastAPI integration. |
|
|
@@ -213,8 +216,10 @@ and committed OpenAPI regression fixtures in `tests/fixtures/`. Verify all gener
|
|
|
213
216
|
| [Client usage](docs/clients.md) | Enums, authentication, cancellation, and errors. |
|
|
214
217
|
| [Architecture](docs/architecture.md) | Native SSE, shared IR, templates, and transports. |
|
|
215
218
|
| [Development](docs/development.md) | Tests, supported scope, and roadmap. |
|
|
219
|
+
| [Releasing](docs/releasing.md) | Tag-based releases and credential-free PyPI publishing. |
|
|
216
220
|
|
|
217
|
-
|
|
218
|
-
contract for your existing REST SDK. See the
|
|
221
|
+
The current release supports GET/POST JSON SSE streams. Ordinary REST endpoints
|
|
222
|
+
stay in the contract for your existing REST SDK. See the
|
|
223
|
+
[supported scope](docs/development.md#supported-scope-and-roadmap).
|
|
219
224
|
|
|
220
225
|
Python 3.12+ · FastAPI 0.143.3+ · Pydantic v2 · [MIT](LICENSE)
|
|
@@ -7,8 +7,10 @@ TypeScript Fetch and Python HTTPX clients from the same definitions.
|
|
|
7
7
|
| --- | --- |
|
|
8
8
|
| [Quickstart](quickstart.md) | Run the complete example and define your first stream. |
|
|
9
9
|
| [Contracts and codegen](codegen.md) | Export OpenAPI, generate both clients, and detect drift in CI. |
|
|
10
|
+
| [Native transports](native-transports.md) | Existing SSE proxies, contract-first generation and private REST codegen views. |
|
|
10
11
|
| [Client usage](clients.md) | Named event values, typed iteration, authentication, cancellation, and errors. |
|
|
11
12
|
| [Development](development.md) | Local checks, test coverage, supported features, and roadmap. |
|
|
13
|
+
| [Releasing](releasing.md) | Workspace release preparation, PyPI publishing, and recovery. |
|
|
12
14
|
| [Architecture](architecture.md) | Server integration, shared IR, generation, and transport boundaries. |
|
|
13
15
|
|
|
14
16
|
Start with the [quickstart](quickstart.md), then use the
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
## Named values and typed iteration
|
|
6
6
|
|
|
7
7
|
Discriminated unions produce an enum named after the union and discriminator:
|
|
8
|
-
`RunEvent` + `type` becomes `RunEventType`.
|
|
9
|
-
also get named values.
|
|
8
|
+
`RunEvent` + `type` becomes `RunEventType`. Named string enums and multi-value
|
|
9
|
+
literal model fields also get named values. Single constant fields, such as
|
|
10
|
+
problem titles and URIs, remain inline literals. Python emits `StrEnum` for enums;
|
|
11
|
+
TypeScript emits an `as const`
|
|
10
12
|
object plus a union type. Both retain exhaustive discriminator narrowing.
|
|
11
13
|
Parameters use camelCase in TypeScript and snake_case in Python; wire aliases
|
|
12
14
|
are preserved.
|
|
@@ -117,6 +119,54 @@ Pydantic; TypeScript provides static types and JSON decoding, with no runtime
|
|
|
117
119
|
schema validator. Cancellation propagates normally; application error events
|
|
118
120
|
remain ordinary members of the user-defined union.
|
|
119
121
|
|
|
122
|
+
## HTTP error contracts
|
|
123
|
+
|
|
124
|
+
The SDK works with ordinary OpenAPI response declarations, including
|
|
125
|
+
`application/json`, `application/problem+json`, and other declared response media
|
|
126
|
+
types. No error registry or particular problem envelope is required. Declare
|
|
127
|
+
HTTP failures with FastAPI's `responses=`; put authentication, authorization,
|
|
128
|
+
and resource checks in dependencies so they can fail before the response starts.
|
|
129
|
+
Even generator statements before the first `yield` execute after response start.
|
|
130
|
+
|
|
131
|
+
Each operation with declared error schemas exports an `OperationErrorBody`
|
|
132
|
+
union: for example `StreamRunEventsErrorBody`. The earlier `OperationError`
|
|
133
|
+
name remains an alias for compatibility; it describes response bodies, not
|
|
134
|
+
the exceptions thrown by the SDK. Python imports these aliases from `models`;
|
|
135
|
+
TypeScript exports them from the SDK entrypoint.
|
|
136
|
+
|
|
137
|
+
Catch HTTP failures around **iteration**, since opening the request is lazy.
|
|
138
|
+
`HttpError.details` deliberately remains unvalidated: proxies and servers can
|
|
139
|
+
return unexpected JSON, plain text, HTML, incomplete bodies, or no body at all.
|
|
140
|
+
An operation's body union does not associate each variant with a status and does
|
|
141
|
+
not prove which operation produced an exception. Check the actual HTTP status
|
|
142
|
+
and validate the body before using application fields.
|
|
143
|
+
|
|
144
|
+
TypeScript provides `isHttpError(error, isDetails)`. Supply a type guard that
|
|
145
|
+
checks every field promised by its return type, or adapt an existing runtime
|
|
146
|
+
validator. The helper verifies the SDK exception class and invokes that guard;
|
|
147
|
+
it does not generate a schema validator or validate the HTTP status. A generic
|
|
148
|
+
type argument alone cannot replace the required guard. Failed guards leave the
|
|
149
|
+
original `HttpError` available for generic handling.
|
|
150
|
+
|
|
151
|
+
Python can validate `error.details` with `TypeAdapter(OperationErrorBody)` and
|
|
152
|
+
handle `ValidationError` as an unexpected response. Both approaches retain
|
|
153
|
+
the original status, response, and diagnostics. Schema unions with permissive
|
|
154
|
+
variants may accept a broad range of bodies; inspect the parsed variant before
|
|
155
|
+
using its fields. Existing limits on bounded HTTP diagnostics still apply.
|
|
156
|
+
|
|
157
|
+
The checked consumer examples show HTTP validation errors, fallback handling,
|
|
158
|
+
stream parsing/transport errors, and ordinary application error events:
|
|
159
|
+
|
|
160
|
+
- [TypeScript error handling](../examples/agent_runs/errors.ts), compiled with the
|
|
161
|
+
generated SDK under the repository's strict TypeScript configuration.
|
|
162
|
+
- [Python error handling](../examples/agent_runs/errors.py), checked by Pyright
|
|
163
|
+
with the generated models.
|
|
164
|
+
|
|
165
|
+
Caller cancellation continues to propagate. Neither SDK converts application
|
|
166
|
+
error events into exceptions or automatically retries a stream.
|
|
167
|
+
|
|
168
|
+
## Python model fields
|
|
169
|
+
|
|
120
170
|
Python uses `None` for omitted optional fields; `model_fields_set` distinguishes
|
|
121
171
|
absence from explicit null. Explicit null is rejected for fields that may only
|
|
122
172
|
be omitted. Requests exclude unset fields and serialize using wire aliases.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Contracts and client generation
|
|
2
|
+
|
|
3
|
+
[Documentation](README.md) · [Project](../README.md)
|
|
4
|
+
|
|
5
|
+
## Export and generate
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
uv run fastapi-streams schema \
|
|
9
|
+
--app examples.agent_runs:app --output tests/fixtures/agent_runs.openapi.json
|
|
10
|
+
|
|
11
|
+
uv run fastapi-streams generate \
|
|
12
|
+
--schema tests/fixtures/agent_runs.openapi.json --language typescript --output frontend/generated
|
|
13
|
+
|
|
14
|
+
uv run fastapi-streams generate \
|
|
15
|
+
--schema tests/fixtures/agent_runs.openapi.json --language python --output myapp/generated
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
No running server is needed. Export imports the application. The codegen extra
|
|
19
|
+
adds Jinja and JSON Schema validation; importing the server package needs neither.
|
|
20
|
+
|
|
21
|
+
The exporter copies native FastAPI output, promotes compatible 3.1 output to
|
|
22
|
+
OpenAPI 3.2.0, updates the declared OAS dialect when necessary, and validates the
|
|
23
|
+
official bundled OpenAPI structural schema, Draft 2020-12 Schema Objects and
|
|
24
|
+
local references. Incompatible contracts fail explicitly. The application's
|
|
25
|
+
cached document and ordinary REST endpoints remain intact.
|
|
26
|
+
|
|
27
|
+
The generator extracts application data from
|
|
28
|
+
`itemSchema.properties.data.contentSchema`. Only stream operations and models
|
|
29
|
+
reachable from their parameters, bodies, events and error responses are emitted.
|
|
30
|
+
Operations use the first tag as their group, defaulting to `streams`.
|
|
31
|
+
|
|
32
|
+
Generated method documentation carries each operation's `summary`, `description`,
|
|
33
|
+
and `deprecated` marker alongside language-specific SDK behavior. Describe
|
|
34
|
+
replay, retention, and server job lifetime explicitly on your endpoint; the
|
|
35
|
+
generator does not infer these business guarantees. Python early exits should
|
|
36
|
+
use `contextlib.aclosing`; TypeScript `for await` cleanup closes its reader.
|
|
37
|
+
|
|
38
|
+
TypeScript has no runtime dependencies and uses Fetch-compatible APIs. The
|
|
39
|
+
example uses ES modules and is tested on Node 24. Generated Python packages
|
|
40
|
+
require Python 3.12+, `httpx>=0.28` and `pydantic>=2.11.2` (`uv add httpx pydantic`).
|
|
41
|
+
|
|
42
|
+
HTTPX is the default. To generate a Python client using HTTPX2 instead, opt in
|
|
43
|
+
when generating and checking it:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
uv run fastapi-streams generate \
|
|
47
|
+
--schema tests/fixtures/agent_runs.openapi.json --language python \
|
|
48
|
+
--python-http-client httpx2 --output myapp/generated
|
|
49
|
+
|
|
50
|
+
uv run fastapi-streams check \
|
|
51
|
+
--schema tests/fixtures/agent_runs.openapi.json --language python \
|
|
52
|
+
--python-http-client httpx2 --output myapp/generated
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Install `httpx2>=2.13.1,<3` and `pydantic>=2.11.2` in that consumer. The
|
|
56
|
+
generated package needs only the selected HTTP library; installing HTTPX2 does
|
|
57
|
+
not change an existing HTTPX client. The Python generator API accepts the same
|
|
58
|
+
choice as `generate_python(contract, http_client="httpx2")`. Pass the choice to
|
|
59
|
+
every `check` or `generate --check` call; omitting it checks HTTPX output.
|
|
60
|
+
`--python-http-client` requires `--language python`.
|
|
61
|
+
|
|
62
|
+
REST operations remain available in the contract for an existing SDK generator
|
|
63
|
+
such as Orval or HeyAPI. Keep REST and streaming SDKs in separate output
|
|
64
|
+
directories. Reusing external generated model imports is a future feature.
|
|
65
|
+
|
|
66
|
+
## Event discriminators
|
|
67
|
+
|
|
68
|
+
A Python default allows omitting a field when constructing a model. It does not
|
|
69
|
+
automatically make the field required in JSON Schema. The generator respects
|
|
70
|
+
`required` and warns with `OptionalDiscriminatorWarning` when a stream event
|
|
71
|
+
union uses an optional discriminator, including nested unions. An absent tag may
|
|
72
|
+
prevent variant selection; TypeScript's static types do not validate incoming JSON.
|
|
73
|
+
|
|
74
|
+
For **output-only** event models whose serializer always emits default fields,
|
|
75
|
+
configure the output schema to describe that behavior:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from pydantic import BaseModel, ConfigDict
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class StreamEvent(BaseModel):
|
|
82
|
+
model_config = ConfigDict(
|
|
83
|
+
json_schema_mode_override="serialization",
|
|
84
|
+
json_schema_serialization_defaults_required=True,
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Inherit event variants from this model, or apply the configuration to an existing
|
|
89
|
+
output-only base. It marks all serialized default fields required, not only the
|
|
90
|
+
discriminator. Avoid applying it globally to shared request models: input and
|
|
91
|
+
output requiredness can differ. Alternatively, declare the tag without a default
|
|
92
|
+
and pass it explicitly. Regenerate the schema and clients after changing models.
|
|
93
|
+
|
|
94
|
+
Warnings are advisory and do not change fields or defaults. Python callers can
|
|
95
|
+
filter or promote this category using the standard `warnings` module; the category
|
|
96
|
+
is available from `fastapi_streams.codegen.diagnostics`.
|
|
97
|
+
|
|
98
|
+
## Check drift in CI
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
uv run fastapi-streams check \
|
|
102
|
+
--app examples.agent_runs:app --schema tests/fixtures/agent_runs.openapi.json \
|
|
103
|
+
--language typescript --output examples/agent_runs/generated
|
|
104
|
+
|
|
105
|
+
uv run fastapi-streams check \
|
|
106
|
+
--app examples.agent_runs:app --schema tests/fixtures/agent_runs.openapi.json \
|
|
107
|
+
--language python --output examples/agent_runs/generated_python
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`check` imports the app, compares its contract, validates the stored schema and
|
|
111
|
+
compares generated files without writing. Omit `--app` for a contract supplied
|
|
112
|
+
by another service. `schema --check` and `generate --check` are also supported.
|
|
113
|
+
Exit codes: **0** current, **1** drift, **2** invalid input.
|
|
114
|
+
|
|
115
|
+
Generation is deterministic. A manifest tracks owned files and cleans up stale
|
|
116
|
+
generated files without deleting neighboring handwritten files. Use a dedicated
|
|
117
|
+
output directory for each language. Unsafe paths and generated-name collisions
|
|
118
|
+
fail explicitly.
|
|
119
|
+
|
|
120
|
+
## Runtime validation and unknown variants
|
|
121
|
+
|
|
122
|
+
Python validates generated event models and request bodies with Pydantic. Supported
|
|
123
|
+
scalar constraints are `pattern`, `minLength`, `maxLength`, `minimum`, `maximum`,
|
|
124
|
+
`exclusiveMinimum`, `exclusiveMaximum`, and `multipleOf`. They survive nested
|
|
125
|
+
models, arrays, nullable types and referenced scalar aliases. Patterns use
|
|
126
|
+
Pydantic's Rust regex engine; unsupported expressions fail generation. Numeric
|
|
127
|
+
multiples follow Pydantic's floating-point tolerance. This is not a complete JSON
|
|
128
|
+
Schema validator. Formats, collection/object limits and other unsupported rules
|
|
129
|
+
emit `UnsupportedConstraintWarning`; promote it to an error in CI when required.
|
|
130
|
+
Constraints alongside enum/const or composition fail explicitly; constraints on
|
|
131
|
+
scalar branches are supported. TypeScript provides static shapes and does not
|
|
132
|
+
validate incoming JSON or enforce scalar constraints at runtime.
|
|
133
|
+
|
|
134
|
+
Python event unions are closed by default: unknown variants raise
|
|
135
|
+
`StreamParseError`. For an upstream that emits more variants than your declared
|
|
136
|
+
subset, explicitly choose a per-request policy:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from generated import RequestOptions
|
|
140
|
+
|
|
141
|
+
options = RequestOptions(unknown_events="ignore")
|
|
142
|
+
async for event in client.runs.run_events(run_id="run_abc", options=options):
|
|
143
|
+
...
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Ignoring requires a top-level discriminated union with known string tags. Only
|
|
147
|
+
valid JSON objects with an unknown string discriminator are skipped. Invalid
|
|
148
|
+
JSON, missing/non-string discriminators and malformed known variants still fail;
|
|
149
|
+
unknown nested variants inside a known event fail too. The option adds no retry,
|
|
150
|
+
reconnect or replay. TypeScript continues to forward JSON-decoded values without
|
|
151
|
+
runtime union validation. Regenerate existing Python SDKs to obtain the option.
|
|
152
|
+
|
|
153
|
+
## Existing native streams and mixed REST generation
|
|
154
|
+
|
|
155
|
+
See the [native transport and mixed-codegen recipe](native-transports.md) when
|
|
156
|
+
an existing generator, native server or byte-preserving proxy owns the stream.
|
|
@@ -17,6 +17,7 @@ npm run test:coverage
|
|
|
17
17
|
uv run pytest -q --cov --cov-report=term-missing --cov-report=xml:coverage-python.xml
|
|
18
18
|
uv run python scripts/codegen.py --check
|
|
19
19
|
uv build
|
|
20
|
+
uv run --frozen twine check --strict dist/*
|
|
20
21
|
uv run python scripts/check_package.py
|
|
21
22
|
```
|
|
22
23
|
|