kscale 0.3.5__py3-none-any.whl → 0.3.7__py3-none-any.whl

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.
kscale/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Defines the common interface for the K-Scale Python API."""
2
2
 
3
- __version__ = "0.3.5"
3
+ __version__ = "0.3.7"
4
4
 
5
5
  from pathlib import Path
6
6
 
kscale/requirements.txt CHANGED
@@ -21,6 +21,3 @@ tabulate
21
21
 
22
22
  # Async
23
23
  async-lru
24
-
25
- # K-Scale
26
- krec
@@ -80,7 +80,23 @@ async def update(current_name: str, name: str | None = None, description: str |
80
80
  click.echo(f" Description: {click.style(robot_class.description or 'N/A', fg='yellow')}")
81
81
 
82
82
 
83
- @cli.command()
83
+ @cli.command("delete")
84
+ @click.argument("name")
85
+ @coro
86
+ async def delete_robot_class(name: str) -> None:
87
+ """Deletes a robot class."""
88
+ async with RobotClassClient() as client:
89
+ await client.delete_robot_class(name)
90
+ click.echo(f"Robot class deleted: {click.style(name, fg='red')}")
91
+
92
+
93
+ @cli.group()
94
+ def metadata() -> None:
95
+ """Handle the robot class metadata."""
96
+ pass
97
+
98
+
99
+ @metadata.command("update")
84
100
  @click.argument("name")
85
101
  @click.argument("json_path", type=click.Path(exists=True))
86
102
  @coro
@@ -96,7 +112,7 @@ async def update_metadata(name: str, json_path: str) -> None:
96
112
  click.echo(f" Name: {click.style(robot_class.class_name, fg='green')}")
97
113
 
98
114
 
99
- @cli.command()
115
+ @metadata.command("get")
100
116
  @click.argument("name")
101
117
  @click.option("--json-path", type=click.Path(exists=False))
102
118
  @coro
@@ -115,27 +131,17 @@ async def get_metadata(name: str, json_path: str | None = None) -> None:
115
131
  json.dump(metadata.model_dump(), f)
116
132
 
117
133
 
118
- @cli.command()
119
- @click.argument("name")
120
- @coro
121
- async def delete(name: str) -> None:
122
- """Deletes a robot class."""
123
- async with RobotClassClient() as client:
124
- await client.delete_robot_class(name)
125
- click.echo(f"Robot class deleted: {click.style(name, fg='red')}")
126
-
127
-
128
134
  @cli.group()
129
135
  def urdf() -> None:
130
136
  """Handle the robot class URDF."""
131
137
  pass
132
138
 
133
139
 
134
- @urdf.command()
140
+ @urdf.command("upload")
135
141
  @click.argument("class_name")
136
142
  @click.argument("urdf_file")
137
143
  @coro
138
- async def upload(class_name: str, urdf_file: str) -> None:
144
+ async def upload_urdf(class_name: str, urdf_file: str) -> None:
139
145
  """Uploads a URDF file to a robot class."""
140
146
  async with RobotClassClient() as client:
141
147
  response = await client.upload_robot_class_urdf(class_name, urdf_file)
@@ -143,18 +149,18 @@ async def upload(class_name: str, urdf_file: str) -> None:
143
149
  click.echo(f" Filename: {click.style(response.filename, fg='green')}")
144
150
 
145
151
 
146
- @urdf.command()
152
+ @urdf.command("download")
147
153
  @click.argument("class_name")
148
154
  @click.option("--cache", is_flag=True, default=False)
149
155
  @coro
150
- async def download(class_name: str, cache: bool) -> None:
156
+ async def download_urdf(class_name: str, cache: bool) -> None:
151
157
  """Downloads a URDF file from a robot class."""
152
158
  async with RobotClassClient() as client:
153
159
  urdf_file = await client.download_and_extract_urdf(class_name, cache=cache)
154
160
  click.echo(f"URDF downloaded: {click.style(urdf_file, fg='green')}")
155
161
 
156
162
 
157
- @urdf.command()
163
+ @urdf.command("pybullet")
158
164
  @click.argument("class_name")
159
165
  @click.option("--no-cache", is_flag=True, default=False)
160
166
  @click.option("--hide-gui", is_flag=True, default=False)
@@ -168,7 +174,7 @@ async def download(class_name: str, cache: bool) -> None:
168
174
  @click.option("--start-height", type=float, default=0.0)
169
175
  @click.option("--cycle-duration", type=float, default=2.0)
170
176
  @coro
171
- async def pybullet(
177
+ async def run_pybullet(
172
178
  class_name: str,
173
179
  no_cache: bool,
174
180
  hide_gui: bool,
@@ -432,5 +438,41 @@ async def pybullet(
432
438
  last_time = cur_time
433
439
 
434
440
 
441
+ @urdf.command("mujoco")
442
+ @click.argument("class_name")
443
+ @click.option("--no-cache", is_flag=True, default=False)
444
+ @coro
445
+ async def run_mujoco(class_name: str, no_cache: bool) -> None:
446
+ """Shows the URDF file for a robot class in Mujoco.
447
+
448
+ This command downloads and extracts the robot class URDF folder,
449
+ searches for an MJCF file (unless --mjcf-path is provided), and then
450
+ launches the Mujoco viewer using the provided MJCF file.
451
+ """
452
+ try:
453
+ import mujoco.viewer
454
+ except ImportError:
455
+ click.echo(
456
+ click.style(
457
+ "Mujoco and mujoco-python-viewer are required; install with `pip install mujoco`",
458
+ fg="red",
459
+ )
460
+ )
461
+ return
462
+
463
+ async with RobotClassClient() as client:
464
+ extracted_folder = await client.download_and_extract_urdf(class_name, cache=not no_cache)
465
+
466
+ try:
467
+ mjcf_file = next(extracted_folder.glob("*.mjcf"))
468
+ except StopIteration:
469
+ click.echo(click.style(f"No MJCF file found in {extracted_folder}", fg="red"))
470
+ return
471
+
472
+ mjcf_path_str = str(mjcf_file.resolve())
473
+ click.echo(f"Launching Mujoco viewer with: {click.style(mjcf_path_str, fg='green')}")
474
+ mujoco.viewer.launch_from_path(mjcf_path_str)
475
+
476
+
435
477
  if __name__ == "__main__":
436
478
  cli()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: kscale
3
- Version: 0.3.5
3
+ Version: 0.3.7
4
4
  Summary: The kscale project
5
5
  Home-page: https://github.com/kscalelabs/kscale
6
6
  Author: Benjamin Bolte
@@ -21,7 +21,6 @@ Requires-Dist: click
21
21
  Requires-Dist: colorlogging
22
22
  Requires-Dist: tabulate
23
23
  Requires-Dist: async-lru
24
- Requires-Dist: krec
25
24
  Provides-Extra: dev
26
25
  Requires-Dist: black; extra == "dev"
27
26
  Requires-Dist: darglint; extra == "dev"
@@ -1,9 +1,9 @@
1
- kscale/__init__.py,sha256=NN9HC3QKPXhqbAfVyGRaWYhhGbXuv0pXAfIybdiBdu0,200
1
+ kscale/__init__.py,sha256=JXk1-68D39Xj5C7awsV8wBXSDoj4Zds3jDuQP0VvMyY,200
2
2
  kscale/cli.py,sha256=PMHLKR5UwdbbReVmqHXpJ-K9-mGHv_0I7KQkwxmFcUA,881
3
3
  kscale/conf.py,sha256=dm35XSnzJp93St-ixVtYN4Nvqvb5upPGBrWkSI6Yb-4,1743
4
4
  kscale/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  kscale/requirements-dev.txt,sha256=WI7-ea4IRJakmqVMN8QKhOsDGrghwtvk03aIsFaNSIw,130
6
- kscale/requirements.txt,sha256=_BGbnKTQaXKx0bNEG0wguod9swsiCb2mF6rLm7sFJ2Q,214
6
+ kscale/requirements.txt,sha256=tj8wBkIhl6ijk5rFqtPCdkpdOS7XSIcUvsz_Eq1axcw,198
7
7
  kscale/artifacts/__init__.py,sha256=RK8wdybtCJPgdLLJ8R8-YMi1Ph5ojqAKVJZowHONtgo,232
8
8
  kscale/artifacts/plane.obj,sha256=x59-IIrWpLjhotChiqT2Ul6U8s0RcHkaEeUZb4KXL1c,348
9
9
  kscale/artifacts/plane.urdf,sha256=LCiTk14AyTHjkZ1jvsb0hNaEaJUxDb8Z1JjsgpXu3YM,819
@@ -15,7 +15,7 @@ kscale/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  kscale/web/utils.py,sha256=Mme-FAQ0_zbjjOQeX8wyq8F4kL4i9fH7ytri16U6qOA,1046
16
16
  kscale/web/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  kscale/web/cli/robot.py,sha256=rI-A4_0uvJPeA71Apl4Z3mV5fIfWkgmzT9JRmJYxz3A,3307
18
- kscale/web/cli/robot_class.py,sha256=Rr8IqZGvAdqtAbA_bNXuo_HJnZURXnqrFEFzwfms3YA,17469
18
+ kscale/web/cli/robot_class.py,sha256=QjE65uw2lSaerrdFr_zZzN9_W5w4Rx4exWZkijpDzmQ,18892
19
19
  kscale/web/cli/token.py,sha256=1rFC8MYKtqbNsQa2KIqwW1tqpaMtFaxuNsallwejXTU,787
20
20
  kscale/web/cli/user.py,sha256=aaJJCL1P5lfhK6ZC9OwOHXKA-I3MWqVZ_k7TYnx33CY,1303
21
21
  kscale/web/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -26,9 +26,9 @@ kscale/web/clients/robot_class.py,sha256=G8Nk6V7LGJE9Wpg9tyyCkIfz1fRTsxXQRgHtlei
26
26
  kscale/web/clients/user.py,sha256=jsa1_s6qXRM-AGBbHlPhd1NierUtynjY9tVAPNr6_Os,568
27
27
  kscale/web/gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  kscale/web/gen/api.py,sha256=VWlt8TaMZaAhCPPIWhx1d4yE0BRfpVz0-_Cps8hjgAI,4662
29
- kscale-0.3.5.dist-info/LICENSE,sha256=HCN2bImAzUOXldAZZI7JZ9PYq6OwMlDAP_PpX1HnuN0,1071
30
- kscale-0.3.5.dist-info/METADATA,sha256=CQEw-lvgEGZ_p3s4ikllSXpjWBsor1G8JN4qjDNwNrU,2340
31
- kscale-0.3.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
32
- kscale-0.3.5.dist-info/entry_points.txt,sha256=N_0pCpPnwGDYVzOeuaSOrbJkS5L3lS9d8CxpJF1f8UI,62
33
- kscale-0.3.5.dist-info/top_level.txt,sha256=C2ynjYwopg6YjgttnI2dJjasyq3EKNmYp-IfQg9Xms4,7
34
- kscale-0.3.5.dist-info/RECORD,,
29
+ kscale-0.3.7.dist-info/LICENSE,sha256=HCN2bImAzUOXldAZZI7JZ9PYq6OwMlDAP_PpX1HnuN0,1071
30
+ kscale-0.3.7.dist-info/METADATA,sha256=0hDh7EJaKk94ofN-EfGPVcvlSNs1vfcuVTI5vx9DB6Y,2320
31
+ kscale-0.3.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
32
+ kscale-0.3.7.dist-info/entry_points.txt,sha256=N_0pCpPnwGDYVzOeuaSOrbJkS5L3lS9d8CxpJF1f8UI,62
33
+ kscale-0.3.7.dist-info/top_level.txt,sha256=C2ynjYwopg6YjgttnI2dJjasyq3EKNmYp-IfQg9Xms4,7
34
+ kscale-0.3.7.dist-info/RECORD,,
File without changes