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.
Files changed (137) hide show
  1. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.github/workflows/ci.yml +10 -5
  2. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.github/workflows/compatibility.yml +9 -5
  3. fastapi_streams-0.2.0/.github/workflows/release.yml +115 -0
  4. fastapi_streams-0.2.0/CHANGELOG.md +136 -0
  5. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/PKG-INFO +13 -8
  6. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/README.md +9 -4
  7. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/README.md +2 -0
  8. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/clients.md +52 -2
  9. fastapi_streams-0.2.0/docs/codegen.md +156 -0
  10. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/development.md +1 -0
  11. fastapi_streams-0.2.0/docs/native-transports.md +49 -0
  12. fastapi_streams-0.2.0/docs/releasing.md +13 -0
  13. fastapi_streams-0.2.0/examples/agent_runs/errors.py +37 -0
  14. fastapi_streams-0.2.0/examples/agent_runs/errors.ts +44 -0
  15. fastapi_streams-0.2.0/examples/agent_runs/generated/agent-runs/api.ts +89 -0
  16. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/index.ts +1 -1
  17. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/transport/errors.ts +11 -0
  18. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/types.ts +16 -16
  19. fastapi_streams-0.2.0/examples/agent_runs/generated_python/agent_runs/api.py +92 -0
  20. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/models.py +7 -1
  21. {fastapi_streams-0.0.1/tests/fixtures → fastapi_streams-0.2.0/examples/agent_runs}/generated_python/runtime.py +27 -0
  22. fastapi_streams-0.2.0/examples/native_proxy.py +99 -0
  23. fastapi_streams-0.2.0/examples/rest_codegen.py +76 -0
  24. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/__init__.py +1 -1
  25. fastapi_streams-0.2.0/fastapi_streams/codegen/diagnostics.py +83 -0
  26. fastapi_streams-0.2.0/fastapi_streams/codegen/documentation.py +66 -0
  27. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/enums.py +4 -4
  28. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/ir.py +83 -5
  29. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/python.py +63 -8
  30. {fastapi_streams-0.0.1/tests/fixtures/generated/transport → fastapi_streams-0.2.0/fastapi_streams/codegen/templates}/errors.ts +11 -0
  31. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/python/api.py.j2 +5 -0
  32. {fastapi_streams-0.0.1/examples/agent_runs/generated_python → fastapi_streams-0.2.0/fastapi_streams/codegen/templates/python}/runtime.py +27 -0
  33. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/typescript/api.ts.j2 +9 -1
  34. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/typescript.py +23 -11
  35. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/pyproject.toml +6 -5
  36. fastapi_streams-0.2.0/scripts/check_release.py +69 -0
  37. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/smoke_package.py +38 -6
  38. fastapi_streams-0.2.0/tests/codegen/test_diagnostics.py +64 -0
  39. fastapi_streams-0.2.0/tests/codegen/test_documentation.py +52 -0
  40. fastapi_streams-0.2.0/tests/codegen/test_error_contracts.py +149 -0
  41. fastapi_streams-0.2.0/tests/codegen/test_literal_fields.py +103 -0
  42. fastapi_streams-0.2.0/tests/codegen/test_native_contract.py +56 -0
  43. fastapi_streams-0.2.0/tests/codegen/test_scalar_constraints.py +65 -0
  44. fastapi_streams-0.2.0/tests/codegen/test_unknown_events.py +83 -0
  45. fastapi_streams-0.2.0/tests/fixtures/generated/fixtures/api.ts +51 -0
  46. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/index.ts +1 -1
  47. {fastapi_streams-0.0.1/fastapi_streams/codegen/templates → fastapi_streams-0.2.0/tests/fixtures/generated/transport}/errors.ts +11 -0
  48. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/types.ts +16 -16
  49. fastapi_streams-0.2.0/tests/fixtures/generated_python/fixtures/api.py +54 -0
  50. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/models.py +2 -0
  51. {fastapi_streams-0.0.1/fastapi_streams/codegen/templates/python → fastapi_streams-0.2.0/tests/fixtures/generated_python}/runtime.py +27 -0
  52. fastapi_streams-0.2.0/tests/test_release.py +119 -0
  53. fastapi_streams-0.2.0/tests/typescript/errors.test.ts +69 -0
  54. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/tsconfig.json +1 -1
  55. fastapi_streams-0.0.1/docs/codegen.md +0 -80
  56. fastapi_streams-0.0.1/examples/agent_runs/generated/agent-runs/api.ts +0 -49
  57. fastapi_streams-0.0.1/examples/agent_runs/generated_python/agent_runs/api.py +0 -54
  58. fastapi_streams-0.0.1/tests/fixtures/generated/fixtures/api.ts +0 -31
  59. fastapi_streams-0.0.1/tests/fixtures/generated_python/fixtures/api.py +0 -35
  60. fastapi_streams-0.0.1/uv.lock +0 -1218
  61. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.gitattributes +0 -0
  62. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.gitignore +0 -0
  63. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/.pre-commit-config.yaml +0 -0
  64. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/AGENTS.md +0 -0
  65. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/LICENSE +0 -0
  66. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/architecture.md +0 -0
  67. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/docs/quickstart.md +0 -0
  68. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/__init__.py +0 -0
  69. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/__init__.py +0 -0
  70. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/consume.py +0 -0
  71. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/consume.ts +0 -0
  72. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/.fastapi-streams.json +0 -0
  73. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/agent-runs/index.ts +0 -0
  74. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/client.ts +0 -0
  75. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated/transport/sse.ts +0 -0
  76. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/.fastapi-streams.json +0 -0
  77. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/__init__.py +0 -0
  78. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/agent_runs/__init__.py +0 -0
  79. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/client.py +0 -0
  80. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/examples/agent_runs/generated_python/py.typed +0 -0
  81. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/__init__.py +0 -0
  82. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/cli.py +0 -0
  83. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/names.py +0 -0
  84. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/openapi.py +0 -0
  85. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/schemas/LICENSE +0 -0
  86. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/schemas/README.md +0 -0
  87. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/schemas/openapi-3.2.json +0 -0
  88. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/python/client.py.j2 +0 -0
  89. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/sse.ts +0 -0
  90. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templates/typescript/client.ts.j2 +0 -0
  91. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/templating.py +0 -0
  92. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/codegen/writer.py +0 -0
  93. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/py.typed +0 -0
  94. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/fastapi_streams/router.py +0 -0
  95. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/package-lock.json +0 -0
  96. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/package.json +0 -0
  97. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/check_package.py +0 -0
  98. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/codegen.py +0 -0
  99. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/scripts/test_compat.py +0 -0
  100. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/__init__.py +0 -0
  101. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/helpers.py +0 -0
  102. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_additional_properties.py +0 -0
  103. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_codegen.py +0 -0
  104. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_contract_boundaries.py +0 -0
  105. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_discriminators.py +0 -0
  106. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_field_names.py +0 -0
  107. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_http_backends.py +0 -0
  108. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_intersections.py +0 -0
  109. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_nested_models.py +0 -0
  110. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_python_client.py +0 -0
  111. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_python_typing.py +0 -0
  112. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_required_properties.py +0 -0
  113. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/codegen/test_schema_matrix.py +0 -0
  114. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/contracts/test_openapi.py +0 -0
  115. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/README.md +0 -0
  116. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/__init__.py +0 -0
  117. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/agent_runs.openapi.json +0 -0
  118. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/compat-client.ts +0 -0
  119. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/.fastapi-streams.json +0 -0
  120. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/client.ts +0 -0
  121. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/fixtures/index.ts +0 -0
  122. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated/transport/sse.ts +0 -0
  123. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/.fastapi-streams.json +0 -0
  124. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/__init__.py +0 -0
  125. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/client.py +0 -0
  126. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/fixtures/__init__.py +0 -0
  127. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/generated_python/py.typed +0 -0
  128. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/integration_app.py +0 -0
  129. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/models.openapi.json +0 -0
  130. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/fixtures/models_app.py +0 -0
  131. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/integration/test_end_to_end.py +0 -0
  132. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/router/test_router.py +0 -0
  133. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/live-client.ts +0 -0
  134. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/models.test.ts +0 -0
  135. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/narrowing.ts +0 -0
  136. {fastapi_streams-0.0.1 → fastapi_streams-0.2.0}/tests/typescript/sse.test.ts +0 -0
  137. {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
- - uses: actions/setup-python@v5
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
- - uses: actions/setup-python@v5
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.1
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/fastapi-streams/tree/main/docs
6
- Project-URL: Source, https://github.com/mathisarends/fastapi-streams
7
- Project-URL: Issues, https://github.com/mathisarends/fastapi-streams/issues
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 GitHub with the optional codegen extra:
48
+ Install from PyPI with the optional codegen extra:
49
49
 
50
50
  ```sh
51
- uv add 'fastapi-streams[codegen] @ git+https://github.com/mathisarends/fastapi-streams.git'
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
- v0.0.1 supports GET/POST JSON SSE streams. Ordinary REST endpoints stay in the
236
- contract for your existing REST SDK. See the [supported scope](docs/development.md#supported-scope-and-roadmap).
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 GitHub with the optional codegen extra:
30
+ Install from PyPI with the optional codegen extra:
31
31
 
32
32
  ```sh
33
- uv add 'fastapi-streams[codegen] @ git+https://github.com/mathisarends/fastapi-streams.git'
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
- v0.0.1 supports GET/POST JSON SSE streams. Ordinary REST endpoints stay in the
218
- contract for your existing REST SDK. See the [supported scope](docs/development.md#supported-scope-and-roadmap).
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`. String enums and literal model fields
9
- also get named values. Python emits `StrEnum`; TypeScript emits an `as const`
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