Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ check_untyped_defs = true
disallow_any_generics = true
disallow_subclassing_any = true
disallow_untyped_calls = false
disallow_untyped_defs = false
disallow_incomplete_defs = false
disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
Expand All @@ -70,6 +70,18 @@ no_implicit_reexport = true
strict_equality = true

ignore_missing_imports = true

[[tool.mypy.overrides]]
module = [
"pytest_pyodide.doctest",
"pytest_pyodide.fixture",
"pytest_pyodide.hook",
"pytest_pyodide.runner",
"pytest_pyodide.server",
"test_install_package"
]
disallow_untyped_defs = false

# this

[tool.ruff]
Expand Down
5 changes: 3 additions & 2 deletions pytest_pyodide/_decorator_in_pyodide.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from base64 import b64decode, b64encode
from inspect import isclass
from io import BytesIO
from types import FrameType

Check warning on line 23 in pytest_pyodide/_decorator_in_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/_decorator_in_pyodide.py#L23

Added line #L23 was not covered by tests
from typing import Any

import pyodide_js
Expand Down Expand Up @@ -60,7 +61,7 @@
pyodide_js._module._Py_IncRef(obj.ptr)
return ("PyodideHandle", obj.ptr)

def reducer_override(self, obj):
def reducer_override(self, obj: Any) -> Any:

Check warning on line 64 in pytest_pyodide/_decorator_in_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/_decorator_in_pyodide.py#L64

Added line #L64 was not covered by tests
try:
from _pytest.outcomes import OutcomeException

Expand Down Expand Up @@ -125,7 +126,7 @@
# If tblib is present, we can show much better tracebacks.
from tblib import pickling_support

def get_locals(frame):
def get_locals(frame: FrameType) -> dict[str, Any]:

Check warning on line 129 in pytest_pyodide/_decorator_in_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/_decorator_in_pyodide.py#L129

Added line #L129 was not covered by tests
result = {}
tbhide = frame.f_locals.get("__tracebackhide__")
if tbhide:
Expand Down
14 changes: 8 additions & 6 deletions pytest_pyodide/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@


class Config:
def __init__(self):
def __init__(self) -> None:

Check warning on line 16 in pytest_pyodide/config.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/config.py#L16

Added line #L16 was not covered by tests
# Flags to be passed to the browser or runtime.
self.flags: dict[RUNTIMES, list[str]] = {
"chrome": ["--js-flags=--expose-gc"],
Expand All @@ -32,27 +32,29 @@

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

def set_flags(self, runtime: RUNTIMES, flags: list[str]):
def set_flags(self, runtime: RUNTIMES, flags: list[str]) -> None:

Check warning on line 37 in pytest_pyodide/config.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/config.py#L37

Added line #L37 was not covered by tests
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):
def set_load_pyodide_script(

Check warning on line 43 in pytest_pyodide/config.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/config.py#L43

Added line #L43 was not covered by tests
self, runtime: RUNTIMES, load_pyodide_script: str
) -> None:
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):
def set_initialize_script(self, initialize_script: str) -> None:

Check warning on line 51 in pytest_pyodide/config.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/config.py#L51

Added line #L51 was not covered by tests
self.initialize_script = initialize_script

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

def add_node_extra_globals(self, l: Iterable[str]):
def add_node_extra_globals(self, l: Iterable[str]) -> None:

Check warning on line 57 in pytest_pyodide/config.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/config.py#L57

Added line #L57 was not covered by tests
self.node_extra_globals.extend(l)

def get_node_extra_globals(self) -> Sequence[str]:
Expand Down
15 changes: 9 additions & 6 deletions pytest_pyodide/copy_files_to_pyodide.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
from collections.abc import MutableSequence, Sequence
from pathlib import Path
from typing import Any
from typing import TYPE_CHECKING

Check warning on line 3 in pytest_pyodide/copy_files_to_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/copy_files_to_pyodide.py#L3

Added line #L3 was not covered by tests

if TYPE_CHECKING:
from .runner import _BrowserBaseRunner

