simulo 0.13.0__tar.gz → 0.13.2__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 (52) hide show
  1. {simulo-0.13.0/src/simulo.egg-info → simulo-0.13.2}/PKG-INFO +2 -1
  2. {simulo-0.13.0 → simulo-0.13.2}/pyproject.toml +16 -13
  3. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/asset.py +10 -10
  4. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/cancel_api.py +1 -1
  5. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/cli.py +69 -7
  6. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/view_session_api.py +1 -1
  7. {simulo-0.13.0 → simulo-0.13.2/src/simulo.egg-info}/PKG-INFO +2 -1
  8. {simulo-0.13.0 → simulo-0.13.2}/src/simulo.egg-info/requires.txt +1 -0
  9. {simulo-0.13.0 → simulo-0.13.2}/MANIFEST.in +0 -0
  10. {simulo-0.13.0 → simulo-0.13.2}/PYPI.md +0 -0
  11. {simulo-0.13.0 → simulo-0.13.2}/setup.cfg +0 -0
  12. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/__init__.py +0 -0
  13. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/__init__.py +0 -0
  14. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/_entrypoint.py +0 -0
  15. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/_mounts.py +0 -0
  16. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/_runner.py +0 -0
  17. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/app.py +0 -0
  18. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/asset_api.py +0 -0
  19. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/asset_package.py +0 -0
  20. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/asset_pins.py +0 -0
  21. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/builtin_aliases.py +0 -0
  22. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/bundle.py +0 -0
  23. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/config.py +0 -0
  24. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/credentials.py +0 -0
  25. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/discovery.py +0 -0
  26. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/http.py +0 -0
  27. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/jobs_api.py +0 -0
  28. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/learning.py +0 -0
  29. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/login.py +0 -0
  30. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/manifest.py +0 -0
  31. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/mode.py +0 -0
  32. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/packaging.py +0 -0
  33. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/registry.py +0 -0
  34. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/runtime.py +0 -0
  35. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/runtime_display.py +0 -0
  36. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/seed_ref.py +0 -0
  37. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/stub.py +0 -0
  38. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/submit_api.py +0 -0
  39. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/templates/__init__.py +0 -0
  40. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/templates/inference/app.py.tmpl +0 -0
  41. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/templates/inference/simuloignore.tmpl +0 -0
  42. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/templates/scenario/app.py.tmpl +0 -0
  43. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/templates/scenario/simuloignore.tmpl +0 -0
  44. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/templates/training/app.py.tmpl +0 -0
  45. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/templates/training/simuloignore.tmpl +0 -0
  46. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/_client/volume.py +0 -0
  47. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/callbacks.py +0 -0
  48. {simulo-0.13.0 → simulo-0.13.2}/src/simulo/py.typed +0 -0
  49. {simulo-0.13.0 → simulo-0.13.2}/src/simulo.egg-info/SOURCES.txt +0 -0
  50. {simulo-0.13.0 → simulo-0.13.2}/src/simulo.egg-info/dependency_links.txt +0 -0
  51. {simulo-0.13.0 → simulo-0.13.2}/src/simulo.egg-info/entry_points.txt +0 -0
  52. {simulo-0.13.0 → simulo-0.13.2}/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.13.0
3
+ Version: 0.13.2
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
@@ -18,6 +18,7 @@ Description-Content-Type: text/markdown
18
18
  Requires-Dist: simulo-interfaces<0.6,>=0.5
19
19
  Requires-Dist: mcap<2,>=1.3
20
20
  Requires-Dist: defusedxml>=0.7.1
21
+ Requires-Dist: usd-core<27,>=25.5
21
22
  Provides-Extra: assets
22
23
  Requires-Dist: usd-core<27,>=25.5; extra == "assets"
