Skip to content
Merged
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
14 changes: 8 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ keywords = ["eeg", "preprocessing", "EEGLAB"]
dependencies = [
"colorama>=0.4.6",
"eeglabio>=0.1.2",
# The h5py, matplotlib, numpy and threadpoolctl floors here, and the scipy
# floors below, are capped by what Pyodide 0.29.5 ships for a browser install.
# Raising one past Pyodide's shipped version breaks eegprep in the browser, so
# check against the Pyodide release before bumping any of them.
# Shipped by 0.29.5: h5py 3.13.0, matplotlib 3.8.4, numpy 2.2.5, scipy 1.14.1,
# threadpoolctl 3.5.0. tests/test_browser_dependency_floors.py enforces this.
# h5py, matplotlib and numpy here, and scipy below, publish no pure-Python wheel,
# so in a browser only Pyodide's bundled build is available and micropip cannot
# substitute another version. Their floors are therefore a ceiling: raising one
# past what Pyodide ships makes the install impossible, not merely larger.
# Shipped by 0.29.5: h5py 3.13.0, matplotlib 3.8.4, numpy 2.2.5, scipy 1.14.1.
# threadpoolctl is bundled too but is pure Python, so micropip can fetch any
# version from PyPI and its floor is not constrained this way.
# tests/test_browser_dependency_floors.py enforces the distinction.
"h5py>=3.12.1",
"matplotlib>=3.8.0",
"mne>=1.10.0",
Expand Down
30 changes: 21 additions & 9 deletions tests/test_browser_dependency_floors.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,26 @@
# the version and this table together when the target release moves.
PYODIDE_VERSION = "0.29.5"
PYODIDE_PYTHON = "3.13.2"
PYODIDE_SHIPS = {

# Packages Pyodide bundles that publish NO pure-Python wheel on PyPI. micropip cannot substitute
# a different version for these, so the bundled build is the only one a browser can have and the
# declared constraint has to be satisfiable by it. This is the set that makes a floor a ceiling.
PYODIDE_COMPILED = {
"h5py": "3.13.0",
"matplotlib": "3.8.4",
"numpy": "2.2.5",
"scipy": "1.14.1",
}

# Also bundled, but pure Python, so micropip can pull any version straight from PyPI and a floor
# above the bundled one costs an extra download rather than breaking the install. Recorded so the
# distinction is explicit, and deliberately not enforced.
PYODIDE_PURE_PYTHON = {
"threadpoolctl": "3.5.0",
}

PYODIDE_SHIPS = {**PYODIDE_COMPILED, **PYODIDE_PURE_PYTHON}

# A packaging marker environment describing Pyodide's interpreter, so a dependency guarded by
# a marker is evaluated the way the browser would evaluate it. Pyodide reports
# ``sys.platform == "emscripten"``, which is what makes the darwin-only scipy floor inactive here.
Expand Down Expand Up @@ -79,26 +91,26 @@ def _declared_floor(requirement: Requirement) -> Version:
return max(floors)


@pytest.mark.parametrize("package", sorted(PYODIDE_SHIPS))
@pytest.mark.parametrize("package", sorted(PYODIDE_COMPILED))
def test_floor_does_not_exceed_what_pyodide_ships(package: str) -> None:
requirement = _requirements_active_in_pyodide().get(package)
assert requirement is not None, f"{package} is no longer a base dependency; drop it from PYODIDE_SHIPS"
assert requirement is not None, f"{package} is no longer a base dependency; drop it from PYODIDE_COMPILED"

floor = _declared_floor(requirement)
shipped = Version(PYODIDE_SHIPS[package])
shipped = Version(PYODIDE_COMPILED[package])
assert floor <= shipped, (
f"{package}>={floor} is above the {shipped} that Pyodide {PYODIDE_VERSION} ships, "
f"so a browser install cannot satisfy it"
)


@pytest.mark.parametrize("package", sorted(PYODIDE_SHIPS))
@pytest.mark.parametrize("package", sorted(PYODIDE_COMPILED))
def test_pyodide_version_satisfies_the_whole_specifier(package: str) -> None:
"""The floor is not the only bound; an upper bound can exclude Pyodide's build too."""
requirement = _requirements_active_in_pyodide().get(package)
assert requirement is not None, f"{package} is no longer a base dependency; drop it from PYODIDE_SHIPS"
assert requirement is not None, f"{package} is no longer a base dependency; drop it from PYODIDE_COMPILED"

shipped = PYODIDE_SHIPS[package]
shipped = PYODIDE_COMPILED[package]
assert requirement.specifier.contains(shipped, prereleases=True), (
f"Pyodide {PYODIDE_VERSION} ships {package} {shipped}, which {requirement} excludes"
)
Expand All @@ -124,7 +136,7 @@ def test_the_darwin_scipy_floor_stays_out_of_the_browser() -> None:
and requirement.marker.evaluate(darwin)
]
assert darwin_floors, "the darwin-specific scipy floor is gone; update or remove this test"
assert max(darwin_floors) > Version(PYODIDE_SHIPS["scipy"]), (
assert max(darwin_floors) > Version(PYODIDE_COMPILED["scipy"]), (
"the darwin scipy floor no longer exceeds Pyodide's build, so the marker split may be "
"unnecessary; confirm before removing this test"
)
Expand All @@ -133,5 +145,5 @@ def test_the_darwin_scipy_floor_stays_out_of_the_browser() -> None:
for raw in _project()["dependencies"]
if (requirement := Requirement(raw)).name == "scipy"
and requirement.marker is not None
and _declared_floor(requirement) > Version(PYODIDE_SHIPS["scipy"])
and _declared_floor(requirement) > Version(PYODIDE_COMPILED["scipy"])
), "a scipy floor above Pyodide's build is active under Pyodide"
Loading