Skip to content

Commit

Permalink
Add a global manager for configuring runtimes (#141)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
ryanking13 and pre-commit-ci[bot] committed Jul 23, 2024
1 parent 67e933d commit d7da97c
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 21 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## [0.58.3] - 2024-07-23

### Added

- Added global config manager.
[#141](https://github.com/pyodide/pytest-pyodide/pull/141)

## [0.58.1] - 2024-06-12

### Fixed
Expand Down
2 changes: 2 additions & 0 deletions pytest_pyodide/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from importlib.metadata import PackageNotFoundError, version

from .config import get_global_config
from .decorator import copy_files_to_pyodide, run_in_pyodide
from .runner import (
NodeRunner,
Expand Down Expand Up @@ -30,4 +31,5 @@
"run_in_pyodide",
"copy_files_to_pyodide",
"spawn_web_server",
"get_global_config",
]
61 changes: 61 additions & 0 deletions pytest_pyodide/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""
Stores the global runtime configuration related to the pytest_pyodide package.
"""

from typing import Literal

RUNTIMES = Literal["chrome", "firefox", "node", "safari"]

_global_load_pyodide_script = """
let pyodide = await loadPyodide({ fullStdLib: false, jsglobals : self });
"""


class Config:
def __init__(self):
# Flags to be passed to the browser or runtime.
self.flags: dict[RUNTIMES, list[str]] = {
"chrome": ["--js-flags=--expose-gc"],
"firefox": [],
"node": [],
"safari": [],
}

# 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,
}

# The script to be executed to initialize the runtime.
self.initialize_script: str = "pyodide.runPython('');"

def set_flags(self, runtime: RUNTIMES, flags: list[str]):
self.flags[runtime] = flags

def get_flags(self, runtime: RUNTIMES) -> list[str]:
return self.flags[runtime]

def set_load_pyodide_script(self, runtime: RUNTIMES, load_pyodide_script: str):
self.load_pyodide_script[runtime] = load_pyodide_script

def get_load_pyodide_script(self, runtime: RUNTIMES) -> str:
return self.load_pyodide_script[runtime]

def set_initialize_script(self, initialize_script: str):
self.initialize_script = initialize_script

def get_initialize_script(self) -> str:
return self.initialize_script


SINGLETON = Config()


def get_global_config() -> Config:
"""
Return the singleton config object.
"""
return SINGLETON
8 changes: 4 additions & 4 deletions pytest_pyodide/fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@

import pytest

from .config import get_global_config
from .runner import (
CHROME_FLAGS,
FIREFOX_FLAGS,
NodeRunner,
PlaywrightChromeRunner,
PlaywrightFirefoxRunner,
Expand Down Expand Up @@ -41,13 +40,14 @@ def _playwright_browsers(request):
)

runtimes = pytest.pyodide_runtimes
cfg = get_global_config()

with sync_playwright() as p:
browsers: dict[str, Any] = {}
supported_browsers: dict[str, tuple[str, list[str]]] = {
# browser name: (attr_name, flags)
"firefox": ("firefox", FIREFOX_FLAGS),
"chrome": ("chromium", CHROME_FLAGS),
"firefox": ("firefox", cfg.get_flags("firefox")),
"chrome": ("chromium", cfg.get_flags("chrome")),
# TODO: enable webkit
# "webkit": (),
}
Expand Down
35 changes: 18 additions & 17 deletions pytest_pyodide/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
import pexpect
import pytest

CHROME_FLAGS: list[str] = ["--js-flags=--expose-gc"]
FIREFOX_FLAGS: list[str] = []
NODE_FLAGS: list[str] = []

from .config import RUNTIMES, get_global_config

TEST_SETUP_CODE = """
Error.stackTraceLimit = Infinity;
Expand Down Expand Up @@ -89,8 +86,6 @@
};
""".strip()

INITIALIZE_SCRIPT = "pyodide.runPython('');"


class JavascriptException(Exception):
def __init__(self, msg, stack):
Expand All @@ -105,10 +100,17 @@ def __str__(self):


class _BrowserBaseRunner:
browser = ""
browser: RUNTIMES = "" # type: ignore[assignment]
script_timeout = 20
JavascriptException = JavascriptException

# A common script that runs after pyodide is loaded
POST_LOAD_PYODIDE_SCRIPT = """
self.pyodide = pyodide;
globalThis.pyodide = pyodide;
pyodide._api.inTestHoist = true; // improve some error messages for tests
"""

def __init__(
self,
server_port,
Expand All @@ -121,13 +123,16 @@ def __init__(
*args,
**kwargs,
):
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.script_type = script_type
self.dist_dir = dist_dir
self.driver = self.get_driver(jspi)

self.set_script_timeout(self.script_timeout)
self.prepare_driver()
self.javascript_setup()
Expand Down Expand Up @@ -171,12 +176,8 @@ def javascript_setup(self):

def load_pyodide(self):
self.run_js(
"""
let pyodide = await loadPyodide({ fullStdLib: false, jsglobals : self });
self.pyodide = pyodide;
globalThis.pyodide = pyodide;
pyodide._api.inTestHoist = true; // improve some error messages for tests
"""
self._config.get_load_pyodide_script(self.browser)
+ self.POST_LOAD_PYODIDE_SCRIPT
)

def initialize_pyodide(self):
Expand All @@ -201,7 +202,7 @@ def initialize_pyodide(self):
}
"""
)
self.run_js(INITIALIZE_SCRIPT)
self.run_js(self._config.get_initialize_script())
from .decorator import initialize_decorator

initialize_decorator(self)
Expand Down Expand Up @@ -430,7 +431,7 @@ def get_driver(self, jspi=False):

options = Options()
options.add_argument("--headless")
for flag in FIREFOX_FLAGS:
for flag in self._config.get_flags("firefox"):
options.add_argument(flag)

return Firefox(service=Service(), options=options)
Expand All @@ -449,7 +450,7 @@ def get_driver(self, jspi=False):
if jspi:
options.add_argument("--enable-features=WebAssemblyExperimentalJSPI")
options.add_argument("--enable-experimental-webassembly-features")
for flag in CHROME_FLAGS:
for flag in self._config.get_flags("chrome"):
options.add_argument(flag)
return Chrome(options=options)

Expand Down Expand Up @@ -544,7 +545,7 @@ def init_node(self, jspi=False):
f"Node version {node_version} is too old, please use node >= 18"
)

extra_args = NODE_FLAGS[:]
extra_args = self._config.get_flags("node")[:]
# Node v14 require the --experimental-wasm-bigint which
# produces errors on later versions
if jspi:
Expand Down
25 changes: 25 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from pytest_pyodide.config import Config, get_global_config


def test_config():
c = Config()

runtimes = ["chrome", "firefox", "node", "safari"]

for runtime in runtimes:
c.get_flags(runtime)
c.get_load_pyodide_script(runtime)

c.set_flags(runtime, ["--headless"])
assert c.get_flags(runtime) == ["--headless"]

c.set_load_pyodide_script(runtime, "console.log('hello')")
assert c.get_load_pyodide_script(runtime) == "console.log('hello')"

c.get_initialize_script()
c.set_initialize_script("console.log('hello')")
assert c.get_initialize_script() == "console.log('hello')"


def test_global_config():
assert get_global_config() is get_global_config()

0 comments on commit d7da97c

Please sign in to comment.