Bug 1680802: Bump vendored virtualenv package r=firefox-build-system-reviewers,sheehan,glandium

The `wheel` package was failing with Mac Big Sur.
It's been updated, but our `virtualenv` package
has its own vendored `wheel` package that is out-of-date.
This updates `virtualenv` to "20.2.2".

This should solve "assert len(base_version) == 2" and
"would build wheel with unsupported tag" errors.

Differential Revision: https://phabricator.services.mozilla.com/D99482
This commit is contained in:
Mitchell Hentges 2020-12-15 18:17:53 +00:00
parent 945b23f181
commit eafc0381ea
116 changed files with 2759 additions and 645 deletions

View File

@ -4,7 +4,7 @@ import sys
import zipfile
ABS_HERE = os.path.abspath(os.path.dirname(__file__))
NEW_IMPORT_SYSTEM = sys.version_info[0:2] > (3, 4)
NEW_IMPORT_SYSTEM = sys.version_info[0] == 3
class VersionPlatformSelect(object):

View File

@ -1,6 +1,6 @@
filelock.py,sha256=5DQTtOaQq7-vgLkZzvOhqhVMh_umfydWgSA8Vuzmf8M,13229
filelock-3.0.12.dist-info/LICENSE,sha256=iNm062BXnBkew5HKBMFhMFctfu3EqG2qWL8oxuFMm80,1210
filelock-3.0.12.dist-info/METADATA,sha256=gjzbv9nxtD-Rj2ysjUuG7SLZCHUQl5hMy68Jij8soPw,4343
filelock-3.0.12.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
filelock-3.0.12.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92
filelock-3.0.12.dist-info/top_level.txt,sha256=NDrf9i5BNogz4hEdsr6Hi7Ws3TlSSKY4Q2Y9_-i2GwU,9
filelock-3.0.12.dist-info/RECORD,,

View File

@ -1,5 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.34.2)
Generator: bdist_wheel (0.35.1)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -1,21 +0,0 @@
importlib_metadata/__init__.py,sha256=phnrEcGP-8cF-_ZZ5peJL4cUVAANOK0CpSWC-0-IVAs,18961
importlib_metadata/_compat.py,sha256=DnM55BbJKFCcZmJOkArmyO76-0g7pA6HEfzSYWXN88k,4417
importlib_metadata/docs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_metadata/docs/changelog.rst,sha256=6EZfl84T0SQHzAXNlTiTegG0cBTa9wiMt0od0ht2n_8,8739
importlib_metadata/docs/conf.py,sha256=m-b6Mju5gFkpSHh-lyJ4iwqf_8t4LjYYFRumtutQSZc,5578
importlib_metadata/docs/index.rst,sha256=rbXrDkLAKLIDccqME5u9CCMEfMKprqzQOkIOuwOnfz4,1907
importlib_metadata/docs/using.rst,sha256=k_L4Hwwsf10ap9xWejyC-_gLz_WtvRfDOzuJA3o7Zw0,9504
importlib_metadata/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_metadata/tests/fixtures.py,sha256=Ua_PqyqBhFqkkNGFsXtgMah6vXKQjeqKo1KhhzYdn-w,5752
importlib_metadata/tests/test_api.py,sha256=YMAGTsRENrtvpw2CSLmRndJMBeT4q_M0GSe-QsnnMZ4,5544
importlib_metadata/tests/test_integration.py,sha256=ykJpwjSkVwvWHG4gUw4RUrZzU_7JKX8vZyPf_kFIrLE,1579
importlib_metadata/tests/test_main.py,sha256=dcsDqyxTRtard2j5ysDDvVwfK6vvXdRtZCaQ0QljSR8,9026
importlib_metadata/tests/test_zip.py,sha256=lOCNPyfJSm9nz0-2RQndM7OQV-_gRjJzyRnvMqXqRSI,2675
importlib_metadata/tests/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_metadata/tests/data/example-21.12-py3-none-any.whl,sha256=I-kYufETid-tDYyR8f1OFJ3t5u_Io23k0cbQxJTUN4I,1455
importlib_metadata/tests/data/example-21.12-py3.6.egg,sha256=-EeugFAijkdUO9xyQHTZkQwZoFXK0_QxICBj6R5AAJo,1497
importlib_metadata-1.7.0.dist-info/LICENSE,sha256=wNe6dAchmJ1VvVB8D9oTc-gHHadCuaSBAev36sYEM6U,571
importlib_metadata-1.7.0.dist-info/METADATA,sha256=AvM2AcUhNbF_2Yyo8ttyVBCh_qGbRHaRE3MVgrHYDVw,2144
importlib_metadata-1.7.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
importlib_metadata-1.7.0.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
importlib_metadata-1.7.0.dist-info/RECORD,,

View File

@ -1,10 +1,10 @@
Metadata-Version: 2.1
Name: importlib-metadata
Version: 1.7.0
Version: 2.1.1
Summary: Read metadata from Python packages
Home-page: http://importlib-metadata.readthedocs.io/
Author: Barry Warsaw
Author-email: barry@python.org
Author: Jason R. Coombs
Author-email: jaraco@jaraco.com
License: Apache Software License
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
@ -24,14 +24,21 @@ Requires-Dist: rst.linker ; extra == 'docs'
Provides-Extra: testing
Requires-Dist: packaging ; extra == 'testing'
Requires-Dist: pep517 ; extra == 'testing'
Requires-Dist: unittest2 ; (python_version < "3") and extra == 'testing'
Requires-Dist: importlib-resources (>=1.3) ; (python_version < "3.9") and extra == 'testing'
=========================
``importlib_metadata``
=========================
``importlib_metadata`` is a library to access the metadata for a Python
package. It is intended to be ported to Python 3.8.
``importlib_metadata`` is a library to access the metadata for a
Python package.
As of Python 3.8, this functionality has been added to the
`Python standard library
<https://docs.python.org/3/library/importlib.metadata.html>`_.
This package supplies backports of that functionality including
improvements added to subsequent Python versions.
Usage
@ -58,9 +65,9 @@ tools (or other conforming packages). It does not support:
Project details
===============
* Project home: https://gitlab.com/python-devs/importlib_metadata
* Report bugs at: https://gitlab.com/python-devs/importlib_metadata/issues
* Code hosting: https://gitlab.com/python-devs/importlib_metadata.git
* Documentation: http://importlib_metadata.readthedocs.io/
* Project home: https://github.com/python/importlib_metadata
* Report bugs at: https://github.com/python/importlib_metadata/issues
* Code hosting: https://github.com/python/importlib_metadata
* Documentation: https://importlib_metadata.readthedocs.io/

View File

@ -0,0 +1,7 @@
importlib_metadata/__init__.py,sha256=uaN7KDLs3-irvgwsxg4VZIuY3ZEo3jhu1dShjE7fR88,19587
importlib_metadata/_compat.py,sha256=DnM55BbJKFCcZmJOkArmyO76-0g7pA6HEfzSYWXN88k,4417
importlib_metadata-2.1.1.dist-info/LICENSE,sha256=wNe6dAchmJ1VvVB8D9oTc-gHHadCuaSBAev36sYEM6U,571
importlib_metadata-2.1.1.dist-info/METADATA,sha256=gBf5nX-Ff6_Ue9dSH4dkWg2FCNHHtQrs6mhunTAac8k,2421
importlib_metadata-2.1.1.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
importlib_metadata-2.1.1.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
importlib_metadata-2.1.1.dist-info/RECORD,,

View File

@ -462,43 +462,67 @@ class FastPath:
for child in names
)
def is_egg(self, search):
base = self.base
return (
base == search.versionless_egg_name
or base.startswith(search.prefix)
and base.endswith('.egg'))
def search(self, name):
for child in self.children():
n_low = child.lower()
if (n_low in name.exact_matches
or n_low.startswith(name.prefix)
and n_low.endswith(name.suffixes)
# legacy case:
or self.is_egg(name) and n_low == 'egg-info'):
yield self.joinpath(child)
return (
self.joinpath(child)
for child in self.children()
if name.matches(child, self.base)
)
class Prepared:
"""
A prepared search for metadata on a possibly-named package.
"""
normalized = ''
prefix = ''
normalized = None
suffixes = '.dist-info', '.egg-info'
exact_matches = [''][:0]
versionless_egg_name = ''
def __init__(self, name):
self.name = name
if name is None:
return
self.normalized = name.lower().replace('-', '_')
self.prefix = self.normalized + '-'
self.normalized = self.normalize(name)
self.exact_matches = [
self.normalized + suffix for suffix in self.suffixes]
self.versionless_egg_name = self.normalized + '.egg'
@staticmethod
def normalize(name):
"""
PEP 503 normalization plus dashes as underscores.
"""
return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_')
@staticmethod
def legacy_normalize(name):
"""
Normalize the package name as found in the convention in
older packaging tools versions and specs.
"""
return name.lower().replace('-', '_')
def matches(self, cand, base):
low = cand.lower()
pre, ext = os.path.splitext(low)
name, sep, rest = pre.partition('-')
return (
low in self.exact_matches
or ext in self.suffixes and (
not self.normalized or
name.replace('.', '_') == self.normalized
)
# legacy case:
or self.is_egg(base) and low == 'egg-info'
)
def is_egg(self, base):
normalized = self.legacy_normalize(self.name or '')
prefix = normalized + '-' if normalized else ''
versionless_egg_name = normalized + '.egg' if self.name else ''
return (
base == versionless_egg_name
or base.startswith(prefix)
and base.endswith('.egg'))
@install
@ -618,6 +642,3 @@ def requires(distribution_name):
packaging.requirement.Requirement.
"""
return distribution(distribution_name).requires
__version__ = version(__name__)

View File

@ -0,0 +1,13 @@
Copyright 2017-2019 Jason R. Coombs, Barry Warsaw
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,94 @@
Metadata-Version: 2.1
Name: importlib-metadata
Version: 3.1.1
Summary: Read metadata from Python packages
Home-page: https://github.com/python/importlib_metadata
Author: Jason R. Coombs
Author-email: jaraco@jaraco.com
License: UNKNOWN
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.6
Requires-Dist: zipp (>=0.5)
Provides-Extra: docs
Requires-Dist: sphinx ; extra == 'docs'
Requires-Dist: jaraco.packaging (>=3.2) ; extra == 'docs'
Requires-Dist: rst.linker (>=1.9) ; extra == 'docs'
Provides-Extra: testing
Requires-Dist: pytest (!=3.7.3,>=3.5) ; extra == 'testing'
Requires-Dist: pytest-checkdocs (>=1.2.3) ; extra == 'testing'
Requires-Dist: pytest-flake8 ; extra == 'testing'
Requires-Dist: pytest-cov ; extra == 'testing'
Requires-Dist: jaraco.test (>=3.2.0) ; extra == 'testing'
Requires-Dist: packaging ; extra == 'testing'
Requires-Dist: pep517 ; extra == 'testing'
Requires-Dist: pyfakefs ; extra == 'testing'
Requires-Dist: flufl.flake8 ; extra == 'testing'
Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing'
Requires-Dist: pytest-mypy ; (platform_python_implementation != "PyPy") and extra == 'testing'
Requires-Dist: importlib-resources (>=1.3) ; (python_version < "3.9") and extra == 'testing'
.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg
:target: `PyPI link`_
.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg
:target: `PyPI link`_
.. _PyPI link: https://pypi.org/project/importlib_metadata
.. image:: https://github.com/python/importlib_metadata/workflows/Automated%20Tests/badge.svg
:target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22Automated+Tests%22
:alt: Automated Tests
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
:alt: Code style: Black
.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest
:target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest
``importlib_metadata`` is a library to access the metadata for a
Python package.
As of Python 3.8, this functionality has been added to the
`Python standard library
<https://docs.python.org/3/library/importlib.metadata.html>`_.
This package supplies backports of that functionality including
improvements added to subsequent Python versions.
Usage
=====
See the `online documentation <https://importlib_metadata.readthedocs.io/>`_
for usage details.
`Finder authors
<https://docs.python.org/3/reference/import.html#finders-and-loaders>`_ can
also add support for custom package installers. See the above documentation
for details.
Caveats
=======
This project primarily supports third-party packages installed by PyPA
tools (or other conforming packages). It does not support:
- Packages in the stdlib.
- Packages installed without metadata.
Project details
===============
* Project home: https://github.com/python/importlib_metadata
* Report bugs at: https://github.com/python/importlib_metadata/issues
* Code hosting: https://github.com/python/importlib_metadata
* Documentation: https://importlib_metadata.readthedocs.io/

View File

@ -0,0 +1,7 @@
importlib_metadata/__init__.py,sha256=QM4Oo096u6JYeokkDUwHgazI_h3o0w9tISPjHtVko_U,19266
importlib_metadata/_compat.py,sha256=OS4joET_vaQClxhumw0NWYdS5N3FX1Ii895aZXLpQaA,2028
importlib_metadata-3.1.1.dist-info/LICENSE,sha256=wNe6dAchmJ1VvVB8D9oTc-gHHadCuaSBAev36sYEM6U,571
importlib_metadata-3.1.1.dist-info/METADATA,sha256=rdblRVlpAdjDcYkqWhn2yVNwrpBqpamdKvxrgA6EWE0,3442
importlib_metadata-3.1.1.dist-info/WHEEL,sha256=gm79cMopkncyn0iSnI0vQNiDJ8t9on0H4_iz-CrpXMk,92
importlib_metadata-3.1.1.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
importlib_metadata-3.1.1.dist-info/RECORD,,

View File

@ -1,5 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.34.2)
Generator: bdist_wheel (0.36.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -0,0 +1,631 @@
import io
import os
import re
import abc
import csv
import sys
import zipp
import email
import pathlib
import operator
import functools
import itertools
import posixpath
import collections
from ._compat import (
NullFinder,
PyPy_repr,
install,
)
from configparser import ConfigParser
from contextlib import suppress
from importlib import import_module
from importlib.abc import MetaPathFinder
from itertools import starmap
__all__ = [
'Distribution',
'DistributionFinder',
'PackageNotFoundError',
'distribution',
'distributions',
'entry_points',
'files',
'metadata',
'requires',
'version',
]
class PackageNotFoundError(ModuleNotFoundError):
"""The package was not found."""
def __str__(self):
tmpl = "No package metadata was found for {self.name}"
return tmpl.format(**locals())
@property
def name(self):
(name,) = self.args
return name
class EntryPoint(
PyPy_repr, collections.namedtuple('EntryPointBase', 'name value group')
):
"""An entry point as defined by Python packaging conventions.
See `the packaging docs on entry points
<https://packaging.python.org/specifications/entry-points/>`_
for more information.
"""
pattern = re.compile(
r'(?P<module>[\w.]+)\s*'
r'(:\s*(?P<attr>[\w.]+))?\s*'
r'(?P<extras>\[.*\])?\s*$'
)
"""
A regular expression describing the syntax for an entry point,
which might look like:
- module
- package.module
- package.module:attribute
- package.module:object.attribute
- package.module:attr [extra1, extra2]
Other combinations are possible as well.
The expression is lenient about whitespace around the ':',
following the attr, and following any extras.
"""
def load(self):
"""Load the entry point from its definition. If only a module
is indicated by the value, return that module. Otherwise,
return the named object.
"""
match = self.pattern.match(self.value)
module = import_module(match.group('module'))
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)
return list(re.finditer(r'\w+', match.group('extras') or ''))
@classmethod
def _from_config(cls, config):
return [
cls(name, value, group)
for group in config.sections()
for name, value in config.items(group)
]
@classmethod
def _from_text(cls, text):
config = ConfigParser(delimiters='=')
# case sensitive: https://stackoverflow.com/q/1611799/812183
config.optionxform = str
try:
config.read_string(text)
except AttributeError: # pragma: nocover
# Python 2 has no read_string
config.readfp(io.StringIO(text))
return EntryPoint._from_config(config)
def __iter__(self):
"""
Supply iter so one may construct dicts of EntryPoints easily.
"""
return iter((self.name, self))
def __reduce__(self):
return (
self.__class__,
(self.name, self.value, self.group),
)
class PackagePath(pathlib.PurePosixPath):
"""A reference to a path in a package"""
def read_text(self, encoding='utf-8'):
with self.locate().open(encoding=encoding) as stream:
return stream.read()
def read_binary(self):
with self.locate().open('rb') as stream:
return stream.read()
def locate(self):
"""Return a path-like object for this path"""
return self.dist.locate_file(self)
class FileHash:
def __init__(self, spec):
self.mode, _, self.value = spec.partition('=')
def __repr__(self):
return '<FileHash mode: {} value: {}>'.format(self.mode, self.value)
class Distribution:
"""A Python distribution package."""
@abc.abstractmethod
def read_text(self, filename):
"""Attempt to load metadata file given by the name.
:param filename: The name of the file in the distribution info.
:return: The text if found, otherwise None.
"""
@abc.abstractmethod
def locate_file(self, path):
"""
Given a path to a file in this distribution, return a path
to it.
"""
@classmethod
def from_name(cls, name):
"""Return the Distribution for the given package name.
:param name: The name of the distribution package to search for.
:return: The Distribution instance (or subclass thereof) for the named
package, if found.
:raises PackageNotFoundError: When the named package's distribution
metadata cannot be found.
"""
for resolver in cls._discover_resolvers():
dists = resolver(DistributionFinder.Context(name=name))
dist = next(iter(dists), None)
if dist is not None:
return dist
else:
raise PackageNotFoundError(name)
@classmethod
def discover(cls, **kwargs):
"""Return an iterable of Distribution objects for all packages.
Pass a ``context`` or pass keyword arguments for constructing
a context.
:context: A ``DistributionFinder.Context`` object.
:return: Iterable of Distribution objects for all packages.
"""
context = kwargs.pop('context', None)
if context and kwargs:
raise ValueError("cannot accept context and kwargs")
context = context or DistributionFinder.Context(**kwargs)
return itertools.chain.from_iterable(
resolver(context) for resolver in cls._discover_resolvers()
)
@staticmethod
def at(path):
"""Return a Distribution for the indicated metadata path
:param path: a string or path-like object
:return: a concrete Distribution instance for the path
"""
return PathDistribution(pathlib.Path(path))
@staticmethod
def _discover_resolvers():
"""Search the meta_path for resolvers."""
declared = (
getattr(finder, 'find_distributions', None) for finder in sys.meta_path
)
return filter(None, declared)
@classmethod
def _local(cls, root='.'):
from pep517 import build, meta
system = build.compat_system(root)
builder = functools.partial(
meta.build,
source_dir=root,
system=system,
)
return PathDistribution(zipp.Path(meta.build_as_zip(builder)))
@property
def metadata(self):
"""Return the parsed metadata for this Distribution.
The returned object will have keys that name the various bits of
metadata. See PEP 566 for details.
"""
text = (
self.read_text('METADATA')
or self.read_text('PKG-INFO')
# This last clause is here to support old egg-info files. Its
# effect is to just end up using the PathDistribution's self._path
# (which points to the egg-info file) attribute unchanged.
or self.read_text('')
)
return email.message_from_string(text)
@property
def version(self):
"""Return the 'Version' metadata for the distribution package."""
return self.metadata['Version']
@property
def entry_points(self):
return EntryPoint._from_text(self.read_text('entry_points.txt'))
@property
def files(self):
"""Files in this distribution.
:return: List of PackagePath for this distribution or None
Result is `None` if the metadata file that enumerates files
(i.e. RECORD for dist-info or SOURCES.txt for egg-info) is
missing.
Result may be empty if the metadata exists but is empty.
"""
file_lines = self._read_files_distinfo() or self._read_files_egginfo()
def make_file(name, hash=None, size_str=None):
result = PackagePath(name)
result.hash = FileHash(hash) if hash else None
result.size = int(size_str) if size_str else None
result.dist = self
return result
return file_lines and list(starmap(make_file, csv.reader(file_lines)))
def _read_files_distinfo(self):
"""
Read the lines of RECORD
"""
text = self.read_text('RECORD')
return text and text.splitlines()
def _read_files_egginfo(self):
"""
SOURCES.txt might contain literal commas, so wrap each line
in quotes.
"""
text = self.read_text('SOURCES.txt')
return text and map('"{}"'.format, text.splitlines())
@property
def requires(self):
"""Generated requirements specified for this Distribution"""
reqs = self._read_dist_info_reqs() or self._read_egg_info_reqs()
return reqs and list(reqs)
def _read_dist_info_reqs(self):
return self.metadata.get_all('Requires-Dist')
def _read_egg_info_reqs(self):
source = self.read_text('requires.txt')
return source and self._deps_from_requires_text(source)
@classmethod
def _deps_from_requires_text(cls, source):
section_pairs = cls._read_sections(source.splitlines())
sections = {
section: list(map(operator.itemgetter('line'), results))
for section, results in itertools.groupby(
section_pairs, operator.itemgetter('section')
)
}
return cls._convert_egg_info_reqs_to_simple_reqs(sections)
@staticmethod
def _read_sections(lines):
section = None
for line in filter(None, lines):
section_match = re.match(r'\[(.*)\]$', line)
if section_match:
section = section_match.group(1)
continue
yield locals()
@staticmethod
def _convert_egg_info_reqs_to_simple_reqs(sections):
"""
Historically, setuptools would solicit and store 'extra'
requirements, including those with environment markers,
in separate sections. More modern tools expect each
dependency to be defined separately, with any relevant
extras and environment markers attached directly to that
requirement. This method converts the former to the
latter. See _test_deps_from_requires_text for an example.
"""
def make_condition(name):
return name and 'extra == "{name}"'.format(name=name)
def parse_condition(section):
section = section or ''
extra, sep, markers = section.partition(':')
if extra and markers:
markers = '({markers})'.format(markers=markers)
conditions = list(filter(None, [markers, make_condition(extra)]))
return '; ' + ' and '.join(conditions) if conditions else ''
for section, deps in sections.items():
for dep in deps:
yield dep + parse_condition(section)
class DistributionFinder(MetaPathFinder):
"""
A MetaPathFinder capable of discovering installed distributions.
"""
class Context:
"""
Keyword arguments presented by the caller to
``distributions()`` or ``Distribution.discover()``
to narrow the scope of a search for distributions
in all DistributionFinders.
Each DistributionFinder may expect any parameters
and should attempt to honor the canonical
parameters defined below when appropriate.
"""
name = None
"""
Specific name for which a distribution finder should match.
A name of ``None`` matches all distributions.
"""
def __init__(self, **kwargs):
vars(self).update(kwargs)
@property
def path(self):
"""
The path that a distribution finder should search.
Typically refers to Python package paths and defaults
to ``sys.path``.
"""
return vars(self).get('path', sys.path)
@abc.abstractmethod
def find_distributions(self, context=Context()):
"""
Find distributions.
Return an iterable of all Distribution instances capable of
loading the metadata for packages matching the ``context``,
a DistributionFinder.Context instance.
"""
class FastPath:
"""
Micro-optimized class for searching a path for
children.
"""
def __init__(self, root):
self.root = str(root)
self.base = os.path.basename(self.root).lower()
def joinpath(self, child):
return pathlib.Path(self.root, child)
def children(self):
with suppress(Exception):
return os.listdir(self.root or '')
with suppress(Exception):
return self.zip_children()
return []
def zip_children(self):
zip_path = zipp.Path(self.root)
names = zip_path.root.namelist()
self.joinpath = zip_path.joinpath
return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names)
def search(self, name):
return (
self.joinpath(child)
for child in self.children()
if name.matches(child, self.base)
)
class Prepared:
"""
A prepared search for metadata on a possibly-named package.
"""
normalized = None
suffixes = '.dist-info', '.egg-info'
exact_matches = [''][:0]
def __init__(self, name):
self.name = name
if name is None:
return
self.normalized = self.normalize(name)
self.exact_matches = [self.normalized + suffix for suffix in self.suffixes]
@staticmethod
def normalize(name):
"""
PEP 503 normalization plus dashes as underscores.
"""
return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_')
@staticmethod
def legacy_normalize(name):
"""
Normalize the package name as found in the convention in
older packaging tools versions and specs.
"""
return name.lower().replace('-', '_')
def matches(self, cand, base):
low = cand.lower()
pre, ext = os.path.splitext(low)
name, sep, rest = pre.partition('-')
return (
low in self.exact_matches
or ext in self.suffixes
and (not self.normalized or name.replace('.', '_') == self.normalized)
# legacy case:
or self.is_egg(base)
and low == 'egg-info'
)
def is_egg(self, base):
normalized = self.legacy_normalize(self.name or '')
prefix = normalized + '-' if normalized else ''
versionless_egg_name = normalized + '.egg' if self.name else ''
return (
base == versionless_egg_name
or base.startswith(prefix)
and base.endswith('.egg')
)
@install
class MetadataPathFinder(NullFinder, DistributionFinder):
"""A degenerate finder for distribution packages on the file system.
This finder supplies only a find_distributions() method for versions
of Python that do not have a PathFinder find_distributions().
"""
def find_distributions(self, context=DistributionFinder.Context()):
"""
Find distributions.
Return an iterable of all Distribution instances capable of
loading the metadata for packages matching ``context.name``
(or all names if ``None`` indicated) along the paths in the list
of directories ``context.path``.
"""
found = self._search_paths(context.name, context.path)
return map(PathDistribution, found)
@classmethod
def _search_paths(cls, name, paths):
"""Find metadata directories in paths heuristically."""
return itertools.chain.from_iterable(
path.search(Prepared(name)) for path in map(FastPath, paths)
)
class PathDistribution(Distribution):
def __init__(self, path):
"""Construct a distribution from a path to the metadata directory.
:param path: A pathlib.Path or similar object supporting
.joinpath(), __div__, .parent, and .read_text().
"""
self._path = path
def read_text(self, filename):
with suppress(
FileNotFoundError,
IsADirectoryError,
KeyError,
NotADirectoryError,
PermissionError,
):
return self._path.joinpath(filename).read_text(encoding='utf-8')
read_text.__doc__ = Distribution.read_text.__doc__
def locate_file(self, path):
return self._path.parent / path
def distribution(distribution_name):
"""Get the ``Distribution`` instance for the named package.
:param distribution_name: The name of the distribution package as a string.
:return: A ``Distribution`` instance (or subclass thereof).
"""
return Distribution.from_name(distribution_name)
def distributions(**kwargs):
"""Get all ``Distribution`` instances in the current environment.
:return: An iterable of ``Distribution`` instances.
"""
return Distribution.discover(**kwargs)
def metadata(distribution_name):
"""Get the metadata for the named package.
:param distribution_name: The name of the distribution package to query.
:return: An email.Message containing the parsed metadata.
"""
return Distribution.from_name(distribution_name).metadata
def version(distribution_name):
"""Get the version string for the named package.
:param distribution_name: The name of the distribution package to query.
:return: The version string for the package as defined in the package's
"Version" metadata key.
"""
return distribution(distribution_name).version
def entry_points():
"""Return EntryPoint objects for all installed packages.
:return: EntryPoint objects for all installed packages.
"""
eps = itertools.chain.from_iterable(dist.entry_points for dist in distributions())
by_group = operator.attrgetter('group')
ordered = sorted(eps, key=by_group)
grouped = itertools.groupby(ordered, by_group)
return {group: tuple(eps) for group, eps in grouped}
def files(distribution_name):
"""Return a list of files for the named package.
:param distribution_name: The name of the distribution package to query.
:return: List of files composing the distribution.
"""
return distribution(distribution_name).files
def requires(distribution_name):
"""
Return a list of requirements for the named package.
:return: An iterator of requirements, suitable for
packaging.requirement.Requirement.
"""
return distribution(distribution_name).requires

View File

@ -0,0 +1,75 @@
import sys
__all__ = ['install', 'NullFinder', 'PyPy_repr']
def install(cls):
"""
Class decorator for installation on sys.meta_path.
Adds the backport DistributionFinder to sys.meta_path and
attempts to disable the finder functionality of the stdlib
DistributionFinder.
"""
sys.meta_path.append(cls())
disable_stdlib_finder()
return cls
def disable_stdlib_finder():
"""
Give the backport primacy for discovering path-based distributions
by monkey-patching the stdlib O_O.
See #91 for more background for rationale on this sketchy
behavior.
"""
def matches(finder):
return getattr(
finder, '__module__', None
) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions')
for finder in filter(matches, sys.meta_path): # pragma: nocover
del finder.find_distributions
class NullFinder:
"""
A "Finder" (aka "MetaClassFinder") that never finds any modules,
but may find distributions.
"""
@staticmethod
def find_spec(*args, **kwargs):
return None
# In Python 2, the import system requires finders
# to have a find_module() method, but this usage
# is deprecated in Python 3 in favor of find_spec().
# For the purposes of this finder (i.e. being present
# on sys.meta_path but having no other import
# system functionality), the two methods are identical.
find_module = find_spec
class PyPy_repr:
"""
Override repr for EntryPoint objects on PyPy to avoid __iter__ access.
Ref #97, #102.
"""
affected = hasattr(sys, 'pypy_version_info')
def __compat_repr__(self): # pragma: nocover
def make_param(name):
value = getattr(self, name)
return '{name}={value!r}'.format(**locals())
params = ', '.join(map(make_param, self._fields))
return 'EntryPoint({params})'.format(**locals())
if affected: # pragma: nocover
__repr__ = __compat_repr__
del affected

View File

@ -1,41 +0,0 @@
from . import abc
from ._compat import Path, ZipPath
class FileReader(abc.TraversableResources):
def __init__(self, loader):
self.path = Path(loader.path).parent
def resource_path(self, resource):
"""
Return the file system path to prevent
`resources.path()` from creating a temporary
copy.
"""
return str(self.path.joinpath(resource))
def files(self):
return self.path
class ZipReader(abc.TraversableResources):
def __init__(self, loader, module):
_, _, name = module.rpartition('.')
prefix = loader.prefix.replace('\\', '/') + name + '/'
self.path = ZipPath(loader.archive, prefix)
def open_resource(self, resource):
try:
return super().open_resource(resource)
except KeyError as exc:
raise FileNotFoundError(exc.args[0])
def is_resource(self, path):
# workaround for `zipfile.Path.is_file` returning true
# for non-existent paths.
target = self.files().joinpath(path)
return target.is_file() and target.exists()
def files(self):
return self.path

View File

@ -1,11 +1,12 @@
Metadata-Version: 2.1
Name: importlib-resources
Version: 3.0.0
Version: 3.2.1
Summary: Read resources from Python packages
Home-page: http://importlib-resources.readthedocs.io/
Home-page: https://github.com/python/importlib_resources
Author: Barry Warsaw
Author-email: barry@python.org
License: UNKNOWN
Project-URL: Documentation, https://importlib-resources.readthedocs.io/
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
@ -24,10 +25,6 @@ Requires-Dist: sphinx ; extra == 'docs'
Requires-Dist: rst.linker ; extra == 'docs'
Requires-Dist: jaraco.packaging ; extra == 'docs'
=========================
``importlib_resources``
=========================
``importlib_resources`` is a backport of Python standard library
`importlib.resources
<https://docs.python.org/3.9/library/importlib.html#module-importlib.resources>`_
@ -42,12 +39,3 @@ reading resources included in packages easier, with more stable and consistent
semantics.
Project details
===============
* Project home: https://gitlab.com/python-devs/importlib_resources
* Report bugs at: https://gitlab.com/python-devs/importlib_resources/issues
* Code hosting: https://gitlab.com/python-devs/importlib_resources.git
* Documentation: https://importlib-resources.readthedocs.io/

View File

@ -1,19 +1,22 @@
importlib_resources/__init__.py,sha256=hswDmLAH0IUlLWwmdHXPN2mgus2bk5IwDP-BFzg7VKo,977
importlib_resources/_common.py,sha256=jXVqgKZ1bt8IbZiErvjIeb69BjqsMSCSt9AwV4bHnE8,3157
importlib_resources/_compat.py,sha256=5nvS1tAZIl_6VqrFSScNVW2wtBGaRXGxcpDXMskruoA,3233
importlib_resources/_common.py,sha256=RN8cXOZtlygvlbyTewd-ni9wC1hwXpfbZnrl7kbx0nI,3121
importlib_resources/_compat.py,sha256=NDCXOf1097aDJJx-_pQ0UIktzVx2G1aPIQTRFGx0FHI,3694
importlib_resources/_py2.py,sha256=G9M5mv1ILl8NARGdNX0v9_F_Hb4HUKCS-FCNK63Ajvw,4146
importlib_resources/_py3.py,sha256=2wJYfjLG8nd9mT1HLBtX96m6zlu9-Tocte9wFl9q_bY,5474
importlib_resources/_py3.py,sha256=5_FhUUHWFG1c3HcLrmDy65ZFB7EYxmHfOV3ybv4uTHM,5710
importlib_resources/abc.py,sha256=6PX4Nprv39YnAht3NymhHIuSso0ocAKqDJZf-A6BgIw,3894
importlib_resources/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/readers.py,sha256=S0DsGQB1li6w5USiZQtiy-5HXe4UAxt-zmKo8QlAxsI,1155
importlib_resources/readers.py,sha256=fGuSBoMeeERUVrscN9Grhp0s-wKMy7nMVbCx92vIlGs,3674
importlib_resources/trees.py,sha256=U3FlQSI5--eF4AdzOjBvW4xnjL21OFX8ivk82Quwv_M,117
importlib_resources/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/_compat.py,sha256=geKWJe8UGXjC181JxmtxR3A_o5VrR4yxolS0xbnxMlw,801
importlib_resources/tests/py27compat.py,sha256=9lDJkGV2swPVQJg6isOorRNFWuP6KeoWd4D2bFNmzLI,965
importlib_resources/tests/test_files.py,sha256=91rf4C74_aJsKNSt-a-03slVpY9QSAuCbogFWnsaPjE,1017
importlib_resources/tests/test_open.py,sha256=yDXmTGXQspByj6WU0prnoVwab1yWWEA3fwz_XIx7TQU,2288
importlib_resources/tests/test_open.py,sha256=pIYWvuTDpQOJKX0SEuOKGotssZcEeY_xNPDqLGCvP_U,2565
importlib_resources/tests/test_path.py,sha256=GnUOu-338o9offnC8xwbXjH9JIQJpD7JujgQkGB106Q,1548
importlib_resources/tests/test_read.py,sha256=DpA7tzxSQlU0_YQuWibB3E5PDL9fQUdzeKoEUGnAx78,2046
importlib_resources/tests/test_resource.py,sha256=X77DzU2BRoM6d59iEh74zDHHw3pKOBGLCg3lP3dH4BI,6467
importlib_resources/tests/util.py,sha256=f0RZU-RkEkybJjXRd7C5HcWMsoLFRWJL4FIUF1CJ2wo,6980
importlib_resources/tests/test_reader.py,sha256=yEO0xyrYDcGRmsBC6A1n99GXiTZpVvp-uGA313s6aao,4638
importlib_resources/tests/test_resource.py,sha256=GbrMeHJ74N6KJG38TDodCp--nsRnFHXJc7NrAEqUPaU,8766
importlib_resources/tests/util.py,sha256=8hBFwqIZRJFNvkboEB7aWsCqTtgUjlWI_iQ0KV158Yk,5914
importlib_resources/tests/data01/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data01/binary.file,sha256=BU7ewdAhH2JP7Qy8qdT5QAsOSRxDdCryxbCr6_DJkNg,4
importlib_resources/tests/data01/utf-16.file,sha256=t5q9qhxX0rYqItBOM8D3ylwG-RHrnOYteTLtQr6sF7g,44
@ -25,16 +28,15 @@ importlib_resources/tests/data02/one/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
importlib_resources/tests/data02/one/resource1.txt,sha256=10flKac7c-XXFzJ3t-AB5MJjlBy__dSZvPE_dOm2q6U,13
importlib_resources/tests/data02/two/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data02/two/resource2.txt,sha256=lt2jbN3TMn9QiFKM832X39bU_62UptDdUkoYzkvEbl0,13
importlib_resources/tests/data03/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data03/namespace/resource1.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data03/namespace/portion1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data03/namespace/portion2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/namespacedata01/binary.file,sha256=BU7ewdAhH2JP7Qy8qdT5QAsOSRxDdCryxbCr6_DJkNg,4
importlib_resources/tests/namespacedata01/utf-16.file,sha256=t5q9qhxX0rYqItBOM8D3ylwG-RHrnOYteTLtQr6sF7g,44
importlib_resources/tests/namespacedata01/utf-8.file,sha256=kwWgYG4yQ-ZF2X_WA66EjYPmxJRn-w8aSOiS9e8tKYY,20
importlib_resources/tests/zipdata01/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/zipdata01/ziptestdata.zip,sha256=AYf51fj80OKCRis93v2DlZjt5rM-VQOPptSHJbFtkXw,1131
importlib_resources/tests/zipdata02/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/zipdata02/ziptestdata.zip,sha256=e6HXvTEObXvJcNxyX5I8tu5M8_6mSN8ALahHfqE7ADA,698
importlib_resources-3.0.0.dist-info/LICENSE,sha256=uWRjFdYGataJX2ziXk048ItUglQmjng3GWBALaWA36U,568
importlib_resources-3.0.0.dist-info/METADATA,sha256=BIalQpWJG-Av5ZUNQXdFsv6M8s8EdYiymu6GaoEL1Rk,2100
importlib_resources-3.0.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
importlib_resources-3.0.0.dist-info/top_level.txt,sha256=fHIjHU1GZwAjvcydpmUnUrTnbvdiWjG4OEVZK8by0TQ,20
importlib_resources-3.0.0.dist-info/RECORD,,
importlib_resources-3.2.1.dist-info/LICENSE,sha256=uWRjFdYGataJX2ziXk048ItUglQmjng3GWBALaWA36U,568
importlib_resources-3.2.1.dist-info/METADATA,sha256=d_tMNLHsZ_lPU-wq04MWr0yEfpwbNFKgfO_CU5GCC9g,1783
importlib_resources-3.2.1.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
importlib_resources-3.2.1.dist-info/top_level.txt,sha256=fHIjHU1GZwAjvcydpmUnUrTnbvdiWjG4OEVZK8by0TQ,20
importlib_resources-3.2.1.dist-info/RECORD,,

View File

@ -1,5 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.34.2)
Generator: bdist_wheel (0.35.1)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View File

@ -93,6 +93,7 @@ def _tempfile(reader, suffix=''):
try:
os.write(fd, reader())
os.close(fd)
del reader
yield Path(raw_path)
finally:
try:
@ -102,14 +103,12 @@ def _tempfile(reader, suffix=''):
@singledispatch
@contextlib.contextmanager
def as_file(path):
"""
Given a Traversable object, return that object as a
path on the local file system in a context manager.
"""
with _tempfile(path.read_bytes, suffix=path.name) as local:
yield local
return _tempfile(path.read_bytes, suffix=path.name)
@as_file.register(Path)

View File

@ -36,6 +36,12 @@ except NameError:
FileNotFoundError = OSError # type: ignore
try:
NotADirectoryError = NotADirectoryError # type: ignore
except NameError:
NotADirectoryError = OSError # type: ignore
try:
from zipfile import Path as ZipPath # type: ignore
except ImportError:
@ -93,6 +99,10 @@ class LoaderAdapter:
with suppress(AttributeError):
return readers.ZipReader(spec.loader, spec.name)
def _namespace_reader(spec):
with suppress(AttributeError, ValueError):
return readers.NamespaceReader(spec.submodule_search_locations)
def _available_reader(spec):
with suppress(AttributeError):
return spec.loader.get_resource_reader(spec.name)
@ -106,6 +116,8 @@ class LoaderAdapter:
_native_reader(self.spec) or
# local ZipReader if a zip module
_zip_reader(self.spec) or
# local NamespaceReader if a namespace module
_namespace_reader(self.spec) or
# local FileReader
readers.FileReader(self)
)

View File

@ -1,8 +1,9 @@
import os
import sys
import io
from . import _common
from contextlib import contextmanager, suppress
from contextlib import suppress
from importlib.abc import ResourceLoader
from io import BytesIO, TextIOWrapper
from pathlib import Path
@ -10,6 +11,8 @@ from types import ModuleType
from typing import Iterable, Iterator, Optional, Set, Union # noqa: F401
from typing import cast
from typing.io import BinaryIO, TextIO
from collections.abc import Sequence
from ._compat import singledispatch
if False: # TYPE_CHECKING
from typing import ContextManager
@ -30,27 +33,29 @@ def open_binary(package: Package, resource: Resource) -> BinaryIO:
return reader.open_resource(resource)
# Using pathlib doesn't work well here due to the lack of 'strict'
# argument for pathlib.Path.resolve() prior to Python 3.6.
absolute_package_path = os.path.abspath(
package.__spec__.origin or 'non-existent file')
package_path = os.path.dirname(absolute_package_path)
full_path = os.path.join(package_path, resource)
try:
return open(full_path, mode='rb')
except OSError:
# Just assume the loader is a resource loader; all the relevant
# importlib.machinery loaders are and an AttributeError for
# get_data() will make it clear what is needed from the loader.
loader = cast(ResourceLoader, package.__spec__.loader)
data = None
if hasattr(package.__spec__.loader, 'get_data'):
with suppress(OSError):
data = loader.get_data(full_path)
if data is None:
package_name = package.__spec__.name
message = '{!r} resource not found in {!r}'.format(
resource, package_name)
raise FileNotFoundError(message)
return BytesIO(data)
if package.__spec__.submodule_search_locations is not None:
paths = package.__spec__.submodule_search_locations
elif package.__spec__.origin is not None:
paths = [os.path.dirname(os.path.abspath(package.__spec__.origin))]
for package_path in paths:
full_path = os.path.join(package_path, resource)
try:
return open(full_path, mode='rb')
except OSError:
# Just assume the loader is a resource loader; all the relevant
# importlib.machinery loaders are and an AttributeError for
# get_data() will make it clear what is needed from the loader.
loader = cast(ResourceLoader, package.__spec__.loader)
data = None
if hasattr(package.__spec__.loader, 'get_data'):
with suppress(OSError):
data = loader.get_data(full_path)
if data is not None:
return BytesIO(data)
raise FileNotFoundError('{!r} resource not found in {!r}'.format(
resource, package.__spec__.name))
def open_text(package: Package,
@ -94,22 +99,26 @@ def path(
"""
reader = _common.get_resource_reader(_common.get_package(package))
return (
_path_from_reader(reader, resource)
_path_from_reader(reader, _common.normalize_path(resource))
if reader else
_common.as_file(
_common.files(package).joinpath(_common.normalize_path(resource)))
)
@contextmanager
def _path_from_reader(reader, resource):
norm_resource = _common.normalize_path(resource)
return _path_from_resource_path(reader, resource) or \
_path_from_open_resource(reader, resource)
def _path_from_resource_path(reader, resource):
with suppress(FileNotFoundError):
yield Path(reader.resource_path(norm_resource))
return
opener_reader = reader.open_resource(norm_resource)
with _common._tempfile(opener_reader.read, suffix=norm_resource) as res:
yield res
return Path(reader.resource_path(resource))
def _path_from_open_resource(reader, resource):
saved = io.BytesIO(reader.open_resource(resource).read())
return _common._tempfile(saved.read, suffix=resource)
def is_resource(package: Package, name: str) -> bool:
@ -138,13 +147,18 @@ def contents(package: Package) -> Iterable[str]:
package = _common.get_package(package)
reader = _common.get_resource_reader(package)
if reader is not None:
return reader.contents()
# Is the package a namespace package? By definition, namespace packages
# cannot have resources.
namespace = (
package.__spec__.origin is None or
package.__spec__.origin == 'namespace'
)
if namespace or not package.__spec__.has_location:
return ()
return list(item.name for item in _common.from_package(package).iterdir())
return _ensure_sequence(reader.contents())
transversable = _common.from_package(package)
if transversable.is_dir():
return list(item.name for item in transversable.iterdir())
return []
@singledispatch
def _ensure_sequence(iterable):
return list(iterable)
@_ensure_sequence.register(Sequence)
def _(iterable):
return iterable

View File

@ -0,0 +1,123 @@
import os.path
from collections import OrderedDict
from . import abc
from ._compat import Path, ZipPath
from ._compat import FileNotFoundError, NotADirectoryError
class FileReader(abc.TraversableResources):
def __init__(self, loader):
self.path = Path(loader.path).parent
def resource_path(self, resource):
"""
Return the file system path to prevent
`resources.path()` from creating a temporary
copy.
"""
return str(self.path.joinpath(resource))
def files(self):
return self.path
class ZipReader(abc.TraversableResources):
def __init__(self, loader, module):
_, _, name = module.rpartition('.')
self.prefix = loader.prefix.replace('\\', '/') + name + '/'
self.archive = loader.archive
def open_resource(self, resource):
try:
return super().open_resource(resource)
except KeyError as exc:
raise FileNotFoundError(exc.args[0])
def is_resource(self, path):
# workaround for `zipfile.Path.is_file` returning true
# for non-existent paths.
target = self.files().joinpath(path)
return target.is_file() and target.exists()
def files(self):
return ZipPath(self.archive, self.prefix)
class MultiplexedPath(abc.Traversable):
"""
Given a series of Traversable objects, implement a merged
version of the interface across all objects. Useful for
namespace packages which may be multihomed at a single
name.
"""
def __init__(self, *paths):
paths = list(OrderedDict.fromkeys(paths)) # remove duplicates
self._paths = list(map(Path, paths))
if not self._paths:
message = 'MultiplexedPath must contain at least one path'
raise FileNotFoundError(message)
if any(not path.is_dir() for path in self._paths):
raise NotADirectoryError(
'MultiplexedPath only supports directories')
def iterdir(self):
visited = []
for path in self._paths:
for file in path.iterdir():
if file.name in visited:
continue
visited.append(file.name)
yield file
def read_bytes(self):
raise FileNotFoundError('{} is not a file'.format(self))
def read_text(self, *args, **kwargs):
raise FileNotFoundError('{} is not a file'.format(self))
def is_dir(self):
return True
def is_file(self):
return False
def joinpath(self, child):
# first try to find child in current paths
for file in self.iterdir():
if file.name == child:
return file
# if it does not exist, construct it with the first path
return self._paths[0] / child
__truediv__ = joinpath
def open(self, *args, **kwargs):
raise FileNotFoundError('{} is not a file'.format(self))
def name(self):
return os.path.basename(self._paths[0])
def __repr__(self):
return 'MultiplexedPath({})'.format(
', '.join("'{}'".format(path) for path in self._paths))
class NamespaceReader(abc.TraversableResources):
def __init__(self, namespace_path):
if 'NamespacePath' not in str(namespace_path):
raise ValueError('Invalid path')
self.path = MultiplexedPath(*list(namespace_path))
def resource_path(self, resource):
"""
Return the file system path to prevent
`resources.path()` from creating a temporary
copy.
"""
return str(self.path.joinpath(resource))
def files(self):
return self.path

View File

@ -0,0 +1,13 @@
Copyright 2017-2019 Brett Cannon, Barry Warsaw
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,41 @@
Metadata-Version: 2.1
Name: importlib-resources
Version: 3.3.0
Summary: Read resources from Python packages
Home-page: https://github.com/python/importlib_resources
Author: Barry Warsaw
Author-email: barry@python.org
License: UNKNOWN
Project-URL: Documentation, https://importlib-resources.readthedocs.io/
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Topic :: Software Development :: Libraries
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7
Requires-Dist: pathlib2 ; python_version < "3"
Requires-Dist: contextlib2 ; python_version < "3"
Requires-Dist: singledispatch ; python_version < "3.4"
Requires-Dist: typing ; python_version < "3.5"
Requires-Dist: zipp (>=0.4) ; python_version < "3.8"
Provides-Extra: docs
Requires-Dist: sphinx ; extra == 'docs'
Requires-Dist: rst.linker ; extra == 'docs'
Requires-Dist: jaraco.packaging ; extra == 'docs'
``importlib_resources`` is a backport of Python standard library
`importlib.resources
<https://docs.python.org/3.9/library/importlib.html#module-importlib.resources>`_
module for Python 2.7, and 3.4 through 3.8. Users of Python 3.9 and beyond
should use the standard library module, since for these versions,
``importlib_resources`` just delegates to that module.
The key goal of this module is to replace parts of `pkg_resources
<https://setuptools.readthedocs.io/en/latest/pkg_resources.html>`_ with a
solution in Python's stdlib that relies on well-defined APIs. This makes
reading resources included in packages easier, with more stable and consistent
semantics.

View File

@ -0,0 +1,42 @@
importlib_resources/__init__.py,sha256=hswDmLAH0IUlLWwmdHXPN2mgus2bk5IwDP-BFzg7VKo,977
importlib_resources/_common.py,sha256=RN8cXOZtlygvlbyTewd-ni9wC1hwXpfbZnrl7kbx0nI,3121
importlib_resources/_compat.py,sha256=NDCXOf1097aDJJx-_pQ0UIktzVx2G1aPIQTRFGx0FHI,3694
importlib_resources/_py2.py,sha256=G9M5mv1ILl8NARGdNX0v9_F_Hb4HUKCS-FCNK63Ajvw,4146
importlib_resources/_py3.py,sha256=Bc-p0UYfPVWXFJ21HLNfVvbVrPJFXBA0g80rqPInkq8,5564
importlib_resources/abc.py,sha256=6PX4Nprv39YnAht3NymhHIuSso0ocAKqDJZf-A6BgIw,3894
importlib_resources/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/readers.py,sha256=fGuSBoMeeERUVrscN9Grhp0s-wKMy7nMVbCx92vIlGs,3674
importlib_resources/trees.py,sha256=U3FlQSI5--eF4AdzOjBvW4xnjL21OFX8ivk82Quwv_M,117
importlib_resources/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/_compat.py,sha256=geKWJe8UGXjC181JxmtxR3A_o5VrR4yxolS0xbnxMlw,801
importlib_resources/tests/py27compat.py,sha256=9lDJkGV2swPVQJg6isOorRNFWuP6KeoWd4D2bFNmzLI,965
importlib_resources/tests/test_files.py,sha256=91rf4C74_aJsKNSt-a-03slVpY9QSAuCbogFWnsaPjE,1017
importlib_resources/tests/test_open.py,sha256=pIYWvuTDpQOJKX0SEuOKGotssZcEeY_xNPDqLGCvP_U,2565
importlib_resources/tests/test_path.py,sha256=GnUOu-338o9offnC8xwbXjH9JIQJpD7JujgQkGB106Q,1548
importlib_resources/tests/test_read.py,sha256=DpA7tzxSQlU0_YQuWibB3E5PDL9fQUdzeKoEUGnAx78,2046
importlib_resources/tests/test_reader.py,sha256=yEO0xyrYDcGRmsBC6A1n99GXiTZpVvp-uGA313s6aao,4638
importlib_resources/tests/test_resource.py,sha256=GbrMeHJ74N6KJG38TDodCp--nsRnFHXJc7NrAEqUPaU,8766
importlib_resources/tests/util.py,sha256=8hBFwqIZRJFNvkboEB7aWsCqTtgUjlWI_iQ0KV158Yk,5914
importlib_resources/tests/data01/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data01/binary.file,sha256=BU7ewdAhH2JP7Qy8qdT5QAsOSRxDdCryxbCr6_DJkNg,4
importlib_resources/tests/data01/utf-16.file,sha256=t5q9qhxX0rYqItBOM8D3ylwG-RHrnOYteTLtQr6sF7g,44
importlib_resources/tests/data01/utf-8.file,sha256=kwWgYG4yQ-ZF2X_WA66EjYPmxJRn-w8aSOiS9e8tKYY,20
importlib_resources/tests/data01/subdirectory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data01/subdirectory/binary.file,sha256=BU7ewdAhH2JP7Qy8qdT5QAsOSRxDdCryxbCr6_DJkNg,4
importlib_resources/tests/data02/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data02/one/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data02/one/resource1.txt,sha256=10flKac7c-XXFzJ3t-AB5MJjlBy__dSZvPE_dOm2q6U,13
importlib_resources/tests/data02/two/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/data02/two/resource2.txt,sha256=lt2jbN3TMn9QiFKM832X39bU_62UptDdUkoYzkvEbl0,13
importlib_resources/tests/namespacedata01/binary.file,sha256=BU7ewdAhH2JP7Qy8qdT5QAsOSRxDdCryxbCr6_DJkNg,4
importlib_resources/tests/namespacedata01/utf-16.file,sha256=t5q9qhxX0rYqItBOM8D3ylwG-RHrnOYteTLtQr6sF7g,44
importlib_resources/tests/namespacedata01/utf-8.file,sha256=kwWgYG4yQ-ZF2X_WA66EjYPmxJRn-w8aSOiS9e8tKYY,20
importlib_resources/tests/zipdata01/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/zipdata01/ziptestdata.zip,sha256=AYf51fj80OKCRis93v2DlZjt5rM-VQOPptSHJbFtkXw,1131
importlib_resources/tests/zipdata02/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_resources/tests/zipdata02/ziptestdata.zip,sha256=e6HXvTEObXvJcNxyX5I8tu5M8_6mSN8ALahHfqE7ADA,698
importlib_resources-3.3.0.dist-info/LICENSE,sha256=uWRjFdYGataJX2ziXk048ItUglQmjng3GWBALaWA36U,568
importlib_resources-3.3.0.dist-info/METADATA,sha256=GxPMbCwUwlCuHNCiPJvP4IC_mTKqP4b_W7UqqNidcF4,1791
importlib_resources-3.3.0.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
importlib_resources-3.3.0.dist-info/top_level.txt,sha256=fHIjHU1GZwAjvcydpmUnUrTnbvdiWjG4OEVZK8by0TQ,20
importlib_resources-3.3.0.dist-info/RECORD,,

View File

@ -1,5 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.34.2)
Generator: bdist_wheel (0.35.1)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View File

@ -0,0 +1,53 @@
"""Read resources contained within a package."""
import sys
from ._common import (
as_file, files,
)
# For compatibility. Ref #88.
# Also requires hook-importlib_resources.py (Ref #101).
__import__('importlib_resources.trees')
__all__ = [
'Package',
'Resource',
'ResourceReader',
'as_file',
'contents',
'files',
'is_resource',
'open_binary',
'open_text',
'path',
'read_binary',
'read_text',
]
if sys.version_info >= (3,):
from importlib_resources._py3 import (
Package,
Resource,
contents,
is_resource,
open_binary,
open_text,
path,
read_binary,
read_text,
)
from importlib_resources.abc import ResourceReader
else:
from importlib_resources._py2 import (
contents,
is_resource,
open_binary,
open_text,
path,
read_binary,
read_text,
)
del __all__[:3]

View File

@ -0,0 +1,120 @@
from __future__ import absolute_import
import os
import tempfile
import contextlib
import types
import importlib
from ._compat import (
Path, FileNotFoundError,
singledispatch, package_spec,
)
if False: # TYPE_CHECKING
from typing import Union, Any, Optional
from .abc import ResourceReader
Package = Union[types.ModuleType, str]
def files(package):
"""
Get a Traversable resource from a package
"""
return from_package(get_package(package))
def normalize_path(path):
# type: (Any) -> str
"""Normalize a path by ensuring it is a string.
If the resulting string contains path separators, an exception is raised.
"""
str_path = str(path)
parent, file_name = os.path.split(str_path)
if parent:
raise ValueError('{!r} must be only a file name'.format(path))
return file_name
def get_resource_reader(package):
# type: (types.ModuleType) -> Optional[ResourceReader]
"""
Return the package's loader if it's a ResourceReader.
"""
# We can't use
# a issubclass() check here because apparently abc.'s __subclasscheck__()
# hook wants to create a weak reference to the object, but
# zipimport.zipimporter does not support weak references, resulting in a
# TypeError. That seems terrible.
spec = package.__spec__
reader = getattr(spec.loader, 'get_resource_reader', None)
if reader is None:
return None
return reader(spec.name)
def resolve(cand):
# type: (Package) -> types.ModuleType
return (
cand if isinstance(cand, types.ModuleType)
else importlib.import_module(cand)
)
def get_package(package):
# type: (Package) -> types.ModuleType
"""Take a package name or module object and return the module.
Raise an exception if the resolved module is not a package.
"""
resolved = resolve(package)
if package_spec(resolved).submodule_search_locations is None:
raise TypeError('{!r} is not a package'.format(package))
return resolved
def from_package(package):
"""
Return a Traversable object for the given package.
"""
spec = package_spec(package)
reader = spec.loader.get_resource_reader(spec.name)
return reader.files()
@contextlib.contextmanager
def _tempfile(reader, suffix=''):
# Not using tempfile.NamedTemporaryFile as it leads to deeper 'try'
# blocks due to the need to close the temporary file to work on Windows
# properly.
fd, raw_path = tempfile.mkstemp(suffix=suffix)
try:
os.write(fd, reader())
os.close(fd)
del reader
yield Path(raw_path)
finally:
try:
os.remove(raw_path)
except FileNotFoundError:
pass
@singledispatch
def as_file(path):
"""
Given a Traversable object, return that object as a
path on the local file system in a context manager.
"""
return _tempfile(path.read_bytes, suffix=path.name)
@as_file.register(Path)
@contextlib.contextmanager
def _(path):
"""
Degenerate behavior for pathlib.Path objects.
"""
yield path

View File

@ -0,0 +1,139 @@
from __future__ import absolute_import
import sys
# flake8: noqa
if sys.version_info > (3,5):
from pathlib import Path, PurePath
else:
from pathlib2 import Path, PurePath # type: ignore
if sys.version_info > (3,):
from contextlib import suppress
else:
from contextlib2 import suppress # type: ignore
try:
from functools import singledispatch
except ImportError:
from singledispatch import singledispatch # type: ignore
try:
from abc import ABC # type: ignore
except ImportError:
from abc import ABCMeta
class ABC(object): # type: ignore
__metaclass__ = ABCMeta
try:
FileNotFoundError = FileNotFoundError # type: ignore
except NameError:
FileNotFoundError = OSError # type: ignore
try:
NotADirectoryError = NotADirectoryError # type: ignore
except NameError:
NotADirectoryError = OSError # type: ignore
try:
from zipfile import Path as ZipPath # type: ignore
except ImportError:
from zipp import Path as ZipPath # type: ignore
try:
from typing import runtime_checkable # type: ignore
except ImportError:
def runtime_checkable(cls): # type: ignore
return cls
try:
from typing import Protocol # type: ignore
except ImportError:
Protocol = ABC # type: ignore
__metaclass__ = type
class PackageSpec:
def __init__(self, **kwargs):
vars(self).update(kwargs)
class TraversableResourcesAdapter:
def __init__(self, spec):
self.spec = spec
self.loader = LoaderAdapter(spec)
def __getattr__(self, name):
return getattr(self.spec, name)
class LoaderAdapter:
"""
Adapt loaders to provide TraversableResources and other
compatibility.
"""
def __init__(self, spec):
self.spec = spec
@property
def path(self):
# Python < 3
return self.spec.origin
def get_resource_reader(self, name):
# Python < 3.9
from . import readers
def _zip_reader(spec):
with suppress(AttributeError):
return readers.ZipReader(spec.loader, spec.name)
def _namespace_reader(spec):
with suppress(AttributeError, ValueError):
return readers.NamespaceReader(spec.submodule_search_locations)
def _available_reader(spec):
with suppress(AttributeError):
return spec.loader.get_resource_reader(spec.name)
def _native_reader(spec):
reader = _available_reader(spec)
return reader if hasattr(reader, 'files') else None
return (
# native reader if it supplies 'files'
_native_reader(self.spec) or
# local ZipReader if a zip module
_zip_reader(self.spec) or
# local NamespaceReader if a namespace module
_namespace_reader(self.spec) or
# local FileReader
readers.FileReader(self)
)
def package_spec(package):
"""
Construct a minimal package spec suitable for
matching the interfaces this library relies upon
in later Python versions.
"""
spec = getattr(package, '__spec__', None) or \
PackageSpec(
origin=package.__file__,
loader=getattr(package, '__loader__', None),
name=package.__name__,
submodule_search_locations=getattr(package, '__path__', None),
)
return TraversableResourcesAdapter(spec)

View File

@ -0,0 +1,107 @@
import os
import errno
from . import _common
from ._compat import FileNotFoundError
from io import BytesIO, TextIOWrapper, open as io_open
def open_binary(package, resource):
"""Return a file-like object opened for binary reading of the resource."""
resource = _common.normalize_path(resource)
package = _common.get_package(package)
# Using pathlib doesn't work well here due to the lack of 'strict' argument
# for pathlib.Path.resolve() prior to Python 3.6.
package_path = os.path.dirname(package.__file__)
relative_path = os.path.join(package_path, resource)
full_path = os.path.abspath(relative_path)
try:
return io_open(full_path, 'rb')
except IOError:
# This might be a package in a zip file. zipimport provides a loader
# with a functioning get_data() method, however we have to strip the
# archive (i.e. the .zip file's name) off the front of the path. This
# is because the zipimport loader in Python 2 doesn't actually follow
# PEP 302. It should allow the full path, but actually requires that
# the path be relative to the zip file.
try:
loader = package.__loader__
full_path = relative_path[len(loader.archive)+1:]
data = loader.get_data(full_path)
except (IOError, AttributeError):
package_name = package.__name__
message = '{!r} resource not found in {!r}'.format(
resource, package_name)
raise FileNotFoundError(message)
return BytesIO(data)
def open_text(package, resource, encoding='utf-8', errors='strict'):
"""Return a file-like object opened for text reading of the resource."""
return TextIOWrapper(
open_binary(package, resource), encoding=encoding, errors=errors)
def read_binary(package, resource):
"""Return the binary contents of the resource."""
with open_binary(package, resource) as fp:
return fp.read()
def read_text(package, resource, encoding='utf-8', errors='strict'):
"""Return the decoded string of the resource.
The decoding-related arguments have the same semantics as those of
bytes.decode().
"""
with open_text(package, resource, encoding, errors) as fp:
return fp.read()
def path(package, resource):
"""A context manager providing a file path object to the resource.
If the resource does not already exist on its own on the file system,
a temporary file will be created. If the file was created, the file
will be deleted upon exiting the context manager (no exception is
raised if the file was deleted prior to the context manager
exiting).
"""
path = _common.files(package).joinpath(_common.normalize_path(resource))
if not path.is_file():
raise FileNotFoundError(path)
return _common.as_file(path)
def is_resource(package, name):
"""True if name is a resource inside package.
Directories are *not* resources.
"""
package = _common.get_package(package)
_common.normalize_path(name)
try:
package_contents = set(contents(package))
except OSError as error:
if error.errno not in (errno.ENOENT, errno.ENOTDIR):
# We won't hit this in the Python 2 tests, so it'll appear
# uncovered. We could mock os.listdir() to return a non-ENOENT or
# ENOTDIR, but then we'd have to depend on another external
# library since Python 2 doesn't have unittest.mock. It's not
# worth it.
raise # pragma: nocover
return False
if name not in package_contents:
return False
return (_common.from_package(package) / name).is_file()
def contents(package):
"""Return an iterable of entries in `package`.
Note that not all entries are resources. Specifically, directories are
not considered resources. Use `is_resource()` on each entry returned here
to check if it is a resource or not.
"""
package = _common.get_package(package)
return list(item.name for item in _common.from_package(package).iterdir())

View File

