Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanking13 committed Jan 20, 2025
1 parent d6cf063 commit 68174f9
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 61 deletions.
7 changes: 2 additions & 5 deletions micropip/_compat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@

loadedPackages = compatibility_layer.loadedPackages

loadDynlibsFromPackage = compatibility_layer.loadDynlibsFromPackage
install = compatibility_layer.install

loadPackage = compatibility_layer.loadPackage

get_dynlibs = compatibility_layer.get_dynlibs

to_js = compatibility_layer.to_js

HttpStatusError = compatibility_layer.HttpStatusError
Expand All @@ -43,9 +41,8 @@
"fetch_bytes",
"fetch_string_and_headers",
"loadedPackages",
"loadDynlibsFromPackage",
"install",
"loadPackage",
"get_dynlibs",
"to_js",
"HttpStatusError",
]
23 changes: 14 additions & 9 deletions micropip/_compat/_compat_in_pyodide.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any
from typing import Any
from urllib.parse import urlparse

if TYPE_CHECKING:
pass

from pyodide._package_loader import get_dynlibs
from pyodide.ffi import IN_BROWSER, to_js
from pyodide.http import HttpStatusError, pyfetch

from .compatibility_layer import CompatibilityLayer

try:
from js import Uint8Array
import pyodide_js
from pyodide_js import loadedPackages, loadPackage
from pyodide_js._api import ( # type: ignore[import]
install,
loadBinaryFile,
loadDynlibsFromPackage,
)

REPODATA_PACKAGES = pyodide_js._api.repodata_packages.to_py()
Expand Down Expand Up @@ -70,11 +68,18 @@ async def fetch_string_and_headers(

return content, headers

loadedPackages = loadedPackages

get_dynlibs = get_dynlibs
@staticmethod
async def install(
data: bytes,
filename: str,
install_dir: str,
installer: str,
source: str,
) -> None:
buffer = Uint8Array.new(data)
await install(buffer, filename, install_dir, installer, source)

loadDynlibsFromPackage = loadDynlibsFromPackage
loadedPackages = loadedPackages

loadPackage = loadPackage

Expand Down
29 changes: 14 additions & 15 deletions micropip/_compat/_compat_not_in_pyodide.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import io
import re
from pathlib import Path
from typing import IO, TYPE_CHECKING, Any
from typing import Any
from urllib.error import HTTPError
from urllib.request import Request, urlopen
from urllib.response import addinfourl
import zipfile

from .compatibility_layer import CompatibilityLayer

if TYPE_CHECKING:
from ..wheelinfo import PackageData


class CompatibilityNotInPyodide(CompatibilityLayer):

Expand Down Expand Up @@ -46,6 +44,17 @@ def _fetch(url: str, kwargs: dict[str, Any]) -> addinfourl:
async def fetch_bytes(url: str, kwargs: dict[str, Any]) -> bytes:
return CompatibilityNotInPyodide._fetch(url, kwargs=kwargs).read()

@staticmethod
async def install(
data: bytes,
filename: str,
install_dir: str,
installer: str,
source: str,
) -> None:
with zipfile.ZipFile(io.BytesIO(data)) as zf:
zf.extractall(install_dir)

@staticmethod
async def fetch_string_and_headers(
url: str, kwargs: dict[str, Any]
Expand All @@ -58,16 +67,6 @@ async def fetch_string_and_headers(
headers = {k.lower(): v for k, v in response.headers.items()}
return response.read().decode(), headers

@staticmethod
def get_dynlibs(archive: IO[bytes], suffix: str, target_dir: Path) -> list[str]:
return []

@staticmethod
async def loadDynlibsFromPackage(
pkg_metadata: "PackageData", dynlibs: list[str]
) -> None:
pass

@staticmethod
async def loadPackage(names: str | list[str]) -> None:
pass
Expand Down
16 changes: 7 additions & 9 deletions micropip/_compat/compatibility_layer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from abc import ABC, abstractmethod
from pathlib import Path
from typing import IO, TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from ..wheelinfo import PackageData
Expand Down Expand Up @@ -51,13 +50,12 @@ async def fetch_string_and_headers(

@staticmethod
@abstractmethod
def get_dynlibs(archive: IO[bytes], suffix: str, target_dir: Path) -> list[str]:
pass

@staticmethod
@abstractmethod
async def loadDynlibsFromPackage(
pkg_metadata: "PackageData", dynlibs: list[str]
async def install(
data: bytes,
filename: str,
install_dir: str,
installer: str,
source: str,
) -> None:
pass

Expand Down
31 changes: 8 additions & 23 deletions micropip/wheelinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
get_dynlibs,
loadDynlibsFromPackage,
loadedPackages,
install as _install_wheel,
)
from ._utils import parse_wheel_filename
from .metadata import Metadata, safe_name, wheel_dist_info_dir
Expand Down Expand Up @@ -128,8 +129,13 @@ async def install(self, target: Path) -> None:
"Micropip internal error: attempted to install wheel before downloading it?"
)
_validate_sha256_checksum(self._data, self.sha256)
self._extract(target)
await self._load_libraries(target)
await _install_wheel(
self._data,
self.filename,
install_dir=target,
installer="micropip",
source=self.url,
)
self._set_installer()

async def download(self, fetch_kwargs: dict[str, Any]):
Expand Down Expand Up @@ -209,12 +215,6 @@ async def _fetch_bytes(self, url: str, fetch_kwargs: dict[str, Any]):
"Check if the server is sending the correct 'Access-Control-Allow-Origin' header."
) from e

def _extract(self, target: Path) -> None:
assert self._data
with zipfile.ZipFile(io.BytesIO(self._data)) as zf:
zf.extractall(target)
self._dist_info = target / wheel_dist_info_dir(zf, self.name)

def _set_installer(self) -> None:
"""
Set the installer metadata in the wheel's .dist-info directory.
Expand All @@ -237,21 +237,6 @@ def _write_dist_info(self, file: str, content: str) -> None:
assert self._dist_info
(self._dist_info / file).write_text(content)

async def _load_libraries(self, target: Path) -> None:
"""
Compiles shared libraries (WASM modules) in the wheel and loads them.
"""
assert self._data

pkg = PackageData(
file_name=self.filename,
package_type="package",
shared_library=False,
)

dynlibs = get_dynlibs(io.BytesIO(self._data), ".whl", target)
await loadDynlibsFromPackage(pkg, dynlibs)


def _validate_sha256_checksum(data: bytes, expected: str | None = None) -> None:
if expected is None:
Expand Down

0 comments on commit 68174f9

Please sign in to comment.