kscale 0.3.10__py3-none-any.whl → 0.3.12__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 +1 -1
- kscale/web/cli/robot_class.py +2 -1
- kscale/web/clients/base.py +21 -5
- kscale/web/clients/robot_class.py +8 -3
- kscale/web/gen/api.py +6 -3
- {kscale-0.3.10.dist-info → kscale-0.3.12.dist-info}/METADATA +1 -1
- {kscale-0.3.10.dist-info → kscale-0.3.12.dist-info}/RECORD +11 -11
- {kscale-0.3.10.dist-info → kscale-0.3.12.dist-info}/WHEEL +1 -1
- {kscale-0.3.10.dist-info → kscale-0.3.12.dist-info}/entry_points.txt +0 -0
- {kscale-0.3.10.dist-info → kscale-0.3.12.dist-info}/licenses/LICENSE +0 -0
- {kscale-0.3.10.dist-info → kscale-0.3.12.dist-info}/top_level.txt +0 -0
kscale/__init__.py
CHANGED
kscale/web/cli/robot_class.py
CHANGED
@@ -41,10 +41,11 @@ async def list() -> None:
|
|
41
41
|
click.style(rc.id, fg="blue"),
|
42
42
|
click.style(rc.class_name, fg="green"),
|
43
43
|
rc.description or "N/A",
|
44
|
+
"N/A" if rc.num_downloads is None else f"{rc.num_downloads:,}",
|
44
45
|
]
|
45
46
|
for rc in robot_classes
|
46
47
|
]
|
47
|
-
click.echo(tabulate(table_data, headers=["ID", "Name", "Description"], tablefmt="simple"))
|
48
|
+
click.echo(tabulate(table_data, headers=["ID", "Name", "Description", "Downloads"], tablefmt="simple"))
|
48
49
|
else:
|
49
50
|
click.echo(click.style("No robot classes found", fg="red"))
|
50
51
|
|
kscale/web/clients/base.py
CHANGED
@@ -9,7 +9,7 @@ import sys
|
|
9
9
|
import time
|
10
10
|
import webbrowser
|
11
11
|
from types import TracebackType
|
12
|
-
from typing import Any, Self, Type
|
12
|
+
from typing import Any, Mapping, Self, Type
|
13
13
|
from urllib.parse import urljoin
|
14
14
|
|
15
15
|
import aiohttp
|
@@ -363,6 +363,7 @@ class BaseClient:
|
|
363
363
|
params: dict[str, Any] | None = None,
|
364
364
|
data: BaseModel | dict[str, Any] | None = None,
|
365
365
|
files: dict[str, Any] | None = None,
|
366
|
+
error_code_suggestions: dict[int, str] | None = None,
|
366
367
|
) -> dict[str, Any]:
|
367
368
|
url = urljoin(self.base_url, endpoint)
|
368
369
|
kwargs: dict[str, Any] = {}
|
@@ -380,12 +381,27 @@ class BaseClient:
|
|
380
381
|
response = await client.request(method, url, **kwargs)
|
381
382
|
|
382
383
|
if response.is_error:
|
383
|
-
|
384
|
-
|
384
|
+
error_code = response.status_code
|
385
|
+
error_json = response.json()
|
386
|
+
use_verbose_error = verbose_error()
|
387
|
+
|
388
|
+
if not use_verbose_error:
|
389
|
+
logger.info("Use KSCALE_VERBOSE_ERROR=1 to see the full error message")
|
390
|
+
logger.info("If this persists, please create an issue here: https://github.com/kscalelabs/kscale")
|
391
|
+
|
392
|
+
logger.error("Got error %d from the K-Scale API", error_code)
|
393
|
+
if isinstance(error_json, Mapping):
|
394
|
+
for key, value in error_json.items():
|
395
|
+
logger.error(" [%s] %s", key, value)
|
396
|
+
else:
|
397
|
+
logger.error(" %s", error_json)
|
398
|
+
|
399
|
+
if error_code_suggestions is not None and error_code in error_code_suggestions:
|
400
|
+
logger.error("Hint: %s", error_code_suggestions[error_code])
|
401
|
+
|
402
|
+
if use_verbose_error:
|
385
403
|
response.raise_for_status()
|
386
404
|
else:
|
387
|
-
logger.error("Use KSCALE_VERBOSE_ERROR=1 to see the full error message")
|
388
|
-
logger.error("If this persists, please create an issue here: https://github.com/kscalelabs/kscale")
|
389
405
|
sys.exit(1)
|
390
406
|
|
391
407
|
return response.json()
|
@@ -31,7 +31,7 @@ class RobotClassClient(BaseClient):
|
|
31
31
|
data = await self._request(
|
32
32
|
"GET",
|
33
33
|
"/robots/",
|
34
|
-
auth=
|
34
|
+
auth=False,
|
35
35
|
)
|
36
36
|
return [RobotClass.model_validate(item) for item in data]
|
37
37
|
|
@@ -39,7 +39,7 @@ class RobotClassClient(BaseClient):
|
|
39
39
|
data = await self._request(
|
40
40
|
"GET",
|
41
41
|
f"/robots/name/{class_name}",
|
42
|
-
auth=
|
42
|
+
auth=False,
|
43
43
|
)
|
44
44
|
return RobotClass.model_validate(data)
|
45
45
|
|
@@ -117,7 +117,12 @@ class RobotClassClient(BaseClient):
|
|
117
117
|
cache_path = get_robots_dir() / class_name / "robot.tgz"
|
118
118
|
if cache and cache_path.exists() and not should_refresh_file(cache_path):
|
119
119
|
return cache_path
|
120
|
-
data = await self._request(
|
120
|
+
data = await self._request(
|
121
|
+
"GET",
|
122
|
+
f"/robots/urdf/{class_name}",
|
123
|
+
auth=False,
|
124
|
+
error_code_suggestions={404: "Use `kscale robot list` to view classes."},
|
125
|
+
)
|
121
126
|
response = RobotDownloadURDFResponse.model_validate(data)
|
122
127
|
expected_hash = response.md5_hash
|
123
128
|
cache_path.parent.mkdir(parents=True, exist_ok=True)
|
kscale/web/gen/api.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# generated by datamodel-codegen:
|
4
4
|
# filename: openapi.json
|
5
|
-
# timestamp: 2025-
|
5
|
+
# timestamp: 2025-05-03T21:02:12+00:00
|
6
6
|
|
7
7
|
from __future__ import annotations
|
8
8
|
|
@@ -37,8 +37,8 @@ class JointMetadataInput(BaseModel):
|
|
37
37
|
offset: Optional[Union[float, str]] = Field(None, title="Offset")
|
38
38
|
flipped: Optional[bool] = Field(None, title="Flipped")
|
39
39
|
actuator_type: Optional[str] = Field(None, title="Actuator Type")
|
40
|
-
nn_id: Optional[int] = Field(None, title="
|
41
|
-
soft_torque_limit: Optional[str] = Field(None, title="Soft Torque Limit")
|
40
|
+
nn_id: Optional[int] = Field(None, title="Nn Id")
|
41
|
+
soft_torque_limit: Optional[Union[float, str]] = Field(None, title="Soft Torque Limit")
|
42
42
|
|
43
43
|
|
44
44
|
class JointMetadataOutput(BaseModel):
|
@@ -50,6 +50,8 @@ class JointMetadataOutput(BaseModel):
|
|
50
50
|
offset: Optional[str] = Field(None, title="Offset")
|
51
51
|
flipped: Optional[bool] = Field(None, title="Flipped")
|
52
52
|
actuator_type: Optional[str] = Field(None, title="Actuator Type")
|
53
|
+
nn_id: Optional[int] = Field(None, title="Nn Id")
|
54
|
+
soft_torque_limit: Optional[str] = Field(None, title="Soft Torque Limit")
|
53
55
|
|
54
56
|
|
55
57
|
class OICDInfo(BaseModel):
|
@@ -139,3 +141,4 @@ class RobotClass(BaseModel):
|
|
139
141
|
description: str = Field(..., title="Description")
|
140
142
|
user_id: str = Field(..., title="User Id")
|
141
143
|
metadata: Optional[RobotURDFMetadataOutput] = None
|
144
|
+
num_downloads: Optional[int] = Field(0, title="Num Downloads")
|
@@ -1,4 +1,4 @@
|
|
1
|
-
kscale/__init__.py,sha256=
|
1
|
+
kscale/__init__.py,sha256=dvs5DUTbLSWgAycehACzl60WVsJdFN7yCMHoTvxFI38,201
|
2
2
|
kscale/cli.py,sha256=JvaPtmWvF7s0D4I3K98eZAItf3oOi2ULsn5aPGxDcu4,795
|
3
3
|
kscale/conf.py,sha256=dm35XSnzJp93St-ixVtYN4Nvqvb5upPGBrWkSI6Yb-4,1743
|
4
4
|
kscale/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -15,19 +15,19 @@ 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=
|
18
|
+
kscale/web/cli/robot_class.py,sha256=Gzg1NTD1iDf04jPVRz_fCKVAjnQ3pmA7dB3KmUjxXwk,19080
|
19
19
|
kscale/web/cli/user.py,sha256=9IGsJBPyhjsmT04mZ2RGOs35ePfqB2RltYP0Ty5zF5o,1290
|
20
20
|
kscale/web/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
|
-
kscale/web/clients/base.py,sha256=
|
21
|
+
kscale/web/clients/base.py,sha256=P5AZdoawNpocgx_8j5v0eauowG5suUf8SnnD7q1_gx0,16213
|
22
22
|
kscale/web/clients/client.py,sha256=rzW2s8T7bKVuybOSQ65-ghl02rcXBoOxnx_nUDwgEPw,362
|
23
23
|
kscale/web/clients/robot.py,sha256=PI8HHkU-4Re9I5rLpp6dGbekRE-rBNVfXZxR_mO2MqE,1485
|
24
|
-
kscale/web/clients/robot_class.py,sha256=
|
24
|
+
kscale/web/clients/robot_class.py,sha256=mgA-95P8lR0eCIF7-9f7oPE5tQ8tYLOIU7a83dFiqCs,6970
|
25
25
|
kscale/web/clients/user.py,sha256=jsa1_s6qXRM-AGBbHlPhd1NierUtynjY9tVAPNr6_Os,568
|
26
26
|
kscale/web/gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
|
-
kscale/web/gen/api.py,sha256=
|
28
|
-
kscale-0.3.
|
29
|
-
kscale-0.3.
|
30
|
-
kscale-0.3.
|
31
|
-
kscale-0.3.
|
32
|
-
kscale-0.3.
|
33
|
-
kscale-0.3.
|
27
|
+
kscale/web/gen/api.py,sha256=VSTHOLFtsjH_9mGYChW0iDbtX5FlLU8Itz5MzDb4maE,5147
|
28
|
+
kscale-0.3.12.dist-info/licenses/LICENSE,sha256=HCN2bImAzUOXldAZZI7JZ9PYq6OwMlDAP_PpX1HnuN0,1071
|
29
|
+
kscale-0.3.12.dist-info/METADATA,sha256=Pqgb5F9FCKrg6aoVgzHzmqKTT229TOMWOBqOa1e9SfM,2343
|
30
|
+
kscale-0.3.12.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
|
31
|
+
kscale-0.3.12.dist-info/entry_points.txt,sha256=N_0pCpPnwGDYVzOeuaSOrbJkS5L3lS9d8CxpJF1f8UI,62
|
32
|
+
kscale-0.3.12.dist-info/top_level.txt,sha256=C2ynjYwopg6YjgttnI2dJjasyq3EKNmYp-IfQg9Xms4,7
|
33
|
+
kscale-0.3.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|