Skip to content

feat!: generate Literal type aliases instead of StrEnum classes#759

Merged
vdusek merged 5 commits intomasterfrom
feat/literals-instead-of-enums
May 3, 2026
Merged

feat!: generate Literal type aliases instead of StrEnum classes#759
vdusek merged 5 commits intomasterfrom
feat/literals-instead-of-enums

Conversation

@vdusek
Copy link
Copy Markdown
Contributor

@vdusek vdusek commented Apr 23, 2026

Issue

Description

Replaces every generated class X(StrEnum) with a X = Literal[...] alias. Users pass plain strings (status='RUNNING') instead of enum members, the aliases are reusable across method signatures, and behavior matches Crawlee and the Apify SDK — avoiding mixing-enum-with-string footguns like #575.

Why post-processing

The natural fix — --enum-field-as-literal=all + --use-type-alias on datamodel-code-generator — only handles enums referenced from operation parameters; the rest get inlined at every reference site with no stable name to import. Filed upstream as koxudaxi/datamodel-code-generator#3104. Until that lands, scripts/postprocess_generated_models.py does the rewrite ourselves; once fixed, we can drop the post-processing.

What the post-process does

  • convert_enums_to_literals — rewrites every top-level class X(StrEnum) to X = Literal[...], preserving value order and class docstring.
  • deduplicate_error_type_enum — removes the duplicate inlined class Type(StrEnum) datamodel-codegen emits alongside the named ErrorType (same upstream issue), and rewires Type annotations to ErrorType. AST-based.
  • split_literals_to_file — moves the 11 alias blocks into _literals_generated.py so consumers don't pull in every Pydantic model.
  • snake_case_camelcase_literal_values — converts camelCase string values (StorageOwnership's 'ownedByMe'/'sharedWithMe') to snake_case and emits _<NAME>_WIRE_VALUES so resource clients can convert back to the wire format.

The hand-maintained _types.py is renamed to _literals.py for symmetry.

Consumers

  • All internal code imports the aliases via TYPE_CHECKING where possible.
  • dataset_collection, key_value_store_collection, request_queue_collection translate ownership back to wire format via _STORAGE_OWNERSHIP_WIRE_VALUES.
  • _TERMINAL_STATUSES in _resource_client.py is derived from TerminalActorJobStatus via typing.get_args() — single source of truth.
  • Docstrings, integration tests, unit tests, and the two docs/02_concepts/code/03_nested_*.py examples no longer reference .MEMBER / .MEMBER.value.

Tests

tests/unit/test_postprocess_generated_models.py covers each step independently plus a full-pipeline integration test.

Breaking change

Tracked under v3 on #576. ActorJobStatus.RUNNING and similar enum-member access no longer exists — pass the plain string instead.

@vdusek vdusek added adhoc Ad-hoc unplanned task added during the sprint. t-tooling Issues with this label are in the ownership of the tooling team. labels Apr 23, 2026
@vdusek vdusek self-assigned this Apr 23, 2026
@github-actions github-actions Bot added this to the 139th sprint - Tooling team milestone Apr 23, 2026
@github-actions github-actions Bot added the tested Temporary label used only programatically for some analytics. label Apr 23, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.41%. Comparing base (fe6546b) to head (475d7b7).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #759      +/-   ##
==========================================
+ Coverage   95.57%   97.41%   +1.84%     
==========================================
  Files          46       47       +1     
  Lines        5174     4725     -449     
==========================================
- Hits         4945     4603     -342     
+ Misses        229      122     -107     
Flag Coverage Δ
integration 95.17% <100.00%> (-0.40%) ⬇️
unit 82.11% <93.54%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vdusek vdusek force-pushed the feat/literals-instead-of-enums branch from 36b6927 to b306913 Compare April 27, 2026 15:01
@vdusek vdusek marked this pull request as ready for review April 27, 2026 15:57
@vdusek vdusek requested review from Pijukatel and janbuchar April 27, 2026 15:58
@vdusek vdusek force-pushed the feat/literals-instead-of-enums branch from ff6fa87 to 965eb8b Compare April 28, 2026 14:08
Comment thread src/apify_client/_types.py
Comment thread scripts/postprocess_generated_models.py Outdated
vdusek added 3 commits April 30, 2026 01:58
…ad-of-enums

# Conflicts:
#	docs/02_concepts/code/03_nested_async.py
#	docs/02_concepts/code/03_nested_sync.py
#	scripts/postprocess_generated_models.py
#	src/apify_client/_consts.py
#	src/apify_client/_models.py
#	src/apify_client/_models_generated.py
#	src/apify_client/_resource_clients/_resource_client.py
#	src/apify_client/_resource_clients/actor.py
#	src/apify_client/_resource_clients/dataset.py
#	src/apify_client/_resource_clients/dataset_collection.py
#	src/apify_client/_resource_clients/key_value_store.py
#	src/apify_client/_resource_clients/key_value_store_collection.py
#	src/apify_client/_resource_clients/request_queue.py
#	src/apify_client/_resource_clients/request_queue_collection.py
#	src/apify_client/_resource_clients/run.py
#	src/apify_client/_resource_clients/run_collection.py
#	src/apify_client/_resource_clients/task.py
#	src/apify_client/_resource_clients/task_collection.py
#	src/apify_client/_resource_clients/webhook.py
#	src/apify_client/_resource_clients/webhook_collection.py
#	tests/integration/test_actor_version.py
#	tests/integration/test_run.py
#	tests/integration/test_webhook.py
#	tests/unit/test_actor_start_params.py
#	tests/unit/test_logging.py
#	tests/unit/test_storage_collection_listing.py
#	tests/unit/test_utils.py
- Revert `_literals.py` rename back to `_types.py` since the file holds
  non-literal types (`WebhooksList`, `Timeout`, `JsonSerializable`) too.
- Rename `snake_case_camelcase_literal_values` to
  `convert_camelcase_literal_values_to_snake_case` so the input/output
  conventions are explicit in the name.
@vdusek vdusek requested a review from janbuchar April 30, 2026 08:55
Copy link
Copy Markdown
Contributor

@janbuchar janbuchar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I like where this is going, but I feel like we need to align about some inconsistencies.

Comment thread docs/04_upgrading/upgrading_to_v3.mdx Outdated
@vdusek vdusek requested a review from janbuchar April 30, 2026 14:03
Copy link
Copy Markdown
Contributor

@janbuchar janbuchar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left one comment that is not really relevant to this PR - please either dismiss it or make an issue to track it.

Comment thread tests/integration/test_actor.py
@vdusek vdusek merged commit 2bf5a75 into master May 3, 2026
26 checks passed
@vdusek vdusek deleted the feat/literals-instead-of-enums branch May 3, 2026 17:34
@vdusek vdusek changed the title feat: generate Literal type aliases instead of StrEnum classes feat!: generate Literal type aliases instead of StrEnum classes May 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

adhoc Ad-hoc unplanned task added during the sprint. t-tooling Issues with this label are in the ownership of the tooling team. tested Temporary label used only programatically for some analytics.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prefer using literal types over enums

3 participants