@ -0,0 +1,160 @@
import os
import io
from . import _common
from contextlib import suppress
from importlib.abc import ResourceLoader
from io import BytesIO, TextIOWrapper
from pathlib import Path
from types import ModuleType
from typing import Iterable, Iterator, Optional, Set, Union # noqa: F401
from typing import cast
from typing.io import BinaryIO, TextIO
from collections.abc import Sequence
from functools import singledispatch
if False: # TYPE_CHECKING
from typing import ContextManager
Package = Union[ModuleType, str]
Resource = Union[str, os.PathLike]
def open_binary(package: Package, resource: Resource) -> BinaryIO:
"""Return a file-like object opened for binary reading of the resource."""
resource = _common.normalize_path(resource)
package = _common.get_package(package)
reader = _common.get_resource_reader(package)
if reader is not None:
return reader.open_resource(resource)
# Using pathlib doesn't work well here due to the lack of 'strict'
# argument for pathlib.Path.resolve() prior to Python 3.6.
if package.__spec__.submodule_search_locations is not None:
paths = package.__spec__.submodule_search_locations
elif package.__spec__.origin is not None:
paths = [os.path.dirname(os.path.abspath(package.__spec__.origin))]
for package_path in paths:
full_path = os.path.join(package_path, resource)
try:
return open(full_path, mode='rb')
except OSError:
# Just assume the loader is a resource loader; all the relevant
# importlib.machinery loaders are and an AttributeError for
# get_data() will make it clear what is needed from the loader.
loader = cast(ResourceLoader, package.__spec__.loader)
data = None
if hasattr(package.__spec__.loader, 'get_data'):
with suppress(OSError):
data = loader.get_data(full_path)
if data is not None:
return BytesIO(data)
raise FileNotFoundError('{!r} resource not found in {!r}'.format(
resource, package.__spec__.name))
def open_text(package: Package,
resource: Resource,
encoding: str = 'utf-8',
errors: str = 'strict') -> TextIO:
"""Return a file-like object opened for text reading of the resource."""
return TextIOWrapper(
open_binary(package, resource), encoding=encoding, errors=errors)
def read_binary(package: Package, resource: Resource) -> bytes:
"""Return the binary contents of the resource."""
with open_binary(package, resource) as fp:
return fp.read()
def read_text(package: Package,
resource: Resource,
encoding: str = 'utf-8',
errors: str = 'strict') -> str:
"""Return the decoded string of the resource.
The decoding-related arguments have the same semantics as those of
bytes.decode().
"""
with open_text(package, resource, encoding, errors) as fp:
return fp.read()
def path(
package: Package, resource: Resource,
) -> 'ContextManager[Path]':
"""A context manager providing a file path object to the resource.
If the resource does not already exist on its own on the file system,
a temporary file will be created. If the file was created, the file
will be deleted upon exiting the context manager (no exception is
raised if the file was deleted prior to the context manager
exiting).
"""
reader = _common.get_resource_reader(_common.get_package(package))
return (
_path_from_reader(reader, _common.normalize_path(resource))
if reader else
_common.as_file(
_common.files(package).joinpath(_common.normalize_path(resource)))
)
def _path_from_reader(reader, resource):
return _path_from_resource_path(reader, resource) or \
_path_from_open_resource(reader, resource)
def _path_from_resource_path(reader, resource):
with suppress(FileNotFoundError):
return Path(reader.resource_path(resource))
def _path_from_open_resource(reader, resource):
saved = io.BytesIO(reader.open_resource(resource).read())
return _common._tempfile(saved.read, suffix=resource)
def is_resource(package: Package, name: str) -> bool:
"""True if `name` is a resource inside `package`.
Directories are *not* resources.
"""
package = _common.get_package(package)
_common.normalize_path(name)
reader = _common.get_resource_reader(package)
if reader is not None:
return reader.is_resource(name)
package_contents = set(contents(package))
if name not in package_contents:
return False
return (_common.from_package(package) / name).is_file()
def contents(package: Package) -> Iterable[str]:
"""Return an iterable of entries in `package`.
Note that not all entries are resources. Specifically, directories are
not considered resources. Use `is_resource()` on each entry returned here
to check if it is a resource or not.
"""
package = _common.get_package(package)
reader = _common.get_resource_reader(package)
if reader is not None:
return _ensure_sequence(reader.contents())
transversable = _common.from_package(package)
if transversable.is_dir():
return list(item.name for item in transversable.iterdir())
return []
@singledispatch
def _ensure_sequence(iterable):
return list(iterable)
@_ensure_sequence.register(Sequence)
def _(iterable):
return iterable

View File

@ -0,0 +1,142 @@
from __future__ import absolute_import
import abc
from ._compat import ABC, FileNotFoundError, runtime_checkable, Protocol
# Use mypy's comment syntax for Python 2 compatibility
try:
from typing import BinaryIO, Iterable, Text
except ImportError:
pass
class ResourceReader(ABC):
"""Abstract base class for loaders to provide resource reading support."""
@abc.abstractmethod
def open_resource(self, resource):
# type: (Text) -> BinaryIO
"""Return an opened, file-like object for binary reading.
The 'resource' argument is expected to represent only a file name.
If the resource cannot be found, FileNotFoundError is raised.
"""
# This deliberately raises FileNotFoundError instead of
# NotImplementedError so that if this method is accidentally called,
# it'll still do the right thing.
raise FileNotFoundError
@abc.abstractmethod
def resource_path(self, resource):
# type: (Text) -> Text
"""Return the file system path to the specified resource.
The 'resource' argument is expected to represent only a file name.
If the resource does not exist on the file system, raise
FileNotFoundError.
"""
# This deliberately raises FileNotFoundError instead of
# NotImplementedError so that if this method is accidentally called,
# it'll still do the right thing.
raise FileNotFoundError
@abc.abstractmethod
def is_resource(self, path):
# type: (Text) -> bool
"""Return True if the named 'path' is a resource.
Files are resources, directories are not.
"""
raise FileNotFoundError
@abc.abstractmethod
def contents(self):
# type: () -> Iterable[str]
"""Return an iterable of entries in `package`."""
raise FileNotFoundError
@runtime_checkable
class Traversable(Protocol):
"""
An object with a subset of pathlib.Path methods suitable for
traversing directories and opening files.
"""
@abc.abstractmethod
def iterdir(self):
"""
Yield Traversable objects in self
"""
@abc.abstractmethod
def read_bytes(self):
"""
Read contents of self as bytes
"""
@abc.abstractmethod
def read_text(self, encoding=None):
"""
Read contents of self as bytes
"""
@abc.abstractmethod
def is_dir(self):
"""
Return True if self is a dir
"""
@abc.abstractmethod
def is_file(self):
"""
Return True if self is a file
"""
@abc.abstractmethod
def joinpath(self, child):
"""
Return Traversable child in self
"""
@abc.abstractmethod
def __truediv__(self, child):
"""
Return Traversable child in self
"""
@abc.abstractmethod
def open(self, mode='r', *args, **kwargs):
"""
mode may be 'r' or 'rb' to open as text or binary. Return a handle
suitable for reading (same as pathlib.Path.open).
When opening as text, accepts encoding parameters such as those
accepted by io.TextIOWrapper.
"""
@abc.abstractproperty
def name(self):
# type: () -> str
"""
The base name of this object without any parent references.
"""
class TraversableResources(ResourceReader):
@abc.abstractmethod
def files(self):
"""Return a Traversable object for the loaded package."""
def open_resource(self, resource):
return self.files().joinpath(resource).open('rb')
def resource_path(self, resource):
raise FileNotFoundError(resource)
def is_resource(self, path):
return self.files().joinpath(path).is_file()
def contents(self):
return (item.name for item in self.files().iterdir())

View File

@ -0,0 +1,123 @@
import os.path
from collections import OrderedDict
from . import abc
from ._compat import Path, ZipPath
from ._compat import FileNotFoundError, NotADirectoryError
class FileReader(abc.TraversableResources):
def __init__(self, loader):
self.path = Path(loader.path).parent
def resource_path(self, resource):
"""
Return the file system path to prevent
`resources.path()` from creating a temporary
copy.
"""
return str(self.path.joinpath(resource))
def files(self):
return self.path
class ZipReader(abc.TraversableResources):
def __init__(self, loader, module):
_, _, name = module.rpartition('.')
self.prefix = loader.prefix.replace('\\', '/') + name + '/'
self.archive = loader.archive
def open_resource(self, resource):
try:
return super().open_resource(resource)
except KeyError as exc:
raise FileNotFoundError(exc.args[0])
def is_resource(self, path):
# workaround for `zipfile.Path.is_file` returning true
# for non-existent paths.
target = self.files().joinpath(path)
return target.is_file() and target.exists()
def files(self):
return ZipPath(self.archive, self.prefix)
class MultiplexedPath(abc.Traversable):
"""
Given a series of Traversable objects, implement a merged
version of the interface across all objects. Useful for
namespace packages which may be multihomed at a single
name.
"""
def __init__(self, *paths):
paths = list(OrderedDict.fromkeys(paths)) # remove duplicates
self._paths = list(map(Path, paths))
if not self._paths:
message = 'MultiplexedPath must contain at least one path'
raise FileNotFoundError(message)
if any(not path.is_dir() for path in self._paths):
raise NotADirectoryError(
'MultiplexedPath only supports directories')
def iterdir(self):
visited = []
for path in self._paths:
for file in path.iterdir():
if file.name in visited:
continue
visited.append(file.name)
yield file
def read_bytes(self):
raise FileNotFoundError('{} is not a file'.format(self))
def read_text(self, *args, **kwargs):
raise FileNotFoundError('{} is not a file'.format(self))
def is_dir(self):
return True
def is_file(self):
return False
def joinpath(self, child):
# first try to find child in current paths
for file in self.iterdir():
if file.name == child:
return file
# if it does not exist, construct it with the first path
return self._paths[0] / child
__truediv__ = joinpath
def open(self, *args, **kwargs):
raise FileNotFoundError('{} is not a file'.format(self))
def name(self):
return os.path.basename(self._paths[0])
def __repr__(self):
return 'MultiplexedPath({})'.format(
', '.join("'{}'".format(path) for path in self._paths))
class NamespaceReader(abc.TraversableResources):
def __init__(self, namespace_path):
if 'NamespacePath' not in str(namespace_path):
raise ValueError('Invalid path')
self.path = MultiplexedPath(*list(namespace_path))
def resource_path(self, resource):
"""
Return the file system path to prevent
`resources.path()` from creating a temporary
copy.
"""
return str(self.path.joinpath(resource))
def files(self):
return self.path

View File

@ -0,0 +1,6 @@
# for compatibility with 1.1, continue to expose as_file here.
from ._common import as_file
__all__ = ['as_file']

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.34.2)
Root-Is-Purelib: false
Tag: cp38-cp38-macosx_10_15_x86_64

View File

@ -1,7 +1,6 @@
_scandir.cpython-38-darwin.so,sha256=3a2UitVjb1MS0I7WSOp7jPGHsKf-ctNYTrBvDmPupOg,27780
scandir.py,sha256=97C2AQInuKk-Phb3aXM7fJomhc-00pZMcBur23NUmrE,24827
scandir-1.10.0.dist-info/LICENSE.txt,sha256=peL73COXREGdKUB828knk8TZwdlWwXT3y3-W-m0FjIY,1464
scandir-1.10.0.dist-info/METADATA,sha256=cv1fZ5DeC3DJqnMByWGiprvGhLpQCkWOZiJduweakGk,9559
scandir-1.10.0.dist-info/WHEEL,sha256=NqgkTkAaRJaCuArPZklUp2tBwn6obHN9aMIfdfLfNkU,110
scandir-1.10.0.dist-info/WHEEL,sha256=WO4o60shExe_A5pkiO6Yb-8OHLGhlAGcs2oJ7aUuE5Q,110
scandir-1.10.0.dist-info/top_level.txt,sha256=Ixze5mNjmis99ql7JEtAYc9-djJMbfRx-FFw3R_zZf8,17
scandir-1.10.0.dist-info/RECORD,,

View File

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.35.1)
Root-Is-Purelib: false
Tag: cp39-cp39-macosx_10_15_x86_64

View File

@ -1,6 +0,0 @@
zipp.py,sha256=o8W25XfoR5DD_krEQLbYrNMmK-x26JvaqeKuboC91YY,7121
zipp-3.1.0.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050
zipp-3.1.0.dist-info/METADATA,sha256=EbCdCb8ZzwzYDA7RF8R830VeruipjOKnj32zpMxPsFM,1899
zipp-3.1.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
zipp-3.1.0.dist-info/top_level.txt,sha256=iAbdoSHfaGqBfVb2XuR9JqSQHCoOsOtG6y9C_LSpqFw,5
zipp-3.1.0.dist-info/RECORD,,

View File

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: zipp
Version: 3.1.0
Version: 3.4.0
Summary: Backport of pathlib-compatible object wrapper for zip files
Home-page: https://github.com/jaraco/zipp
Author: Jason R. Coombs
@ -18,8 +18,15 @@ Requires-Dist: sphinx ; extra == 'docs'
Requires-Dist: jaraco.packaging (>=3.2) ; extra == 'docs'
Requires-Dist: rst.linker (>=1.9) ; extra == 'docs'
Provides-Extra: testing
Requires-Dist: pytest (!=3.7.3,>=3.5) ; extra == 'testing'
Requires-Dist: pytest-checkdocs (>=1.2.3) ; extra == 'testing'
Requires-Dist: pytest-flake8 ; extra == 'testing'
Requires-Dist: pytest-cov ; extra == 'testing'
Requires-Dist: jaraco.test (>=3.2.0) ; extra == 'testing'
Requires-Dist: jaraco.itertools ; extra == 'testing'
Requires-Dist: func-timeout ; extra == 'testing'
Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing'
Requires-Dist: pytest-mypy ; (platform_python_implementation != "PyPy") and extra == 'testing'
.. image:: https://img.shields.io/pypi/v/zipp.svg
:target: `PyPI link`_
@ -29,19 +36,14 @@ Requires-Dist: func-timeout ; extra == 'testing'
.. _PyPI link: https://pypi.org/project/zipp
.. image:: https://dev.azure.com/jaraco/zipp/_apis/build/status/jaraco.zipp?branchName=master
:target: https://dev.azure.com/jaraco/zipp/_build/latest?definitionId=1&branchName=master
.. image:: https://img.shields.io/travis/jaraco/zipp/master.svg
:target: https://travis-ci.org/jaraco/zipp
.. image:: https://github.com/jaraco/zipp/workflows/Automated%20Tests/badge.svg
:target: https://github.com/jaraco/zipp/actions?query=workflow%3A%22Automated+Tests%22
:alt: Automated Tests
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
:alt: Code style: Black
.. image:: https://img.shields.io/appveyor/ci/jaraco/zipp/master.svg
:target: https://ci.appveyor.com/project/jaraco/zipp/branch/master
.. .. image:: https://readthedocs.org/projects/zipp/badge/?version=latest
.. :target: https://zipp.readthedocs.io/en/latest/?badge=latest

View File

@ -0,0 +1,6 @@
zipp.py,sha256=wMSoYxAIPgYnqJAW0JcAl5sWaIcFc5xk3dNjf6ElGgU,8089
zipp-3.4.0.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050
zipp-3.4.0.dist-info/METADATA,sha256=noSfks-ReGCmOSTxll7TELBJy0P_yAvVLa0FCFyhMeM,2134
zipp-3.4.0.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92
zipp-3.4.0.dist-info/top_level.txt,sha256=iAbdoSHfaGqBfVb2XuR9JqSQHCoOsOtG6y9C_LSpqFw,5
zipp-3.4.0.dist-info/RECORD,,

View File

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.35.1)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -4,6 +4,7 @@ import zipfile
import itertools
import contextlib
import sys
import pathlib
if sys.version_info < (3, 7):
from collections import OrderedDict
@ -105,13 +106,12 @@ class CompleteDirs(zipfile.ZipFile):
if not isinstance(source, zipfile.ZipFile):
return cls(_pathlib_compat(source))
# Only allow for FastPath when supplied zipfile is read-only
# Only allow for FastLookup when supplied zipfile is read-only
if 'r' not in source.mode:
cls = CompleteDirs
res = cls.__new__(cls)
vars(res).update(vars(source))
return res
source.__class__ = cls
return source
class FastLookup(CompleteDirs):
@ -119,6 +119,7 @@ class FastLookup(CompleteDirs):
ZipFile subclass to ensure implicit
dirs exist and are resolved rapidly.
"""
def namelist(self):
with contextlib.suppress(AttributeError):
return self.__names
@ -161,7 +162,7 @@ class Path:
>>> zf.writestr('a.txt', 'content of a')
>>> zf.writestr('b/c.txt', 'content of c')
>>> zf.writestr('b/d/e.txt', 'content of e')
>>> zf.filename = 'abcde.zip'
>>> zf.filename = 'mem/abcde.zip'
Path accepts the zipfile object itself or a filename
@ -173,9 +174,9 @@ class Path:
>>> a, b = root.iterdir()
>>> a
Path('abcde.zip', 'a.txt')
Path('mem/abcde.zip', 'a.txt')
>>> b
Path('abcde.zip', 'b/')
Path('mem/abcde.zip', 'b/')
name property:
@ -186,7 +187,7 @@ class Path:
>>> c = b / 'c.txt'
>>> c
Path('abcde.zip', 'b/c.txt')
Path('mem/abcde.zip', 'b/c.txt')
>>> c.name
'c.txt'
@ -204,13 +205,35 @@ class Path:
Coercion to string:
>>> str(c)
'abcde.zip/b/c.txt'
>>> import os
>>> str(c).replace(os.sep, posixpath.sep)
'mem/abcde.zip/b/c.txt'
At the root, ``name``, ``filename``, and ``parent``
resolve to the zipfile. Note these attributes are not
valid and will raise a ``ValueError`` if the zipfile
has no filename.
>>> root.name
'abcde.zip'
>>> str(root.filename).replace(os.sep, posixpath.sep)
'mem/abcde.zip'
>>> str(root.parent)
'mem'
"""
__repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})"
def __init__(self, root, at=""):
"""
Construct a Path from a ZipFile or filename.
Note: When the source is an existing ZipFile object,
its type (__class__) will be mutated to a
specialized type. If the caller wishes to retain the
original type, the caller should either create a
separate ZipFile object or pass a filename.
"""
self.root = FastLookup.make(root)
self.at = at
@ -234,7 +257,11 @@ class Path:
@property
def name(self):
return posixpath.basename(self.at.rstrip("/"))
return pathlib.Path(self.at).name or self.filename.name
@property
def filename(self):
return pathlib.Path(self.root.filename).joinpath(self.at)
def read_text(self, *args, **kwargs):
with self.open('r', *args, **kwargs) as strm:
@ -248,13 +275,13 @@ class Path:
return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/")
def _next(self, at):
return Path(self.root, at)
return self.__class__(self.root, at)
def is_dir(self):
return not self.at or self.at.endswith("/")
def is_file(self):
return not self.is_dir()
return self.exists() and not self.is_dir()
def exists(self):
return self.at in self.root._name_set()
@ -271,14 +298,16 @@ class Path:
def __repr__(self):
return self.__repr.format(self=self)
def joinpath(self, add):
next = posixpath.join(self.at, _pathlib_compat(add))
def joinpath(self, *other):
next = posixpath.join(self.at, *map(_pathlib_compat, other))
return self._next(self.root.resolve_dir(next))
__truediv__ = joinpath
@property
def parent(self):
if not self.at:
return self.filename.parent
parent_at = posixpath.dirname(self.at.rstrip('/'))
if parent_at:
parent_at += '/'

View File

