From f5ed6500b04b9efdc3a17e02f294340c4c6e138e Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 7 Apr 2026 16:51:58 +0200 Subject: [PATCH 1/2] ci: use poe tasks for model generation in CI workflow Add `generate-models-from-file` poe task that accepts a local file path, working around datamodel-codegen's behavior where `url` in pyproject.toml takes precedence over the `--input` CLI flag. Update the CI workflow to call poe tasks instead of datamodel-codegen directly, ensuring the downloaded artifact is actually used when available. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/manual_regenerate_models.yaml | 4 ++-- pyproject.toml | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/manual_regenerate_models.yaml b/.github/workflows/manual_regenerate_models.yaml index 84b37df2..86793801 100644 --- a/.github/workflows/manual_regenerate_models.yaml +++ b/.github/workflows/manual_regenerate_models.yaml @@ -79,9 +79,9 @@ jobs: - name: Generate models from OpenAPI spec run: | if [[ -f openapi-spec/openapi.json ]]; then - uv run datamodel-codegen --input openapi-spec/openapi.json + uv run poe generate-models-from-file openapi-spec/openapi.json else - uv run datamodel-codegen + uv run poe generate-models fi - name: Commit model changes diff --git a/pyproject.toml b/pyproject.toml index cee47d80..ffc77fda 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -269,4 +269,16 @@ shell = "./build_api_reference.sh && corepack enable && yarn && uv run yarn star cwd = "website" [tool.poe.tasks.generate-models] -shell = "uv run datamodel-codegen" +shell = "uv run datamodel-codegen && python scripts/fix_generated_models.py" + +[tool.poe.tasks.generate-models-from-file] +# The --input flag is ignored when url is set in pyproject.toml, so we temporarily +# replace url with input, run the generator, and restore the original pyproject.toml. +shell = """ +sed -i 's|^url = .*|input = "'"$input_file"'"|' pyproject.toml +uv run datamodel-codegen && python scripts/fix_generated_models.py +STATUS=$? +git checkout pyproject.toml +exit $STATUS +""" +args = [{ name = "input-file", positional = true, required = true }] From 746b9f94dc355f860b51f16ccef9738d64b8a15f Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 7 Apr 2026 17:00:36 +0200 Subject: [PATCH 2/2] ci: move url/input args from datamodel-codegen config to poe tasks Remove `url` from [tool.datamodel-codegen] config and pass it explicitly via --url/--input in poe tasks. This eliminates the sed workaround in generate-models-from-file and prevents --input from being silently ignored when url is set in config. Co-Authored-By: Claude Opus 4.6 (1M context) --- pyproject.toml | 13 ++----- scripts/postprocess_generated_models.py | 46 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 scripts/postprocess_generated_models.py diff --git a/pyproject.toml b/pyproject.toml index ffc77fda..10a60135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -208,7 +208,6 @@ context = 7 # https://koxudaxi.github.io/datamodel-code-generator/ [tool.datamodel-codegen] -url = "https://docs.apify.com/api/openapi.json" input_file_type = "openapi" output = "src/apify_client/_models.py" target_python_version = "3.11" @@ -269,16 +268,8 @@ shell = "./build_api_reference.sh && corepack enable && yarn && uv run yarn star cwd = "website" [tool.poe.tasks.generate-models] -shell = "uv run datamodel-codegen && python scripts/fix_generated_models.py" +shell = "uv run datamodel-codegen --url https://docs.apify.com/api/openapi.json && python scripts/postprocess_generated_models.py" [tool.poe.tasks.generate-models-from-file] -# The --input flag is ignored when url is set in pyproject.toml, so we temporarily -# replace url with input, run the generator, and restore the original pyproject.toml. -shell = """ -sed -i 's|^url = .*|input = "'"$input_file"'"|' pyproject.toml -uv run datamodel-codegen && python scripts/fix_generated_models.py -STATUS=$? -git checkout pyproject.toml -exit $STATUS -""" +shell = "uv run datamodel-codegen --input $input_file && python scripts/postprocess_generated_models.py" args = [{ name = "input-file", positional = true, required = true }] diff --git a/scripts/postprocess_generated_models.py b/scripts/postprocess_generated_models.py new file mode 100644 index 00000000..46a1d0ab --- /dev/null +++ b/scripts/postprocess_generated_models.py @@ -0,0 +1,46 @@ +"""Post-process the generated _models.py to fix known datamodel-codegen issues. + +Currently fixes: +- Discriminator field names: datamodel-codegen sometimes emits the JSON property name (camelCase) + instead of the Python field name (snake_case) in `Field(discriminator='...')` annotations, + particularly when the discriminator is on a schema referenced inside array items. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +MODELS_PATH = Path(__file__).resolve().parent.parent / 'src' / 'apify_client' / '_models.py' + +# Map of camelCase discriminator values to their snake_case equivalents. +# Add new entries here as needed when the OpenAPI spec introduces new discriminators. +DISCRIMINATOR_FIXES: dict[str, str] = { + 'pricingModel': 'pricing_model', +} + + +def fix_discriminators(content: str) -> str: + """Replace camelCase discriminator values with their snake_case equivalents.""" + for camel, snake in DISCRIMINATOR_FIXES.items(): + content = re.sub( + rf"discriminator='{camel}'", + f"discriminator='{snake}'", + content, + ) + return content + + +def main() -> None: + content = MODELS_PATH.read_text() + fixed = fix_discriminators(content) + + if fixed != content: + MODELS_PATH.write_text(fixed) + print(f'Fixed discriminator values in {MODELS_PATH}') + else: + print('No discriminator fixes needed') + + +if __name__ == '__main__': + main()