23
24
  Provides-Extra: dev
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simulo"
7
- version = "0.13.0"
7
+ version = "0.13.2"
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"
@@ -34,22 +34,25 @@ dependencies = [
34
34
  # defaults to stay XXE/billion-laughs-safe; defusedxml pins that
35
35
  # protection explicitly. Pure Python, zero transitive dependencies,
36
36
  # ~25 KB — genuinely "cheap": adding it does not compromise the
37
- # featherweight/no-USD-extra promise below (that promise is about
38
- # avoiding usd-core's tens of MB, not about being literally
39
- # zero-dependency).
37
+ # featherweight promise below (that promise was about avoiding
38
+ # usd-core's tens of MB via an opt-in extra; usd-core itself joined the
39
+ # base footprint in 0.13.1 — see its own comment just below).
40
40
  "defusedxml>=0.7.1",
41
+ # usd-core: simulator-free but tens of MB — moved from the `assets`
42
+ # extra into the base install in 0.13.1 so `pip install simulo` covers
43
+ # USD-tree publishing/inspection out of the box (no separate extra to
44
+ # discover first). Still torch-free and still lazy-imported ONLY on the
45
+ # USD inspection path (`_client/asset_package.py::_load_pxr_usdutils`) —
46
+ # importing `simulo` itself never pays its cost.
47
+ "usd-core>=25.5,<27",
41
48
  ]
42
49
 
43
50
  [project.optional-dependencies]
44
- # `assets` — the FIRST user-facing extras group: USD package inspection for
45
- # `simulo asset publish`/`validate` of USD trees (dependency closure + entry
46
- # detection via pxr.UsdUtils). usd-core is simulator-free but tens of MB, so
47
- # it must never tax users who don't publish USD: the import is lazy, ONLY in
48
- # the USD inspection path (`_client/asset_package.py::_load_pxr_usdutils`),
49
- # and a missing extra fails with the copyable `pip install "simulo[assets]"`.
50
- # URDF publishing needs no OPT-IN extra (defusedxml + path math, both tiny
51
- # always-installed base dependencies above — see that dependency's own
52
- # comment).
51
+ # `assets` — kept for backward compatibility with `pip install
52
+ # "simulo[assets]"` (the 0.13.0-era spelling): usd-core moved into the base
53
+ # install above in 0.13.1, so this extra is now redundant (its dep is
54
+ # already installed unconditionally) but harmless — resolvers don't warn on
55
+ # an extra whose contents are already satisfied by the base requirement.
53
56
  assets = ["usd-core>=25.5,<27"]
54
57
  dev = ["black>=24.0", "isort>=5.13", "ruff>=0.5", "mypy>=1.10", "pytest>=8.2", "build>=1.2", "twine>=5.1"]
55
58
  # `dev` carries build/twine but deliberately not commitizen; `release` below
@@ -2,12 +2,12 @@
2
2
 
3
3
  A registry asset ref is ``[<publisher>/]<kind>/<name>[:v<N>]`` (e.g.
4
4
  ``robot/so-arm-100:v3``, ``simulo/world/warehouse:v2``, or the unpinned
5
- ``robot/forklift`` — resolved to an exact version **at submit**, §6). The grammar
5
+ ``robot/forklift`` — resolved to an exact version **at submit**). The grammar
6
6
  is the ONE shared parser from ``simulo.interfaces.platform.asset_catalog`` — the
7
7
  CLI, the control plane, the worker, and the console all parse through it, so the
8
8
  grammar can never drift. This handle carries the parsed ``kind`` (``robot`` /
9
- ``world``), which enables **kind safety** (``Robot(asset=<world asset>)`` fails
10
- with a one-line explanation — see :meth:`require_kind`).
9
+ ``world`` / ``prop``), which enables **kind safety** (``Robot(asset=<world asset>)`` fails
10
+ with a one-line explanation naming the mismatched kind).
11
11
 
12
12
  The on-disk :attr:`path` only exists in **execution mode**:
13
13
 
