workers-py 1.4.0__tar.gz → 1.5.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.
Files changed (25) hide show
  1. {workers_py-1.4.0 → workers_py-1.5.1}/CHANGELOG.md +18 -0
  2. {workers_py-1.4.0 → workers_py-1.5.1}/PKG-INFO +2 -1
  3. {workers_py-1.4.0 → workers_py-1.5.1}/pyproject.toml +2 -1
  4. {workers_py-1.4.0 → workers_py-1.5.1}/src/pywrangler/cli.py +21 -3
  5. {workers_py-1.4.0 → workers_py-1.5.1}/src/pywrangler/sync.py +1 -2
  6. workers_py-1.5.1/src/pywrangler/types.py +45 -0
  7. {workers_py-1.4.0 → workers_py-1.5.1}/src/pywrangler/utils.py +2 -0
  8. {workers_py-1.4.0 → workers_py-1.5.1}/tests/test_cli.py +1 -4
  9. workers_py-1.5.1/tests/test_types.py +61 -0
  10. {workers_py-1.4.0 → workers_py-1.5.1}/uv.lock +47 -4
  11. {workers_py-1.4.0 → workers_py-1.5.1}/.github/workflows/commitlint.yml +0 -0
  12. {workers_py-1.4.0 → workers_py-1.5.1}/.github/workflows/lint.yml +0 -0
  13. {workers_py-1.4.0 → workers_py-1.5.1}/.github/workflows/release.yml +0 -0
  14. {workers_py-1.4.0 → workers_py-1.5.1}/.github/workflows/tests.yml +0 -0
  15. {workers_py-1.4.0 → workers_py-1.5.1}/.gitignore +0 -0
  16. {workers_py-1.4.0 → workers_py-1.5.1}/.pre-commit-config.yaml +0 -0
  17. {workers_py-1.4.0 → workers_py-1.5.1}/CLAUDE.md +0 -0
  18. {workers_py-1.4.0 → workers_py-1.5.1}/CONTRIBUTING.md +0 -0
  19. {workers_py-1.4.0 → workers_py-1.5.1}/README.md +0 -0
  20. {workers_py-1.4.0 → workers_py-1.5.1}/src/pywrangler/__init__.py +0 -0
  21. {workers_py-1.4.0 → workers_py-1.5.1}/src/pywrangler/__main__.py +0 -0
  22. {workers_py-1.4.0 → workers_py-1.5.1}/src/pywrangler/metadata.py +0 -0
  23. {workers_py-1.4.0 → workers_py-1.5.1}/tests/__init__.py +0 -0
  24. {workers_py-1.4.0 → workers_py-1.5.1}/tests/test_py_version_detect.py +0 -0
  25. {workers_py-1.4.0 → workers_py-1.5.1}/workers.py +0 -0
