Supporty custom wheel locations in micropip

This commit is contained in:
Roman Yurchak 2020-05-11 01:32:59 +02:00
parent faee135865
commit ac68a30511
3 changed files with 101 additions and 6 deletions

View File

@ -97,7 +97,10 @@ class SeleniumWrapper:
@property
def logs(self):
logs = self.driver.execute_script("return window.logs")
return '\n'.join(str(x) for x in logs)
if logs is not None:
return '\n'.join(str(x) for x in logs)
else:
return ""
def clean_logs(self):
self.driver.execute_script("window.logs = []")

View File

@ -2,7 +2,17 @@ try:
from js import Promise, XMLHttpRequest
except ImportError:
XMLHttpRequest = None
from js import pyodide as js_pyodide
try:
from js import pyodide as js_pyodide
except ImportError:
class js_pyodide: # type: ignore
"""A mock object to allow import of this package outside pyodide"""
class _module:
class packages:
dependencies = [] # type: ignore
import hashlib
import importlib
@ -10,6 +20,7 @@ import io
import json
from pathlib import Path
import zipfile
from typing import Dict, Any, Union, List, Tuple
from distlib import markers, util, version
@ -64,12 +75,43 @@ def _get_pypi_json(pkgname):
return json.load(fd)
def _parse_wheel_url(url: str) -> Tuple[str, Dict[str, Any], str]:
"""Parse wheels url and extract available metadata
See https://www.python.org/dev/peps/pep-0427/#file-name-convention
"""
file_name = Path(url).name
# also strip '.whl' extension.
wheel_name = Path(url).stem
tokens = wheel_name.split('-')
# TODO: support optional build tags in the filename (cf PEP 427)
if len(tokens) < 5:
raise ValueError(f'{file_name} is not a valid wheel file name.')
version, python_tag, abi_tag, platform = tokens[-4:]
name = '-'.join(tokens[:-4])
wheel = {
'digests': None, # checksums not available
'filename': file_name,
'packagetype': 'bdist_wheel',
'python_version': python_tag,
'abi_tag': abi_tag,
'platform': platform,
'url': url,
}
return name, wheel, version
class _WheelInstaller:
def extract_wheel(self, fd):
with zipfile.ZipFile(fd) as zf:
zf.extractall(WHEEL_BASE)
def validate_wheel(self, data, fileinfo):
if fileinfo.get('digests') is None:
# No checksums available, e.g. because installing
# from a different location than PyPi.
return
sha256 = fileinfo['digests']['sha256']
m = hashlib.sha256()
m.update(data.getvalue())
@ -108,7 +150,7 @@ class _PackageManager:
def install(
self,
requirements,
requirements: Union[str, List[str]],
ctx=None,
wheel_installer=None,
resolve=_nullop,
@ -127,7 +169,7 @@ class _PackageManager:
if isinstance(requirements, str):
requirements = [requirements]
transaction = {
transaction: Dict[str, Any] = {
'wheels': [],
'pyodide_packages': set(),
'locked': dict(self.installed_packages)
@ -162,7 +204,13 @@ class _PackageManager:
wheel_installer(name, wheel, do_resolve, reject)
self.installed_packages[name] = ver
def add_requirement(self, requirement, ctx, transaction):
def add_requirement(self, requirement: str, ctx, transaction):
if requirement.startswith(('http://', 'https://')):
# custom download location
name, wheel, version = _parse_wheel_url(requirement)
transaction['wheels'].append((name, wheel, version))
return
req = util.parse_requirement(requirement)
# If it's a Pyodide package, use that instead of the one on PyPI
@ -223,7 +271,7 @@ PACKAGE_MANAGER = _PackageManager()
del _PackageManager
def install(requirements):
def install(requirements: Union[str, List[str]]):
"""
Install the given package and all of its dependencies.

View File

@ -1,4 +1,10 @@
import time
import sys
from pathlib import Path
import pytest
sys.path.append(str(Path(__file__).resolve().parent / 'micropip'))
def test_install_simple(selenium_standalone):
@ -24,3 +30,41 @@ def test_install_simple(selenium_standalone):
"stemmer.stemWords('go going goes gone'.split())") == [
'go', 'go', 'goe', 'gone'
]
print(selenium_standalone.logs)
def test_parse_wheel_url():
import micropip
url = "https://a/snowballstemmer-2.0.0-py2.py3-none-any.whl"
name, wheel, version = micropip._parse_wheel_url(url)
assert name == 'snowballstemmer'
assert version == '2.0.0'
assert wheel == {
'digests': None,
'filename': 'snowballstemmer-2.0.0-py2.py3-none-any.whl',
'packagetype': 'bdist_wheel',
'python_version': 'py2.py3',
'abi_tag': 'none',
'platform': 'any',
'url': url
}
msg = "not a valid wheel file name"
with pytest.raises(ValueError, match=msg):
url = "https://a/snowballstemmer-2.0.0-py2.whl"
name, params, version = micropip._parse_wheel_url(url)
url = "http://scikit_learn-0.22.2.post1-cp35-cp35m-macosx_10_9_intel.whl"
name, wheel, version = micropip._parse_wheel_url(url)
assert name == 'scikit_learn'
assert wheel['platform'] == 'macosx_10_9_intel'
def test_install_custom_url(selenium_standalone, web_server_secondary):
server_hostname, server_port, server_log = web_server_secondary
selenium_standalone.load_package("micropip")
selenium_standalone.run("import micropip")
base_url = f'http://{server_hostname}:{server_port}/test/'
url = base_url + 'snowballstemmer-2.0.0-py2.py3-none-any.whl'
selenium_standalone.run(f"micropip.install('{url}')")