@@ -131,7 +131,7 @@ class Asset:
131
131
  """A read-only, registry-resolved resource mounted into running jobs.
132
132
 
133
133
  A registry ref is ``[<publisher>/]<kind>/<name>[:v<N>]`` (e.g.
134
- ``robot/so-arm-100:v3``); :meth:`from_registry` names one, and :attr:`path`
134
+ ``simulo/robot/cartpole:v1``); :meth:`from_registry` names one, and :attr:`path`
135
135
  resolves to its read-only mount inside a running job. ``Asset`` is also how a
136
136
  task names USD/URDF model sources to load into a scene — :meth:`usd` /
137
137
  :meth:`urdf`.
@@ -154,8 +154,8 @@ class Asset:
154
154
 
155
155
  ``uri`` is a catalog ref ``[<publisher>/]<kind>/<name>[:v<N>]`` — the
156
156
  publisher defaults to your own org, ``simulo`` names the global catalog,
157
- and an omitted ``:v<N>`` is resolved to the current latest **at submit**
158
- (§6). The handle is directly consumable wherever a model source is
157
+ and an omitted ``:v<N>`` is resolved to the current latest **at submit**.
158
+ The handle is directly consumable wherever a model source is
159
159
  accepted — ``Robot(asset=...)`` for a ``robot`` ref, ``scene.add(...)``
160
160
  for a ``world`` ref.
161
161
  """
@@ -166,7 +166,7 @@ class Asset:
166
166
  """Name a USD model source to load into a scene.
167
167
 
168
168
  At submit time this returns an inert, torch-free spec object so authoring
169
- stays lean; on the worker it resolves to the real model asset. The return
169
+ stays lean; in the execution runtime it resolves to the real model asset. The return
170
170
  type depends on mode, so it is typed ``Any``.
171
171
  """
172
172
  return cls._model_asset("usd", path)
@@ -194,7 +194,7 @@ class Asset:
194
194
 
195
195
  @property
196
196
  def kind(self) -> str:
197
- """The ``<kind>`` segment of the ref — ``"robot"`` or ``"world"``."""
197
+ """The ``<kind>`` segment of the ref — ``"robot"``, ``"world"``, or ``"prop"``."""
198
198
  return self._ref.kind
199
199
 
200
200
  @property
@@ -252,8 +252,8 @@ class Asset:
252
252
 
253
253
  Resolution order, in execution mode:
254
254
 
255
- 1. ``SIMULO_ASSET_<uri>`` — the mount the runner (cloud worker or local
256
- ``run-package``) exported for this asset. When set, it is authoritative.
255
+ 1. ``SIMULO_ASSET_<uri>`` — the mount the execution environment
256
+ exported for this asset. When set, it is authoritative.
257
257
  2. The on-disk catalog cache ``~/.simulo/assets/<org>/<kind>/<name>/v<N>/``
258
258
  — the colon-free layout ``simulo asset get`` writes into. Used for a
259
259
  local run with no runner-provided mount.
@@ -1,7 +1,7 @@
1
1
  """HTTP client for the job cancel endpoint (stdlib only, torch-free).
2
2
 
3
3
  Wire contract (job-cancel-and-demo-apps plan — see
4
- ``context/implementation-plans/job-cancel-and-demo-apps-plan.md``; the control
4
+ ``context/implementation-plans/archive/job-cancel-and-demo-apps-plan.md``; the control
5
5
  plane's half of this route is built by a parallel PR, so this client codes
6
6
  directly against the plan's PINNED contract rather than waiting on it):
7
7
  ``POST /v1/jobs/{job_id}/cancel`` (Cognito bearer, org-scoped).
@@ -80,6 +80,7 @@ from __future__ import annotations
80
80
 
81
81
  import argparse
82
82
  import hashlib
83
+ import importlib.metadata
83
84
  import importlib.resources
84
85
  import json
85
86
  import math
@@ -325,6 +326,9 @@ def _submit_app(
325
326
  fallback) so every construction anywhere in the discovery-time control flow is
326
327
  captured, mounted or not.
327
328
  """
329
+ if not app_file.is_file():
330
+ raise SystemExit(f"No such app file: {app_file}")
331
+
328
332
  previous_mode = os.environ.get("SIMULO_MODE")
329
333
  os.environ["SIMULO_MODE"] = DISCOVERY
330
334
  try:
@@ -458,7 +462,19 @@ def _follow_and_report(handle: JobHandle) -> int:
458
462
  assert handle.base_url is not None, "a cloud JobHandle always carries a base_url"
459
463
  client = JobsApiClient(handle.base_url, token=handle.token)
