Skip to content

fix: address the review of API targets and the Python client target - #346

Merged
tconley1428 merged 21 commits into
refactor/api-generation-targetsfrom
moe/fix/api-generation-targets-review
Oct 30, 2026
Merged

tconley1428 merged 21 commits into
refactor/api-generation-targetsfrom
moe/fix/api-generation-targets-review

Conversation

@moetemp

@moetemp moetemp commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

What changed?

This PR fixes the issues from the review of #344.

  • The sample defaults that need Workflow code say targets="workflow".
  • With no --targets, WIT with resources or sources generates again, as on main.
  • A client handle gets the Nexus client of its own service. Each extension has a get_<resource> factory to rebuild one.
  • The client protocol matches temporalio.client.NexusClient.
  • A resource field wins over a source of the same name, in every language.
  • examples.toml refuses bad input with clear errors.
  • The stream sample gets the Python client target, through a config variant.

Why?

With #344 alone, existing WIT broke with --targets client, definitions-only generation refused resources, and a temporalio.client.Client couldn't be the client.

How did you test it?

Link to a test plan if any -

  • Unit Tests
  • Staging
  • End to End Tests

The golden samples show most fixes, and the rest have a sample test or a rejection fixture. test_sdk_client.py runs a real temporalio.client.Client subclass through the SDK's Nexus path. Generation with no target has no test yet.

@moetemp
moetemp marked this pull request as ready for review October 30, 2026 07:20
@moetemp
moetemp requested a review from a team as a code owner October 30, 2026 07:20
@moetemp
moetemp marked this pull request as draft October 30, 2026 07:23
@moetemp
moetemp force-pushed the moe/fix/api-generation-targets-review branch from a5c7270 to 4875677 Compare October 30, 2026 08:06
@tconley1428
tconley1428 force-pushed the refactor/api-generation-targets branch from 798a802 to f746287 Compare October 30, 2026 18:17
A default without a target list applies to every target, and these helpers need a Workflow context.
`PythonTarget` copied `GenerationTarget`, and two checks ran twice per run. A
private client method named `_create_nexus_client` replaced the extension hook.
One long line has no trailing comma, so `ruff format` joined the requests in the
samples, and unformatted output got lines of about 200 characters.
Without a source default in the shared model, decode refused an empty sourced
value. A handler then rejected requests that it accepted before.
The root classes had stub methods that always raised, and the client package
kept private copies of them. The client now decodes results into the root
classes.
A handler that implements a service generates definitions only, from the WIT
that its callers share. That WIT can have resources and sources, and the
default build has no `--targets`, so it couldn't generate such WIT at all.
When another interface returned a resource, the handle kept the client of the
returning service, so its methods started operations on the wrong endpoint.
`Client.create_nexus_client` didn't fit the generated hook, so a real client
failed to type-check and to run. The SDK needs an operation ID, so each call
passes a new random one.
To rebuild a client handle from stored identity fields, a caller needed the
private `_create_nexus_client` hook and the wire names of the service.
A misspelled key was read as a child configuration and the parent then stopped generating. The error now names the key and its section.
A misspelled section name gave definitions-only output with no error, or an error that did not point at examples.toml.
Children whose names map to one directory in any language would merge their files. Names with a leading digit or a Python keyword are not importable packages.
The target-sources sample now builds for the workflow target in all three languages. Go filled sourced fields only on proto-backed inputs, so operations without a proto input now fill them too.
Go output with no Workflow API kept the imports of that API and did not compile. The renderer pruned only aliased imports, and now prunes plain ones too.
The client constructor line describes a new feature, so it moves to added. The breaking entry lists the flag and library changes, and a new fixed entry covers Go output with no Workflow API.
The flag is gone, so READMEs, specs and comments now name the Workflow API.
A reader could copy the sample, but its fields do not match the meaning of the borrowed messages.
The sources line still said that resources need a target. The `kw_only`
flips had no entry yet.
The stream sample is the one System Nexus service with a client, and no sample
built or type-checked it. Only Python has the client target, so Python builds
both APIs in its own variant, and TypeScript and .NET keep the Workflow API.
The `orders` interface in `target-sources.wit` broke the .NET build of that
sample, which now runs in every language. Two services there declare two
`Operations` classes in one namespace.
Go, TypeScript and .NET replaced a resource field with the source of the same
request field, and Python kept the resource field. Each now sends the
resource's value and fills only the other sources.
@moetemp
moetemp force-pushed the moe/fix/api-generation-targets-review branch from 4875677 to 4660b19 Compare October 30, 2026 23:00
@@ -0,0 +1,34 @@
package temporal:cross-service-resource@1.0.0;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's ditch this.