Check warning on line 6 in pytest_pyodide/copy_files_to_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/copy_files_to_pyodide.py#L5-L6

Added lines #L5 - L6 were not covered by tests

from .server import spawn_web_server

_copied_files: dict[Any, MutableSequence[tuple[Path, str]]] = {}
_copied_files: dict["_BrowserBaseRunner", MutableSequence[tuple[Path, str]]] = {}

Check warning on line 10 in pytest_pyodide/copy_files_to_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/copy_files_to_pyodide.py#L10

Added line #L10 was not covered by tests


def copy_files_to_emscripten_fs(
file_list: Sequence[Path | str | tuple[Path | str, Path | str]],
selenium: Any,
install_wheels=True,
recurse_directories=True,
):
selenium: "_BrowserBaseRunner",
install_wheels: bool = True,
recurse_directories: bool = True,
) -> None:
"""
Copies files in file_list to the emscripten file system. Files
are passed as a list of source Path / install Path pairs.
Expand Down
43 changes: 28 additions & 15 deletions pytest_pyodide/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,37 @@
import pickle
import sys
from base64 import b64decode, b64encode
from collections.abc import Callable, Collection
from collections.abc import Callable, Collection, Sequence

Check warning on line 6 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L6

Added line #L6 was not covered by tests
from copy import deepcopy
from io import BytesIO
from typing import Any, Protocol
from pathlib import Path
from typing import TYPE_CHECKING, Any, ParamSpec, Protocol, TypeVar

Check warning on line 10 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L9-L10

Added lines #L9 - L10 were not covered by tests

from .copy_files_to_pyodide import copy_files_to_emscripten_fs
from .hook import ORIGINAL_MODULE_ASTS, REWRITTEN_MODULE_ASTS, pytest_wrapper
from .runner import _BrowserBaseRunner
from .utils import package_is_built as _package_is_built

if TYPE_CHECKING:
from .runner import _BrowserBaseRunner

Check warning on line 17 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L16-L17

Added lines #L16 - L17 were not covered by tests

MaybeAsyncFuncDef = ast.FunctionDef | ast.AsyncFunctionDef


def package_is_built(package_name: str):
def package_is_built(package_name: str) -> bool:

Check warning on line 22 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L22

Added line #L22 was not covered by tests
return _package_is_built(package_name, pytest_wrapper.pyodide_dist_dir)


class SeleniumType(Protocol):
JavascriptException: type
browser: str

def load_package(self, pkgs: str | list[str]):
def load_package(self, pkgs: str | list[str]) -> None:

Check warning on line 30 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L30

Added line #L30 was not covered by tests
...

def run_async(self, code: str):
def run_async(self, code: str) -> Any:

Check warning on line 33 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L33

Added line #L33 was not covered by tests
...

def run_js(self, code: str):
def run_js(self, code: str) -> Any:

Check warning on line 36 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L36

Added line #L36 was not covered by tests
...


Expand Down Expand Up @@ -78,7 +81,7 @@
self.selenium = selenium
self.ptr: int | None = ptr

def __del__(self):
def __del__(self) -> None:

Check warning on line 84 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L84

Added line #L84 was not covered by tests
if self.ptr is None:
return
ptr = self.ptr
Expand Down Expand Up @@ -261,7 +264,7 @@
# This will show:
# > run(selenium_arg_name, (arg1, arg2, ...))
# in the traceback.
def fake_body_for_traceback(arg1, arg2, selenium_arg_name):
def fake_body_for_traceback(arg1: Any, arg2: Any, selenium_arg_name: str) -> None:
run(selenium_arg_name, (arg1, arg2, ...))

# Adjust line numbers to point into our fake function
Expand All @@ -280,7 +283,7 @@
return globs[funcdef.name] # type: ignore[no-any-return]


def initialize_decorator(selenium):
def initialize_decorator(selenium: "_BrowserBaseRunner") -> None:

Check warning on line 286 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L286

Added line #L286 was not covered by tests
from pathlib import Path

_decorator_in_pyodide = (
Expand Down Expand Up @@ -364,7 +367,9 @@


class run_in_pyodide:
def __new__(cls, function: Callable[..., Any] | None = None, /, **kwargs):
def __new__(

Check warning on line 370 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L370

Added line #L370 was not covered by tests
cls, function: Callable[..., Any] | None = None, /, **kwargs: Any
) -> Any:
if function:
# Probably we were used like:
#
Expand Down Expand Up @@ -442,7 +447,7 @@
self._async_func = isinstance(funcdef, ast.AsyncFunctionDef)
return wrapper

def _run(self, selenium: SeleniumType, args: tuple[Any, ...]):
def _run(self, selenium: SeleniumType, args: tuple[Any, ...]) -> Any:

Check warning on line 450 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L450

Added line #L450 was not covered by tests
"""The main runner, called from the AST generated in _create_outer_func."""
__tracebackhide__ = True
code = self._code_template(args)
Expand Down Expand Up @@ -485,12 +490,20 @@
"""