460
464
  print(f"Following job {handle.job_id} (--detach to submit without waiting)...", file=sys.stderr, flush=True)
461
- return _drain_logs(client, str(handle.job_id), follow=True)
465
+ try:
466
+ return _drain_logs(client, str(handle.job_id), follow=True)
467
+ except KeyboardInterrupt:
468
+ # The submit already succeeded — only the client-side follow loop
469
+ # died. Say so explicitly: without this, a user watching a raw
470
+ # traceback (or even a bare "^C") could easily read Ctrl-C as having
471
+ # killed the job itself, when it is still running server-side.
472
+ print(
473
+ f"\nInterrupted — the job is still running in the cloud. Reattach with:"
474
+ f" simulo logs {handle.job_id} --follow",
475
+ file=sys.stderr,
476
+ )
477
+ return 130
462
478
 
463
479
 
464
480
  def _cmd_run(args: argparse.Namespace, extras: Sequence[str]) -> int:
@@ -3079,8 +3095,18 @@ def _asset_publish_impl(args: argparse.Namespace) -> int:
3079
3095
  revived = bool(initiate.get("revived"))
3080
3096
 
3081
3097
  if upload is not None:
3082
- target = "the global catalog" if admin else _asset_publisher_label(client, args.kind, name)
3083
- echo(f"Uploading to {target}…")
3098
+ if admin:
3099
+ echo("Uploading to the global catalog…")
3100
+ else:
3101
+ publisher = _asset_publisher_label(client, args.kind, name)
3102
+ # `_asset_publisher_label` already falls back to "your
3103
+ # organization" when the org handle can't be resolved
3104
+ # (display-only, never fails a publish) — don't wrap that
3105
+ # into "your organization's catalog (your organization)".
3106
+ if publisher == "your organization":
3107
+ echo("Uploading to your organization's catalog…")
3108
+ else:
3109
+ echo(f"Uploading to your organization's catalog ({publisher})…")
3084
3110
  complete, resumed_parts = upload_archive(
3085
3111
  client,
3086
3112
  version_id=version_id,
@@ -4312,6 +4338,21 @@ def _nonnegative_int(value: str) -> int:
4312
4338
  return parsed
4313
4339
 
4314
4340
 
4341
+ def _resolve_version() -> str:
4342
+ """Resolve the installed ``simulo`` distribution version for ``--version``.
4343
+
4344
+ Reads the installed wheel's metadata (``importlib.metadata``) rather than a
4345
+ hardcoded string, so it can never drift from what ``pip show simulo``
4346
+ reports. Falls back to a plain placeholder if the distribution metadata is
4347
+ unavailable (e.g. running this module straight from a source checkout with
4348
+ no installed ``simulo`` distribution at all).
4349
+ """
4350
+ try:
4351
+ return importlib.metadata.version("simulo")
4352
+ except importlib.metadata.PackageNotFoundError:
4353
+ return "unknown"
4354
+
4355
+
4315
4356
  def _build_parser() -> argparse.ArgumentParser:
4316
4357
  parser = argparse.ArgumentParser(
4317
4358
  prog="simulo",
@@ -4320,6 +4361,18 @@ def _build_parser() -> argparse.ArgumentParser:
4320
4361
  "(simulo jobs / logs / result / recordings / models / view / cancel)."
4321
4362
  ),
4322
4363
  )
4364
+ # ``action="version"`` fires (prints + exits 0) while argparse is still
4365
+ # consuming optionals — before the subparsers' ``required=True`` check
4366
+ # runs — so ``simulo --version`` / ``simulo -v`` work standalone, with no
4367
+ # subcommand needed. No other short flag is registered anywhere on this
4368
+ # parser (or any subparser), so ``-v`` is free to alias ``--version``.
4369
+ parser.add_argument(
4370
+ "--version",
4371
+ "-v",
4372
+ action="version",
4373
+ version=f"simulo {_resolve_version()}",
4374
+ help="Show the simulo version and exit.",
4375
+ )
4323
4376
  sub = parser.add_subparsers(dest="command", required=True)
4324
4377
 
