Skip to content

[python] add typeddict models-mode for Python HTTP client emitter#10439

Open
iscai-msft wants to merge 79 commits into
microsoft:mainfrom
iscai-msft:python/addTypedDict
Open

[python] add typeddict models-mode for Python HTTP client emitter#10439
iscai-msft wants to merge 79 commits into
microsoft:mainfrom
iscai-msft:python/addTypedDict

Conversation

@iscai-msft

@iscai-msft iscai-msft commented Apr 21, 2026

Copy link
Copy Markdown
Member

fixes #8800

Add a new 'typeddict' value for the models-mode option that generates Python TypedDict classes instead of DPG model classes. Key features:

  • TypedDict classes with Required[T]/NotRequired[T] annotations
  • TypedDict inheritance for non-discriminated models
  • Discriminated models: Union of leaf TypedDicts, no abstract base class
  • Input-only: operations accept TypedDict input, return dict output
  • Wire names used as TypedDict keys
  • _model_base.py still generated for serialization utilities

Add a new 'typeddict' value for the models-mode option that generates
Python TypedDict classes instead of DPG model classes. Key features:

- TypedDict classes with Required[T]/NotRequired[T] annotations
- TypedDict inheritance for non-discriminated models
- Discriminated models: Union of leaf TypedDicts, no abstract base class
- Input-only: operations accept TypedDict input, return dict output
- Wire names used as TypedDict keys
- _model_base.py still generated for serialization utilities

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:python Issue for the Python client emitter: @typespec/http-client-python label Apr 21, 2026
@pkg-pr-new

pkg-pr-new Bot commented Apr 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-python@10439

commit: ceed358

@github-actions

github-actions Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-client-python
Show changes

@typespec/http-client-python - feature ✏️

[python] Always generate TypedDict typing hints for input models in the types.py file, and named union aliases in the _unions.py file

@azure-sdk

azure-sdk commented Apr 21, 2026

Copy link
Copy Markdown
Collaborator

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

iscai-msft and others added 12 commits April 21, 2026 14:37
- TypedDictModelType returns 'JSON' for response type annotations
- Response.type_annotation/docstring passes is_response=True
- Typeddict deserialization uses response.json() directly
- Removed NotRequired from TypedDictModelSerializer (total=False handles it)
- Updated mock API tests to verify JSON dict responses

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add client/naming typeddict variant to regenerate-common.ts
- Create test_client_naming_typeddict.py with 11 tests verifying TypedDict
  uses wire names (defaultName, wireName) not client names
- Tests cover: ClientNameModel, LanguageClientNameModel,
  ClientNameAndJsonEncodedNameModel, ClientModel, PythonModel

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
TypedDict is already JSON, so the MutableMapping[str, Any] overload
is unnecessary. Only keep TypedDict model + IO[bytes] overloads.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Typeddict mode uses response.json() directly, so _deserialize is never
called. Skip importing it to avoid W0611 unused-import lint warning.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove unused MutableMapping/Any imports from TypedDictModelType.imports()
- Skip _deserialize import in paging_operation.py for typeddict mode

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
TypedDictModelType returns 'JSON' for response type annotations but
never defined the JSON = MutableMapping[str, Any] type alias, causing
NameError at runtime.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@iscai-msft iscai-msft force-pushed the python/addTypedDict branch from 34e0cda to 95db199 Compare April 29, 2026 15:39
@msyyc

msyyc commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

There is new file named types.py for each package but in some packages like https://github.com/Azure/azure-sdk-for-python/pull/47346/changes#r3379542204, the file is not referred by other model/operation, is it expected?

@msyyc

msyyc commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@msyyc

msyyc commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@iscai-msft iscai-msft requested a review from kashifkhan as a code owner June 22, 2026 17:47
iscai-msft and others added 4 commits June 22, 2026 15:28
# Conflicts:
#	packages/http-client-python/generator/pygen/preprocess/__init__.py
- Add crossLanguageDefinitionId-based dedup to dpg model TypedDict creation
  (prevents duplicate TypedDict classes when multiple operations share the same body model)
- Dedup typeddict_models in TypesSerializer: prefer dpg model over typeddict copy
  when both exist with the same crossLanguageDefinitionId

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@iscai-msft

Copy link
Copy Markdown
Member Author

https://github.com/Azure/azure-sdk-for-python/pull/47346/changes#r3379640848

this is defined as a named union, that's why we generate it as one

iscai-msft and others added 3 commits June 24, 2026 12:12
…ct copies from _models.py

- Only add 'from . import types' to sync __init__.py, not aio
  (types.py is generated at the sync level, aio doesn't have one)
- Filter out base='typeddict' models from _models.py class list
  (typeddict copies should only appear in types.py, not as model classes)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 'List' import to ListType.imports() when property/operation named 'list'
  exists (fixes NameError in special-words types.py)
- Use has_non_json_models() for has_models in ModelInitSerializer to avoid
  generating 'from . import _models' when _models.py doesn't exist
- Remove 'from . import types' from __init__.py — each TypedDict type's
  imports() already handles adding the types import where needed (operations)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@iscai-msft iscai-msft force-pushed the python/addTypedDict branch from f77576c to 14b7d6c Compare June 24, 2026 20:20
iscai-msft and others added 3 commits June 24, 2026 16:31
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace is_operation_file with serialize_namespace_type to correctly
determine when to add the typing.List import. Operation/client files
only need it when has_operation_named_list is True, while model/types
files need it when has_property_named_list is True.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e conflicts

Remove the 'from typing import List' import entirely from ListType.
Types/model files now always use lowercase 'list' since a TypedDict
field named 'list' doesn't shadow the builtin. Operation files still
use the 'List = list' alias from define_mypy_type when there's an
operation named 'list'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@msyyc msyyc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Will take another review soon.

@msyyc msyyc self-requested a review June 25, 2026 00:18
The response type rendering passes is_operation_file=True but not
serialize_namespace_type, so we need to check both to correctly
determine operation context.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@msyyc msyyc self-requested a review June 25, 2026 00:19
iscai-msft and others added 5 commits June 25, 2026 12:56
For models that are typeddict-only (either via models-mode=typeddict or
individual models marked as typedDictOnly), skip the isinstance check
against _models.X (which doesn't exist) and skip json.dumps
serialization. TypedDict models are plain dicts and should be passed
directly to the request as JSON.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add tests passing TypedDicts to regular dpg operations (both sync and
  async) to verify model + typeddict combined overloads work
- Add async test for typeddictonly variant

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:python Issue for the Python client emitter: @typespec/http-client-python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Python] Add alpha TypedDict support

5 participants