Skip to content

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

Open
iscai-msft wants to merge 34 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 34 commits into
microsoft:mainfrom
iscai-msft:python/addTypedDict

Conversation

@iscai-msft
Copy link
Copy Markdown
Member

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

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
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 21, 2026

Open in StackBlitz

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

commit: 136e247

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

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

@azure-sdk
Copy link
Copy Markdown
Collaborator

azure-sdk commented Apr 21, 2026

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
iscai-msft and others added 17 commits May 6, 2026 10:40
- Skip rest_field/rest_discriminator imports for TYPES_FILE context
- Use bare model/enum names in types.py instead of _models.Name prefix
  to avoid pyright reportInvalidTypeForm with dotted forward refs
- Import model/enum names directly from .models under TYPE_CHECKING
- Fix unions file to properly import and reference discriminated subtypes
- Fix typed-dict-only import style to use 'from .. import types' module

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

# Conflicts:
#	packages/http-client-python/eng/scripts/ci/regenerate.ts
Discriminated model unions now reference TypedDict subtypes instead of
_Model classes. Union aliases are generated in types.py alongside the
TypedDict definitions, and _unions.py is only generated when named
unions exist.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ensures nested discriminated bases (e.g. Shark) are defined before
their parents (e.g. Fish = Union[Salmon, Shark]).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All TypedDict models are defined in the same types.py file, so cross-
namespace model imports also cause redefinition errors. Remove the
same_namespace check so any model that will be a TypedDict is never
imported from its models module.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Discriminated bases are now Union aliases in types.py, so they must
also be excluded from TYPE_CHECKING imports to avoid shadowing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a TypedDict field wire_name matches a Python builtin type name
(e.g. 'int'), it shadows that builtin in subsequent annotations.
Move such properties to the end of the class to prevent this.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use builtins.X qualification when a TypedDict field wire_name shadows
  a Python builtin type name (e.g. int, str, list) that appears in
  type annotations within the same class
- Add functional TypedDict form for models with Python keyword wire_names
  (e.g. and, class, for) since keywords can't be identifiers in class bodies
- Only import builtins when actually needed (when shadowed builtins appear
  in annotations)
- Remove the previous sorting workaround

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously types.py was only generated once at the root namespace with
all models. Now it's generated per namespace alongside the models/
folder, using only that namespace's models. This ensures sub-namespaces
like modelproperties/ get their own types.py.

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

2 participants