robot-wrapper-sdk 0.2.9__tar.gz → 0.2.11__tar.gz
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.
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/PKG-INFO +1 -1
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/pyproject.toml +1 -1
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/domain/entities.py +12 -2
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/infrastructure/api_client.py +81 -54
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/infrastructure/robot_api_repository.py +25 -10
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/PKG-INFO +1 -1
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/README.md +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/examples/main.py +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/application/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/application/usecases.py +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/domain/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/domain/repositories.py +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_sdk/infrastructure/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/SOURCES.txt +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/dependency_links.txt +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/requires.txt +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/top_level.txt +0 -0
- {robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/setup.cfg +0 -0
|
@@ -32,13 +32,15 @@ def normalize_robot_auth_status(status: str | RobotAuthStatus) -> str:
|
|
|
32
32
|
def ensure_valid_robot_status(status: str) -> None:
|
|
33
33
|
allowed = {s.value for s in RobotStatus}
|
|
34
34
|
if status not in allowed:
|
|
35
|
-
raise ValueError(
|
|
35
|
+
raise ValueError(
|
|
36
|
+
f"invalid status: {status}. allowed={sorted(allowed)}")
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
def ensure_valid_robot_auth_status(status: str) -> None:
|
|
39
40
|
allowed = {s.value for s in RobotAuthStatus}
|
|
40
41
|
if status not in allowed:
|
|
41
|
-
raise ValueError(
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"invalid auth_status: {status}. allowed={sorted(allowed)}")
|
|
42
44
|
|
|
43
45
|
|
|
44
46
|
def ensure_valid_worker_robot_auth_status(status: str) -> None:
|
|
@@ -70,16 +72,19 @@ class Robot:
|
|
|
70
72
|
username: str
|
|
71
73
|
platform: str
|
|
72
74
|
status: str
|
|
75
|
+
auth_status: str
|
|
73
76
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
74
77
|
project_id: Optional[str] = None
|
|
75
78
|
primary_environment: Optional[str] = None
|
|
76
79
|
created_at: Optional[str] = None
|
|
77
80
|
|
|
81
|
+
|
|
78
82
|
@dataclass
|
|
79
83
|
class RobotSecrets:
|
|
80
84
|
password: str
|
|
81
85
|
two_fa_secret: str
|
|
82
86
|
|
|
87
|
+
|
|
83
88
|
@dataclass
|
|
84
89
|
class RobotActivity:
|
|
85
90
|
id: str
|
|
@@ -87,25 +92,30 @@ class RobotActivity:
|
|
|
87
92
|
status: str
|
|
88
93
|
message: str
|
|
89
94
|
|
|
95
|
+
|
|
90
96
|
@dataclass
|
|
91
97
|
class AcquireNeedLoginRequest:
|
|
92
98
|
limit: int = 20
|
|
93
99
|
lock_minutes: int = 30
|
|
94
100
|
|
|
101
|
+
|
|
95
102
|
@dataclass
|
|
96
103
|
class AcquireUnhardenedRequest:
|
|
97
104
|
limit: int = 20
|
|
98
105
|
lock_minutes: int = 30
|
|
99
106
|
min_age_days: int = 0
|
|
100
107
|
|
|
108
|
+
|
|
101
109
|
@dataclass
|
|
102
110
|
class UpdateAuthStatusRequest:
|
|
103
111
|
auth_status: str
|
|
104
112
|
|
|
113
|
+
|
|
105
114
|
@dataclass
|
|
106
115
|
class UpdateSecurityHardenedRequest:
|
|
107
116
|
security_hardened: bool
|
|
108
117
|
|
|
118
|
+
|
|
109
119
|
@dataclass
|
|
110
120
|
class StandardResponse:
|
|
111
121
|
status: str
|
|
@@ -3,14 +3,71 @@ import os
|
|
|
3
3
|
from typing import Dict, Any, Optional
|
|
4
4
|
from httpx import RemoteProtocolError
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
def _build_httpx_client(base_url: str, auth: httpx.Auth, proxy_url: Optional[str]) -> httpx.Client:
|
|
8
|
+
kwargs: Dict[str, Any] = {"base_url": base_url, "auth": auth}
|
|
9
|
+
if proxy_url:
|
|
10
|
+
kwargs["proxy"] = proxy_url
|
|
11
|
+
try:
|
|
12
|
+
return httpx.Client(**kwargs)
|
|
13
|
+
except TypeError:
|
|
14
|
+
if "proxy" in kwargs:
|
|
15
|
+
kwargs["proxies"] = kwargs.pop("proxy")
|
|
16
|
+
return httpx.Client(**kwargs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _build_async_httpx_client(base_url: str, auth: httpx.Auth, proxy_url: Optional[str]) -> httpx.AsyncClient:
|
|
20
|
+
kwargs: Dict[str, Any] = {"base_url": base_url, "auth": auth}
|
|
21
|
+
if proxy_url:
|
|
22
|
+
kwargs["proxy"] = proxy_url
|
|
23
|
+
try:
|
|
24
|
+
return httpx.AsyncClient(**kwargs)
|
|
25
|
+
except TypeError:
|
|
26
|
+
if "proxy" in kwargs:
|
|
27
|
+
kwargs["proxies"] = kwargs.pop("proxy")
|
|
28
|
+
return httpx.AsyncClient(**kwargs)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _build_plain_httpx_client(proxy_url: Optional[str]) -> httpx.Client:
|
|
32
|
+
kwargs: Dict[str, Any] = {}
|
|
33
|
+
if proxy_url:
|
|
34
|
+
kwargs["proxy"] = proxy_url
|
|
35
|
+
try:
|
|
36
|
+
return httpx.Client(**kwargs)
|
|
37
|
+
except TypeError:
|
|
38
|
+
if "proxy" in kwargs:
|
|
39
|
+
kwargs["proxies"] = kwargs.pop("proxy")
|
|
40
|
+
return httpx.Client(**kwargs)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _build_plain_async_httpx_client(proxy_url: Optional[str]) -> httpx.AsyncClient:
|
|
44
|
+
kwargs: Dict[str, Any] = {}
|
|
45
|
+
if proxy_url:
|
|
46
|
+
kwargs["proxy"] = proxy_url
|
|
47
|
+
try:
|
|
48
|
+
return httpx.AsyncClient(**kwargs)
|
|
49
|
+
except TypeError:
|
|
50
|
+
if "proxy" in kwargs:
|
|
51
|
+
kwargs["proxies"] = kwargs.pop("proxy")
|
|
52
|
+
return httpx.AsyncClient(**kwargs)
|
|
53
|
+
|
|
6
54
|
def _extract_tokens(payload: Dict[str, Any]) -> tuple[Optional[str], Optional[str]]:
|
|
7
|
-
|
|
8
|
-
if isinstance(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
55
|
+
container = payload.get("data") if isinstance(payload, dict) and isinstance(payload.get("data"), dict) else payload
|
|
56
|
+
if not isinstance(container, dict):
|
|
57
|
+
return None, None
|
|
58
|
+
|
|
59
|
+
access_token = (
|
|
60
|
+
container.get("access_token")
|
|
61
|
+
or container.get("accessToken")
|
|
62
|
+
or container.get("AccessToken")
|
|
63
|
+
or payload.get("access_token") if isinstance(payload, dict) else None
|
|
64
|
+
)
|
|
65
|
+
refresh_token = (
|
|
66
|
+
container.get("refresh_token")
|
|
67
|
+
or container.get("refreshToken")
|
|
68
|
+
or container.get("RefreshToken")
|
|
69
|
+
or payload.get("refresh_token") if isinstance(payload, dict) else None
|
|
70
|
+
)
|
|
14
71
|
|
|
15
72
|
access_token = str(access_token).strip() if access_token else None
|
|
16
73
|
refresh_token = str(refresh_token).strip() if refresh_token else None
|
|
@@ -69,10 +126,10 @@ class HTTPClient:
|
|
|
69
126
|
self.access_token: Optional[str] = None
|
|
70
127
|
self.refresh_token: Optional[str] = None
|
|
71
128
|
|
|
72
|
-
self.client =
|
|
129
|
+
self.client = _build_httpx_client(
|
|
73
130
|
base_url=self.base_url,
|
|
74
131
|
auth=RobotAuth(self._get_or_login, self._refresh),
|
|
75
|
-
|
|
132
|
+
proxy_url=self.proxy_url,
|
|
76
133
|
)
|
|
77
134
|
|
|
78
135
|
def _get_or_login(self) -> str:
|
|
@@ -84,7 +141,7 @@ class HTTPClient:
|
|
|
84
141
|
return token
|
|
85
142
|
|
|
86
143
|
def _login(self) -> None:
|
|
87
|
-
with
|
|
144
|
+
with _build_plain_httpx_client(self.proxy_url) as c:
|
|
88
145
|
resp = c.post(
|
|
89
146
|
f"{self.base_url}/api/v1/developer/auth/token",
|
|
90
147
|
json={"app_id": self.app_id, "app_secret": self.app_secret}
|
|
@@ -99,28 +156,10 @@ class HTTPClient:
|
|
|
99
156
|
raise
|
|
100
157
|
|
|
101
158
|
def _refresh(self) -> str:
|
|
102
|
-
|
|
103
|
-
if not self.refresh_token:
|
|
104
|
-
self._login()
|
|
105
|
-
token = str(self.access_token).strip() if self.access_token else ""
|
|
106
|
-
if not token:
|
|
107
|
-
raise RuntimeError("Empty access token after login")
|
|
108
|
-
return token
|
|
109
|
-
|
|
110
|
-
with httpx.Client(proxy=self.proxy_url) as c:
|
|
111
|
-
resp = c.post(
|
|
112
|
-
f"{self.base_url}/api/v1/developer/auth/refresh",
|
|
113
|
-
json={"refresh_token": self.refresh_token}
|
|
114
|
-
)
|
|
115
|
-
if resp.status_code >= 400:
|
|
116
|
-
self._login()
|
|
117
|
-
else:
|
|
118
|
-
data = resp.json()
|
|
119
|
-
self.access_token, self.refresh_token = _extract_tokens(data)
|
|
120
|
-
|
|
159
|
+
self._login()
|
|
121
160
|
token = str(self.access_token).strip() if self.access_token else ""
|
|
122
161
|
if not token:
|
|
123
|
-
raise RuntimeError("
|
|
162
|
+
raise RuntimeError("Empty access token after login")
|
|
124
163
|
return token
|
|
125
164
|
|
|
126
165
|
def request(self, method: str, path: str, **kwargs: Any) -> Dict[str, Any]:
|
|
@@ -132,6 +171,11 @@ class HTTPClient:
|
|
|
132
171
|
path = f"/{path}"
|
|
133
172
|
full_path = f"/api/v1/developer{path}"
|
|
134
173
|
|
|
174
|
+
headers = dict(kwargs.pop("headers", {}) or {})
|
|
175
|
+
if "/auth/" not in full_path and "Authorization" not in headers:
|
|
176
|
+
headers["Authorization"] = f"Bearer {self._get_or_login()}"
|
|
177
|
+
kwargs["headers"] = headers
|
|
178
|
+
|
|
135
179
|
print(f"🚀 Requesting: {self.base_url}{full_path}")
|
|
136
180
|
last_err: Optional[Exception] = None
|
|
137
181
|
resp = None
|
|
@@ -146,10 +190,10 @@ class HTTPClient:
|
|
|
146
190
|
raise
|
|
147
191
|
last_err = err
|
|
148
192
|
self.client.close()
|
|
149
|
-
self.client =
|
|
193
|
+
self.client = _build_httpx_client(
|
|
150
194
|
base_url=self.base_url,
|
|
151
195
|
auth=RobotAuth(self._get_or_login, self._refresh),
|
|
152
|
-
|
|
196
|
+
proxy_url=self.proxy_url,
|
|
153
197
|
)
|
|
154
198
|
|
|
155
199
|
if resp is None:
|
|
@@ -183,10 +227,10 @@ class AsyncHTTPClient:
|
|
|
183
227
|
self.access_token: Optional[str] = None
|
|
184
228
|
self.refresh_token: Optional[str] = None
|
|
185
229
|
|
|
186
|
-
self.client =
|
|
230
|
+
self.client = _build_async_httpx_client(
|
|
187
231
|
base_url=self.base_url,
|
|
188
232
|
auth=AsyncRobotAuth(self._get_or_login, self._refresh),
|
|
189
|
-
|
|
233
|
+
proxy_url=self.proxy_url,
|
|
190
234
|
)
|
|
191
235
|
|
|
192
236
|
async def _get_or_login(self) -> str:
|
|
@@ -198,7 +242,7 @@ class AsyncHTTPClient:
|
|
|
198
242
|
return token
|
|
199
243
|
|
|
200
244
|
async def _login(self) -> None:
|
|
201
|
-
async with
|
|
245
|
+
async with _build_plain_async_httpx_client(self.proxy_url) as c:
|
|
202
246
|
resp = await c.post(
|
|
203
247
|
f"{self.base_url}/api/v1/developer/auth/token",
|
|
204
248
|
json={"app_id": self.app_id, "app_secret": self.app_secret}
|
|
@@ -213,27 +257,10 @@ class AsyncHTTPClient:
|
|
|
213
257
|
raise
|
|
214
258
|
|
|
215
259
|
async def _refresh(self) -> str:
|
|
216
|
-
|
|
217
|
-
await self._login()
|
|
218
|
-
token = str(self.access_token).strip() if self.access_token else ""
|
|
219
|
-
if not token:
|
|
220
|
-
raise RuntimeError("Empty access token after login")
|
|
221
|
-
return token
|
|
222
|
-
|
|
223
|
-
async with httpx.AsyncClient(proxy=self.proxy_url) as c:
|
|
224
|
-
resp = await c.post(
|
|
225
|
-
f"{self.base_url}/api/v1/developer/auth/refresh",
|
|
226
|
-
json={"refresh_token": self.refresh_token}
|
|
227
|
-
)
|
|
228
|
-
if resp.status_code >= 400:
|
|
229
|
-
await self._login()
|
|
230
|
-
else:
|
|
231
|
-
data = resp.json()
|
|
232
|
-
self.access_token, self.refresh_token = _extract_tokens(data)
|
|
233
|
-
|
|
260
|
+
await self._login()
|
|
234
261
|
token = str(self.access_token).strip() if self.access_token else ""
|
|
235
262
|
if not token:
|
|
236
|
-
raise RuntimeError("
|
|
263
|
+
raise RuntimeError("Empty access token after login")
|
|
237
264
|
return token
|
|
238
265
|
|
|
239
266
|
async def request(self, method: str, path: str, **kwargs: Any) -> Dict[str, Any]:
|
|
@@ -39,13 +39,26 @@ def _extract_items(resp: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
|
39
39
|
return [item for item in nested if isinstance(item, dict)]
|
|
40
40
|
return []
|
|
41
41
|
|
|
42
|
+
|
|
43
|
+
def _to_robot_payload(item: Dict[str, Any]) -> Dict[str, Any]:
|
|
44
|
+
payload = dict(item)
|
|
45
|
+
payload.setdefault("auth_status", "")
|
|
46
|
+
payload.setdefault("metadata", {})
|
|
47
|
+
return payload
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _to_robots(items: List[Dict[str, Any]]) -> List[Robot]:
|
|
51
|
+
return [Robot(**_to_robot_payload(item)) for item in items]
|
|
52
|
+
|
|
42
53
|
class RobotAPIRepository(RobotRepository):
|
|
43
54
|
def __init__(self, client: HTTPClient):
|
|
44
55
|
self.client = client
|
|
45
56
|
|
|
46
57
|
def find_by_id(self, robot_id: str) -> Optional[Robot]:
|
|
47
58
|
resp = self.client.request("GET", f"/robots/{robot_id}")
|
|
48
|
-
|
|
59
|
+
payload = resp.get("data") if isinstance(resp, dict) else None
|
|
60
|
+
data = payload if isinstance(payload, dict) else resp
|
|
61
|
+
return Robot(**_to_robot_payload(data)) if isinstance(data, dict) else None
|
|
49
62
|
|
|
50
63
|
def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
51
64
|
normalized_status = normalize_robot_status(status)
|
|
@@ -67,7 +80,7 @@ class RobotAPIRepository(RobotRepository):
|
|
|
67
80
|
|
|
68
81
|
resp = self.client.request("GET", "/robots", params=params)
|
|
69
82
|
data, total = _extract_list_payload(resp)
|
|
70
|
-
return
|
|
83
|
+
return _to_robots(data), total
|
|
71
84
|
|
|
72
85
|
def acquire_need_login(self, limit: int = 20, lock_minutes: int = 30) -> List[Robot]:
|
|
73
86
|
resp = self.client.request(
|
|
@@ -76,7 +89,7 @@ class RobotAPIRepository(RobotRepository):
|
|
|
76
89
|
json={"limit": limit, "lock_minutes": lock_minutes},
|
|
77
90
|
)
|
|
78
91
|
data = _extract_items(resp)
|
|
79
|
-
return
|
|
92
|
+
return _to_robots(data)
|
|
80
93
|
|
|
81
94
|
def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0) -> List[Robot]:
|
|
82
95
|
resp = self.client.request(
|
|
@@ -85,7 +98,7 @@ class RobotAPIRepository(RobotRepository):
|
|
|
85
98
|
json={"limit": limit, "lock_minutes": lock_minutes, "min_age_days": min_age_days},
|
|
86
99
|
)
|
|
87
100
|
data = _extract_items(resp)
|
|
88
|
-
return
|
|
101
|
+
return _to_robots(data)
|
|
89
102
|
|
|
90
103
|
def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
91
104
|
normalized_auth_status = normalize_robot_auth_status(auth_status)
|
|
@@ -106,7 +119,7 @@ class RobotAPIRepository(RobotRepository):
|
|
|
106
119
|
def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
107
120
|
self.client.request(
|
|
108
121
|
"PATCH",
|
|
109
|
-
f"/robots/{robot_id}",
|
|
122
|
+
f"/robots/{robot_id}/metadata",
|
|
110
123
|
json={"metadata": metadata},
|
|
111
124
|
)
|
|
112
125
|
|
|
@@ -116,7 +129,9 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
116
129
|
|
|
117
130
|
async def find_by_id(self, robot_id: str) -> Optional[Robot]:
|
|
118
131
|
resp = await self.client.request("GET", f"/robots/{robot_id}")
|
|
119
|
-
|
|
132
|
+
payload = resp.get("data") if isinstance(resp, dict) else None
|
|
133
|
+
data = payload if isinstance(payload, dict) else resp
|
|
134
|
+
return Robot(**_to_robot_payload(data)) if isinstance(data, dict) else None
|
|
120
135
|
|
|
121
136
|
async def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
122
137
|
normalized_status = normalize_robot_status(status)
|
|
@@ -138,7 +153,7 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
138
153
|
|
|
139
154
|
resp = await self.client.request("GET", "/robots", params=params)
|
|
140
155
|
data, total = _extract_list_payload(resp)
|
|
141
|
-
return
|
|
156
|
+
return _to_robots(data), total
|
|
142
157
|
|
|
143
158
|
async def acquire_need_login(self, limit: int = 20, lock_minutes: int = 30) -> List[Robot]:
|
|
144
159
|
resp = await self.client.request(
|
|
@@ -147,7 +162,7 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
147
162
|
json={"limit": limit, "lock_minutes": lock_minutes},
|
|
148
163
|
)
|
|
149
164
|
data = _extract_items(resp)
|
|
150
|
-
return
|
|
165
|
+
return _to_robots(data)
|
|
151
166
|
|
|
152
167
|
async def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0) -> List[Robot]:
|
|
153
168
|
resp = await self.client.request(
|
|
@@ -156,7 +171,7 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
156
171
|
json={"limit": limit, "lock_minutes": lock_minutes, "min_age_days": min_age_days},
|
|
157
172
|
)
|
|
158
173
|
data = _extract_items(resp)
|
|
159
|
-
return
|
|
174
|
+
return _to_robots(data)
|
|
160
175
|
|
|
161
176
|
async def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
162
177
|
normalized_auth_status = normalize_robot_auth_status(auth_status)
|
|
@@ -177,6 +192,6 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
177
192
|
async def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
178
193
|
await self.client.request(
|
|
179
194
|
"PATCH",
|
|
180
|
-
f"/robots/{robot_id}",
|
|
195
|
+
f"/robots/{robot_id}/metadata",
|
|
181
196
|
json={"metadata": metadata},
|
|
182
197
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/requires.txt
RENAMED
|
File without changes
|
{robot_wrapper_sdk-0.2.9 → robot_wrapper_sdk-0.2.11}/robot_wrapper_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|