kscale 0.1.5__py3-none-any.whl → 0.2.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- kscale/__init__.py +2 -2
- kscale/web/cli/robot_class.py +1 -1
- kscale/web/clients/client.py +4 -0
- kscale/web/clients/robot_class.py +37 -6
- {kscale-0.1.5.dist-info → kscale-0.2.1.dist-info}/METADATA +1 -1
- {kscale-0.1.5.dist-info → kscale-0.2.1.dist-info}/RECORD +10 -12
- kscale/api.py +0 -11
- kscale/web/api.py +0 -18
- {kscale-0.1.5.dist-info → kscale-0.2.1.dist-info}/LICENSE +0 -0
- {kscale-0.1.5.dist-info → kscale-0.2.1.dist-info}/WHEEL +0 -0
- {kscale-0.1.5.dist-info → kscale-0.2.1.dist-info}/entry_points.txt +0 -0
- {kscale-0.1.5.dist-info → kscale-0.2.1.dist-info}/top_level.txt +0 -0
kscale/__init__.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
"""Defines the common interface for the K-Scale Python API."""
|
2
2
|
|
3
|
-
__version__ = "0.1
|
3
|
+
__version__ = "0.2.1"
|
4
4
|
|
5
5
|
from pathlib import Path
|
6
6
|
|
7
|
-
from kscale.
|
7
|
+
from kscale.web.clients.client import WWWClient as K
|
8
8
|
|
9
9
|
ROOT_DIR = Path(__file__).parent
|
kscale/web/cli/robot_class.py
CHANGED
@@ -105,7 +105,7 @@ async def upload(class_name: str, urdf_file: str) -> None:
|
|
105
105
|
async def download(class_name: str, no_cache: bool) -> None:
|
106
106
|
"""Downloads a URDF file from a robot class."""
|
107
107
|
async with RobotClassClient() as client:
|
108
|
-
urdf_file = await client.
|
108
|
+
urdf_file = await client.download_compressed_urdf(class_name, cache=not no_cache)
|
109
109
|
click.echo(f"URDF downloaded: {click.style(urdf_file, fg='green')}")
|
110
110
|
|
111
111
|
|
kscale/web/clients/client.py
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
"""Defines a unified client for the K-Scale WWW API."""
|
2
2
|
|
3
3
|
from kscale.web.clients.base import BaseClient
|
4
|
+
from kscale.web.clients.robot import RobotClient
|
5
|
+
from kscale.web.clients.robot_class import RobotClassClient
|
4
6
|
from kscale.web.clients.user import UserClient
|
5
7
|
|
6
8
|
|
7
9
|
class WWWClient(
|
10
|
+
RobotClient,
|
11
|
+
RobotClassClient,
|
8
12
|
UserClient,
|
9
13
|
BaseClient,
|
10
14
|
):
|
@@ -21,6 +21,8 @@ logger = logging.getLogger(__name__)
|
|
21
21
|
UPLOAD_TIMEOUT = 300.0
|
22
22
|
DOWNLOAD_TIMEOUT = 60.0
|
23
23
|
|
24
|
+
INFO_FILE_NAME = ".info.json"
|
25
|
+
|
24
26
|
|
25
27
|
class RobotClassClient(BaseClient):
|
26
28
|
async def get_robot_classes(self) -> list[RobotClass]:
|
@@ -98,7 +100,7 @@ class RobotClassClient(BaseClient):
|
|
98
100
|
r.raise_for_status()
|
99
101
|
return response
|
100
102
|
|
101
|
-
async def
|
103
|
+
async def download_compressed_urdf(self, class_name: str, *, cache: bool = True) -> Path:
|
102
104
|
cache_path = get_robots_dir() / class_name / "robot.tgz"
|
103
105
|
if cache and cache_path.exists() and not should_refresh_file(cache_path):
|
104
106
|
return cache_path
|
@@ -108,7 +110,7 @@ class RobotClassClient(BaseClient):
|
|
108
110
|
cache_path.parent.mkdir(parents=True, exist_ok=True)
|
109
111
|
|
110
112
|
# Checks the md5 hash of the file.
|
111
|
-
cache_path_info = cache_path.parent /
|
113
|
+
cache_path_info = cache_path.parent / INFO_FILE_NAME
|
112
114
|
if cache_path_info.exists():
|
113
115
|
with open(cache_path_info, "r") as f:
|
114
116
|
info = json.load(f)
|
@@ -133,13 +135,42 @@ class RobotClassClient(BaseClient):
|
|
133
135
|
if hash_value_hex != expected_hash:
|
134
136
|
raise ValueError(f"MD5 hash mismatch: {hash_value_hex} != {expected_hash}")
|
135
137
|
|
136
|
-
logger.info("Unpacking downloaded file")
|
137
|
-
with tarfile.open(cache_path, "r:gz") as tar:
|
138
|
-
tar.extractall(path=cache_path.parent)
|
139
|
-
|
140
138
|
logger.info("Updating downloaded file information")
|
141
139
|
info = {"md5_hash": hash_value_hex}
|
142
140
|
with open(cache_path_info, "w") as f:
|
143
141
|
json.dump(info, f)
|
144
142
|
|
145
143
|
return cache_path
|
144
|
+
|
145
|
+
async def download_and_extract_urdf(self, class_name: str, *, cache: bool = True) -> Path:
|
146
|
+
cache_path = await self.download_compressed_urdf(class_name, cache=cache)
|
147
|
+
|
148
|
+
# Reads the MD5 hash from the info file.
|
149
|
+
cache_path_info = cache_path.parent / INFO_FILE_NAME
|
150
|
+
with open(cache_path_info, "r") as f:
|
151
|
+
info = json.load(f)
|
152
|
+
expected_hash = info["md5_hash"]
|
153
|
+
|
154
|
+
# Unpacks the file if requested.
|
155
|
+
unpack_path = cache_path.parent / "robot"
|
156
|
+
unpack_path.mkdir(parents=True, exist_ok=True)
|
157
|
+
unpacked_path_info = unpack_path / INFO_FILE_NAME
|
158
|
+
|
159
|
+
# If the file has already been unpacked, return the path.
|
160
|
+
if unpacked_path_info.exists():
|
161
|
+
with open(unpacked_path_info, "r") as f:
|
162
|
+
info = json.load(f)
|
163
|
+
if info["md5_hash"] == expected_hash:
|
164
|
+
unpack_path.touch()
|
165
|
+
return unpack_path
|
166
|
+
|
167
|
+
logger.info("Unpacking URDF file")
|
168
|
+
with tarfile.open(cache_path, "r:gz") as tar:
|
169
|
+
tar.extractall(path=unpack_path)
|
170
|
+
|
171
|
+
logger.info("Updating downloaded file information")
|
172
|
+
info = {"md5_hash": expected_hash}
|
173
|
+
with open(unpacked_path_info, "w") as f:
|
174
|
+
json.dump(info, f)
|
175
|
+
|
176
|
+
return unpack_path
|
@@ -1,5 +1,4 @@
|
|
1
|
-
kscale/__init__.py,sha256=
|
2
|
-
kscale/api.py,sha256=jmiuFurTN_Gj_-k-6asqxw8wp-_bgJUXgMPFgJ4lqHA,230
|
1
|
+
kscale/__init__.py,sha256=73uaPK_Lj05TFJYmYf9BjFp9JHB5XKLlMIwORoDZpx0,200
|
3
2
|
kscale/cli.py,sha256=PMHLKR5UwdbbReVmqHXpJ-K9-mGHv_0I7KQkwxmFcUA,881
|
4
3
|
kscale/conf.py,sha256=OLGz2J-9NAaICoWeN9-hCxrOsyf0vpJBNw-UzIsHdwE,1572
|
5
4
|
kscale/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -13,24 +12,23 @@ kscale/utils/api_base.py,sha256=Kk_WtRDdJHmOg6NtHmVxVrcfARSUkhfr29ypLch_pO0,112
|
|
13
12
|
kscale/utils/checksum.py,sha256=jt6QmmQND9zrOEnUtOfZpLYROhgto4Gh3OpdUWk4tZA,1093
|
14
13
|
kscale/utils/cli.py,sha256=JoaY5x5SdUx97KmMM9j5AjRRUqqrTlJ9qVckZptEsYA,827
|
15
14
|
kscale/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
-
kscale/web/api.py,sha256=oyW0XLfX96RPe1xNgdf8ejfATdLlNlP0CL1lP0FN1nM,593
|
17
15
|
kscale/web/utils.py,sha256=Mme-FAQ0_zbjjOQeX8wyq8F4kL4i9fH7ytri16U6qOA,1046
|
18
16
|
kscale/web/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
17
|
kscale/web/cli/robot.py,sha256=rI-A4_0uvJPeA71Apl4Z3mV5fIfWkgmzT9JRmJYxz3A,3307
|
20
|
-
kscale/web/cli/robot_class.py,sha256=
|
18
|
+
kscale/web/cli/robot_class.py,sha256=8igY6oWUDafb644QzmqC5cX6Az0rNJau_jvLr7YkCd0,3573
|
21
19
|
kscale/web/cli/token.py,sha256=1rFC8MYKtqbNsQa2KIqwW1tqpaMtFaxuNsallwejXTU,787
|
22
20
|
kscale/web/cli/user.py,sha256=aaJJCL1P5lfhK6ZC9OwOHXKA-I3MWqVZ_k7TYnx33CY,1303
|
23
21
|
kscale/web/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
22
|
kscale/web/clients/base.py,sha256=uovIxtkotRxrIFL0PhLYDIhhfXrIGjXxNY2FLVO3L18,15110
|
25
|
-
kscale/web/clients/client.py,sha256=
|
23
|
+
kscale/web/clients/client.py,sha256=rzW2s8T7bKVuybOSQ65-ghl02rcXBoOxnx_nUDwgEPw,362
|
26
24
|
kscale/web/clients/robot.py,sha256=HMfJnkDxaJ_o7X2vdYYS9iob1JRoBG2qiGmQpCQZpAk,1485
|
27
|
-
kscale/web/clients/robot_class.py,sha256=
|
25
|
+
kscale/web/clients/robot_class.py,sha256=zCFL-Y_jIfO9_qOwzBAHzfgFxzpltMte4LM5haCC24U,6385
|
28
26
|
kscale/web/clients/user.py,sha256=jsa1_s6qXRM-AGBbHlPhd1NierUtynjY9tVAPNr6_Os,568
|
29
27
|
kscale/web/gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
28
|
kscale/web/gen/api.py,sha256=SovcII36JFgK9jd2CXlLPMjiUROGB4vEnapOsYMUrkU,2188
|
31
|
-
kscale-0.1.
|
32
|
-
kscale-0.1.
|
33
|
-
kscale-0.1.
|
34
|
-
kscale-0.1.
|
35
|
-
kscale-0.1.
|
36
|
-
kscale-0.1.
|
29
|
+
kscale-0.2.1.dist-info/LICENSE,sha256=HCN2bImAzUOXldAZZI7JZ9PYq6OwMlDAP_PpX1HnuN0,1071
|
30
|
+
kscale-0.2.1.dist-info/METADATA,sha256=IeSxq7ApAKrn48Xep-kRu-wQpOq14y_M3GbUgcpHbJE,2340
|
31
|
+
kscale-0.2.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
32
|
+
kscale-0.2.1.dist-info/entry_points.txt,sha256=N_0pCpPnwGDYVzOeuaSOrbJkS5L3lS9d8CxpJF1f8UI,62
|
33
|
+
kscale-0.2.1.dist-info/top_level.txt,sha256=C2ynjYwopg6YjgttnI2dJjasyq3EKNmYp-IfQg9Xms4,7
|
34
|
+
kscale-0.2.1.dist-info/RECORD,,
|
kscale/api.py
DELETED
kscale/web/api.py
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
"""Defines a common interface for the K-Scale WWW API."""
|
2
|
-
|
3
|
-
from kscale.utils.api_base import APIBase
|
4
|
-
from kscale.web.clients.client import WWWClient
|
5
|
-
from kscale.web.gen.api import ProfileResponse
|
6
|
-
|
7
|
-
|
8
|
-
class WebAPI(APIBase):
|
9
|
-
async def www_client(self) -> WWWClient:
|
10
|
-
return WWWClient()
|
11
|
-
|
12
|
-
async def get_profile_info(self) -> ProfileResponse:
|
13
|
-
client = await self.www_client()
|
14
|
-
return await client.get_profile_info()
|
15
|
-
|
16
|
-
async def get_api_key(self, num_hours: int = 24) -> str:
|
17
|
-
client = await self.www_client()
|
18
|
-
return await client.get_api_key(num_hours)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|