4325
4378
  run = sub.add_parser(
@@ -4489,7 +4542,7 @@ def _build_parser() -> argparse.ArgumentParser:
4489
4542
  asset = sub.add_parser(
4490
4543
  "asset",
4491
4544
  help=(
4492
- "Publish, validate, browse, and manage robot/world asset packages in your "
4545
+ "Publish, validate, browse, and manage robot, world, and prop asset packages in your "
4493
4546
  "organization's catalog and the Simulo global catalog (USD or URDF)."
4494
4547
  ),
4495
4548
  )
@@ -4560,7 +4613,7 @@ def _build_parser() -> argparse.ArgumentParser:
4560
4613
  "publish",
4561
4614
  help=(
4562
4615
  "Publish a USD or URDF package as a new immutable asset version: inspect + "
4563
- "upload + cloud-validate in one command (§5.1)."
4616
+ "upload + cloud-validate in one command."
4564
4617
  ),
4565
4618
  )
4566
4619
  asset_publish.add_argument("path", help="Directory (or single USD/URDF file) to publish.")
@@ -4708,7 +4761,7 @@ def _build_parser() -> argparse.ArgumentParser:
4708
4761
  "get",
4709
4762
  help=(
4710
4763
  "Download an org-catalog asset version to the local cache (~/.simulo/assets/...); "
4711
- "global assets are usable in jobs but not exportable (§5.4)."
4764
+ "global assets are usable in jobs but not exportable."
4712
4765
  ),
4713
4766
  )
4714
4767
  asset_get.add_argument("ref", help="Asset reference, e.g. robot/forklift:v3 (unpinned = latest published version).")
@@ -5003,7 +5056,16 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
5003
5056
  _make_output_encoding_safe()
5004
5057
  parser = _build_parser()
5005
5058
  args, extras = parser.parse_known_args(argv)
5006
- result: int = args.func(args, extras)
5059
+ try:
5060
+ result: int = args.func(args, extras)
5061
+ except KeyboardInterrupt:
5062
+ # Last-resort safety net: every dispatched command already has its own
5063
+ # clean handling (``_observe_handler`` for the observe verbs,
5064
+ # ``_follow_and_report`` for ``simulo run``'s post-submit follow), so
5065
+ # this only fires for a Ctrl-C in whatever's left uncovered. Either
5066
+ # way, standard SIGINT exit code, never a raw traceback.
5067
+ print("\nInterrupted.", file=sys.stderr)
5068
+ return 130
5007
5069
  return result
5008
5070
 
5009
5071
 
@@ -1,7 +1,7 @@
1
1
  """HTTP client for the live-view session mint endpoint (stdlib only, torch-free).
2
2
 
3
3
  Wire contract (live-visualization plan, Wave 2 PR3 — control-plane; see
4
- ``context/implementation-plans/live-visualization-plan.md`` and PR3's
4
+ ``context/implementation-plans/archive/live-visualization-plan.md`` and PR3's
5
5
  ``simulo_control_plane.jobs.view_sessions.mint_view_session``):
6
6
  ``POST /v1/jobs/{job_id}/view-session`` mints a short-lived (TTL <= 5 min)
7
7
  gateway-audience session for watching a running ``--viewstream`` job's live
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulo
3
- Version: 0.13.0
3
+ Version: 0.13.2
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
@@ -18,6 +18,7 @@ Description-Content-Type: text/markdown
18
18
  Requires-Dist: simulo-interfaces<0.6,>=0.5
19
19
  Requires-Dist: mcap<2,>=1.3
20
20
  Requires-Dist: defusedxml>=0.7.1
21
+ Requires-Dist: usd-core<27,>=25.5
21
22
  Provides-Extra: assets
22
23
  Requires-Dist: usd-core<27,>=25.5; extra == "assets"
23
24
  Provides-Extra: dev
@@ -1,6 +1,7 @@
1
1
  simulo-interfaces<0.6,>=0.5
2
2
  mcap<2,>=1.3
3
3
  defusedxml>=0.7.1
4
+ usd-core<27,>=25.5
4
5
 
5
6
  [assets]
6
7
  usd-core<27,>=25.5
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes