wherobots-python-sdk 0.6.0__py3-none-any.whl → 0.7.0__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.
- wherobots/__version__.py +1 -1
- wherobots/api/base.py +15 -7
- wherobots/api/drive.py +1 -1
- wherobots/api/files.py +8 -1
- wherobots/api/workload_auth.py +116 -0
- wherobots/config.py +12 -2
- wherobots/exceptions.py +1 -1
- {wherobots_python_sdk-0.6.0.dist-info → wherobots_python_sdk-0.7.0.dist-info}/METADATA +14 -5
- {wherobots_python_sdk-0.6.0.dist-info → wherobots_python_sdk-0.7.0.dist-info}/RECORD +12 -11
- {wherobots_python_sdk-0.6.0.dist-info → wherobots_python_sdk-0.7.0.dist-info}/WHEEL +0 -0
- {wherobots_python_sdk-0.6.0.dist-info → wherobots_python_sdk-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {wherobots_python_sdk-0.6.0.dist-info → wherobots_python_sdk-0.7.0.dist-info}/top_level.txt +0 -0
wherobots/__version__.py
CHANGED
wherobots/api/base.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""Low-level HTTP client for the Wherobots REST API.
|
|
2
2
|
|
|
3
3
|
``BaseClient`` wraps a ``requests.Session`` with:
|
|
4
|
-
* Auth
|
|
4
|
+
* Auth: ``X-API-Key`` when an API key is configured, otherwise the
|
|
5
|
+
workload-identity token mounted in Wherobots notebook and job pods.
|
|
5
6
|
* Client attribution via the advisory ``X-Wherobots-Client`` header,
|
|
6
7
|
set once on the session so every outgoing request carries it.
|
|
7
8
|
* Automatic retry with exponential back-off for transient errors
|
|
@@ -20,6 +21,7 @@ from requests.adapters import HTTPAdapter
|
|
|
20
21
|
from urllib3.util.retry import Retry
|
|
21
22
|
|
|
22
23
|
from wherobots.__version__ import __version__
|
|
24
|
+
from wherobots.api.workload_auth import shared_workload_identity_auth
|
|
23
25
|
from wherobots.config import WherobotsConfig # noqa: TC001
|
|
24
26
|
from wherobots.exceptions import WherobotsAPIError, WherobotsConfigError
|
|
25
27
|
from wherobots.utils.client_header import CLIENT_HEADER, client_header_value
|
|
@@ -57,8 +59,8 @@ class BaseClient:
|
|
|
57
59
|
back-off, and unified error mapping to ``WherobotsAPIError``.
|
|
58
60
|
|
|
59
61
|
Args:
|
|
60
|
-
config: A populated ``WherobotsConfig``. Must contain
|
|
61
|
-
``api_key``
|
|
62
|
+
config: A populated ``WherobotsConfig``. Must contain ``base_url``
|
|
63
|
+
and either ``api_key`` or ``id_token_path``.
|
|
62
64
|
max_retries: Maximum number of retries for transient failures.
|
|
63
65
|
backoff_factor: Multiplier for exponential back-off between
|
|
64
66
|
retries.
|
|
@@ -75,10 +77,11 @@ class BaseClient:
|
|
|
75
77
|
# session is built.
|
|
76
78
|
self._closed = False
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
api_key = (config.api_key or "").strip()
|
|
81
|
+
if not api_key and not config.id_token_path:
|
|
79
82
|
raise WherobotsConfigError(
|
|
80
|
-
"
|
|
81
|
-
"WHEROBOTS_API_KEY
|
|
83
|
+
"No Wherobots credentials found. Provide the api_key parameter, set "
|
|
84
|
+
"WHEROBOTS_API_KEY, or run inside a Wherobots notebook or job."
|
|
82
85
|
)
|
|
83
86
|
|
|
84
87
|
self._config = config
|
|
@@ -122,9 +125,14 @@ class BaseClient:
|
|
|
122
125
|
"Content-Type": "application/json",
|
|
123
126
|
"User-Agent": f"wherobots-python-sdk/{__version__}",
|
|
124
127
|
CLIENT_HEADER: client_header_value(config.client_chain),
|
|
125
|
-
**self._auth_headers(config.api_key),
|
|
126
128
|
}
|
|
127
129
|
)
|
|
130
|
+
if api_key:
|
|
131
|
+
self._session.headers.update(self._auth_headers(api_key))
|
|
132
|
+
elif config.id_token_path:
|
|
133
|
+
self._session.auth = shared_workload_identity_auth(
|
|
134
|
+
self._base_url, config.id_token_path, self._timeout
|
|
135
|
+
)
|
|
128
136
|
|
|
129
137
|
@property
|
|
130
138
|
def timeout(self) -> int:
|
wherobots/api/drive.py
CHANGED
|
@@ -336,7 +336,7 @@ class FilesDrive:
|
|
|
336
336
|
"""
|
|
337
337
|
if err.status_code == _HTTP_UNAUTHORIZED:
|
|
338
338
|
return WherobotsNotAuthenticatedError(
|
|
339
|
-
"The Wherobots API
|
|
339
|
+
"The Wherobots API did not accept the credentials (HTTP 401)",
|
|
340
340
|
status_code=err.status_code,
|
|
341
341
|
response=err.response,
|
|
342
342
|
request_id=err.request_id,
|
wherobots/api/files.py
CHANGED
|
@@ -29,7 +29,11 @@ from botocore.session import Session as BotocoreSession
|
|
|
29
29
|
|
|
30
30
|
from wherobots.api.base import BaseClient
|
|
31
31
|
from wherobots.config import WherobotsConfig # noqa: TC001
|
|
32
|
-
from wherobots.exceptions import
|
|
32
|
+
from wherobots.exceptions import (
|
|
33
|
+
WherobotsAPIError,
|
|
34
|
+
WherobotsNotAuthenticatedError,
|
|
35
|
+
WherobotsValidationError,
|
|
36
|
+
)
|
|
33
37
|
from wherobots.models import StorageIntegration, TemporaryAwsCredentials
|
|
34
38
|
from wherobots.utils.logger import get_logger
|
|
35
39
|
|
|
@@ -110,6 +114,9 @@ class FilesAPI:
|
|
|
110
114
|
"/storage/credentials",
|
|
111
115
|
json_body={"path": path, "access_mode": access_mode},
|
|
112
116
|
)
|
|
117
|
+
except WherobotsNotAuthenticatedError:
|
|
118
|
+
# The workload token exchange failed before this request was sent (ADR-0003).
|
|
119
|
+
raise
|
|
113
120
|
except WherobotsAPIError as exc:
|
|
114
121
|
# Scrub: never let the credentials endpoint's error
|
|
115
122
|
# response body bubble out — it could contain partial
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Workload-identity auth for code running inside Wherobots (ADR-0003).
|
|
2
|
+
|
|
3
|
+
Wherobots notebook and job pods mount a workload-identity token and set
|
|
4
|
+
``WHEROBOTS_ID_TOKEN_PATH`` to it. The API accepts that token as an OAuth
|
|
5
|
+
refresh token at ``/ste/oauth2/token`` and returns a short-lived bearer token
|
|
6
|
+
that acts as the user who launched the workload.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import functools
|
|
12
|
+
import threading
|
|
13
|
+
import time
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
import requests
|
|
17
|
+
from requests.auth import AuthBase
|
|
18
|
+
|
|
19
|
+
from wherobots.exceptions import WherobotsConfigError, WherobotsNotAuthenticatedError
|
|
20
|
+
|
|
21
|
+
_EXCHANGE_PATH = "/ste/oauth2/token"
|
|
22
|
+
# Descriptive only: the API does not enforce scope on these tokens.
|
|
23
|
+
_SCOPE = "api"
|
|
24
|
+
_REFRESH_MARGIN_SECONDS = 60
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class WorkloadIdentityAuth(AuthBase):
|
|
28
|
+
"""Sets ``Authorization: Bearer`` from the mounted workload-identity token.
|
|
29
|
+
|
|
30
|
+
The bearer token is cached and swapped for a new one shortly before it
|
|
31
|
+
expires, so long-running jobs keep working past its one-hour lifetime.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
base_url: Wherobots API base URL (already validated as HTTPS).
|
|
35
|
+
id_token_path: Path to the mounted workload-identity token.
|
|
36
|
+
timeout: Timeout in seconds for the token exchange request.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, base_url: str, id_token_path: str, timeout: int) -> None:
|
|
40
|
+
"""Build the auth; see the class docstring."""
|
|
41
|
+
self._token_url = f"{base_url}{_EXCHANGE_PATH}"
|
|
42
|
+
self._id_token_path = Path(id_token_path)
|
|
43
|
+
self._timeout = timeout
|
|
44
|
+
self._lock = threading.Lock()
|
|
45
|
+
self._access_token: str | None = None
|
|
46
|
+
self._refresh_at = 0.0
|
|
47
|
+
|
|
48
|
+
def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest:
|
|
49
|
+
"""Attach the current bearer token to *request*."""
|
|
50
|
+
request.headers["Authorization"] = f"Bearer {self._current_token()}"
|
|
51
|
+
return request
|
|
52
|
+
|
|
53
|
+
def _current_token(self) -> str:
|
|
54
|
+
with self._lock:
|
|
55
|
+
if self._access_token is None or time.monotonic() >= self._refresh_at:
|
|
56
|
+
token, expires_in = self._exchange()
|
|
57
|
+
self._access_token = token
|
|
58
|
+
self._refresh_at = time.monotonic() + max(0, expires_in - _REFRESH_MARGIN_SECONDS)
|
|
59
|
+
return self._access_token
|
|
60
|
+
|
|
61
|
+
def _exchange(self) -> tuple[str, int]:
|
|
62
|
+
try:
|
|
63
|
+
id_token = self._id_token_path.read_text(encoding="utf-8").strip()
|
|
64
|
+
except (OSError, UnicodeDecodeError) as exc:
|
|
65
|
+
raise WherobotsConfigError(
|
|
66
|
+
f"Cannot read the workload identity token at {self._id_token_path}: {exc}"
|
|
67
|
+
) from exc
|
|
68
|
+
if not id_token:
|
|
69
|
+
raise WherobotsConfigError(
|
|
70
|
+
f"The workload identity token at {self._id_token_path} is empty"
|
|
71
|
+
)
|
|
72
|
+
# Errors carry no status_code: it would read as the status of the caller's own request.
|
|
73
|
+
try:
|
|
74
|
+
response = requests.post(
|
|
75
|
+
self._token_url,
|
|
76
|
+
data={"grant_type": "refresh_token", "refresh_token": id_token, "scope": _SCOPE},
|
|
77
|
+
timeout=self._timeout,
|
|
78
|
+
allow_redirects=False,
|
|
79
|
+
)
|
|
80
|
+
response.raise_for_status()
|
|
81
|
+
payload = response.json()
|
|
82
|
+
except requests.HTTPError as exc:
|
|
83
|
+
raise WherobotsNotAuthenticatedError(_rejection_message(exc.response)) from exc
|
|
84
|
+
except (requests.RequestException, ValueError) as exc:
|
|
85
|
+
raise WherobotsNotAuthenticatedError(
|
|
86
|
+
f"Workload identity token exchange failed: {exc}"
|
|
87
|
+
) from exc
|
|
88
|
+
|
|
89
|
+
token = payload.get("access_token") if isinstance(payload, dict) else None
|
|
90
|
+
expires_in = payload.get("expires_in") if isinstance(payload, dict) else None
|
|
91
|
+
if not isinstance(token, str) or not isinstance(expires_in, int):
|
|
92
|
+
raise WherobotsNotAuthenticatedError(
|
|
93
|
+
"Workload identity token exchange returned an unexpected body"
|
|
94
|
+
)
|
|
95
|
+
return token, expires_in
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@functools.cache
|
|
99
|
+
def shared_workload_identity_auth(
|
|
100
|
+
base_url: str, id_token_path: str, timeout: int
|
|
101
|
+
) -> WorkloadIdentityAuth:
|
|
102
|
+
"""Return one auth per process and token, so every client reuses one bearer token."""
|
|
103
|
+
return WorkloadIdentityAuth(base_url, id_token_path, timeout)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _rejection_message(response: requests.Response | None) -> str:
|
|
107
|
+
message = "Workload identity token exchange was rejected"
|
|
108
|
+
if response is None:
|
|
109
|
+
return message
|
|
110
|
+
message = f"{message} (status {response.status_code})"
|
|
111
|
+
try:
|
|
112
|
+
body = response.json()
|
|
113
|
+
except ValueError:
|
|
114
|
+
return message
|
|
115
|
+
reason = body.get("message") if isinstance(body, dict) else None
|
|
116
|
+
return f"{message}: {reason}" if isinstance(reason, str) else message
|
wherobots/config.py
CHANGED
|
@@ -25,6 +25,9 @@ class WherobotsConfig:
|
|
|
25
25
|
embed this SDK (e.g. the Airflow provider). The SDK appends its
|
|
26
26
|
own hop to the right of it, so the origin client stays leftmost.
|
|
27
27
|
Advisory only — it never affects authentication.
|
|
28
|
+
id_token_path: Workload-identity token mounted in Wherobots notebook
|
|
29
|
+
and job pods. Used for auth only when no ``api_key`` is set
|
|
30
|
+
(ADR-0003).
|
|
28
31
|
"""
|
|
29
32
|
|
|
30
33
|
api_key: str | None = None
|
|
@@ -35,6 +38,7 @@ class WherobotsConfig:
|
|
|
35
38
|
version: str = "latest"
|
|
36
39
|
request_timeout_seconds: int = 30
|
|
37
40
|
client_chain: str | None = None
|
|
41
|
+
id_token_path: str | None = None
|
|
38
42
|
|
|
39
43
|
def __repr__(self) -> str:
|
|
40
44
|
"""Return a string representation with the API key masked."""
|
|
@@ -54,7 +58,8 @@ class WherobotsConfig:
|
|
|
54
58
|
f"base_url={self.base_url!r}, "
|
|
55
59
|
f"version={self.version!r}, "
|
|
56
60
|
f"request_timeout_seconds={self.request_timeout_seconds!r}, "
|
|
57
|
-
f"client_chain={self.client_chain!r}
|
|
61
|
+
f"client_chain={self.client_chain!r}, "
|
|
62
|
+
f"id_token_path={self.id_token_path!r})"
|
|
58
63
|
)
|
|
59
64
|
|
|
60
65
|
def __post_init__(self) -> None:
|
|
@@ -90,6 +95,7 @@ class WherobotsConfig:
|
|
|
90
95
|
version: str | None = None,
|
|
91
96
|
request_timeout_seconds: int | None = None,
|
|
92
97
|
client_chain: str | None = None,
|
|
98
|
+
id_token_path: str | None = None,
|
|
93
99
|
) -> WherobotsConfig:
|
|
94
100
|
"""Build configuration from environment variables with optional overrides.
|
|
95
101
|
|
|
@@ -108,6 +114,8 @@ class WherobotsConfig:
|
|
|
108
114
|
client_chain: Override for ``WHEROBOTS_CLIENT_CHAIN`` — the
|
|
109
115
|
upstream ``X-Wherobots-Client`` chain this SDK appends its
|
|
110
116
|
own hop to.
|
|
117
|
+
id_token_path: Override for ``WHEROBOTS_ID_TOKEN_PATH``, which
|
|
118
|
+
Wherobots notebook and job pods set.
|
|
111
119
|
|
|
112
120
|
Returns:
|
|
113
121
|
A validated ``WherobotsConfig`` instance.
|
|
@@ -163,7 +171,8 @@ class WherobotsConfig:
|
|
|
163
171
|
)
|
|
164
172
|
|
|
165
173
|
return cls(
|
|
166
|
-
|
|
174
|
+
# A blank key must not hide WHEROBOTS_API_KEY behind workload identity.
|
|
175
|
+
api_key=(api_key or "").strip() or _env("WHEROBOTS_API_KEY"),
|
|
167
176
|
region=region or _env("WHEROBOTS_REGION"),
|
|
168
177
|
s3_bucket=s3_bucket or _env("WHEROBOTS_S3_BUCKET"),
|
|
169
178
|
s3_prefix=s3_prefix or _env("WHEROBOTS_S3_PREFIX") or "wherobots-jobs",
|
|
@@ -173,4 +182,5 @@ class WherobotsConfig:
|
|
|
173
182
|
version=version or _env("WHEROBOTS_VERSION") or "latest",
|
|
174
183
|
request_timeout_seconds=timeout,
|
|
175
184
|
client_chain=client_chain or _env("WHEROBOTS_CLIENT_CHAIN"),
|
|
185
|
+
id_token_path=id_token_path or _env("WHEROBOTS_ID_TOKEN_PATH"),
|
|
176
186
|
)
|
wherobots/exceptions.py
CHANGED
|
@@ -48,7 +48,7 @@ class WherobotsTimeoutError(WherobotsJobError):
|
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
class WherobotsNotAuthenticatedError(WherobotsAPIError):
|
|
51
|
-
"""Raised when the Wherobots API does not accept the
|
|
51
|
+
"""Raised when the Wherobots API does not accept the credentials."""
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
class WherobotsFileNotFoundError(WherobotsAPIError):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wherobots-python-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Python SDK for Wherobots (currently covers the Jobs REST API)
|
|
5
5
|
Author-email: Wherobots <support@wherobots.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -21,7 +21,7 @@ Requires-Python: >=3.11
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: requests>=2.34.2
|
|
24
|
-
Requires-Dist: boto3>=1.
|
|
24
|
+
Requires-Dist: boto3>=1.34.0
|
|
25
25
|
Dynamic: license-file
|
|
26
26
|
|
|
27
27
|
# Wherobots Python SDK
|
|
@@ -118,18 +118,27 @@ job = WherobotsJob(
|
|
|
118
118
|
|
|
119
119
|
The API key can also be set via the `WHEROBOTS_API_KEY` environment variable.
|
|
120
120
|
|
|
121
|
+
Inside a Wherobots notebook or job, no API key is needed. The SDK authenticates as the user who
|
|
122
|
+
launched the workload, using the token Wherobots mounts in the pod. An API key, when set, takes
|
|
123
|
+
precedence.
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
job = WherobotsJob(script="s3://bucket/script.py", name="my-job-001")
|
|
127
|
+
```
|
|
128
|
+
|
|
121
129
|
## Configuration
|
|
122
130
|
|
|
123
131
|
### Environment Variables
|
|
124
132
|
|
|
125
133
|
| Variable | Description | Default |
|
|
126
134
|
|------------------------------------|---------------------------------|--------------------------------------|
|
|
127
|
-
| `WHEROBOTS_API_KEY` | API key | *(required)*
|
|
135
|
+
| `WHEROBOTS_API_KEY` | API key | *(required outside Wherobots)* |
|
|
128
136
|
| `WHEROBOTS_REGION` | Region override (else org default) | *(none — org default)* |
|
|
129
137
|
| `WHEROBOTS_API_BASE_URL` | API base URL | `https://api.cloud.wherobots.com` |
|
|
130
138
|
| `WHEROBOTS_VERSION` | Wherobots version | `latest` |
|
|
131
139
|
| `WHEROBOTS_REQUEST_TIMEOUT_SECONDS`| HTTP request timeout (seconds) | `30` |
|
|
132
140
|
| `WHEROBOTS_CLIENT_CHAIN` | Upstream client-attribution chain (see below) | *(none)* |
|
|
141
|
+
| `WHEROBOTS_ID_TOKEN_PATH` | Workload identity token, set by Wherobots notebooks and jobs | *(none)* |
|
|
133
142
|
|
|
134
143
|
### WherobotsConfig
|
|
135
144
|
|
|
@@ -456,7 +465,7 @@ with wherobots.Wherobots() as wb:
|
|
|
456
465
|
| Failure | Raised as |
|
|
457
466
|
|---|---|
|
|
458
467
|
| Files is not enabled for this drive in this region | `WherobotsFilesNotEnabledError` (`.drive`, `.region`) |
|
|
459
|
-
| The
|
|
468
|
+
| The credentials were not accepted | `WherobotsNotAuthenticatedError` |
|
|
460
469
|
| No such file or folder | `WherobotsFileNotFoundError` |
|
|
461
470
|
| Transfer to or from storage failed | `WherobotsS3Error` |
|
|
462
471
|
|
|
@@ -673,7 +682,7 @@ All exceptions inherit from `WherobotsJobError`.
|
|
|
673
682
|
| `WherobotsS3Error` | A transfer to or from storage failed, including Files presigned uploads and downloads. |
|
|
674
683
|
| `WherobotsConfigError` | Configuration is missing or invalid. |
|
|
675
684
|
| `WherobotsTimeoutError` | Job exceeded the specified timeout. |
|
|
676
|
-
| `WherobotsNotAuthenticatedError` | Files: the
|
|
685
|
+
| `WherobotsNotAuthenticatedError` | Files: the credentials were not accepted (HTTP 401). In a Wherobots pod: the workload identity token exchange failed. Subclass of `WherobotsAPIError`. |
|
|
677
686
|
| `WherobotsFilesNotEnabledError` | Files is not enabled for a drive in a region. Has `drive`, `region`. Subclass of `WherobotsAPIError`. |
|
|
678
687
|
| `WherobotsFileNotFoundError` | Files: no such file or folder. Subclass of `WherobotsAPIError`. |
|
|
679
688
|
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
wherobots/__init__.py,sha256=MUFjzOBaVW2lzPw35F5SBlTChJBKl1n0-p16qUnIO9k,2759
|
|
2
|
-
wherobots/__version__.py,sha256=
|
|
2
|
+
wherobots/__version__.py,sha256=fIE1uN53hY31LBi8pDljwzsVPIy2DxhD_1aN1rJ34iw,111
|
|
3
3
|
wherobots/client.py,sha256=mFShTtxXfCg9GLVMykM7jC1SvuDCZ_sY9JnHIOlOwxQ,37797
|
|
4
|
-
wherobots/config.py,sha256=
|
|
4
|
+
wherobots/config.py,sha256=53BCZxXathnEjEJqwti07MxTmqNyYNP3b40qmri1blE,7986
|
|
5
5
|
wherobots/enums.py,sha256=T_x0QzDCmrZZTfYuEjkdjT_tbt0DDP5S-Kr5HnC8j2o,5218
|
|
6
|
-
wherobots/exceptions.py,sha256=
|
|
6
|
+
wherobots/exceptions.py,sha256=lBzjRNtWRGyh0PgnIKAQr4x2liEhFvWoLn-Ndf91nCQ,2558
|
|
7
7
|
wherobots/models.py,sha256=A1KxUivCoUUzFFhhMJCfu7qJHs_2ouYJR27gk39UzWs,62256
|
|
8
8
|
wherobots/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
wherobots/sdk.py,sha256=AcLC_ZFqTl24Vthcu_EfK7FFUJEyftGJJkusEp-zayI,3481
|
|
10
10
|
wherobots/api/__init__.py,sha256=VT1nx6K777qV-PX-7hrBfCWPL1h6WYc4ljj_-qqhdko,360
|
|
11
|
-
wherobots/api/base.py,sha256=
|
|
12
|
-
wherobots/api/drive.py,sha256=
|
|
13
|
-
wherobots/api/files.py,sha256=
|
|
11
|
+
wherobots/api/base.py,sha256=y9rCRBDX5II3gLD1muhjlYtAA_X3IC78w6wqzKke8RY,12479
|
|
12
|
+
wherobots/api/drive.py,sha256=X-HmUN3Z2aw3H56kd0AcfxC_44pZE7Fh5SIC7Q16rQo,18809
|
|
13
|
+
wherobots/api/files.py,sha256=a_OteB6rQRF7PHvIeazAoh7NeAfg7UNq-GheZzSal_k,23498
|
|
14
14
|
wherobots/api/runs.py,sha256=y0yF_h74S4ScebgCxHjT07kBlj8aIHlfYN6iBaBktgs,8654
|
|
15
15
|
wherobots/api/tasks.py,sha256=9knNtwU0Kb2NYkuabaaNkhiOyZjscec-JT8rkZZbIiY,9144
|
|
16
|
+
wherobots/api/workload_auth.py,sha256=zhJXROeYV47HJvEqzGAbd4oaqkuqXQGHZQRCHeDIYuE,4725
|
|
16
17
|
wherobots/utils/__init__.py,sha256=cTM2QNJDauQWyGBTJPE5yH4ULc4Ucg_4KFzemjM3HaA,193
|
|
17
18
|
wherobots/utils/client_header.py,sha256=-zczKIl8QfFBs1uTLbzp6cGLEzit1qGgdWbV9MLYEcM,8083
|
|
18
19
|
wherobots/utils/logger.py,sha256=eclhD9Vf2LsSm4engRzT3jE2v0wdHJH01OfeI3ml4HM,1103
|
|
19
20
|
wherobots/utils/validation.py,sha256=mjWGGhNji1crdn1AhLZoTIfknSQm38X0MmgI4ow14T8,907
|
|
20
|
-
wherobots_python_sdk-0.
|
|
21
|
-
wherobots_python_sdk-0.
|
|
22
|
-
wherobots_python_sdk-0.
|
|
23
|
-
wherobots_python_sdk-0.
|
|
24
|
-
wherobots_python_sdk-0.
|
|
21
|
+
wherobots_python_sdk-0.7.0.dist-info/licenses/LICENSE,sha256=U1EH466XmvxbqaWOY0cax49w0R87_6w6yJLyV14v4bc,10767
|
|
22
|
+
wherobots_python_sdk-0.7.0.dist-info/METADATA,sha256=eyfrSSkWK3vTgWCla5BSrDusKgW3XJrs4Aw-RfTzWiE,33310
|
|
23
|
+
wherobots_python_sdk-0.7.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
24
|
+
wherobots_python_sdk-0.7.0.dist-info/top_level.txt,sha256=oL-n-9GIG0rmUeukuytUqdN6yfROIsVh8bNrgZsOdxw,10
|
|
25
|
+
wherobots_python_sdk-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
{wherobots_python_sdk-0.6.0.dist-info → wherobots_python_sdk-0.7.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|