@ -21,8 +21,8 @@
"distlib": "__virtualenv__/distlib-0.3.1-py2.py3-none-any/distlib-0.3.1.dist-info",
"filelock": "__virtualenv__/filelock-3.0.12-py3-none-any/filelock-3.0.12.dist-info",
"six": "__virtualenv__/six-1.15.0-py2.py3-none-any/six-1.15.0.dist-info",
"importlib_metadata": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata-1.7.0.dist-info",
"zipp": "__virtualenv__/zipp-3.1.0-py3-none-any/zipp-3.1.0.dist-info"
"importlib_metadata": "__virtualenv__/importlib_metadata-3.1.1-py3-none-any/importlib_metadata-3.1.1.dist-info",
"zipp": "__virtualenv__/zipp-3.4.0-py3-none-any/zipp-3.4.0.dist-info"
}
},
"3.6": {
@ -31,9 +31,9 @@
"distlib": "__virtualenv__/distlib-0.3.1-py2.py3-none-any/distlib-0.3.1.dist-info",
"filelock": "__virtualenv__/filelock-3.0.12-py3-none-any/filelock-3.0.12.dist-info",
"six": "__virtualenv__/six-1.15.0-py2.py3-none-any/six-1.15.0.dist-info",
"importlib_metadata": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata-1.7.0.dist-info",
"zipp": "__virtualenv__/zipp-3.1.0-py3-none-any/zipp-3.1.0.dist-info",
"importlib_resources": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources-3.0.0.dist-info"
"importlib_metadata": "__virtualenv__/importlib_metadata-3.1.1-py3-none-any/importlib_metadata-3.1.1.dist-info",
"zipp": "__virtualenv__/zipp-3.4.0-py3-none-any/zipp-3.4.0.dist-info",
"importlib_resources": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources-3.3.0.dist-info"
}
},
"3.5": {
@ -42,9 +42,9 @@
"distlib": "__virtualenv__/distlib-0.3.1-py2.py3-none-any/distlib-0.3.1.dist-info",
"filelock": "__virtualenv__/filelock-3.0.12-py3-none-any/filelock-3.0.12.dist-info",
"six": "__virtualenv__/six-1.15.0-py2.py3-none-any/six-1.15.0.dist-info",
"importlib_metadata": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata-1.7.0.dist-info",
"importlib_metadata": "__virtualenv__/importlib_metadata-2.1.1-py2.py3-none-any/importlib_metadata-2.1.1.dist-info",
"zipp": "__virtualenv__/zipp-1.2.0-py2.py3-none-any/zipp-1.2.0.dist-info",
"importlib_resources": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources-3.0.0.dist-info"
"importlib_resources": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources-3.2.1.dist-info"
}
},
"3.4": {
@ -58,7 +58,7 @@
"importlib_resources": "__virtualenv__/importlib_resources-1.0.2-py2.py3-none-any/importlib_resources-1.0.2.dist-info",
"typing": "__virtualenv__/typing-3.7.4.1-py3-none-any/typing-3.7.4.1.dist-info",
"pathlib2": "__virtualenv__/pathlib2-2.3.5-py2.py3-none-any/pathlib2-2.3.5.dist-info",
"scandir": "__virtualenv__/scandir-1.10.0-cp38-cp38-macosx_10_15_x86_64/scandir-1.10.0.dist-info"
"scandir": "__virtualenv__/scandir-1.10.0-cp39-cp39-macosx_10_15_x86_64/scandir-1.10.0.dist-info"
}
},
"2.7": {
@ -72,7 +72,7 @@
"importlib_resources": "__virtualenv__/importlib_resources-1.0.2-py2.py3-none-any/importlib_resources-1.0.2.dist-info",
"typing": "__virtualenv__/typing-3.7.4.3-py2-none-any/typing-3.7.4.3.dist-info",
"pathlib2": "__virtualenv__/pathlib2-2.3.5-py2.py3-none-any/pathlib2-2.3.5.dist-info",
"scandir": "__virtualenv__/scandir-1.10.0-cp38-cp38-macosx_10_15_x86_64/scandir-1.10.0.dist-info",
"scandir": "__virtualenv__/scandir-1.10.0-cp39-cp39-macosx_10_15_x86_64/scandir-1.10.0.dist-info",
"contextlib2": "__virtualenv__/contextlib2-0.6.0.post1-py2.py3-none-any/contextlib2-0.6.0.post1.dist-info",
"configparser": "__virtualenv__/configparser-4.0.2-py2.py3-none-any/configparser-4.0.2.dist-info"
},

View File

