mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Upgrade outdated vendored deps
- Upgrade outdated `pip_shims` and `requirementslib` deps ahead of release - Upgrade `importlib-metadata` Signed-off-by: Dan Ryan <dan.ryan@canonical.com>
This commit is contained in:
@@ -6,3 +6,6 @@ Add and update vendored dependencies to accommodate ``safety`` vendoring:
|
||||
- **certifi** ``2019.11.28`` => ``2020.4.5.1``
|
||||
- **pyparsing** ``2.4.6`` => ``2.4.7``
|
||||
- **resolvelib** ``0.2.2`` => ``0.3.0``
|
||||
- **importlib-metadata** ``1.5.1`` => ``1.6.0``
|
||||
- **pip-shims** ``0.5.1`` => ``0.5.2``
|
||||
- **requirementslib** ``1.5.5`` => ``1.5.6``
|
||||
|
||||
+13
-2
@@ -28,6 +28,7 @@ from ._compat import (
|
||||
MetaPathFinder,
|
||||
email_message_from_string,
|
||||
PyPy_repr,
|
||||
unique_ordered,
|
||||
)
|
||||
from importlib import import_module
|
||||
from itertools import starmap
|
||||
@@ -95,6 +96,16 @@ class EntryPoint(
|
||||
attrs = filter(None, (match.group('attr') or '').split('.'))
|
||||
return functools.reduce(getattr, attrs, module)
|
||||
|
||||
@property
|
||||
def module(self):
|
||||
match = self.pattern.match(self.value)
|
||||
return match.group('module')
|
||||
|
||||
@property
|
||||
def attr(self):
|
||||
match = self.pattern.match(self.value)
|
||||
return match.group('attr')
|
||||
|
||||
@property
|
||||
def extras(self):
|
||||
match = self.pattern.match(self.value)
|
||||
@@ -425,8 +436,8 @@ class FastPath:
|
||||
names = zip_path.root.namelist()
|
||||
self.joinpath = zip_path.joinpath
|
||||
|
||||
return (
|
||||
posixpath.split(child)[0]
|
||||
return unique_ordered(
|
||||
child.split(posixpath.sep, 1)[0]
|
||||
for child in names
|
||||
)
|
||||
|
||||
|
||||
+17
@@ -15,9 +15,11 @@ if sys.version_info > (3,): # pragma: nocover
|
||||
NotADirectoryError = builtins.NotADirectoryError
|
||||
PermissionError = builtins.PermissionError
|
||||
map = builtins.map
|
||||
from itertools import filterfalse
|
||||
else: # pragma: nocover
|
||||
from backports.configparser import ConfigParser
|
||||
from itertools import imap as map # type: ignore
|
||||
from itertools import ifilterfalse as filterfalse
|
||||
import contextlib2 as contextlib
|
||||
FileNotFoundError = IOError, OSError
|
||||
IsADirectoryError = IOError, OSError
|
||||
@@ -131,3 +133,18 @@ class PyPy_repr:
|
||||
if affected: # pragma: nocover
|
||||
__repr__ = __compat_repr__
|
||||
del affected
|
||||
|
||||
|
||||
# from itertools recipes
|
||||
def unique_everseen(iterable): # pragma: nocover
|
||||
"List unique elements, preserving order. Remember all elements ever seen."
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
|
||||
for element in filterfalse(seen.__contains__, iterable):
|
||||
seen_add(element)
|
||||
yield element
|
||||
|
||||
|
||||
unique_ordered = (
|
||||
unique_everseen if sys.version_info < (3, 7) else dict.fromkeys)
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
importlib_metadata NEWS
|
||||
=========================
|
||||
|
||||
v1.6.0
|
||||
======
|
||||
|
||||
* Added ``module`` and ``attr`` attributes to ``EntryPoint``
|
||||
|
||||
v1.5.2
|
||||
======
|
||||
|
||||
* Fix redundant entries from ``FastPath.zip_children``.
|
||||
Closes #117.
|
||||
|
||||
v1.5.1
|
||||
======
|
||||
|
||||
|
||||
+9
-1
@@ -70,7 +70,9 @@ Entry points
|
||||
The ``entry_points()`` function returns a dictionary of all entry points,
|
||||
keyed by group. Entry points are represented by ``EntryPoint`` instances;
|
||||
each ``EntryPoint`` has a ``.name``, ``.group``, and ``.value`` attributes and
|
||||
a ``.load()`` method to resolve the value::
|
||||
a ``.load()`` method to resolve the value. There are also ``.module``,
|
||||
``.attr``, and ``.extras`` attributes for getting the components of the
|
||||
``.value`` attribute::
|
||||
|
||||
>>> eps = entry_points()
|
||||
>>> list(eps)
|
||||
@@ -79,6 +81,12 @@ a ``.load()`` method to resolve the value::
|
||||
>>> wheel = [ep for ep in scripts if ep.name == 'wheel'][0]
|
||||
>>> wheel
|
||||
EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')
|
||||
>>> wheel.module
|
||||
'wheel.cli'
|
||||
>>> wheel.attr
|
||||
'main'
|
||||
>>> wheel.extras
|
||||
[]
|
||||
>>> main = wheel.load()
|
||||
>>> main
|
||||
<function main at 0x103528488>
|
||||
|
||||
@@ -250,3 +250,9 @@ class TestEntryPoints(unittest.TestCase):
|
||||
"""
|
||||
with self.assertRaises(Exception):
|
||||
json.dumps(self.ep)
|
||||
|
||||
def test_module(self):
|
||||
assert self.ep.module == 'value'
|
||||
|
||||
def test_attr(self):
|
||||
assert self.ep.attr is None
|
||||
|
||||
+8
-1
@@ -1,7 +1,10 @@
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from .. import distribution, entry_points, files, PackageNotFoundError, version
|
||||
from .. import (
|
||||
distribution, entry_points, files, PackageNotFoundError,
|
||||
version, distributions,
|
||||
)
|
||||
|
||||
try:
|
||||
from importlib.resources import path
|
||||
@@ -52,6 +55,10 @@ class TestZip(unittest.TestCase):
|
||||
path = str(file.dist.locate_file(file))
|
||||
assert '.whl/' in path, path
|
||||
|
||||
def test_one_distribution(self):
|
||||
dists = list(distributions(path=sys.path[:1]))
|
||||
assert len(dists) == 1
|
||||
|
||||
|
||||
class TestEgg(TestZip):
|
||||
def setUp(self):
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@ import sys
|
||||
|
||||
from . import shims
|
||||
|
||||
__version__ = "0.5.1"
|
||||
__version__ = "0.5.2"
|
||||
|
||||
|
||||
if "pip_shims" in sys.modules:
|
||||
|
||||
Vendored
+146
-78
@@ -19,6 +19,8 @@ from packaging import specifiers
|
||||
from .environment import MYPY_RUNNING
|
||||
from .utils import (
|
||||
call_function_with_correct_args,
|
||||
filter_allowed_args,
|
||||
get_allowed_args,
|
||||
get_method_args,
|
||||
nullcontext,
|
||||
suppress_setattr,
|
||||
@@ -65,6 +67,7 @@ if MYPY_RUNNING:
|
||||
TCommandInstance = TypeVar("TCommandInstance")
|
||||
TCmdDict = Dict[str, Union[Tuple[str, str, str], TCommandInstance]]
|
||||
TInstallRequirement = TypeVar("TInstallRequirement")
|
||||
TFormatControl = TypeVar("TFormatControl")
|
||||
TShimmedCmdDict = Union[TShim, TCmdDict]
|
||||
TWheelCache = TypeVar("TWheelCache")
|
||||
TPreparer = TypeVar("TPreparer")
|
||||
@@ -352,11 +355,11 @@ def ensure_resolution_dirs(**kwargs):
|
||||
|
||||
@contextlib.contextmanager
|
||||
def wheel_cache(
|
||||
wheel_cache_provider, # type: TShimmedFunc
|
||||
tempdir_manager_provider, # type: TShimmedFunc
|
||||
cache_dir, # type: str
|
||||
cache_dir=None, # type: str
|
||||
format_control=None, # type: Any
|
||||
wheel_cache_provider=None, # type: TShimmedFunc
|
||||
format_control_provider=None, # type: Optional[TShimmedFunc]
|
||||
tempdir_manager_provider=None, # type: TShimmedFunc
|
||||
):
|
||||
tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider)
|
||||
wheel_cache_provider = resolve_possible_shim(wheel_cache_provider)
|
||||
@@ -490,6 +493,7 @@ def get_requirement_set(
|
||||
cache_dir=None, # type: Optional[str]
|
||||
options=None, # type: Optional[Values]
|
||||
install_cmd_provider=None, # type: Optional[TShimmedFunc]
|
||||
wheel_cache_provider=None, # type: Optional[TShimmedFunc]
|
||||
):
|
||||
# (...) -> TRequirementSet
|
||||
"""
|
||||
@@ -499,6 +503,8 @@ def get_requirement_set(
|
||||
invalid parameters will be ignored if they are not needed to generate a
|
||||
requirement set on the current pip version.
|
||||
|
||||
:param :class:`~pip_shims.models.ShimmedPathCollection` wheel_cache_provider: A
|
||||
context manager provider which resolves to a `WheelCache` instance
|
||||
:param install_command: A :class:`~pip._internal.commands.install.InstallCommand`
|
||||
instance which is used to generate the finder.
|
||||
:param :class:`~pip_shims.models.ShimmedPathCollection` req_set_provider: A provider
|
||||
@@ -538,6 +544,7 @@ def get_requirement_set(
|
||||
:return: A new requirement set instance
|
||||
:rtype: :class:`~pip._internal.req.req_set.RequirementSet`
|
||||
"""
|
||||
wheel_cache_provider = resolve_possible_shim(wheel_cache_provider)
|
||||
req_set_provider = resolve_possible_shim(req_set_provider)
|
||||
if install_command is None:
|
||||
install_cmd_provider = resolve_possible_shim(install_cmd_provider)
|
||||
@@ -565,10 +572,13 @@ def get_requirement_set(
|
||||
)
|
||||
if session is None and "session" in required_args:
|
||||
session = get_session(install_cmd=install_command, options=options)
|
||||
results["wheel_cache"] = wheel_cache
|
||||
results["session"] = session
|
||||
results["wheel_download_dir"] = wheel_download_dir
|
||||
return call_function_with_correct_args(req_set_provider, **results)
|
||||
with ExitStack() as stack:
|
||||
if wheel_cache is None:
|
||||
wheel_cache = stack.enter_context(wheel_cache_provider(cache_dir=cache_dir))
|
||||
results["wheel_cache"] = wheel_cache
|
||||
results["session"] = session
|
||||
results["wheel_download_dir"] = wheel_download_dir
|
||||
return call_function_with_correct_args(req_set_provider, **results)
|
||||
|
||||
|
||||
def get_package_finder(
|
||||
@@ -665,11 +675,11 @@ def get_package_finder(
|
||||
):
|
||||
if target_python and not received_python:
|
||||
tags = target_python.get_tags()
|
||||
version_impl = set([t[0] for t in tags])
|
||||
version_impl = {t[0] for t in tags}
|
||||
# impls = set([v[:2] for v in version_impl])
|
||||
# impls.remove("py")
|
||||
# impl = next(iter(impls), "py") if not target_python
|
||||
versions = set([v[2:] for v in version_impl])
|
||||
versions = {v[2:] for v in version_impl}
|
||||
build_kwargs.update(
|
||||
{
|
||||
"platform": target_python.platform,
|
||||
@@ -689,6 +699,7 @@ def get_package_finder(
|
||||
def shim_unpack(
|
||||
unpack_fn, # type: TShimmedFunc
|
||||
download_dir, # type str
|
||||
tempdir_manager_provider, # type: TShimmedFunc
|
||||
ireq=None, # type: Optional[Any]
|
||||
link=None, # type: Optional[Any]
|
||||
location=None, # type Optional[str],
|
||||
@@ -708,6 +719,8 @@ def shim_unpack(
|
||||
:param unpack_fn: A callable or shim referring to the pip implementation
|
||||
:type unpack_fn: Callable
|
||||
:param str download_dir: The directory to download the file to
|
||||
:param TShimmedFunc tempdir_manager_provider: A callable or shim referring to
|
||||
`global_tempdir_manager` function from pip or a shimmed no-op context manager
|
||||
:param Optional[:class:`~pip._internal.req.req_install.InstallRequirement`] ireq:
|
||||
an Install Requirement instance, defaults to None
|
||||
:param Optional[:class:`~pip._internal.models.link.Link`] link: A Link instance,
|
||||
@@ -727,31 +740,33 @@ def shim_unpack(
|
||||
"""
|
||||
unpack_fn = resolve_possible_shim(unpack_fn)
|
||||
downloader_provider = resolve_possible_shim(downloader_provider)
|
||||
tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider)
|
||||
required_args = inspect.getargs(unpack_fn.__code__).args # type: ignore
|
||||
unpack_kwargs = {"download_dir": download_dir}
|
||||
if ireq:
|
||||
if not link and ireq.link:
|
||||
link = ireq.link
|
||||
if only_download is None:
|
||||
only_download = ireq.is_wheel
|
||||
if hashes is None:
|
||||
hashes = ireq.hashes(True)
|
||||
if location is None and getattr(ireq, "source_dir", None):
|
||||
location = ireq.source_dir
|
||||
unpack_kwargs.update({"link": link, "location": location})
|
||||
if hashes is not None and "hashes" in required_args:
|
||||
unpack_kwargs["hashes"] = hashes
|
||||
if "progress_bar" in required_args:
|
||||
unpack_kwargs["progress_bar"] = progress_bar
|
||||
if only_download is not None and "only_download" in required_args:
|
||||
unpack_kwargs["only_download"] = only_download
|
||||
if session is not None and "session" in required_args:
|
||||
unpack_kwargs["session"] = session
|
||||
if "downloader" in required_args and downloader_provider is not None:
|
||||
assert session is not None
|
||||
assert progress_bar is not None
|
||||
unpack_kwargs["downloader"] = downloader_provider(session, progress_bar)
|
||||
return unpack_fn(**unpack_kwargs) # type: ignore
|
||||
with tempdir_manager_provider():
|
||||
if ireq:
|
||||
if not link and ireq.link:
|
||||
link = ireq.link
|
||||
if only_download is None:
|
||||
only_download = ireq.is_wheel
|
||||
if hashes is None:
|
||||
hashes = ireq.hashes(True)
|
||||
if location is None and getattr(ireq, "source_dir", None):
|
||||
location = ireq.source_dir
|
||||
unpack_kwargs.update({"link": link, "location": location})
|
||||
if hashes is not None and "hashes" in required_args:
|
||||
unpack_kwargs["hashes"] = hashes
|
||||
if "progress_bar" in required_args:
|
||||
unpack_kwargs["progress_bar"] = progress_bar
|
||||
if only_download is not None and "only_download" in required_args:
|
||||
unpack_kwargs["only_download"] = only_download
|
||||
if session is not None and "session" in required_args:
|
||||
unpack_kwargs["session"] = session
|
||||
if "downloader" in required_args and downloader_provider is not None:
|
||||
assert session is not None
|
||||
assert progress_bar is not None
|
||||
unpack_kwargs["downloader"] = downloader_provider(session, progress_bar)
|
||||
return unpack_fn(**unpack_kwargs) # type: ignore
|
||||
|
||||
|
||||
def _ensure_finder(
|
||||
@@ -860,7 +875,7 @@ def make_preparer(
|
||||
preparer_fn = resolve_possible_shim(preparer_fn)
|
||||
downloader_provider = resolve_possible_shim(downloader_provider)
|
||||
finder_provider = resolve_possible_shim(finder_provider)
|
||||
required_args = inspect.getargs(preparer_fn.__init__.__code__).args # type: ignore
|
||||
required_args, required_kwargs = get_allowed_args(preparer_fn) # type: ignore
|
||||
if not req_tracker and not req_tracker_fn and "req_tracker" in required_args:
|
||||
raise TypeError("No requirement tracker and no req tracker generator found!")
|
||||
if "downloader" in required_args and not downloader_provider:
|
||||
@@ -918,6 +933,38 @@ def make_preparer(
|
||||
yield result
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _ensure_wheel_cache(
|
||||
wheel_cache=None, # type: Optional[Type[TWheelCache]]
|
||||
wheel_cache_provider=None, # type: Optional[Callable]
|
||||
format_control=None, # type: Optional[TFormatControl]
|
||||
format_control_provider=None, # type: Optional[Type[TShimmedFunc]]
|
||||
options=None, # type: Optional[Values]
|
||||
cache_dir=None, # type: Optional[str]
|
||||
):
|
||||
if wheel_cache is not None:
|
||||
yield wheel_cache
|
||||
elif wheel_cache_provider is not None:
|
||||
with ExitStack() as stack:
|
||||
cache_dir = getattr(options, "cache_dir", cache_dir)
|
||||
format_control = getattr(
|
||||
options,
|
||||
"format_control",
|
||||
format_control_provider(None, None), # TFormatControl
|
||||
)
|
||||
wheel_cache = stack.enter_context(
|
||||
wheel_cache_provider(cache_dir, format_control)
|
||||
)
|
||||
yield wheel_cache
|
||||
|
||||
|
||||
def get_ireq_output_path(wheel_cache, ireq):
|
||||
if getattr(wheel_cache, "get_path_for_link", None):
|
||||
return wheel_cache.get_path_for_link(ireq.link)
|
||||
elif getattr(wheel_cache, "cached_wheel", None):
|
||||
return wheel_cache.cached_wheel(ireq.link, ireq.name).url_without_fragment
|
||||
|
||||
|
||||
def get_resolver(
|
||||
resolver_fn, # type: TShimmedFunc
|
||||
install_req_provider=None, # type: Optional[TShimmedFunc]
|
||||
@@ -938,6 +985,7 @@ def get_resolver(
|
||||
make_install_req=None, # type: Optional[Callable]
|
||||
install_cmd_provider=None, # type: Optional[TShimmedFunc]
|
||||
install_cmd=None, # type: Optional[TCommandInstance]
|
||||
use_pep517=True, # type: bool
|
||||
):
|
||||
# (...) -> TResolver
|
||||
"""
|
||||
@@ -985,6 +1033,7 @@ def get_resolver(
|
||||
to the resolver for actually generating install requirements, if necessary
|
||||
:param Optional[TCommandInstance] install_cmd: The install command used to create
|
||||
the finder, session, and options if needed, defaults to None.
|
||||
:param bool use_pep517: Whether to use the pep517 build process.
|
||||
:return: A new resolver instance.
|
||||
:rtype: :class:`~pip._internal.legacy_resolve.Resolver`
|
||||
|
||||
@@ -1049,7 +1098,7 @@ def get_resolver(
|
||||
continue
|
||||
elif val is None and install_cmd is None:
|
||||
raise TypeError(
|
||||
"Preparer requires a {0} but did not receive one "
|
||||
"Preparer requires a {} but did not receive one "
|
||||
"and cannot generate one".format(arg)
|
||||
)
|
||||
elif arg == "session" and val is None:
|
||||
@@ -1059,26 +1108,21 @@ def get_resolver(
|
||||
resolver_kwargs[arg] = val
|
||||
if "make_install_req" in required_args:
|
||||
if make_install_req is None and install_req_provider is not None:
|
||||
make_install_req_kwargs = {
|
||||
"isolated": isolated,
|
||||
"wheel_cache": wheel_cache,
|
||||
"use_pep517": use_pep517,
|
||||
}
|
||||
factory_args, factory_kwargs = filter_allowed_args(
|
||||
install_req_provider, **make_install_req_kwargs
|
||||
)
|
||||
make_install_req = functools.partial(
|
||||
install_req_provider,
|
||||
isolated=isolated,
|
||||
wheel_cache=wheel_cache,
|
||||
# use_pep517=use_pep517,
|
||||
install_req_provider, *factory_args, **factory_kwargs
|
||||
)
|
||||
assert make_install_req is not None
|
||||
resolver_kwargs["make_install_req"] = make_install_req
|
||||
if "isolated" in required_args:
|
||||
resolver_kwargs["isolated"] = isolated
|
||||
if "wheel_cache" in required_args:
|
||||
if wheel_cache is None and wheel_cache_provider is not None:
|
||||
cache_dir = getattr(options, "cache_dir", None)
|
||||
format_control = getattr(
|
||||
options,
|
||||
"format_control",
|
||||
format_control_provider(None, None), # type: ignore
|
||||
)
|
||||
wheel_cache = wheel_cache_provider(cache_dir, format_control)
|
||||
resolver_kwargs["wheel_cache"] = wheel_cache
|
||||
resolver_kwargs.update(
|
||||
{
|
||||
"upgrade_strategy": upgrade_strategy,
|
||||
@@ -1090,6 +1134,15 @@ def get_resolver(
|
||||
"preparer": preparer,
|
||||
}
|
||||
)
|
||||
if "wheel_cache" in required_args:
|
||||
with _ensure_wheel_cache(
|
||||
wheel_cache=wheel_cache,
|
||||
wheel_cache_provider=wheel_cache_provider,
|
||||
format_control_provider=format_control_provider,
|
||||
options=options,
|
||||
) as wheel_cache:
|
||||
resolver_kwargs["wheel_cache"] = wheel_cache
|
||||
return resolver_fn(**resolver_kwargs) # type: ignore
|
||||
return resolver_fn(**resolver_kwargs) # type: ignore
|
||||
|
||||
|
||||
@@ -1255,22 +1308,29 @@ def resolve( # noqa:C901
|
||||
if session is None:
|
||||
session = get_session(install_cmd=install_command, options=options)
|
||||
if finder is None:
|
||||
finder = finder_provider(install_command, options=options, session=session) # type: ignore
|
||||
finder = finder_provider(
|
||||
install_command, options=options, session=session
|
||||
) # type: ignore
|
||||
format_control = getattr(options, "format_control", None)
|
||||
if not format_control:
|
||||
format_control = format_control_provider(None, None) # type: ignore
|
||||
wheel_cache = wheel_cache_provider(
|
||||
kwargs["cache_dir"], format_control
|
||||
wheel_cache = ctx.enter_context(
|
||||
wheel_cache_provider(kwargs["cache_dir"], format_control)
|
||||
) # type: ignore
|
||||
ireq.is_direct = True # type: ignore
|
||||
build_location_kwargs = {"build_dir": kwargs["build_dir"], "autodelete": True}
|
||||
call_function_with_correct_args(ireq.build_location, **build_location_kwargs)
|
||||
# ireq.build_location(kwargs["build_dir"]) # type: ignore
|
||||
if reqset_provider is None:
|
||||
raise TypeError(
|
||||
"cannot resolve without a requirement set provider... failed!"
|
||||
)
|
||||
reqset = reqset_provider(install_command, options=options, session=session, wheel_download_dir=wheel_download_dir, **kwargs) # type: ignore
|
||||
reqset = reqset_provider(
|
||||
install_command,
|
||||
options=options,
|
||||
session=session,
|
||||
wheel_download_dir=wheel_download_dir,
|
||||
**kwargs
|
||||
) # type: ignore
|
||||
if getattr(reqset, "prepare_files", None):
|
||||
reqset.add_requirement(ireq)
|
||||
results = reqset.prepare_files(finder)
|
||||
@@ -1293,7 +1353,6 @@ def resolve( # noqa:C901
|
||||
"use_user_site": use_user_site,
|
||||
"require_hashes": require_hashes,
|
||||
}
|
||||
# with req_tracker_provider() as req_tracker:
|
||||
if isinstance(req_tracker_provider, (types.FunctionType, functools.partial)):
|
||||
preparer_args["req_tracker"] = ctx.enter_context(req_tracker_provider())
|
||||
resolver_keys = [
|
||||
@@ -1338,7 +1397,7 @@ def resolve( # noqa:C901
|
||||
return results
|
||||
|
||||
|
||||
def build_wheel(
|
||||
def build_wheel( # noqa:C901
|
||||
req=None, # type: Optional[TInstallRequirement]
|
||||
reqset=None, # type: Optional[Union[TReqSet, Iterable[TInstallRequirement]]]
|
||||
output_dir=None, # type: Optional[str]
|
||||
@@ -1368,8 +1427,9 @@ def build_wheel(
|
||||
build_many_provider=None, # type: Optional[TShimmedFunc]
|
||||
install_command_provider=None, # type: Optional[TShimmedFunc]
|
||||
finder_provider=None, # type: Optional[TShimmedFunc]
|
||||
reqset_provider=None, # type: Optional[TShimmedFunc]
|
||||
):
|
||||
# type: (...) -> Optional[Union[str, Tuple[List[TInstallRequirement], List[TInstallRequirement]]]]
|
||||
# type: (...) -> Generator[Union[str, Tuple[List[TInstallRequirement], ...]], None, None]
|
||||
"""
|
||||
Build a wheel or a set of wheels
|
||||
|
||||
@@ -1421,19 +1481,21 @@ def build_wheel(
|
||||
:param Optional[TShimmedFunc] install_command_provider: A shim for providing new
|
||||
install command instances
|
||||
:param TShimmedFunc finder_provider: A provider to package finder instances
|
||||
:param TShimmedFunc reqset_provider: A provider for requirement set generation
|
||||
:return: A tuple of successful and failed install requirements or else a path to
|
||||
a wheel
|
||||
:rtype: Optional[Union[str, Tuple[List[TInstallRequirement], List[TInstallRequirement]]]]
|
||||
"""
|
||||
wheel_cache_provider = resolve_possible_shim(wheel_cache_provider)
|
||||
preparer = resolve_possible_shim(preparer)
|
||||
preparer_provider = resolve_possible_shim(preparer_provider)
|
||||
wheel_builder_provider = resolve_possible_shim(wheel_builder_provider)
|
||||
build_one_provider = resolve_possible_shim(build_one_provider)
|
||||
build_one_inside_env_provider = resolve_possible_shim(build_one_inside_env_provider)
|
||||
build_many_provider = resolve_possible_shim(build_many_provider)
|
||||
install_cmd_provider = resolve_possible_shim(install_command_provider)
|
||||
format_control_provider = resolve_possible_shim(format_control_provider)
|
||||
finder_provider = resolve_possible_shim(finder_provider)
|
||||
finder_provider = resolve_possible_shim(finder_provider) or get_package_finder
|
||||
reqset_provider = resolve_possible_shim(reqset_provider)
|
||||
global_options = [] if global_options is None else global_options
|
||||
build_options = [] if build_options is None else build_options
|
||||
options = None
|
||||
@@ -1447,25 +1509,31 @@ def build_wheel(
|
||||
}
|
||||
if not req and not reqset:
|
||||
raise TypeError("Must provide either a requirement or requirement set to build")
|
||||
if wheel_cache is None and (reqset is not None or output_dir is None):
|
||||
if install_command is None:
|
||||
assert isinstance(install_cmd_provider, (type, functools.partial))
|
||||
install_command = install_cmd_provider()
|
||||
kwargs, options = populate_options(install_command, options, **kwarg_map)
|
||||
format_control = getattr(options, "format_control", None)
|
||||
if not format_control:
|
||||
format_control = format_control_provider(None, None) # type: ignore
|
||||
wheel_cache = wheel_cache_provider(options.cache_dir, format_control)
|
||||
if req and not reqset and not output_dir:
|
||||
output_dir = wheel_cache.get_path_for_link(req.link)
|
||||
if not reqset and build_one_provider:
|
||||
yield build_one_provider(req, output_dir, build_options, global_options)
|
||||
elif build_many_provider:
|
||||
yield build_many_provider(
|
||||
reqset, wheel_cache, build_options, global_options, check_binary_allowed
|
||||
)
|
||||
else:
|
||||
with ExitStack() as ctx:
|
||||
with ExitStack() as ctx:
|
||||
kwargs = kwarg_map.copy()
|
||||
if wheel_cache is None and (reqset is not None or output_dir is None):
|
||||
if install_command is None:
|
||||
assert isinstance(install_cmd_provider, (type, functools.partial))
|
||||
install_command = install_cmd_provider()
|
||||
kwargs, options = populate_options(install_command, options, **kwarg_map)
|
||||
format_control = getattr(options, "format_control", None)
|
||||
if not format_control:
|
||||
format_control = format_control_provider(None, None) # type: ignore
|
||||
wheel_cache = ctx.enter_context(
|
||||
wheel_cache_provider(options.cache_dir, format_control)
|
||||
)
|
||||
if req and not reqset and not output_dir:
|
||||
output_dir = get_ireq_output_path(wheel_cache, req)
|
||||
if not reqset and build_one_provider:
|
||||
yield build_one_provider(req, output_dir, build_options, global_options)
|
||||
elif build_many_provider:
|
||||
yield build_many_provider(
|
||||
reqset, wheel_cache, build_options, global_options, check_binary_allowed
|
||||
)
|
||||
else:
|
||||
builder_args, builder_kwargs = get_allowed_args(wheel_builder_provider)
|
||||
if "requirement_set" in builder_args and not reqset:
|
||||
reqset = reqset_provider()
|
||||
if session is None and finder is None:
|
||||
session = get_session(install_cmd=install_command, options=options)
|
||||
finder = finder_provider(
|
||||
@@ -1503,7 +1571,7 @@ def build_wheel(
|
||||
)
|
||||
if req and not reqset:
|
||||
if not output_dir:
|
||||
output_dir = wheel_cache.get_path_for_link(req.link)
|
||||
output_dir = get_ireq_output_path(wheel_cache, req)
|
||||
if use_pep517 is not None:
|
||||
req.use_pep517 = use_pep517
|
||||
yield builder._build_one(req, output_dir)
|
||||
|
||||
Vendored
+38
-22
@@ -104,6 +104,9 @@ PIP_VERSION_SET = {
|
||||
"19.2.3",
|
||||
"19.3",
|
||||
"19.3.1",
|
||||
"20.0",
|
||||
"20.0.1",
|
||||
"20.0.2",
|
||||
}
|
||||
|
||||
|
||||
@@ -140,9 +143,9 @@ class PipVersion(Sequence):
|
||||
parsed_version = self._parse()
|
||||
if base_import_path is None:
|
||||
if parsed_version >= parse_version("10.0.0"):
|
||||
base_import_path = "{0}._internal".format(BASE_IMPORT_PATH)
|
||||
base_import_path = "{}._internal".format(BASE_IMPORT_PATH)
|
||||
else:
|
||||
base_import_path = "{0}".format(BASE_IMPORT_PATH)
|
||||
base_import_path = "{}".format(BASE_IMPORT_PATH)
|
||||
self.base_import_path = base_import_path
|
||||
self.parsed_version = parsed_version
|
||||
|
||||
@@ -175,13 +178,12 @@ class PipVersion(Sequence):
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
return "{0!s}".format(self.parsed_version)
|
||||
return "{!s}".format(self.parsed_version)
|
||||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return (
|
||||
"<PipVersion {0!r}, Path: {1!r}, Vendor Path: {2!r}, "
|
||||
"Parsed Version: {3!r}>"
|
||||
"<PipVersion {!r}, Path: {!r}, Vendor Path: {!r}, " "Parsed Version: {!r}>"
|
||||
).format(
|
||||
self.version,
|
||||
self.base_import_path,
|
||||
@@ -253,17 +255,17 @@ class PipVersionRange(Sequence):
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
return "{0!s} -> {1!s}".format(self._versions[0], self._versions[-1])
|
||||
return "{!s} -> {!s}".format(self._versions[0], self._versions[-1])
|
||||
|
||||
@property
|
||||
def base_import_paths(self):
|
||||
# type: () -> Set[str]
|
||||
return set([version.base_import_path for version in self._versions])
|
||||
return {version.base_import_path for version in self._versions}
|
||||
|
||||
@property
|
||||
def vendor_import_paths(self):
|
||||
# type: () -> Set[str]
|
||||
return set([version.vendor_import_path for version in self._versions])
|
||||
return {version.vendor_import_path for version in self._versions}
|
||||
|
||||
def is_valid(self):
|
||||
# type: () -> bool
|
||||
@@ -430,7 +432,7 @@ class ShimmedPath(object):
|
||||
if not self.is_class:
|
||||
return provided
|
||||
if not inspect.isclass(provided):
|
||||
raise TypeError("Provided argument is not a class: {0!r}".format(provided))
|
||||
raise TypeError("Provided argument is not a class: {!r}".format(provided))
|
||||
methods = self._parse_provides_dict(
|
||||
self.provided_methods, prepend_arg_to_callables="self"
|
||||
)
|
||||
@@ -554,9 +556,7 @@ class ShimmedPath(object):
|
||||
imported, result = self._shim_parent(imported, attribute_name)
|
||||
if result is not None:
|
||||
result = self._ensure_functions(result)
|
||||
full_import_path = "{0}.{1}".format(
|
||||
self.calculated_module_path, attribute_name
|
||||
)
|
||||
full_import_path = "{}.{}".format(self.calculated_module_path, attribute_name)
|
||||
self._imported = imported
|
||||
assert isinstance(result, types.ModuleType)
|
||||
self._provided = result
|
||||
@@ -921,13 +921,6 @@ unpack_url = ShimmedPathCollection("unpack_url", ImportTypes.FUNCTION)
|
||||
unpack_url.create_path("download.unpack_url", "7.0.0", "19.3.9")
|
||||
unpack_url.create_path("operations.prepare.unpack_url", "20.0", "9999")
|
||||
|
||||
shim_unpack = ShimmedPathCollection("shim_unpack", ImportTypes.FUNCTION)
|
||||
shim_unpack.set_default(
|
||||
functools.partial(
|
||||
compat.shim_unpack, unpack_fn=unpack_url, downloader_provider=Downloader
|
||||
)
|
||||
)
|
||||
|
||||
is_installable_dir = ShimmedPathCollection("is_installable_dir", ImportTypes.FUNCTION)
|
||||
is_installable_dir.create_path("utils.misc.is_installable_dir", "10.0.0", "9999")
|
||||
is_installable_dir.create_path("utils.is_installable_dir", "7.0.0", "9.0.3")
|
||||
@@ -1036,6 +1029,16 @@ global_tempdir_manager.create_path(
|
||||
"utils.temp_dir.global_tempdir_manager", "7.0.0", "9999"
|
||||
)
|
||||
|
||||
shim_unpack = ShimmedPathCollection("shim_unpack", ImportTypes.FUNCTION)
|
||||
shim_unpack.set_default(
|
||||
functools.partial(
|
||||
compat.shim_unpack,
|
||||
unpack_fn=unpack_url,
|
||||
downloader_provider=Downloader,
|
||||
tempdir_manager_provider=global_tempdir_manager,
|
||||
)
|
||||
)
|
||||
|
||||
get_requirement_tracker = ShimmedPathCollection(
|
||||
"get_requirement_tracker", ImportTypes.CONTEXTMANAGER
|
||||
)
|
||||
@@ -1128,6 +1131,17 @@ DEV_PKGS.create_path("commands.freeze.DEV_PKGS", "9.0.0", "9999")
|
||||
DEV_PKGS.set_default({"setuptools", "pip", "distribute", "wheel"})
|
||||
|
||||
|
||||
wheel_cache = ShimmedPathCollection("wheel_cache", ImportTypes.FUNCTION)
|
||||
wheel_cache.set_default(
|
||||
functools.partial(
|
||||
compat.wheel_cache,
|
||||
wheel_cache_provider=WheelCache,
|
||||
tempdir_manager_provider=global_tempdir_manager,
|
||||
format_control_provider=FormatControl,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
get_package_finder = ShimmedPathCollection("get_package_finder", ImportTypes.FUNCTION)
|
||||
get_package_finder.set_default(
|
||||
functools.partial(
|
||||
@@ -1158,7 +1172,7 @@ get_resolver.set_default(
|
||||
install_cmd_provider=InstallCommand,
|
||||
resolver_fn=Resolver,
|
||||
install_req_provider=install_req_from_req_string,
|
||||
wheel_cache_provider=WheelCache,
|
||||
wheel_cache_provider=wheel_cache,
|
||||
format_control_provider=FormatControl,
|
||||
)
|
||||
)
|
||||
@@ -1170,6 +1184,7 @@ get_requirement_set.set_default(
|
||||
compat.get_requirement_set,
|
||||
install_cmd_provider=InstallCommand,
|
||||
req_set_provider=RequirementSet,
|
||||
wheel_cache_provider=wheel_cache,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1182,7 +1197,7 @@ resolve.set_default(
|
||||
reqset_provider=get_requirement_set,
|
||||
finder_provider=get_package_finder,
|
||||
resolver_provider=get_resolver,
|
||||
wheel_cache_provider=WheelCache,
|
||||
wheel_cache_provider=wheel_cache,
|
||||
format_control_provider=FormatControl,
|
||||
make_preparer_provider=make_preparer,
|
||||
req_tracker_provider=get_requirement_tracker,
|
||||
@@ -1196,12 +1211,13 @@ build_wheel.set_default(
|
||||
functools.partial(
|
||||
compat.build_wheel,
|
||||
install_command_provider=InstallCommand,
|
||||
wheel_cache_provider=WheelCache,
|
||||
wheel_cache_provider=wheel_cache,
|
||||
wheel_builder_provider=WheelBuilder,
|
||||
build_one_provider=build_one,
|
||||
build_one_inside_env_provider=build_one_inside_env,
|
||||
build_many_provider=build,
|
||||
preparer_provider=make_preparer,
|
||||
format_control_provider=FormatControl,
|
||||
reqset_provider=get_requirement_set,
|
||||
)
|
||||
)
|
||||
|
||||
Vendored
+23
@@ -440,3 +440,26 @@ def call_function_with_correct_args(fn, **provided_kwargs):
|
||||
continue
|
||||
kwargs[arg] = provided_kwargs[arg]
|
||||
return fn(*args, **kwargs)
|
||||
|
||||
|
||||
def filter_allowed_args(fn, **provided_kwargs):
|
||||
# type: (Callable, Dict[str, Any]) -> Tuple[List[Any], Dict[str, Any]]
|
||||
"""
|
||||
Given a function and a kwarg mapping, return only those kwargs used in the function.
|
||||
|
||||
:param Callable fn: A function to inspect
|
||||
:param Dict[str, Any] kwargs: A mapping of kwargs to filter
|
||||
:return: A new, filtered kwarg mapping
|
||||
:rtype: Tuple[List[Any], Dict[str, Any]]
|
||||
"""
|
||||
args = []
|
||||
kwargs = {}
|
||||
func_args, func_kwargs = get_allowed_args(fn)
|
||||
for arg in func_args:
|
||||
if arg in provided_kwargs:
|
||||
args.append(provided_kwargs[arg])
|
||||
for arg in func_kwargs:
|
||||
if arg not in provided_kwargs:
|
||||
continue
|
||||
kwargs[arg] = provided_kwargs[arg]
|
||||
return args, kwargs
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ from .models.lockfile import Lockfile
|
||||
from .models.pipfile import Pipfile
|
||||
from .models.requirements import Requirement
|
||||
|
||||
__version__ = "1.5.4"
|
||||
__version__ = "1.5.6"
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
+39
-5
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import itertools
|
||||
import operator
|
||||
import re
|
||||
|
||||
import attr
|
||||
import distlib.markers
|
||||
@@ -196,15 +197,19 @@ def _get_specs(specset):
|
||||
return sorted(result, key=operator.itemgetter(1))
|
||||
|
||||
|
||||
# TODO: Rename this to something meaningful
|
||||
def _group_by_op(specs):
|
||||
# type: (Union[Set[Specifier], SpecifierSet]) -> Iterator
|
||||
specs = [_get_specs(x) for x in list(specs)]
|
||||
flattened = [(op, version) for spec in specs for op, version in spec]
|
||||
flattened = [
|
||||
((op, len(version) > 2), version) for spec in specs for op, version in spec
|
||||
]
|
||||
specs = sorted(flattened)
|
||||
grouping = itertools.groupby(specs, key=operator.itemgetter(0))
|
||||
return grouping
|
||||
|
||||
|
||||
# TODO: rename this to something meaningful
|
||||
def normalize_specifier_set(specs):
|
||||
# type: (Union[str, SpecifierSet]) -> Optional[Set[Specifier]]
|
||||
"""Given a specifier set, a string, or an iterable, normalize the specifiers
|
||||
@@ -235,6 +240,8 @@ def normalize_specifier_set(specs):
|
||||
return normalize_specifier_set(SpecifierSet(",".join(spec_list)))
|
||||
|
||||
|
||||
# TODO: Check if this is used by anything public otherwise make it private
|
||||
# And rename it to something meaningful
|
||||
def get_sorted_version_string(version_set):
|
||||
# type: (Set[AnyStr]) -> AnyStr
|
||||
version_list = sorted(
|
||||
@@ -244,6 +251,9 @@ def get_sorted_version_string(version_set):
|
||||
return version
|
||||
|
||||
|
||||
# TODO: Rename this to something meaningful
|
||||
# TODO: Add a deprecation decorator and deprecate this -- i'm sure it's used
|
||||
# in other libraries
|
||||
@lru_cache(maxsize=1024)
|
||||
def cleanup_pyspecs(specs, joiner="or"):
|
||||
specs = normalize_specifier_set(specs)
|
||||
@@ -275,7 +285,8 @@ def cleanup_pyspecs(specs, joiner="or"):
|
||||
"==": lambda x: "in" if len(x) > 1 else "==",
|
||||
}
|
||||
translation_keys = list(translation_map.keys())
|
||||
for op, versions in _group_by_op(tuple(specs)):
|
||||
for op_and_version_type, versions in _group_by_op(tuple(specs)):
|
||||
op = op_and_version_type[0]
|
||||
versions = [version[1] for version in versions]
|
||||
versions = sorted(dedup(versions))
|
||||
op_key = next(iter(k for k in translation_keys if op in k), None)
|
||||
@@ -284,10 +295,11 @@ def cleanup_pyspecs(specs, joiner="or"):
|
||||
version_value = translation_map[op_key][joiner](versions)
|
||||
if op in op_translations:
|
||||
op = op_translations[op](versions)
|
||||
results[op] = version_value
|
||||
return sorted([(k, v) for k, v in results.items()], key=operator.itemgetter(1))
|
||||
results[(op, op_and_version_type[1])] = version_value
|
||||
return sorted([(k[0], v) for k, v in results.items()], key=operator.itemgetter(1))
|
||||
|
||||
|
||||
# TODO: Rename this to something meaningful
|
||||
@lru_cache(maxsize=1024)
|
||||
def fix_version_tuple(version_tuple):
|
||||
# type: (Tuple[AnyStr, AnyStr]) -> Tuple[AnyStr, AnyStr]
|
||||
@@ -302,6 +314,7 @@ def fix_version_tuple(version_tuple):
|
||||
return (op, version)
|
||||
|
||||
|
||||
# TODO: Rename this to something meaningful, deprecate it (See prior function)
|
||||
@lru_cache(maxsize=128)
|
||||
def get_versions(specset, group_by_operator=True):
|
||||
# type: (Union[Set[Specifier], SpecifierSet], bool) -> List[Tuple[STRING_TYPE, STRING_TYPE]]
|
||||
@@ -590,6 +603,7 @@ def get_specset(marker_list):
|
||||
return specifiers
|
||||
|
||||
|
||||
# TODO: Refactor this (reduce complexity)
|
||||
def parse_marker_dict(marker_dict):
|
||||
op = marker_dict["op"]
|
||||
lhs = marker_dict["lhs"]
|
||||
@@ -658,9 +672,16 @@ def parse_marker_dict(marker_dict):
|
||||
return specset, finalized_marker
|
||||
|
||||
|
||||
def _contains_micro_version(version_string):
|
||||
return re.search("\d+\.\d+\.\d+", version_string) is not None
|
||||
|
||||
|
||||
def format_pyversion(parts):
|
||||
op, val = parts
|
||||
return "python_version {0} '{1}'".format(op, val)
|
||||
version_marker = (
|
||||
"python_full_version" if _contains_micro_version(val) else "python_version"
|
||||
)
|
||||
return "{0} {1} '{2}'".format(version_marker, op, val)
|
||||
|
||||
|
||||
def normalize_marker_str(marker):
|
||||
@@ -699,3 +720,16 @@ def marker_from_specifier(spec):
|
||||
marker_segments.append(format_pyversion(marker_segment))
|
||||
marker_str = " and ".join(marker_segments).replace('"', "'")
|
||||
return Marker(marker_str)
|
||||
|
||||
|
||||
def merge_markers(m1, m2):
|
||||
# type: (Marker, Marker) -> Optional[Marker]
|
||||
if not all((m1, m2)):
|
||||
return next(iter(v for v in (m1, m2) if v), None)
|
||||
m1 = _ensure_marker(m1)
|
||||
m2 = _ensure_marker(m2)
|
||||
_markers = [] # type: List[Marker]
|
||||
for marker in (m1, m2):
|
||||
_markers.append(str(marker))
|
||||
marker_str = " and ".join([normalize_marker_str(m) for m in _markers if m])
|
||||
return _ensure_marker(normalize_marker_str(marker_str))
|
||||
|
||||
+1240
File diff suppressed because it is too large
Load Diff
@@ -164,6 +164,10 @@ class Pipfile(object):
|
||||
# type: () -> Union[plette.pipfiles.Pipfile, PipfileLoader]
|
||||
return self.projectfile.model
|
||||
|
||||
@property
|
||||
def root(self):
|
||||
return self.path.parent
|
||||
|
||||
@property
|
||||
def extended_keys(self):
|
||||
return [
|
||||
|
||||
+5
-2
@@ -679,7 +679,7 @@ AST_COMPARATORS = dict(
|
||||
(ast.And, operator.and_),
|
||||
(ast.Or, operator.or_),
|
||||
(ast.Not, operator.not_),
|
||||
(ast.In, operator.contains),
|
||||
(ast.In, lambda a, b: operator.contains(b, a)),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -746,6 +746,9 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no
|
||||
unparsed = item.s
|
||||
elif isinstance(item, ast.Subscript):
|
||||
unparsed = unparse(item.value)
|
||||
if not initial_mapping:
|
||||
if isinstance(item.slice, ast.Index):
|
||||
unparsed = unparsed[unparse(item.slice.value)]
|
||||
elif any(isinstance(item, k) for k in AST_BINOP_MAP.keys()):
|
||||
unparsed = AST_BINOP_MAP[type(item)]
|
||||
elif isinstance(item, ast.Num):
|
||||
@@ -789,7 +792,7 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no
|
||||
elif isinstance(item, constant):
|
||||
unparsed = item.value
|
||||
elif isinstance(item, ast.Compare):
|
||||
if isinstance(item.left, ast.Attribute):
|
||||
if isinstance(item.left, ast.Attribute) or isinstance(item.left, ast.Str):
|
||||
import importlib
|
||||
|
||||
left = unparse(item.left)
|
||||
|
||||
+1
-1
@@ -723,7 +723,7 @@ def get_pinned_version(ireq):
|
||||
except AttributeError:
|
||||
raise TypeError("Expected InstallRequirement, not {}".format(type(ireq).__name__))
|
||||
|
||||
if ireq.editable:
|
||||
if getattr(ireq, "editable", False):
|
||||
raise ValueError("InstallRequirement is editable")
|
||||
if not specifier:
|
||||
raise ValueError("InstallRequirement has no version specification")
|
||||
|
||||
Vendored
+3
-3
@@ -26,7 +26,7 @@ requests==2.23.0
|
||||
idna==2.9
|
||||
urllib3==1.25.9
|
||||
certifi==2020.4.5.1
|
||||
requirementslib==1.5.5
|
||||
requirementslib==1.5.6
|
||||
attrs==19.3.0
|
||||
distlib==0.3.0
|
||||
packaging==20.3
|
||||
@@ -39,7 +39,7 @@ semver==2.9.0
|
||||
toml==0.10.0
|
||||
cached-property==1.5.1
|
||||
vistir==0.5.0
|
||||
pip-shims==0.5.1
|
||||
pip-shims==0.5.2
|
||||
contextlib2==0.6.0.post1
|
||||
funcsigs==1.0.2
|
||||
enum34==1.1.6
|
||||
@@ -50,7 +50,7 @@ resolvelib==0.3.0
|
||||
backports.functools_lru_cache==1.5
|
||||
pep517==0.8.2
|
||||
zipp==0.6.0
|
||||
importlib_metadata==1.5.1
|
||||
importlib_metadata==1.6.0
|
||||
importlib-resources==1.4.0
|
||||
more-itertools==5.0.0
|
||||
git+https://github.com/sarugaku/passa.git@master#egg=passa
|
||||
|
||||
Reference in New Issue
Block a user