diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index 66b4d0146..8c0ed3ff0 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -115,8 +115,8 @@ jobs: strategy: matrix: - bun-version: [latest] - python-version: ["3.13"] + bun-version: [ latest ] + python-version: [ "3.13" ] steps: - uses: actions/checkout@v4 @@ -140,14 +140,55 @@ jobs: - name: Repository contains actual python-sdk version run: | - diff_result=$(git diff --exit-code --name-only examples/python/generated || true) + diff_result=$(git diff --exit-code --name-only examples/python/fhir_types || true) + + if [ -z "$diff_result" ]; then + echo "✅ Generated SDK is identical to the one stored in repository." + else + echo "❌ Generated SDK differs from the one stored in repository." + echo "Differences:" + git diff examples/python/fhir_types + exit 1 + fi + + test-python-fhirpy-sdk-test: + runs-on: ubuntu-latest + + strategy: + matrix: + bun-version: [ latest ] + python-version: [ "3.13" ] + + steps: + - uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: ${{ matrix.bun-version }} + + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Test Python fhirpy SDK + run: | + export AIDBOX_LICENSE_ID="${{ secrets.AIDBOX_LICENSE_ID }}" + make test-python-fhirpy-sdk + + - name: Repository contains actual python-fhirpy-sdk version + run: | + diff_result=$(git diff --exit-code --name-only examples/python-fhirpy/fhir_types || true) if [ -z "$diff_result" ]; then echo "✅ Generated SDK is identical to the one stored in repository." else echo "❌ Generated SDK differs from the one stored in repository." echo "Differences:" - git diff examples/python/generated + git diff examples/python-fhirpy/fhir_types exit 1 fi diff --git a/Makefile b/Makefile index b1d9c1991..05d8e5526 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ test-all-example-generation: bun run examples/local-package-folder/generate.ts bun run examples/mustache/mustache-java-r4-gen.ts bun run examples/python/generate.ts + bun run examples/python-fhirpy/generate.ts bun run examples/typescript-ccda/generate.ts bun run examples/typescript-r4/generate.ts bun run examples/typescript-sql-on-fhir/generate.ts @@ -81,27 +82,49 @@ test-csharp-sdk: typecheck format prepare-aidbox-runme lint cd examples/csharp && dotnet test PYTHON=python3.13 -PYTHON_SDK_EXAMPLE=./examples/python +PYTHON_EXAMPLE=./examples/python +PYTHON_FHIRPY_EXAMPLE=./examples/python-fhirpy -test-python-sdk: typecheck format prepare-aidbox-runme lint +generate-python-sdk: $(TYPECHECK) --project examples/python/tsconfig.json bun run examples/python/generate.ts - @if [ ! -d "$(PYTHON_SDK_EXAMPLE)/venv" ]; then \ - cd $(PYTHON_SDK_EXAMPLE) && \ +generate-python-sdk-fhirpy: + $(TYPECHECK) --project examples/python-fhirpy/tsconfig.json + bun run examples/python-fhirpy/generate.ts + +python-test-setup: + @if [ ! -d "$(PYTHON_EXAMPLE)/venv" ]; then \ + cd $(PYTHON_EXAMPLE) && \ $(PYTHON) -m venv venv && \ . venv/bin/activate && \ pip install -r fhir_types/requirements.txt; \ fi - # Run mypy in strict mode - cd $(PYTHON_SDK_EXAMPLE) && \ +python-fhirpy-test-setup: + @if [ ! -d "$(PYTHON_FHIRPY_EXAMPLE)/venv" ]; then \ + cd $(PYTHON_FHIRPY_EXAMPLE) && \ + $(PYTHON) -m venv venv && \ . venv/bin/activate && \ - mypy --strict . + pip install -r fhir_types/requirements.txt && \ + pip install fhirpy; \ + fi - cd $(PYTHON_SDK_EXAMPLE) && \ - . venv/bin/activate && \ - python -m pytest test_sdk.py -v +test-python-sdk: typecheck format prepare-aidbox-runme lint generate-python-sdk python-test-setup + # Run mypy in strict mode + cd $(PYTHON_EXAMPLE) && \ + . venv/bin/activate && \ + mypy --strict . + + cd $(PYTHON_EXAMPLE) && \ + . venv/bin/activate && \ + python -m pytest test_sdk.py -v + +test-python-fhirpy-sdk: typecheck format prepare-aidbox-runme lint generate-python-sdk-fhirpy python-fhirpy-test-setup + # Run mypy in strict mode + cd $(PYTHON_FHIRPY_EXAMPLE) && \ + . venv/bin/activate && \ + mypy --strict . release: echo Push tag for $(VERSION) diff --git a/README.md b/README.md index 2aa45c3fb..3ac108f63 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,8 @@ See the [examples/](examples/) directory for working demonstrations: - **[typescript-r4/](examples/typescript-r4/)** - FHIR R4 type generation with resource creation demo and profile usage - **[typescript-ccda/](examples/typescript-ccda/)** - C-CDA on FHIR type generation - **[typescript-sql-on-fhir/](examples/typescript-sql-on-fhir/)** - SQL on FHIR ViewDefinition with tree shaking -- **[python/](examples/python/)** - Python/Pydantic model generation with configurable field formats +- **[python/](examples/python/)** - Python/Pydantic model generation with simple requests-based client +- **[python-fhirpy/](examples/python-fhirpy/)** - Python/Pydantic model generation with fhirpy async client - **[csharp/](examples/csharp/)** - C# class generation with namespace configuration - **[mustache/](examples/mustache/)** - Java generation with Mustache templates and post-generation hooks - **[local-package-folder/](examples/local-package-folder/)** - Loading unpublished local FHIR packages diff --git a/assets/api/writer-generator/python/fhirpy_base_model.py b/assets/api/writer-generator/python/fhirpy_base_model.py new file mode 100644 index 000000000..e14be7fbc --- /dev/null +++ b/assets/api/writer-generator/python/fhirpy_base_model.py @@ -0,0 +1,32 @@ +from typing import Any, Union, Optional, Iterator, Tuple, Dict +from pydantic import BaseModel, Field +from typing import Protocol + + +class ResourceProtocol(Protocol): + resourceType: Any + id: Union[str, None] + + +class FhirpyBaseModel(BaseModel): + """ + This class satisfies ResourceProtocol + """ + resource_type: str = Field(alias="resourceType") + id: Optional[str] = Field(None, alias="id") + + @property + def resourceType(self) -> str: + return self.resource_type + + @resourceType.setter + def resourceType(self, value: str) -> None: + self.resource_type = value + + def __iter__(self) -> Iterator[Tuple[str, Any]]: # type: ignore[override] + data = self.model_dump(mode='json', by_alias=True, exclude_none=True) + return iter(data.items()) + + def serialize(self) -> Dict[str, Any]: + """Serialize to dict (compatible with fhirpy's serialize method)""" + return self.model_dump(mode='json', by_alias=True, exclude_none=True) diff --git a/examples/README.md b/examples/README.md index 1bbebcf0a..cdcb42a68 100644 --- a/examples/README.md +++ b/examples/README.md @@ -21,11 +21,16 @@ This directory contains working examples demonstrating the capabilities of Atomi ### Multi-Language Generation -- **[python/](python/)** - Python/Pydantic model generation +- **[python/](python/)** - Python/Pydantic model generation with simple requests-based client - `generate.ts` - Generates Python models with configurable field formats - Supports `snake_case` or `camelCase` field naming - Configurable extra field validation - - Client implementation example: [examples/python/client.py](examples/python/client.py). + - Client implementation example: [python/client.py](python/client.py) + +- **[python-fhirpy/](python-fhirpy/)** - Python/Pydantic models with fhirpy async client + - `generate.ts` - Generates Python models with fhirpy integration + - Uses `fhirpyClient: true` for async FHIR client support + - Client implementation example: [python-fhirpy/client.py](python-fhirpy/client.py) - **[csharp/](csharp/)** - C# class generation diff --git a/examples/python-fhirpy/.gitignore b/examples/python-fhirpy/.gitignore new file mode 100644 index 000000000..d9bd8be76 --- /dev/null +++ b/examples/python-fhirpy/.gitignore @@ -0,0 +1,4 @@ +.pytest_cache +__pycache__ +.mypy_cache +venv diff --git a/examples/python-fhirpy/README.md b/examples/python-fhirpy/README.md new file mode 100644 index 000000000..4d74da943 --- /dev/null +++ b/examples/python-fhirpy/README.md @@ -0,0 +1,147 @@ +# Python fhirpy Example + +FHIR R4 type generation with Pydantic models integrated with the [fhirpy](https://github.com/beda-software/fhir-py) async client library. + +## Overview + +This example demonstrates how to use generated Python/Pydantic models with the `fhirpy` async FHIR client. It includes: + +- Full FHIR R4 resource type definitions as Pydantic models +- Integration with `fhirpy` AsyncFHIRClient +- Automatic validation and serialization +- Async/await patterns for FHIR operations + +For a simpler example using `requests`, see [python-simple/](../python-simple/). + +## Setup + +### Python Environment + +1. Create virtual environment: + +```bash +cd examples/python-fhirpy +python3 -m venv venv + +# On macOS/Linux: +source venv/bin/activate +# On Windows: +venv\Scripts\activate +``` + +2. Install Python dependencies: + +```bash +pip install -r fhir_types/requirements.txt +pip install fhirpy +``` + +3. Check Python version: + +```bash +python --version # Should be 3.10 or higher +``` + +## Generating Types + +To generate Python/Pydantic types for FHIR R4 with fhirpy support: + +```bash +bun run examples/python-fhirpy/generate.ts +``` + +This will output to `./examples/python-fhirpy/fhir_types/` + +## Configuration + +Edit `generate.ts` to customize: + +```typescript +.python({ + allowExtraFields: false, // Reject unknown fields in models + fieldFormat: "snake_case", // or "camelCase" + fhirpyClient: true // Enable fhirpy integration +}) +``` + +The `fhirpyClient: true` option generates models that inherit from a base class compatible with fhirpy's client API. + +## Using with fhirpy + +### Basic Usage + +```python +import asyncio +from fhirpy import AsyncFHIRClient +from fhir_types.hl7_fhir_r4_core import HumanName +from fhir_types.hl7_fhir_r4_core.patient import Patient + +async def main(): + client = AsyncFHIRClient( + "http://localhost:8080/fhir", + authorization="Basic ", + ) + + # Create a patient using typed models + patient = Patient( + name=[HumanName(given=["John"], family="Doe")], + gender="male", + birthDate="1980-01-01", + ) + + # Use fhirpy's client API with the typed model + created = await client.create(patient) + print(f"Created patient: {created.id}") + + # Search for patients + patients = await client.resources("Patient").fetch() + for pat in patients: + print(f"Found: {pat.get('name', [{}])[0].get('family', 'N/A')}") + +asyncio.run(main()) +``` + +### Resource API + +```python +from fhir_types.hl7_fhir_r4_core.organization import Organization + +organization = Organization( + name="My Organization", + active=True +) + +# Use fhirpy's resource API +org_resource = await client.resource( + "Organization", + **organization.model_dump(exclude_none=True) +).save() + +print(f"Created organization: {org_resource.id}") +``` + +## Type Checking + +### MyPy Integration + +Verify type safety with MyPy: + +```bash +pip install mypy +mypy fhir_types/ +``` + +## Running the Demo + +Start a FHIR server (e.g., using the docker-compose in examples/), then run: + +```bash +python client.py +``` + +## Next Steps + +- See [python-simple/](../python-simple/) for basic requests-based example +- See [examples/](../) overview for other language examples +- Check [../../CLAUDE.md](../../CLAUDE.md) for architecture details +- Learn more about [fhirpy](https://github.com/beda-software/fhir-py) diff --git a/examples/python-fhirpy/client.py b/examples/python-fhirpy/client.py new file mode 100644 index 000000000..3bd141382 --- /dev/null +++ b/examples/python-fhirpy/client.py @@ -0,0 +1,84 @@ +import asyncio +import base64 +import json +from typing import TypeVar, Dict, Any, Tuple +from pydantic import BaseModel +from fhirpy import AsyncFHIRClient + +from fhir_types.hl7_fhir_r4_core import HumanName +from fhir_types.hl7_fhir_r4_core.patient import Patient +from fhir_types.hl7_fhir_r4_core.organization import Organization + +T = TypeVar('T', bound=BaseModel) + +FHIR_SERVER_URL = "http://localhost:8080/fhir" +USERNAME = "root" +PASSWORD = "" +TOKEN = base64.b64encode(f"{USERNAME}:{PASSWORD}".encode()).decode() + + +def get_resource_components(model: T) -> Tuple[str, Dict[str, Any]]: + """ + Extracts the FHIR resource type and the serialized resource body + from a Pydantic FHIR model. + """ + + resource_dict: Dict[str, Any] = model.model_dump( + mode='json', + by_alias=True, + exclude_none=True + ) + + resource_type = resource_dict.pop('resourceType', None) + if not resource_type and hasattr(model, 'resource_type'): + resource_type = model.resource_type + + if not resource_type: + raise ValueError("Cannot determine resource type from model") + + return resource_type, resource_dict + + +async def main() -> None: + """ + Demonstrates usage of fhirpy AsyncFHIRClient to create and fetch FHIR resources. + Both Client and Resource APIs are showcased. + """ + + client = AsyncFHIRClient( + FHIR_SERVER_URL, + authorization=f"Basic {TOKEN}", + ) + + patient = Patient( + name=[HumanName(given=["Bob"], family="Cool2")], + gender="female", + birth_date="1980-01-01", + ) + + # Create the Patient using fhirpy's client API + created_patient = await client.create(patient) + + print(f"Created patient: {created_patient.id}") + print(json.dumps(created_patient.serialize(), indent=2)) + + organization = Organization( + name="Beda Software", + active=True + ) + + # Save the Organization using fhirpy's resource API + organization_resource = await client.resource( + "Organization", + **organization.model_dump(exclude_none=True) + ).save() + + print(f"Created organization: {organization_resource.id}") + + patients = await client.resources("Patient").fetch() + for pat in patients: + print(f"Found: {pat.get('name', [{}])[0].get('family', 'N/A')}") # type: ignore[no-untyped-call] + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/python-fhirpy/generate.ts b/examples/python-fhirpy/generate.ts new file mode 100644 index 000000000..8bbd17cff --- /dev/null +++ b/examples/python-fhirpy/generate.ts @@ -0,0 +1,24 @@ +import { APIBuilder, prettyReport } from "../../src"; + +if (require.main === module) { + console.log("📦 Generating FHIR R4 Core Types with fhirpy support..."); + + const builder = new APIBuilder() + .throwException() + .fromPackage("hl7.fhir.r4.core", "4.0.1") + .python({ + allowExtraFields: false, + fieldFormat: "snake_case", + fhirpyClient: true, + }) + .outputTo("./examples/python-fhirpy/fhir_types") + .cleanOutput(true); + + const report = await builder.generate(); + + console.log(prettyReport(report)); + + if (!report.success) { + process.exit(1); + } +} diff --git a/examples/python-fhirpy/mypy.ini b/examples/python-fhirpy/mypy.ini new file mode 100644 index 000000000..4a3426103 --- /dev/null +++ b/examples/python-fhirpy/mypy.ini @@ -0,0 +1,13 @@ +[mypy] +python_version = 3.13 +disallow_untyped_defs = False +disallow_incomplete_defs = False +check_untyped_defs = True +disallow_untyped_decorators = False +no_implicit_optional = True +strict_optional = False +warn_redundant_casts = False +warn_unused_ignores = True +warn_return_any = False +warn_unreachable = True +plugins = pydantic.mypy diff --git a/examples/python-fhirpy/tsconfig.json b/examples/python-fhirpy/tsconfig.json new file mode 100644 index 000000000..27663aaca --- /dev/null +++ b/examples/python-fhirpy/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "include": [ + "./" + ] +} diff --git a/examples/python/README.md b/examples/python/README.md index 3a0566180..4bc3e991d 100644 --- a/examples/python/README.md +++ b/examples/python/README.md @@ -11,7 +11,9 @@ This example demonstrates how to generate Python/Pydantic models from the FHIR R - Configurable field naming conventions (snake_case or camelCase) - Integration with Python type checking and IDE support - Virtual environment setup -- FHIR server client example +- Simple FHIR server client example using `requests` + +For an example using the `fhirpy` async client library, see [python-fhirpy/](../python-fhirpy/). ## Setup @@ -32,7 +34,7 @@ venv\Scripts\activate 2. Install Python dependencies: ```bash -pip install -r requirements.txt +pip install -r fhir_types/requirements.txt ``` 3. Check Python version: @@ -109,36 +111,6 @@ except ValidationError as e: print(f"Validation error: {e}") ``` -### Working with Observations - -```python -from fhir_types import Observation -from datetime import datetime - -observation = Observation( - resource_type="Observation", - id="obs-1", - status="final", - code={ - "coding": [{ - "system": "http://loinc.org", - "code": "39156-5", - "display": "BMI" - }] - }, - subject={"reference": "Patient/patient-1"}, - effective_date_time=datetime.now(), - value={ - "quantity": { - "value": 25.5, - "unit": "kg/m2" - } - } -) - -print(observation.code.coding[0].display) -``` - ### Serialization and Deserialization ```python @@ -176,72 +148,12 @@ Generated Pydantic models provide: ## Running Tests -Create tests to verify generated types: - ```bash -pytest tests/ -v -``` - -### Example Test - -```python -from fhir_types import Patient, Observation -from pydantic import ValidationError -import pytest - -def test_patient_creation(): - patient = Patient( - resource_type="Patient", - id="patient-1", - name=[{"family": "Smith", "given": ["John"]}] - ) - assert patient.id == "patient-1" - assert patient.name[0].family == "Smith" - -def test_patient_validation(): - with pytest.raises(ValidationError): - Patient( - resource_type="InvalidType", - id="patient-1" - ) - -def test_field_format(): - patient = Patient( - resource_type="Patient", - birth_date="1980-01-15" # snake_case format - ) - assert patient.birth_date is not None -``` - -## Customization - -### Different Field Format - -Regenerate with camelCase: - -```typescript -.python({ - fieldFormat: "camelCase" -}) -``` - -### Lenient Validation - -Allow extra fields: - -```typescript -.python({ - allowExtraFields: true -}) -``` - -### Custom Output Directory - -```typescript -.outputTo("./my_fhir_types") +pytest test_sdk.py -v ``` ## Next Steps +- See [python-fhirpy/](../python-fhirpy/) for fhirpy async client example - See [examples/](../) overview for other language examples - Check [../../CLAUDE.md](../../CLAUDE.md) for architecture details diff --git a/examples/python/generate.ts b/examples/python/generate.ts index 47f32e00a..51ec6e4ae 100644 --- a/examples/python/generate.ts +++ b/examples/python/generate.ts @@ -7,7 +7,7 @@ const builder = new APIBuilder() .fromPackage("hl7.fhir.r4.core", "4.0.1") .python({ allowExtraFields: false, - staticDir: "./src/api/writer-generator/python/static-files", + fhirpyClient: false, fieldFormat: "snake_case", }) .outputTo("./examples/python/fhir_types") diff --git a/src/api/writer-generator/python.ts b/src/api/writer-generator/python.ts index 206d89705..8e524ba14 100644 --- a/src/api/writer-generator/python.ts +++ b/src/api/writer-generator/python.ts @@ -82,9 +82,9 @@ const MAX_IMPORT_LINE_LENGTH = 100; export interface PythonGeneratorOptions extends WriterOptions { allowExtraFields?: boolean; - staticDir?: string; rootPackageName: string; /// e.g. .hl7_fhir_r4_core.Patient. fieldFormat: StringFormatKey; + fhirpyClient?: boolean; } interface ImportGroup { @@ -101,10 +101,6 @@ const fixReservedWords = (name: string): string => { return PYTHON_KEYWORDS.has(name) ? `${name}_` : name; }; -const injectSuperClasses = (name: string): string[] => { - return name === "Resource" || name === "Element" ? ["BaseModel"] : []; -}; - const canonicalToName = (canonical: string | undefined, dropFragment = true) => { if (!canonical) return undefined; let localName = canonical.split("/").pop(); @@ -149,10 +145,12 @@ type TypeSchemaPackageGroups = { export class Python extends Writer { private readonly nameFormatFunction: (name: string) => string; private tsIndex: TypeSchemaIndex | undefined; + private readonly forFhirpyClient: boolean; constructor(options: PythonGeneratorOptions) { super({ ...options, resolveAssets: options.resolveAssets ?? resolvePyAssets }); this.nameFormatFunction = this.getFieldFormatFunction(options.fieldFormat); + this.forFhirpyClient = options.fhirpyClient ?? false; } override async generate(tsIndex: TypeSchemaIndex): Promise { @@ -167,7 +165,12 @@ export class Python extends Writer { private generateRootPackages(groups: TypeSchemaPackageGroups): void { this.generateRootInitFile(groups); - this.cp(resolvePyAssets("requirements.txt"), "requirements.txt"); + if (this.forFhirpyClient) + this.copyAssets( + resolvePyAssets("fhirpy_base_model.py"), + Path.resolve(this.opts.outputDir, "fhirpy_base_model.py"), + ); + this.copyAssets(resolvePyAssets("requirements.txt"), Path.resolve(this.opts.outputDir, "requirements.txt")); } private generateSDKPackages(groups: TypeSchemaPackageGroups): void { @@ -368,6 +371,7 @@ export class Python extends Writer { this.cat(`${snakeCase(schema.identifier.name)}.py`, () => { this.generateDisclaimer(); this.generateDefaultImports(); + this.generateFhirBaseModelImport(); this.line(); this.generateDependenciesImports(schema); this.line(); @@ -377,7 +381,12 @@ export class Python extends Writer { }); } - generateType(schema: RegularTypeSchema): void { + private generateFhirBaseModelImport(): void { + if (this.forFhirpyClient) + this.pyImportFrom(`${this.opts.rootPackageName}.fhirpy_base_model`, "FhirpyBaseModel"); + } + + private generateType(schema: RegularTypeSchema): void { const className = deriveResourceName(schema.identifier); const superClasses = this.getSuperClasses(schema); @@ -389,7 +398,7 @@ export class Python extends Writer { } private getSuperClasses(schema: RegularTypeSchema): string[] { - return [...(schema.base ? [schema.base.name] : []), ...injectSuperClasses(schema.identifier.name)]; + return [...(schema.base ? [schema.base.name] : []), ...this.injectSuperClasses(schema.identifier.url)]; } private generateClassBody(schema: RegularTypeSchema): void { @@ -503,7 +512,7 @@ export class Python extends Writer { this.line(" return cls.model_validate_json(json)"); } - generateNestedTypes(schema: RegularTypeSchema): void { + private generateNestedTypes(schema: RegularTypeSchema): void { if (!schema.nested) return; this.line(); @@ -560,7 +569,7 @@ export class Python extends Writer { return grouped; } - pyImportFrom(pyPackage: string, ...entities: string[]): void { + private pyImportFrom(pyPackage: string, ...entities: string[]): void { const oneLine = `from ${pyPackage} import ${entities.join(", ")}`; if (this.shouldUseSingleLineImport(oneLine, entities)) { @@ -680,7 +689,7 @@ export class Python extends Writer { return this.pyFhirPackage(identifier); } - getFieldFormatFunction(format: StringFormatKey): (name: string) => string { + private getFieldFormatFunction(format: StringFormatKey): (name: string) => string { if (!AVAILABLE_STRING_FORMATS[format]) { this.logger()?.warn(`Unknown field format '${format}'. Defaulting to SnakeCase.`); this.logger()?.warn(`Supported formats: ${Object.keys(AVAILABLE_STRING_FORMATS).join(", ")}`); @@ -688,4 +697,11 @@ export class Python extends Writer { } return AVAILABLE_STRING_FORMATS[format]; } + + private injectSuperClasses(url: string): string[] { + const name = canonicalToName(url); + if (name === "resource") return this.forFhirpyClient ? ["FhirpyBaseModel"] : ["BaseModel"]; + if (name === "element") return ["BaseModel"]; + return []; + } } diff --git a/src/api/writer-generator/writer.ts b/src/api/writer-generator/writer.ts index 4a2243b2c..690bac0e4 100644 --- a/src/api/writer-generator/writer.ts +++ b/src/api/writer-generator/writer.ts @@ -105,6 +105,16 @@ export abstract class FileSystemWriter=2.32.0,<3.0.0 -pytest>=8.3.0,<9.0.0 -pydantic>=2.11.0,<3.0.0 -mypy>=1.9.0,<2.0.0 -types-requests>=2.32.0,<3.0.0" -`; +exports[`Python Writer Generator static files 1`] = `undefined`;