@ -72,18 +72,9 @@
"distlib._backport.tarfile": "__virtualenv__/distlib-0.3.1-py2.py3-none-any/distlib/_backport/tarfile.py",
"filelock": "__virtualenv__/filelock-3.0.12-py3-none-any/filelock.py",
"six": "__virtualenv__/six-1.15.0-py2.py3-none-any/six.py",
"importlib_metadata": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/__init__.py",
"importlib_metadata._compat": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/_compat.py",
"importlib_metadata.docs": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/docs/__init__.py",
"importlib_metadata.docs.conf": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/docs/conf.py",
"importlib_metadata.tests": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/__init__.py",
"importlib_metadata.tests.fixtures": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/fixtures.py",
"importlib_metadata.tests.test_api": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_api.py",
"importlib_metadata.tests.test_integration": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_integration.py",
"importlib_metadata.tests.test_main": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_main.py",
"importlib_metadata.tests.test_zip": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_zip.py",
"importlib_metadata.tests.data": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/data/__init__.py",
"zipp": "__virtualenv__/zipp-3.1.0-py3-none-any/zipp.py"
"importlib_metadata": "__virtualenv__/importlib_metadata-3.1.1-py3-none-any/importlib_metadata/__init__.py",
"importlib_metadata._compat": "__virtualenv__/importlib_metadata-3.1.1-py3-none-any/importlib_metadata/_compat.py",
"zipp": "__virtualenv__/zipp-3.4.0-py3-none-any/zipp.py"
}
},
"3.6": {
@ -109,43 +100,34 @@
"distlib._backport.tarfile": "__virtualenv__/distlib-0.3.1-py2.py3-none-any/distlib/_backport/tarfile.py",
"filelock": "__virtualenv__/filelock-3.0.12-py3-none-any/filelock.py",
"six": "__virtualenv__/six-1.15.0-py2.py3-none-any/six.py",
"importlib_metadata": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/__init__.py",
"importlib_metadata._compat": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/_compat.py",
"importlib_metadata.docs": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/docs/__init__.py",
"importlib_metadata.docs.conf": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/docs/conf.py",
"importlib_metadata.tests": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/__init__.py",
"importlib_metadata.tests.fixtures": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/fixtures.py",
"importlib_metadata.tests.test_api": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_api.py",
"importlib_metadata.tests.test_integration": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_integration.py",
"importlib_metadata.tests.test_main": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_main.py",
"importlib_metadata.tests.test_zip": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_zip.py",
"importlib_metadata.tests.data": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/data/__init__.py",
"zipp": "__virtualenv__/zipp-3.1.0-py3-none-any/zipp.py",
"importlib_resources": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/__init__.py",
"importlib_resources._common": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_common.py",
"importlib_resources._compat": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_compat.py",
"importlib_resources._py2": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_py2.py",
"importlib_resources._py3": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_py3.py",
"importlib_resources.abc": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/abc.py",
"importlib_resources.readers": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/readers.py",
"importlib_resources.trees": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/trees.py",
"importlib_resources.tests": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/__init__.py",
"importlib_resources.tests.test_files": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_files.py",
"importlib_resources.tests.test_open": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_open.py",
"importlib_resources.tests.test_path": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_path.py",
"importlib_resources.tests.test_read": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_read.py",
"importlib_resources.tests.test_resource": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_resource.py",
"importlib_resources.tests.util": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/util.py",
"importlib_resources.tests.data01": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data01/__init__.py",
"importlib_resources.tests.data01.subdirectory": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data01/subdirectory/__init__.py",
"importlib_resources.tests.data02": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data02/__init__.py",
"importlib_resources.tests.data02.one": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data02/one/__init__.py",
"importlib_resources.tests.data02.two": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data02/two/__init__.py",
"importlib_resources.tests.data03": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data03/__init__.py",
"importlib_resources.tests.data03.namespace.portion1": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data03/namespace/portion1/__init__.py",
"importlib_resources.tests.data03.namespace.portion2": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data03/namespace/portion2/__init__.py",
"importlib_resources.tests.zipdata01": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/zipdata01/__init__.py",
"importlib_resources.tests.zipdata02": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/zipdata02/__init__.py"
"importlib_metadata": "__virtualenv__/importlib_metadata-3.1.1-py3-none-any/importlib_metadata/__init__.py",
"importlib_metadata._compat": "__virtualenv__/importlib_metadata-3.1.1-py3-none-any/importlib_metadata/_compat.py",
"zipp": "__virtualenv__/zipp-3.4.0-py3-none-any/zipp.py",
"importlib_resources": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/__init__.py",
"importlib_resources._common": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/_common.py",
"importlib_resources._compat": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/_compat.py",
"importlib_resources._py2": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/_py2.py",
"importlib_resources._py3": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/_py3.py",
"importlib_resources.abc": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/abc.py",
"importlib_resources.readers": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/readers.py",
"importlib_resources.trees": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/trees.py",
"importlib_resources.tests": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/__init__.py",
"importlib_resources.tests._compat": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/_compat.py",
"importlib_resources.tests.py27compat": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/py27compat.py",
"importlib_resources.tests.test_files": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/test_files.py",
"importlib_resources.tests.test_open": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/test_open.py",
"importlib_resources.tests.test_path": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/test_path.py",
"importlib_resources.tests.test_read": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/test_read.py",
"importlib_resources.tests.test_reader": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/test_reader.py",
"importlib_resources.tests.test_resource": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/test_resource.py",
"importlib_resources.tests.util": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/util.py",
"importlib_resources.tests.data01": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/data01/__init__.py",
"importlib_resources.tests.data01.subdirectory": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/data01/subdirectory/__init__.py",
"importlib_resources.tests.data02": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/data02/__init__.py",
"importlib_resources.tests.data02.one": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/data02/one/__init__.py",
"importlib_resources.tests.data02.two": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/data02/two/__init__.py",
"importlib_resources.tests.zipdata01": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/zipdata01/__init__.py",
"importlib_resources.tests.zipdata02": "__virtualenv__/importlib_resources-3.3.0-py2.py3-none-any/importlib_resources/tests/zipdata02/__init__.py"
}
},
"3.5": {
@ -171,43 +153,34 @@
"distlib._backport.tarfile": "__virtualenv__/distlib-0.3.1-py2.py3-none-any/distlib/_backport/tarfile.py",
"filelock": "__virtualenv__/filelock-3.0.12-py3-none-any/filelock.py",
"six": "__virtualenv__/six-1.15.0-py2.py3-none-any/six.py",
"importlib_metadata": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/__init__.py",
"importlib_metadata._compat": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/_compat.py",
"importlib_metadata.docs": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/docs/__init__.py",
"importlib_metadata.docs.conf": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/docs/conf.py",
"importlib_metadata.tests": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/__init__.py",
"importlib_metadata.tests.fixtures": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/fixtures.py",
"importlib_metadata.tests.test_api": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_api.py",
"importlib_metadata.tests.test_integration": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_integration.py",
"importlib_metadata.tests.test_main": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_main.py",
"importlib_metadata.tests.test_zip": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/test_zip.py",
"importlib_metadata.tests.data": "__virtualenv__/importlib_metadata-1.7.0-py2.py3-none-any/importlib_metadata/tests/data/__init__.py",
"importlib_metadata": "__virtualenv__/importlib_metadata-2.1.1-py2.py3-none-any/importlib_metadata/__init__.py",
"importlib_metadata._compat": "__virtualenv__/importlib_metadata-2.1.1-py2.py3-none-any/importlib_metadata/_compat.py",
"zipp": "__virtualenv__/zipp-1.2.0-py2.py3-none-any/zipp.py",
"importlib_resources": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/__init__.py",
"importlib_resources._common": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_common.py",
"importlib_resources._compat": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_compat.py",
"importlib_resources._py2": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_py2.py",
"importlib_resources._py3": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/_py3.py",
"importlib_resources.abc": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/abc.py",
"importlib_resources.readers": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/readers.py",
"importlib_resources.trees": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/trees.py",
"importlib_resources.tests": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/__init__.py",
"importlib_resources.tests.test_files": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_files.py",
"importlib_resources.tests.test_open": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_open.py",
"importlib_resources.tests.test_path": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_path.py",
"importlib_resources.tests.test_read": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_read.py",
"importlib_resources.tests.test_resource": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/test_resource.py",
"importlib_resources.tests.util": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/util.py",
"importlib_resources.tests.data01": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data01/__init__.py",
"importlib_resources.tests.data01.subdirectory": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data01/subdirectory/__init__.py",
"importlib_resources.tests.data02": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data02/__init__.py",
"importlib_resources.tests.data02.one": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data02/one/__init__.py",
"importlib_resources.tests.data02.two": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data02/two/__init__.py",
"importlib_resources.tests.data03": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data03/__init__.py",
"importlib_resources.tests.data03.namespace.portion1": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data03/namespace/portion1/__init__.py",
"importlib_resources.tests.data03.namespace.portion2": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/data03/namespace/portion2/__init__.py",
"importlib_resources.tests.zipdata01": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/zipdata01/__init__.py",
"importlib_resources.tests.zipdata02": "__virtualenv__/importlib_resources-3.0.0-py2.py3-none-any/importlib_resources/tests/zipdata02/__init__.py"
"importlib_resources": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/__init__.py",
"importlib_resources._common": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/_common.py",
"importlib_resources._compat": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/_compat.py",
"importlib_resources._py2": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/_py2.py",
"importlib_resources._py3": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/_py3.py",
"importlib_resources.abc": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/abc.py",
"importlib_resources.readers": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/readers.py",
"importlib_resources.trees": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/trees.py",
"importlib_resources.tests": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/__init__.py",
"importlib_resources.tests._compat": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/_compat.py",
"importlib_resources.tests.py27compat": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/py27compat.py",
"importlib_resources.tests.test_files": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/test_files.py",
"importlib_resources.tests.test_open": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/test_open.py",
"importlib_resources.tests.test_path": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/test_path.py",
"importlib_resources.tests.test_read": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/test_read.py",
"importlib_resources.tests.test_reader": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/test_reader.py",
"importlib_resources.tests.test_resource": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/test_resource.py",
"importlib_resources.tests.util": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/util.py",
"importlib_resources.tests.data01": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/data01/__init__.py",
"importlib_resources.tests.data01.subdirectory": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/data01/subdirectory/__init__.py",
"importlib_resources.tests.data02": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/data02/__init__.py",
"importlib_resources.tests.data02.one": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/data02/one/__init__.py",
"importlib_resources.tests.data02.two": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/data02/two/__init__.py",
"importlib_resources.tests.zipdata01": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/zipdata01/__init__.py",
"importlib_resources.tests.zipdata02": "__virtualenv__/importlib_resources-3.2.1-py2.py3-none-any/importlib_resources/tests/zipdata02/__init__.py"
}
},
"3.4": {
@ -267,7 +240,7 @@
"importlib_resources.tests.zipdata02": "__virtualenv__/importlib_resources-1.0.2-py2.py3-none-any/importlib_resources/tests/zipdata02/__init__.py",
"typing": "__virtualenv__/typing-3.7.4.1-py3-none-any/typing.py",
"pathlib2": "__virtualenv__/pathlib2-2.3.5-py2.py3-none-any/pathlib2/__init__.py",
"scandir": "__virtualenv__/scandir-1.10.0-cp38-cp38-macosx_10_15_x86_64/scandir.py"
"scandir": "__virtualenv__/scandir-1.10.0-cp39-cp39-macosx_10_15_x86_64/scandir.py"
}
},
"2.7": {
@ -327,7 +300,7 @@
"importlib_resources.tests.zipdata02": "__virtualenv__/importlib_resources-1.0.2-py2.py3-none-any/importlib_resources/tests/zipdata02/__init__.py",
"typing": "__virtualenv__/typing-3.7.4.3-py2-none-any/typing.py",
"pathlib2": "__virtualenv__/pathlib2-2.3.5-py2.py3-none-any/pathlib2/__init__.py",
"scandir": "__virtualenv__/scandir-1.10.0-cp38-cp38-macosx_10_15_x86_64/scandir.py",
"scandir": "__virtualenv__/scandir-1.10.0-cp39-cp39-macosx_10_15_x86_64/scandir.py",
"contextlib2": "__virtualenv__/contextlib2-0.6.0.post1-py2.py3-none-any/contextlib2.py",
"configparser": "__virtualenv__/configparser-4.0.2-py2.py3-none-any/configparser.py",
"backports": "__virtualenv__/configparser-4.0.2-py2.py3-none-any/backports/__init__.py",

View File

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: virtualenv
Version: 20.0.31
Version: 20.2.2
Summary: Virtual Python Environment builder
Home-page: https://virtualenv.pypa.io/
Author: Bernat Gabor
@ -26,6 +26,7 @@ Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries
@ -39,7 +40,7 @@ Requires-Dist: filelock (<4,>=3.0.0)
Requires-Dist: six (<2,>=1.9.0)
Requires-Dist: pathlib2 (<3,>=2.3.3) ; python_version < "3.4" and sys_platform != "win32"
Requires-Dist: importlib-resources (>=1.0) ; python_version < "3.7"
Requires-Dist: importlib-metadata (<2,>=0.12) ; python_version < "3.8"
Requires-Dist: importlib-metadata (>=0.12) ; python_version < "3.8"
Provides-Extra: docs
Requires-Dist: proselint (>=0.10.2) ; extra == 'docs'
Requires-Dist: sphinx (>=3) ; extra == 'docs'
@ -47,7 +48,7 @@ Requires-Dist: sphinx-argparse (>=0.2.5) ; extra == 'docs'
Requires-Dist: sphinx-rtd-theme (>=0.4.3) ; extra == 'docs'
Requires-Dist: towncrier (>=19.9.0rc1) ; extra == 'docs'
Provides-Extra: testing
Requires-Dist: coverage (>=5) ; extra == 'testing'
Requires-Dist: coverage (>=4) ; extra == 'testing'
Requires-Dist: coverage-enable-subprocess (>=1) ; extra == 'testing'
Requires-Dist: flaky (>=3) ; extra == 'testing'
Requires-Dist: pytest (>=4) ; extra == 'testing'
@ -69,8 +70,8 @@ Requires-Dist: xonsh (>=0.9.16) ; (python_version > "3.4" and python_version !=
[![Gitter Chat](https://img.shields.io/gitter/room/pypa/virtualenv?color=FF004F&style=flat-square)](https://gitter.im/pypa/virtualenv)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/virtualenv?style=flat-square)](https://pypistats.org/packages/virtualenv)
[![PyPI - License](https://img.shields.io/pypi/l/virtualenv?style=flat-square)](https://opensource.org/licenses/MIT)
[![Build Status](https://github.com/pypa/virtualenv/workflows/check/badge.svg?branch=master&event=push)](https://github.com/pypa/virtualenv/actions?query=workflow%3Acheck)
[![codecov](https://codecov.io/gh/pypa/virtualenv/branch/master/graph/badge.svg)](https://codecov.io/gh/pypa/virtualenv)
[![Build Status](https://github.com/pypa/virtualenv/workflows/check/badge.svg?branch=main&event=push)](https://github.com/pypa/virtualenv/actions?query=workflow%3Acheck)
[![codecov](https://codecov.io/gh/pypa/virtualenv/branch/main/graph/badge.svg)](https://codecov.io/gh/pypa/virtualenv)
[![Code style:
black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square)](https://github.com/psf/black)

View File

@ -2,12 +2,12 @@ virtualenv/__init__.py,sha256=SMvpjz4VJ3vJ_yfDDPzJAdi2GJOYd_UBXXuvImO07gk,205
virtualenv/__main__.py,sha256=QMwDqrR4QbhEivl8yoRmAr6G1BY92gr4n1ConcDIxc4,2770
virtualenv/info.py,sha256=-2pI_kyC9fNj5OR8AQWkKjlpOk4_96Lmbco3atYYBdY,1921
virtualenv/report.py,sha256=M2OHHCWdOHZsn74tj1MYYKmaI3QRJF8VA1FZIdkQTMQ,1594
virtualenv/version.py,sha256=3ieAw0XY11zpShwBdavzQZAO60AeVi5FVy0KWrcxwUY,66
virtualenv/version.py,sha256=T9L0FIrWWe1IEvi_PNtZQcEIf_WbHAtFeLA1_hwZ07I,65
virtualenv/activation/__init__.py,sha256=jLIERxJXMnHq2fH49RdWqBoaiASres4CTKMdUJOeos0,480
virtualenv/activation/activator.py,sha256=CXomkRvhzcAeygYlDwQdDjfPyZQG85aBab5GIVQPv2M,1341
virtualenv/activation/via_template.py,sha256=B88RGc0qoGc46DmKJmLJuzcCJU_iXWhdD93r6KLuYHQ,2204
virtualenv/activation/via_template.py,sha256=U8LgH-lyTjXIQBUdbd0xOZpXNICpiKhsfpiZwzQg7tU,2372
virtualenv/activation/bash/__init__.py,sha256=7aC1WfvyzgFrIQs13jOuESuAbuiAnTsKkOe0iReRoaE,312
virtualenv/activation/bash/activate.sh,sha256=xkIDykLyI5CO3K7eeAujgPiBP2eleYDTFsqhaXsOUG4,2249
virtualenv/activation/bash/activate.sh,sha256=aHia5vyXg2JwymkvRXCp29Aswcg88Mz5UrssXbX9Jjc,2398
virtualenv/activation/batch/__init__.py,sha256=K0gVfwuXV7uoaMDL7moWGCq7uTDzI64giZzQQ8s2qnU,733
virtualenv/activation/batch/activate.bat,sha256=PeQnWWsjvHT-jIWhYI7hbdzkDBZx5UOstnsCmq5PYtw,1031
virtualenv/activation/batch/deactivate.bat,sha256=6OznnO-HC2wnWUN7YAT-bj815zeKMXEPC0keyBYwKUU,510
@ -17,104 +17,106 @@ virtualenv/activation/cshell/activate.csh,sha256=jYwms8OTiVu9MJwXltuEm43HU09BJUq
virtualenv/activation/fish/__init__.py,sha256=hDkJq1P1wK2qm6BXydXWA9GMkBpj-TaejbKSceFnGZU,251
virtualenv/activation/fish/activate.fish,sha256=V7nVwSI_nsFEMlJjSQxCayNWkjubXi1KSgSw1bEakh8,3099
virtualenv/activation/powershell/__init__.py,sha256=EA-73s5TUMkgxAhLwucFg3gsBwW5huNh7qB4I7uEU-U,256
virtualenv/activation/powershell/activate.ps1,sha256=qXTD2IZIPXIr3HZbNahnym8l3FFwa1o_pyB8cSmxeg0,1867
virtualenv/activation/powershell/activate.ps1,sha256=jVw_FwfVJzcByQ3Sku-wlnOo_a0-OSpAQ8R17kXVgIM,1807
virtualenv/activation/python/__init__.py,sha256=Uv53LqOrIT_2dO1FXcUYAnwH1eypG8CJ2InhSx1GRI4,1323
virtualenv/activation/python/activate_this.py,sha256=Xpz7exdGSjmWk0KfwHLofIpDPUtazNSNGrxT0-5ZG_s,1208
virtualenv/activation/xonsh/__init__.py,sha256=7NUevd5EpHRMZdSyR1KgFTe9QQBO94zZOwFH6MR6zjo,355
virtualenv/activation/xonsh/activate.xsh,sha256=qkKgWfrUjYKrgrmhf45VuBz99EMadtiNU8GMfHZZ7AU,1172
virtualenv/app_data/__init__.py,sha256=mOgHrNxZ320NcDvl2EU9Uhaq9XSwnJwkldKAWtrMCKo,1882
virtualenv/app_data/base.py,sha256=wtoduyV2lc020XNdOwt5gu1lkUJd0n_LMrgT8nifAwo,2054
virtualenv/app_data/na.py,sha256=fCISMfJt3opkAqCmJBZTW9tody6ECfVPXtSrY5ZJueY,1321
virtualenv/app_data/via_disk_folder.py,sha256=bJxZIXTAqQekwRZuoYgAE1fvwQ6w1dBR2IJFe09OIjE,5404
virtualenv/app_data/via_tempdir.py,sha256=vt4I1wAaNouOeFSTFX5DPbA3zPZ1ikVGzXBDsNLNHRM,771
virtualenv/app_data/__init__.py,sha256=nwgqY-Our_SYcDisLfRLmWrTSPytDkjck9-lzg-pOI8,1462
virtualenv/app_data/base.py,sha256=dbS5Maob1-Cqs6EVqTmmbjAGeNYA1iw3pmdgYPWCJak,2129
virtualenv/app_data/na.py,sha256=iMRVpCe4m5Q5WM5bC3ee1wYyfkfHvkcQ-8tgIw4druc,1306
virtualenv/app_data/read_only.py,sha256=MD-4Bl2SZZiGw0g8qZy0YLBGZGCuFYXnAEvWboF1PSc,1006
virtualenv/app_data/via_disk_folder.py,sha256=CdNXQkenyH178MtSs2Ve6uDUs30-oZpkOz_1guTtTz0,5597
virtualenv/app_data/via_tempdir.py,sha256=Z_-PoU7qeZe-idzi3nqys4FX0rfsRgOQ9_7XwX3hxSA,770
virtualenv/config/__init__.py,sha256=8ArZTco6Meo0W9i4dqnwmDO8BJYTaHX7oQx1o06vCm4,57
virtualenv/config/convert.py,sha256=msrkiG2Vq9gYQXf1C5W4n3b0ZTv6weFANV-mLUq6uMo,2091
virtualenv/config/convert.py,sha256=WYGjMRKVriZkfTH3z1fI0sDQRZxCxAedqWbOGsaquyg,2693
virtualenv/config/env_var.py,sha256=48XpOurSLLjMX-kXjvOpZuAoOUP-LvnbotTlmebhhFk,844
virtualenv/config/ini.py,sha256=neMqXrA6IOkLF_M_MCQWQSeqNm4CT8tj_h3GdbJv1Cg,2783
virtualenv/config/cli/__init__.py,sha256=8ArZTco6Meo0W9i4dqnwmDO8BJYTaHX7oQx1o06vCm4,57
virtualenv/config/cli/parser.py,sha256=y5IqHccLBqFpocpE75X611nVrP8v394VW94a9GAojvE,4524
virtualenv/create/__init__.py,sha256=8ArZTco6Meo0W9i4dqnwmDO8BJYTaHX7oQx1o06vCm4,57
virtualenv/create/creator.py,sha256=D2YsK817anGhHxjh_ew7MlRCGjPPzW95lroRPlzblGk,8437
virtualenv/create/creator.py,sha256=4jxxEGXCWd6tInT37QNt-13_yDtcIJdPB6EkoYzDkbM,8889
virtualenv/create/debug.py,sha256=ETOke8w4Ib8fiufAHVeOkH3v0zrztljw3WjGvZyE0Mk,3342
virtualenv/create/describe.py,sha256=bm0V2wpFOjdN_MkzZuJAEBSttmi5YGPVwxtwGYU5zQU,3561
virtualenv/create/pyenv_cfg.py,sha256=VsOGfzUpaVCO3J29zrhIeip4jZ4b7llbe45iOQAIRGg,1717
virtualenv/create/via_global_ref/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/create/via_global_ref/_virtualenv.py,sha256=aEuMB5MrpKhKwuWumv5J7wTpK6w9jUGR1FXPCdCT5fw,5662
virtualenv/create/via_global_ref/api.py,sha256=uAQjwBRJ-u4d6A24QuxeB-khIrSGiP7-W_SQxNdE-Sk,4277
virtualenv/create/via_global_ref/api.py,sha256=5MPq3XJBuUOBj53oIigeWWPm68M-J_E644WWbz37qOU,4357
virtualenv/create/via_global_ref/store.py,sha256=cqLBEhQ979xHnlidqmxlDjsvj2Wr-mBo7shvGQSEBxU,685
virtualenv/create/via_global_ref/venv.py,sha256=A6XrGu3oco_ZIHv0s-TybW7lErAomgLOYDMtgpdACc0,2919
virtualenv/create/via_global_ref/venv.py,sha256=p5RkDcXhr1pmOwnl1dpS06UYHmfNVy2ld4sTwsYjYWU,2955
virtualenv/create/via_global_ref/builtin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/create/via_global_ref/builtin/builtin_way.py,sha256=hO22nT-itVoYiy8wXrXXYzHw86toCp_Uq-cURR7w6ck,546
virtualenv/create/via_global_ref/builtin/ref.py,sha256=-r9sJSW9X9rHxThk2yyJJRA5KkmJPW_axuffYBsFDIU,5501
virtualenv/create/via_global_ref/builtin/via_global_self_do.py,sha256=9aH07lmA6SMvtynv7ZTO6Gh2aDDFdUiDQrlbtT9xze4,4057
virtualenv/create/via_global_ref/builtin/ref.py,sha256=xCTICJhE-OiopBxl6ymo1P1NqgK3KEF8ZUOtQDtDTVA,5477
virtualenv/create/via_global_ref/builtin/via_global_self_do.py,sha256=d569fX7fjq5vHvGGXDjo-1Xi__HhqU2xjDJOuYrmGjw,4552
virtualenv/create/via_global_ref/builtin/cpython/__init__.py,sha256=8ArZTco6Meo0W9i4dqnwmDO8BJYTaHX7oQx1o06vCm4,57
virtualenv/create/via_global_ref/builtin/cpython/common.py,sha256=_ycHGl1I4Pr7RfsXlUP0otJw9VQ0L744lTpPTTxPo6w,1909
virtualenv/create/via_global_ref/builtin/cpython/common.py,sha256=U7EvB9-2DlOQTGrTyPrEcItEbJ1sFBzo1EAOcAIjQ5Q,2392
virtualenv/create/via_global_ref/builtin/cpython/cpython2.py,sha256=p41H2g6wAqhJzeUU48nH3u05-yWEbwCzhyj4pn8rnm4,3757
virtualenv/create/via_global_ref/builtin/cpython/cpython3.py,sha256=9sY098at5Wp1Fhu1Aux1y06wH2ecbGj3bRucl4CGSQY,2473
virtualenv/create/via_global_ref/builtin/cpython/mac_os.py,sha256=Hc9FVoQPuf8IV5j17LVj49lH7nyCep2nh_lWlZm49YI,12318
virtualenv/create/via_global_ref/builtin/cpython/cpython3.py,sha256=gguQAhTQb0PH7Xg-G-mgQm5LlhyyW0V0piV3LwI-PeM,3111
virtualenv/create/via_global_ref/builtin/cpython/mac_os.py,sha256=B0Lqgo8geZBSKSpHWUB46lDYRggW4Kg2AZUp3Z7xn9M,12382
virtualenv/create/via_global_ref/builtin/pypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/create/via_global_ref/builtin/pypy/common.py,sha256=KagqBNEuysqqO-n-VCCpuMvBK8MiZFMJQRWbWW12c6g,1696
virtualenv/create/via_global_ref/builtin/pypy/common.py,sha256=-t-TZxCTJwpIh_oRsDyv5IilH19jKqJrZa27zWN_8Ws,1816
virtualenv/create/via_global_ref/builtin/pypy/pypy2.py,sha256=bmMY_KJZ1iD_ifq-X9ZBOlOpJ1aN7839qigBgnWRIdA,3535
virtualenv/create/via_global_ref/builtin/pypy/pypy3.py,sha256=ti6hmOIC4HiTBnEYKytO-d9wH-eLeMoQxQ0kZRhnNrw,1751
virtualenv/create/via_global_ref/builtin/python2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/create/via_global_ref/builtin/python2/python2.py,sha256=jkJwmkeJVTzwzo95eMIptTfdBA-qmyIqZcpt48iOitU,4276
virtualenv/create/via_global_ref/builtin/python2/site.py,sha256=mp-Y1VLSXqhIeOojQefy8ffIylWqfq20jEfc2UwMTYU,6120
virtualenv/create/via_global_ref/builtin/python2/site.py,sha256=4uguJDuWPmB25yBmpsMYKLOnIVXkerck0UO8CP8F2c4,6078
virtualenv/discovery/__init__.py,sha256=8ArZTco6Meo0W9i4dqnwmDO8BJYTaHX7oQx1o06vCm4,57
virtualenv/discovery/builtin.py,sha256=1c4Py9DnkiCLrbHp7bffvQtJI9HkxfVyFedt6IFMKEs,5079
virtualenv/discovery/cached_py_info.py,sha256=vQiAFDoBjR13zrdmc5q97z4upBxWzUG6H6IHJZjqjeU,5007
virtualenv/discovery/builtin.py,sha256=rB6XaQwuK1HfvJsrla3BoSQUH9QkJnwKHGWBdbK4QGM,5432
virtualenv/discovery/cached_py_info.py,sha256=l2lELE8YkwKXCNopImY2VjmpHPTawh1d3qmdsXMtkRs,5043
virtualenv/discovery/discover.py,sha256=evJYn4APkwjNmdolNeIBSHiOudkvN59c5oVYI2Zsjlg,1209
virtualenv/discovery/py_info.py,sha256=PMbQIitL6ELOJpAZF3rrMxPxM8oOmTK9aDvb4YHTDEw,21783
virtualenv/discovery/py_info.py,sha256=QtZFq0xav1tEpKI5seEJaEOkc_FXer21Gzgl_Ccqy98,21793
virtualenv/discovery/py_spec.py,sha256=wQhLzCfXoSPsAAO9nm5-I2lNolVDux4W2vPSUfJGjlc,4790
virtualenv/discovery/windows/__init__.py,sha256=TPbnzCtRyw47pRVHTO8ikwljNcczxmSLDdWtwasxvQU,1036
virtualenv/discovery/windows/pep514.py,sha256=YYiaJzo-XuMtO78BMFMAudqkeJiLQkFnUTOuQZ5lJz8,5451
virtualenv/run/__init__.py,sha256=REhXScKzirtvWjFpTZdepZCKIxcjsRHZtt3q5mDsrMQ,5771
virtualenv/run/session.py,sha256=mzXJyVQlXXgj_kO9IJDor44Co7WKiyFGnZ0mCTIy5x0,2547
virtualenv/run/__init__.py,sha256=lVIiIq_LoMHUGYkrTSx0tpFG_aYywy_u6GWUReHRcUA,5777
virtualenv/run/session.py,sha256=S4NZiHzij1vp895mN9s9ZwYobJjjdP37QOHCb1o-Ufo,2563
virtualenv/run/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/run/plugin/activators.py,sha256=kmHShj36eHfbnsiAJzX0U5LYvGhe0WkRYjbuKDz6gVM,2117
virtualenv/run/plugin/base.py,sha256=-2185C01PaxOG7gnMbWWyZlo24n_FYo5J5_naeNZw8s,1934
virtualenv/run/plugin/creators.py,sha256=5L7G5mk2GIOIaZVvDZszd2VVBSUM3jkAR4aBO0OkOXY,3517
virtualenv/run/plugin/discovery.py,sha256=ba9szD21er0-AkuMXrdFOjFEDsIekRWljXdXkj_-8EM,994
virtualenv/run/plugin/seeders.py,sha256=XVKaikuOC4JUO4lirHzowEJ6d0pI1pFfywCx3heE70g,1026
virtualenv/run/plugin/creators.py,sha256=PIxJ85KmrQU7lUO-r8Znxbb4lTEzwHggc9lcDqmt2tc,3494
virtualenv/run/plugin/discovery.py,sha256=3ykxRvPA1FJMkqsbr2TV0LBRPT5UCFeJdzEHfuEjxRM,1002
virtualenv/run/plugin/seeders.py,sha256=c1mhzu0HNzKdif6YUV35fuAOS0XHFJz3TtccLW5fWG0,1074
virtualenv/seed/__init__.py,sha256=8ArZTco6Meo0W9i4dqnwmDO8BJYTaHX7oQx1o06vCm4,57
virtualenv/seed/seeder.py,sha256=DSGE_8Ycj01vj8mkppUBA9h7JG76XsVBMt-5MWlMF6k,1178
virtualenv/seed/embed/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/seed/embed/base_embed.py,sha256=j4qcALcc-ylU0bKjVxiELPqk4MJ8f0pmbe_lVYVH_5Q,4166
virtualenv/seed/embed/base_embed.py,sha256=46mWtqWj_MjOQEqMJyosL0RWGL6HwrHAL2r1Jxc9DuI,4182
virtualenv/seed/embed/pip_invoke.py,sha256=EMVwIeoW15SuorJ8z_-vBxPXwQJLS0ILA0Va9zNoOLI,2127
virtualenv/seed/embed/via_app_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/seed/embed/via_app_data/via_app_data.py,sha256=quofMFCWc-OxvxdAJwZTWS5mOugnYB7wRqSJZxmkl-E,6053
virtualenv/seed/embed/via_app_data/via_app_data.py,sha256=NkVhEFv4iuKG0qvEg4AAmucMwmQgNaPLB-Syepzgps0,5994
virtualenv/seed/embed/via_app_data/pip_install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
virtualenv/seed/embed/via_app_data/pip_install/base.py,sha256=rnR60JzM7G04cPDo2eH-aR8-iQuFXBgHJ2lQnSf0Gfs,6355
virtualenv/seed/embed/via_app_data/pip_install/copy.py,sha256=gG2NePFHOYh-bsCf6TpsaQ_qrYhdBy67k0RWuwHSAwo,1307
virtualenv/seed/embed/via_app_data/pip_install/symlink.py,sha256=wHCpfKobvjjaZLUSwM3FSCblZfiBFw4IQYsxwlfEEu0,2362
virtualenv/seed/wheels/__init__.py,sha256=1J7el7lNjAwGxM4dmricrbVhSbYxs5sPzv9PTx2A6qA,226
virtualenv/seed/wheels/acquire.py,sha256=Iq_QPJgUPCyHfrS3t2EUUj8fieymfcKNve1JbJQ5Uyc,4420
virtualenv/seed/wheels/bundle.py,sha256=xYbhh5nQEwec2vnqNJWNVtDL3VyjGkgDWVXSuXzXB-Y,1961
virtualenv/seed/wheels/periodic_update.py,sha256=A9l7ZpjtWzGrq2nh39y8g5OppUryHb7_W3bCR7TAnPc,12756
virtualenv/seed/wheels/acquire.py,sha256=qchqlIynLi2VP2VtdAfVfZJHbUPcLY2Ui5r7Eh-aZz8,4426
virtualenv/seed/wheels/bundle.py,sha256=W0uVjClv9IBa50jRvPKm0jMwWnrYTEfDny2Z6bw2W7c,1835
virtualenv/seed/wheels/periodic_update.py,sha256=HNVEuU2OYdWHW7lVO0h3NkpLkC8bu-5R7igJRXBnGDc,12792
virtualenv/seed/wheels/util.py,sha256=Zdo76KEDqbNmM5u9JTuyu5uzEN_fQ4oj6qHOt0h0o1M,3960
virtualenv/seed/wheels/embed/__init__.py,sha256=qc4QGDYH6J4ikiW1GPSkgjpapQDB7TpPd6TTr21jvbU,1995
virtualenv/seed/wheels/embed/__init__.py,sha256=CLMKoeveDRyiNAdZjEtD38cepgNXkg65xzFu5OSHEus,1995
virtualenv/seed/wheels/embed/pip-19.1.1-py2.py3-none-any.whl,sha256=mTE08EdUcbkUUsoCnUOQ3I8pisY6cSgU8QHNG220ZnY,1360957
virtualenv/seed/wheels/embed/pip-20.2.2-py2.py3-none-any.whl,sha256=UkTlFJT10d-7idpJLUJQywf5JGZEc20Q7WxF3rGkhQA,1503623
virtualenv/seed/wheels/embed/pip-20.3.1-py2.py3-none-any.whl,sha256=Ql55sgk5q7_6djOpEVGogq7cd1ZNkxPjWE6wQWwoxVg,1518513
virtualenv/seed/wheels/embed/setuptools-43.0.0-py2.py3-none-any.whl,sha256=pn-qUVGe8ozYJhr_DiIbbkw3D4-4utqKo-etiUUZmWM,583228
virtualenv/seed/wheels/embed/setuptools-44.1.1-py2.py3-none-any.whl,sha256=J6cUwJJTE05gpvpoEw94xwN-VWLE8h-PMY8q6QDRUtU,583493
virtualenv/seed/wheels/embed/setuptools-49.6.0-py3-none-any.whl,sha256=TdW7CgoM_3e0bKXdOoSFfuSMg-giOIa1VmE8ckmUBz8,803275
virtualenv/seed/wheels/embed/setuptools-50.3.2-py3-none-any.whl,sha256=LCQqCFb7rX775WDfSnrdkyTzQM9I30NlHpYEkkRmeUo,785194
virtualenv/seed/wheels/embed/setuptools-51.0.0-py3-none-any.whl,sha256=jBd5NiFZRcmjfvgJraD6s2UZGVL3oSNhhDK7-sNTxSk,785164
virtualenv/seed/wheels/embed/wheel-0.33.6-py2.py3-none-any.whl,sha256=9NoXY9O-zy4s2SoUp8kg8PAOyjD93p6pksg2aFufryg,21556
virtualenv/seed/wheels/embed/wheel-0.35.1-py2.py3-none-any.whl,sha256=SXrdU1JdFsFzwsHHM7j2VVEOkJ6njMDinTdCQ1RLd6I,33174
virtualenv/seed/wheels/embed/wheel-0.36.1-py2.py3-none-any.whl,sha256=kGhk-3IsCrXy-cNbLGXjrzwAlALBCKcJwKyie8LJGHs,34788
virtualenv/util/__init__.py,sha256=om6Hs2lH5igf5lkcSmQFiU7iMZ0Wx4dmSlMc6XW_Llg,199
virtualenv/util/error.py,sha256=SRSZlXvMYQuJwxoUfNhlAyo3VwrAnIsZemSwPOxpjns,352
virtualenv/util/lock.py,sha256=AyYqRMsz5YnLNDLNTrutjLqS8m0lkLqNNDpxW565b44,3550
virtualenv/util/lock.py,sha256=oFa0FcbE_TVDHOol44Mgtfa4D3ZjnVy-HSQx-y7ERKQ,4727
virtualenv/util/six.py,sha256=_8KWXUWi3-AaFmz4LkdyNra-uNuf70vlxwjN7oeRo8g,1463
virtualenv/util/zipapp.py,sha256=jtf4Vn7XBnjPs_B_ObIQv_x4pFlIlPKAWHYLFV59h6U,1054
virtualenv/util/path/__init__.py,sha256=YaBAxtzGBdMu0uUtppe0ZeCHw5HhO-5zjeb3-fzyMoI,336
virtualenv/util/path/_permission.py,sha256=XpO2vGAk_92_biD4MEQcAQq2Zc8_rpm3M3n_hMUA1rw,745
virtualenv/util/path/_sync.py,sha256=7oEmxJB5fc7NIsVgPJTJ4mpVPjNaNHAdhqlgIFSDfm0,2370
virtualenv/util/path/_pathlib/__init__.py,sha256=evaey395zOuDc3FlukUeJ8SzRqLx1xWOKmg-TEPsRd4,1446
virtualenv/util/path/_pathlib/via_os_path.py,sha256=wlnf0MIktEP01kG9z8iKOI86levXmkX7UX1LMLK7A-E,3701
virtualenv/util/subprocess/__init__.py,sha256=2H-ZQ74OKq60eSpxfRWD-8gVUydczkrKSexl18DzOXI,753
virtualenv/util/subprocess/_win_subprocess.py,sha256=0-eJVcxBs1Fe76OVTQnUVLaLzB4tlJxEZ-vZECQ4xL4,5576
virtualenv-20.0.31.dist-info/LICENSE,sha256=XBWRk3jFsqqrexnOpw2M3HX3aHnjJFTkwDmfi3HRcek,1074
virtualenv-20.0.31.dist-info/METADATA,sha256=Pwhk7KR7q09ZjMUtWXYwzvuWD1mY4hxS1e9eqpsjRs8,4923
virtualenv-20.0.31.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
virtualenv-20.0.31.dist-info/entry_points.txt,sha256=1DALKzYOcffJa7Q15TQlMQu0yeFXEy5W124y0aJEfYU,1615
virtualenv-20.0.31.dist-info/top_level.txt,sha256=JV-LVlC8YeIw1DgiYI0hEot7tgFy5IWdKVcSG7NyzaI,11
virtualenv-20.0.31.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
virtualenv-20.0.31.dist-info/RECORD,,
virtualenv/util/path/_sync.py,sha256=rheUrGsCqmhMwNs-uc5rDthNSUlsOrBJPoK8KZj3O1o,2393
virtualenv/util/path/_pathlib/__init__.py,sha256=FjKCi8scB5MnHg2fLX5REoE0bOPkMXqpBEILVTeJZGQ,2130
virtualenv/util/path/_pathlib/via_os_path.py,sha256=fYDFAX483zVvC9hAOAC9FYtrGdZethS0vtYtKsL5r-s,3772
virtualenv/util/subprocess/__init__.py,sha256=1UmFrdBv2sVeUfZbDcO2yZpe28AE0ULOu9dRKlpJaa0,801
virtualenv/util/subprocess/_win_subprocess.py,sha256=SChkXAKVbpehyrHod1ld76RSdTIalrgME1rtz5jUfm0,5655
virtualenv-20.2.2.dist-info/LICENSE,sha256=XBWRk3jFsqqrexnOpw2M3HX3aHnjJFTkwDmfi3HRcek,1074
virtualenv-20.2.2.dist-info/METADATA,sha256=OWyC_GXU3AvST-YiGhmI2iE4ntdcBm-6Q1yCaU9Bx_U,4965
virtualenv-20.2.2.dist-info/WHEEL,sha256=oh0NKYrTcu1i1-wgrI1cnhkjYIi8WJ-8qd9Jrr5_y4E,110
virtualenv-20.2.2.dist-info/entry_points.txt,sha256=1DALKzYOcffJa7Q15TQlMQu0yeFXEy5W124y0aJEfYU,1615
virtualenv-20.2.2.dist-info/top_level.txt,sha256=JV-LVlC8YeIw1DgiYI0hEot7tgFy5IWdKVcSG7NyzaI,11
virtualenv-20.2.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
virtualenv-20.2.2.dist-info/RECORD,,

View File

@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.36.1)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View File

@ -47,6 +47,9 @@ deactivate () {
deactivate nondestructive
VIRTUAL_ENV='__VIRTUAL_ENV__'
if ([ "$OSTYPE" = "cygwin" ] || [ "$OSTYPE" = "msys" ]) && $(command -v cygpath &> /dev/null) ; then
VIRTUAL_ENV=$(cygpath -u "$VIRTUAL_ENV")
fi
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"

View File

@ -1,60 +1,60 @@
$script:THIS_PATH = $myinvocation.mycommand.path
$script:BASE_DIR = Split-Path (Resolve-Path "$THIS_PATH/..") -Parent
function global:deactivate([switch] $NonDestructive) {
if (Test-Path variable:_OLD_VIRTUAL_PATH) {
$env:PATH = $variable:_OLD_VIRTUAL_PATH
Remove-Variable "_OLD_VIRTUAL_PATH" -Scope global
}
if (Test-Path function:_old_virtual_prompt) {
$function:prompt = $function:_old_virtual_prompt
Remove-Item function:\_old_virtual_prompt
}
if ($env:VIRTUAL_ENV) {
Remove-Item env:VIRTUAL_ENV -ErrorAction SilentlyContinue
}
if (!$NonDestructive) {
# Self destruct!
Remove-Item function:deactivate
Remove-Item function:pydoc
}
}
function global:pydoc {
python -m pydoc $args
}
# unset irrelevant variables
deactivate -nondestructive
$VIRTUAL_ENV = $BASE_DIR
$env:VIRTUAL_ENV = $VIRTUAL_ENV
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
$env:PATH = "$env:VIRTUAL_ENV/__BIN_NAME____PATH_SEP__" + $env:PATH
if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
function global:_old_virtual_prompt {
""
}
$function:_old_virtual_prompt = $function:prompt
if ("__VIRTUAL_PROMPT__" -ne "") {
function global:prompt {
# Add the custom prefix to the existing prompt
$previous_prompt_value = & $function:_old_virtual_prompt
("__VIRTUAL_PROMPT__" + $previous_prompt_value)
}
}
else {
function global:prompt {
# Add a prefix to the current prompt, but don't discard it.
$previous_prompt_value = & $function:_old_virtual_prompt
$new_prompt_value = "($( Split-Path $env:VIRTUAL_ENV -Leaf )) "
($new_prompt_value + $previous_prompt_value)
}
}
}
$script:THIS_PATH = $myinvocation.mycommand.path
$script:BASE_DIR = Split-Path (Resolve-Path "$THIS_PATH/..") -Parent
function global:deactivate([switch] $NonDestructive) {
if (Test-Path variable:_OLD_VIRTUAL_PATH) {
$env:PATH = $variable:_OLD_VIRTUAL_PATH
Remove-Variable "_OLD_VIRTUAL_PATH" -Scope global
}
if (Test-Path function:_old_virtual_prompt) {
$function:prompt = $function:_old_virtual_prompt
Remove-Item function:\_old_virtual_prompt
}
if ($env:VIRTUAL_ENV) {
Remove-Item env:VIRTUAL_ENV -ErrorAction SilentlyContinue
}
if (!$NonDestructive) {
# Self destruct!
Remove-Item function:deactivate
Remove-Item function:pydoc
}
}
function global:pydoc {
python -m pydoc $args
}
# unset irrelevant variables
deactivate -nondestructive
$VIRTUAL_ENV = $BASE_DIR
$env:VIRTUAL_ENV = $VIRTUAL_ENV
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
$env:PATH = "$env:VIRTUAL_ENV/__BIN_NAME____PATH_SEP__" + $env:PATH
if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
function global:_old_virtual_prompt {
""
}
$function:_old_virtual_prompt = $function:prompt
if ("__VIRTUAL_PROMPT__" -ne "") {
function global:prompt {
# Add the custom prefix to the existing prompt
$previous_prompt_value = & $function:_old_virtual_prompt
("__VIRTUAL_PROMPT__" + $previous_prompt_value)
}
}
else {
function global:prompt {
# Add a prefix to the current prompt, but don't discard it.
$previous_prompt_value = & $function:_old_virtual_prompt
$new_prompt_value = "($( Split-Path $env:VIRTUAL_ENV -Leaf )) "
($new_prompt_value + $previous_prompt_value)
}
}
}

View File

@ -11,9 +11,9 @@ from virtualenv.util.six import ensure_text
from .activator import Activator
if sys.version_info >= (3, 7):
from importlib.resources import read_text
from importlib.resources import read_binary
else:
from importlib_resources import read_text
from importlib_resources import read_binary
@add_metaclass(ABCMeta)
@ -44,7 +44,8 @@ class ViaTemplateActivator(Activator):
for template in templates:
text = self.instantiate_template(replacements, template, creator)
dest = to_folder / self.as_name(template)
dest.write_text(text, encoding="utf-8")
# use write_bytes to avoid platform specific line normalization (\n -> \r\n)
dest.write_bytes(text.encode("utf-8"))
generated.append(dest)
return generated
@ -52,8 +53,9 @@ class ViaTemplateActivator(Activator):
return template.name
def instantiate_template(self, replacements, template, creator):
# read text and do replacements
text = read_text(self.__module__, str(template), encoding="utf-8", errors="strict")
# read content as binary to avoid platform specific line normalization (\n -> \r\n)
binary = read_binary(self.__module__, str(template))
text = binary.decode("utf-8", errors="strict")
for key, value in replacements.items():
value = self._repr_unicode(creator, value)
text = text.replace(key, value)

View File

@ -5,58 +5,53 @@ from __future__ import absolute_import, unicode_literals
import logging
import os
from argparse import Action, ArgumentError
from appdirs import user_data_dir
from .na import AppDataDisabled
from .read_only import ReadOnlyAppData
from .via_disk_folder import AppDataDiskFolder
from .via_tempdir import TempAppData
class AppDataAction(Action):
def __call__(self, parser, namespace, values, option_string=None):
folder = self._check_folder(values)
if folder is None:
raise ArgumentError("app data path {} is not valid".format(values))
setattr(namespace, self.dest, AppDataDiskFolder(folder))
def _default_app_data_dir(): # type: () -> str
key = str("VIRTUALENV_OVERRIDE_APP_DATA")
if key in os.environ:
return os.environ[key]
else:
return user_data_dir(appname="virtualenv", appauthor="pypa")
@staticmethod
def _check_folder(folder):
folder = os.path.abspath(folder)
if not os.path.exists(folder):
try:
os.makedirs(folder)
logging.debug("created app data folder %s", folder)
except OSError as exception:
logging.info("could not create app data folder %s due to %r", folder, exception)
return None
write_enabled = os.access(folder, os.W_OK)
if write_enabled:
return folder
def make_app_data(folder, **kwargs):
read_only = kwargs.pop("read_only")
if kwargs: # py3+ kwonly
raise TypeError("unexpected keywords: {}")
if folder is None:
folder = _default_app_data_dir()
folder = os.path.abspath(folder)
if read_only:
return ReadOnlyAppData(folder)
if not os.path.isdir(folder):
try:
os.makedirs(folder)
logging.debug("created app data folder %s", folder)
except OSError as exception:
logging.info("could not create app data folder %s due to %r", folder, exception)
if os.access(folder, os.W_OK):
return AppDataDiskFolder(folder)
else:
logging.debug("app data folder %s has no write access", folder)
return None
@staticmethod
def default():
for folder in AppDataAction._app_data_candidates():
folder = AppDataAction._check_folder(folder)
if folder is not None:
return AppDataDiskFolder(folder)
return AppDataDisabled()
@staticmethod
def _app_data_candidates():
key = str("VIRTUALENV_OVERRIDE_APP_DATA")
if key in os.environ:
yield os.environ[key]
else:
yield user_data_dir(appname="virtualenv", appauthor="pypa")
return TempAppData()
__all__ = (
"AppDataDiskFolder",
"TempAppData",
"AppDataAction",
"AppDataDisabled",
"AppDataDiskFolder",
"ReadOnlyAppData",
"TempAppData",
"make_app_data",
)

View File

@ -31,6 +31,10 @@ class AppData(object):
def py_info_clear(self):
raise NotImplementedError
@property
def can_update(self):
raise NotImplementedError
@abstractmethod
def embed_update_log(self, distribution, for_py_version):
raise NotImplementedError

View File

@ -8,6 +8,9 @@ from .base import AppData, ContentStore
class AppDataDisabled(AppData):
"""No application cache available (most likely as we don't have write permissions)"""
transient = True
can_update = False
def __init__(self):
pass
@ -40,10 +43,6 @@ class AppDataDisabled(AppData):
def wheel_image(self, for_py_version, name):
raise self.error
@property
def transient(self):
return True
def py_info_clear(self):
""""""

View File

@ -0,0 +1,34 @@
import os.path
from virtualenv.util.lock import NoOpFileLock
from .via_disk_folder import AppDataDiskFolder, PyInfoStoreDisk
class ReadOnlyAppData(AppDataDiskFolder):
can_update = False
def __init__(self, folder): # type: (str) -> None
if not os.path.isdir(folder):
raise RuntimeError("read-only app data directory {} does not exist".format(folder))
self.lock = NoOpFileLock(folder)
def reset(self): # type: () -> None
raise RuntimeError("read-only app data does not support reset")
def py_info_clear(self): # type: () -> None
raise NotImplementedError
def py_info(self, path):
return _PyInfoStoreDiskReadOnly(self.py_info_at, path)
def embed_update_log(self, distribution, for_py_version):
raise NotImplementedError
class _PyInfoStoreDiskReadOnly(PyInfoStoreDisk):
def write(self, content):
raise RuntimeError("read-only app data python info cannot be updated")
__all__ = ("ReadOnlyAppData",)

View File

@ -46,15 +46,17 @@ class AppDataDiskFolder(AppData):
Store the application data on the disk within a folder layout.
"""
transient = False
can_update = True
def __init__(self, folder):
self.lock = ReentrantFileLock(folder)
def __repr__(self):
return "{}".format(self.lock.path)
return "{}({})".format(type(self).__name__, self.lock.path)
@property
def transient(self):
return False
def __str__(self):
return str(self.lock.path)
def reset(self):
logging.debug("reset app data folder %s", self.lock.path)
@ -137,7 +139,10 @@ class JSONStoreDisk(ContentStore):
except Exception: # noqa
pass
if bad_format:
self.remove()
try:
self.remove()
except OSError: # reading and writing on the same file may cause race on multiple processes
pass
return None
def remove(self):
@ -151,10 +156,7 @@ class JSONStoreDisk(ContentStore):
def write(self, content):
folder = self.file.parent
try:
folder.mkdir(parents=True, exist_ok=True)
except OSError:
pass
folder.mkdir(parents=True, exist_ok=True)
self.file.write_text(ensure_text(json.dumps(content, sort_keys=True, indent=2)))
logging.debug("wrote {} at %s".format(self.msg), *self.msg_args)
@ -168,5 +170,8 @@ class PyInfoStoreDisk(JSONStoreDisk):
class EmbedDistributionUpdateStoreDisk(JSONStoreDisk):
def __init__(self, in_folder, distribution):
super(EmbedDistributionUpdateStoreDisk, self).__init__(
in_folder, distribution, "embed update of distribution %s", (distribution,),
in_folder,
distribution,
"embed update of distribution %s",
(distribution,),
)

View File

@ -9,6 +9,9 @@ from .via_disk_folder import AppDataDiskFolder
class TempAppData(AppDataDiskFolder):
transient = True
can_update = False
def __init__(self):
super(TempAppData, self).__init__(folder=mkdtemp())
logging.debug("created temporary app data folder %s", self.lock.path)
@ -21,8 +24,4 @@ class TempAppData(AppDataDiskFolder):
safe_delete(self.lock.path)
def embed_update_log(self, distribution, for_py_version):
return None
@property
def transient(self):
return True
raise NotImplementedError

View File

@ -46,9 +46,7 @@ class ListType(TypeData):
""""""
def convert(self, value, flatten=True):
if isinstance(value, (str, bytes)):
value = filter(None, [x.strip() for x in value.splitlines()])
values = list(value)
values = self.split_values(value)
result = []
for value in values:
sub_values = value.split(os.pathsep)
@ -56,6 +54,25 @@ class ListType(TypeData):
converted = [self.as_type(i) for i in result]
return converted
def split_values(self, value):
"""Split the provided value into a list.
First this is done by newlines. If there were no newlines in the text,
then we next try to split by comma.
"""
if isinstance(value, (str, bytes)):
# Use `splitlines` rather than a custom check for whether there is
# more than one line. This ensures that the full `splitlines()`
# logic is supported here.
values = value.splitlines()
if len(values) <= 1:
values = value.split(",")
values = filter(None, [x.strip() for x in values])
else:
values = list(value)
return values
def convert(value, as_type, source):
"""Convert the value as a given type where the value comes from the given source"""

View File

@ -44,6 +44,7 @@ class Creator(object):
self._debug = None
self.dest = Path(options.dest)
self.clear = options.clear
self.no_vcs_ignore = options.no_vcs_ignore
self.pyenv_cfg = PyEnvCfg.from_folder(self.dest)
self.app_data = options.app_data
@ -57,6 +58,7 @@ class Creator(object):
return [
("dest", ensure_text(str(self.dest))),
("clear", self.clear),
("no_vcs_ignore", self.no_vcs_ignore),
]
@classmethod
@ -79,7 +81,9 @@ class Creator(object):
:param meta: value as returned by :meth:`can_create`
"""
parser.add_argument(
"dest", help="directory to create virtualenv at", type=cls.validate_dest,
"dest",
help="directory to create virtualenv at",
type=cls.validate_dest,
)
parser.add_argument(
"--clear",
@ -88,6 +92,13 @@ class Creator(object):
help="remove the destination directory if exist before starting (will overwrite files otherwise)",
default=False,
)
parser.add_argument(
"--no-vcs-ignore",
dest="no_vcs_ignore",
action="store_true",
help="don't create VCS ignore directive in the destination directory",
default=False,
)
@abstractmethod
def create(self):
@ -120,7 +131,9 @@ class Creator(object):
if refused:
raise ArgumentTypeError(
"the file system codec ({}) cannot handle characters {!r} within {!r}".format(
encoding, "".join(refused.keys()), raw_value,
encoding,
"".join(refused.keys()),
raw_value,
),
)
if os.pathsep in raw_value:
@ -156,7 +169,8 @@ class Creator(object):
safe_delete(self.dest)
self.create()
self.set_pyenv_cfg()
self.setup_ignore_vcs()
if not self.no_vcs_ignore:
self.setup_ignore_vcs()
def set_pyenv_cfg(self):
self.pyenv_cfg.content = OrderedDict()

View File

@ -8,6 +8,7 @@ from six import add_metaclass
from virtualenv.info import fs_supports_symlink
from virtualenv.util.path import Path
from virtualenv.util.six import ensure_text
from ..creator import Creator, CreatorMeta
@ -91,10 +92,10 @@ class ViaGlobalRefApi(Creator):
text = self.env_patch_text()
if text:
pth = self.purelib / "_virtualenv.pth"
logging.debug("create virtualenv import hook file %s", pth)
logging.debug("create virtualenv import hook file %s", ensure_text(str(pth)))
pth.write_text("import _virtualenv")
dest_path = self.purelib / "_virtualenv.py"
logging.debug("create %s", dest_path)
logging.debug("create %s", ensure_text(str(dest_path)))
dest_path.write_text(text)
def env_patch_text(self):

View File

@ -6,6 +6,7 @@ from collections import OrderedDict
from six import add_metaclass
from virtualenv.create.describe import PosixSupports, WindowsSupports
from virtualenv.create.via_global_ref.builtin.ref import RefMust, RefWhen
from virtualenv.util.path import Path
from ..via_global_self_do import ViaGlobalRefVirtualenvBuiltin
@ -33,19 +34,27 @@ class CPythonPosix(CPython, PosixSupports):
targets = OrderedDict(
(i, None) for i in ["python", "python{}".format(major), "python{}.{}".format(major, minor), host_exe.name]
)
yield host_exe, list(targets.keys())
must = RefMust.COPY if interpreter.version_info.major == 2 else RefMust.NA
yield host_exe, list(targets.keys()), must, RefWhen.ANY
@add_metaclass(ABCMeta)
class CPythonWindows(CPython, WindowsSupports):
@classmethod
def _executables(cls, interpreter):
host = Path(interpreter.system_executable)
# symlink of the python executables does not work reliably, copy always instead
# - https://bugs.python.org/issue42013
# - venv
host = cls.host_python(interpreter)
for path in (host.parent / n for n in {"python.exe", host.name}):
yield host, [path.name]
yield host, [path.name], RefMust.COPY, RefWhen.ANY
# for more info on pythonw.exe see https://stackoverflow.com/a/30313091
python_w = host.parent / "pythonw.exe"
yield python_w, [python_w.name]
yield python_w, [python_w.name], RefMust.COPY, RefWhen.ANY
@classmethod
def host_python(cls, interpreter):
return Path(interpreter.system_executable)
def is_mac_os_framework(interpreter):

View File

@ -55,8 +55,21 @@ class CPython3Windows(CPythonWindows, CPython3):
def sources(cls, interpreter):
for src in super(CPython3Windows, cls).sources(interpreter):
yield src
for src in cls.include_dll_and_pyd(interpreter):
yield src
if not cls.venv_37p(interpreter):
for src in cls.include_dll_and_pyd(interpreter):
yield src
@staticmethod
def venv_37p(interpreter):
return interpreter.version_info.minor >= 7
@classmethod
def host_python(cls, interpreter):
if cls.venv_37p(interpreter):
# starting with CPython 3.7 Windows ships with a venvlauncher.exe that avoids the need for dll/pyd copies
# it also means the wrapper must be copied to avoid bugs such as https://bugs.python.org/issue42013
return Path(interpreter.system_stdlib) / "venv" / "scripts" / "nt" / "python.exe"
return super(CPython3Windows, cls).host_python(interpreter)
@classmethod
def include_dll_and_pyd(cls, interpreter):

View File

@ -9,7 +9,7 @@ from textwrap import dedent
from six import add_metaclass
from virtualenv.create.via_global_ref.builtin.ref import ExePathRefToDest, PathRefToDest
from virtualenv.create.via_global_ref.builtin.ref import ExePathRefToDest, PathRefToDest, RefMust
from virtualenv.util.path import Path
from virtualenv.util.six import ensure_text
@ -29,7 +29,8 @@ class CPythonmacOsFramework(CPython):
for src in super(CPythonmacOsFramework, cls).sources(interpreter):
yield src
# add a symlink to the host python image
ref = PathRefToDest(cls.image_ref(interpreter), dest=lambda self, _: self.dest / ".Python", must_symlink=True)
exe = cls.image_ref(interpreter)
ref = PathRefToDest(exe, dest=lambda self, _: self.dest / ".Python", must=RefMust.SYMLINK)
yield ref
def create(self):
@ -40,7 +41,7 @@ class CPythonmacOsFramework(CPython):
current = self.current_mach_o_image_path()
for src in self._sources:
if isinstance(src, ExePathRefToDest):
if src.must_copy or not self.symlinks:
if src.must == RefMust.COPY or not self.symlinks:
exes = [self.bin_dir / src.base]
if not self.symlinks:
exes.extend(self.bin_dir / a for a in src.aliases)
@ -49,12 +50,12 @@ class CPythonmacOsFramework(CPython):
@classmethod
def _executables(cls, interpreter):
for _, targets in super(CPythonmacOsFramework, cls)._executables(interpreter):
for _, targets, must, when in super(CPythonmacOsFramework, cls)._executables(interpreter):
# Make sure we use the embedded interpreter inside the framework, even if sys.executable points to the
# stub executable in ${sys.prefix}/bin.
# See http://groups.google.com/group/python-virtualenv/browse_thread/thread/17cab2f85da75951
fixed_host_exe = Path(interpreter.prefix) / "Resources" / "Python.app" / "Contents" / "MacOS" / "Python"
yield fixed_host_exe, targets
yield fixed_host_exe, targets, must, when
@abstractmethod
def current_mach_o_image_path(self):
@ -241,7 +242,7 @@ def _builtin_change_mach_o(maxint):
def mach_o_change(at_path, what, value):
"""Replace a given name (what) in any LC_LOAD_DYLIB command found in the given binary with a new name (value),
provided it's shorter."""
provided it's shorter."""
def do_macho(file, bits, endian):
# Read Mach-O header (the magic number is assumed read by the caller)

View File

@ -4,7 +4,7 @@ import abc
from six import add_metaclass
from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest, RefMust, RefWhen
from virtualenv.util.path import Path
from ..via_global_self_do import ViaGlobalRefVirtualenvBuiltin
@ -20,7 +20,8 @@ class PyPy(ViaGlobalRefVirtualenvBuiltin):
def _executables(cls, interpreter):
host = Path(interpreter.system_executable)
targets = sorted("{}{}".format(name, PyPy.suffix) for name in cls.exe_names(interpreter))
yield host, targets
must = RefMust.COPY if interpreter.version_info.major == 2 else RefMust.NA
yield host, targets, must, RefWhen.ANY
@classmethod
def exe_names(cls, interpreter):

View File

@ -52,8 +52,7 @@ def load_host_site():
add_site_dir = sys.modules["site"].addsitedir
for path in json.loads(site_packages):
full_path = os.path.abspath(os.path.join(here, path.encode("utf-8")))
if full_path not in sys.path:
add_site_dir(full_path)
add_site_dir(full_path)
sep = "\\" if sys.platform == "win32" else "/" # no os module here yet - poor mans version

View File

@ -17,6 +17,18 @@ from virtualenv.util.path import copy, make_exe, symlink
from virtualenv.util.six import ensure_text
class RefMust(object):
NA = "NA"
COPY = "copy"
SYMLINK = "symlink"
class RefWhen(object):
ANY = "ANY"
COPY = "copy"
SYMLINK = "symlink"
@add_metaclass(ABCMeta)
class PathRef(object):
"""Base class that checks if a file reference can be symlink/copied"""
@ -24,9 +36,9 @@ class PathRef(object):
FS_SUPPORTS_SYMLINK = fs_supports_symlink()
FS_CASE_SENSITIVE = fs_is_case_sensitive()
def __init__(self, src, must_symlink, must_copy):
self.must_symlink = must_symlink
self.must_copy = must_copy
def __init__(self, src, must=RefMust.NA, when=RefWhen.ANY):
self.must = must
self.when = when
self.src = src
try:
self.exists = src.exists()
@ -35,8 +47,6 @@ class PathRef(object):
self._can_read = None if self.exists else False
self._can_copy = None if self.exists else False
self._can_symlink = None if self.exists else False
if self.must_copy is True and self.must_symlink is True:
raise ValueError("can copy and symlink at the same time")
def __repr__(self):
return "{}(src={})".format(self.__class__.__name__, self.src)
@ -57,7 +67,7 @@ class PathRef(object):
@property
def can_copy(self):
if self._can_copy is None:
if self.must_symlink:
if self.must == RefMust.SYMLINK:
self._can_copy = self.can_symlink
else:
self._can_copy = self.can_read
@ -66,7 +76,7 @@ class PathRef(object):
@property
def can_symlink(self):
if self._can_symlink is None:
if self.must_copy:
if self.must == RefMust.COPY:
self._can_symlink = self.can_copy
else:
self._can_symlink = self.FS_SUPPORTS_SYMLINK and self.can_read
@ -77,9 +87,9 @@ class PathRef(object):
raise NotImplementedError
def method(self, symlinks):
if self.must_symlink:
if self.must == RefMust.SYMLINK:
return symlink
if self.must_copy:
if self.must == RefMust.COPY:
return copy
return symlink if symlinks else copy
@ -88,8 +98,8 @@ class PathRef(object):
class ExePathRef(PathRef):
"""Base class that checks if a executable can be references via symlink/copy"""
def __init__(self, src, must_symlink, must_copy):
super(ExePathRef, self).__init__(src, must_symlink, must_copy)
def __init__(self, src, must=RefMust.NA, when=RefWhen.ANY):
super(ExePathRef, self).__init__(src, must, when)
self._can_run = None
@property
@ -114,8 +124,8 @@ class ExePathRef(PathRef):
class PathRefToDest(PathRef):
"""Link a path on the file system"""
def __init__(self, src, dest, must_symlink=False, must_copy=False):
super(PathRefToDest, self).__init__(src, must_symlink, must_copy)
def __init__(self, src, dest, must=RefMust.NA, when=RefWhen.ANY):
super(PathRefToDest, self).__init__(src, must, when)
self.dest = dest
def run(self, creator, symlinks):
@ -131,15 +141,14 @@ class PathRefToDest(PathRef):
class ExePathRefToDest(PathRefToDest, ExePathRef):
"""Link a exe path on the file system"""
def __init__(self, src, targets, dest, must_symlink=False, must_copy=False):
ExePathRef.__init__(self, src, must_symlink, must_copy)
PathRefToDest.__init__(self, src, dest, must_symlink, must_copy)
def __init__(self, src, targets, dest, must=RefMust.NA, when=RefWhen.ANY):
ExePathRef.__init__(self, src, must, when)
PathRefToDest.__init__(self, src, dest, must, when)
if not self.FS_CASE_SENSITIVE:
targets = list(OrderedDict((i.lower(), None) for i in targets).keys())
self.base = targets[0]
self.aliases = targets[1:]
self.dest = dest
self.must_copy = must_copy
def run(self, creator, symlinks):
bin_dir = self.dest(creator, self.src).parent

View File

@ -4,7 +4,7 @@ from abc import ABCMeta
from six import add_metaclass
from virtualenv.create.via_global_ref.builtin.ref import ExePathRefToDest
from virtualenv.create.via_global_ref.builtin.ref import ExePathRefToDest, RefMust, RefWhen
from virtualenv.util.path import ensure_dir
from ..api import ViaGlobalRefApi, ViaGlobalRefMeta
@ -27,26 +27,37 @@ class ViaGlobalRefVirtualenvBuiltin(ViaGlobalRefApi, VirtualenvBuiltin):
def can_create(cls, interpreter):
"""By default all built-in methods assume that if we can describe it we can create it"""
# first we must be able to describe it
if cls.can_describe(interpreter):
meta = cls.setup_meta(interpreter)
if meta is not None and meta:
for src in cls.sources(interpreter):
if src.exists:
if meta.can_copy and not src.can_copy:
meta.copy_error = "cannot copy {}".format(src)
if meta.can_symlink and not src.can_symlink:
meta.symlink_error = "cannot symlink {}".format(src)
if not meta.can_copy and not meta.can_symlink:
meta.error = "neither copy or symlink supported, copy: {} symlink: {}".format(
meta.copy_error, meta.symlink_error,
)
else:
meta.error = "missing required file {}".format(src)
if meta.error:
break
meta.sources.append(src)
return meta
return None
if not cls.can_describe(interpreter):
return None
meta = cls.setup_meta(interpreter)
if meta is not None and meta:
cls._sources_can_be_applied(interpreter, meta)
return meta
@classmethod
def _sources_can_be_applied(cls, interpreter, meta):
for src in cls.sources(interpreter):
if src.exists:
if meta.can_copy and not src.can_copy:
meta.copy_error = "cannot copy {}".format(src)
if meta.can_symlink and not src.can_symlink:
meta.symlink_error = "cannot symlink {}".format(src)
else:
msg = "missing required file {}".format(src)
if src.when == RefMust.NA:
meta.error = msg
elif src.when == RefMust.COPY:
meta.copy_error = msg
elif src.when == RefMust.SYMLINK:
meta.symlink_error = msg
if not meta.can_copy and not meta.can_symlink:
meta.error = "neither copy or symlink supported, copy: {} symlink: {}".format(
meta.copy_error,
meta.symlink_error,
)
if meta.error:
break
meta.sources.append(src)
@classmethod
def setup_meta(cls, interpreter):
@ -54,9 +65,8 @@ class ViaGlobalRefVirtualenvBuiltin(ViaGlobalRefApi, VirtualenvBuiltin):
@classmethod
def sources(cls, interpreter):
is_py2 = interpreter.version_info.major == 2
for host_exe, targets in cls._executables(interpreter):
yield ExePathRefToDest(host_exe, dest=cls.to_bin, targets=targets, must_copy=is_py2)
for host_exe, targets, must, when in cls._executables(interpreter):
yield ExePathRefToDest(host_exe, dest=cls.to_bin, targets=targets, must=must, when=when)
def to_bin(self, src):
return self.bin_dir / src.name
@ -79,7 +89,12 @@ class ViaGlobalRefVirtualenvBuiltin(ViaGlobalRefApi, VirtualenvBuiltin):
try:
self.enable_system_site_package = False
for src in self._sources:
src.run(self, self.symlinks)
if (
src.when == RefWhen.ANY
or (src.when == RefWhen.SYMLINK and self.symlinks is True)
or (src.when == RefWhen.COPY and self.symlinks is False)
):
src.run(self, self.symlinks)
finally:
if true_system_site != self.enable_system_site_package:
self.enable_system_site_package = true_system_site
@ -92,7 +107,7 @@ class ViaGlobalRefVirtualenvBuiltin(ViaGlobalRefApi, VirtualenvBuiltin):
"""
We directly inject the base prefix and base exec prefix to avoid site.py needing to discover these
from home (which usually is done within the interpreter itself)
"""
"""
super(ViaGlobalRefVirtualenvBuiltin, self).set_pyenv_cfg()
self.pyenv_cfg["base-prefix"] = self.interpreter.system_prefix
self.pyenv_cfg["base-exec-prefix"] = self.interpreter.system_exec_prefix

View File

@ -46,7 +46,10 @@ class Venv(ViaGlobalRefApi):
from venv import EnvBuilder
builder = EnvBuilder(
system_site_packages=self.enable_system_site_package, clear=False, symlinks=self.symlinks, with_pip=False,
system_site_packages=self.enable_system_site_package,
clear=False,
symlinks=self.symlinks,
with_pip=False,
)
builder.create(str(self.dest))

View File

@ -15,7 +15,7 @@ from .py_spec import PythonSpec
class Builtin(Discover):
def __init__(self, options):
super(Builtin, self).__init__(options)
self.python_spec = options.python
self.python_spec = options.python if options.python else [sys.executable]
self.app_data = options.app_data
@classmethod
@ -25,18 +25,26 @@ class Builtin(Discover):
"--python",
dest="python",
metavar="py",
help="target interpreter for which to create a virtual (either absolute path or identifier string)",
default=sys.executable,
type=str,
action="append",
default=[],
help="interpreter based on what to create environment (path/identifier) "
"- by default use the interpreter where the tool is installed - first found wins",
)
def run(self):
return get_interpreter(self.python_spec, self.app_data)
for python_spec in self.python_spec:
result = get_interpreter(python_spec, self.app_data)
if result is not None:
return result
return None
def __repr__(self):
return ensure_str(self.__unicode__())
def __unicode__(self):
return "{} discover of python_spec={!r}".format(self.__class__.__name__, self.python_spec)
spec = self.python_spec[0] if len(self.python_spec) == 1 else self.python_spec
return "{} discover of python_spec={!r}".format(self.__class__.__name__, spec)
def get_interpreter(key, app_data=None):

View File

@ -104,7 +104,10 @@ def _run_subprocess(cls, exe, app_data):
result.executable = exe # keep original executable as this may contain initialization code
else:
msg = "failed to query {} with code {}{}{}".format(
exe, code, " out: {!r}".format(out) if out else "", " err: {!r}".format(err) if err else "",
exe,
code,
" out: {!r}".format(out) if out else "",
" err: {!r}".format(err) if err else "",
)
failure = RuntimeError(msg)
return failure, result

View File

@ -120,7 +120,7 @@ class PythonInfo(object):
@staticmethod
def _distutils_install():
# follow https://github.com/pypa/pip/blob/master/src/pip/_internal/locations.py#L95
# follow https://github.com/pypa/pip/blob/main/src/pip/_internal/locations.py#L95
# note here we don't import Distribution directly to allow setuptools to patch it
d = dist.Distribution({"script_args": "--no-user-cfg"}) # conf files not parsed so they do not hijack paths
if hasattr(sys, "_framework"):
@ -198,7 +198,8 @@ class PythonInfo(object):
def __repr__(self):
return "{}({!r})".format(
self.__class__.__name__, {k: v for k, v in self.__dict__.items() if not k.startswith("_")},
self.__class__.__name__,
{k: v for k, v in self.__dict__.items() if not k.startswith("_")},
)
def __str__(self):

View File

@ -1,8 +1,9 @@
from __future__ import absolute_import, unicode_literals
import logging
from functools import partial
from ..app_data import AppDataAction, AppDataDisabled, TempAppData
from ..app_data import make_app_data
from ..config.cli.parser import VirtualEnvConfigParser
from ..report import LEVELS, setup_report
from ..run.session import Session
@ -88,32 +89,31 @@ def handle_extra_commands(options):
def load_app_data(args, parser, options):
parser.add_argument(
"--read-only-app-data",
action="store_true",
help="use app data folder in read-only mode (write operations will fail with error)",
)
options, _ = parser.parse_known_args(args, namespace=options)
# here we need a write-able application data (e.g. the zipapp might need this for discovery cache)
default_app_data = AppDataAction.default()
parser.add_argument(
"--app-data",
dest="app_data",
action=AppDataAction,
default="<temp folder>" if isinstance(default_app_data, AppDataDisabled) else default_app_data,
help="a data folder used as cache by the virtualenv",
type=partial(make_app_data, read_only=options.read_only_app_data),
default=make_app_data(None, read_only=options.read_only_app_data),
)
parser.add_argument(
"--reset-app-data",
dest="reset_app_data",
action="store_true",
help="start with empty app data folder",
default=False,
)
parser.add_argument(
"--upgrade-embed-wheels",
dest="upgrade_embed_wheels",
action="store_true",
help="trigger a manual update of the embedded wheels",
default=False,
)
options, _ = parser.parse_known_args(args, namespace=options)
if options.app_data == "<temp folder>":
options.app_data = TempAppData()
if options.reset_app_data:
options.app_data.reset()
return options
@ -134,7 +134,8 @@ def _do_report_setup(parser, args, setup_logging):
level_map = ", ".join("{}={}".format(logging.getLevelName(l), c) for c, l in sorted(list(LEVELS.items())))
msg = "verbosity = verbose - quiet, default {}, mapping => {}"
verbosity_group = parser.add_argument_group(
title="verbosity", description=msg.format(logging.getLevelName(LEVELS[3]), level_map),
title="verbosity",
description=msg.format(logging.getLevelName(LEVELS[3]), level_map),
)
verbosity = verbosity_group.add_mutually_exclusive_group()
verbosity.add_argument("-v", "--verbose", action="count", dest="verbose", help="increase verbosity", default=2)

View File

@ -18,14 +18,14 @@ class CreatorSelector(ComponentBuilder):
@classmethod
def for_interpreter(cls, interpreter):
key_to_class, key_to_meta, builtin_key, describe = OrderedDict(), {}, None, None
errored = defaultdict(list)
errors = defaultdict(list)
for key, creator_class in cls.options("virtualenv.create").items():
if key == "builtin":
raise RuntimeError("builtin creator is a reserved name")
meta = creator_class.can_create(interpreter)
if meta:
if meta.error:
errored[meta.error].append(creator_class)
errors[meta.error].append(creator_class)
else:
if "builtin" not in key_to_class and issubclass(creator_class, VirtualenvBuiltin):
builtin_key = key
@ -36,16 +36,16 @@ class CreatorSelector(ComponentBuilder):
if describe is None and issubclass(creator_class, Describe) and creator_class.can_describe(interpreter):
describe = creator_class
if not key_to_meta:
if errored:
raise RuntimeError(
"\n".join(
"{} for creators {}".format(k, ", ".join(i.__name__ for i in v)) for k, v in errored.items()
),
)
if errors:
rows = ["{} for creators {}".format(k, ", ".join(i.__name__ for i in v)) for k, v in errors.items()]
raise RuntimeError("\n".join(rows))
else:
raise RuntimeError("No virtualenv implementation for {}".format(interpreter))
return CreatorInfo(
key_to_class=key_to_class, key_to_meta=key_to_meta, describe=describe, builtin_key=builtin_key,
key_to_class=key_to_class,
key_to_meta=key_to_meta,
describe=describe,
builtin_key=builtin_key,
)
def add_selector_arg_parse(self, name, choices):

View File

@ -10,7 +10,8 @@ class Discovery(PluginLoader):
def get_discover(parser, args):
discover_types = Discovery.entry_points_for("virtualenv.discovery")
discovery_parser = parser.add_argument_group(
title="discovery", description="discover and provide a target interpreter",
title="discovery",
description="discover and provide a target interpreter",
)
discovery_parser.add_argument(
"--discovery",

View File

@ -17,7 +17,11 @@ class SeederSelector(ComponentBuilder):
help="seed packages install method",
)
self.parser.add_argument(
"--no-seed", "--without-pip", help="do not install seed packages", action="store_true", dest="no_seed",
"--no-seed",
"--without-pip",
help="do not install seed packages",
action="store_true",
dest="no_seed",
)
@staticmethod

View File

@ -62,7 +62,8 @@ class Session(object):
def _activate(self):
if self.activators:
logging.info(
"add activators for %s", ", ".join(type(i).__name__.replace("Activator", "") for i in self.activators),
"add activators for %s",
", ".join(type(i).__name__.replace("Activator", "") for i in self.activators),
)
for activator in self.activators:
activator.generate(self.creator)

View File

@ -109,7 +109,8 @@ class BaseEmbed(Seeder):
if getattr(self, "no_{}".format(distribution)):
continue
result += " {}{},".format(
distribution, "={}".format(getattr(self, "{}_version".format(distribution), None) or "latest"),
distribution,
"={}".format(getattr(self, "{}_version".format(distribution), None) or "latest"),
)
return result[:-1] + ")"

View File

@ -8,14 +8,10 @@ from contextlib import contextmanager
from subprocess import CalledProcessError
from threading import Lock, Thread
import six
from virtualenv.info import fs_supports_symlink
from virtualenv.seed.embed.base_embed import BaseEmbed
from virtualenv.seed.wheels import get_wheel
from virtualenv.util.lock import _CountedFileLock
from virtualenv.util.path import Path
from virtualenv.util.six import ensure_text
from .pip_install.copy import CopyPipInstall
from .pip_install.symlink import SymlinkPipInstall
@ -54,7 +50,8 @@ class FromAppData(BaseEmbed):
key = Path(installer_class.__name__) / wheel.path.stem
wheel_img = self.app_data.wheel_image(creator.interpreter.version_release_str, key)
installer = installer_class(wheel.path, creator, wheel_img)
with _CountedFileLock(ensure_text(str(wheel_img.parent / "{}.lock".format(wheel_img.name)))):
parent = self.app_data.lock / wheel_img.parent
with parent.non_reentrant_lock_for_key(wheel_img.name):
if not installer.has_image():
installer.build_image()
installer.install(creator.interpreter.version_info)
@ -104,7 +101,7 @@ class FromAppData(BaseEmbed):
if version is not None:
msg += " version {}".format(version)
msg += ", pip download exit code {}".format(failure.returncode)
output = failure.output if six.PY2 else (failure.output + failure.stderr)
output = failure.output if sys.version_info < (3, 5) else (failure.output + failure.stderr)
if output:
msg += "\n"
msg += output

Some files were not shown because too many files have changed in this diff Show More