simulo-interfaces 0.7.0__tar.gz → 0.11.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 (56) hide show
  1. {simulo_interfaces-0.7.0/src/simulo_interfaces.egg-info → simulo_interfaces-0.11.0}/PKG-INFO +6 -5
  2. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/pyproject.toml +11 -2
  3. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/__init__.py +1 -1
  4. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/__init__.py +190 -0
  5. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/actuator.py +53 -0
  6. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/asset.py +99 -0
  7. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/entity.py +180 -0
  8. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/light.py +87 -0
  9. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/materials.py +80 -0
  10. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/physics.py +154 -0
  11. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/pose.py +100 -0
  12. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/primitives.py +132 -0
  13. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/record.py +400 -0
  14. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/robot.py +378 -0
  15. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/scene.py +154 -0
  16. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/sensor.py +133 -0
  17. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/terrain.py +306 -0
  18. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/visual.py +302 -0
  19. simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/world.py +111 -0
  20. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/exceptions.py +1 -1
  21. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/ids.py +1 -0
  22. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/__init__.py +70 -1
  23. simulo_interfaces-0.11.0/src/simulo/interfaces/platform/artifacts.py +721 -0
  24. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/asset.py +2 -1
  25. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/asset_catalog.py +77 -81
  26. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/debug.py +4 -4
  27. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/domain.py +5 -5
  28. simulo_interfaces-0.11.0/src/simulo/interfaces/platform/enums.py +177 -0
  29. simulo_interfaces-0.11.0/src/simulo/interfaces/platform/manifest.py +290 -0
  30. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/runs.py +75 -3
  31. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/submit.py +28 -10
  32. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/anomaly.py +74 -8
  33. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/components.py +26 -6
  34. simulo_interfaces-0.11.0/src/simulo/interfaces/runtime/env.py +101 -0
  35. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/player.py +16 -1
  36. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/scenario.py +9 -2
  37. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/task.py +8 -1
  38. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/trainer.py +10 -0
  39. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0/src/simulo_interfaces.egg-info}/PKG-INFO +6 -5
  40. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/SOURCES.txt +18 -0
  41. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/requires.txt +5 -4
  42. simulo_interfaces-0.7.0/src/simulo/interfaces/platform/enums.py +0 -106
  43. simulo_interfaces-0.7.0/src/simulo/interfaces/runtime/env.py +0 -56
  44. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/MANIFEST.in +0 -0
  45. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/PYPI.md +0 -0
  46. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/setup.cfg +0 -0
  47. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/app.py +0 -0
  48. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/callbacks.py +0 -0
  49. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/runtime.py +0 -0
  50. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/volume.py +0 -0
  51. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/py.typed +0 -0
  52. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/__init__.py +0 -0
  53. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/policy.py +0 -0
  54. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/tensors.py +0 -0
  55. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/dependency_links.txt +0 -0
  56. {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulo-interfaces
3
- Version: 0.7.0
3
+ Version: 0.11.0
4
4
  Summary: Type contracts for the Simulo SDK. Installed automatically as a dependency of the simulo package.
5
5
  Author-email: Simulo Team <team@simulo.ai>
6
6
  License: BSD-3-Clause
@@ -16,13 +16,14 @@ Classifier: Typing :: Typed
16
16
  Requires-Python: >=3.11
17
17
  Description-Content-Type: text/markdown
18
18
  Provides-Extra: dev
19
- Requires-Dist: black>=24.0; extra == "dev"
20
- Requires-Dist: isort>=5.13; extra == "dev"
21
- Requires-Dist: ruff>=0.5; extra == "dev"
22
- Requires-Dist: mypy>=1.10; extra == "dev"
19
+ Requires-Dist: black==26.5.1; extra == "dev"
20
+ Requires-Dist: isort==8.0.1; extra == "dev"
21
+ Requires-Dist: ruff==0.15.21; extra == "dev"
22
+ Requires-Dist: mypy==2.3.0; extra == "dev"
23
23
  Requires-Dist: pytest>=8.2; extra == "dev"
24
24
  Requires-Dist: build>=1.2; extra == "dev"
25
25
  Requires-Dist: twine>=5.1; extra == "dev"
26
+ Requires-Dist: packaging>=23; extra == "dev"
26
27
  Provides-Extra: release
27
28
  Requires-Dist: commitizen>=3.27; extra == "release"
28
29
  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-interfaces"
7
- version = "0.7.0"
7
+ version = "0.11.0"
8
8
  description = "Type contracts for the Simulo SDK. Installed automatically as a dependency of the simulo package."
9
9
  readme = "PYPI.md"
10
10
  requires-python = ">=3.11"
@@ -26,7 +26,16 @@ classifiers = [
26
26
  dependencies = []
27
27
 
28
28
  [project.optional-dependencies]
29
- dev = ["black>=24.0", "isort>=5.13", "ruff>=0.5", "mypy>=1.10", "pytest>=8.2", "build>=1.2", "twine>=5.1"]
29
+ # black/isort/ruff/mypy pinned EXACT, not >=: see simulo-backend/pyproject.toml's
30
+ # `dev` extra for the full rationale (2026-08-01 ruff 0.15.21->0.16.1 CI incident).
31
+ # Keep in lockstep with `.github/workflows/simulo-interfaces-ci.yml`'s
32
+ # `ruff`/`black`/`isort`/`mypy` steps, which resolve their versions from THIS extra
33
+ # (`pip install -e ".[dev]"`).
34
+ dev = ["black==26.5.1", "isort==8.0.1", "ruff==0.15.21", "mypy==2.3.0", "pytest>=8.2", "build>=1.2",
35
+ "twine>=5.1", "packaging>=23"]
36
+ # `packaging` is a direct test dependency, not incidental: the consumer-pin guard parses
37
+ # PEP 508 requirements with it. It arrives transitively via pytest today, which is exactly
38
+ # why it is declared here — a transitive dep that disappears takes the guard with it.
30
39
  # `dev` carries build/twine but deliberately not commitizen; `release` below
31
40
  # adds commitizen for cutting version bumps without a second build/twine copy.
32
41
  release = ["commitizen>=3.27", "build>=1.2", "twine>=5.1"]
@@ -1,6 +1,6 @@
1
1
  """Simulo Interfaces — implementation-free contract layer for the Simulo platform.
2
2
 
3
- Torch-free, zero-runtime-dependency (Rule #11). Importable on a laptop with no
3
+ Torch-free, zero-runtime-dependency. Importable on a laptop with no
4
4
  torch / numpy / gymnasium / Isaac / AWS / HTTP / DB installed. Two parts:
5
5
 
6
6
  * **Part A — ``simulo.interfaces.runtime``**: tensor-library-agnostic structural
@@ -0,0 +1,190 @@
1
+ """Part C — the typed authoring surface.
2
+
3
+ The **relocation and mirror destination** for the Simulo authoring value types.
4
+ Each type here has exactly ONE definition — this one — shared by both
5
+ distributions: the thin client authors these values at submit (torch-free,
6
+ e.g. ``simulo.Pose(xyz=(1, 2, 3))``) and the backend executes them on the
7
+ worker. There is no other copy and no re-export shim anywhere ("nuke as you
8
+ go", per the owner's 2026-07-26 directive recorded in the plan): the former
9
+ backend ``core`` modules for these types are deleted, so ``isinstance`` keeps
10
+ working because only this definition exists.
11
+
12
+ Relocated so far — Wave C1: ``pose`` (``Pose``), ``materials`` (``Material``,
13
+ ``SurfaceMaterial``), ``physics`` (``Physics``, ``Collision``, ``RigidPhysics``,
14
+ ``DeformableMaterial``, ``DeformablePhysics``), ``asset`` (``AssetSource``,
15
+ ``USDAsset``, ``URDFAsset`` — the model-source specs, distinct from the thin
16
+ client's registry-handle ``simulo.Asset``; renamed from ``Asset`` — owner
17
+ decision — to resolve that exact name collision), and ``light`` (``Light``,
18
+ ``LightConfig``, ``DistantLight``, ``DomeLight``). Wave C2: ``terrain``
19
+ (``Terrain``, ``TerrainConfig``, ``GroundPlane``, ``SubTerrainConfig``,
20
+ ``RoughTerrain``), ``primitives`` (``PrimitiveShape``, ``Cone``,
21
+ ``Cuboid``, ``Sphere``, ``Cylinder``, ``Transform``), ``entity`` (``Entity``,
22
+ ``AssetEntity``), and ``visual`` (``Visual``, ``VisualMarkerBase``,
23
+ ``AxesMarker``, ``SphereMarker``, ``ArrowMarker``, ``PointMarker``).
24
+ Wave C4: ``record`` (``RecordConfig`` — the MCAP recording configuration;
25
+ stdlib-only, so it classifies RELOCATE, and the backend recorder imports it
26
+ from here), and ``world`` (``World``, ``USDWorld``): ``Terrain`` is the
27
+ ground you *generate* (``plane``, ``rough``); ``World.usd(...)`` returns
28
+ ``USDWorld``, a prebuilt place you *bring*.
29
+
30
+ Mirrored so far — Wave C2: ``scene`` (``SceneProtocol``, ``SceneGroupProtocol``
31
+ — the first MIRROR; the concrete ``Scene``/``SceneGroup`` stay in the backend
32
+ package and explicitly inherit these Protocols). Wave C3: ``robot``
33
+ (``RobotProtocol``, plus ``RobotStateProtocol`` — the grouped live-state
34
+ contract behind ``robot.state``), ``sensor`` (``SensorProtocol``,
35
+ ``CameraProtocol``), and ``actuator`` (``ActuatorProtocol``) — same
36
+ mechanism; the concrete classes
37
+ stay in the backend package and explicitly inherit their Protocols, and the
38
+ other concrete sensor/actuator subclasses conform through their bases. Later
39
+ waves add the remaining RELOCATE-classified types and MIRROR Protocols.
40
+
41
+ **R-C3 is the hard constraint on everything that lands here:** no module in
42
+ this package — or anywhere else in ``simulo-interfaces`` — may import
43
+ ``simulo.core``, ``simulo.backend``, or the thin client's private internal
44
+ package, at import time or at call time (the ``Scene`` trap: zero torch
45
+ imports, but call-time imports of torch-coupled ``core`` modules deep inside a
46
+ method body). Guarded by ``tests/test_no_core_dependency.py`` in this package —
47
+ both a static import-statement guard and a runtime ``sys.modules`` check that
48
+ imports every submodule AND instantiates/calls the relocated API, because the
49
+ static guard alone cannot see ``from simulo import core``, dynamic access, or a
50
+ call-time-only import buried in a method body.
51
+
52
+ Two relocation mechanisms select which types land here and how (see the derived
53
+ plan for the full worked example and rejected alternatives):
54
+
55
+ * **RELOCATE** — the class definition MOVES here; the old ``core/<module>.py``
56
+ is deleted and every call site rewritten in the same PR (no re-export shims).
57
+ Reserved for types with zero import-time *or* call-time dependency on
58
+ anything that cannot live in a zero-dependency package.
59
+ * **MIRROR** — a ``typing.Protocol`` (named ``*Protocol``, matching the
60
+ ``runtime`` contracts) with real signatures and ``...`` bodies lands here,
61
+ describing the class's PUBLIC surface only; the backend's ``core/`` class
62
+ explicitly INHERITS it (nominal conformance, the same pattern
63
+ ``simulo-protocol`` already blesses for the ``runtime`` Protocols). Reserved
64
+ for everything else — anything with a real or call-time dependency on torch,
65
+ numpy, gymnasium, skrl, isaaclab, or another MIRROR-classified ``core``
66
+ module. Divergence is gated in three measured layers, because no single one
67
+ suffices: mypy fails signature-*shape* drift (arity, kinds,
68
+ default-presence, types) at the ``core/`` definition site but is SILENT on
69
+ parameter renames and on a property degrading to a plain attribute — those
70
+ need the backend suite's signature-conformance test (per-member bidirectional
71
+ — it compares the live contract against the live implementation — plus a
72
+ member-SET equality check over the implementation's statically-derivable
73
+ public surface: class-body names across its MRO and ``__init__``-bound
74
+ instance attributes, with a pinned documented-omissions allowlist; an extra
75
+ public member is legal subtyping no per-member loop can see, and attributes
76
+ bound outside ``__init__`` stay statically invisible even to the set check)
77
+ — and
78
+ constructor signatures need a separate ``__call__``-Protocol pin in the
79
+ backend's static conformance checks (type checkers exempt ``__init__`` from
80
+ override checks).
81
+
82
+ The checked-in authoring-surface inventory table classifies every name
83
+ currently referenced by the example trees (RELOCATE or MIRROR, source module,
84
+ and cross-references for cryptic engine-style names) — that table, not this
85
+ docstring, is the source of truth for what lands here and when.
86
+ """
87
+
88
+ from simulo.interfaces.authoring.actuator import ActuatorProtocol
89
+ from simulo.interfaces.authoring.asset import AssetSource, URDFAsset, USDAsset
90
+ from simulo.interfaces.authoring.entity import AssetEntity, Entity
91
+ from simulo.interfaces.authoring.light import DistantLight, DomeLight, Light, LightConfig
92
+ from simulo.interfaces.authoring.materials import Material, SurfaceMaterial
93
+ from simulo.interfaces.authoring.physics import (
94
+ Collision,
95
+ DeformableMaterial,
96
+ DeformablePhysics,
97
+ Physics,
98
+ RigidPhysics,
99
+ )
100
+ from simulo.interfaces.authoring.pose import Pose
101
+ from simulo.interfaces.authoring.primitives import (
102
+ Cone,
103
+ Cuboid,
104
+ Cylinder,
105
+ PrimitiveShape,
106
+ Sphere,
107
+ Transform,
108
+ )
109
+ from simulo.interfaces.authoring.record import RecordConfig
110
+ from simulo.interfaces.authoring.robot import RobotProtocol, RobotStateProtocol
111
+ from simulo.interfaces.authoring.scene import SceneGroupProtocol, SceneProtocol
112
+ from simulo.interfaces.authoring.sensor import CameraProtocol, SensorProtocol
113
+ from simulo.interfaces.authoring.terrain import (
114
+ GroundPlane,
115
+ RoughTerrain,
116
+ SubTerrainConfig,
117
+ Terrain,
118
+ TerrainConfig,
119
+ )
120
+ from simulo.interfaces.authoring.visual import (
121
+ ArrowMarker,
122
+ AxesMarker,
123
+ PointMarker,
124
+ SphereMarker,
125
+ Visual,
126
+ VisualMarkerBase,
127
+ )
128
+ from simulo.interfaces.authoring.world import USDWorld, World
129
+
130
+ __all__ = [
131
+ # pose
132
+ "Pose",
133
+ # materials
134
+ "Material",
135
+ "SurfaceMaterial",
136
+ # physics
137
+ "Collision",
138
+ "RigidPhysics",
139
+ "DeformableMaterial",
140
+ "DeformablePhysics",
141
+ "Physics",
142
+ # asset (model-source specs)
143
+ "AssetSource",
144
+ "USDAsset",
145
+ "URDFAsset",
146
+ # light
147
+ "LightConfig",
148
+ "DistantLight",
149
+ "DomeLight",
150
+ "Light",
151
+ # terrain (ground you generate)
152
+ "TerrainConfig",
153
+ "GroundPlane",
154
+ "SubTerrainConfig",
155
+ "RoughTerrain",
156
+ "Terrain",
157
+ # world (a prebuilt place you bring — split from terrain in Wave C4)
158
+ "USDWorld",
159
+ "World",
160
+ # primitives
161
+ "PrimitiveShape",
162
+ "Cone",
163
+ "Cuboid",
164
+ "Sphere",
165
+ "Cylinder",
166
+ "Transform",
167
+ # entity
168
+ "Entity",
169
+ "AssetEntity",
170
+ # record (RELOCATED Wave C4 — the MCAP recording config; its helper
171
+ # functions stay importable from ``simulo.interfaces.authoring.record``)
172
+ "RecordConfig",
173
+ # visual
174
+ "VisualMarkerBase",
175
+ "AxesMarker",
176
+ "SphereMarker",
177
+ "ArrowMarker",
178
+ "PointMarker",
179
+ "Visual",
180
+ # scene (MIRROR — the concrete classes live in the backend package)
181
+ "SceneProtocol",
182
+ "SceneGroupProtocol",
183
+ # robot / sensor / actuator (MIRROR — the concrete classes live in the
184
+ # backend package and explicitly inherit these Protocols)
185
+ "RobotProtocol",
186
+ "RobotStateProtocol",
187
+ "SensorProtocol",
188
+ "CameraProtocol",
189
+ "ActuatorProtocol",
190
+ ]
@@ -0,0 +1,53 @@
1
+ """``ActuatorProtocol`` — the declared actuator authoring contract.
2
+
3
+ A MIRROR, not a relocation (same mechanism as the Scene, Robot, and Sensor
4
+ contracts in this package): the concrete ``Actuator`` implementation stays in
5
+ the backend package — its command path writes into a live simulation engine
6
+ handle — so what lives here is the declared public surface only.
7
+
8
+ The backend's concrete ``Actuator`` base class explicitly inherits this
9
+ Protocol (nominal conformance); concrete actuator types (e.g. the surface
10
+ gripper) inherit it through the base and keep their richer surfaces as
11
+ implementation-defined extensions.
12
+
13
+ Enforcement is the standard four layers for a mirror (see the Robot contract
14
+ module's docstring). ``get_state`` faithfully mirrors today's untyped return:
15
+ a named supported subset for actuator state is a later, separate contract
16
+ decision, deliberately not designed here.
17
+ """
18
+
19
+ from typing import Any, Optional, Protocol, runtime_checkable
20
+
21
+
22
+ @runtime_checkable
23
+ class ActuatorProtocol(Protocol):
24
+ """The actuator authoring contract — an action interface for robots.
25
+
26
+ An actuator is configured at authoring time, attached to a scene path,
27
+ and driven with commands during simulation. Concrete actuator types
28
+ define their own command and state shapes.
29
+ """
30
+
31
+ path: Optional[str]
32
+ """Scene path where the actuator is attached (may be set via the scene)."""
33
+
34
+ enabled: bool
35
+ """Whether the actuator is active."""
36
+
37
+ @property
38
+ def name(self) -> Optional[str]:
39
+ """Actuator name — set by the scene when the actuator is added."""
40
+ ...
41
+
42
+ def set_command(self, command: Any) -> None:
43
+ """Set an actuator-specific command. Commands are buffered and
44
+ flushed automatically before the next physics step."""
45
+ ...
46
+
47
+ def get_state(self) -> Any:
48
+ """Current actuator-specific state."""
49
+ ...
50
+
51
+ def reset(self) -> None:
52
+ """Reset the actuator to its default state."""
53
+ ...
@@ -0,0 +1,99 @@
1
+ """Model-source asset specs — USD/URDF sources a scene loads.
2
+
3
+ Owns the canonical ``AssetSource`` / ``USDAsset`` / ``URDFAsset`` model-source
4
+ dataclasses. Distinct from the thin client's user-facing ``simulo.Asset``
5
+ registry handle (a catalog ref like ``robot/so-arm-100:v3``): these classes
6
+ name a USD/URDF *file source* to load into a scene, and the backend consumes
7
+ them when it builds the simulation.
8
+
9
+ Renamed from ``Asset`` (owner decision): the old name collided with the
10
+ thin client's registry-handle ``simulo.Asset`` — same name, different
11
+ constructor, different members, both user-facing. Nothing failed on the
12
+ collision (both expose ``.usd()``/``.urdf()``, the handle's just returns
13
+ ``Any``), which is exactly why it was worth a rename rather than a shim.
14
+ """
15
+
16
+ from dataclasses import dataclass
17
+ from typing import TYPE_CHECKING
18
+
19
+
20
+ @dataclass
21
+ class AssetSource:
22
+ """Base model-source asset class."""
23
+
24
+ if TYPE_CHECKING:
25
+ # ``AssetSource.usd`` / ``AssetSource.urdf`` are attached dynamically
26
+ # below (they return the ``USDAsset`` / ``URDFAsset`` subclasses,
27
+ # which are defined after this class). These declarations never
28
+ # execute; they exist so a type checker sees the convenience aliases
29
+ # with their precise signatures instead of rejecting
30
+ # ``AssetSource.usd(...)`` as an unknown attribute.
31
+ @classmethod
32
+ def usd(cls, path: str) -> "USDAsset": ...
33
+
34
+ @classmethod
35
+ def urdf(cls, path: str) -> "URDFAsset": ...
36
+
37
+
38
+ @dataclass
39
+ class USDAsset(AssetSource):
40
+ """USD file asset.
41
+
42
+ Attributes:
43
+ path: Path to USD file (supports file://, nucleus:// schemes). The
44
+ legacy simulo:// path alias is REMOVED — 'simulo/...' is a catalog
45
+ ref ([publisher/]kind/name[:vN], 'simulo' = the global-catalog
46
+ publisher), resolved through
47
+ simulo.Asset.from_registry("robot/<name>:v1"), never a runtime
48
+ path scheme. A simulo:// path raises a clear migration error at
49
+ resolution time.
50
+ """
51
+
52
+ path: str
53
+
54
+ @classmethod
55
+ def usd(cls, path: str) -> "USDAsset":
56
+ """Create a USD asset.
57
+
58
+ Args:
59
+ path: Path to USD file
60
+
61
+ Returns:
62
+ USDAsset instance
63
+ """
64
+ return cls(path=path)
65
+
66
+
67
+ @dataclass
68
+ class URDFAsset(AssetSource):
69
+ """URDF file asset.
70
+
71
+ Attributes:
72
+ path: Path to URDF file
73
+ """
74
+
75
+ path: str
76
+
77
+ @classmethod
78
+ def urdf(cls, path: str) -> "URDFAsset":
79
+ """Create a URDF asset.
80
+
81
+ Args:
82
+ path: Path to URDF file
83
+
84
+ Returns:
85
+ URDFAsset instance
86
+ """
87
+ return cls(path=path)
88
+
89
+
90
+ # Alias for convenience — callers reach for `AssetSource.usd(...)` /
91
+ # `AssetSource.urdf(...)`.
92
+ # Attached dynamically; the TYPE_CHECKING declarations on AssetSource above
93
+ # are what let a type checker see them.
94
+ AssetSource.usd = USDAsset.usd # type: ignore[method-assign]
95
+ AssetSource.urdf = URDFAsset.urdf # type: ignore[method-assign]
96
+
97
+ # Explicit public surface — keeps the TYPE_CHECKING import (needed for the
98
+ # static-only `usd`/`urdf` declarations above) off the star-import namespace.
99
+ __all__ = ["AssetSource", "USDAsset", "URDFAsset"]
@@ -0,0 +1,180 @@
1
+ """Entity abstraction for objects in the scene."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Optional, Tuple
5
+
6
+ from simulo.interfaces.authoring.asset import AssetSource
7
+ from simulo.interfaces.authoring.materials import Material
8
+ from simulo.interfaces.authoring.physics import DeformablePhysics, RigidPhysics
9
+ from simulo.interfaces.authoring.pose import Pose
10
+ from simulo.interfaces.authoring.primitives import Cone, Cuboid, Cylinder, Sphere
11
+
12
+
13
+ @dataclass
14
+ class Entity:
15
+ """An Entity is any object that can exist within a Scene.
16
+
17
+ Entities represent presence. They exist in space, have identity,
18
+ and may have physical state.
19
+ """
20
+
21
+ name: str
22
+ pose: Pose = field(default_factory=Pose.identity)
23
+ material: Optional[Material] = None
24
+ physics: Optional[RigidPhysics | DeformablePhysics] = None
25
+
26
+ class primitive:
27
+ """Factory for primitive entities."""
28
+
29
+ @staticmethod
30
+ def cone(
31
+ name: str,
32
+ radius: float = 0.5,
33
+ height: float = 1.0,
34
+ pose: Optional[Pose] = None,
35
+ material: Optional[Material] = None,
36
+ physics: Optional[RigidPhysics | DeformablePhysics] = None,
37
+ ) -> Cone:
38
+ """Create a cone entity.
39
+
40
+ Args:
41
+ name: Entity name
42
+ radius: Cone base radius
43
+ height: Cone height
44
+ pose: Pose in space
45
+ material: Visual material
46
+ physics: Physics properties
47
+
48
+ Returns:
49
+ Cone entity
50
+ """
51
+ return Cone(
52
+ name=name,
53
+ radius=radius,
54
+ height=height,
55
+ pose=pose or Pose.identity(),
56
+ material=material,
57
+ physics=physics,
58
+ )
59
+
60
+ @staticmethod
61
+ def cuboid(
62
+ name: str,
63
+ size: Tuple[float, float, float] = (1.0, 1.0, 1.0),
64
+ pose: Optional[Pose] = None,
65
+ material: Optional[Material] = None,
66
+ physics: Optional[RigidPhysics | DeformablePhysics] = None,
67
+ ) -> Cuboid:
68
+ """Create a cuboid entity.
69
+
70
+ Args:
71
+ name: Entity name
72
+ size: Box size as (width, depth, height)
73
+ pose: Pose in space
74
+ material: Visual material
75
+ physics: Physics properties
76
+
77
+ Returns:
78
+ Cuboid entity
79
+ """
80
+ return Cuboid(
81
+ name=name,
82
+ size=size,
83
+ pose=pose or Pose.identity(),
84
+ material=material,
85
+ physics=physics,
86
+ )
87
+
88
+ @staticmethod
89
+ def sphere(
90
+ name: str,
91
+ radius: float = 0.5,
92
+ pose: Optional[Pose] = None,
93
+ material: Optional[Material] = None,
94
+ physics: Optional[RigidPhysics | DeformablePhysics] = None,
95
+ ) -> Sphere:
96
+ """Create a sphere entity.
97
+
98
+ Args:
99
+ name: Entity name
100
+ radius: Sphere radius
101
+ pose: Pose in space
102
+ material: Visual material
103
+ physics: Physics properties
104
+
105
+ Returns:
106
+ Sphere entity
107
+ """
108
+ return Sphere(
109
+ name=name,
110
+ radius=radius,
111
+ pose=pose or Pose.identity(),
112
+ material=material,
113
+ physics=physics,
114
+ )
115
+
116
+ @staticmethod
117
+ def cylinder(
118
+ name: str,
119
+ radius: float = 0.5,
120
+ height: float = 1.0,
121
+ pose: Optional[Pose] = None,
122
+ material: Optional[Material] = None,
123
+ physics: Optional[RigidPhysics | DeformablePhysics] = None,
124
+ ) -> Cylinder:
125
+ """Create a cylinder entity.
126
+
127
+ Args:
128
+ name: Entity name
129
+ radius: Cylinder radius
130
+ height: Cylinder height
131
+ pose: Pose in space
132
+ material: Visual material
133
+ physics: Physics properties
134
+
135
+ Returns:
136
+ Cylinder entity
137
+ """
138
+ return Cylinder(
139
+ name=name,
140
+ radius=radius,
141
+ height=height,
142
+ pose=pose or Pose.identity(),
143
+ material=material,
144
+ physics=physics,
145
+ )
146
+
147
+ @staticmethod
148
+ def from_asset(
149
+ name: str,
150
+ asset: AssetSource,
151
+ pose: Optional[Pose] = None,
152
+ ) -> "AssetEntity":
153
+ """Create an entity from a USD or URDF asset.
154
+
155
+ Args:
156
+ name: Entity name
157
+ asset: Asset specification
158
+ pose: Pose in space
159
+
160
+ Returns:
161
+ AssetEntity instance
162
+ """
163
+ return AssetEntity(
164
+ name=name,
165
+ asset=asset,
166
+ pose=pose or Pose.identity(),
167
+ )
168
+
169
+
170
+ @dataclass
171
+ class AssetEntity(Entity):
172
+ """Entity loaded from an external asset file.
173
+
174
+ Attributes:
175
+ asset: Asset specification (USD, URDF, etc.). Required at construction;
176
+ ``None`` is not a valid default but is kept here to preserve the
177
+ existing dataclass field ordering. Callers always supply this.
178
+ """
179
+
180
+ asset: Optional[AssetSource] = None
@@ -0,0 +1,87 @@
1
+ """Light source definitions."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Optional, Tuple
5
+
6
+ from simulo.interfaces.authoring.pose import Pose
7
+
8
+
9
+ @dataclass
10
+ class LightConfig:
11
+ """Base light configuration."""
12
+
13
+ name: str
14
+ intensity: float = 1000.0
15
+ color: Tuple[float, float, float] = (1.0, 1.0, 1.0)
16
+ pose: Pose = field(default_factory=Pose.identity)
17
+
18
+
19
+ @dataclass
20
+ class DistantLight(LightConfig):
21
+ """Distant (directional) light source.
22
+
23
+ Similar to sunlight - parallel rays from infinity.
24
+ """
25
+
26
+ pass
27
+
28
+
29
+ @dataclass
30
+ class DomeLight(LightConfig):
31
+ """Dome light for ambient illumination."""
32
+
33
+ pass
34
+
35
+
36
+ class Light:
37
+ """Light factory."""
38
+
39
+ @staticmethod
40
+ def distant(
41
+ name: str = "distantLight",
42
+ intensity: float = 1000.0,
43
+ color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
44
+ pose: Optional[Pose] = None,
45
+ ) -> DistantLight:
46
+ """Create a distant light.
47
+
48
+ Args:
49
+ name: Light name
50
+ intensity: Light intensity
51
+ color: RGB color
52
+ pose: Pose in space
53
+
54
+ Returns:
55
+ DistantLight instance
56
+ """
57
+ return DistantLight(
58
+ name=name,
59
+ intensity=intensity,
60
+ color=color,
61
+ pose=pose or Pose.identity(),
62
+ )
63
+
64
+ @staticmethod
65
+ def dome(
66
+ name: str = "domeLight",
67
+ intensity: float = 1000.0,
68
+ color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
69
+ ) -> DomeLight:
70
+ """Create a dome light.
71
+
72
+ Args:
73
+ name: Light name
74
+ intensity: Light intensity
75
+ color: RGB color
76
+
77
+ Returns:
78
+ DomeLight instance
79
+ """
80
+ return DomeLight(
81
+ name=name,
82
+ intensity=intensity,
83
+ color=color,
84
+ )
85
+
86
+
87
+ __all__ = ["LightConfig", "DistantLight", "DomeLight", "Light"]