def copy_files_to_pyodide(file_list, install_wheels=True, recurse_directories=True):
T = TypeVar("T")
P = ParamSpec("P")

Check warning on line 494 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L493-L494

Added lines #L493 - L494 were not covered by tests


def copy_files_to_pyodide(

Check warning on line 497 in pytest_pyodide/decorator.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/decorator.py#L497

Added line #L497 was not covered by tests
file_list: Sequence[Path | str | tuple[Path | str, Path | str]],
install_wheels: bool = True,
recurse_directories: bool = True,
) -> Callable[[Callable[P, T]], Callable[P, T]]:
"""A decorator that copies files across to pyodide"""

def wrap(fn):
def wrap(fn: Callable[P, T]) -> Callable[P, T]:
@functools.wraps(fn)
def wrapped_f(*args, **argv):
def wrapped_f(*args: P.args, **argv: P.kwargs) -> T:
# get selenium from args
selenium = None
for a in args:
Expand Down
3 changes: 2 additions & 1 deletion pytest_pyodide/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from copy import copy
from doctest import DocTest, DocTestRunner, register_optionflag
from pathlib import Path
from typing import Any

from _pytest.doctest import (
DoctestModule,
Expand Down Expand Up @@ -115,7 +116,7 @@ def run_doctest_in_pyodide_outer(
compileflags: int | None = None,
out: Callable[[str], object] | None = None,
clear_globs: bool = True,
):
) -> Any:
if not getattr(test, "pyodide_test", None):
# Run host test as normal
return host_DocTestRunner_run(self, test, compileflags, out, clear_globs)
Expand Down
7 changes: 3 additions & 4 deletions pytest_pyodide/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,15 @@
rt[0].params = pytest_wrapper.pyodide_runtimes


def pytest_collection(session: Session):
def pytest_collection(session: Session) -> None:

Check warning on line 189 in pytest_pyodide/hook.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/hook.py#L189

Added line #L189 was not covered by tests
from .doctest import patch_doctest_runner

patch_doctest_runner()
session.config.option.doctestmodules_ = session.config.option.doctestmodules
set_runtime_fixture_params(session)


def pytest_collect_file(file_path: Path, parent: Collector):
def pytest_collect_file(file_path: Path, parent: Collector) -> Any:

Check warning on line 197 in pytest_pyodide/hook.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/hook.py#L197

Added line #L197 was not covered by tests
# Have to set doctestmodules to False to prevent original hook from
# triggering
parent.config.option.doctestmodules = False
Expand Down Expand Up @@ -258,7 +258,7 @@
return False


def modifyitems_run_in_pyodide(items: list[Any]):
def modifyitems_run_in_pyodide(items: list[Any]) -> None:

Check warning on line 261 in pytest_pyodide/hook.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/hook.py#L261

Added line #L261 was not covered by tests
# TODO: get rid of this
# if we are running tests in pyodide, then run all tests for each runtime
new_items = []
Expand All @@ -273,7 +273,6 @@
x.pyodide_runtime = runtime
new_items.append(x)
items[:] = new_items
return


