Skip to content

fix(python): keep resources out of the payload converter - #104

Closed
moetemp wants to merge 2 commits into
moe/up/upstream-344from
moe/up/resource-not-data
Closed

moetemp wants to merge 2 commits into
moe/up/upstream-344from
moe/up/resource-not-data

Conversation

@moetemp

@moetemp moetemp commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

What changed?

This PR makes generated Python resources with methods plain classes, so the payload converter refuses them.

  • With Add independent Python client generation and explicit API targets temporalio/nexgen#344, a resource is a dataclass. So a client Stream encodes as its stream and created fields, and decodes as a Workflow Stream whose publish, read and close work.
  • A resource with methods is now a plain class with the same __init__ and attributes, and __eq__ and __repr__ over its identity fields. The JSON converter refuses it in both directions. Code passes the identity fields, such as the stream sample's StreamRef, and builds the handle with the factory.
  • Workflow calls decode a direct resource result as its identity record, such as UserData, and then build the handle, as the client calls already do.
  • A resource with no methods, such as WorkflowHandle or SignalResult, has no calls, so it stays a dataclass, as in Add independent Python client generation and explicit API targets temporalio/nexgen#344.
  • TypeScript isn't affected, since its JSON converter returns plain objects and the generated code builds the handle. .NET has the same round trip, since a Workflow resource decodes into a handle whose calls work. Its fix needs identity records in the .NET service contracts, so it's for a follow-up PR if this direction is OK.

Why?

A handle has calls, so decoded data shouldn't turn into one. In the Nov. 2 handles sync, we agreed that code converts a handle explicitly, as the SDK's workflow.to_stream(handle) does.

How did you test it?

Link to a test plan if any -

  • Unit Tests
  • Staging
  • End to End Tests

The round-trip test now checks that encoding a resource raises, that decoding into the Workflow Stream raises, and that the StreamRef round-trips and gives an equal handle through the factory. The sample Workflows that returned a handle now return its identity record, and a new test checks that a SignalResult still round-trips. cargo test --all-features, cargo validate python and a full sample regeneration pass.

A handle has calls, so decoded data must not turn into one. A Python resource is a plain class
that the converter refuses, and Workflow calls decode a direct resource result as its identity
DTO before they build the handle.
A resource with no methods has no calls, so it stays a dataclass that the payload converter
encodes and decodes. Only a handle with calls is a plain class.
@moetemp

moetemp commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

Moved to temporalio#357.

@moetemp moetemp closed this Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant