envloop-cli 1.13.0__tar.gz → 1.14.0__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.
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/PKG-INFO +3 -3
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/README.pypi.md +2 -2
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/auth_login.py +3 -3
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/cli.py +1 -6
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/http.py +22 -3
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/pyproject.toml +1 -1
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/.gitignore +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/__init__.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/agent_runs.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/auth_cli.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/auth_workspace.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/cli_errors.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/cli_output.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/client.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/config.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/inference.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/job_logs.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/job_spec_cli.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/lifecycle_cli.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/navigation_resources.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/profile_secrets.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/profile_updates.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/resource_cli.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/resources.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/rsi_cli.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/sandbox.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/terminal.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train_log_cli.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train_progress.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train_runner_cli.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/training/__init__.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/utils/__init__.py +0 -0
- {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/utils/logging.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: envloop-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.0
|
|
4
4
|
Summary: EnvLoop CLI and Python SDK for jobs, training, checkpoints and inference
|
|
5
5
|
Project-URL: Homepage, https://envloop.ai
|
|
6
6
|
Project-URL: Documentation, https://docs.envloop.ai
|
|
@@ -192,8 +192,8 @@ Choose a published Runner readable in your project. Save this request as `gpu-ru
|
|
|
192
192
|
{
|
|
193
193
|
"request_id": "gpu-run-001",
|
|
194
194
|
"trials": [
|
|
195
|
-
{"name": "first", "spec": {"runner": "envhub/bash
|
|
196
|
-
{"name": "second", "spec": {"runner": "envhub/bash
|
|
195
|
+
{"name": "first", "spec": {"runner": "envhub/bash@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}},
|
|
196
|
+
{"name": "second", "spec": {"runner": "envhub/bash@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}}
|
|
197
197
|
]
|
|
198
198
|
}
|
|
199
199
|
```
|
|
@@ -178,8 +178,8 @@ Choose a published Runner readable in your project. Save this request as `gpu-ru
|
|
|
178
178
|
{
|
|
179
179
|
"request_id": "gpu-run-001",
|
|
180
180
|
"trials": [
|
|
181
|
-
{"name": "first", "spec": {"runner": "envhub/bash
|
|
182
|
-
{"name": "second", "spec": {"runner": "envhub/bash
|
|
181
|
+
{"name": "first", "spec": {"runner": "envhub/bash@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}},
|
|
182
|
+
{"name": "second", "spec": {"runner": "envhub/bash@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}}
|
|
183
183
|
]
|
|
184
184
|
}
|
|
185
185
|
```
|
|
@@ -7,18 +7,18 @@ import webbrowser
|
|
|
7
7
|
from http.client import InvalidURL
|
|
8
8
|
from urllib.error import HTTPError, URLError
|
|
9
9
|
from urllib.parse import parse_qs, urlsplit
|
|
10
|
-
from urllib.request import
|
|
10
|
+
from urllib.request import Request
|
|
11
11
|
|
|
12
12
|
from .auth_workspace import _identity
|
|
13
13
|
from .config import ConfigError, normalize_url
|
|
14
|
-
from .http import
|
|
14
|
+
from .http import build_client_opener
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def _request(url, action, body, timeout):
|
|
18
18
|
request = Request(url + '/v1/auth/cli/' + action, data=json.dumps(body).encode(),
|
|
19
19
|
headers={'Content-Type': 'application/json'}, method='POST')
|
|
20
20
|
try:
|
|
21
|
-
with
|
|
21
|
+
with build_client_opener().open(request, timeout=timeout) as response:
|
|
22
22
|
raw = response.read(8193)
|
|
23
23
|
if len(raw) > 8192:
|
|
24
24
|
raise ConfigError('AUTH_LOGIN_INVALID_RESPONSE')
|
|
@@ -6,15 +6,10 @@ import math
|
|
|
6
6
|
import os
|
|
7
7
|
import shlex
|
|
8
8
|
import sys
|
|
9
|
-
from importlib.metadata import PackageNotFoundError, version
|
|
10
9
|
from pathlib import Path
|
|
11
10
|
|
|
12
11
|
from .client import Client
|
|
13
|
-
|
|
14
|
-
try:
|
|
15
|
-
CLI_VERSION = version("envloop-cli")
|
|
16
|
-
except PackageNotFoundError:
|
|
17
|
-
CLI_VERSION = "unknown"
|
|
12
|
+
from .http import CLI_VERSION
|
|
18
13
|
|
|
19
14
|
|
|
20
15
|
SECTIONS = {
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
import base64
|
|
4
4
|
import json
|
|
5
5
|
import math
|
|
6
|
+
import platform
|
|
6
7
|
import re
|
|
7
8
|
from datetime import datetime, timezone
|
|
8
9
|
from email.utils import parsedate_to_datetime
|
|
9
10
|
from http.client import HTTPException, InvalidURL
|
|
11
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
10
12
|
from urllib.error import HTTPError, URLError
|
|
11
13
|
from urllib.parse import quote, urlencode, urljoin, urlsplit
|
|
12
14
|
from urllib.request import HTTPRedirectHandler, ProxyHandler, Request, build_opener
|
|
@@ -66,6 +68,23 @@ class NoRedirect(HTTPRedirectHandler):
|
|
|
66
68
|
return None
|
|
67
69
|
|
|
68
70
|
|
|
71
|
+
try:
|
|
72
|
+
CLI_VERSION = version("envloop-cli")
|
|
73
|
+
except PackageNotFoundError:
|
|
74
|
+
CLI_VERSION = "unknown"
|
|
75
|
+
|
|
76
|
+
# Cloudflare bot rules answer urllib's default "Python-urllib/3.x" with error 1010 (staging workers.dev).
|
|
77
|
+
USER_AGENT = (f"envloop-cli/{CLI_VERSION} (python/{platform.python_version()}; "
|
|
78
|
+
f"{'-'.join(filter(None, (platform.system().lower(), platform.machine().lower()))) or 'unknown'})")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def build_client_opener():
|
|
82
|
+
"""Proxy-aware opener that never follows redirects and names the client in every request."""
|
|
83
|
+
opener = build_opener(ProxyHandler(), NoRedirect())
|
|
84
|
+
opener.addheaders = [("User-Agent", USER_AGENT)]
|
|
85
|
+
return opener
|
|
86
|
+
|
|
87
|
+
|
|
69
88
|
def _text(value, limit, secrets=()):
|
|
70
89
|
"""One printable line: no control characters, no submitted secret or URL query, bounded length."""
|
|
71
90
|
if not isinstance(value, str):
|
|
@@ -169,7 +188,7 @@ class HttpService:
|
|
|
169
188
|
self.base = connection.api_url
|
|
170
189
|
self.secret = connection.api_key
|
|
171
190
|
self.timeout = timeout
|
|
172
|
-
self.opener =
|
|
191
|
+
self.opener = build_client_opener()
|
|
173
192
|
|
|
174
193
|
def remote_error(self, error, body=None, **options):
|
|
175
194
|
submitted = body.get("secrets") if isinstance(body, dict) else None
|
|
@@ -210,7 +229,7 @@ class HttpService:
|
|
|
210
229
|
or parts.username is not None or parts.password is not None or parts.fragment):
|
|
211
230
|
raise RemoteError('UNSAFE_ARTIFACT_REDIRECT')
|
|
212
231
|
try:
|
|
213
|
-
return Download(
|
|
232
|
+
return Download(build_client_opener().open(url, timeout=self.timeout))
|
|
214
233
|
except HTTPError as error:
|
|
215
234
|
error.close()
|
|
216
235
|
raise RemoteError('ARTIFACT_DOWNLOAD_FAILED', error.code) from None
|
|
@@ -309,7 +328,7 @@ class HttpService:
|
|
|
309
328
|
# A presigned object URL carries its own authority: use a separate opener
|
|
310
329
|
# with no Authorization / workspace / project headers and no further hops.
|
|
311
330
|
try:
|
|
312
|
-
return Download(
|
|
331
|
+
return Download(build_client_opener().open(target, timeout=self.timeout))
|
|
313
332
|
except HTTPError as error:
|
|
314
333
|
error.close()
|
|
315
334
|
raise RemoteError("ARTIFACT_DOWNLOAD_FAILED", error.code) from None
|
|
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
|
|
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
|
|
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
|
|
File without changes
|