Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,7 @@ To build the SDK from source for use as a dependency, the following prerequisite
* [uv](https://docs.astral.sh/uv/)
* [Rust](https://www.rust-lang.org/)
* [Protobuf Compiler](https://protobuf.dev/)
* [Node.js](https://nodejs.org/)

Use `uv` to install `poe`:

Expand Down Expand Up @@ -2074,6 +2075,12 @@ back from this downgrade, restore both of those files and run `uv sync --all-ext
run for protobuf version 3 by setting the `TEMPORAL_TEST_PROTO3` env var to `1` prior to running
tests.

The local build and lint flows also regenerate Temporal system Nexus models. By default this pulls
in `nexus-rpc-gen@0.1.0-alpha.4` via `npx`. To use an existing checkout instead, set
`TEMPORAL_NEXUS_RPC_GEN_DIR` to the `nexus-rpc-gen` repo root or its `src` directory before
running `poe build-develop`, `poe lint`, or `poe gen-protos`. The local checkout override path
also requires [`pnpm`](https://pnpm.io/) to be installed.

### Style

* Mostly [Google Style Guide](https://google.github.io/styleguide/pyguide.html). Notable exceptions:
Expand Down
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,14 @@ gen-protos = [
{ cmd = "uv run scripts/gen_protos.py" },
{ cmd = "uv run scripts/gen_payload_visitor.py" },
{ cmd = "uv run scripts/gen_bridge_client.py" },
{ ref = "gen-nexus-system-models" },
{ ref = "format" },
]
gen-protos-docker = [
{ cmd = "uv run scripts/gen_protos_docker.py" },
{ cmd = "uv run scripts/gen_payload_visitor.py" },
{ cmd = "uv run scripts/gen_bridge_client.py" },
{ ref = "gen-nexus-system-models" },
{ ref = "format" },
]
lint = [
Expand All @@ -102,6 +104,7 @@ lint-types = [
{ cmd = "uv run mypy --namespace-packages --check-untyped-defs ." },
{ cmd = "uv run basedpyright" },
]
gen-nexus-system-models = "uv run scripts/gen_nexus_system_models.py"
run-bench = "uv run python scripts/run_bench.py"
test = "uv run pytest"

Expand Down Expand Up @@ -139,14 +142,17 @@ environment = { PATH = "$PATH:$HOME/.cargo/bin", CARGO_NET_GIT_FETCH_WITH_CLI =
ignore_missing_imports = true
exclude = [
# Ignore generated code
'build',
'temporalio/api',
'temporalio/bridge/proto',
'temporalio/nexus/system/_workflow_service_generated.py',
]

[tool.pydocstyle]
convention = "google"
# https://github.com/PyCQA/pydocstyle/issues/363#issuecomment-625563088
match_dir = "^(?!(docs|scripts|tests|api|proto|\\.)).*"
match_dir = "^(?!(build|docs|scripts|tests|api|proto|\\.)).*"
match = "^(?!_workflow_service_generated\\.py$).*\\.py"
add_ignore = [
# We like to wrap at a certain number of chars, even long summary sentences.
# https://github.com/PyCQA/pydocstyle/issues/184
Expand Down
124 changes: 124 additions & 0 deletions scripts/gen_nexus_system_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path

NEXUS_RPC_GEN_ENV_VAR = "TEMPORAL_NEXUS_RPC_GEN_DIR"
NEXUS_RPC_GEN_VERSION = "0.1.0-alpha.4"


def main() -> None:
repo_root = Path(__file__).resolve().parent.parent
# TODO: Remove the local .nexusrpc.yaml shim once the upstream API repo
# checks in the Nexus definition we can consume directly.
override_root = normalize_nexus_rpc_gen_root(
Path.cwd(), env_value=NEXUS_RPC_GEN_ENV_VAR
)
input_schema = (
repo_root
/ "temporalio"
/ "bridge"
/ "sdk-core"
/ "crates"
/ "common"
/ "protos"
/ "api_upstream"
/ "nexus"
/ "temporal-proto-models-nexusrpc.yaml"
)
output_file = (
repo_root / "temporalio" / "nexus" / "system" / "_workflow_service_generated.py"
)

if not input_schema.is_file():
raise RuntimeError(f"Expected Nexus schema at {input_schema}")

run_nexus_rpc_gen(
override_root=override_root,
output_file=output_file,
input_schema=input_schema,
)
subprocess.run(
[
"uv",
"run",
"ruff",
"check",
"--select",
"I",
"--fix",
str(output_file),
],
cwd=repo_root,
check=True,
)
subprocess.run(
[
"uv",
"run",
"ruff",
"format",
str(output_file),
],
cwd=repo_root,
check=True,
)


def run_nexus_rpc_gen(
*, override_root: Path | None, output_file: Path, input_schema: Path
) -> None:
common_args = [
"--lang",
"py",
"--out-file",
str(output_file),
str(input_schema),
]
if override_root is None:
subprocess.run(
["npx", "--yes", f"nexus-rpc-gen@{NEXUS_RPC_GEN_VERSION}", *common_args],
check=True,
)
return

subprocess.run(
[
"node",
"packages/nexus-rpc-gen/dist/index.js",
*common_args,
],
cwd=override_root,
check=True,
)


def normalize_nexus_rpc_gen_root(base_dir: Path, env_value: str) -> Path | None:
raw_root = env_get(env_value)
if raw_root is None:
return None
candidate = Path(raw_root)
if not candidate.is_absolute():
candidate = base_dir / candidate
candidate = candidate.resolve()
if (candidate / "package.json").is_file() and (candidate / "packages").is_dir():
return candidate
if (candidate / "src" / "package.json").is_file():
return candidate / "src"
raise RuntimeError(
f"{NEXUS_RPC_GEN_ENV_VAR} must point to the nexus-rpc-gen repo root or its src directory"
)


def env_get(name: str) -> str | None:
return os.environ.get(name)


if __name__ == "__main__":
try:
main()
except Exception as err:
print(f"Failed to generate Nexus system models: {err}", file=sys.stderr)
raise
Loading