You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Consider accepting both snake_case and camelCase values for dicts and Literals #756
I think there is a case for accepting camelCase here instead - it is exactly what the API accepts. On the other hand, snake_case fits in better with the rest of the Python code and works better for the "I just don't want to look up what model I need to import" use case for TypedDicts.
The same tension already exists today for Literal values used in resource-client methods, e.g.:
The Apify API expects these as camelCase (createdAt, lastRunStartedAt), while the Python client exposes them in snake_case to match Python conventions. The same question now arises for the newly generated input-side TypedDicts from #738 (field names in dicts passed to client methods).
Proposal
Consider — and, if agreed, implement — accepting bothsnake_case and camelCase values in:
Literal arguments already present across resource clients (e.g. sort_by, pricing-model literals, webhook event-type literals, etc.) — accept both forms.
Trade-offs to weigh
Pro snake_case only: consistent with Pydantic models and the rest of the Python code; idiomatic for Python users.
Pro camelCase only: matches the API 1:1 — users who already know the API don't need a translation table, which is especially valuable for the "I don't want to import the Pydantic model, just pass a dict" use case.
Pro accepting both: maximum ergonomics, no wrong answer for the user; cost is implementation complexity (normalization layer) and documentation/typing clarity (both forms must be reflected in the type hints so the type checker accepts them).
Scope
Decide on the policy (one style only vs. both accepted).
If accepting both: define normalization boundary (input translation to API payload), update generation scripts (scripts/postprocess_generated_models.py) and the hand-written literals in resource clients, and ensure type checkers (ty) see both forms.
No action here. We've already decided to keep literal values verbatim as the API spells them (UPPERCASE enums, 'createdAt', etc.) rather than introducing snake_case variants with a translation layer.
TypedDicts
Open question, runtime already does the right thing.
All TypedDicts in _typeddicts.py use snake_case keys.
On every resource-client method that accepts <Name>Dict | <Name>, the dict is round-tripped through <Name>.model_validate(dict) before being sent.
Which means it accepts both snake_case and camelCase keys at runtime. Only the type checker rejects it.
The remaining question is whether to make the type checker accept camelCase keys too. Python's TypedDict has no alias mechanism, so the only ways are:
Generate a snake variant + camel variant per shape and union them — doubles the public surface, no mixed-key dicts, autocomplete becomes ambiguous.
Status quo + document that camelCase keys are runtime-tolerated.
I'm not convinced the downsides of option 1 are justified, so I'd rather go with option 2.
* The remaining question is whether to make the type checker accept `camelCase` keys too. Python's TypedDict has no alias mechanism, so the only ways are:
1. Generate a snake variant + camel variant per shape and union them
- doubles the public surface
With respect to the number of attributes, that's a conservative estimate - not every key is made of multiple words 🙂 Of course, there would be two TypedDicts instead of one, that much is true.
- no mixed-key dicts
I'd argue that this is desirable.
- autocomplete becomes ambiguous.
In the sense that it would offer both versions of a key, correct? I'd try this out on a simple mock function to see how vscode intellisense handles it.
2. Status quo + document that `camelCase` keys are runtime-tolerated.
Documentation that says that you don't really need to trust the type checker is not great for multiple reasons.
I'm not convinced the downsides of option 1 are justified, so I'd rather go with option 2.
Do you mean the three mentioned above or did something slip? If not, then the only serious issue I see is the ambiguous autocompletion, and I think we should at least try it live to see the actual practical impact would be.
Activity
vdusek commentedon May 11, 2026
Update...
Literals
UPPERCASEenums, 'createdAt', etc.) rather than introducingsnake_casevariants with a translation layer.TypedDicts
_typeddicts.pyusesnake_casekeys.<Name>Dict | <Name>, the dict is round-tripped through<Name>.model_validate(dict)before being sent.snake_caseandcamelCasekeys at runtime. Only the type checker rejects it.camelCasekeys too. Python's TypedDict has no alias mechanism, so the only ways are:camelCasekeys are runtime-tolerated.I'm not convinced the downsides of option 1 are justified, so I'd rather go with option 2.
@janbuchar please let me know what you think.
janbuchar commentedon May 11, 2026
With respect to the number of attributes, that's a conservative estimate - not every key is made of multiple words 🙂 Of course, there would be two TypedDicts instead of one, that much is true.
I'd argue that this is desirable.
In the sense that it would offer both versions of a key, correct? I'd try this out on a simple mock function to see how vscode intellisense handles it.
Documentation that says that you don't really need to trust the type checker is not great for multiple reasons.
Do you mean the three mentioned above or did something slip? If not, then the only serious issue I see is the ambiguous autocompletion, and I think we should at least try it live to see the actual practical impact would be.
vdusek commentedon May 14, 2026
Thanks for your opinion. I'll try to implement a PoC, see how big it's gonna be, and whether/how the IDEs &
tyare able to deal with it.feat: accept camelCase keys in input TypedDicts
feat: accept camelCase keys in input TypedDicts (#793)