@@ -2,6 +2,24 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.5.1 (2025-10-13)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Fix default value for --outdir in help message
10
+ ([#39](https://github.com/cloudflare/workers-py/pull/39),
11
+ [`7aded7a`](https://github.com/cloudflare/workers-py/commit/7aded7a43580fc50b6408baee0184fa814481c9b))
12
+
13
+
14
+ ## v1.5.0 (2025-10-10)
15
+
16
+ ### Features
17
+
18
+ - Implement pywrangler types to generate Python type stubs
19
+ ([#38](https://github.com/cloudflare/workers-py/pull/38),
20
+ [`39b67bd`](https://github.com/cloudflare/workers-py/commit/39b67bd24ed3916de12aa9025703ed18fe4a73cd))
21
+
22
+
5
23
  ## v1.4.0 (2025-10-10)
6
24
 
7
25
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workers-py
3
- Version: 1.4.0
3
+ Version: 1.5.1
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
@@ -11,6 +11,7 @@ Requires-Python: >=3.10
11
11
  Requires-Dist: click<9.0.0,>=8.0.0
12
12
  Requires-Dist: pyjson5>=1.6.0
13
13
  Requires-Dist: pyodide-cli
14
+ Requires-Dist: pyodide-py
14
15
  Requires-Dist: rich>=13.0.0
15
16
  Provides-Extra: build
16
17
  Requires-Dist: uv~=0.5.23; extra == 'build'
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "workers-py"
7
- version = "1.4.0"
7
+ version = "1.5.1"
8
8
  description = "A set of libraries and tools for Python Workers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -18,6 +18,7 @@ dependencies = [
18
18
  "rich>=13.0.0",
19
19
  "pyodide-cli",
20
20
  "pyjson5>=1.6.0",
21
+ "pyodide-py",
21
22
  ]
22
23
 
23
24
  [dependency-groups]
@@ -4,13 +4,11 @@ import sys
4
4
  import textwrap
5
5
  import click
6
6
 
7
- from pywrangler.utils import setup_logging, write_success
7
+ from .utils import setup_logging, write_success, WRANGLER_COMMAND
8
8
 
9
9
  setup_logging()
10
10
  logger = logging.getLogger("pywrangler")
11
11
 
12
- WRANGLER_COMMAND = ["npx", "--yes", "wrangler"]
13
-
14
12
 
15
13
  class ProxyToWranglerGroup(click.Group):
16
14
  def get_help(self, ctx):
@@ -95,6 +93,26 @@ def app(ctx, debug=False):
95
93
  logger.setLevel(logging.DEBUG)
96
94
 
97
95
 
96
+ @app.command("types")
97
+ @click.option(
98
+ "-o",
99
+ "--outdir",
100
+ type=click.Path(writable=True),
101
+ help="The output directory to write the generated types. Default: ./src",
102
+ )
103
+ @click.option(
104
+ "-c",
105
+ "--config",
106
+ type=click.Path(exists=True, dir_okay=False, readable=True),
107
+ help="Path to Wrangler configuration file",
108
+ )
109
+ def types_command(outdir=None, config=None):
110
+ from .types import wrangler_types
111
+
112
+ wrangler_types(outdir, config)
113
+ raise click.exceptions.Exit(code=0)
114
+
115
+
98
116
  @app.command("sync")
99
117
  @click.option("--force", is_flag=True, help="Force sync even if no changes detected")
100
118
  def sync_command(force=False, directly_requested=True):
@@ -377,10 +377,9 @@ def _install_requirements_to_vendor(requirements: list[str]):
377
377
 
378
378
 
379
379
  def _install_requirements_to_venv(requirements: list[str]):
380
- # Create a requirements file for .venv-workers that includes webtypy and pyodide-py
380
+ # Create a requirements file for .venv-workers that includes pyodide-py
381
381
  relative_venv_workers_path = VENV_WORKERS_PATH.relative_to(PROJECT_ROOT)
382
382
  requirements = requirements.copy()
383
- requirements.append("webtypy")
384
383
  requirements.append("pyodide-py")
385
384
 
386
385
  logger.info(
@@ -0,0 +1,45 @@
1
+ from .utils import WRANGLER_COMMAND, run_command
2
+ from tempfile import TemporaryDirectory
3
+ from pathlib import Path
4
+ import logging
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ TSCONFIG = """
9
+ {
10
+ "compilerOptions": {
11
+ "target": "esnext",
12
+ "module": "esnext",
13
+ "moduleResolution": "nodenext",
14
+ "lib": ["esnext"]
15
+ },
16
+ "include": ["worker-configuration.d.ts"]
17
+ }
18
+ """
19
+
20
+ PACKAGE_JSON = """
21
+ {
22
+ "dependencies": {
23
+ "typescript": "^5.3.2"
24
+ }
25
+ }
26
+ """
27
+
28
+
29
+ def wrangler_types(outdir_arg: str | None, config: str | None, /):
30
+ args = ["types"]
31
+ if config:
32
+ args += ["--config", config]
33
+ if outdir_arg is None:
34
+ outdir = Path("src")
35
+ else:
36
+ outdir = Path(outdir_arg)
37
+ stubs_dir = outdir / "js-stubs"
38
+ stubs_dir.mkdir(parents=True, exist_ok=True)
39
+ with TemporaryDirectory() as tmp_str:
40
+ tmp = Path(tmp_str)
41
+ run_command(WRANGLER_COMMAND + args + [tmp / "worker-configuration.d.ts"])
42
+ (tmp / "tsconfig.json").write_text(TSCONFIG)
43
+ (tmp / "package.json").write_text(PACKAGE_JSON)
44
+ run_command(["npm", "-C", tmp, "install"])
45
+ run_command(["npx", "@pyodide/ts-to-python", tmp, stubs_dir / "__init__.pyi"])
@@ -6,6 +6,8 @@ import click
6
6
  from rich.logging import Console, RichHandler
7
7
  from rich.theme import Theme
8
8
 
9
+ WRANGLER_COMMAND = ["npx", "--yes", "wrangler"]
10
+
9
11
  logger = logging.getLogger(__name__)
10
12
 
11
13
  SUCCESS_LEVEL = 100
@@ -213,10 +213,7 @@ def test_sync_command_integration(dependencies, clean_test_dir):
213
213
  "site-packages directory does not exist in .venv-workers"
214
214
  )
215
215
 
216
- # Check that webtypy and pyodide-py are installed (should always be installed, even if no deps are specified)
217
- assert is_package_installed(site_packages_path, "webtypy"), (
218
- "webtypy package was not installed in .venv-workers"
219
- )
216
+ # Check that pyodide-py is installed (should always be installed, even if no deps are specified)
220
217
  assert is_package_installed(site_packages_path, "pyodide-py"), (
221
218
  "pyodide-py package was not installed in .venv-workers"
222
219
  )
@@ -0,0 +1,61 @@
1
+ from contextlib import chdir
2
+ from subprocess import run
3
+
4
+
5
+ # Import the full module so we can patch constants
6
+ from pywrangler.types import wrangler_types
7
+
8
+
9
+ WRANGLER_TOML = """
10
+ compatibility_date = "2025-08-14"
11
+
12
+ kv_namespaces = [
13
+ { binding = "FOO", id = "<YOUR_KV_NAMESPACE_ID>" }
14
+ ]
15
+ """
16
+
17
+ PYPROJECT_TOML = """
18
+ [dependency-groups]
19
+ dev = [
20
+ "mypy>=1.17.1",
21
+ "pyodide-py",
22
+ ]
23
+
24
+ [tool.mypy]
25
+ files = [
26
+ "src",
27
+ ]
28
+ """
29
+
30
+ WORKER = """
31
+ from typing import TYPE_CHECKING
32
+ if TYPE_CHECKING:
33
+ from js import Env
34
+
35
+ class Default:
36
+ env: "Env"
37
+ async def fetch(self) -> None:
38
+ reveal_type(self.env.FOO) # Revealed type is "js.KVNamespace_iface"
39
+ bar = await self.env.FOO.get("bar")
40
+ reveal_type(bar) # Revealed type is "builtins.str | None"
41
+ """
42
+
43
+
44
+ def test_types(tmp_path):
45
+ config_path = tmp_path / "wrangler.toml"
46
+ pyproject_path = tmp_path / "pyproject.toml"
47
+ worker_dir = tmp_path / "src/worker"
48
+ worker_path = worker_dir / "entry.py"
49
+
50
+ worker_dir.mkdir(parents=True)
51
+ worker_path.write_text(WORKER)
52
+ config_path.write_text(WRANGLER_TOML)
53
+ pyproject_path.write_text(PYPROJECT_TOML)
54
+
55
+ with chdir(tmp_path):
56
+ wrangler_types(None, None)
57
+ result = run(["uv", "run", "mypy"], capture_output=True, text=True)
58
+
59
+ assert 'Revealed type is "js.KVNamespace_iface"' in result.stdout
60
+ assert 'Revealed type is "builtins.str | None"' in result.stdout
61
+ assert "Success: no issues found" in result.stdout
@@ -1,7 +1,8 @@
1
1
  version = 1
2
2
  requires-python = ">=3.10"
3
3
  resolution-markers = [
4
- "python_full_version >= '3.12'",
4
+ "python_full_version >= '3.13'",
5
+ "python_full_version == '3.12.*'",
5
6
  "python_full_version < '3.12'",
6
7
  ]
7
8
 
@@ -54,7 +55,8 @@ name = "click"
54
55
  version = "8.1.8"
55
56
  source = { registry = "https://pypi.org/simple" }
56
57
  resolution-markers = [
57
- "python_full_version >= '3.12'",
58
+ "python_full_version >= '3.13'",
59
+ "python_full_version == '3.12.*'",
58
60
  ]
59
61
  dependencies = [
60
62
  { name = "colorama", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" },
@@ -424,7 +426,8 @@ name = "pyodide-cli"
424
426
  version = "0.3.0"
425
427
  source = { registry = "https://pypi.org/simple" }
426
428
  resolution-markers = [
427
- "python_full_version >= '3.12'",
429
+ "python_full_version >= '3.13'",
430
+ "python_full_version == '3.12.*'",
428
431
  ]
429
432
  dependencies = [
430
433
  { name = "rich", marker = "python_full_version >= '3.12'" },
@@ -435,6 +438,42 @@ wheels = [
435
438
  { url = "https://files.pythonhosted.org/packages/b4/93/b9815f6f4ef30dd8490bea2a82aa664e5aa9162fa38986b35a0898522d22/pyodide_cli-0.3.0-py3-none-any.whl", hash = "sha256:9d2736e04ddb380fd7eac664e5e4ba23d2c1dd29ed38a98b6246ec529ffc834a", size = 11630 },
436
439
  ]
437
440
 
441
+ [[package]]
442
+ name = "pyodide-py"
443
+ version = "0.25.1"
444
+ source = { registry = "https://pypi.org/simple" }
445
+ resolution-markers = [
446
+ "python_full_version < '3.12'",
447
+ ]
448
+ sdist = { url = "https://files.pythonhosted.org/packages/06/b5/bd547175f2f91ff9afb79d5fcd8604c8b59295ae2161985a782194f220e6/pyodide-py-0.25.1.tar.gz", hash = "sha256:844fc310585118efbc1daeb4390bb7aecdf1d9fb508c4aa9f21588842c1c8a4e", size = 43322 }
449
+ wheels = [
450
+ { url = "https://files.pythonhosted.org/packages/1c/e6/f16847dae08ce4e1d544c66336561c38b883613e1bb6fa61491bae7a1b5c/pyodide_py-0.25.1-py3-none-any.whl", hash = "sha256:bfd93301ee0ee022e6cbcee5a3a9a28b34a2f7348ebb06186df1514be79e5499", size = 48290 },
451
+ ]
452
+
453
+ [[package]]
454
+ name = "pyodide-py"
455
+ version = "0.27.7"
456
+ source = { registry = "https://pypi.org/simple" }
457
+ resolution-markers = [
458
+ "python_full_version == '3.12.*'",
459
+ ]
460
+ sdist = { url = "https://files.pythonhosted.org/packages/9d/99/d7b3c9137de5a76a63f2ef89d43c878dcb4dce8118866fb58d26290698f9/pyodide_py-0.27.7.tar.gz", hash = "sha256:afb68f8abf503f691a4ab5d2ffdbf6dd05117920508e1161e04a34737c649d36", size = 52051 }
461
+ wheels = [
462
+ { url = "https://files.pythonhosted.org/packages/24/c5/825f73fb815a17838bef3342999247bea1100a0b2e576e5c17b2bdd68766/pyodide_py-0.27.7-py3-none-any.whl", hash = "sha256:2fa7db63a14720e548eb6174d492643424f8b5f21d43b7c9fecb6d712187fe6a", size = 57930 },
463
+ ]
464
+
465
+ [[package]]
466
+ name = "pyodide-py"
467
+ version = "0.28.3"
468
+ source = { registry = "https://pypi.org/simple" }
469
+ resolution-markers = [
470
+ "python_full_version >= '3.13'",
471
+ ]
472
+ sdist = { url = "https://files.pythonhosted.org/packages/2d/59/95d573e0d967af70d8823552c1efee19eb2dfbca23de9ca139516c98c5d1/pyodide_py-0.28.3.tar.gz", hash = "sha256:e521d9714eb57b163e0aadca40b85870a8ea949cb03443c0e5f3ed7d45cd3a98", size = 52898 }
473
+ wheels = [
474
+ { url = "https://files.pythonhosted.org/packages/4a/2a/2cca0a4e52a9495f21cab634b58dc413fddf72faf5baed9d2c8741544631/pyodide_py-0.28.3-py3-none-any.whl", hash = "sha256:de6ba9db35ed1ef75b80a70cf11dafa373ad786f95f72e9dbe46ffaf8cdea23c", size = 58853 },
475
+ ]
476
+
438
477
  [[package]]
439
478
  name = "pytest"
440
479
  version = "8.3.5"
@@ -650,7 +689,7 @@ wheels = [
650
689
 
651
690
  [[package]]
652
691
  name = "workers-py"
653
- version = "1.4.0"
692
+ version = "1.5.1"
654
693
  source = { editable = "." }
655
694
  dependencies = [
656
695
  { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
@@ -658,6 +697,9 @@ dependencies = [
658
697
  { name = "pyjson5" },
659
698
  { name = "pyodide-cli", version = "0.2.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
660
699
  { name = "pyodide-cli", version = "0.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
700
+ { name = "pyodide-py", version = "0.25.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
701
+ { name = "pyodide-py", version = "0.27.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.12.*'" },
702
+ { name = "pyodide-py", version = "0.28.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
661
703
  { name = "rich" },
662
704
  ]
663
705
 
@@ -682,6 +724,7 @@ requires-dist = [
682
724
  { name = "click", specifier = ">=8.0.0,<9.0.0" },
683
725
  { name = "pyjson5", specifier = ">=1.6.0" },
684
726
  { name = "pyodide-cli" },
727
+ { name = "pyodide-py" },
685
728
  { name = "rich", specifier = ">=13.0.0" },
686
729
  { name = "uv", marker = "extra == 'build'", specifier = "~=0.5.23" },
687
730
  ]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes