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
@microsoft-github-policy-service microsoft-github-policy-service Bot added the stale Mark a PR that hasn't been recently updated and will be closed. label Sep 3, 2026
@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

Hi @Kashif Khan (@kashifkhan). Your PR has had no update for 14 days and it is marked as a stale PR. If it is not updated within 14 additional days, the PR will automatically be closed. If you want to refresh the PR, please remove the stale label.

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 stale Mark a PR that hasn't been recently updated and will be closed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants