simulo 0.19.0__tar.gz → 0.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. {simulo-0.19.0/src/simulo.egg-info → simulo-0.20.0}/PKG-INFO +4 -2
  2. {simulo-0.19.0 → simulo-0.20.0}/pyproject.toml +14 -2
  3. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/app.py +11 -32
  4. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/artifacts.py +17 -35
  5. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/cli.py +743 -23
  6. simulo-0.20.0/src/simulo/_client/export_api.py +205 -0
  7. simulo-0.20.0/src/simulo/_client/export_bundle.py +296 -0
  8. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/submit_api.py +47 -8
  9. {simulo-0.19.0 → simulo-0.20.0/src/simulo.egg-info}/PKG-INFO +4 -2
  10. {simulo-0.19.0 → simulo-0.20.0}/src/simulo.egg-info/SOURCES.txt +2 -0
  11. {simulo-0.19.0 → simulo-0.20.0}/src/simulo.egg-info/requires.txt +3 -1
  12. {simulo-0.19.0 → simulo-0.20.0}/MANIFEST.in +0 -0
  13. {simulo-0.19.0 → simulo-0.20.0}/PYPI.md +0 -0
  14. {simulo-0.19.0 → simulo-0.20.0}/setup.cfg +0 -0
  15. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/__init__.py +0 -0
  16. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/__init__.py +0 -0
  17. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/_entrypoint.py +0 -0
  18. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/_mounts.py +0 -0
  19. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/_runner.py +0 -0
  20. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/asset.py +0 -0
  21. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/asset_api.py +0 -0
  22. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/asset_package.py +0 -0
  23. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/asset_pins.py +0 -0
  24. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/builtin_aliases.py +0 -0
  25. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/bundle.py +0 -0
  26. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/cancel_api.py +0 -0
  27. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/config.py +0 -0
  28. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/credentials.py +0 -0
  29. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/discovery.py +0 -0
  30. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/facades.py +0 -0
  31. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/http.py +0 -0
  32. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/jobs_api.py +0 -0
  33. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/learning.py +0 -0
  34. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/login.py +0 -0
  35. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/mode.py +0 -0
  36. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/packaging.py +0 -0
  37. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/preflight_api.py +0 -0
  38. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/preflight_render.py +0 -0
  39. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/registry.py +0 -0
  40. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/runtime.py +0 -0
  41. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/runtime_display.py +0 -0
  42. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/seed_ref.py +0 -0
  43. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/stub.py +0 -0
  44. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/templates/__init__.py +0 -0
  45. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/templates/inference/app.py.tmpl +0 -0
  46. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/templates/inference/simuloignore.tmpl +0 -0
  47. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/templates/scenario/app.py.tmpl +0 -0
  48. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/templates/scenario/simuloignore.tmpl +0 -0
  49. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/templates/training/app.py.tmpl +0 -0
  50. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/templates/training/simuloignore.tmpl +0 -0
  51. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/view_session_api.py +0 -0
  52. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/_client/volume.py +0 -0
  53. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/callbacks.py +0 -0
  54. {simulo-0.19.0 → simulo-0.20.0}/src/simulo/py.typed +0 -0
  55. {simulo-0.19.0 → simulo-0.20.0}/src/simulo.egg-info/dependency_links.txt +0 -0
  56. {simulo-0.19.0 → simulo-0.20.0}/src/simulo.egg-info/entry_points.txt +0 -0
  57. {simulo-0.19.0 → simulo-0.20.0}/src/simulo.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulo
3
- Version: 0.19.0
3
+ Version: 0.20.0
4
4
  Summary: Simulo SDK and CLI — define robotics simulation and training apps in Python and run them on the Simulo cloud.
5
5
  Author-email: Simulo Team <team@simulo.ai>
6
6
  License: BSD-3-Clause
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Typing :: Typed
16
16
  Requires-Python: >=3.11
17
17
  Description-Content-Type: text/markdown
18
- Requires-Dist: simulo-interfaces<0.14,>=0.13.0
18
+ Requires-Dist: simulo-interfaces<0.15,>=0.14.0
19
19
  Requires-Dist: mcap<2,>=1.3
20
20
  Requires-Dist: defusedxml>=0.7.1
21
21
  Requires-Dist: usd-core<27,>=25.5
@@ -30,6 +30,8 @@ Requires-Dist: types-defusedxml==0.7.0.20260504; extra == "dev"
30
30
  Requires-Dist: pytest>=8.2; extra == "dev"
31
31
  Requires-Dist: build>=1.2; extra == "dev"
32
32
  Requires-Dist: twine>=5.1; extra == "dev"
33
+ Requires-Dist: setuptools>=68; extra == "dev"
34
+ Requires-Dist: wheel; extra == "dev"
33
35
  Provides-Extra: release
34
36
  Requires-Dist: commitizen>=3.27; extra == "release"
35
37
  Requires-Dist: build>=1.2; extra == "release"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simulo"
7
- version = "0.19.0"
7
+ version = "0.20.0"
8
8
  description = "Simulo SDK and CLI — define robotics simulation and training apps in Python and run them on the Simulo cloud."
9
9
  readme = "PYPI.md"
10
10
  requires-python = ">=3.11"
@@ -26,7 +26,7 @@ classifiers = [
26
26
  # mcap: used by `simulo recordings` to read back a downloaded recording and
27
27
  # verify it (message count) — MIT-licensed, deps only lz4+zstandard.
28
28
  dependencies = [
29
- "simulo-interfaces>=0.13.0,<0.14",
29
+ "simulo-interfaces>=0.14.0,<0.15",
30
30
  "mcap>=1.3,<2",
31
31
  # Hardened XML parsing for URDF ingestion (USD Asset Catalogs, PR-12 fix
32
32
  # loop 2, security NIT): stdlib xml.etree.ElementTree relies on
@@ -77,6 +77,18 @@ dev = [
77
77
  "pytest>=8.2",
78
78
  "build>=1.2",
79
79
  "twine>=5.1",
80
+ # setuptools/wheel: `tests/test_create_wheel_packaging.py` builds a real wheel with
81
+ # `python -m build --wheel --no-isolation`, which reuses THIS interpreter's
82
+ # already-installed setuptools/wheel instead of resolving `[build-system].requires`
83
+ # into a fresh, network-fetched isolated build venv. Constraints mirror
84
+ # `[build-system].requires` above EXACTLY so the two can never drift apart.
85
+ # Without this, `pip install -e ".[dev]"` in a fresh Python 3.12 venv (which no
86
+ # longer bundles setuptools, unlike 3.11 and earlier) leaves that test failing with
87
+ # `Cannot import 'setuptools.build_meta'` — measured 2026-08-12. It passed in CI
88
+ # only because `.github/workflows/simulo-ci.yml` installs `pip setuptools wheel` as
89
+ # its own step, independently of this extra, which masked the gap.
90
+ "setuptools>=68",
91
+ "wheel",
80
92
  ]
81
93
  # `dev` carries build/twine but deliberately not commitizen; `release` below
82
94
  # adds commitizen for cutting version bumps without a second build/twine copy.
@@ -1025,35 +1025,14 @@ class App:
1025
1025
 
1026
1026
  Raises:
1027
1027
  ValueError: ``timeout`` is not ``None`` and is not a positive
1028
- integer (mirrors the worker's own
1029
- ``worker._effective_job_timeout_s`` guard — bare ``bool`` is
1030
- excluded even though it is an ``int`` subclass).
1028
+ integer. ``True`` and ``False`` are not accepted as timeouts.
1031
1029
  TypeError: ``produces=`` or ``consumes=`` was passed. Outputs are
1032
- never declared on the decorator: callbacks
1033
- already imply their outputs, and a job body registers any
1034
- other produced file at execution time with
1035
- ``simulo.save_artifact(name, path)``. ``consumes=`` is
1036
- reserved for a future input declaration (chain jobs with
1037
- ``simulo run --from <job>[:latest|:best]`` today).
1038
-
1039
- Note this guard is a deliberate BEHAVIOUR CHANGE, not the
1040
- formalisation of something that already failed. Neither kwarg
1041
- was ever *supported*, but until PR-B8 both were silently
1042
- *accepted*: ``**extra`` folded them straight into the job's
1043
- resource spec, so ``@app.job(produces=["report.html"])``
1044
- produced ``resources == {"produces": ["report.html"]}`` in
1045
- every published client — a misconfiguration the user could
1046
- not see, which is exactly why it is now rejected.
1047
-
1048
- It is safe because the affected population is empty **by
1049
- evidence, not by construction**: no use of either kwarg exists
1050
- in this repo, its history, the demos, or the docs site. The
1051
- residual regression path is the worker, and it is worth naming
1052
- — an ALREADY-ARCHIVED package whose source contains
1053
- ``produces=`` now raises this ``TypeError`` at module import
1054
- on an upgraded runner, before discovery or execution reaches
1055
- anything else. Weigh that path first if the evidence above
1056
- ever stops holding.
1030
+ not declared on the decorator. Callbacks such as
1031
+ ``ResumableCheckpoint`` already declare their supported
1032
+ outputs. Return small JSON values from the job, or use a named
1033
+ volume for files another job needs. ``consumes=`` is reserved;
1034
+ continue from a checkpoint with
1035
+ ``simulo run --from <job>[:latest|:best]`` instead.
1057
1036
  """
1058
1037
  if timeout is not None and (isinstance(timeout, bool) or not isinstance(timeout, int) or timeout < 1):
1059
1038
  raise ValueError(
@@ -1062,10 +1041,10 @@ class App:
1062
1041
  )
1063
1042
  if "produces" in extra:
1064
1043
  raise TypeError(
1065
- "@app.job(produces=...) is not supported — job outputs are never declared on the "
1066
- "decorator. Callbacks such as simulo.callbacks.ResumableCheckpoint or DebugOnAnomaly "
1067
- "already declare the outputs they produce, and a job body registers any other produced "
1068
- "file at execution time with simulo.save_artifact(name, path). Remove produces=."
1044
+ "@app.job(produces=...) is not supported. Callbacks such as "
1045
+ "ResumableCheckpoint and DebugOnAnomaly already declare their supported outputs. "
1046
+ "Return small JSON values from the job, or use a named Volume for files another "
1047
+ "job needs. Remove produces=."
1069
1048
  )
1070
1049
  if "consumes" in extra:
1071
1050
  raise TypeError(
@@ -38,30 +38,24 @@ def save_artifact(
38
38
  path: Union[str, bytes, "os.PathLike[str]", "os.PathLike[bytes]"],
39
39
  kind: Union[ArtifactKind, str] = ArtifactKind.FILE,
40
40
  ) -> bool:
41
- """Register a file this job produced so the platform keeps it as an artifact.
41
+ """Register metadata for a file produced while this job is running.
42
42
 
43
- Call it from a job body, after writing the file::
44
-
45
- report = "/reports/summary.html"
46
- write_report(report)
47
- simulo.save_artifact("summary.html", report, kind="report")
48
-
49
- The worker uploads every registered file once the job completes, and it
50
- appears under the job's artifacts (``simulo artifacts <job>``) with the
51
- ``name`` given here as its filename.
43
+ This validates the name, path, and kind, then records them in the running
44
+ job. The current managed platform does not upload general files registered
45
+ this way, so registration alone does not make the file available through
46
+ ``simulo artifacts`` after the job finishes. Return small JSON values from
47
+ the job, use a named :class:`simulo.Volume` for files another job needs, or
48
+ use the supported model and recording workflows for downloadable output.
52
49
 
53
50
  Args:
54
- name: The artifact's logical filename — what the platform stores,
55
- lists, and saves downloads under. A single safe filename, never a
56
- path: separators, control characters, dots-only tokens, empty and
57
- over-length names are rejected immediately with ``ValueError``
58
- (:func:`~simulo.interfaces.platform.artifacts._validate_artifact_name`).
51
+ name: The registration's logical filename. It must be one safe
52
+ filename, never a path: separators, control characters, dots-only
53
+ tokens, empty values, and over-length names are rejected with
54
+ ``ValueError``.
59
55
  path: Filesystem path of the produced file. ``str``, ``bytes``, or any
60
56
  ``os.PathLike`` (a ``pathlib.Path`` works); bytes-ish values are
61
57
  ``os.fsdecode``-d, so a real non-UTF-8 filename registers fine.
62
- Validated for usability (type, length, non-empty, no NUL) — *where*
63
- it points is contained by the worker's uploader, which skips any
64
- path outside the job's own artifact roots.
58
+ Validated for usability: type, length, non-empty, and no NUL.
65
59
  kind: What the output is — an
66
60
  :class:`~simulo.interfaces.platform.enums.ArtifactKind` or its wire
67
61
  string (e.g. ``"report"``, ``"dataset"``). Defaults to
@@ -70,27 +64,15 @@ def save_artifact(
70
64
 
71
65
  Returns:
72
66
  ``True`` when the registration was kept; ``False`` when it was dropped
73
- because the run already registered ``simulo.outputs``'s
74
- ``MAX_REGISTERED_OUTPUTS`` (1000) artifacts — a loop registering every
75
- step's scratch file is a mistake, and the registry warns once on stderr
76
- rather than failing the run over bookkeeping.
67
+ because the run already registered 1000 files. Register final output,
68
+ not a new scratch file on every simulation step.
77
69
 
78
70
  Raises:
79
71
  ValueError: ``name`` is not a safe single filename, ``path`` is not
80
72
  usable as a path, or ``kind`` is not a known artifact kind — all
81
- surfaced at the call site, on the worker, before anything is
82
- registered. **Every** argument problem arrives as ``ValueError``,
83
- including the ones ``os.fsdecode`` would otherwise raise as
84
- something else (see below) — one ``except ValueError`` around an
85
- optional registration is a complete guard.
86
- ModuleNotFoundError: ``simulo.outputs`` is installed but something IT
87
- imports is missing (a broken backend install). Propagated as-is
88
- rather than relabelled, because the missing module is not
89
- ``simulo.outputs``.
90
- RuntimeError: called where the ``simulo.outputs`` registry is not
91
- installed (a submit-only environment forced into execution mode) —
92
- never a supported state; at submit this function is not even
93
- reachable, the name resolves to a Stub.
73
+ surfaced at the call site before anything is registered.
74
+ ModuleNotFoundError: The job runtime is missing a required dependency.
75
+ RuntimeError: Called outside a supported job execution context.
94
76
  """
95
77
  if isinstance(path, (bytes, os.PathLike)):
96
78
  # ``os.fsdecode`` maps a bytes / PathLike path to the exact ``str`` the