Skip to content

Commit 4b72ba4

Browse files
authored
MAINT Remove remaining codes that import compat functions directly (#263)
1 parent 24aa530 commit 4b72ba4

7 files changed

Lines changed: 80 additions & 67 deletions

File tree

micropip/package_manager.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
)
1212

1313
from . import _mock_package, package_index
14-
from ._compat import CompatibilityLayer, compatibility_layer
14+
from ._compat import CompatibilityLayer
1515
from ._utils import get_files_in_distribution, get_root
1616
from ._vendored.packaging.src.packaging.markers import default_environment
1717
from .constants import FAQ_URLS
@@ -29,10 +29,7 @@ class PackageManager:
2929
independent of other instances.
3030
"""
3131

32-
def __init__(self, compat: type[CompatibilityLayer] | None = None) -> None:
33-
34-
if compat is None:
35-
compat = compatibility_layer
32+
def __init__(self, compat: type[CompatibilityLayer]) -> None:
3633

3734
self.index_urls = package_index.DEFAULT_INDEX_URLS[:]
3835
self.compat_layer: type[CompatibilityLayer] = compat
@@ -239,7 +236,9 @@ async def install(
239236
# Install PyPI packages
240237
# detect whether the wheel metadata is from PyPI or from custom location
241238
# wheel metadata from PyPI has SHA256 checksum digest.
242-
await asyncio.gather(*(wheel.install(wheel_base) for wheel in wheels))
239+
await asyncio.gather(
240+
*(wheel.install(wheel_base, self.compat_layer) for wheel in wheels)
241+
)
243242

244243
# Install built-in packages
245244
if pyodide_packages:

micropip/transaction.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,13 +332,17 @@ async def add_wheel(
332332
logger.info("Collecting %s%s", wheel.name, specifier)
333333
logger.info(" Downloading %s", wheel.url.split("/")[-1])
334334

335-
wheel_download_task = asyncio.create_task(wheel.download(self.fetch_kwargs))
335+
wheel_download_task = asyncio.create_task(
336+
wheel.download(self.fetch_kwargs, self._compat_layer)
337+
)
336338
if self.deps:
337339
# Case 1) If metadata file is available,
338340
# we can gather requirements without waiting for the wheel to be downloaded.
339341
if wheel.pep658_metadata_available():
340342
try:
341-
await wheel.download_pep658_metadata(self.fetch_kwargs)
343+
await wheel.download_pep658_metadata(
344+
self.fetch_kwargs, self._compat_layer
345+
)
342346
except OSError:
343347
# If something goes wrong while downloading the metadata,
344348
# we have to wait for the wheel to be downloaded.

micropip/wheelinfo.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@
77
from typing import Any, Literal
88
from urllib.parse import ParseResult, unquote, urlparse
99

10-
from ._compat import (
11-
fetch_bytes,
12-
install,
13-
loadedPackages,
14-
to_js,
15-
)
10+
from ._compat import CompatibilityLayer
1611
from ._utils import best_compatible_tag_index, parse_wheel_filename
1712
from ._vendored.packaging.src.packaging.requirements import Requirement
1813
from ._vendored.packaging.src.packaging.tags import Tag
@@ -132,7 +127,9 @@ def from_package_index(
132127
_best_tag_index=best_tag_index,
133128
)
134129

135-
async def install(self, target: Path) -> None:
130+
async def install(
131+
self, target: Path, compat_layer: type[CompatibilityLayer]
132+
) -> None:
136133
"""
137134
Install the wheel to the target directory.
138135
@@ -148,13 +145,15 @@ async def install(self, target: Path) -> None:
148145
"Micropip internal error: attempted to install wheel before downloading it?"
149146
)
150147
_validate_sha256_checksum(self._data, self.sha256)
151-
await self._install(target)
148+
await self._install(target, compat_layer)
152149

153-
async def download(self, fetch_kwargs: dict[str, Any]):
150+
async def download(
151+
self, fetch_kwargs: dict[str, Any], compat_layer: type[CompatibilityLayer]
152+
):
154153
if self._data is not None:
155154
return
156155

157-
self._data = await self._fetch_bytes(self.url, fetch_kwargs)
156+
self._data = await self._fetch_bytes(self.url, fetch_kwargs, compat_layer)
158157

159158
# The wheel's metadata might be downloaded separately from the wheel itself.
160159
# If it is not downloaded yet or if the metadata is not available, extract it from the wheel.
@@ -174,14 +173,15 @@ def pep658_metadata_available(self) -> bool:
174173
async def download_pep658_metadata(
175174
self,
176175
fetch_kwargs: dict[str, Any],
176+
compat_layer: type[CompatibilityLayer],
177177
) -> None:
178178
"""
179179
Download the wheel's metadata. If the metadata is not available, return None.
180180
"""
181181
if self.core_metadata is None:
182182
return None
183183

184-
data = await self._fetch_bytes(self.metadata_url, fetch_kwargs)
184+
data = await self._fetch_bytes(self.metadata_url, fetch_kwargs, compat_layer)
185185

186186
match self.core_metadata:
187187
case {"sha256": checksum}: # sha256 checksum available
@@ -204,14 +204,19 @@ def requires(self, extras: set[str]) -> list[Requirement]:
204204
self._requires = requires
205205
return requires
206206

207-
async def _fetch_bytes(self, url: str, fetch_kwargs: dict[str, Any]):
207+
async def _fetch_bytes(
208+
self,
209+
url: str,
210+
fetch_kwargs: dict[str, Any],
211+
compat_layer: type[CompatibilityLayer],
212+
):
208213
if self.parsed_url.scheme not in ("https", "http", "emfs", "file"):
209214
# Don't raise ValueError it gets swallowed
210215
raise TypeError(
211216
f"Cannot download from a non-remote location: {url!r} ({self.parsed_url!r})"
212217
)
213218
try:
214-
bytes = await fetch_bytes(url, fetch_kwargs)
219+
bytes = await compat_layer.fetch_bytes(url, fetch_kwargs)
215220
return bytes
216221
except OSError as e:
217222
if self.parsed_url.hostname in [
@@ -228,7 +233,9 @@ async def _fetch_bytes(self, url: str, fetch_kwargs: dict[str, Any]):
228233
) from e
229234
raise e
230235

231-
async def _install(self, target: Path) -> None:
236+
async def _install(
237+
self, target: Path, compat_layer: type[CompatibilityLayer]
238+
) -> None:
232239
"""
233240
Install the wheel to the target directory.
234241
"""
@@ -247,15 +254,15 @@ async def _install(self, target: Path) -> None:
247254
sorted(x.name for x in self._requires)
248255
)
249256

250-
await install(
257+
await compat_layer.install(
251258
# TODO: Probably update install API to accept bytes directly, instead of converting it to JS.
252-
to_js(self._data),
259+
compat_layer.to_js(self._data),
253260
self.filename,
254261
str(target),
255262
metadata,
256263
)
257264

258-
setattr(loadedPackages, self._project_name, wheel_source)
265+
setattr(compat_layer.loadedPackages, self._project_name, wheel_source)
259266

260267

261268
def _validate_sha256_checksum(data: bytes, expected: str | None = None) -> None:

tests/conftest.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ def __eq__(self, other):
240240

241241

242242
class mock_fetch_cls:
243-
def __init__(self):
243+
def __init__(self, compat_layer=None):
244+
self._compat_layer = compat_layer
244245
self.releases_map = {}
245246
self.metadata_map = {}
246247
self.top_level_map = {}
@@ -351,12 +352,12 @@ def write_file(filename, contents):
351352

352353

353354
@pytest.fixture
354-
def mock_fetch(monkeypatch, mock_importlib):
355-
from micropip import package_index, wheelinfo
355+
def mock_fetch(monkeypatch, mock_importlib, host_compat_layer):
356+
from micropip import package_index
356357

357-
result = mock_fetch_cls()
358+
result = mock_fetch_cls(host_compat_layer)
358359
monkeypatch.setattr(package_index, "query_package", result.query_package)
359-
monkeypatch.setattr(wheelinfo, "fetch_bytes", result._fetch_bytes)
360+
monkeypatch.setattr(host_compat_layer, "fetch_bytes", result._fetch_bytes)
360361
return result
361362

362363

@@ -469,3 +470,15 @@ def host_compat_layer():
469470
from micropip._compat._compat_not_in_pyodide import CompatibilityNotInPyodide
470471

471472
yield CompatibilityNotInPyodide
473+
474+
475+
@pytest.fixture
476+
def host_package_manager(host_compat_layer):
477+
"""
478+
Fixture to provide a package manager for the host environment.
479+
"""
480+
from micropip.package_manager import PackageManager
481+
482+
package_manager = PackageManager(compat=host_compat_layer)
483+
484+
yield package_manager

tests/test_install.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,14 +264,13 @@ async def test_install_pre(
264264

265265

266266
@pytest.mark.asyncio
267-
async def test_fetch_wheel_fail(monkeypatch, wheel_base):
267+
async def test_fetch_wheel_fail(monkeypatch, wheel_base, host_compat_layer):
268268
import micropip
269-
from micropip import wheelinfo
270269

271270
def _mock_fetch_bytes(arg, *args, **kwargs):
272271
raise OSError(f"Request for {arg} failed with status 404: Not Found")
273272

274-
monkeypatch.setattr(wheelinfo, "fetch_bytes", _mock_fetch_bytes)
273+
monkeypatch.setattr(host_compat_layer, "fetch_bytes", _mock_fetch_bytes)
275274

276275
msg = "Access-Control-Allow-Origin"
277276
with pytest.raises(ValueError, match=msg):
@@ -395,7 +394,9 @@ async def run_test(selenium, url, name, version):
395394

396395

397396
@pytest.mark.asyncio
398-
async def test_custom_index_urls(mock_package_index_json_api, monkeypatch):
397+
async def test_custom_index_urls(
398+
mock_package_index_json_api, monkeypatch, host_compat_layer
399+
):
399400
mock_server_fake_package = mock_package_index_json_api(
400401
pkgs=["fake-pkg-micropip-test"]
401402
)
@@ -407,9 +408,7 @@ async def _mock_fetch_bytes(url, *args):
407408
_wheel_url = url
408409
return b"fake wheel"
409410

410-
from micropip import wheelinfo
411-
412-
monkeypatch.setattr(wheelinfo, "fetch_bytes", _mock_fetch_bytes)
411+
monkeypatch.setattr(host_compat_layer, "fetch_bytes", _mock_fetch_bytes)
413412

414413
try:
415414
await micropip.install(

tests/test_package_manager.py

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,10 @@
22
from conftest import mock_fetch_cls
33

44
import micropip.package_index as package_index
5-
from micropip.package_manager import PackageManager
65

76

8-
def get_test_package_manager() -> PackageManager:
9-
package_manager = PackageManager()
10-
11-
# TODO: inject necessary constructor parameters
12-
13-
return package_manager
14-
15-
16-
def test_set_index_urls():
17-
manager = get_test_package_manager()
7+
def test_set_index_urls(host_package_manager):
8+
manager = host_package_manager
189

1910
default_index_urls = package_index.DEFAULT_INDEX_URLS
2011
assert manager.index_urls == default_index_urls
@@ -34,8 +25,8 @@ def test_set_index_urls():
3425

3526

3627
@pytest.mark.asyncio
37-
async def test_list_packages(mock_fetch: mock_fetch_cls):
38-
manager = get_test_package_manager()
28+
async def test_list_packages(mock_fetch: mock_fetch_cls, host_package_manager):
29+
manager = host_package_manager
3930

4031
dummy = "dummy"
4132
mock_fetch.add_pkg_version(dummy)
@@ -50,8 +41,10 @@ async def test_list_packages(mock_fetch: mock_fetch_cls):
5041

5142

5243
@pytest.mark.asyncio
53-
async def test_custom_index_url(mock_package_index_json_api, monkeypatch):
54-
manager = get_test_package_manager()
44+
async def test_custom_index_url(
45+
mock_package_index_json_api, monkeypatch, host_compat_layer, host_package_manager
46+
):
47+
manager = host_package_manager
5548

5649
mock_server_fake_package = mock_package_index_json_api(
5750
pkgs=["fake-pkg-micropip-test"]
@@ -64,9 +57,7 @@ async def _mock_fetch_bytes(url, *args):
6457
_wheel_url = url
6558
return b"fake wheel"
6659

67-
from micropip import wheelinfo
68-
69-
monkeypatch.setattr(wheelinfo, "fetch_bytes", _mock_fetch_bytes)
60+
monkeypatch.setattr(host_compat_layer, "fetch_bytes", _mock_fetch_bytes)
7061

7162
manager.set_index_urls([mock_server_fake_package])
7263

tests/test_wheelinfo.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,24 @@ def test_from_package_index():
5151

5252

5353
@pytest.mark.asyncio
54-
async def test_download(wheel_catalog):
54+
async def test_download(wheel_catalog, host_compat_layer):
5555
pytest_wheel = wheel_catalog.get("pytest")
5656
wheel = WheelInfo.from_url(pytest_wheel.url)
5757

5858
assert wheel._metadata is None
5959

60-
await wheel.download({})
60+
await wheel.download({}, host_compat_layer)
6161

6262
assert wheel._metadata is not None
6363

6464

6565
@pytest.mark.asyncio
66-
async def test_requires(wheel_catalog, tmp_path):
66+
async def test_requires(wheel_catalog, tmp_path, host_compat_layer):
6767
pytest_wheel = wheel_catalog.get("pytest")
6868
wheel = WheelInfo.from_url(pytest_wheel.url)
69-
await wheel.download({})
69+
await wheel.download({}, host_compat_layer)
7070

71-
wheel._install(tmp_path)
71+
wheel._install(tmp_path, host_compat_layer)
7272

7373
requirements_default = [str(r.name) for r in wheel.requires(set())]
7474
assert "pluggy" in requirements_default
@@ -80,7 +80,7 @@ async def test_requires(wheel_catalog, tmp_path):
8080

8181

8282
@pytest.mark.asyncio
83-
async def test_download_pep658_metadata(wheel_catalog):
83+
async def test_download_pep658_metadata(wheel_catalog, host_compat_layer):
8484
pytest_wheel = wheel_catalog.get("pytest")
8585
sha256 = "dummy-sha256"
8686
size = 1234
@@ -98,7 +98,7 @@ async def test_download_pep658_metadata(wheel_catalog):
9898

9999
assert wheel_with_metadata.pep658_metadata_available()
100100
assert wheel_with_metadata._metadata is None
101-
await wheel_with_metadata.download_pep658_metadata({})
101+
await wheel_with_metadata.download_pep658_metadata({}, host_compat_layer)
102102
assert wheel_with_metadata._metadata is not None
103103

104104
# metadata should be calculated from the metadata file
@@ -119,7 +119,7 @@ async def test_download_pep658_metadata(wheel_catalog):
119119

120120
assert not wheel_without_metadata.pep658_metadata_available()
121121
assert wheel_without_metadata._metadata is None
122-
await wheel_without_metadata.download_pep658_metadata({})
122+
await wheel_without_metadata.download_pep658_metadata({}, host_compat_layer)
123123
assert wheel_without_metadata._metadata is None
124124

125125
# 3) the metadata extracted from the wheel should be the same
@@ -134,14 +134,14 @@ async def test_download_pep658_metadata(wheel_catalog):
134134
)
135135

136136
assert wheel._metadata is None
137-
await wheel.download({})
137+
await wheel.download({}, host_compat_layer)
138138
assert wheel._metadata is not None
139139

140140
assert wheel._metadata.deps == wheel_with_metadata._metadata.deps
141141

142142

143143
@pytest.mark.asyncio
144-
async def test_download_pep658_metadata_checksum(wheel_catalog):
144+
async def test_download_pep658_metadata_checksum(wheel_catalog, host_compat_layer):
145145
pytest_wheel = wheel_catalog.get("pytest")
146146
sha256 = "dummy-sha256"
147147
size = 1234
@@ -158,7 +158,7 @@ async def test_download_pep658_metadata_checksum(wheel_catalog):
158158

159159
assert wheel._metadata is None
160160
with pytest.raises(RuntimeError, match="Invalid checksum: expected dummy-sha256"):
161-
await wheel.download_pep658_metadata({})
161+
await wheel.download_pep658_metadata({}, host_compat_layer)
162162

163163
checksum = "62eb95408ccec185e7a3b8f354a1df1721cd8f463922f5a900c7bf4b69c5a4e8" # TODO: calculate this from the file
164164
wheel = WheelInfo.from_package_index(
@@ -172,5 +172,5 @@ async def test_download_pep658_metadata_checksum(wheel_catalog):
172172
)
173173

174174
assert wheel._metadata is None
175-
await wheel.download_pep658_metadata({})
175+
await wheel.download_pep658_metadata({}, host_compat_layer)
176176
assert wheel._metadata is not None

0 commit comments

Comments
 (0)