Skip to content

[Python] - Improve Model Deserialization Perf - #11705

Draft
Kashif Khan (kashifkhan) wants to merge 4 commits into
mainfrom
kashifkhan/deserialization_perf
Draft

[Python] - Improve Model Deserialization Perf#11705
Kashif Khan (kashifkhan) wants to merge 4 commits into
mainfrom
kashifkhan/deserialization_perf

Conversation

@kashifkhan

@kashifkhan Kashif Khan (kashifkhan) commented Aug 17, 2026

Copy link
Copy Markdown
Member

This PR focusses on improving the performance of the deserialization path of python generated files. I wanted to focus on a couple areas where speed ups could be done and see some results

  • Do less work :) - today, when a model is built from a parsed payload, every value was sent to _serialize. Things like int, float, list[str] don't need to be serialized. Store them as is and work on things that need it
  • Look things up once, not every time — we compute two things one time per model class: a rest_name2field map, and the small list of fields that have client defaults. That way building each object skips re-scanning all the fields
  • Annotation Cache - figuring out how to deserialize a field (e.g. List[Pet], Optional[datetime]) means walking typing internals, and the answer never changes for a given type, so it's cached.
    On a ~5.6 MB DocumentIntelligence-shaped (why I started this) response on Python 3.10:

• Building the model tree: ~2.7× faster (~880 ms dropped to ~330 ms)
• Build + read every field: roughly halved (~2.0 s dropped to ~1.15 s)

@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 Aug 17, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 5227b40

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

❌ There is undocummented changes. Run chronus add to add a changeset or click here.

The following packages have changes but are not documented.

  • @typespec/http-client-python
Show changes

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Python emitter diff

Baseline gh:df318a15173a362f0f2bbccc7bd8a74ee8168e05 vs this PR.

Diff summary: 204 file(s), +29988 / -1836

Rendered diff: inline on the run summary, or the emitter-diff-html artifact.

Informational check (eng/emitter-diff); does not block the PR.

@azure-sdk-automation

azure-sdk-automation Bot commented Aug 17, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

dict_to_pass.update(
{k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()}
{
k: create_value(rest_field_by_rest_name.get(k), v)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

just to double click, are we sure that rest_field_by_rest_name.get(k) has the same fallback path for _get_rest_field(self._attr_to_rest_field, k) with keys that aren't rest names?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes pretty sure that is the case ( are there any tests/edge case etc I can use to further confirm ? )

right now in main we have

{k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()}

and _get_rest_field is:

 try:
        return next(rf for rf in attr_to_rest_field.values() if rf._rest_name == rest_name)
    except StopIteration:
        return None

Same dict ( attr_to_rest_field.values() ), same key ( rf._rest_name ), right after _rest_name is finalized — so  .get(k)  returns the identical  _RestField for a match and None  for a non-rest-name key

def _deserialize(cls, data, exist_discriminators):
if not hasattr(cls, "__mapping__"):
return cls(data)
return cls(data) if isinstance(data, ET.Element) else cls(_OwnedWireValue(data))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: maybe combine these two cls(data) if ... else ... into one function / variable definition

@kashifkhan
Kashif Khan (kashifkhan) force-pushed the kashifkhan/deserialization_perf branch from d85b447 to 5227b40 Compare August 18, 2026 21:33
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.

2 participants