SIGN IN SIGN UP

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

## Issue

- Closes #576

## 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](https://github.com/koxudaxi/datamodel-code-generator/issues/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.
V
Vlada Dusek committed
2bf5a75f38a74a48c5c9a9682d9eaf330da27935
Parent: 63b866a
Committed by GitHub <noreply@github.com> on 5/3/2026, 5:34:14 PM