[error]
kind = "python-generated-name-conflict"
contains = ["`get_job`", "resource `Job`", "service `Scheduler`"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Fix all these to be single strings.

@tconley1428
tconley1428 marked this pull request as ready for review October 30, 2026 23:28
@tconley1428
tconley1428 merged commit 7dea731 into refactor/api-generation-targets Oct 30, 2026
3 checks passed
@tconley1428
tconley1428 deleted the moe/fix/api-generation-targets-review branch October 30, 2026 23:28
tconley1428 pushed a commit that referenced this pull request Nov 2, 2026
…346)

* Scoped the Workflow-only sample defaults to the Workflow target.

A default without a target list applies to every target, and these helpers need a Workflow context.

* Used `GenerationTarget` in Python and ran each target check once.

`PythonTarget` copied `GenerationTarget`, and two checks ran twice per run. A
private client method named `_create_nexus_client` replaced the extension hook.

* Rendered each resource method request argument on its own line.

One long line has no trailing comma, so `ruff format` joined the requests in the
samples, and unformatted output got lines of about 200 characters.

* Accepted an empty sourced string again in Python proto decode.

Without a source default in the shared model, decode refused an empty sourced
value. A handler then rejected requests that it accepted before.

* Rendered fields-only resources when the Workflow target is off.

The root classes had stub methods that always raised, and the client package
kept private copies of them. The client now decodes results into the root
classes.

* Generated definitions for resources and sources with no API target.

A handler that implements a service generates definitions only, from the WIT
that its callers share. That WIT can have resources and sources, and the
default build has no `--targets`, so it couldn't generate such WIT at all.

* Gave a returned client handle the Nexus client of its own service.

When another interface returned a resource, the handle kept the client of the
returning service, so its methods started operations on the wrong endpoint.

* Matched the client Nexus protocol to `temporalio.client.NexusClient`.

`Client.create_nexus_client` didn't fit the generated hook, so a real client
failed to type-check and to run. The SDK needs an operation ID, so each call
passes a new random one.

* Added a public factory for each resource on the client extensions.

To rebuild a client handle from stored identity fields, a caller needed the
private `_create_nexus_client` hook and the wire names of the service.

* Rejected unknown settings in examples.toml by name.

A misspelled key was read as a child configuration and the parent then stopped generating. The error now names the key and its section.

* Rejected examples.toml sections that match no input.

A misspelled section name gave definitions-only output with no error, or an error that did not point at examples.toml.

* Rejected child names that share a directory or cannot name a package.

Children whose names map to one directory in any language would merge their files. Names with a leading digit or a Python keyword are not importable packages.

* Built the target-sources sample in TypeScript, Go and .NET.

The target-sources sample now builds for the workflow target in all three languages. Go filled sourced fields only on proto-backed inputs, so operations without a proto input now fill them too.

* Pruned Go imports that the rendered code does not use.

Go output with no Workflow API kept the imports of that API and did not compile. The renderer pruned only aliased imports, and now prunes plain ones too.

* Updated the changelog for the targets change.

The client constructor line describes a new feature, so it moves to added. The breaking entry lists the flag and library changes, and a new fixed entry covers Go output with no Workflow API.

* Renamed the leftover native-api wording to Workflow API.

The flag is gone, so READMEs, specs and comments now name the Workflow API.

* Explained why target-sources borrows Temporal protos.

A reader could copy the sample, but its fields do not match the meaning of the borrowed messages.

* Updated the core-fix changelog and reworded a native API comment.

The sources line still said that resources need a target. The `kw_only`
flips had no entry yet.

* Generated and tested the Python client of the stream sample.

The stream sample is the one System Nexus service with a client, and no sample
built or type-checked it. Only Python has the client target, so Python builds
both APIs in its own variant, and TypeScript and .NET keep the Workflow API.

* Moved the cross-interface resource sample to its own WIT.

The `orders` interface in `target-sources.wit` broke the .NET build of that
sample, which now runs in every language. Two services there declare two
`Operations` classes in one namespace.

* Used a resource field before its source in every language.

Go, TypeScript and .NET replaced a resource field with the source of the same
request field, and Python kept the resource field. Each now sends the
resource's value and fills only the other sources.
tconley1428 added a commit that referenced this pull request Nov 3, 2026
* feat(python): add a client target

