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.
Files changed (34) hide show
  1. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/PKG-INFO +3 -3
  2. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/README.pypi.md +2 -2
  3. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/auth_login.py +3 -3
  4. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/cli.py +1 -6
  5. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/http.py +22 -3
  6. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/pyproject.toml +1 -1
  7. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/.gitignore +0 -0
  8. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/__init__.py +0 -0
  9. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/agent_runs.py +0 -0
  10. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/auth_cli.py +0 -0
  11. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/auth_workspace.py +0 -0
  12. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/cli_errors.py +0 -0
  13. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/cli_output.py +0 -0
  14. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/client.py +0 -0
  15. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/config.py +0 -0
  16. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/inference.py +0 -0
  17. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/job_logs.py +0 -0
  18. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/job_spec_cli.py +0 -0
  19. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/lifecycle_cli.py +0 -0
  20. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/navigation_resources.py +0 -0
  21. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/profile_secrets.py +0 -0
  22. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/profile_updates.py +0 -0
  23. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/resource_cli.py +0 -0
  24. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/resources.py +0 -0
  25. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/rsi_cli.py +0 -0
  26. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/sandbox.py +0 -0
  27. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/terminal.py +0 -0
  28. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train.py +0 -0
  29. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train_log_cli.py +0 -0
  30. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train_progress.py +0 -0
  31. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/train_runner_cli.py +0 -0
  32. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/training/__init__.py +0 -0
  33. {envloop_cli-1.13.0 → envloop_cli-1.14.0}/envloop/utils/__init__.py +0 -0
  34. {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.13.0
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-runner@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}},
196
- {"name": "second", "spec": {"runner": "envhub/bash-runner@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}}
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-runner@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}},
182
- {"name": "second", "spec": {"runner": "envhub/bash-runner@FULL_COMMIT", "resources": {"gpu_type": "H100", "gpus": 4}, "timeout_sec": 600}}
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 ProxyHandler, Request, build_opener
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 NoRedirect
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 build_opener(ProxyHandler(), NoRedirect()).open(request, timeout=timeout) as response:
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 = build_opener(ProxyHandler(), NoRedirect())
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(build_opener(ProxyHandler(), NoRedirect()).open(url, timeout=self.timeout))
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(build_opener(ProxyHandler(), NoRedirect()).open(target, timeout=self.timeout))
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "envloop-cli"
3
- version = "1.13.0"
3
+ version = "1.14.0"
4
4
  description = "EnvLoop CLI and Python SDK for jobs, training, checkpoints and inference"
5
5
  requires-python = ">=3.11"
6
6
  readme = "README.pypi.md"
File without changes