kscale 0.0.11__py3-none-any.whl → 0.1.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: kscale
3
- Version: 0.0.11
3
+ Version: 0.1.0
4
4
  Summary: The kscale project
5
5
  Home-page: https://github.com/kscalelabs/kscale
6
6
  Author: Benjamin Bolte
@@ -8,23 +8,35 @@ Requires-Python: >=3.11
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
10
  Requires-Dist: omegaconf
11
- Requires-Dist: email-validator
11
+ Requires-Dist: email_validator
12
+ Requires-Dist: colorlogging
13
+ Requires-Dist: aiohttp
14
+ Requires-Dist: cryptography
12
15
  Requires-Dist: httpx
13
- Requires-Dist: requests
14
16
  Requires-Dist: pydantic
17
+ Requires-Dist: pyjwt
18
+ Requires-Dist: requests
19
+ Requires-Dist: yarl
20
+ Requires-Dist: aiofiles
21
+ Requires-Dist: click
22
+ Requires-Dist: tabulate
23
+ Requires-Dist: async-lru
24
+ Requires-Dist: krec
15
25
  Provides-Extra: dev
16
- Requires-Dist: black ; extra == 'dev'
17
- Requires-Dist: darglint ; extra == 'dev'
18
- Requires-Dist: mypy ; extra == 'dev'
19
- Requires-Dist: pytest ; extra == 'dev'
20
- Requires-Dist: ruff ; extra == 'dev'
21
- Requires-Dist: datamodel-code-generator ; extra == 'dev'
22
-
23
- <p align="center">
24
- <picture>
25
- <img alt="K-Scale Open Source Robotics" src="https://media.kscale.dev/kscale-open-source-header.png" style="max-width: 100%;">
26
- </picture>
27
- </p>
26
+ Requires-Dist: black; extra == "dev"
27
+ Requires-Dist: darglint; extra == "dev"
28
+ Requires-Dist: mypy; extra == "dev"
29
+ Requires-Dist: pytest; extra == "dev"
30
+ Requires-Dist: ruff; extra == "dev"
31
+ Requires-Dist: datamodel-code-generator; extra == "dev"
32
+ Dynamic: author
33
+ Dynamic: description
34
+ Dynamic: description-content-type
35
+ Dynamic: home-page
36
+ Dynamic: provides-extra
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
28
40
 
29
41
  <div align="center">
30
42
 
@@ -43,41 +55,10 @@ Requires-Dist: datamodel-code-generator ; extra == 'dev'
43
55
 
44
56
  # K-Scale Command Line Interface
45
57
 
