From 5d3cc8afeae9fef505174f64ffcaf933294ea7b3 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 11:31:42 +0000 Subject: [PATCH 01/14] Add lockfile-dir flag --- .github/workflows/build.yaml | 2 +- COMPATIBILITY.md | 21 +++++++++++---------- pytest_pyodide/config.py | 23 +++++++++++++++++------ pytest_pyodide/decorator.py | 2 +- pytest_pyodide/hook.py | 15 +++++++++++++++ pytest_pyodide/utils.py | 10 +++++----- tests/test_options.py | 20 ++++++++++++++++++++ 7 files changed, 70 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a6c12813..c926285d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -15,7 +15,7 @@ jobs: with: build-artifact-name: none build-artifact-path: none - pyodide-versions: "0.27.2,0.26.4" + pyodide-versions: "0.28.0a3" deploy: runs-on: ubuntu-24.04 diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index d69621e3..f16d8263 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -5,14 +5,15 @@ Other versions may work, however with no guarantee. | pytest-pyodide | Tested Pyodide versions | | -------------- | ----------------------- | -| main branch | 0.26.4, 0.27.2 | -| 0.58.* | 0.24.1, 0.25.1, 0.26.1 | -| 0.57.* | 0.23.4, 0.24.1, 0.25.1 | -| 0.56.* | 0.23.4, 0.24.1 | -| 0.55.* | 0.23.4, 0.24.1 | -| 0.54.* | 0.23.4, 0.24.1 | -| 0.53.* | 0.23.2, 0.22.0 | -| 0.52.* | 0.23.2, 0.22.0 | -| 0.51.* | 0.23.2, 0.22.0, 0.21.3 | -| 0.50.* | 0.22.0, 0.21.3 | +| main branch | 0.28.0a3 | +| 0.58.6 | 0.26.4, 0.27.2 | +| 0.58.1-5 | 0.24.1, 0.25.1, 0.26.1 | +| 0.57.* | 0.23.4, 0.24.1, 0.25.1 | +| 0.56.* | 0.23.4, 0.24.1 | +| 0.55.* | 0.23.4, 0.24.1 | +| 0.54.* | 0.23.4, 0.24.1 | +| 0.53.* | 0.23.2, 0.22.0 | +| 0.52.* | 0.23.2, 0.22.0 | +| 0.51.* | 0.23.2, 0.22.0, 0.21.3 | +| 0.50.* | 0.22.0, 0.21.3 | | 0.23.* | 0.21.0 | diff --git a/pytest_pyodide/config.py b/pytest_pyodide/config.py index 0ed7c6b8..01cd3d74 100644 --- a/pytest_pyodide/config.py +++ b/pytest_pyodide/config.py @@ -5,10 +5,12 @@ from collections.abc import Iterable, Sequence from typing import Literal +from .hook import pytest_wrapper + RUNTIMES = Literal["chrome", "firefox", "node", "safari"] _global_load_pyodide_script = """ -let pyodide = await loadPyodide({ fullStdLib: false, jsglobals : self }); +let pyodide = await loadPyodide({ fullStdLib: false, jsglobals : self, lockFileURL: "%s" }); """ @@ -22,12 +24,16 @@ def __init__(self): "safari": [], } + global_load_pyodide_script = _global_load_pyodide_script % ( + pytest_wrapper.pyodide_lockfile_dir / "pyodide-lock.json" + ) + # The script to be executed to load the Pyodide. self.load_pyodide_script: dict[RUNTIMES, str] = { - "chrome": _global_load_pyodide_script, - "firefox": _global_load_pyodide_script, - "node": _global_load_pyodide_script, - "safari": _global_load_pyodide_script, + "chrome": global_load_pyodide_script, + "firefox": global_load_pyodide_script, + "node": global_load_pyodide_script, + "safari": global_load_pyodide_script, } # The script to be executed to initialize the runtime. @@ -59,11 +65,16 @@ def get_node_extra_globals(self) -> Sequence[str]: return self.node_extra_globals -SINGLETON = Config() +SINGLETON = None def get_global_config() -> Config: """ Return the singleton config object. """ + global SINGLETON + if not isinstance(SINGLETON, Config): + # lazy initialization so that the global config object can use the pytest configs + SINGLETON = Config() + return SINGLETON diff --git a/pytest_pyodide/decorator.py b/pytest_pyodide/decorator.py index dcbf365b..7a4e546b 100644 --- a/pytest_pyodide/decorator.py +++ b/pytest_pyodide/decorator.py @@ -17,7 +17,7 @@ def package_is_built(package_name: str): - return _package_is_built(package_name, pytest_wrapper.pyodide_dist_dir) + return _package_is_built(package_name, pytest_wrapper.pyodide_lockfile_dir) class SeleniumType(Protocol): diff --git a/pytest_pyodide/hook.py b/pytest_pyodide/hook.py index c95f61b8..9a929748 100644 --- a/pytest_pyodide/hook.py +++ b/pytest_pyodide/hook.py @@ -39,6 +39,7 @@ class PytestWrapper: pyodide_run_host_test: bool pyodide_runtimes: set[str] pyodide_dist_dir: Path + pyodide_lockfile_dir: Path pyodide_options_stack: list[tuple[bool, set[str], Path]] def __setattr__(self, name, value): @@ -123,11 +124,16 @@ def pytest_configure(config): pytest_wrapper.pyodide_run_host_test, pytest_wrapper.pyodide_runtimes, pytest_wrapper.pyodide_dist_dir, + pytest_wrapper.pyodide_lockfile_dir, ) ) pytest_wrapper.pyodide_run_host_test = run_host pytest_wrapper.pyodide_runtimes = runtimes pytest_wrapper.pyodide_dist_dir = config.option.dist_dir + if config.option.lockfile_path is None: + pytest_wrapper.pyodide_lockfile_dir = config.option.dist_dir + else: + pytest_wrapper.pyodide_lockfile_dir = config.option.lockfile_dir def pytest_unconfigure(config): @@ -137,6 +143,7 @@ def pytest_unconfigure(config): pytest_wrapper.pyodide_run_host_test, pytest_wrapper.pyodide_runtimes, pytest_wrapper.pyodide_dist_dir, + pytest_wrapper.pyodide_lockfile_dir, ) = pytest_wrapper.pyodide_options_stack.pop() except IndexError: pass @@ -153,6 +160,14 @@ def pytest_addoption(parser): help="Path to the pyodide dist directory", type=Path, ) + group.addoption( + "--lockfile-dir", + dest="lockfile_dir", + action="store", + default=None, + help="Path to the directory where the pyodide lockfile is stored. Defaults to the dist directory.", + type=Path, + ) group.addoption( "--runner", default="selenium", diff --git a/pytest_pyodide/utils.py b/pytest_pyodide/utils.py index 3350e20d..963b8fd1 100644 --- a/pytest_pyodide/utils.py +++ b/pytest_pyodide/utils.py @@ -40,16 +40,16 @@ def parse_xfail_browsers(node) -> dict[str, str]: @functools.cache -def built_packages(dist_dir: Path) -> list[str]: +def built_packages(lockfile_dir: Path) -> list[str]: """Returns the list of built package names from repodata.json""" - repodata_path = dist_dir / "pyodide-lock.json" + repodata_path = lockfile_dir / "pyodide-lock.json" if not repodata_path.exists(): # Try again for backwards compatibility - repodata_path = dist_dir / "repodata.json" + repodata_path = lockfile_dir / "repodata.json" if not repodata_path.exists(): return [] return list(json.loads(repodata_path.read_text())["packages"].keys()) -def package_is_built(package_name: str, dist_dir: Path) -> bool: - return package_name.lower() in built_packages(dist_dir) +def package_is_built(package_name: str, lockfile_dir: Path) -> bool: + return package_name.lower() in built_packages(lockfile_dir) diff --git a/tests/test_options.py b/tests/test_options.py index 930e5c41..3ceebd1f 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -21,6 +21,21 @@ def test_option(request): result.assert_outcomes(passed=1) +def test_lockfile_dir(pytester): + lockfile_dir = str(Path("lockfile").resolve()) + + pytester.makepyfile( + f""" + import pytest + def test_option(request): + assert str(request.config.getoption("--lockfile-dir", "")) == {lockfile_dir!r} + """ + ) + + result = pytester.runpytest("--lockfile-dir", "lockfile") + result.assert_outcomes(passed=1) + + @pytest.mark.parametrize("runner", ["selenium", "playwright"]) def test_runner(pytester, runner): pytester.makepyfile( @@ -102,12 +117,14 @@ def test_options_pytester(): assert pytest.pyodide_run_host_test == True assert pytest.pyodide_runtimes == set(["chrome","firefox","safari","node"]) assert pytest.pyodide_dist_dir == Path("some_weird_dir").resolve() + assert pytest.pyodide_lockfile_dir == Path("some_other_dir").resolve() """ ) ) run_host = pytest.pyodide_run_host_test runtimes = pytest.pyodide_runtimes dist_dir = pytest.pyodide_dist_dir + lockfile_dir = pytest.pyodide_lockfile_dir result = pytester.runpytest( "--dist-dir", @@ -116,9 +133,12 @@ def test_options_pytester(): "chrome,firefox,safari,node", "--dist-dir", "some_weird_dir", + "--lockfile-dir", + "some_other_dir", ) result.assert_outcomes(passed=1) assert run_host == pytest.pyodide_run_host_test assert runtimes == pytest.pyodide_runtimes assert dist_dir == pytest.pyodide_dist_dir + assert lockfile_dir == pytest.pyodide_lockfile_dir From c46c93db72ec1702428aff93bee6c3043a26d952 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 11:34:57 +0000 Subject: [PATCH 02/14] python version --- .github/workflows/main.yaml | 2 +- .github/workflows/testall.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 23ba3865..30d9b151 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -102,7 +102,7 @@ jobs: - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: - python-version: 3.12 + python-version: 3.13 - name: install pyodide-py run: | diff --git a/.github/workflows/testall.yaml b/.github/workflows/testall.yaml index f4d32454..0f235461 100644 --- a/.github/workflows/testall.yaml +++ b/.github/workflows/testall.yaml @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: - python-version: 3.12 # keep this in sync with Pyodide's Python version + python-version: 3.13 # keep this in sync with Pyodide's Python version - name: Build test matrix id: build-matrix run: | From 81df0f0770138fc361865995e74dcda612738157 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 11:58:55 +0000 Subject: [PATCH 03/14] Replace dynamically --- pytest_pyodide/config.py | 25 ++++++------------- pytest_pyodide/runner.py | 4 +-- tests/test_options.py | 53 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/pytest_pyodide/config.py b/pytest_pyodide/config.py index 01cd3d74..5a282cd0 100644 --- a/pytest_pyodide/config.py +++ b/pytest_pyodide/config.py @@ -5,12 +5,12 @@ from collections.abc import Iterable, Sequence from typing import Literal -from .hook import pytest_wrapper +PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR = "PYODIDE_LOCKFILE_URL_PLACEHOLDER" RUNTIMES = Literal["chrome", "firefox", "node", "safari"] -_global_load_pyodide_script = """ -let pyodide = await loadPyodide({ fullStdLib: false, jsglobals : self, lockFileURL: "%s" }); +_global_load_pyodide_script = f""" +let pyodide = await loadPyodide({{ fullStdLib: false, jsglobals : self, lockFileURL: "{PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR}" }}); """ @@ -24,16 +24,12 @@ def __init__(self): "safari": [], } - global_load_pyodide_script = _global_load_pyodide_script % ( - pytest_wrapper.pyodide_lockfile_dir / "pyodide-lock.json" - ) - # The script to be executed to load the Pyodide. self.load_pyodide_script: dict[RUNTIMES, str] = { - "chrome": global_load_pyodide_script, - "firefox": global_load_pyodide_script, - "node": global_load_pyodide_script, - "safari": global_load_pyodide_script, + "chrome": _global_load_pyodide_script, + "firefox": _global_load_pyodide_script, + "node": _global_load_pyodide_script, + "safari": _global_load_pyodide_script, } # The script to be executed to initialize the runtime. @@ -65,16 +61,11 @@ def get_node_extra_globals(self) -> Sequence[str]: return self.node_extra_globals -SINGLETON = None +SINGLETON = Config() def get_global_config() -> Config: """ Return the singleton config object. """ - global SINGLETON - if not isinstance(SINGLETON, Config): - # lazy initialization so that the global config object can use the pytest configs - SINGLETON = Config() - return SINGLETON diff --git a/pytest_pyodide/runner.py b/pytest_pyodide/runner.py index 49aed483..87215f9c 100644 --- a/pytest_pyodide/runner.py +++ b/pytest_pyodide/runner.py @@ -6,7 +6,7 @@ import pexpect import pytest -from .config import RUNTIMES, get_global_config +from .config import RUNTIMES, get_global_config, PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR from .hook import pytest_wrapper TEST_SETUP_CODE = """ @@ -178,7 +178,7 @@ def javascript_setup(self): def load_pyodide(self): self.run_js( - self._config.get_load_pyodide_script(self.browser) + self._config.get_load_pyodide_script(self.browser).replace(PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, str(pytest_wrapper.pyodide_lockfile_dir)) + self.POST_LOAD_PYODIDE_SCRIPT ) diff --git a/tests/test_options.py b/tests/test_options.py index 3ceebd1f..ea355f22 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -142,3 +142,56 @@ def test_options_pytester(): assert runtimes == pytest.pyodide_runtimes assert dist_dir == pytest.pyodide_dist_dir assert lockfile_dir == pytest.pyodide_lockfile_dir + + +def test_options_diffrent_lockfile_dir(pytester, tmp_path): + pytester.makepyfile( + dedent( + """ + import pytest + from pathlib import Path + + def test_options_diffrent_lockfile_dir(selenium_standalone): + v = selenium_standalone.run_js("pyodide._api.lockfile_packages.testpkg.version") + assert v == "1.2.3" + """ + ) + ) + + test_lockfile = tmp_path / "pyodide-lock.json" + test_lockfile.write_text( + dedent( + """ + { + "info": { + "abi_version": "2025_0", + "arch": "wasm32", + "platform": "emscripten_4_0_9", + "python": "3.13.2", + "version": "0.28.0.dev0" + }, + "packages": { + "testpkg": { + "name": "testpkg", + "version": "1.2.3", + "depends": [], + "file_name": "testpkg-1.2.3-py3-none-any.whl", + "install_dir": "site", + "package_type": "package", + "unvendored_tests": false, + "imports": [], + "sha256": "dummy-sha256-value" + } + } + } + """ + ) + ) + + result = pytester.runpytest( + "--lockfile-dir", + str(tmp_path.resolve()), + ) + result.assert_outcomes(passed=1) + + assert pytest.pyodide_lockfile_dir == tmp_path.resolve() \ No newline at end of file From 031ecda60b5559f35f57bd0d67815a7f55f16ee8 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 12:00:59 +0000 Subject: [PATCH 04/14] typo --- pytest_pyodide/hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_pyodide/hook.py b/pytest_pyodide/hook.py index 9a929748..720481f0 100644 --- a/pytest_pyodide/hook.py +++ b/pytest_pyodide/hook.py @@ -130,7 +130,7 @@ def pytest_configure(config): pytest_wrapper.pyodide_run_host_test = run_host pytest_wrapper.pyodide_runtimes = runtimes pytest_wrapper.pyodide_dist_dir = config.option.dist_dir - if config.option.lockfile_path is None: + if config.option.lockfile_dir is None: pytest_wrapper.pyodide_lockfile_dir = config.option.dist_dir else: pytest_wrapper.pyodide_lockfile_dir = config.option.lockfile_dir From ee65e025a1c4b59f1f9f30e1177779ad040561c3 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 12:04:34 +0000 Subject: [PATCH 05/14] path --- pytest_pyodide/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_pyodide/runner.py b/pytest_pyodide/runner.py index 87215f9c..a377df47 100644 --- a/pytest_pyodide/runner.py +++ b/pytest_pyodide/runner.py @@ -178,7 +178,7 @@ def javascript_setup(self): def load_pyodide(self): self.run_js( - self._config.get_load_pyodide_script(self.browser).replace(PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, str(pytest_wrapper.pyodide_lockfile_dir)) + self._config.get_load_pyodide_script(self.browser).replace(PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, str(pytest_wrapper.pyodide_lockfile_dir / "pyodide-lock.json")) + self.POST_LOAD_PYODIDE_SCRIPT ) From cf4910ed16dce941f5bcd0a8b78ae2b65d424840 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 12:25:19 +0000 Subject: [PATCH 06/14] run server for lockfile --- pytest_pyodide/fixture.py | 27 +++++++++++++++++---------- pytest_pyodide/runner.py | 16 ++++++++-------- pytest_pyodide/server.py | 5 +++-- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/pytest_pyodide/fixture.py b/pytest_pyodide/fixture.py index 65ea6f78..6235e02f 100644 --- a/pytest_pyodide/fixture.py +++ b/pytest_pyodide/fixture.py @@ -88,7 +88,7 @@ def selenium_common( return None, as initializing Pyodide for selenium is expensive """ - server_hostname, server_port, server_log = web_server_main + (runtime_server_url, runtime_server_log), (lockfile_server_url, lockfile_server_log) = web_server_main runner_type = request.config.option.runner.lower() runner_set: dict[tuple[str, str], type[_BrowserBaseRunner]] = { @@ -107,9 +107,10 @@ def selenium_common( dist_dir = Path(os.getcwd(), request.config.getoption("--dist-dir")) runner = runner_cls( - server_port=server_port, - server_hostname=server_hostname, - server_log=server_log, + runtime_server_url=runtime_server_url, + runtime_server_url=runtime_server_log, + lockfile_server_url=lockfile_server_url, + lockfile_server_log=lockfile_server_log, load_pyodide=load_pyodide, browsers=browsers, script_type=script_type, @@ -339,17 +340,23 @@ def console_html_fixture(request, runtime, web_server_main, playwright_browsers) @pytest.fixture(scope="session") -def web_server_main(request): +def web_server_main(): """Web server that serves files in the dist directory""" - with spawn_web_server(request.config.option.dist_dir) as output: - yield output + with spawn_web_server(pytest_wrapper.pyodide_dist_dir) as dist_dir_server, spawn_web_server(pytest_wrapper.pyodide_lockfile_dir) as lockfile_dir_server: + yield ( + dist_dir_server, + lockfile_dir_server, + ) @pytest.fixture(scope="session") -def web_server_secondary(request): +def web_server_secondary(): """Secondary web server that serves files dist directory""" - with spawn_web_server(request.config.option.dist_dir) as output: - yield output + with spawn_web_server(pytest_wrapper.pyodide_dist_dir) as dist_dir_server, spawn_web_server(pytest_wrapper.pyodide_lockfile_dir) as lockfile_dir_server: + yield ( + dist_dir_server, + lockfile_dir_server, + ) @pytest.fixture(params=["classic", "module"], scope="module") diff --git a/pytest_pyodide/runner.py b/pytest_pyodide/runner.py index a377df47..185d192f 100644 --- a/pytest_pyodide/runner.py +++ b/pytest_pyodide/runner.py @@ -115,9 +115,10 @@ class _BrowserBaseRunner: def __init__( self, - server_port, - server_hostname="127.0.0.1", - server_log=None, + runtime_server_url, + lockfile_server_url, + runtime_server_log=None, + lockfile_server_log=None, load_pyodide=True, script_type="classic", dist_dir=None, @@ -127,10 +128,9 @@ def __init__( ): self._config = get_global_config() - self.server_port = server_port - self.server_hostname = server_hostname - self.base_url = f"http://{self.server_hostname}:{self.server_port}" - self.server_log = server_log + self.base_url = runtime_server_url + self.lockfile_server_url = lockfile_server_url + self.server_log = runtime_server_log self.script_type = script_type self.dist_dir = dist_dir self.driver = self.get_driver(jspi) @@ -178,7 +178,7 @@ def javascript_setup(self): def load_pyodide(self): self.run_js( - self._config.get_load_pyodide_script(self.browser).replace(PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, str(pytest_wrapper.pyodide_lockfile_dir / "pyodide-lock.json")) + self._config.get_load_pyodide_script(self.browser).replace(PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, str(self.lockfile_server_url / "pyodide-lock.json")) + self.POST_LOAD_PYODIDE_SCRIPT ) diff --git a/pytest_pyodide/server.py b/pytest_pyodide/server.py index f92adca9..696c7178 100644 --- a/pytest_pyodide/server.py +++ b/pytest_pyodide/server.py @@ -93,12 +93,13 @@ def spawn_web_server(dist_dir, extra_headers=None, handler_cls=None): p.start() port = q.get(timeout=20) hostname = "127.0.0.1" + url = f"http://{hostname}:{port}" print( - f"Spawning webserver at http://{hostname}:{port} " + f"Spawning webserver at {url} " f"(see logs in {log_path})" ) - yield hostname, port, log_path + yield url, log_path finally: q.put("TERMINATE") p.join() From 1ea989ecdf21996948789bd6c5845b87776612e5 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 12:28:07 +0000 Subject: [PATCH 07/14] lint --- pytest_pyodide/config.py | 1 - pytest_pyodide/fixture.py | 19 +++++++++++++++---- pytest_pyodide/hook.py | 2 +- pytest_pyodide/runner.py | 9 ++++++--- pytest_pyodide/server.py | 5 +---- tests/test_options.py | 2 +- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/pytest_pyodide/config.py b/pytest_pyodide/config.py index 5a282cd0..2631ab3c 100644 --- a/pytest_pyodide/config.py +++ b/pytest_pyodide/config.py @@ -5,7 +5,6 @@ from collections.abc import Iterable, Sequence from typing import Literal - PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR = "PYODIDE_LOCKFILE_URL_PLACEHOLDER" RUNTIMES = Literal["chrome", "firefox", "node", "safari"] diff --git a/pytest_pyodide/fixture.py b/pytest_pyodide/fixture.py index 6235e02f..ed16d6e2 100644 --- a/pytest_pyodide/fixture.py +++ b/pytest_pyodide/fixture.py @@ -88,7 +88,10 @@ def selenium_common( return None, as initializing Pyodide for selenium is expensive """ - (runtime_server_url, runtime_server_log), (lockfile_server_url, lockfile_server_log) = web_server_main + (runtime_server_url, runtime_server_log), ( + lockfile_server_url, + lockfile_server_log, + ) = web_server_main runner_type = request.config.option.runner.lower() runner_set: dict[tuple[str, str], type[_BrowserBaseRunner]] = { @@ -108,7 +111,7 @@ def selenium_common( dist_dir = Path(os.getcwd(), request.config.getoption("--dist-dir")) runner = runner_cls( runtime_server_url=runtime_server_url, - runtime_server_url=runtime_server_log, + runtime_server_log=runtime_server_log, lockfile_server_url=lockfile_server_url, lockfile_server_log=lockfile_server_log, load_pyodide=load_pyodide, @@ -342,7 +345,11 @@ def console_html_fixture(request, runtime, web_server_main, playwright_browsers) @pytest.fixture(scope="session") def web_server_main(): """Web server that serves files in the dist directory""" - with spawn_web_server(pytest_wrapper.pyodide_dist_dir) as dist_dir_server, spawn_web_server(pytest_wrapper.pyodide_lockfile_dir) as lockfile_dir_server: + with spawn_web_server( + pytest_wrapper.pyodide_dist_dir + ) as dist_dir_server, spawn_web_server( + pytest_wrapper.pyodide_lockfile_dir + ) as lockfile_dir_server: yield ( dist_dir_server, lockfile_dir_server, @@ -352,7 +359,11 @@ def web_server_main(): @pytest.fixture(scope="session") def web_server_secondary(): """Secondary web server that serves files dist directory""" - with spawn_web_server(pytest_wrapper.pyodide_dist_dir) as dist_dir_server, spawn_web_server(pytest_wrapper.pyodide_lockfile_dir) as lockfile_dir_server: + with spawn_web_server( + pytest_wrapper.pyodide_dist_dir + ) as dist_dir_server, spawn_web_server( + pytest_wrapper.pyodide_lockfile_dir + ) as lockfile_dir_server: yield ( dist_dir_server, lockfile_dir_server, diff --git a/pytest_pyodide/hook.py b/pytest_pyodide/hook.py index 720481f0..9aec8d6b 100644 --- a/pytest_pyodide/hook.py +++ b/pytest_pyodide/hook.py @@ -40,7 +40,7 @@ class PytestWrapper: pyodide_runtimes: set[str] pyodide_dist_dir: Path pyodide_lockfile_dir: Path - pyodide_options_stack: list[tuple[bool, set[str], Path]] + pyodide_options_stack: list[tuple[bool, set[str], Path, Path]] def __setattr__(self, name, value): setattr(pytest, name, value) diff --git a/pytest_pyodide/runner.py b/pytest_pyodide/runner.py index 185d192f..bbcd044f 100644 --- a/pytest_pyodide/runner.py +++ b/pytest_pyodide/runner.py @@ -6,7 +6,7 @@ import pexpect import pytest -from .config import RUNTIMES, get_global_config, PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR +from .config import PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, RUNTIMES, get_global_config from .hook import pytest_wrapper TEST_SETUP_CODE = """ @@ -178,7 +178,10 @@ def javascript_setup(self): def load_pyodide(self): self.run_js( - self._config.get_load_pyodide_script(self.browser).replace(PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, str(self.lockfile_server_url / "pyodide-lock.json")) + self._config.get_load_pyodide_script(self.browser).replace( + PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, + str(self.lockfile_server_url / "pyodide-lock.json"), + ) + self.POST_LOAD_PYODIDE_SCRIPT ) @@ -321,7 +324,7 @@ def run_webworker(self, code): }}); return await res """.format( - f"http://{self.server_hostname}:{self.server_port}/{worker_file}", + f"{self.base_url}/{worker_file}", self.script_type, code, ), diff --git a/pytest_pyodide/server.py b/pytest_pyodide/server.py index 696c7178..819c4e90 100644 --- a/pytest_pyodide/server.py +++ b/pytest_pyodide/server.py @@ -95,10 +95,7 @@ def spawn_web_server(dist_dir, extra_headers=None, handler_cls=None): hostname = "127.0.0.1" url = f"http://{hostname}:{port}" - print( - f"Spawning webserver at {url} " - f"(see logs in {log_path})" - ) + print(f"Spawning webserver at {url} " f"(see logs in {log_path})") yield url, log_path finally: q.put("TERMINATE") diff --git a/tests/test_options.py b/tests/test_options.py index ea355f22..1055de27 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -194,4 +194,4 @@ def test_options_diffrent_lockfile_dir(selenium_standalone): ) result.assert_outcomes(passed=1) - assert pytest.pyodide_lockfile_dir == tmp_path.resolve() \ No newline at end of file + assert pytest.pyodide_lockfile_dir == tmp_path.resolve() From be35be079435b5362ec63483712fd76b9cbab5c2 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 12:35:24 +0000 Subject: [PATCH 08/14] Fix nod --- pytest_pyodide/fixture.py | 4 +++- pytest_pyodide/runner.py | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pytest_pyodide/fixture.py b/pytest_pyodide/fixture.py index ed16d6e2..3b1d406d 100644 --- a/pytest_pyodide/fixture.py +++ b/pytest_pyodide/fixture.py @@ -108,7 +108,8 @@ def selenium_common( if runner_cls is None: raise AssertionError(f"Unknown runner or browser: {runner_type} / {runtime}") - dist_dir = Path(os.getcwd(), request.config.getoption("--dist-dir")) + dist_dir = Path(os.getcwd(), pytest_wrapper.pyodide_dist_dir) + lockfile_dir = Path(os.getcwd(), pytest_wrapper.pyodide_lockfile_dir) runner = runner_cls( runtime_server_url=runtime_server_url, runtime_server_log=runtime_server_log, @@ -118,6 +119,7 @@ def selenium_common( browsers=browsers, script_type=script_type, dist_dir=dist_dir, + lockfile_dir=lockfile_dir, jspi=jspi, ) try: diff --git a/pytest_pyodide/runner.py b/pytest_pyodide/runner.py index bbcd044f..7e5b464d 100644 --- a/pytest_pyodide/runner.py +++ b/pytest_pyodide/runner.py @@ -122,6 +122,7 @@ def __init__( load_pyodide=True, script_type="classic", dist_dir=None, + lockfile_dir=None, jspi=False, *args, **kwargs, @@ -133,6 +134,7 @@ def __init__( self.server_log = runtime_server_log self.script_type = script_type self.dist_dir = dist_dir + self.lockfile_dir = lockfile_dir self.driver = self.get_driver(jspi) self.set_script_timeout(self.script_timeout) @@ -180,7 +182,7 @@ def load_pyodide(self): self.run_js( self._config.get_load_pyodide_script(self.browser).replace( PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, - str(self.lockfile_server_url / "pyodide-lock.json"), + f"{self.lockfile_server_url}/pyodide-lock.json", ) + self.POST_LOAD_PYODIDE_SCRIPT ) @@ -569,6 +571,15 @@ def init_node(self, jspi=False): except (pexpect.exceptions.EOF, pexpect.exceptions.TIMEOUT): raise JavascriptException("", self.p.before.decode()) from None + def load_pyodide(self): + self.run_js( + self._config.get_load_pyodide_script(self.browser).replace( + PYODIDE_LOCKFILE_URL_PLACEHOLDER_STR, + f"{self.lockfile_dir}/pyodide-lock.json", + ) + + self.POST_LOAD_PYODIDE_SCRIPT + ) + def get_driver(self, jspi=False): self._logs = [] self.init_node(jspi) From 3f6761d701c329ef2808adcb188e5d909b86cfd4 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 12:54:03 +0000 Subject: [PATCH 09/14] Fix tests --- pytest_pyodide/copy_files_to_pyodide.py | 5 ++--- pytest_pyodide/hook.py | 6 ++---- tests/test_options.py | 20 +++++++++++++++++++- tests/test_server.py | 20 +++++++++----------- tests/test_testing.py | 4 ++-- 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/pytest_pyodide/copy_files_to_pyodide.py b/pytest_pyodide/copy_files_to_pyodide.py index 72ae2744..cda1888d 100644 --- a/pytest_pyodide/copy_files_to_pyodide.py +++ b/pytest_pyodide/copy_files_to_pyodide.py @@ -87,8 +87,7 @@ def copy_files_to_emscripten_fs( return base_path = Path.cwd() with spawn_web_server(base_path) as server: - server_hostname, server_port, _ = server - base_url = f"http://{server_hostname}:{server_port}/" + base_url, _ = server # fetch all files into the pyodide # n.b. this might be slow for big packages @@ -111,7 +110,7 @@ async def _fetch_file(src,dest): ) for file, dest in new_files: _copied_files[selenium].append((file, dest)) - file_url = base_url + str(file.relative_to(base_path).as_posix()) + file_url = f"{base_url}/{file.relative_to(base_path).as_posix()}" if file.suffix == ".whl" and install_wheels: # wheel - install the wheel on the pyodide side before # any fetches (and don't copy it) diff --git a/pytest_pyodide/hook.py b/pytest_pyodide/hook.py index 9aec8d6b..7ebe6c81 100644 --- a/pytest_pyodide/hook.py +++ b/pytest_pyodide/hook.py @@ -114,6 +114,7 @@ def pytest_configure(config): ) config.option.dist_dir = Path(config.option.dist_dir).resolve() + config.option.lockfile_dir = Path(config.option.lockfile_dir or config.option.dist_dir).resolve() run_host, runtimes = _filter_runtimes(config.option.runtime) if not hasattr(pytest, "pyodide_options_stack"): @@ -130,10 +131,7 @@ def pytest_configure(config): pytest_wrapper.pyodide_run_host_test = run_host pytest_wrapper.pyodide_runtimes = runtimes pytest_wrapper.pyodide_dist_dir = config.option.dist_dir - if config.option.lockfile_dir is None: - pytest_wrapper.pyodide_lockfile_dir = config.option.dist_dir - else: - pytest_wrapper.pyodide_lockfile_dir = config.option.lockfile_dir + pytest_wrapper.pyodide_lockfile_dir = config.option.lockfile_dir def pytest_unconfigure(config): diff --git a/tests/test_options.py b/tests/test_options.py index 1055de27..c025c947 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -144,7 +144,7 @@ def test_options_pytester(): assert lockfile_dir == pytest.pyodide_lockfile_dir -def test_options_diffrent_lockfile_dir(pytester, tmp_path): +def test_options_different_lockfile_dir(request, pytester, tmp_path): pytester.makepyfile( dedent( """ @@ -188,9 +188,27 @@ def test_options_diffrent_lockfile_dir(selenium_standalone): ) ) + # result = pytester.inline_run( + # file, + # "--doctest-modules", + # "--dist-dir", + # request.config.getoption("--dist-dir"), + # "--rt", + # ",".join(pytest.pyodide_runtimes), + # "--runner", + # request.config.option.runner, + # "--rootdir", + # str(file.parent), + # plugins=(MyPlugin(),), + # ) + result = pytester.runpytest( + "--dist-dir", + request.config.getoption("--dist-dir"), "--lockfile-dir", str(tmp_path.resolve()), + "--runner", + request.config.option.runner, ) result.assert_outcomes(passed=1) diff --git a/tests/test_server.py b/tests/test_server.py index 15da3668..3dc3ab8a 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -10,11 +10,10 @@ def test_spawn_web_server_with_params(tmp_path): (tmp_path / "index.txt").write_text("a") extra_headers = {"Custom-Header": "42"} with spawn_web_server(tmp_path, extra_headers=extra_headers) as ( - hostname, - port, + url, log_path, ): - res = requests.get(f"http://{hostname}:{port}/index.txt") + res = requests.get(f"{url}/index.txt") assert res.ok assert res.headers assert res.content == b"a" @@ -25,9 +24,9 @@ def test_spawn_web_server_with_params(tmp_path): def test_spawn_web_server_default_templates(tmp_path): default_templates = _default_templates() - with spawn_web_server(tmp_path) as (hostname, port, _): + with spawn_web_server(tmp_path) as (url, _): for path, content in default_templates.items(): - res = requests.get(f"http://{hostname}:{port}{path}") + res = requests.get(f"{url}{path}") assert res.ok assert res.headers assert res.content == content @@ -46,18 +45,17 @@ def test_spawn_web_server_custom_templates(tmp_path): default_templates = _default_templates() with spawn_web_server(tmp_path, handler_cls=CustomTemplateHandler) as ( - hostname, - port, + url, _, ): for path, content in default_templates.items(): - res = requests.get(f"http://{hostname}:{port}{path}") + res = requests.get(f"{url}{path}") assert res.ok assert res.headers assert res.content == content assert res.headers["Access-Control-Allow-Origin"] == "*" - res = requests.get(f"http://{hostname}:{port}/index.txt") + res = requests.get(f"{url}/index.txt") assert res.ok assert res.content == b"hello world" @@ -71,7 +69,7 @@ def do_GET(self): def test_custom_handler(tmp_path): with spawn_web_server(tmp_path, handler_cls=HelloWorldHandler) as server: - hostname, port, _ = server - res = requests.get(f"http://{hostname}:{port}/index.txt") + url, _ = server + res = requests.get(f"{url}/index.txt") assert res.ok assert res.content == b"hello world" diff --git a/tests/test_testing.py b/tests/test_testing.py index 7afcafb1..d0e4964f 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -4,9 +4,9 @@ def test_web_server_secondary(selenium, web_server_secondary): - host, port, logs = web_server_secondary + (url, logs), _ = web_server_secondary assert pathlib.Path(logs).exists() - assert selenium.server_port != port + assert selenium.runtime_server_url != url def test_host(): From 34acac1ac1d5f67a622c05da003acf5d06f61591 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 13:02:50 +0000 Subject: [PATCH 10/14] Fix test --- examples/test_install_package.py | 3 +-- tests/test_doctest.py | 1 + tests/test_options.py | 16 ++-------------- tests/test_testing.py | 2 +- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/examples/test_install_package.py b/examples/test_install_package.py index 388c93a7..68fba61c 100644 --- a/examples/test_install_package.py +++ b/examples/test_install_package.py @@ -5,8 +5,7 @@ def test_install_from_custom_server(selenium_standalone): with spawn_web_server(Path(__file__).parent / "wheels") as server: - server_hostname, server_port, _ = server - base_url = f"http://{server_hostname}:{server_port}/" + base_url, _ = server url = base_url + "snowballstemmer-2.2.0-py2.py3-none-any.whl" selenium = selenium_standalone diff --git a/tests/test_doctest.py b/tests/test_doctest.py index 99231db1..7f39b26e 100644 --- a/tests/test_doctest.py +++ b/tests/test_doctest.py @@ -85,6 +85,7 @@ def pytest_fixture_setup(self, fixturedef, request): captured = capsys.readouterr() expected = dedent( """ + 002 003 >>> from js import Object # doctest: +RUN_IN_PYODIDE 004 >>> 1 == 2 Expected: diff --git a/tests/test_options.py b/tests/test_options.py index c025c947..1e317e6e 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -188,20 +188,6 @@ def test_options_diffrent_lockfile_dir(selenium_standalone): ) ) - # result = pytester.inline_run( - # file, - # "--doctest-modules", - # "--dist-dir", - # request.config.getoption("--dist-dir"), - # "--rt", - # ",".join(pytest.pyodide_runtimes), - # "--runner", - # request.config.option.runner, - # "--rootdir", - # str(file.parent), - # plugins=(MyPlugin(),), - # ) - result = pytester.runpytest( "--dist-dir", request.config.getoption("--dist-dir"), @@ -209,6 +195,8 @@ def test_options_diffrent_lockfile_dir(selenium_standalone): str(tmp_path.resolve()), "--runner", request.config.option.runner, + "--rt", + ",".join(pytest.pyodide_runtimes), ) result.assert_outcomes(passed=1) diff --git a/tests/test_testing.py b/tests/test_testing.py index d0e4964f..c11cb22e 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -6,7 +6,7 @@ def test_web_server_secondary(selenium, web_server_secondary): (url, logs), _ = web_server_secondary assert pathlib.Path(logs).exists() - assert selenium.runtime_server_url != url + assert selenium.base_url != url def test_host(): From 5fa39cc5aad2c8cdd1075a4644b1aa4ec0de8f26 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 13:17:32 +0000 Subject: [PATCH 11/14] Fix test --- examples/test_install_package.py | 2 +- tests/test_doctest.py | 5 ++- tests/test_options.py | 53 +++++++++----------------------- 3 files changed, 18 insertions(+), 42 deletions(-) diff --git a/examples/test_install_package.py b/examples/test_install_package.py index 68fba61c..3bea4c23 100644 --- a/examples/test_install_package.py +++ b/examples/test_install_package.py @@ -6,7 +6,7 @@ def test_install_from_custom_server(selenium_standalone): with spawn_web_server(Path(__file__).parent / "wheels") as server: base_url, _ = server - url = base_url + "snowballstemmer-2.2.0-py2.py3-none-any.whl" + url = base_url + "/snowballstemmer-2.2.0-py2.py3-none-any.whl" selenium = selenium_standalone selenium.run_js( diff --git a/tests/test_doctest.py b/tests/test_doctest.py index 7f39b26e..9cf6c57b 100644 --- a/tests/test_doctest.py +++ b/tests/test_doctest.py @@ -85,9 +85,8 @@ def pytest_fixture_setup(self, fixturedef, request): captured = capsys.readouterr() expected = dedent( """ - 002 - 003 >>> from js import Object # doctest: +RUN_IN_PYODIDE - 004 >>> 1 == 2 + 003 >>> from js import Object # doctest: +RUN_IN_PYODIDE + 004 >>> 1 == 2 Expected: True Got: diff --git a/tests/test_options.py b/tests/test_options.py index 1e317e6e..c3c21db2 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -1,3 +1,4 @@ +import json from pathlib import Path from textwrap import dedent @@ -6,6 +7,8 @@ from pytest_pyodide.hook import _filter_runtimes + + def test_dist_dir(pytester): dist_dir = str(Path("dist").resolve()) @@ -144,49 +147,25 @@ def test_options_pytester(): assert lockfile_dir == pytest.pyodide_lockfile_dir -def test_options_different_lockfile_dir(request, pytester, tmp_path): +def test_options_different_lockfile_dir(request, pytester, tmp_path, selenium): pytester.makepyfile( dedent( """ - import pytest - from pathlib import Path - - def test_options_diffrent_lockfile_dir(selenium_standalone): - v = selenium_standalone.run_js("pyodide._api.lockfile_packages.testpkg.version") - assert v == "1.2.3" + def test_options_different_lockfile_dir(selenium_standalone): + selenium_standalone.load_package("cloned_micropip") + selenium_standalone.run("import micropip") """ ) ) - test_lockfile = tmp_path / "pyodide-lock.json" - test_lockfile.write_text( - dedent( - """ - { - "info": { - "abi_version": "2025_0", - "arch": "wasm32", - "platform": "emscripten_4_0_9", - "python": "3.13.2", - "version": "0.28.0.dev0" - }, - "packages": { - "testpkg": { - "name": "testpkg", - "version": "1.2.3", - "depends": [], - "file_name": "testpkg-1.2.3-py3-none-any.whl", - "install_dir": "site", - "package_type": "package", - "unvendored_tests": false, - "imports": [], - "sha256": "dummy-sha256-value" - } - } - } - """ - ) - ) + orig_lockfile = f"{selenium.dist_dir}/pyodide-lock.json" + new_lockfile = tmp_path / "pyodide-lock.json" + + lockfile_content = json.loads(Path(orig_lockfile).read_text()) + # assume micropip is always available in the lockfile + lockfile_content["packages"]["cloned-micropip"] = lockfile_content["packages"]["micropip"] + + new_lockfile.write_text(json.dumps(lockfile_content, indent=4)) result = pytester.runpytest( "--dist-dir", @@ -199,5 +178,3 @@ def test_options_diffrent_lockfile_dir(selenium_standalone): ",".join(pytest.pyodide_runtimes), ) result.assert_outcomes(passed=1) - - assert pytest.pyodide_lockfile_dir == tmp_path.resolve() From ce6d91f829f7c65392ee82717181f1f4675174ec Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 15 Jun 2025 13:18:04 +0000 Subject: [PATCH 12/14] Fix tests --- pytest_pyodide/hook.py | 4 +++- tests/test_options.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pytest_pyodide/hook.py b/pytest_pyodide/hook.py index 7ebe6c81..1b059090 100644 --- a/pytest_pyodide/hook.py +++ b/pytest_pyodide/hook.py @@ -114,7 +114,9 @@ def pytest_configure(config): ) config.option.dist_dir = Path(config.option.dist_dir).resolve() - config.option.lockfile_dir = Path(config.option.lockfile_dir or config.option.dist_dir).resolve() + config.option.lockfile_dir = Path( + config.option.lockfile_dir or config.option.dist_dir + ).resolve() run_host, runtimes = _filter_runtimes(config.option.runtime) if not hasattr(pytest, "pyodide_options_stack"): diff --git a/tests/test_options.py b/tests/test_options.py index c3c21db2..d80c3f4c 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -7,8 +7,6 @@ from pytest_pyodide.hook import _filter_runtimes - - def test_dist_dir(pytester): dist_dir = str(Path("dist").resolve()) @@ -163,7 +161,9 @@ def test_options_different_lockfile_dir(selenium_standalone): lockfile_content = json.loads(Path(orig_lockfile).read_text()) # assume micropip is always available in the lockfile - lockfile_content["packages"]["cloned-micropip"] = lockfile_content["packages"]["micropip"] + lockfile_content["packages"]["cloned-micropip"] = lockfile_content["packages"][ + "micropip" + ] new_lockfile.write_text(json.dumps(lockfile_content, indent=4)) From 7aa1b7549235e3c71f39dbbcacc00d05a562b247 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Mon, 16 Jun 2025 09:48:24 +0000 Subject: [PATCH 13/14] Reduce diff --- examples/test_install_package.py | 5 +++-- pytest_pyodide/copy_files_to_pyodide.py | 5 +++-- pytest_pyodide/fixture.py | 12 +++++++----- pytest_pyodide/server.py | 8 +++++--- tests/test_server.py | 20 +++++++++++--------- tests/test_testing.py | 4 ++-- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/examples/test_install_package.py b/examples/test_install_package.py index 3bea4c23..388c93a7 100644 --- a/examples/test_install_package.py +++ b/examples/test_install_package.py @@ -5,8 +5,9 @@ def test_install_from_custom_server(selenium_standalone): with spawn_web_server(Path(__file__).parent / "wheels") as server: - base_url, _ = server - url = base_url + "/snowballstemmer-2.2.0-py2.py3-none-any.whl" + server_hostname, server_port, _ = server + base_url = f"http://{server_hostname}:{server_port}/" + url = base_url + "snowballstemmer-2.2.0-py2.py3-none-any.whl" selenium = selenium_standalone selenium.run_js( diff --git a/pytest_pyodide/copy_files_to_pyodide.py b/pytest_pyodide/copy_files_to_pyodide.py index cda1888d..72ae2744 100644 --- a/pytest_pyodide/copy_files_to_pyodide.py +++ b/pytest_pyodide/copy_files_to_pyodide.py @@ -87,7 +87,8 @@ def copy_files_to_emscripten_fs( return base_path = Path.cwd() with spawn_web_server(base_path) as server: - base_url, _ = server + server_hostname, server_port, _ = server + base_url = f"http://{server_hostname}:{server_port}/" # fetch all files into the pyodide # n.b. this might be slow for big packages @@ -110,7 +111,7 @@ async def _fetch_file(src,dest): ) for file, dest in new_files: _copied_files[selenium].append((file, dest)) - file_url = f"{base_url}/{file.relative_to(base_path).as_posix()}" + file_url = base_url + str(file.relative_to(base_path).as_posix()) if file.suffix == ".whl" and install_wheels: # wheel - install the wheel on the pyodide side before # any fetches (and don't copy it) diff --git a/pytest_pyodide/fixture.py b/pytest_pyodide/fixture.py index 3b1d406d..1f31a73f 100644 --- a/pytest_pyodide/fixture.py +++ b/pytest_pyodide/fixture.py @@ -88,10 +88,12 @@ def selenium_common( return None, as initializing Pyodide for selenium is expensive """ - (runtime_server_url, runtime_server_log), ( - lockfile_server_url, - lockfile_server_log, - ) = web_server_main + runtime_server, lockfile_server = web_server_main + runtime_server_url = f"http://{runtime_server[0]}:{runtime_server[1]}" + runtime_server_log = runtime_server[2] + lockfile_server_url = f"http://{lockfile_server[0]}:{lockfile_server[1]}" + lockfile_server_log = lockfile_server[2] + runner_type = request.config.option.runner.lower() runner_set: dict[tuple[str, str], type[_BrowserBaseRunner]] = { @@ -335,7 +337,7 @@ def console_html_fixture(request, runtime, web_server_main, playwright_browsers) browsers=playwright_browsers, ) as selenium: selenium.goto( - f"http://{selenium.server_hostname}:{selenium.server_port}/console.html" + f"{selenium.dist_url}/console.html" ) selenium.javascript_setup() try: diff --git a/pytest_pyodide/server.py b/pytest_pyodide/server.py index 819c4e90..f92adca9 100644 --- a/pytest_pyodide/server.py +++ b/pytest_pyodide/server.py @@ -93,10 +93,12 @@ def spawn_web_server(dist_dir, extra_headers=None, handler_cls=None): p.start() port = q.get(timeout=20) hostname = "127.0.0.1" - url = f"http://{hostname}:{port}" - print(f"Spawning webserver at {url} " f"(see logs in {log_path})") - yield url, log_path + print( + f"Spawning webserver at http://{hostname}:{port} " + f"(see logs in {log_path})" + ) + yield hostname, port, log_path finally: q.put("TERMINATE") p.join() diff --git a/tests/test_server.py b/tests/test_server.py index 3dc3ab8a..15da3668 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -10,10 +10,11 @@ def test_spawn_web_server_with_params(tmp_path): (tmp_path / "index.txt").write_text("a") extra_headers = {"Custom-Header": "42"} with spawn_web_server(tmp_path, extra_headers=extra_headers) as ( - url, + hostname, + port, log_path, ): - res = requests.get(f"{url}/index.txt") + res = requests.get(f"http://{hostname}:{port}/index.txt") assert res.ok assert res.headers assert res.content == b"a" @@ -24,9 +25,9 @@ def test_spawn_web_server_with_params(tmp_path): def test_spawn_web_server_default_templates(tmp_path): default_templates = _default_templates() - with spawn_web_server(tmp_path) as (url, _): + with spawn_web_server(tmp_path) as (hostname, port, _): for path, content in default_templates.items(): - res = requests.get(f"{url}{path}") + res = requests.get(f"http://{hostname}:{port}{path}") assert res.ok assert res.headers assert res.content == content @@ -45,17 +46,18 @@ def test_spawn_web_server_custom_templates(tmp_path): default_templates = _default_templates() with spawn_web_server(tmp_path, handler_cls=CustomTemplateHandler) as ( - url, + hostname, + port, _, ): for path, content in default_templates.items(): - res = requests.get(f"{url}{path}") + res = requests.get(f"http://{hostname}:{port}{path}") assert res.ok assert res.headers assert res.content == content assert res.headers["Access-Control-Allow-Origin"] == "*" - res = requests.get(f"{url}/index.txt") + res = requests.get(f"http://{hostname}:{port}/index.txt") assert res.ok assert res.content == b"hello world" @@ -69,7 +71,7 @@ def do_GET(self): def test_custom_handler(tmp_path): with spawn_web_server(tmp_path, handler_cls=HelloWorldHandler) as server: - url, _ = server - res = requests.get(f"{url}/index.txt") + hostname, port, _ = server + res = requests.get(f"http://{hostname}:{port}/index.txt") assert res.ok assert res.content == b"hello world" diff --git a/tests/test_testing.py b/tests/test_testing.py index c11cb22e..e1765cd4 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -4,9 +4,9 @@ def test_web_server_secondary(selenium, web_server_secondary): - (url, logs), _ = web_server_secondary + (host, port, logs), _ = web_server_secondary assert pathlib.Path(logs).exists() - assert selenium.base_url != url + assert selenium.base_url != f"http://{host}:{port}" def test_host(): From 844ecabc7f80d5a80b28b70e90ad2c37daaeb525 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 09:48:42 +0000 Subject: [PATCH 14/14] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pytest_pyodide/fixture.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pytest_pyodide/fixture.py b/pytest_pyodide/fixture.py index 1f31a73f..f591d00e 100644 --- a/pytest_pyodide/fixture.py +++ b/pytest_pyodide/fixture.py @@ -336,9 +336,7 @@ def console_html_fixture(request, runtime, web_server_main, playwright_browsers) load_pyodide=False, browsers=playwright_browsers, ) as selenium: - selenium.goto( - f"{selenium.dist_url}/console.html" - ) + selenium.goto(f"{selenium.dist_url}/console.html") selenium.javascript_setup() try: yield selenium