Skip to content

feat(http-client-python): generate structured JSONL/SSE streaming - #11594

Draft
Libba Lawrence (l0lawrence) wants to merge 2 commits into
mainfrom
l0lawrence-jsonl-sse-streaming-codegen
Draft

feat(http-client-python): generate structured JSONL/SSE streaming#11594
Libba Lawrence (l0lawrence) wants to merge 2 commits into
mainfrom
l0lawrence-jsonl-sse-streaming-codegen

Conversation

@l0lawrence

Copy link
Copy Markdown
Member

Summary

  • Generate Azure-flavor client methods that return Stream[T] / AsyncStream[T] for JSONL (application/jsonl) and SSE (text/event-stream) response streams.
  • Use TCGC streamMetadata / sseMetadata to deserialize JSONL items and dispatch named SSE events to their concrete generated models, including terminal-event handling.
  • Vendor the JSONL/SSE streaming runtime in generated packages while preserving unbranded raw-byte iterator behavior.
  • Preserve registered stream item-type references across request overloads.
stream = client.receive()  # Stream[Thing]
for thing in stream:
    ...

Coverage

  • Emitter structured-streaming tests
  • Pygen response and serializer coverage
  • Azure JSONL/SSE regeneration
  • Sync and async Spector smoke coverage for homogeneous and heterogeneous streams

Notes

This uses the TCGC prerelease containing sseMetadata. The external Azure mock API streaming test still asserts the previous raw-byte contract and is expected to remain failing until that test is aligned with the type-driven behavior.

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

pkg-pr-new Bot commented Aug 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 1d5dddc

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-client-python
Show changes

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

Generate structured streaming client methods for the Azure flavor: operations whose HTTP response is a JSONL (application/jsonl) or SSE (text/event-stream) stream now return Stream[T] / AsyncStream[T], yielding deserialized model instances instead of raw bytes.,> ,> Stream and AsyncStream are available from the generated package's base namespace. Their runtime (plus the JSONL / SSE decoders) is vendored at _utils/streaming_base.py, so it depends only on the released azure.core.rest.,> ,> python,> from your_sdk import Stream,> ,> stream: Stream[Thing] = client.receive(),> for thing in stream:,> ...,>

@l0lawrence Libba Lawrence (l0lawrence) changed the title feat(http-client-python): generate structured JSONL/SSE streaming (Azure flavor) feat(http-client-python): generate structured JSONL/SSE streaming Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Python emitter diff

Baseline gh:006b5cbfca9336a6b9bf127cf716fe645a201fa7 vs this PR.

Diff summary: 129 file(s), +14423 / -76

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 7, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

Copilot AI 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.

Pull request overview

This PR adds structured streaming support to the TypeSpec Python emitter/generator for the Azure flavor, emitting client methods that return Stream[T] / AsyncStream[T] for JSONL (application/jsonl) and SSE (text/event-stream) responses, using TCGC streaming metadata to drive per-item deserialization and SSE event dispatch. It also vendors a small streaming runtime into generated packages to avoid requiring an unreleased azure.core.streaming dependency.

Changes:

  • Emit a streaming block in response YAML for structured JSONL/SSE streams (including SSE event/terminal metadata) and preserve it across request overloads.
  • Generate and write a vendored _utils/streaming_base.py runtime (Stream/AsyncStream + JSONL/SSE decoders) when needed, and update response/operation modeling + response handling to return Stream[T]/AsyncStream[T].
  • Add emitter-side unit tests for structured-stream detection and update dependency versions to TCGC prereleases that expose sseMetadata.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/http-client-python/README.md Documents structured streaming behavior for Azure flavor and the vendored runtime.
packages/http-client-python/package.json Updates dev dependencies to prereleases and adds an npm overrides entry for compiler version alignment.
packages/http-client-python/package-lock.json Locks new prerelease dependency resolutions used by the emitter/generator tests.
packages/http-client-python/generator/pygen/preprocess/init.py Preserves streaming metadata across generated overload YAML updates.
packages/http-client-python/generator/pygen/codegen/templates/streaming_base.py.jinja2 Adds vendored streaming runtime template (Stream/AsyncStream + JSONL/SSE decoding).
packages/http-client-python/generator/pygen/codegen/serializers/general_serializer.py Adds serializer for the new streaming runtime template.
packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py Emits response handling that returns Stream/AsyncStream with per-item deserialization callbacks.
packages/http-client-python/generator/pygen/codegen/serializers/init.py Writes _utils/streaming_base.py when structured streaming is present.
packages/http-client-python/generator/pygen/codegen/models/response.py Models structured stream metadata, stream return annotations, and imports needed for generated operations.
packages/http-client-python/generator/pygen/codegen/models/operation.py Forces stream=True for structured streaming operations and exposes a structured-stream predicate.
packages/http-client-python/generator/pygen/codegen/models/code_model.py Tracks whether any structured streaming exists to decide if vendored runtime must be emitted.
packages/http-client-python/emitter/test/streaming.test.ts Adds emitter unit tests for structured-stream detection and kind inference.
packages/http-client-python/emitter/src/http.ts Emits response streaming YAML using TCGC stream/sse metadata; adds structured stream detection helpers.
cspell.yaml Adds streaming/runtime-related identifiers to the spellchecker dictionary.
.chronus/changes/structured-streaming-2026-0-0.md Changelog entry describing the new Azure-flavor structured streaming support.
Files not reviewed (1)
  • packages/http-client-python/package-lock.json: Generated file

Comment on lines +44 to +68
def iter_events(self, iter_bytes: Iterator[bytes]) -> Iterator[T_co]:
"""Iterate over events from a byte iterator.

:param iter_bytes: An iterator of byte chunks.
:type iter_bytes: Iterator[bytes]
:return: An iterator of decoded data.
:rtype: Iterator[DecodedType_co]
"""
...


@runtime_checkable
class AsyncStreamDecoder(Protocol[T_co]):
"""Protocol for async stream decoders."""

# Why this isn't async def: https://mypy.readthedocs.io/en/stable/more_types.html#asynchronous-iterators
def aiter_events(self, iter_bytes: AsyncIterator[bytes]) -> AsyncIterator[T_co]:
"""Asynchronously iterate over events from a byte iterator.

:param iter_bytes: An asynchronous iterator of byte chunks.
:type iter_bytes: AsyncIterator[bytes]
:return: An asynchronous iterator of decoded data.
:rtype: AsyncIterator[DecodedType_co]
"""
...
Comment on lines +122 to +129
async def aiter_lines(iter_bytes: AsyncIterator[bytes]) -> AsyncIterator[str]:
"""Iterate over lines from a byte iterator.

:param iter_bytes: An iterator of byte chunks.
:type iter_bytes: Iterator[bytes]
:rtype: Iterator[str]
:return: An iterator of lines.
"""
@l0lawrence
Libba Lawrence (l0lawrence) force-pushed the l0lawrence-jsonl-sse-streaming-codegen branch from d93a175 to c3924da Compare August 7, 2026 19:14
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e57edafe-9764-4b99-a1ae-0efd56e8729e
@l0lawrence
Libba Lawrence (l0lawrence) force-pushed the l0lawrence-jsonl-sse-streaming-codegen branch from c3924da to 294b0c5 Compare August 7, 2026 19:22

def serialize_init_file(self, clients: list[Client]) -> str:
template = self.env.get_template("init.py.jinja2")
expose_streaming_types = (

@l0lawrence Libba Lawrence (l0lawrence) Aug 10, 2026

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.

Instead of doing this and exposing Stream directly since we are going to eventually use azure-core, should we not expose this and instead type the outputs as Iterators that will eventually become an iterator created by azure-core vs gen code vendor?

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