feat: generate TypedDict types for input-side models#738
feat: generate TypedDict types for input-side models#738
Conversation
Codecov Report❌ Patch coverage is
❌ Your patch check has failed because the patch coverage (40.35%) is below the target coverage (50.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## master #738 +/- ##
==========================================
- Coverage 95.36% 94.03% -1.33%
==========================================
Files 45 48 +3
Lines 5118 5201 +83
==========================================
+ Hits 4881 4891 +10
- Misses 237 310 +73
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
1eb5c1d to
f63bb00
Compare
Add TypedDict counterparts for generated Pydantic models so users passing plain dicts to resource-client methods get full type-checker support without importing Pydantic models. Closes #666. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f63bb00 to
00f228a
Compare
|
@Pijukatel @janbuchar Let me guys know what you think, this change also has some drawbacks:
|
| The URL of the request. | ||
| """ | ||
| method: NotRequired[Literal['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']] | ||
| retry_count: NotRequired[int] |
There was a problem hiding this comment.
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. Did you consider this @vdusek?
There was a problem hiding this comment.
I think we should keep the public interface Python-idiomatic and stick with snake_case. I recently made some updates in this direction, moving the interface to snake_case, see #736.
I wouldn't have a bug problem in leaving it just as the API accepts it, but we would have to do it in all places to be consistent.
There was a problem hiding this comment.
Since we shove everything into Pydantic, we should also be perfectly capable of supporting both, no? Like, camelCase and snake_case version of every model where this is applicable.
| # Seed models for the TypedDict pruning. Every TypedDict in `_typeddicts.py` that is not | ||
| # transitively reachable from this set is removed. Keep in sync with the `dict | <Model>` unions | ||
| # on resource-client method signatures. | ||
| TYPEDDICT_SEEDS: frozenset[str] = frozenset( |
There was a problem hiding this comment.
The naming is more about the pruning algorithm than about the top-level intent. Why are these three selected?
Maybe some name like:
REQUIRED_DICTS or USED_DICTS ...
and some hint in the comment about why just these 3 are selected
| return refs - exclude | ||
|
|
||
|
|
||
| def _compute_transitive_closure(deps: dict[str, set[str]], seeds: set[str]) -> set[str]: |
There was a problem hiding this comment.
Usage of closure in naming can be misleading, as it has its own meaning in Python, different from set theory, and while reading Python code, the reader will probably have the Python meaning in mind first.
Maybe better name based on what is the purpose of it:
_compute_reachable_symbols or _compute_transitive_dependencies or ...
and same for closure: set[str] = set() -> reachable_symbols or transitive_dependencies or...
| def test_webhook_representation_list_from_dicts() -> None: | ||
| """Test that from_webhooks accepts plain dicts with the minimal ad-hoc webhook shape.""" | ||
| result = WebhookRepresentationList.from_webhooks( | ||
| # The runtime only needs the keys consumed by WebhookRepresentation (event_types, request_url, |
There was a problem hiding this comment.
If it does not require so much, is the typing correct?
Summary
Adds
TypedDictcounterparts for input-side models so users passing plain dicts to resource-client methods get full type-checker support without importing Pydantic models.datamodel-code-generatorpass (--output-model-type typing.TypedDict) inpoe generate-models._models_generated.py/_typeddicts_generated.py. Hand-written_models.py/_typeddicts.pynow only hold shapes not exposed by the OpenAPI spec (e.g.RequestInput,RequestInputDict).scripts/postprocess_generated_models.pyto trim the TypedDict file to input-relevant classes (plus transitive deps), rename them with aDictsuffix, and add@docs_group('Typed dicts').actor,task,task_collection,request_queue) to acceptTypedDict | PydanticModelunions..rules.mdandmanual_regenerate_models.yamlto reflect the new layout.Closes #666.