workers-py 1.7.0__py3-none-any.whl → 1.7.2__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.
- pywrangler/cli.py +10 -2
- pywrangler/sync.py +30 -5
- pywrangler/types.py +5 -3
- pywrangler/utils.py +80 -7
- {workers_py-1.7.0.dist-info → workers_py-1.7.2.dist-info}/METADATA +1 -1
- workers_py-1.7.2.dist-info/RECORD +12 -0
- {workers_py-1.7.0.dist-info → workers_py-1.7.2.dist-info}/WHEEL +1 -1
- workers_py-1.7.0.dist-info/RECORD +0 -12
- {workers_py-1.7.0.dist-info → workers_py-1.7.2.dist-info}/entry_points.txt +0 -0
pywrangler/cli.py
CHANGED
|
@@ -2,6 +2,7 @@ import logging
|
|
|
2
2
|
import subprocess
|
|
3
3
|
import sys
|
|
4
4
|
import textwrap
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
from typing import Never
|
|
6
7
|
|
|
7
8
|
import click
|
|
@@ -11,6 +12,8 @@ from .utils import (
|
|
|
11
12
|
WRANGLER_COMMAND,
|
|
12
13
|
WRANGLER_CREATE_COMMAND,
|
|
13
14
|
check_wrangler_version,
|
|
15
|
+
log_startup_info,
|
|
16
|
+
run_command,
|
|
14
17
|
setup_logging,
|
|
15
18
|
write_success,
|
|
16
19
|
)
|
|
@@ -56,6 +59,8 @@ class ProxyToWranglerGroup(click.Group):
|
|
|
56
59
|
command = super().get_command(ctx, cmd_name)
|
|
57
60
|
|
|
58
61
|
if command is None:
|
|
62
|
+
log_startup_info()
|
|
63
|
+
|
|
59
64
|
try:
|
|
60
65
|
cmd_index = sys.argv.index(cmd_name)
|
|
61
66
|
remaining_args = sys.argv[cmd_index + 1 :]
|
|
@@ -106,6 +111,8 @@ def app(debug: bool = False) -> None:
|
|
|
106
111
|
if debug:
|
|
107
112
|
logger.setLevel(logging.DEBUG)
|
|
108
113
|
|
|
114
|
+
log_startup_info()
|
|
115
|
+
|
|
109
116
|
|
|
110
117
|
@app.command("types")
|
|
111
118
|
@click.option(
|
|
@@ -135,6 +142,7 @@ def sync_command(force: bool = False) -> None:
|
|
|
135
142
|
|
|
136
143
|
Also creates a virtual env for Workers that you can use for testing.
|
|
137
144
|
"""
|
|
145
|
+
|
|
138
146
|
sync(force, directly_requested=True)
|
|
139
147
|
write_success("Sync process completed successfully.")
|
|
140
148
|
|
|
@@ -143,7 +151,7 @@ def _proxy_to_wrangler(command_name: str, args_list: list[str]) -> Never:
|
|
|
143
151
|
command_to_run = WRANGLER_COMMAND + [command_name] + args_list
|
|
144
152
|
logger.info(f"Passing command to npx wrangler: {' '.join(command_to_run)}")
|
|
145
153
|
try:
|
|
146
|
-
process =
|
|
154
|
+
process = run_command(command_to_run, check=False, cwd=Path("."))
|
|
147
155
|
click.get_current_context().exit(process.returncode)
|
|
148
156
|
except FileNotFoundError as e:
|
|
149
157
|
logger.error(
|
|
@@ -156,7 +164,7 @@ def _proxy_to_create_cloudflare(args_list: list[str]) -> Never:
|
|
|
156
164
|
command_to_run = WRANGLER_CREATE_COMMAND + args_list
|
|
157
165
|
logger.info(f"Passing command to npx create-cloudflare: {' '.join(command_to_run)}")
|
|
158
166
|
try:
|
|
159
|
-
process =
|
|
167
|
+
process = run_command(command_to_run, check=False, cwd=Path("."))
|
|
160
168
|
click.get_current_context().exit(process.returncode)
|
|
161
169
|
except FileNotFoundError as e:
|
|
162
170
|
logger.error(
|
pywrangler/sync.py
CHANGED
|
@@ -137,7 +137,7 @@ def create_pyodide_venv() -> None:
|
|
|
137
137
|
pyodide_venv_path.parent.mkdir(parents=True, exist_ok=True)
|
|
138
138
|
interp_name = get_uv_pyodide_interp_name()
|
|
139
139
|
run_command(["uv", "python", "install", interp_name])
|
|
140
|
-
run_command(["uv", "venv", pyodide_venv_path, "--python", interp_name])
|
|
140
|
+
run_command(["uv", "venv", str(pyodide_venv_path), "--python", interp_name])
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
def parse_requirements() -> list[str]:
|
|
@@ -147,6 +147,9 @@ def parse_requirements() -> list[str]:
|
|
|
147
147
|
dependencies = pyproject_data.get("project", {}).get("dependencies", [])
|
|
148
148
|
|
|
149
149
|
logger.info(f"Found {len(dependencies)} dependencies.")
|
|
150
|
+
if dependencies:
|
|
151
|
+
for dep in dependencies:
|
|
152
|
+
logger.debug(f" - {dep}")
|
|
150
153
|
return dependencies
|
|
151
154
|
|
|
152
155
|
|
|
@@ -192,7 +195,7 @@ def _install_requirements_to_vendor(requirements: list[str]) -> None:
|
|
|
192
195
|
],
|
|
193
196
|
capture_output=True,
|
|
194
197
|
check=False,
|
|
195
|
-
env=os.environ | {"VIRTUAL_ENV": get_pyodide_venv_path()},
|
|
198
|
+
env=os.environ | {"VIRTUAL_ENV": str(get_pyodide_venv_path())},
|
|
196
199
|
)
|
|
197
200
|
if result.returncode != 0:
|
|
198
201
|
logger.warning(result.stdout.strip())
|
|
@@ -215,11 +218,16 @@ def _install_requirements_to_vendor(requirements: list[str]) -> None:
|
|
|
215
218
|
"Installation of packages into the Python Worker failed. Possibly because these packages are not currently supported. See above for details."
|
|
216
219
|
)
|
|
217
220
|
raise click.exceptions.Exit(code=result.returncode)
|
|
221
|
+
|
|
222
|
+
_log_installed_packages(get_pyodide_venv_path())
|
|
223
|
+
|
|
218
224
|
pyv = get_python_version()
|
|
219
225
|
shutil.rmtree(vendor_path)
|
|
220
|
-
|
|
221
|
-
|
|
226
|
+
|
|
227
|
+
site_packages_path = (
|
|
228
|
+
f"lib/python{pyv}/site-packages" if os.name != "nt" else "Lib/site-packages"
|
|
222
229
|
)
|
|
230
|
+
shutil.copytree(get_pyodide_venv_path() / site_packages_path, vendor_path)
|
|
223
231
|
|
|
224
232
|
# Create a pyvenv.cfg file in python_modules to mark it as a virtual environment
|
|
225
233
|
(vendor_path / "pyvenv.cfg").touch()
|
|
@@ -231,6 +239,20 @@ def _install_requirements_to_vendor(requirements: list[str]) -> None:
|
|
|
231
239
|
)
|
|
232
240
|
|
|
233
241
|
|
|
242
|
+
def _log_installed_packages(venv_path: Path) -> None:
|
|
243
|
+
result = run_command(
|
|
244
|
+
["uv", "pip", "list", "--format=freeze"],
|
|
245
|
+
env=os.environ | {"VIRTUAL_ENV": str(venv_path)},
|
|
246
|
+
capture_output=True,
|
|
247
|
+
check=False,
|
|
248
|
+
)
|
|
249
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
250
|
+
logger.debug("Installed packages:")
|
|
251
|
+
for line in result.stdout.strip().split("\n"):
|
|
252
|
+
if line.strip():
|
|
253
|
+
logger.debug(f" {line.strip()}")
|
|
254
|
+
|
|
255
|
+
|
|
234
256
|
def _install_requirements_to_venv(requirements: list[str]) -> None:
|
|
235
257
|
# Create a requirements file for .venv-workers that includes pyodide-py
|
|
236
258
|
venv_workers_path = get_venv_workers_path()
|
|
@@ -253,7 +275,7 @@ def _install_requirements_to_venv(requirements: list[str]) -> None:
|
|
|
253
275
|
requirements_file,
|
|
254
276
|
],
|
|
255
277
|
check=False,
|
|
256
|
-
env=os.environ | {"VIRTUAL_ENV": venv_workers_path},
|
|
278
|
+
env=os.environ | {"VIRTUAL_ENV": str(venv_workers_path)},
|
|
257
279
|
capture_output=True,
|
|
258
280
|
)
|
|
259
281
|
if result.returncode != 0:
|
|
@@ -312,12 +334,15 @@ def sync(force: bool = False, directly_requested: bool = False) -> None:
|
|
|
312
334
|
# Check if sync is needed based on file timestamps
|
|
313
335
|
sync_needed = force or is_sync_needed()
|
|
314
336
|
if not sync_needed:
|
|
337
|
+
logger.debug("Sync not needed - no changes detected")
|
|
315
338
|
if directly_requested:
|
|
316
339
|
logger.warning(
|
|
317
340
|
"pyproject.toml hasn't changed since last sync, use --force to ignore timestamp check"
|
|
318
341
|
)
|
|
319
342
|
return
|
|
320
343
|
|
|
344
|
+
logger.debug("Sync needed - proceeding with installation")
|
|
345
|
+
|
|
321
346
|
# Check to make sure a wrangler config file exists.
|
|
322
347
|
check_wrangler_config()
|
|
323
348
|
|
pywrangler/types.py
CHANGED
|
@@ -39,8 +39,10 @@ def wrangler_types(outdir_arg: str | None, config: str | None, /) -> None:
|
|
|
39
39
|
stubs_dir.mkdir(parents=True, exist_ok=True)
|
|
40
40
|
with TemporaryDirectory() as tmp_str:
|
|
41
41
|
tmp = Path(tmp_str)
|
|
42
|
-
run_command(WRANGLER_COMMAND + args + [tmp / "worker-configuration.d.ts"])
|
|
42
|
+
run_command(WRANGLER_COMMAND + args + [str(tmp / "worker-configuration.d.ts")])
|
|
43
43
|
(tmp / "tsconfig.json").write_text(TSCONFIG)
|
|
44
44
|
(tmp / "package.json").write_text(PACKAGE_JSON)
|
|
45
|
-
run_command(["npm", "-C", tmp, "install"])
|
|
46
|
-
run_command(
|
|
45
|
+
run_command(["npm", "-C", str(tmp), "install"])
|
|
46
|
+
run_command(
|
|
47
|
+
["npx", "@pyodide/ts-to-python", str(tmp), str(stubs_dir / "__init__.pyi")]
|
|
48
|
+
)
|
pywrangler/utils.py
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import os
|
|
3
|
+
import platform
|
|
2
4
|
import re
|
|
5
|
+
import shutil
|
|
3
6
|
import subprocess
|
|
7
|
+
import sys
|
|
4
8
|
import tomllib
|
|
9
|
+
from collections.abc import Mapping
|
|
5
10
|
from datetime import datetime
|
|
6
11
|
from functools import cache
|
|
7
12
|
from pathlib import Path
|
|
@@ -20,12 +25,47 @@ WRANGLER_CREATE_COMMAND = ["npx", "--yes", "create-cloudflare"]
|
|
|
20
25
|
|
|
21
26
|
logger = logging.getLogger(__name__)
|
|
22
27
|
|
|
23
|
-
SUCCESS_LEVEL =
|
|
24
|
-
RUNNING_LEVEL =
|
|
25
|
-
OUTPUT_LEVEL =
|
|
28
|
+
SUCCESS_LEVEL = logging.CRITICAL + 50
|
|
29
|
+
RUNNING_LEVEL = logging.DEBUG + 5
|
|
30
|
+
OUTPUT_LEVEL = logging.DEBUG + 6
|
|
26
31
|
|
|
32
|
+
# Valid log levels for PYWRANGLER_LOG environment variable
|
|
33
|
+
_LOG_LEVEL_MAP = {
|
|
34
|
+
"debug": logging.DEBUG,
|
|
35
|
+
"info": logging.INFO,
|
|
36
|
+
"warning": logging.WARNING,
|
|
37
|
+
"warn": logging.WARNING, # alias
|
|
38
|
+
"error": logging.ERROR,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def setup_logging() -> int:
|
|
43
|
+
"""
|
|
44
|
+
Configure logging with Rich handler.
|
|
45
|
+
|
|
46
|
+
Reads PYWRANGLER_LOG environment variable to set log level.
|
|
47
|
+
Valid values: debug, info, warning, warn, error (case-insensitive).
|
|
48
|
+
Defaults to INFO if not set or invalid.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
The configured logging level (e.g., logging.DEBUG, logging.INFO).
|
|
52
|
+
"""
|
|
53
|
+
# Determine log level from environment variable
|
|
54
|
+
env_level = os.environ.get("PYWRANGLER_LOG", "").lower().strip()
|
|
55
|
+
if env_level and env_level not in _LOG_LEVEL_MAP:
|
|
56
|
+
# Print warning to stderr for invalid value (before logging is configured)
|
|
57
|
+
print(
|
|
58
|
+
f"Warning: Invalid PYWRANGLER_LOG value '{env_level}'. "
|
|
59
|
+
f"Valid values: {', '.join(sorted(set(_LOG_LEVEL_MAP.keys())))}. "
|
|
60
|
+
"Defaulting to 'info'.",
|
|
61
|
+
file=sys.stderr,
|
|
62
|
+
)
|
|
63
|
+
log_level = logging.INFO
|
|
64
|
+
elif env_level:
|
|
65
|
+
log_level = _LOG_LEVEL_MAP[env_level]
|
|
66
|
+
else:
|
|
67
|
+
log_level = logging.INFO
|
|
27
68
|
|
|
28
|
-
def setup_logging() -> None:
|
|
29
69
|
console = Console(
|
|
30
70
|
theme=Theme(
|
|
31
71
|
{
|
|
@@ -39,7 +79,7 @@ def setup_logging() -> None:
|
|
|
39
79
|
|
|
40
80
|
# Configure Rich logger
|
|
41
81
|
logging.basicConfig(
|
|
42
|
-
level=
|
|
82
|
+
level=log_level,
|
|
43
83
|
format="%(message)s",
|
|
44
84
|
force=True, # Ensure this configuration is applied
|
|
45
85
|
handlers=[
|
|
@@ -52,15 +92,37 @@ def setup_logging() -> None:
|
|
|
52
92
|
logging.addLevelName(RUNNING_LEVEL, "RUNNING")
|
|
53
93
|
logging.addLevelName(OUTPUT_LEVEL, "OUTPUT")
|
|
54
94
|
|
|
95
|
+
return log_level
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _get_pywrangler_version() -> str:
|
|
99
|
+
"""Get the version of pywrangler."""
|
|
100
|
+
try:
|
|
101
|
+
from importlib.metadata import version
|
|
102
|
+
|
|
103
|
+
return version("workers-py")
|
|
104
|
+
except Exception:
|
|
105
|
+
return "unknown"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def log_startup_info() -> None:
|
|
109
|
+
"""
|
|
110
|
+
Log startup information for debugging.
|
|
111
|
+
"""
|
|
112
|
+
logger.debug(f"pywrangler version: {_get_pywrangler_version()}")
|
|
113
|
+
logger.debug(f"Python: {platform.python_version()}")
|
|
114
|
+
logger.debug(f"Platform: {sys.platform}")
|
|
115
|
+
logger.debug(f"Working directory: {Path.cwd()}")
|
|
116
|
+
|
|
55
117
|
|
|
56
118
|
def write_success(msg: str) -> None:
|
|
57
119
|
logging.log(SUCCESS_LEVEL, msg)
|
|
58
120
|
|
|
59
121
|
|
|
60
122
|
def run_command(
|
|
61
|
-
command: list[str
|
|
123
|
+
command: list[str],
|
|
62
124
|
cwd: Path | None = None,
|
|
63
|
-
env:
|
|
125
|
+
env: Mapping[str, str] | None = None,
|
|
64
126
|
check: bool = True,
|
|
65
127
|
capture_output: bool = False,
|
|
66
128
|
) -> subprocess.CompletedProcess[str]:
|
|
@@ -78,6 +140,16 @@ def run_command(
|
|
|
78
140
|
A subprocess.CompletedProcess instance.
|
|
79
141
|
"""
|
|
80
142
|
logger.log(RUNNING_LEVEL, f"{' '.join(str(arg) for arg in command)}")
|
|
143
|
+
|
|
144
|
+
# Some tools like `npm` may be a batch file on Windows (npm.cmd), and calling them only by
|
|
145
|
+
# name may fails in subprocess.run. Use shutil.which to find the real name.
|
|
146
|
+
abspath = shutil.which(command[0])
|
|
147
|
+
if not abspath:
|
|
148
|
+
logger.error(f"Command not found: {command[0]}. Is it installed and in PATH?")
|
|
149
|
+
raise click.exceptions.Exit(code=1)
|
|
150
|
+
|
|
151
|
+
realname = str(Path(command[0]).with_name(Path(abspath).name))
|
|
152
|
+
command = [realname] + command[1:]
|
|
81
153
|
try:
|
|
82
154
|
kwargs = {}
|
|
83
155
|
if capture_output:
|
|
@@ -89,6 +161,7 @@ def run_command(
|
|
|
89
161
|
env=env,
|
|
90
162
|
check=check,
|
|
91
163
|
text=True,
|
|
164
|
+
encoding="utf-8",
|
|
92
165
|
**kwargs,
|
|
93
166
|
) # type: ignore[call-overload]
|
|
94
167
|
if process.stdout and not capture_output:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: workers-py
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.2
|
|
4
4
|
Summary: A set of libraries and tools for Python Workers
|
|
5
5
|
Project-URL: Homepage, https://github.com/cloudflare/workers-py
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/cloudflare/workers-py/issues
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
pywrangler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
pywrangler/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
3
|
+
pywrangler/cli.py,sha256=61xV08_qsIAEG5RXrlkWQOM-OmpjocibM7H87jCae7Q,5594
|
|
4
|
+
pywrangler/metadata.py,sha256=ndh584ALzshSXwduTmqVczfF5Mpn7z0F9ztn3Dugf70,408
|
|
5
|
+
pywrangler/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
pywrangler/sync.py,sha256=Jrvm7yIjJBrHRfsAJDrqvAqB6CT425btjVJZGaWqwy4,12516
|
|
7
|
+
pywrangler/types.py,sha256=ZWupb2f_uLoWJcl_h6jW5lARH-ksUGwWMcDXS446-og,1225
|
|
8
|
+
pywrangler/utils.py,sha256=7wAykiTiZJ9MRfvo2-L5nIRGRHSslxCRJzPhQMUiaEw,12879
|
|
9
|
+
workers_py-1.7.2.dist-info/METADATA,sha256=ZdAd-LIXCfifsGpvnPnkWyNLBPTYPqrbDcoFSwBzFn0,1774
|
|
10
|
+
workers_py-1.7.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
11
|
+
workers_py-1.7.2.dist-info/entry_points.txt,sha256=pt6X-Nv5-gSiKUwrnvLwzlSXs9yP37m7zdTAi8f6nAM,50
|
|
12
|
+
workers_py-1.7.2.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
pywrangler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
pywrangler/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
3
|
-
pywrangler/cli.py,sha256=8C4iBntruyMkQqOb0KfH_H0QNGYYWEBtKFA7b7zGSmE,5467
|
|
4
|
-
pywrangler/metadata.py,sha256=ndh584ALzshSXwduTmqVczfF5Mpn7z0F9ztn3Dugf70,408
|
|
5
|
-
pywrangler/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
pywrangler/sync.py,sha256=TuM_bmBdgi37xYFtD62GTNwyNaDgO87QwfS-OYLR8OM,11647
|
|
7
|
-
pywrangler/types.py,sha256=hYJ6hNIjWb0faBGW82AWfCBsF_JPb7sXKCXPtFM3Mhk,1183
|
|
8
|
-
pywrangler/utils.py,sha256=mPY8LcRqYMuyVzyWS_077-4MX3K6sIThV1gY8_br9U0,10495
|
|
9
|
-
workers_py-1.7.0.dist-info/METADATA,sha256=z6R2A_5LLb2hE5xY6NOpqXxX0ooA3kexOp1BIho7qlc,1774
|
|
10
|
-
workers_py-1.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
-
workers_py-1.7.0.dist-info/entry_points.txt,sha256=pt6X-Nv5-gSiKUwrnvLwzlSXs9yP37m7zdTAi8f6nAM,50
|
|
12
|
-
workers_py-1.7.0.dist-info/RECORD,,
|
|
File without changes
|