def pytest_collection_modifyitems(items: list[Any]) -> None:
Expand Down
11 changes: 6 additions & 5 deletions pytest_pyodide/hypothesis.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import io
import pickle
from typing import Any
from zoneinfo import ZoneInfo

from hypothesis import HealthCheck, settings, strategies


def is_picklable(x):
def is_picklable(x: Any) -> bool:
try:
pickle.dumps(x)
return True
except Exception:
return False


def is_equal_to_self(x):
def is_equal_to_self(x: Any) -> bool:
try:
return x == x
return bool(x == x)

Check warning on line 19 in pytest_pyodide/hypothesis.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/hypothesis.py#L19

Added line #L19 was not covered by tests
except Exception:
return False

Expand All @@ -29,14 +30,14 @@


class NoHypothesisUnpickler(pickle.Unpickler):
def find_class(self, module, name):
def find_class(self, module: str, name: str) -> Any:
# Only allow safe classes from builtins.
if module == "hypothesis":
raise pickle.UnpicklingError()
return super().find_class(module, name)


def no_hypothesis(x):
def no_hypothesis(x: Any) -> bool:
try:
NoHypothesisUnpickler(io.BytesIO(pickle.dumps(x))).load()
return True
Expand Down
16 changes: 10 additions & 6 deletions pytest_pyodide/run_tests_inside_pyodide.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from contextlib import AbstractContextManager
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, Generic, TypeVar
from typing import TYPE_CHECKING, Any, Generic, TypeVar

Check warning on line 7 in pytest_pyodide/run_tests_inside_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/run_tests_inside_pyodide.py#L7

Added line #L7 was not covered by tests

if TYPE_CHECKING:
from .runner import _BrowserBaseRunner
Expand Down Expand Up @@ -32,10 +32,10 @@
def get_value(self) -> T:
return self.value

def __del__(self):
def __del__(self) -> None:

Check warning on line 35 in pytest_pyodide/run_tests_inside_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/run_tests_inside_pyodide.py#L35

Added line #L35 was not covered by tests
self.close()

def close(self):
def close(self) -> None:

Check warning on line 38 in pytest_pyodide/run_tests_inside_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/run_tests_inside_pyodide.py#L38

Added line #L38 was not covered by tests
if self.ctx_manager is not None:
self.ctx_manager.__exit__(None, None, None)
del self.value
Expand All @@ -52,7 +52,9 @@
_playwright_browser_generator = None


def get_browser_pyodide(request: pytest.FixtureRequest, runtime: str):
def get_browser_pyodide(

Check warning on line 55 in pytest_pyodide/run_tests_inside_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/run_tests_inside_pyodide.py#L55

Added line #L55 was not covered by tests
request: pytest.FixtureRequest, runtime: str
) -> "_BrowserBaseRunner":
"""Start a browser running with pyodide, ready to run pytest
calls. If the same runtime is already running, it will
just return that.
Expand Down Expand Up @@ -110,7 +112,9 @@
return None


def run_test_in_pyodide(node_tree_id, selenium, ignore_fail=False):
def run_test_in_pyodide(

Check warning on line 115 in pytest_pyodide/run_tests_inside_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/run_tests_inside_pyodide.py#L115

Added line #L115 was not covered by tests
node_tree_id: Any, selenium: "_BrowserBaseRunner", ignore_fail: bool = False
) -> bool:
"""This runs a single test (identified by node_tree_id) inside
the pyodide runtime. How it does it is by calling pytest on the
browser pyodide with the full node ID, which is the same
Expand Down Expand Up @@ -162,7 +166,7 @@
return True


def close_pyodide_browsers():
def close_pyodide_browsers() -> None:

Check warning on line 169 in pytest_pyodide/run_tests_inside_pyodide.py

View check run for this annotation

Codecov / codecov/patch

pytest_pyodide/run_tests_inside_pyodide.py#L169

Added line #L169 was not covered by tests
"""Close the browsers that are currently open with
pyodide runtime initialised.

Expand Down
Loading
Loading