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.22% 94.06% -1.17%
==========================================
Files 45 48 +3
Lines 5154 5237 +83
==========================================
+ Hits 4908 4926 +18
- Misses 246 311 +65
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:
|
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.
There was a problem hiding this comment.
I don't think so, TypedDicts don't have anything like Field(alias=...).
AI summary of what we do with the models:
The generated Pydantic models use
model_config = ConfigDict(populate_by_name=True)and each field has a camelCaseField(alias=...).populate_by_name=Truetells Pydantic "when constructing or validating, accept either the Python field name (snake_case) or the declared alias (camelCase)." So something likeRun.model_validate({'defaultDatasetId': 'x'})andRun.model_validate({'default_dataset_id': 'x'})both work today. Serialization still emits camelCase (via by_alias=True) so the wire format matches the API.
But TypedDicts don't have the equivalent of Pydantic's Field(alias=...) and there's no built-in way to declare "this key may be either unique_key or uniqueKey" in a single TypedDict. We would have to generate a 2nd TypedDict for every model with camelCase keys, and then combined it via union in the input. IMO that would be horrible.
There was a problem hiding this comment.
We would have to generate a 2nd TypedDict for every model with camelCase keys, and then combined it via union in the input.
Yeah, that's what I had in mind.
IMO that would be horrible.
Care to elaborate? 😁 I agree that it would increase the amount of generated code by quite a bit, but it could also be more approachable for users (even from a BC point of view).
| 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?
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>
aa1c2ab to
8c286c0
Compare
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.