`--targets workflow,client` also writes a `client` package, with its own resource classes and a
client extension for each service. Its methods start each operation through `_create_nexus_client`
and return the result. The models are shared, and the Workflow package doesn't change. The
operation renderers take a target and start each line at its indent, so both targets share them.
The stream sample gets the client target.

* Refactor generation around independently selected API targets

* Checkpoint target validation and reviewed documentation

* Bind client resources explicitly and add inherited sample configurations

* Unify field origins across language selection and API planning

* Keep sample configuration docs in the advanced guide

* fix: address the review of API targets and the Python client target (#346)

* Scoped the Workflow-only sample defaults to the Workflow target.

A default without a target list applies to every target, and these helpers need a Workflow context.

* Used `GenerationTarget` in Python and ran each target check once.

`PythonTarget` copied `GenerationTarget`, and two checks ran twice per run. A
private client method named `_create_nexus_client` replaced the extension hook.

* Rendered each resource method request argument on its own line.

One long line has no trailing comma, so `ruff format` joined the requests in the
samples, and unformatted output got lines of about 200 characters.

* Accepted an empty sourced string again in Python proto decode.

Without a source default in the shared model, decode refused an empty sourced
value. A handler then rejected requests that it accepted before.

* Rendered fields-only resources when the Workflow target is off.

The root classes had stub methods that always raised, and the client package
kept private copies of them. The client now decodes results into the root
classes.

* Generated definitions for resources and sources with no API target.

A handler that implements a service generates definitions only, from the WIT
that its callers share. That WIT can have resources and sources, and the
default build has no `--targets`, so it couldn't generate such WIT at all.

* Gave a returned client handle the Nexus client of its own service.

When another interface returned a resource, the handle kept the client of the
returning service, so its methods started operations on the wrong endpoint.

* Matched the client Nexus protocol to `temporalio.client.NexusClient`.

`Client.create_nexus_client` didn't fit the generated hook, so a real client
failed to type-check and to run. The SDK needs an operation ID, so each call
passes a new random one.

* Added a public factory for each resource on the client extensions.

To rebuild a client handle from stored identity fields, a caller needed the
private `_create_nexus_client` hook and the wire names of the service.

* Rejected unknown settings in examples.toml by name.

A misspelled key was read as a child configuration and the parent then stopped generating. The error now names the key and its section.

* Rejected examples.toml sections that match no input.

A misspelled section name gave definitions-only output with no error, or an error that did not point at examples.toml.

* Rejected child names that share a directory or cannot name a package.

Children whose names map to one directory in any language would merge their files. Names with a leading digit or a Python keyword are not importable packages.

* Built the target-sources sample in TypeScript, Go and .NET.

The target-sources sample now builds for the workflow target in all three languages. Go filled sourced fields only on proto-backed inputs, so operations without a proto input now fill them too.

* Pruned Go imports that the rendered code does not use.

Go output with no Workflow API kept the imports of that API and did not compile. The renderer pruned only aliased imports, and now prunes plain ones too.

* Updated the changelog for the targets change.

The client constructor line describes a new feature, so it moves to added. The breaking entry lists the flag and library changes, and a new fixed entry covers Go output with no Workflow API.

* Renamed the leftover native-api wording to Workflow API.

The flag is gone, so READMEs, specs and comments now name the Workflow API.

* Explained why target-sources borrows Temporal protos.

A reader could copy the sample, but its fields do not match the meaning of the borrowed messages.

* Updated the core-fix changelog and reworded a native API comment.

The sources line still said that resources need a target. The `kw_only`
flips had no entry yet.

* Generated and tested the Python client of the stream sample.

The stream sample is the one System Nexus service with a client, and no sample
built or type-checked it. Only Python has the client target, so Python builds
both APIs in its own variant, and TypeScript and .NET keep the Workflow API.

* Moved the cross-interface resource sample to its own WIT.

The `orders` interface in `target-sources.wit` broke the .NET build of that
sample, which now runs in every language. Two services there declare two
`Operations` classes in one namespace.

* Used a resource field before its source in every language.

Go, TypeScript and .NET replaced a resource field with the source of the same
request field, and Python kept the resource field. Each now sends the
resource's value and fills only the other sources.

* Separate shared models from Python API packages

* Adapt upstream Stream tests to target sample layout

* Allow target-specific repeated source and default directives

* Use shared generation target lists and trim redundant tests

* Refine Python client APIs and share service contracts

* Use the SDK System Nexus endpoint constant

---------

Co-authored-by: Moe Dashti <mohammad.dashti@temporal.io>
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.

2 participants