46
- This is a command line tool for interacting with various services provided by K-Scale Labs, such as:
47
-
48
- - [K-Scale Store](https://kscale.store/)
58
+ This is a command line tool for interacting with various services provided by K-Scale Labs. For more information, see the [documentation](https://docs.kscale.dev/pkg/intro).
49
59
 
50
60
  ## Installation
51
61
 
52
62
  ```bash
53
63
  pip install kscale
54
64
  ```
55
-
56
- ## Usage
57
-
58
- ### CLI
59
-
60
- Download a URDF from the K-Scale Store:
61
-
62
- ```bash
63
- kscale urdf download <artifact_id>
64
- ```
65
-
66
- Upload a URDF to the K-Scale Store:
67
-
68
- ```bash
69
- kscale urdf upload <artifact_id> <root_dir>
70
- ```
71
-
72
- ### Python API
73
-
74
- Reference a URDF by ID from the K-Scale Store:
75
-
76
- ```python
77
- from kscale import KScale
78
-
79
- async def main():
80
- kscale = KScale()
81
- urdf_dir_path = await kscale.store.urdf("123456")
82
- print(urdf_dir_path)
83
- ```
@@ -0,0 +1,36 @@
1
+ kscale/__init__.py,sha256=2jGtLxds4EdX8FEGT3yA74b0VgrkOEBx_PxiWvoh924,172
2
+ kscale/api.py,sha256=jmiuFurTN_Gj_-k-6asqxw8wp-_bgJUXgMPFgJ4lqHA,230
3
+ kscale/cli.py,sha256=PMHLKR5UwdbbReVmqHXpJ-K9-mGHv_0I7KQkwxmFcUA,881
4
+ kscale/conf.py,sha256=i5gDTs8D73l2OvX4pOlPWtT2PC26MmoKw3PPwf8HM7U,1526
5
+ kscale/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ kscale/requirements-dev.txt,sha256=WI7-ea4IRJakmqVMN8QKhOsDGrghwtvk03aIsFaNSIw,130
7
+ kscale/requirements.txt,sha256=lKDpyebp9nHZ2uHIuS6FQ6SAg7YO_0sDyb67MFmP4h4,214
8
+ kscale/artifacts/__init__.py,sha256=RK8wdybtCJPgdLLJ8R8-YMi1Ph5ojqAKVJZowHONtgo,232
9
+ kscale/artifacts/plane.obj,sha256=x59-IIrWpLjhotChiqT2Ul6U8s0RcHkaEeUZb4KXL1c,348
10
+ kscale/artifacts/plane.urdf,sha256=LCiTk14AyTHjkZ1jvsb0hNaEaJUxDb8Z1JjsgpXu3YM,819
11
+ kscale/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ kscale/utils/api_base.py,sha256=Kk_WtRDdJHmOg6NtHmVxVrcfARSUkhfr29ypLch_pO0,112
13
+ kscale/utils/checksum.py,sha256=jt6QmmQND9zrOEnUtOfZpLYROhgto4Gh3OpdUWk4tZA,1093
14
+ kscale/utils/cli.py,sha256=JoaY5x5SdUx97KmMM9j5AjRRUqqrTlJ9qVckZptEsYA,827
15
+ kscale/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ kscale/web/api.py,sha256=YioIdruq7LCKSBf9SvOGkv914W36_zBmpTzsJqKc0wE,439
17
+ kscale/web/utils.py,sha256=KFB9lrgn_2BRY38Sfbb_QOKZ8fWyINqIqLPwN0rjbyk,806
18
+ kscale/web/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ kscale/web/cli/robot.py,sha256=rI-A4_0uvJPeA71Apl4Z3mV5fIfWkgmzT9JRmJYxz3A,3307
20
+ kscale/web/cli/robot_class.py,sha256=ymC5phUqofvOXv5P6f51b9lMK5eRDaavvnzS0x9rDbU,3574
21
+ kscale/web/cli/token.py,sha256=1rFC8MYKtqbNsQa2KIqwW1tqpaMtFaxuNsallwejXTU,787
22
+ kscale/web/cli/user.py,sha256=qO0z2K5uA48hEiOOYEzv6BO2nOlCpITTDZFuiNl6d34,817
23
+ kscale/web/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ kscale/web/clients/base.py,sha256=NRqRH2JTXjJLUMDM93txKgwFu9bQRYhCYLYy7vE76Ik,11462
25
+ kscale/web/clients/client.py,sha256=QjBicdHQYNoUG9XRjAYmGu3THae9DzWa_hQox3OO1Gw,214
26
+ kscale/web/clients/robot.py,sha256=HMfJnkDxaJ_o7X2vdYYS9iob1JRoBG2qiGmQpCQZpAk,1485
27
+ kscale/web/clients/robot_class.py,sha256=yC0G4pVPDoEskf0QfQLxejyDgHLT8gR1RLJ8ioCGoOM,4236
28
+ kscale/web/clients/user.py,sha256=9iv8J-ROm_yBIwi-0oqldReLkNBFktdHRv3UCOxBzjY,377
29
+ kscale/web/gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ kscale/web/gen/api.py,sha256=SovcII36JFgK9jd2CXlLPMjiUROGB4vEnapOsYMUrkU,2188
31
+ kscale-0.1.0.dist-info/LICENSE,sha256=HCN2bImAzUOXldAZZI7JZ9PYq6OwMlDAP_PpX1HnuN0,1071
32
+ kscale-0.1.0.dist-info/METADATA,sha256=EBGeAHNhtgjRQ38M_3n_mQ1LFlaogmA3qgUsVa45zEA,2340
33
+ kscale-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
34
+ kscale-0.1.0.dist-info/entry_points.txt,sha256=N_0pCpPnwGDYVzOeuaSOrbJkS5L3lS9d8CxpJF1f8UI,62
35
+ kscale-0.1.0.dist-info/top_level.txt,sha256=C2ynjYwopg6YjgttnI2dJjasyq3EKNmYp-IfQg9Xms4,7
36
+ kscale-0.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ ks = kscale.cli:cli
3
+ kscale = kscale.cli:cli
kscale/store/api.py DELETED
@@ -1,64 +0,0 @@
1
- """Defines a common interface for the K-Scale Store API."""
2
-
3
- from pathlib import Path
4
- from typing import overload
5
-
6
- from kscale.store.gen.api import UploadArtifactResponse
7
- from kscale.store.urdf import download_urdf, upload_urdf
8
- from kscale.utils.api_base import APIBase
9
-
10
-
11
- class StoreAPI(APIBase):
12
- def __init__(
13
- self,
14
- *,
15
- api_key: str | None = None,
16
- ) -> None:
17
- super().__init__()
18
-
19
- self.api_key = api_key
20
-
21
- async def artifact_root(self, artifact_id: str) -> Path:
22
- return await download_urdf(artifact_id)
23
-
24
- @overload
25
- async def urdf_path(self, artifact_id: str) -> Path: ...
26
-
27
- @overload
28
- async def urdf_path(self, artifact_id: str, *, throw_if_missing: bool = True) -> Path | None: ...
29
-
30
- async def urdf_path(self, artifact_id: str, *, throw_if_missing: bool = True) -> Path | None:
31
- root_dir = await self.artifact_root(artifact_id)
32
- urdf_path = next(root_dir.glob("*.urdf"), None)
33
- if urdf_path is None and throw_if_missing:
34
- raise FileNotFoundError(f"No URDF found for artifact {artifact_id}")
35
- return urdf_path
36
-
37
- @overload
38
- async def mjcf_path(self, artifact_id: str) -> Path: ...
39
-
40
- @overload
41
- async def mjcf_path(self, artifact_id: str, *, throw_if_missing: bool = True) -> Path | None: ...
42
-
43
- async def mjcf_path(self, artifact_id: str, *, throw_if_missing: bool = True) -> Path | None:
44
- root_dir = await self.artifact_root(artifact_id)
45
- mjcf_path = next(root_dir.glob("*.mjcf"), None)
46
- if mjcf_path is None and throw_if_missing:
47
- raise FileNotFoundError(f"No MJCF found for artifact {artifact_id}")
48
- return mjcf_path
49
-
50
- @overload
51
- async def xml_path(self, artifact_id: str) -> Path: ...
52
-
53
- @overload
54
- async def xml_path(self, artifact_id: str, *, throw_if_missing: bool = True) -> Path | None: ...
55
-
56
- async def xml_path(self, artifact_id: str, *, throw_if_missing: bool = True) -> Path | None:
57
- root_dir = await self.artifact_root(artifact_id)
58
- xml_path = next(root_dir.glob("*.xml"), None)
59
- if xml_path is None and throw_if_missing:
60
- raise FileNotFoundError(f"No XML found for artifact {artifact_id}")
61
- return xml_path
62
-
63
- async def upload_urdf(self, listing_id: str, root_dir: Path) -> UploadArtifactResponse:
64
- return await upload_urdf(listing_id, root_dir)
kscale/store/cli.py DELETED
@@ -1,35 +0,0 @@
1
- """Defines the top-level KOL CLI."""
2
-
3
- import argparse
4
- import asyncio
5
- from typing import Sequence
6
-
7
- from kscale.store import pybullet, urdf
8
-
9
-
10
- async def main(args: Sequence[str] | None = None) -> None:
11
- parser = argparse.ArgumentParser(description="K-Scale OnShape Library", add_help=False)
12
- parser.add_argument(
13
- "subcommand",
14
- choices=[
15
- "urdf",
16
- "pybullet",
17
- ],
18
- help="The subcommand to run",
19
- )
20
- parsed_args, remaining_args = parser.parse_known_args(args)
21
-
22
- match parsed_args.subcommand:
23
- case "urdf":
24
- await urdf.main(remaining_args)
25
- case "pybullet":
26
- await pybullet.main(remaining_args)
27
-
28
-
29
- def sync_main(args: Sequence[str] | None = None) -> None:
30
- asyncio.run(main(args))
31
-
32
-
33
- if __name__ == "__main__":
34
- # python3 -m kscale.store.cli
35
- sync_main()
kscale/store/client.py DELETED
@@ -1,82 +0,0 @@
1
- """Defines a typed client for the K-Scale Store API."""
2
-
3
- import logging
4
- from pathlib import Path
5
- from types import TracebackType
6
- from typing import Any, Dict, Type
7
- from urllib.parse import urljoin
8
-
9
- import httpx
10
- from pydantic import BaseModel
11
-
12
- from kscale.store.gen.api import (
13
- NewListingRequest,
14
- NewListingResponse,
15
- SingleArtifactResponse,
16
- UploadArtifactResponse,
17
- )
18
- from kscale.store.utils import get_api_key, get_api_root
19
-
20
- logger = logging.getLogger(__name__)
21
-
22
-
23
- class KScaleStoreClient:
24
- def __init__(self, base_url: str = get_api_root()) -> None:
25
- self.base_url = base_url
26
- self.client = httpx.AsyncClient(
27
- base_url=self.base_url,
28
- headers={"Authorization": f"Bearer {get_api_key()}"},
29
- timeout=httpx.Timeout(30.0),
30
- )
31
-
32
- async def _request(
33
- self,
34
- method: str,
35
- endpoint: str,
36
- *,
37
- params: Dict[str, Any] | None = None,
38
- data: BaseModel | None = None,
39
- files: Dict[str, Any] | None = None,
40
- ) -> Dict[str, Any]:
41
- url = urljoin(self.base_url, endpoint)
42
- kwargs: Dict[str, Any] = {"params": params}
43
-
44
- if data:
45
- kwargs["json"] = data.dict(exclude_unset=True)
46
- if files:
47
- kwargs["files"] = files
48
-
49
- response = await self.client.request(method, url, **kwargs)
50
- if response.is_error:
51
- logger.error(f"Error response from K-Scale Store: {response.text}")
52
- response.raise_for_status()
53
- return response.json()
54
-
55
- async def get_artifact_info(self, artifact_id: str) -> SingleArtifactResponse:
56
- data = await self._request("GET", f"/artifacts/info/{artifact_id}")
57
- return SingleArtifactResponse(**data)
58
-
59
- async def upload_artifact(self, listing_id: str, file_path: str) -> UploadArtifactResponse:
60
- file_name = Path(file_path).name
61
- with open(file_path, "rb") as f:
62
- files = {"files": (file_name, f, "application/gzip")}
63
- data = await self._request("POST", f"/artifacts/upload/{listing_id}", files=files)
64
- return UploadArtifactResponse(**data)
65
-
66
- async def create_listing(self, request: NewListingRequest) -> NewListingResponse:
67
- data = await self._request("POST", "/listings", data=request)
68
- return NewListingResponse(**data)
69
-
70
- async def close(self) -> None:
71
- await self.client.aclose()
72
-
73
- async def __aenter__(self) -> "KScaleStoreClient":
74
- return self
75
-
76
- async def __aexit__(
77
- self,
78
- exc_type: Type[BaseException] | None,
79
- exc_val: BaseException | None,
80
- exc_tb: TracebackType | None,
81
- ) -> None:
82
- await self.close()