envloop-cli 0.1.0__tar.gz → 0.1.1__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-0.1.0 → envloop_cli-0.1.1}/PKG-INFO +8 -4
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/README.md +7 -3
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/pyproject.toml +1 -1
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/src/el_cli/http.py +13 -2
- envloop_cli-0.1.1/tests/test_http_proxy.py +59 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/.gitignore +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/src/el_cli/__init__.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/src/el_cli/cli.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/src/el_cli/client.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/src/el_cli/train.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/src/el_cli/utils/__init__.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/src/el_cli/utils/logging.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/tests/test_bearer.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/tests/test_cli_help.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/tests/test_job_submit_cli.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/tests/test_jobs_http.py +0 -0
- {envloop_cli-0.1.0 → envloop_cli-0.1.1}/tests/test_train_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: envloop-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Standalone el command-line client for EnvLoop
|
|
5
5
|
Project-URL: Repository, https://github.com/EnvLoop/envloop
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -8,7 +8,7 @@ Description-Content-Type: text/markdown
|
|
|
8
8
|
|
|
9
9
|
# envloop-cli
|
|
10
10
|
|
|
11
|
-
Independent Python 3.11+ project providing the existing `el` CLI, version 0.1.
|
|
11
|
+
Independent Python 3.11+ project providing the existing `el` CLI, version 0.1.1.
|
|
12
12
|
It builds and installs without the envloop SDK checkout or any third-party runtime
|
|
13
13
|
dependencies. The distribution is `envloop-cli`; its private implementation package
|
|
14
14
|
is `el_cli`, so it does not overwrite the `envloop` SDK namespace.
|
|
@@ -16,12 +16,16 @@ is `el_cli`, so it does not overwrite the `envloop` SDK namespace.
|
|
|
16
16
|
After publication:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
pip install envloop-cli==0.1.
|
|
19
|
+
pip install envloop-cli==0.1.1
|
|
20
20
|
el --help
|
|
21
21
|
el train --help
|
|
22
22
|
el --api-url https://api.envloop.ai --workspace-id YOUR_WORKSPACE train job list
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
HTTP requests use system proxies by default (`HTTPS_PROXY` / `HTTP_PROXY`,
|
|
26
|
+
with `ALL_PROXY` as a fallback); lowercase equivalents and `NO_PROXY` are
|
|
27
|
+
honored. Without a configured proxy, requests connect directly.
|
|
28
|
+
|
|
25
29
|
Set `ENVLOOP_API_KEY` privately in your environment. Existing command names,
|
|
26
30
|
arguments, JSON output, error codes and `envloop/0.1` User-Agent are preserved.
|
|
27
31
|
Local Task/Profile commands still require a separately installed compatible
|
|
@@ -65,7 +69,7 @@ uv run --locked pytest -q --ignore=tests/test_jobs_http.py
|
|
|
65
69
|
uv run --locked ruff check .
|
|
66
70
|
uv build
|
|
67
71
|
python -m venv /tmp/el-cli-clean
|
|
68
|
-
/tmp/el-cli-clean/bin/python -m pip install dist/envloop_cli-0.1.
|
|
72
|
+
/tmp/el-cli-clean/bin/python -m pip install dist/envloop_cli-0.1.1-py3-none-any.whl
|
|
69
73
|
/tmp/el-cli-clean/bin/el --help
|
|
70
74
|
/tmp/el-cli-clean/bin/el train --help
|
|
71
75
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# envloop-cli
|
|
2
2
|
|
|
3
|
-
Independent Python 3.11+ project providing the existing `el` CLI, version 0.1.
|
|
3
|
+
Independent Python 3.11+ project providing the existing `el` CLI, version 0.1.1.
|
|
4
4
|
It builds and installs without the envloop SDK checkout or any third-party runtime
|
|
5
5
|
dependencies. The distribution is `envloop-cli`; its private implementation package
|
|
6
6
|
is `el_cli`, so it does not overwrite the `envloop` SDK namespace.
|
|
@@ -8,12 +8,16 @@ is `el_cli`, so it does not overwrite the `envloop` SDK namespace.
|
|
|
8
8
|
After publication:
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
pip install envloop-cli==0.1.
|
|
11
|
+
pip install envloop-cli==0.1.1
|
|
12
12
|
el --help
|
|
13
13
|
el train --help
|
|
14
14
|
el --api-url https://api.envloop.ai --workspace-id YOUR_WORKSPACE train job list
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
HTTP requests use system proxies by default (`HTTPS_PROXY` / `HTTP_PROXY`,
|
|
18
|
+
with `ALL_PROXY` as a fallback); lowercase equivalents and `NO_PROXY` are
|
|
19
|
+
honored. Without a configured proxy, requests connect directly.
|
|
20
|
+
|
|
17
21
|
Set `ENVLOOP_API_KEY` privately in your environment. Existing command names,
|
|
18
22
|
arguments, JSON output, error codes and `envloop/0.1` User-Agent are preserved.
|
|
19
23
|
Local Task/Profile commands still require a separately installed compatible
|
|
@@ -57,7 +61,7 @@ uv run --locked pytest -q --ignore=tests/test_jobs_http.py
|
|
|
57
61
|
uv run --locked ruff check .
|
|
58
62
|
uv build
|
|
59
63
|
python -m venv /tmp/el-cli-clean
|
|
60
|
-
/tmp/el-cli-clean/bin/python -m pip install dist/envloop_cli-0.1.
|
|
64
|
+
/tmp/el-cli-clean/bin/python -m pip install dist/envloop_cli-0.1.1-py3-none-any.whl
|
|
61
65
|
/tmp/el-cli-clean/bin/el --help
|
|
62
66
|
/tmp/el-cli-clean/bin/el train --help
|
|
63
67
|
```
|
|
@@ -7,7 +7,13 @@ import os
|
|
|
7
7
|
import re
|
|
8
8
|
from urllib.error import HTTPError, URLError
|
|
9
9
|
from urllib.parse import quote, urlencode, urlsplit
|
|
10
|
-
from urllib.request import
|
|
10
|
+
from urllib.request import (
|
|
11
|
+
HTTPRedirectHandler,
|
|
12
|
+
ProxyHandler,
|
|
13
|
+
Request,
|
|
14
|
+
build_opener,
|
|
15
|
+
getproxies,
|
|
16
|
+
)
|
|
11
17
|
|
|
12
18
|
|
|
13
19
|
class RemoteError(RuntimeError):
|
|
@@ -50,7 +56,12 @@ class HttpService:
|
|
|
50
56
|
self.headers["X-Workspace-ID"] = workspace
|
|
51
57
|
self.base = base_url.rstrip("/").removesuffix("/v1")
|
|
52
58
|
self.timeout = timeout
|
|
53
|
-
|
|
59
|
+
proxies = getproxies()
|
|
60
|
+
# urllib discovers ALL_PROXY but does not apply it to HTTP(S).
|
|
61
|
+
if proxies.get("all"):
|
|
62
|
+
for scheme in ("http", "https"):
|
|
63
|
+
proxies.setdefault(scheme, proxies["all"])
|
|
64
|
+
self.opener = build_opener(ProxyHandler(proxies), NoRedirect())
|
|
54
65
|
|
|
55
66
|
def request(self, method, path, body=None):
|
|
56
67
|
request = Request(self.base + path,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Regression coverage using a local proxy/API at the network boundary."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import threading
|
|
6
|
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from el_cli.cli import main
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.mark.parametrize('proxy_variable', ['HTTP_PROXY', 'http_proxy', 'ALL_PROXY'])
|
|
14
|
+
def test_train_list_uses_environment_proxy(proxy_variable, monkeypatch, capsys):
|
|
15
|
+
run_list(monkeypatch, capsys, proxy_variable=proxy_variable)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.parametrize('bypass', [False, True])
|
|
19
|
+
def test_train_list_connects_directly(monkeypatch, capsys, bypass):
|
|
20
|
+
run_list(monkeypatch, capsys, bypass=bypass)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def run_list(monkeypatch, capsys, *, proxy_variable=None, bypass=False):
|
|
24
|
+
for name in os.environ:
|
|
25
|
+
if name.lower().endswith('_proxy'):
|
|
26
|
+
monkeypatch.delenv(name)
|
|
27
|
+
monkeypatch.setenv('NO_PROXY', '127.0.0.1' if bypass else '')
|
|
28
|
+
seen = []
|
|
29
|
+
|
|
30
|
+
class Handler(BaseHTTPRequestHandler):
|
|
31
|
+
def do_GET(self):
|
|
32
|
+
seen.append(self.path)
|
|
33
|
+
self.send_response(200)
|
|
34
|
+
self.end_headers()
|
|
35
|
+
self.wfile.write(b'{"items":[]}')
|
|
36
|
+
|
|
37
|
+
def log_message(self, *args):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
server = ThreadingHTTPServer(('127.0.0.1', 0), Handler)
|
|
41
|
+
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
|
42
|
+
thread.start()
|
|
43
|
+
base = f'http://127.0.0.1:{server.server_port}'
|
|
44
|
+
if proxy_variable:
|
|
45
|
+
monkeypatch.setenv(proxy_variable, base)
|
|
46
|
+
origin = 'http://127.0.0.1:1'
|
|
47
|
+
else:
|
|
48
|
+
origin = base
|
|
49
|
+
if bypass:
|
|
50
|
+
monkeypatch.setenv('HTTP_PROXY', 'http://127.0.0.1:1')
|
|
51
|
+
try:
|
|
52
|
+
assert main(['--api-url', origin, 'train', 'job', 'list']) == 0
|
|
53
|
+
assert json.loads(capsys.readouterr().out) == {'items': []}
|
|
54
|
+
path = '/v1/train/jobs?limit=25'
|
|
55
|
+
assert seen == [origin + path if proxy_variable else path]
|
|
56
|
+
finally:
|
|
57
|
+
server.shutdown()
|
|
58
|
+
server.server_close()
|
|
59
|
+
thread.join()
|
|
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
|