[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
This commit is contained in:
pre-commit-ci[bot] 2024-04-13 00:00:18 +00:00
parent 72ad6dc953
commit f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions

View file

@ -13,32 +13,33 @@ The package resource API is designed to work with normal filesystem packages,
.zip files and with custom PEP 302 loaders that support the ``get_data()``
method.
"""
from __future__ import annotations
import sys
import os
import io
import time
import re
import types
import zipfile
import zipimport
import warnings
import stat
import functools
import pkgutil
import operator
import platform
import collections
import plistlib
import email.parser
import errno
import functools
import importlib
import inspect
import io
import itertools
import ntpath
import operator
import os
import pkgutil
import platform
import plistlib
import posixpath
import re
import stat
import sys
import tempfile
import textwrap
import itertools
import inspect
import ntpath
import posixpath
import importlib
import time
import types
import warnings
import zipfile
import zipimport
from pkgutil import get_importer
try:
@ -78,11 +79,6 @@ __import__('pkg_resources.extern.packaging.specifiers')
__import__('pkg_resources.extern.packaging.requirements')
__import__('pkg_resources.extern.packaging.markers')
if sys.version_info < (3, 5):
raise RuntimeError("Python 3.5 or later is required")
# declare some globals that will be defined later to
# satisfy the linters.
require = None
working_set = None
add_activation_listener = None
@ -174,9 +170,9 @@ def get_supported_platform():
"""
plat = get_build_platform()
m = macosVersionString.match(plat)
if m is not None and sys.platform == "darwin":
if m is not None and sys.platform == 'darwin':
try:
plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
plat = 'macosx-{}-{}'.format('.'.join(_macos_vers()[:2]), m.group(3))
except ValueError:
# not macOS
pass
@ -248,7 +244,7 @@ class VersionConflict(ResolutionError):
Requirement.
"""
_template = "{self.dist} is installed but {self.req} is required"
_template = '{self.dist} is installed but {self.req} is required'
@property
def dist(self):
@ -288,8 +284,10 @@ class ContextualVersionConflict(VersionConflict):
class DistributionNotFound(ResolutionError):
"""A requested distribution was not found"""
_template = ("The '{self.req}' distribution was not found "
"and is required by {self.requirers_str}")
_template = (
"The '{self.req}' distribution was not found "
'and is required by {self.requirers_str}'
)
@property
def req(self):
@ -378,11 +376,11 @@ def get_build_platform():
from sysconfig import get_platform
plat = get_platform()
if sys.platform == "darwin" and not plat.startswith('macosx-'):
if sys.platform == 'darwin' and not plat.startswith('macosx-'):
try:
version = _macos_vers()
machine = os.uname()[4].replace(" ", "_")
return "macosx-%d.%d-%s" % (
machine = os.uname()[4].replace(' ', '_')
return 'macosx-%d.%d-%s' % (
int(version[0]), int(version[1]),
_macos_arch(machine),
)
@ -393,8 +391,8 @@ def get_build_platform():
return plat
macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")
darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
macosVersionString = re.compile(r'macosx-(\d+)\.(\d+)-(.*)')
darwinVersionString = re.compile(r'darwin-(\d+)\.(\d+)\.(\d+)-(.*)')
# XXX backward compat
get_platform = get_build_platform
@ -423,9 +421,9 @@ def compatible_platforms(provided, required):
provDarwin = darwinVersionString.match(provided)
if provDarwin:
dversion = int(provDarwin.group(1))
macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
if dversion == 7 and macosversion >= "10.3" or \
dversion == 8 and macosversion >= "10.4":
macosversion = '{}.{}'.format(reqMac.group(1), reqMac.group(2))
if dversion == 7 and macosversion >= '10.3' or \
dversion == 8 and macosversion >= '10.4':
return True
# egg isn't macOS or legacy darwin
return False
@ -465,7 +463,7 @@ def get_distribution(dist):
if isinstance(dist, Requirement):
dist = get_provider(dist)
if not isinstance(dist, Distribution):
raise TypeError("Expected string, Requirement, or Distribution", dist)
raise TypeError('Expected string, Requirement, or Distribution', dist)
return dist
@ -698,8 +696,10 @@ class WorkingSet:
self._added_new(dist)
# FIXME: 'WorkingSet.resolve' is too complex (11)
def resolve(self, requirements, env=None, installer=None, # noqa: C901
replace_conflicting=False, extras=None):
def resolve(
self, requirements, env=None, installer=None, # noqa: C901
replace_conflicting=False, extras=None,
):
"""List all distributions needed to (recursively) meet `requirements`
`requirements` must be a sequence of ``Requirement`` objects. `env`,
@ -765,7 +765,7 @@ class WorkingSet:
ws = WorkingSet([])
dist = best[req.key] = env.best_match(
req, ws, installer,
replace_conflicting=replace_conflicting
replace_conflicting=replace_conflicting,
)
if dist is None:
requirers = required_by.get(req, None)
@ -791,7 +791,8 @@ class WorkingSet:
return to_activate
def find_plugins(
self, plugin_env, full_env=None, installer=None, fallback=True):
self, plugin_env, full_env=None, installer=None, fallback=True,
):
"""Find all activatable distributions in `plugin_env`
Example usage::
@ -911,7 +912,7 @@ class WorkingSet:
def __getstate__(self):
return (
self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
self.callbacks[:]
self.callbacks[:],
)
def __setstate__(self, e_k_b_c):
@ -947,7 +948,8 @@ class Environment:
def __init__(
self, search_path=None, platform=get_supported_platform(),
python=PY_MAJOR):
python=PY_MAJOR,
):
"""Snapshot distributions available on a search path
Any distributions found on `search_path` are added to the environment.
@ -977,9 +979,9 @@ class Environment:
is returned.
"""
py_compat = (
self.python is None
or dist.py_version is None
or dist.py_version == self.python
self.python is None or
dist.py_version is None or
dist.py_version == self.python
)
return py_compat and compatible_platforms(dist.platform, self.platform)
@ -1023,7 +1025,8 @@ class Environment:
dists.sort(key=operator.attrgetter('hashcmp'), reverse=True)
def best_match(
self, req, working_set, installer=None, replace_conflicting=False):
self, req, working_set, installer=None, replace_conflicting=False,
):
"""Find distribution best matching `req` and usable on `working_set`
This calls the ``find(req)`` method of the `working_set` to see if a
@ -1077,7 +1080,7 @@ class Environment:
for dist in other[project]:
self.add(dist)
else:
raise TypeError("Can't add %r to environment" % (other,))
raise TypeError("Can't add {!r} to environment".format(other))
return self
def __add__(self, other):
@ -1122,31 +1125,31 @@ class ResourceManager:
def resource_isdir(self, package_or_requirement, resource_name):
"""Is the named resource an existing directory?"""
return get_provider(package_or_requirement).resource_isdir(
resource_name
resource_name,
)
def resource_filename(self, package_or_requirement, resource_name):
"""Return a true filesystem path for specified resource"""
return get_provider(package_or_requirement).get_resource_filename(
self, resource_name
self, resource_name,
)
def resource_stream(self, package_or_requirement, resource_name):
"""Return a readable file-like object for specified resource"""
return get_provider(package_or_requirement).get_resource_stream(
self, resource_name
self, resource_name,
)
def resource_string(self, package_or_requirement, resource_name):
"""Return specified resource as a string"""
return get_provider(package_or_requirement).get_resource_string(
self, resource_name
self, resource_name,
)
def resource_listdir(self, package_or_requirement, resource_name):
"""List the contents of the named resource directory"""
return get_provider(package_or_requirement).resource_listdir(
resource_name
resource_name,
)
def extraction_error(self):
@ -1220,13 +1223,13 @@ class ResourceManager:
mode = os.stat(path).st_mode
if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
msg = (
"Extraction path is writable by group/others "
"and vulnerable to attack when "
"used with get_resource_filename ({path}). "
"Consider a more secure "
"location (set with .set_extraction_path or the "
"PYTHON_EGG_CACHE environment variable)."
).format(**locals())
f'Extraction path is writable by group/others '
f'and vulnerable to attack when '
f'used with get_resource_filename ({path}). '
f'Consider a more secure '
f'location (set with .set_extraction_path or the '
f'PYTHON_EGG_CACHE environment variable).'
)
warnings.warn(msg, UserWarning)
def postprocess(self, tempname, filename):
@ -1270,7 +1273,7 @@ class ResourceManager:
"""
if self.cached_files:
raise ValueError(
"Can't change extraction path, files already extracted"
"Can't change extraction path, files already extracted",
)
self.extraction_path = path
@ -1296,8 +1299,8 @@ def get_default_cache():
named "Python-Eggs".
"""
return (
os.environ.get('PYTHON_EGG_CACHE')
or appdirs.user_cache_dir(appname='Python-Eggs')
os.environ.get('PYTHON_EGG_CACHE') or
appdirs.user_cache_dir(appname='Python-Eggs')
)
@ -1402,7 +1405,7 @@ class NullProvider:
def get_metadata(self, name):
if not self.egg_info:
return ""
return ''
path = self._get_metadata_path(name)
value = self._get(path)
try:
@ -1410,7 +1413,7 @@ class NullProvider:
except UnicodeDecodeError as exc:
# Include the path in the error message to simplify
# troubleshooting, and without changing the exception type.
exc.reason += ' in {} file at path: {}'.format(name, path)
exc.reason += f' in {name} file at path: {path}'
raise
def get_metadata_lines(self, name):
@ -1434,8 +1437,7 @@ class NullProvider:
script = 'scripts/' + script_name
if not self.has_metadata(script):
raise ResolutionError(
"Script {script!r} not found in metadata at {self.egg_info!r}"
.format(**locals()),
f'Script {script!r} not found in metadata at {self.egg_info!r}',
)
script_text = self.get_metadata(script).replace('\r\n', '\n')
script_text = script_text.replace('\r', '\n')
@ -1449,24 +1451,24 @@ class NullProvider:
else:
from linecache import cache
cache[script_filename] = (
len(script_text), 0, script_text.split('\n'), script_filename
len(script_text), 0, script_text.split('\n'), script_filename,
)
script_code = compile(script_text, script_filename, 'exec')
exec(script_code, namespace, namespace)
def _has(self, path):
raise NotImplementedError(
"Can't perform this operation for unregistered loader type"
"Can't perform this operation for unregistered loader type",
)
def _isdir(self, path):
raise NotImplementedError(
"Can't perform this operation for unregistered loader type"
"Can't perform this operation for unregistered loader type",
)
def _listdir(self, path):
raise NotImplementedError(
"Can't perform this operation for unregistered loader type"
"Can't perform this operation for unregistered loader type",
)
def _fn(self, base, resource_name):
@ -1536,7 +1538,7 @@ is not allowed.
if not invalid:
return
msg = "Use of .. or absolute path in a resource path is not allowed."
msg = 'Use of .. or absolute path in a resource path is not allowed.'
# Aggressively disallow Windows absolute paths
if ntpath.isabs(path) and not posixpath.isabs(path):
@ -1545,7 +1547,7 @@ is not allowed.
# for compatibility, warn; in future
# raise ValueError(msg)
warnings.warn(
msg[:-1] + " and will raise exceptions in a future release.",
msg[:-1] + ' and will raise exceptions in a future release.',
DeprecationWarning,
stacklevel=4,
)
@ -1554,7 +1556,7 @@ is not allowed.
if hasattr(self.loader, 'get_data'):
return self.loader.get_data(path)
raise NotImplementedError(
"Can't perform this operation for loaders without 'get_data()'"
"Can't perform this operation for loaders without 'get_data()'",
)
@ -1708,7 +1710,7 @@ class ZipProvider(EggProvider):
if fspath.startswith(self.zip_pre):
return fspath[len(self.zip_pre):]
raise AssertionError(
"%s is not a subpath of %s" % (fspath, self.zip_pre)
'{} is not a subpath of {}'.format(fspath, self.zip_pre),
)
def _parts(self, zip_path):
@ -1718,7 +1720,7 @@ class ZipProvider(EggProvider):
if fspath.startswith(self.egg_root + os.sep):
return fspath[len(self.egg_root) + 1:].split(os.sep)
raise AssertionError(
"%s is not a subpath of %s" % (fspath, self.egg_root)
'{} is not a subpath of {}'.format(fspath, self.egg_root),
)
@property
@ -1728,7 +1730,7 @@ class ZipProvider(EggProvider):
def get_resource_filename(self, manager, resource_name):
if not self.egg_name:
raise NotImplementedError(
"resource_filename() only supported for .egg, not .zip"
'resource_filename() only supported for .egg, not .zip',
)
# no need to lock for extraction, since we use temp names
zip_path = self._resource_to_zip(resource_name)
@ -1753,7 +1755,7 @@ class ZipProvider(EggProvider):
if zip_path in self._index():
for name in self._index()[zip_path]:
last = self._extract_resource(
manager, os.path.join(zip_path, name)
manager, os.path.join(zip_path, name),
)
# return the extracted directory name
return os.path.dirname(last)
@ -1761,19 +1763,21 @@ class ZipProvider(EggProvider):
timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
if not WRITE_SUPPORT:
raise IOError('"os.rename" and "os.unlink" are not supported '
'on this platform')
raise OSError(
'"os.rename" and "os.unlink" are not supported '
'on this platform',
)
try:
real_path = manager.get_cache_path(
self.egg_name, self._parts(zip_path)
self.egg_name, self._parts(zip_path),
)
if self._is_current(real_path, zip_path):
return real_path
outf, tmpnam = _mkstemp(
".$extract",
'.$extract',
dir=os.path.dirname(real_path),
)
os.write(outf, self.loader.get_data(zip_path))
@ -1784,7 +1788,7 @@ class ZipProvider(EggProvider):
try:
rename(tmpnam, real_path)
except os.error:
except OSError:
if os.path.isfile(real_path):
if self._is_current(real_path, zip_path):
# the file became current since it was checked above,
@ -1797,7 +1801,7 @@ class ZipProvider(EggProvider):
return real_path
raise
except os.error:
except OSError:
# report a user-friendly error
manager.extraction_error()
@ -1888,9 +1892,9 @@ class FileMetadata(EmptyProvider):
def get_metadata(self, name):
if name != 'PKG-INFO':
raise KeyError("No metadata except PKG-INFO is available")
raise KeyError('No metadata except PKG-INFO is available')
with io.open(self.path, encoding='utf-8', errors="replace") as f:
with open(self.path, encoding='utf-8', errors='replace') as f:
metadata = f.read()
self._warn_on_replacement(metadata)
return metadata
@ -1898,7 +1902,7 @@ class FileMetadata(EmptyProvider):
def _warn_on_replacement(self, metadata):
replacement_char = '<EFBFBD>'
if replacement_char in metadata:
tmpl = "{self.path} could not be properly decoded in UTF-8"
tmpl = '{self.path} could not be properly decoded in UTF-8'
msg = tmpl.format(**locals())
warnings.warn(msg)
@ -1984,8 +1988,7 @@ def find_eggs_in_zip(importer, path_item, only=False):
if _is_egg_path(subitem):
subpath = os.path.join(path_item, subitem)
dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath)
for dist in dists:
yield dist
yield from dists
elif subitem.lower().endswith(('.dist-info', '.egg-info')):
subpath = os.path.join(path_item, subitem)
submeta = EggMetadata(zipimport.zipimporter(subpath))
@ -2036,8 +2039,8 @@ def find_on_path(importer, path_item, only=False):
if _is_unpacked_egg(path_item):
yield Distribution.from_filename(
path_item, metadata=PathMetadata(
path_item, os.path.join(path_item, 'EGG-INFO')
)
path_item, os.path.join(path_item, 'EGG-INFO'),
),
)
return
@ -2060,8 +2063,7 @@ def find_on_path(importer, path_item, only=False):
for entry in path_item_entries:
fullpath = os.path.join(path_item, entry)
factory = dist_factory(path_item, entry, only)
for dist in factory(fullpath):
yield dist
yield from factory(fullpath)
def dist_factory(path_item, entry, only):
@ -2092,6 +2094,7 @@ class NoDists:
>>> list(NoDists()('anything'))
[]
"""
def __bool__(self):
return False
@ -2195,7 +2198,7 @@ def _handle_ns(packageName, path_item):
except AttributeError:
# capture warnings due to #1111
with warnings.catch_warnings():
warnings.simplefilter("ignore")
warnings.simplefilter('ignore')
loader = importer.find_module(packageName)
if loader is None:
@ -2206,7 +2209,7 @@ def _handle_ns(packageName, path_item):
module.__path__ = []
_set_parent_ns(packageName)
elif not hasattr(module, '__path__'):
raise TypeError("Not a package:", packageName)
raise TypeError('Not a package:', packageName)
handler = _find_adapter(_namespace_handlers, importer)
subpath = handler(importer, path_item, packageName, module)
if subpath is not None:
@ -2269,7 +2272,7 @@ def declare_namespace(packageName):
try:
path = sys.modules[parent].__path__
except AttributeError as e:
raise TypeError("Not a package:", parent) from e
raise TypeError('Not a package:', parent) from e
# Track what packages are namespaces, so when new path items are added,
# they can be updated
@ -2326,8 +2329,13 @@ register_namespace_handler(object, null_ns_handler)
def normalize_path(filename):
"""Normalize a file/dir name for comparison purposes"""
return os.path.normcase(os.path.realpath(os.path.normpath(
_cygwin_patch(filename))))
return os.path.normcase(
os.path.realpath(
os.path.normpath(
_cygwin_patch(filename),
),
),
)
def _cygwin_patch(filename): # pragma: nocover
@ -2396,7 +2404,7 @@ def yield_lines(strs):
yield s
MODULE = re.compile(r"\w+(\.\w+)*$").match
MODULE = re.compile(r'\w+(\.\w+)*$').match
EGG_NAME = re.compile(
r"""
(?P<name>[^-]+) (
@ -2416,7 +2424,7 @@ class EntryPoint:
def __init__(self, name, module_name, attrs=(), extras=(), dist=None):
if not MODULE(module_name):
raise ValueError("Invalid module name", module_name)
raise ValueError('Invalid module name', module_name)
self.name = name
self.module_name = module_name
self.attrs = tuple(attrs)
@ -2424,7 +2432,7 @@ class EntryPoint:
self.dist = dist
def __str__(self):
s = "%s = %s" % (self.name, self.module_name)
s = '{} = {}'.format(self.name, self.module_name)
if self.attrs:
s += ':' + '.'.join(self.attrs)
if self.extras:
@ -2432,7 +2440,7 @@ class EntryPoint:
return s
def __repr__(self):
return "EntryPoint.parse(%r)" % str(self)
return 'EntryPoint.parse(%r)' % str(self)
def load(self, require=True, *args, **kwargs):
"""
@ -2440,8 +2448,8 @@ class EntryPoint:
"""
if not require or args or kwargs:
warnings.warn(
"Parameters to load are deprecated. Call .resolve and "
".require separately.",
'Parameters to load are deprecated. Call .resolve and '
'.require separately.',
PkgResourcesDeprecationWarning,
stacklevel=2,
)
@ -2478,7 +2486,7 @@ class EntryPoint:
r'=\s*'
r'(?P<module>[\w.]+)\s*'
r'(:\s*(?P<attr>[\w.]+))?\s*'
r'(?P<extras>\[.*\])?\s*$'
r'(?P<extras>\[.*\])?\s*$',
)
@classmethod
@ -2514,12 +2522,12 @@ class EntryPoint:
def parse_group(cls, group, lines, dist=None):
"""Parse an entry point group"""
if not MODULE(group):
raise ValueError("Invalid group name", group)
raise ValueError('Invalid group name', group)
this = {}
for line in yield_lines(lines):
ep = cls.parse(line, dist)
if ep.name in this:
raise ValueError("Duplicate entry point", group, ep.name)
raise ValueError('Duplicate entry point', group, ep.name)
this[ep.name] = ep
return this
@ -2535,10 +2543,10 @@ class EntryPoint:
if group is None:
if not lines:
continue
raise ValueError("Entry points must be listed in groups")
raise ValueError('Entry points must be listed in groups')
group = group.strip()
if group in maps:
raise ValueError("Duplicate group name", group)
raise ValueError('Duplicate group name', group)
maps[group] = cls.parse_group(group, lines, dist)
return maps
@ -2563,7 +2571,8 @@ class Distribution:
def __init__(
self, location=None, metadata=None, project_name=None,
version=None, py_version=PY_MAJOR, platform=None,
precedence=EGG_DIST):
precedence=EGG_DIST,
):
self.project_name = safe_name(project_name or 'Unknown')
if version is not None:
self._version = safe_version(version)
@ -2583,11 +2592,11 @@ class Distribution:
match = EGG_NAME(basename)
if match:
project_name, version, py_version, platform = match.group(
'name', 'ver', 'pyver', 'plat'
'name', 'ver', 'pyver', 'plat',
)
return cls(
location, metadata, project_name=project_name, version=version,
py_version=py_version, platform=platform, **kw
py_version=py_version, platform=platform, **kw,
)._reload_version()
def _reload_version(self):
@ -2642,7 +2651,7 @@ class Distribution:
@property
def parsed_version(self):
if not hasattr(self, "_parsed_version"):
if not hasattr(self, '_parsed_version'):
self._parsed_version = parse_version(self.version)
return self._parsed_version
@ -2712,8 +2721,8 @@ class Distribution:
reqs = dm.pop(extra)
new_extra, _, marker = extra.partition(':')
fails_marker = marker and (
invalid_marker(marker)
or not evaluate_marker(marker)
invalid_marker(marker) or
not evaluate_marker(marker)
)
if fails_marker:
reqs = []
@ -2739,7 +2748,7 @@ class Distribution:
deps.extend(dm[safe_extra(ext)])
except KeyError as e:
raise UnknownExtra(
"%s has no such extra feature %r" % (self, ext)
'{} has no such extra feature {!r}'.format(self, ext),
) from e
return deps
@ -2762,8 +2771,7 @@ class Distribution:
def _get_metadata(self, name):
if self.has_metadata(name):
for line in self.get_metadata_lines(name):
yield line
yield from self.get_metadata_lines(name)
def _get_version(self):
lines = self._get_metadata(self.PKG_INFO)
@ -2784,9 +2792,9 @@ class Distribution:
def egg_name(self):
"""Return what this distribution's standard .egg filename should be"""
filename = "%s-%s-py%s" % (
filename = '{}-{}-py{}'.format(
to_filename(self.project_name), to_filename(self.version),
self.py_version or PY_MAJOR
self.py_version or PY_MAJOR,
)
if self.platform:
@ -2795,7 +2803,7 @@ class Distribution:
def __repr__(self):
if self.location:
return "%s (%s)" % (self, self.location)
return '{} ({})'.format(self, self.location)
else:
return str(self)
@ -2804,8 +2812,8 @@ class Distribution:
version = getattr(self, 'version', None)
except ValueError:
version = None
version = version or "[unknown version]"
return "%s %s" % (self.project_name, version)
version = version or '[unknown version]'
return '{} {}'.format(self.project_name, version)
def __getattr__(self, attr):
"""Delegate all unrecognized public attributes to .metadata provider"""
@ -2815,26 +2823,26 @@ class Distribution:
def __dir__(self):
return list(
set(super(Distribution, self).__dir__())
| set(
set(super().__dir__()) |
{
attr for attr in self._provider.__dir__()
if not attr.startswith('_')
)
},
)
@classmethod
def from_filename(cls, filename, metadata=None, **kw):
return cls.from_location(
_normalize_cached(filename), os.path.basename(filename), metadata,
**kw
**kw,
)
def as_requirement(self):
"""Return a ``Requirement`` that matches this distribution exactly"""
if isinstance(self.parsed_version, packaging.version.Version):
spec = "%s==%s" % (self.project_name, self.parsed_version)
spec = '{}=={}'.format(self.project_name, self.parsed_version)
else:
spec = "%s===%s" % (self.project_name, self.parsed_version)
spec = '{}==={}'.format(self.project_name, self.parsed_version)
return Requirement.parse(spec)
@ -2842,7 +2850,7 @@ class Distribution:
"""Return the `name` entry point of `group` or raise ImportError"""
ep = self.get_entry_info(group, name)
if ep is None:
raise ImportError("Entry point %r not found" % ((group, name),))
raise ImportError('Entry point {!r} not found'.format((group, name)))
return ep.load()
def get_entry_map(self, group=None):
@ -2851,7 +2859,7 @@ class Distribution:
ep_map = self._ep_map
except AttributeError:
ep_map = self._ep_map = EntryPoint.parse_map(
self._get_metadata('entry_points.txt'), self
self._get_metadata('entry_points.txt'), self,
)
if group is not None:
return ep_map.get(group, {})
@ -2938,25 +2946,29 @@ class Distribution:
nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt'))
loc = normalize_path(self.location)
for modname in self._get_metadata('top_level.txt'):
if (modname not in sys.modules or modname in nsp
or modname in _namespace_packages):
if (
modname not in sys.modules or modname in nsp or
modname in _namespace_packages
):
continue
if modname in ('pkg_resources', 'setuptools', 'site'):
continue
fn = getattr(sys.modules[modname], '__file__', None)
if fn and (normalize_path(fn).startswith(loc) or
fn.startswith(self.location)):
if fn and (
normalize_path(fn).startswith(loc) or
fn.startswith(self.location)
):
continue
issue_warning(
"Module %s was already imported from %s, but %s is being added"
" to sys.path" % (modname, fn, self.location),
'Module %s was already imported from %s, but %s is being added'
' to sys.path' % (modname, fn, self.location),
)
def has_version(self):
try:
self.version
except ValueError:
issue_warning("Unbuilt egg for " + repr(self))
issue_warning('Unbuilt egg for ' + repr(self))
return False
return True
@ -2998,7 +3010,7 @@ class DistInfoDistribution(Distribution):
w/metadata, .dist-info style.
"""
PKG_INFO = 'METADATA'
EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")
EQEQ = re.compile(r'([\(,])\s*(\d.*?)\s*([,\)])')
@property
def _parsed_pkg_info(self):
@ -3085,18 +3097,19 @@ def parse_requirements(strs):
class RequirementParseError(packaging.requirements.InvalidRequirement):
"Compatibility wrapper for InvalidRequirement"
'Compatibility wrapper for InvalidRequirement'
class Requirement(packaging.requirements.Requirement):
def __init__(self, requirement_string):
"""DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
super(Requirement, self).__init__(requirement_string)
super().__init__(requirement_string)
self.unsafe_name = self.name
project_name = safe_name(self.name)
self.project_name, self.key = project_name, project_name.lower()
self.specs = [
(spec.operator, spec.version) for spec in self.specifier]
(spec.operator, spec.version) for spec in self.specifier
]
self.extras = tuple(map(safe_extra, self.extras))
self.hashCmp = (
self.key,
@ -3132,7 +3145,7 @@ class Requirement(packaging.requirements.Requirement):
return self.__hash
def __repr__(self):
return "Requirement.parse(%r)" % str(self)
return 'Requirement.parse(%r)' % str(self)
@staticmethod
def parse(s):
@ -3167,7 +3180,7 @@ def ensure_directory(path):
def _bypass_ensure_directory(path):
"""Sandbox-bypassing version of ensure_directory()"""
if not WRITE_SUPPORT:
raise IOError('"os.mkdir" not supported on this platform.')
raise OSError('"os.mkdir" not supported on this platform.')
dirname, filename = split(path)
if dirname and filename and not isdir(dirname):
_bypass_ensure_directory(dirname)
@ -3188,14 +3201,14 @@ def split_sections(s):
section = None
content = []
for line in yield_lines(s):
if line.startswith("["):
if line.endswith("]"):
if line.startswith('['):
if line.endswith(']'):
if section or content:
yield section, content
section = line[1:-1].strip()
content = []
else:
raise ValueError("Invalid section heading", line)
raise ValueError('Invalid section heading', line)
else:
content.append(line)
@ -3218,7 +3231,7 @@ def _mkstemp(*args, **kw):
# randomly just because they use pkg_resources. We want to append the rule
# because we want earlier uses of filterwarnings to take precedence over this
# one.
warnings.filterwarnings("ignore", category=PEP440Warning, append=True)
warnings.filterwarnings('ignore', category=PEP440Warning, append=True)
# from jaraco.functools 1.3
@ -3229,7 +3242,7 @@ def _call_aside(f, *args, **kwargs):
@_call_aside
def _initialize(g=globals()):
"Set up global resource manager (deliberately not state-saved)"
'Set up global resource manager (deliberately not state-saved)'
manager = ResourceManager()
g['_manager'] = manager
g.update(

View file

@ -1,8 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2005-2010 ActiveState Software Inc.
# Copyright (c) 2013 Eddy Petrișor
"""Utilities for determining application-specific dirs.
See <http://github.com/ActiveState/appdirs> for details and usage.
@ -12,6 +10,7 @@ See <http://github.com/ActiveState/appdirs> for details and usage.
# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
from __future__ import annotations
__version_info__ = (1, 4, 3)
__version__ = '.'.join(map(str, __version_info__))
@ -28,11 +27,11 @@ if PY3:
if sys.platform.startswith('java'):
import platform
os_name = platform.java_ver()[3][0]
if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
system = 'win32'
elif os_name.startswith('Mac'): # "Mac OS X", etc.
elif os_name.startswith('Mac'): # "Mac OS X", etc.
system = 'darwin'
else: # "Linux", "SunOS", "FreeBSD", etc.
else: # "Linux", "SunOS", "FreeBSD", etc.
# Setting this to "linux2" is not ideal, but only Windows or Mac
# are actually checked for and the rest of the module expects
# *sys.platform* style strings.
@ -41,7 +40,6 @@ else:
system = sys.platform
def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
r"""Return full path to the user-specific data dir for this application.
@ -74,10 +72,10 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
That means, by default "~/.local/share/<AppName>".
"""
if system == "win32":
if system == 'win32':
if appauthor is None:
appauthor = appname
const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
const = roaming and 'CSIDL_APPDATA' or 'CSIDL_LOCAL_APPDATA'
path = os.path.normpath(_get_win_folder(const))
if appname:
if appauthor is not False:
@ -89,7 +87,7 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
if appname:
path = os.path.join(path, appname)
else:
path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
path = os.getenv('XDG_DATA_HOME', os.path.expanduser('~/.local/share'))
if appname:
path = os.path.join(path, appname)
if appname and version:
@ -128,10 +126,10 @@ def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
"""
if system == "win32":
if system == 'win32':
if appauthor is None:
appauthor = appname
path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
path = os.path.normpath(_get_win_folder('CSIDL_COMMON_APPDATA'))
if appname:
if appauthor is not False:
path = os.path.join(path, appauthor, appname)
@ -144,8 +142,10 @@ def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
else:
# XDG default for $XDG_DATA_DIRS
# only first, if multipath is False
path = os.getenv('XDG_DATA_DIRS',
os.pathsep.join(['/usr/local/share', '/usr/share']))
path = os.getenv(
'XDG_DATA_DIRS',
os.pathsep.join(['/usr/local/share', '/usr/share']),
)
pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
if appname:
if version:
@ -192,10 +192,10 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
That means, by default "~/.config/<AppName>".
"""
if system in ["win32", "darwin"]:
if system in ['win32', 'darwin']:
path = user_data_dir(appname, appauthor, None, roaming)
else:
path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config'))
if appname:
path = os.path.join(path, appname)
if appname and version:
@ -233,7 +233,7 @@ def site_config_dir(appname=None, appauthor=None, version=None, multipath=False)
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
"""
if system in ["win32", "darwin"]:
if system in ['win32', 'darwin']:
path = site_data_dir(appname, appauthor)
if appname and version:
path = os.path.join(path, version)
@ -287,17 +287,17 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
This can be disabled with the `opinion=False` option.
"""
if system == "win32":
if system == 'win32':
if appauthor is None:
appauthor = appname
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
path = os.path.normpath(_get_win_folder('CSIDL_LOCAL_APPDATA'))
if appname:
if appauthor is not False:
path = os.path.join(path, appauthor, appname)
else:
path = os.path.join(path, appname)
if opinion:
path = os.path.join(path, "Cache")
path = os.path.join(path, 'Cache')
elif system == 'darwin':
path = os.path.expanduser('~/Library/Caches')
if appname:
@ -342,10 +342,10 @@ def user_state_dir(appname=None, appauthor=None, version=None, roaming=False):
That means, by default "~/.local/state/<AppName>".
"""
if system in ["win32", "darwin"]:
if system in ['win32', 'darwin']:
path = user_data_dir(appname, appauthor, None, roaming)
else:
path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state"))
path = os.getenv('XDG_STATE_HOME', os.path.expanduser('~/.local/state'))
if appname:
path = os.path.join(path, appname)
if appname and version:
@ -385,29 +385,33 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
value for Windows and appends "log" to the user cache dir for Unix.
This can be disabled with the `opinion=False` option.
"""
if system == "darwin":
if system == 'darwin':
path = os.path.join(
os.path.expanduser('~/Library/Logs'),
appname)
elif system == "win32":
appname,
)
elif system == 'win32':
path = user_data_dir(appname, appauthor, version)
version = False
if opinion:
path = os.path.join(path, "Logs")
path = os.path.join(path, 'Logs')
else:
path = user_cache_dir(appname, appauthor, version)
version = False
if opinion:
path = os.path.join(path, "log")
path = os.path.join(path, 'log')
if appname and version:
path = os.path.join(path, version)
return path
class AppDirs(object):
class AppDirs:
"""Convenience wrapper for getting application dirs."""
def __init__(self, appname=None, appauthor=None, version=None,
roaming=False, multipath=False):
def __init__(
self, appname=None, appauthor=None, version=None,
roaming=False, multipath=False,
):
self.appname = appname
self.appauthor = appauthor
self.version = version
@ -416,38 +420,52 @@ class AppDirs(object):
@property
def user_data_dir(self):
return user_data_dir(self.appname, self.appauthor,
version=self.version, roaming=self.roaming)
return user_data_dir(
self.appname, self.appauthor,
version=self.version, roaming=self.roaming,
)
@property
def site_data_dir(self):
return site_data_dir(self.appname, self.appauthor,
version=self.version, multipath=self.multipath)
return site_data_dir(
self.appname, self.appauthor,
version=self.version, multipath=self.multipath,
)
@property
def user_config_dir(self):
return user_config_dir(self.appname, self.appauthor,
version=self.version, roaming=self.roaming)
return user_config_dir(
self.appname, self.appauthor,
version=self.version, roaming=self.roaming,
)
@property
def site_config_dir(self):
return site_config_dir(self.appname, self.appauthor,
version=self.version, multipath=self.multipath)
return site_config_dir(
self.appname, self.appauthor,
version=self.version, multipath=self.multipath,
)
@property
def user_cache_dir(self):
return user_cache_dir(self.appname, self.appauthor,
version=self.version)
return user_cache_dir(
self.appname, self.appauthor,
version=self.version,
)
@property
def user_state_dir(self):
return user_state_dir(self.appname, self.appauthor,
version=self.version)
return user_state_dir(
self.appname, self.appauthor,
version=self.version,
)
@property
def user_log_dir(self):
return user_log_dir(self.appname, self.appauthor,
version=self.version)
return user_log_dir(
self.appname, self.appauthor,
version=self.version,
)
#---- internal support stuff
@ -458,19 +476,19 @@ def _get_win_folder_from_registry(csidl_name):
names.
"""
if PY3:
import winreg as _winreg
import winreg as _winreg
else:
import _winreg
import _winreg
shell_folder_name = {
"CSIDL_APPDATA": "AppData",
"CSIDL_COMMON_APPDATA": "Common AppData",
"CSIDL_LOCAL_APPDATA": "Local AppData",
'CSIDL_APPDATA': 'AppData',
'CSIDL_COMMON_APPDATA': 'Common AppData',
'CSIDL_LOCAL_APPDATA': 'Local AppData',
}[csidl_name]
key = _winreg.OpenKey(
_winreg.HKEY_CURRENT_USER,
r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',
)
dir, type = _winreg.QueryValueEx(key, shell_folder_name)
return dir
@ -507,9 +525,9 @@ def _get_win_folder_with_ctypes(csidl_name):
import ctypes
csidl_const = {
"CSIDL_APPDATA": 26,
"CSIDL_COMMON_APPDATA": 35,
"CSIDL_LOCAL_APPDATA": 28,
'CSIDL_APPDATA': 26,
'CSIDL_COMMON_APPDATA': 35,
'CSIDL_LOCAL_APPDATA': 28,
}[csidl_name]
buf = ctypes.create_unicode_buffer(1024)
@ -529,6 +547,7 @@ def _get_win_folder_with_ctypes(csidl_name):
return buf.value
def _get_win_folder_with_jna(csidl_name):
import array
from com.sun import jna
@ -538,7 +557,7 @@ def _get_win_folder_with_jna(csidl_name):
buf = array.zeros('c', buf_size)
shell = win32.Shell32.INSTANCE
shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
dir = jna.Native.toString(buf.tostring()).rstrip('\0')
# Downgrade to short path name if have highbit chars. See
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
@ -551,11 +570,12 @@ def _get_win_folder_with_jna(csidl_name):
buf = array.zeros('c', buf_size)
kernel = win32.Kernel32.INSTANCE
if kernel.GetShortPathName(dir, buf, buf_size):
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
dir = jna.Native.toString(buf.tostring()).rstrip('\0')
return dir
if system == "win32":
if system == 'win32':
try:
import win32com.shell
_get_win_folder = _get_win_folder_with_pywin32
@ -573,36 +593,38 @@ if system == "win32":
#---- self test code
if __name__ == "__main__":
appname = "MyApp"
appauthor = "MyCompany"
if __name__ == '__main__':
appname = 'MyApp'
appauthor = 'MyCompany'
props = ("user_data_dir",
"user_config_dir",
"user_cache_dir",
"user_state_dir",
"user_log_dir",
"site_data_dir",
"site_config_dir")
props = (
'user_data_dir',
'user_config_dir',
'user_cache_dir',
'user_state_dir',
'user_log_dir',
'site_data_dir',
'site_config_dir',
)
print("-- app dirs %s --" % __version__)
print('-- app dirs %s --' % __version__)
print("-- app dirs (with optional 'version')")
dirs = AppDirs(appname, appauthor, version="1.0")
dirs = AppDirs(appname, appauthor, version='1.0')
for prop in props:
print("%s: %s" % (prop, getattr(dirs, prop)))
print('{}: {}'.format(prop, getattr(dirs, prop)))
print("\n-- app dirs (without optional 'version')")
dirs = AppDirs(appname, appauthor)
for prop in props:
print("%s: %s" % (prop, getattr(dirs, prop)))
print('{}: {}'.format(prop, getattr(dirs, prop)))
print("\n-- app dirs (without optional 'appauthor')")
dirs = AppDirs(appname)
for prop in props:
print("%s: %s" % (prop, getattr(dirs, prop)))
print('{}: {}'.format(prop, getattr(dirs, prop)))
print("\n-- app dirs (with disabled 'appauthor')")
dirs = AppDirs(appname, appauthor=False)
for prop in props:
print("%s: %s" % (prop, getattr(dirs, prop)))
print('{}: {}'.format(prop, getattr(dirs, prop)))

View file

@ -1,27 +1,27 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
__all__ = [
"__title__",
"__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
'__title__',
'__summary__',
'__uri__',
'__version__',
'__author__',
'__email__',
'__license__',
'__copyright__',
]
__title__ = "packaging"
__summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging"
__title__ = 'packaging'
__summary__ = 'Core utilities for Python packages'
__uri__ = 'https://github.com/pypa/packaging'
__version__ = "20.4"
__version__ = '20.4'
__author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io"
__author__ = 'Donald Stufft and individual contributors'
__email__ = 'donald@stufft.io'
__license__ = "BSD-2-Clause or Apache-2.0"
__copyright__ = "Copyright 2014-2019 %s" % __author__
__license__ = 'BSD-2-Clause or Apache-2.0'
__copyright__ = 'Copyright 2014-2019 %s' % __author__

View file

@ -1,26 +1,24 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
from .__about__ import (
__author__,
__copyright__,
__email__,
__license__,
__summary__,
__title__,
__uri__,
__version__,
)
from .__about__ import __author__
from .__about__ import __copyright__
from .__about__ import __email__
from .__about__ import __license__
from .__about__ import __summary__
from .__about__ import __title__
from .__about__ import __uri__
from .__about__ import __version__
__all__ = [
"__title__",
"__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
'__title__',
'__summary__',
'__uri__',
'__version__',
'__author__',
'__email__',
'__license__',
'__copyright__',
]

View file

@ -1,7 +1,7 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import sys
@ -35,4 +35,4 @@ def with_metaclass(meta, *bases):
# type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any
return meta(name, bases, d)
return type.__new__(metaclass, "temporary_class", (), {})
return type.__new__(metaclass, 'temporary_class', (), {})

View file

@ -1,13 +1,13 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
class InfinityType(object):
class InfinityType:
def __repr__(self):
# type: () -> str
return "Infinity"
return 'Infinity'
def __hash__(self):
# type: () -> int
@ -45,10 +45,10 @@ class InfinityType(object):
Infinity = InfinityType()
class NegativeInfinityType(object):
class NegativeInfinityType:
def __repr__(self):
# type: () -> str
return "-Infinity"
return '-Infinity'
def __hash__(self):
# type: () -> int

View file

@ -25,8 +25,9 @@ In packaging, all static-typing related imports should be guarded as follows:
Ref: https://github.com/python/mypy/issues/3216
"""
from __future__ import annotations
__all__ = ["TYPE_CHECKING", "cast"]
__all__ = ['TYPE_CHECKING', 'cast']
# The TYPE_CHECKING constant defined by the typing module is False at runtime
# but True while type checking.

View file

@ -1,20 +1,27 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import operator
import os
import platform
import sys
from pkg_resources.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd
from pkg_resources.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString
from pkg_resources.extern.pyparsing import Forward
from pkg_resources.extern.pyparsing import Group
from pkg_resources.extern.pyparsing import Literal as L # noqa
from pkg_resources.extern.pyparsing import ParseException
from pkg_resources.extern.pyparsing import ParseResults
from pkg_resources.extern.pyparsing import QuotedString
from pkg_resources.extern.pyparsing import stringEnd
from pkg_resources.extern.pyparsing import stringStart
from pkg_resources.extern.pyparsing import ZeroOrMore
from ._compat import string_types
from ._typing import TYPE_CHECKING
from .specifiers import Specifier, InvalidSpecifier
from .specifiers import InvalidSpecifier
from .specifiers import Specifier
if TYPE_CHECKING: # pragma: no cover
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
@ -23,11 +30,11 @@ if TYPE_CHECKING: # pragma: no cover
__all__ = [
"InvalidMarker",
"UndefinedComparison",
"UndefinedEnvironmentName",
"Marker",
"default_environment",
'InvalidMarker',
'UndefinedComparison',
'UndefinedEnvironmentName',
'Marker',
'default_environment',
]
@ -50,7 +57,7 @@ class UndefinedEnvironmentName(ValueError):
"""
class Node(object):
class Node:
def __init__(self, value):
# type: (Any) -> None
self.value = value
@ -61,7 +68,7 @@ class Node(object):
def __repr__(self):
# type: () -> str
return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
return f'<{self.__class__.__name__}({str(self)!r})>'
def serialize(self):
# type: () -> str
@ -77,7 +84,7 @@ class Variable(Node):
class Value(Node):
def serialize(self):
# type: () -> str
return '"{0}"'.format(self)
return f'"{self}"'
class Op(Node):
@ -87,54 +94,54 @@ class Op(Node):
VARIABLE = (
L("implementation_version")
| L("platform_python_implementation")
| L("implementation_name")
| L("python_full_version")
| L("platform_release")
| L("platform_version")
| L("platform_machine")
| L("platform_system")
| L("python_version")
| L("sys_platform")
| L("os_name")
| L("os.name") # PEP-345
| L("sys.platform") # PEP-345
| L("platform.version") # PEP-345
| L("platform.machine") # PEP-345
| L("platform.python_implementation") # PEP-345
| L("python_implementation") # undocumented setuptools legacy
| L("extra") # PEP-508
L('implementation_version') |
L('platform_python_implementation') |
L('implementation_name') |
L('python_full_version') |
L('platform_release') |
L('platform_version') |
L('platform_machine') |
L('platform_system') |
L('python_version') |
L('sys_platform') |
L('os_name') |
L('os.name') | # PEP-345
L('sys.platform') | # PEP-345
L('platform.version') | # PEP-345
L('platform.machine') | # PEP-345
L('platform.python_implementation') | # PEP-345
L('python_implementation') | # undocumented setuptools legacy
L('extra') # PEP-508
)
ALIASES = {
"os.name": "os_name",
"sys.platform": "sys_platform",
"platform.version": "platform_version",
"platform.machine": "platform_machine",
"platform.python_implementation": "platform_python_implementation",
"python_implementation": "platform_python_implementation",
'os.name': 'os_name',
'sys.platform': 'sys_platform',
'platform.version': 'platform_version',
'platform.machine': 'platform_machine',
'platform.python_implementation': 'platform_python_implementation',
'python_implementation': 'platform_python_implementation',
}
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
VERSION_CMP = (
L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
L('===') | L('==') | L('>=') | L('<=') | L('!=') | L('~=') | L('>') | L('<')
)
MARKER_OP = VERSION_CMP | L("not in") | L("in")
MARKER_OP = VERSION_CMP | L('not in') | L('in')
MARKER_OP.setParseAction(lambda s, l, t: Op(t[0]))
MARKER_VALUE = QuotedString("'") | QuotedString('"')
MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0]))
BOOLOP = L("and") | L("or")
BOOLOP = L('and') | L('or')
MARKER_VAR = VARIABLE | MARKER_VALUE
MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR)
MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0]))
LPAREN = L("(").suppress()
RPAREN = L(")").suppress()
LPAREN = L('(').suppress()
RPAREN = L(')').suppress()
MARKER_EXPR = Forward()
MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN)
@ -161,40 +168,40 @@ def _format_marker(marker, first=True):
# the rest of this function so that we don't get extraneous () on the
# outside.
if (
isinstance(marker, list)
and len(marker) == 1
and isinstance(marker[0], (list, tuple))
isinstance(marker, list) and
len(marker) == 1 and
isinstance(marker[0], (list, tuple))
):
return _format_marker(marker[0])
if isinstance(marker, list):
inner = (_format_marker(m, first=False) for m in marker)
if first:
return " ".join(inner)
return ' '.join(inner)
else:
return "(" + " ".join(inner) + ")"
return '(' + ' '.join(inner) + ')'
elif isinstance(marker, tuple):
return " ".join([m.serialize() for m in marker])
return ' '.join([m.serialize() for m in marker])
else:
return marker
_operators = {
"in": lambda lhs, rhs: lhs in rhs,
"not in": lambda lhs, rhs: lhs not in rhs,
"<": operator.lt,
"<=": operator.le,
"==": operator.eq,
"!=": operator.ne,
">=": operator.ge,
">": operator.gt,
'in': lambda lhs, rhs: lhs in rhs,
'not in': lambda lhs, rhs: lhs not in rhs,
'<': operator.lt,
'<=': operator.le,
'==': operator.eq,
'!=': operator.ne,
'>=': operator.ge,
'>': operator.gt,
} # type: Dict[str, Operator]
def _eval_op(lhs, op, rhs):
# type: (str, Op, str) -> bool
try:
spec = Specifier("".join([op.serialize(), rhs]))
spec = Specifier(''.join([op.serialize(), rhs]))
except InvalidSpecifier:
pass
else:
@ -203,13 +210,13 @@ def _eval_op(lhs, op, rhs):
oper = _operators.get(op.serialize()) # type: Optional[Operator]
if oper is None:
raise UndefinedComparison(
"Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
f'Undefined {op!r} on {lhs!r} and {rhs!r}.',
)
return oper(lhs, rhs)
class Undefined(object):
class Undefined:
pass
@ -222,7 +229,7 @@ def _get_env(environment, name):
if isinstance(value, Undefined):
raise UndefinedEnvironmentName(
"{0!r} does not exist in evaluation environment.".format(name)
f'{name!r} does not exist in evaluation environment.',
)
return value
@ -249,8 +256,8 @@ def _evaluate_markers(markers, environment):
groups[-1].append(_eval_op(lhs_value, op, rhs_value))
else:
assert marker in ["and", "or"]
if marker == "or":
assert marker in ['and', 'or']
if marker == 'or':
groups.append([])
return any(all(item) for item in groups)
@ -258,48 +265,48 @@ def _evaluate_markers(markers, environment):
def format_full_version(info):
# type: (sys._version_info) -> str
version = "{0.major}.{0.minor}.{0.micro}".format(info)
version = '{0.major}.{0.minor}.{0.micro}'.format(info)
kind = info.releaselevel
if kind != "final":
if kind != 'final':
version += kind[0] + str(info.serial)
return version
def default_environment():
# type: () -> Dict[str, str]
if hasattr(sys, "implementation"):
if hasattr(sys, 'implementation'):
# Ignoring the `sys.implementation` reference for type checking due to
# mypy not liking that the attribute doesn't exist in Python 2.7 when
# run with the `--py27` flag.
iver = format_full_version(sys.implementation.version) # type: ignore
implementation_name = sys.implementation.name # type: ignore
else:
iver = "0"
implementation_name = ""
iver = '0'
implementation_name = ''
return {
"implementation_name": implementation_name,
"implementation_version": iver,
"os_name": os.name,
"platform_machine": platform.machine(),
"platform_release": platform.release(),
"platform_system": platform.system(),
"platform_version": platform.version(),
"python_full_version": platform.python_version(),
"platform_python_implementation": platform.python_implementation(),
"python_version": ".".join(platform.python_version_tuple()[:2]),
"sys_platform": sys.platform,
'implementation_name': implementation_name,
'implementation_version': iver,
'os_name': os.name,
'platform_machine': platform.machine(),
'platform_release': platform.release(),
'platform_system': platform.system(),
'platform_version': platform.version(),
'python_full_version': platform.python_version(),
'platform_python_implementation': platform.python_implementation(),
'python_version': '.'.join(platform.python_version_tuple()[:2]),
'sys_platform': sys.platform,
}
class Marker(object):
class Marker:
def __init__(self, marker):
# type: (str) -> None
try:
self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e:
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
marker, marker[e.loc : e.loc + 8]
err_str = 'Invalid marker: {!r}, parse error at {!r}'.format(
marker, marker[e.loc: e.loc + 8],
)
raise InvalidMarker(err_str)
@ -309,7 +316,7 @@ class Marker(object):
def __repr__(self):
# type: () -> str
return "<Marker({0!r})>".format(str(self))
return f'<Marker({str(self)!r})>'
def evaluate(self, environment=None):
# type: (Optional[Dict[str, str]]) -> bool

View file

@ -1,19 +1,29 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import string
import re
from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
from pkg_resources.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine
from pkg_resources.extern.pyparsing import Literal as L # noqa
import string
from urllib import parse as urlparse
from pkg_resources.extern.pyparsing import Combine
from pkg_resources.extern.pyparsing import Literal as L # noqa
from pkg_resources.extern.pyparsing import Optional
from pkg_resources.extern.pyparsing import originalTextFor
from pkg_resources.extern.pyparsing import ParseException
from pkg_resources.extern.pyparsing import Regex
from pkg_resources.extern.pyparsing import stringEnd
from pkg_resources.extern.pyparsing import stringStart
from pkg_resources.extern.pyparsing import Word
from pkg_resources.extern.pyparsing import ZeroOrMore
from ._typing import TYPE_CHECKING
from .markers import MARKER_EXPR, Marker
from .specifiers import LegacySpecifier, Specifier, SpecifierSet
from .markers import Marker
from .markers import MARKER_EXPR
from .specifiers import LegacySpecifier
from .specifiers import Specifier
from .specifiers import SpecifierSet
if TYPE_CHECKING: # pragma: no cover
from typing import List
@ -27,43 +37,43 @@ class InvalidRequirement(ValueError):
ALPHANUM = Word(string.ascii_letters + string.digits)
LBRACKET = L("[").suppress()
RBRACKET = L("]").suppress()
LPAREN = L("(").suppress()
RPAREN = L(")").suppress()
COMMA = L(",").suppress()
SEMICOLON = L(";").suppress()
AT = L("@").suppress()
LBRACKET = L('[').suppress()
RBRACKET = L(']').suppress()
LPAREN = L('(').suppress()
RPAREN = L(')').suppress()
COMMA = L(',').suppress()
SEMICOLON = L(';').suppress()
AT = L('@').suppress()
PUNCTUATION = Word("-_.")
PUNCTUATION = Word('-_.')
IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM)
IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
NAME = IDENTIFIER("name")
NAME = IDENTIFIER('name')
EXTRA = IDENTIFIER
URI = Regex(r"[^ ]+")("url")
URI = Regex(r'[^ ]+')('url')
URL = AT + URI
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)('extras')
VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
VERSION_MANY = Combine(
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
)("_raw_spec")
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=',', adjacent=False,
)('_raw_spec')
_VERSION_SPEC = Optional((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
VERSION_SPEC = originalTextFor(_VERSION_SPEC)('specifier')
VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
MARKER_EXPR = originalTextFor(MARKER_EXPR())('marker')
MARKER_EXPR.setParseAction(
lambda s, l, t: Marker(s[t._original_start : t._original_end])
lambda s, l, t: Marker(s[t._original_start: t._original_end]),
)
MARKER_SEPARATOR = SEMICOLON
MARKER = MARKER_SEPARATOR + MARKER_EXPR
@ -76,10 +86,10 @@ NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARK
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
# pkg_resources.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
# issue #104
REQUIREMENT.parseString("x[]")
REQUIREMENT.parseString('x[]')
class Requirement(object):
class Requirement:
"""Parse a requirement.
Parse a given requirement string into its parts, such as name, specifier,
@ -98,21 +108,21 @@ class Requirement(object):
req = REQUIREMENT.parseString(requirement_string)
except ParseException as e:
raise InvalidRequirement(
'Parse error at "{0!r}": {1}'.format(
requirement_string[e.loc : e.loc + 8], e.msg
)
'Parse error at "{!r}": {}'.format(
requirement_string[e.loc: e.loc + 8], e.msg,
),
)
self.name = req.name
if req.url:
parsed_url = urlparse.urlparse(req.url)
if parsed_url.scheme == "file":
if parsed_url.scheme == 'file':
if urlparse.urlunparse(parsed_url) != req.url:
raise InvalidRequirement("Invalid URL given")
raise InvalidRequirement('Invalid URL given')
elif not (parsed_url.scheme and parsed_url.netloc) or (
not parsed_url.scheme and not parsed_url.netloc
):
raise InvalidRequirement("Invalid URL: {0}".format(req.url))
raise InvalidRequirement(f'Invalid URL: {req.url}')
self.url = req.url
else:
self.url = None
@ -125,21 +135,21 @@ class Requirement(object):
parts = [self.name] # type: List[str]
if self.extras:
parts.append("[{0}]".format(",".join(sorted(self.extras))))
parts.append('[{}]'.format(','.join(sorted(self.extras))))
if self.specifier:
parts.append(str(self.specifier))
if self.url:
parts.append("@ {0}".format(self.url))
parts.append(f'@ {self.url}')
if self.marker:
parts.append(" ")
parts.append(' ')
if self.marker:
parts.append("; {0}".format(self.marker))
parts.append(f'; {self.marker}')
return "".join(parts)
return ''.join(parts)
def __repr__(self):
# type: () -> str
return "<Requirement({0!r})>".format(str(self))
return f'<Requirement({str(self)!r})>'

View file

@ -1,17 +1,20 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import abc
import functools
import itertools
import re
from ._compat import string_types, with_metaclass
from ._compat import string_types
from ._compat import with_metaclass
from ._typing import TYPE_CHECKING
from .utils import canonicalize_version
from .version import Version, LegacyVersion, parse
from .version import LegacyVersion
from .version import parse
from .version import Version
if TYPE_CHECKING: # pragma: no cover
from typing import (
@ -105,15 +108,15 @@ class _IndividualSpecifier(BaseSpecifier):
_operators = {} # type: Dict[str, str]
def __init__(self, spec="", prereleases=None):
def __init__(self, spec='', prereleases=None):
# type: (str, Optional[bool]) -> None
match = self._regex.search(spec)
if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
self._spec = (
match.group("operator").strip(),
match.group("version").strip(),
match.group('operator').strip(),
match.group('version').strip(),
) # type: Tuple[str, str]
# Store whether or not this Specifier should accept prereleases
@ -122,16 +125,16 @@ class _IndividualSpecifier(BaseSpecifier):
def __repr__(self):
# type: () -> str
pre = (
", prereleases={0!r}".format(self.prereleases)
f', prereleases={self.prereleases!r}'
if self._prereleases is not None
else ""
else ''
)
return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
return f'<{self.__class__.__name__}({str(self)!r}{pre})>'
def __str__(self):
# type: () -> str
return "{0}{1}".format(*self._spec)
return '{}{}'.format(*self._spec)
@property
def _canonical_spec(self):
@ -169,7 +172,7 @@ class _IndividualSpecifier(BaseSpecifier):
def _get_operator(self, op):
# type: (str) -> CallableOperator
operator_callable = getattr(
self, "_compare_{0}".format(self._operators[op])
self, f'_compare_{self._operators[op]}',
) # type: CallableOperator
return operator_callable
@ -231,7 +234,7 @@ class _IndividualSpecifier(BaseSpecifier):
yielded = False
found_prereleases = []
kw = {"prereleases": prereleases if prereleases is not None else True}
kw = {'prereleases': prereleases if prereleases is not None else True}
# Attempt to iterate over all the values in the iterable and if any of
# them match, yield them.
@ -274,15 +277,15 @@ class LegacySpecifier(_IndividualSpecifier):
)
"""
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r'^\s*' + _regex_str + r'\s*$', re.VERBOSE | re.IGNORECASE)
_operators = {
"==": "equal",
"!=": "not_equal",
"<=": "less_than_equal",
">=": "greater_than_equal",
"<": "less_than",
">": "greater_than",
'==': 'equal',
'!=': 'not_equal',
'<=': 'less_than_equal',
'>=': 'greater_than_equal',
'<': 'less_than',
'>': 'greater_than',
}
def _coerce_version(self, version):
@ -317,7 +320,7 @@ class LegacySpecifier(_IndividualSpecifier):
def _require_version_compare(
fn # type: (Callable[[Specifier, ParsedVersion, str], bool])
fn, # type: (Callable[[Specifier, ParsedVersion, str], bool])
):
# type: (...) -> Callable[[Specifier, ParsedVersion, str], bool]
@functools.wraps(fn)
@ -425,17 +428,17 @@ class Specifier(_IndividualSpecifier):
)
"""
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r'^\s*' + _regex_str + r'\s*$', re.VERBOSE | re.IGNORECASE)
_operators = {
"~=": "compatible",
"==": "equal",
"!=": "not_equal",
"<=": "less_than_equal",
">=": "greater_than_equal",
"<": "less_than",
">": "greater_than",
"===": "arbitrary",
'~=': 'compatible',
'==': 'equal',
'!=': 'not_equal',
'<=': 'less_than_equal',
'>=': 'greater_than_equal',
'<': 'less_than',
'>': 'greater_than',
'===': 'arbitrary',
}
@_require_version_compare
@ -451,20 +454,20 @@ class Specifier(_IndividualSpecifier):
# We want everything but the last item in the version, but we want to
# ignore post and dev releases and we want to treat the pre-release as
# it's own separate segment.
prefix = ".".join(
prefix = '.'.join(
list(
itertools.takewhile(
lambda x: (not x.startswith("post") and not x.startswith("dev")),
lambda x: (not x.startswith('post') and not x.startswith('dev')),
_version_split(spec),
)
)[:-1]
),
)[:-1],
)
# Add the prefix notation to the end of our string
prefix += ".*"
prefix += '.*'
return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
prospective, prefix
return self._get_operator('>=')(prospective, spec) and self._get_operator('==')(
prospective, prefix,
)
@_require_version_compare
@ -472,7 +475,7 @@ class Specifier(_IndividualSpecifier):
# type: (ParsedVersion, str) -> bool
# We need special logic to handle prefix matching
if spec.endswith(".*"):
if spec.endswith('.*'):
# In the case of prefix matching we want to ignore local segment.
prospective = Version(prospective.public)
# Split the spec out by dots, and pretend that there is an implicit
@ -492,7 +495,7 @@ class Specifier(_IndividualSpecifier):
# Pad out our two sides with zeros so that they both equal the same
# length.
padded_spec, padded_prospective = _pad_version(
split_spec, shortened_prospective
split_spec, shortened_prospective,
)
return padded_prospective == padded_spec
@ -608,10 +611,10 @@ class Specifier(_IndividualSpecifier):
# operators, and if they are if they are including an explicit
# prerelease.
operator, version = self._spec
if operator in ["==", ">=", "<=", "~=", "==="]:
if operator in ['==', '>=', '<=', '~=', '===']:
# The == specifier can include a trailing .*, if it does we
# want to remove before parsing.
if operator == "==" and version.endswith(".*"):
if operator == '==' and version.endswith('.*'):
version = version[:-2]
# Parse the version, and if it is a pre-release than this
@ -627,13 +630,13 @@ class Specifier(_IndividualSpecifier):
self._prereleases = value
_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
_prefix_regex = re.compile(r'^([0-9]+)((?:a|b|c|rc)[0-9]+)$')
def _version_split(version):
# type: (str) -> List[str]
result = [] # type: List[str]
for item in version.split("."):
for item in version.split('.'):
match = _prefix_regex.search(item)
if match:
result.extend(match.groups())
@ -651,23 +654,23 @@ def _pad_version(left, right):
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
# Get the rest of our versions
left_split.append(left[len(left_split[0]) :])
right_split.append(right[len(right_split[0]) :])
left_split.append(left[len(left_split[0]):])
right_split.append(right[len(right_split[0]):])
# Insert our padding
left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
left_split.insert(1, ['0'] * max(0, len(right_split[0]) - len(left_split[0])))
right_split.insert(1, ['0'] * max(0, len(left_split[0]) - len(right_split[0])))
return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
class SpecifierSet(BaseSpecifier):
def __init__(self, specifiers="", prereleases=None):
def __init__(self, specifiers='', prereleases=None):
# type: (str, Optional[bool]) -> None
# Split on , to break each individual specifier into it's own item, and
# strip each item to remove leading/trailing whitespace.
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
split_specifiers = [s.strip() for s in specifiers.split(',') if s.strip()]
# Parsed each individual specifier, attempting first to make it a
# Specifier and falling back to a LegacySpecifier.
@ -688,16 +691,16 @@ class SpecifierSet(BaseSpecifier):
def __repr__(self):
# type: () -> str
pre = (
", prereleases={0!r}".format(self.prereleases)
f', prereleases={self.prereleases!r}'
if self._prereleases is not None
else ""
else ''
)
return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
return f'<SpecifierSet({str(self)!r}{pre})>'
def __str__(self):
# type: () -> str
return ",".join(sorted(str(s) for s in self._specs))
return ','.join(sorted(str(s) for s in self._specs))
def __hash__(self):
# type: () -> int
@ -721,8 +724,8 @@ class SpecifierSet(BaseSpecifier):
specifier._prereleases = self._prereleases
else:
raise ValueError(
"Cannot combine SpecifierSets with True and False prerelease "
"overrides."
'Cannot combine SpecifierSets with True and False prerelease '
'overrides.',
)
return specifier

View file

@ -1,8 +1,7 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import
from __future__ import annotations
import distutils.util
@ -46,18 +45,18 @@ if TYPE_CHECKING: # pragma: no cover
logger = logging.getLogger(__name__)
INTERPRETER_SHORT_NAMES = {
"python": "py", # Generic.
"cpython": "cp",
"pypy": "pp",
"ironpython": "ip",
"jython": "jy",
'python': 'py', # Generic.
'cpython': 'cp',
'pypy': 'pp',
'ironpython': 'ip',
'jython': 'jy',
} # type: Dict[str, str]
_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32
class Tag(object):
class Tag:
"""
A representation of the tag triple for a wheel.
@ -65,7 +64,7 @@ class Tag(object):
is also supported.
"""
__slots__ = ["_interpreter", "_abi", "_platform"]
__slots__ = ['_interpreter', '_abi', '_platform']
def __init__(self, interpreter, abi, platform):
# type: (str, str, str) -> None
@ -94,9 +93,9 @@ class Tag(object):
return NotImplemented
return (
(self.platform == other.platform)
and (self.abi == other.abi)
and (self.interpreter == other.interpreter)
(self.platform == other.platform) and
(self.abi == other.abi) and
(self.interpreter == other.interpreter)
)
def __hash__(self):
@ -105,11 +104,11 @@ class Tag(object):
def __str__(self):
# type: () -> str
return "{}-{}-{}".format(self._interpreter, self._abi, self._platform)
return f'{self._interpreter}-{self._abi}-{self._platform}'
def __repr__(self):
# type: () -> str
return "<{self} @ {self_id}>".format(self=self, self_id=id(self))
return f'<{self} @ {id(self)}>'
def parse_tag(tag):
@ -121,10 +120,10 @@ def parse_tag(tag):
compressed tag set.
"""
tags = set()
interpreters, abis, platforms = tag.split("-")
for interpreter in interpreters.split("."):
for abi in abis.split("."):
for platform_ in platforms.split("."):
interpreters, abis, platforms = tag.split('-')
for interpreter in interpreters.split('.'):
for abi in abis.split('.'):
for platform_ in platforms.split('.'):
tags.add(Tag(interpreter, abi, platform_))
return frozenset(tags)
@ -136,13 +135,13 @@ def _warn_keyword_parameter(func_name, kwargs):
"""
if not kwargs:
return False
elif len(kwargs) > 1 or "warn" not in kwargs:
kwargs.pop("warn", None)
elif len(kwargs) > 1 or 'warn' not in kwargs:
kwargs.pop('warn', None)
arg = next(iter(kwargs.keys()))
raise TypeError(
"{}() got an unexpected keyword argument {!r}".format(func_name, arg)
f'{func_name}() got an unexpected keyword argument {arg!r}',
)
return kwargs["warn"]
return kwargs['warn']
def _get_config_var(name, warn=False):
@ -150,14 +149,14 @@ def _get_config_var(name, warn=False):
value = sysconfig.get_config_var(name)
if value is None and warn:
logger.debug(
"Config variable '%s' is unset, Python ABI tag may be incorrect", name
"Config variable '%s' is unset, Python ABI tag may be incorrect", name,
)
return value
def _normalize_string(string):
# type: (str) -> str
return string.replace(".", "_").replace("-", "_")
return string.replace('.', '_').replace('-', '_')
def _abi3_applies(python_version):
@ -175,33 +174,33 @@ def _cpython_abis(py_version, warn=False):
py_version = tuple(py_version) # To allow for version comparison.
abis = []
version = _version_nodot(py_version[:2])
debug = pymalloc = ucs4 = ""
with_debug = _get_config_var("Py_DEBUG", warn)
has_refcount = hasattr(sys, "gettotalrefcount")
debug = pymalloc = ucs4 = ''
with_debug = _get_config_var('Py_DEBUG', warn)
has_refcount = hasattr(sys, 'gettotalrefcount')
# Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
# extension modules is the best option.
# https://github.com/pypa/pip/issues/3383#issuecomment-173267692
has_ext = "_d.pyd" in EXTENSION_SUFFIXES
has_ext = '_d.pyd' in EXTENSION_SUFFIXES
if with_debug or (with_debug is None and (has_refcount or has_ext)):
debug = "d"
debug = 'd'
if py_version < (3, 8):
with_pymalloc = _get_config_var("WITH_PYMALLOC", warn)
with_pymalloc = _get_config_var('WITH_PYMALLOC', warn)
if with_pymalloc or with_pymalloc is None:
pymalloc = "m"
pymalloc = 'm'
if py_version < (3, 3):
unicode_size = _get_config_var("Py_UNICODE_SIZE", warn)
unicode_size = _get_config_var('Py_UNICODE_SIZE', warn)
if unicode_size == 4 or (
unicode_size is None and sys.maxunicode == 0x10FFFF
):
ucs4 = "u"
ucs4 = 'u'
elif debug:
# Debug builds can also load "normal" extension modules.
# We can also assume no UCS-4 or pymalloc requirement.
abis.append("cp{version}".format(version=version))
abis.append(f'cp{version}')
abis.insert(
0,
"cp{version}{debug}{pymalloc}{ucs4}".format(
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4
'cp{version}{debug}{pymalloc}{ucs4}'.format(
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4,
),
)
return abis
@ -211,7 +210,7 @@ def cpython_tags(
python_version=None, # type: Optional[PythonVersion]
abis=None, # type: Optional[Iterable[str]]
platforms=None, # type: Optional[Iterable[str]]
**kwargs # type: bool
**kwargs, # type: bool
):
# type: (...) -> Iterator[Tag]
"""
@ -229,11 +228,11 @@ def cpython_tags(
If 'abi3' or 'none' are specified in 'abis' then they will be yielded at
their normal position and not at the beginning.
"""
warn = _warn_keyword_parameter("cpython_tags", kwargs)
warn = _warn_keyword_parameter('cpython_tags', kwargs)
if not python_version:
python_version = sys.version_info[:2]
interpreter = "cp{}".format(_version_nodot(python_version[:2]))
interpreter = f'cp{_version_nodot(python_version[:2])}'
if abis is None:
if len(python_version) > 1:
@ -242,7 +241,7 @@ def cpython_tags(
abis = []
abis = list(abis)
# 'abi3' and 'none' are explicitly handled later.
for explicit_abi in ("abi3", "none"):
for explicit_abi in ('abi3', 'none'):
try:
abis.remove(explicit_abi)
except ValueError:
@ -253,23 +252,21 @@ def cpython_tags(
for platform_ in platforms:
yield Tag(interpreter, abi, platform_)
if _abi3_applies(python_version):
for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms):
yield tag
for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms):
yield tag
yield from (Tag(interpreter, 'abi3', platform_) for platform_ in platforms)
yield from (Tag(interpreter, 'none', platform_) for platform_ in platforms)
if _abi3_applies(python_version):
for minor_version in range(python_version[1] - 1, 1, -1):
for platform_ in platforms:
interpreter = "cp{version}".format(
version=_version_nodot((python_version[0], minor_version))
interpreter = 'cp{version}'.format(
version=_version_nodot((python_version[0], minor_version)),
)
yield Tag(interpreter, "abi3", platform_)
yield Tag(interpreter, 'abi3', platform_)
def _generic_abi():
# type: () -> Iterator[str]
abi = sysconfig.get_config_var("SOABI")
abi = sysconfig.get_config_var('SOABI')
if abi:
yield _normalize_string(abi)
@ -278,7 +275,7 @@ def generic_tags(
interpreter=None, # type: Optional[str]
abis=None, # type: Optional[Iterable[str]]
platforms=None, # type: Optional[Iterable[str]]
**kwargs # type: bool
**kwargs, # type: bool
):
# type: (...) -> Iterator[Tag]
"""
@ -289,17 +286,17 @@ def generic_tags(
The "none" ABI will be added if it was not explicitly provided.
"""
warn = _warn_keyword_parameter("generic_tags", kwargs)
warn = _warn_keyword_parameter('generic_tags', kwargs)
if not interpreter:
interp_name = interpreter_name()
interp_version = interpreter_version(warn=warn)
interpreter = "".join([interp_name, interp_version])
interpreter = ''.join([interp_name, interp_version])
if abis is None:
abis = _generic_abi()
platforms = list(platforms or _platform_tags())
abis = list(abis)
if "none" not in abis:
abis.append("none")
if 'none' not in abis:
abis.append('none')
for abi in abis:
for platform_ in platforms:
yield Tag(interpreter, abi, platform_)
@ -314,11 +311,11 @@ def _py_interpreter_range(py_version):
all previous versions of that major version.
"""
if len(py_version) > 1:
yield "py{version}".format(version=_version_nodot(py_version[:2]))
yield "py{major}".format(major=py_version[0])
yield f'py{_version_nodot(py_version[:2])}'
yield f'py{py_version[0]}'
if len(py_version) > 1:
for minor in range(py_version[1] - 1, -1, -1):
yield "py{version}".format(version=_version_nodot((py_version[0], minor)))
yield f'py{_version_nodot((py_version[0], minor))}'
def compatible_tags(
@ -340,11 +337,11 @@ def compatible_tags(
platforms = list(platforms or _platform_tags())
for version in _py_interpreter_range(python_version):
for platform_ in platforms:
yield Tag(version, "none", platform_)
yield Tag(version, 'none', platform_)
if interpreter:
yield Tag(interpreter, "none", "any")
yield Tag(interpreter, 'none', 'any')
for version in _py_interpreter_range(python_version):
yield Tag(version, "none", "any")
yield Tag(version, 'none', 'any')
def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
@ -352,37 +349,37 @@ def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
if not is_32bit:
return arch
if arch.startswith("ppc"):
return "ppc"
if arch.startswith('ppc'):
return 'ppc'
return "i386"
return 'i386'
def _mac_binary_formats(version, cpu_arch):
# type: (MacVersion, str) -> List[str]
formats = [cpu_arch]
if cpu_arch == "x86_64":
if cpu_arch == 'x86_64':
if version < (10, 4):
return []
formats.extend(["intel", "fat64", "fat32"])
formats.extend(['intel', 'fat64', 'fat32'])
elif cpu_arch == "i386":
elif cpu_arch == 'i386':
if version < (10, 4):
return []
formats.extend(["intel", "fat32", "fat"])
formats.extend(['intel', 'fat32', 'fat'])
elif cpu_arch == "ppc64":
elif cpu_arch == 'ppc64':
# TODO: Need to care about 32-bit PPC for ppc64 through 10.2?
if version > (10, 5) or version < (10, 4):
return []
formats.append("fat64")
formats.append('fat64')
elif cpu_arch == "ppc":
elif cpu_arch == 'ppc':
if version > (10, 6):
return []
formats.extend(["fat32", "fat"])
formats.extend(['fat32', 'fat'])
formats.append("universal")
formats.append('universal')
return formats
@ -398,7 +395,7 @@ def mac_platforms(version=None, arch=None):
"""
version_str, _, cpu_arch = platform.mac_ver() # type: ignore
if version is None:
version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
version = cast('MacVersion', tuple(map(int, version_str.split('.')[:2])))
else:
version = version
if arch is None:
@ -409,7 +406,7 @@ def mac_platforms(version=None, arch=None):
compat_version = version[0], minor_version
binary_formats = _mac_binary_formats(compat_version, arch)
for binary_format in binary_formats:
yield "macosx_{major}_{minor}_{binary_format}".format(
yield 'macosx_{major}_{minor}_{binary_format}'.format(
major=compat_version[0],
minor=compat_version[1],
binary_format=binary_format,
@ -423,7 +420,7 @@ def _is_manylinux_compatible(name, glibc_version):
try:
import _manylinux # noqa
return bool(getattr(_manylinux, name + "_compatible"))
return bool(getattr(_manylinux, name + '_compatible'))
except (ImportError, AttributeError):
# Fall through to heuristic check below.
pass
@ -449,7 +446,7 @@ def _glibc_version_string_confstr():
try:
# os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17".
version_string = os.confstr( # type: ignore[attr-defined] # noqa: F821
"CS_GNU_LIBC_VERSION"
'CS_GNU_LIBC_VERSION',
)
assert version_string is not None
_, version = version_string.split() # type: Tuple[str, str]
@ -488,7 +485,7 @@ def _glibc_version_string_ctypes():
version_str = gnu_get_libc_version() # type: str
# py2 / py3 compatibility:
if not isinstance(version_str, str):
version_str = version_str.decode("ascii")
version_str = version_str.decode('ascii')
return version_str
@ -502,17 +499,17 @@ def _check_glibc_version(version_str, required_major, minimum_minor):
# random junk that might come after the minor version -- this might happen
# in patched/forked versions of glibc (e.g. Linaro's version of glibc
# uses version strings like "2.20-2014.11"). See gh-3588.
m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
m = re.match(r'(?P<major>[0-9]+)\.(?P<minor>[0-9]+)', version_str)
if not m:
warnings.warn(
"Expected glibc version with 2 components major.minor,"
" got: %s" % version_str,
'Expected glibc version with 2 components major.minor,'
' got: %s' % version_str,
RuntimeWarning,
)
return False
return (
int(m.group("major")) == required_major
and int(m.group("minor")) >= minimum_minor
int(m.group('major')) == required_major and
int(m.group('minor')) >= minimum_minor
)
@ -528,7 +525,7 @@ def _have_compatible_glibc(required_major, minimum_minor):
# identify the architecture of the running executable in some cases, so we
# determine it dynamically by reading the information from the running
# process. This only applies on Linux, which uses the ELF format.
class _ELFFileHeader(object):
class _ELFFileHeader:
# https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
class _InvalidELFFileHeader(ValueError):
"""
@ -554,28 +551,28 @@ class _ELFFileHeader(object):
# type: (str) -> int
try:
(result,) = struct.unpack(
fmt, file.read(struct.calcsize(fmt))
fmt, file.read(struct.calcsize(fmt)),
) # type: (int, )
except struct.error:
raise _ELFFileHeader._InvalidELFFileHeader()
return result
self.e_ident_magic = unpack(">I")
self.e_ident_magic = unpack('>I')
if self.e_ident_magic != self.ELF_MAGIC_NUMBER:
raise _ELFFileHeader._InvalidELFFileHeader()
self.e_ident_class = unpack("B")
self.e_ident_class = unpack('B')
if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}:
raise _ELFFileHeader._InvalidELFFileHeader()
self.e_ident_data = unpack("B")
self.e_ident_data = unpack('B')
if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}:
raise _ELFFileHeader._InvalidELFFileHeader()
self.e_ident_version = unpack("B")
self.e_ident_osabi = unpack("B")
self.e_ident_abiversion = unpack("B")
self.e_ident_version = unpack('B')
self.e_ident_osabi = unpack('B')
self.e_ident_abiversion = unpack('B')
self.e_ident_pad = file.read(7)
format_h = "<H" if self.e_ident_data == self.ELFDATA2LSB else ">H"
format_i = "<I" if self.e_ident_data == self.ELFDATA2LSB else ">I"
format_q = "<Q" if self.e_ident_data == self.ELFDATA2LSB else ">Q"
format_h = '<H' if self.e_ident_data == self.ELFDATA2LSB else '>H'
format_i = '<I' if self.e_ident_data == self.ELFDATA2LSB else '>I'
format_q = '<Q' if self.e_ident_data == self.ELFDATA2LSB else '>Q'
format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q
self.e_type = unpack(format_h)
self.e_machine = unpack(format_h)
@ -595,9 +592,9 @@ class _ELFFileHeader(object):
def _get_elf_header():
# type: () -> Optional[_ELFFileHeader]
try:
with open(sys.executable, "rb") as f:
with open(sys.executable, 'rb') as f:
elf_header = _ELFFileHeader(f)
except (IOError, OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
return None
return elf_header
@ -635,9 +632,9 @@ def _is_linux_i686():
def _have_compatible_manylinux_abi(arch):
# type: (str) -> bool
if arch == "armv7l":
if arch == 'armv7l':
return _is_linux_armhf()
if arch == "i686":
if arch == 'i686':
return _is_linux_i686()
return True
@ -646,32 +643,32 @@ def _linux_platforms(is_32bit=_32_BIT_INTERPRETER):
# type: (bool) -> Iterator[str]
linux = _normalize_string(distutils.util.get_platform())
if is_32bit:
if linux == "linux_x86_64":
linux = "linux_i686"
elif linux == "linux_aarch64":
linux = "linux_armv7l"
if linux == 'linux_x86_64':
linux = 'linux_i686'
elif linux == 'linux_aarch64':
linux = 'linux_armv7l'
manylinux_support = []
_, arch = linux.split("_", 1)
_, arch = linux.split('_', 1)
if _have_compatible_manylinux_abi(arch):
if arch in {"x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"}:
if arch in {'x86_64', 'i686', 'aarch64', 'armv7l', 'ppc64', 'ppc64le', 's390x'}:
manylinux_support.append(
("manylinux2014", (2, 17))
('manylinux2014', (2, 17)),
) # CentOS 7 w/ glibc 2.17 (PEP 599)
if arch in {"x86_64", "i686"}:
if arch in {'x86_64', 'i686'}:
manylinux_support.append(
("manylinux2010", (2, 12))
('manylinux2010', (2, 12)),
) # CentOS 6 w/ glibc 2.12 (PEP 571)
manylinux_support.append(
("manylinux1", (2, 5))
('manylinux1', (2, 5)),
) # CentOS 5 w/ glibc 2.5 (PEP 513)
manylinux_support_iter = iter(manylinux_support)
for name, glibc_version in manylinux_support_iter:
if _is_manylinux_compatible(name, glibc_version):
yield linux.replace("linux", name)
yield linux.replace('linux', name)
break
# Support for a later manylinux implies support for an earlier version.
for name, _ in manylinux_support_iter:
yield linux.replace("linux", name)
yield linux.replace('linux', name)
yield linux
@ -685,9 +682,9 @@ def _platform_tags():
"""
Provides the platform tags for this installation.
"""
if platform.system() == "Darwin":
if platform.system() == 'Darwin':
return mac_platforms()
elif platform.system() == "Linux":
elif platform.system() == 'Linux':
return _linux_platforms()
else:
return _generic_platforms()
@ -711,8 +708,8 @@ def interpreter_version(**kwargs):
"""
Returns the version of the running interpreter.
"""
warn = _warn_keyword_parameter("interpreter_version", kwargs)
version = _get_config_var("py_version_nodot", warn=warn)
warn = _warn_keyword_parameter('interpreter_version', kwargs)
version = _get_config_var('py_version_nodot', warn=warn)
if version:
version = str(version)
else:
@ -723,9 +720,9 @@ def interpreter_version(**kwargs):
def _version_nodot(version):
# type: (PythonVersion) -> str
if any(v >= 10 for v in version):
sep = "_"
sep = '_'
else:
sep = ""
sep = ''
return sep.join(map(str, version))
@ -737,15 +734,12 @@ def sys_tags(**kwargs):
The order of the sequence corresponds to priority order for the
interpreter, from most to least important.
"""
warn = _warn_keyword_parameter("sys_tags", kwargs)
warn = _warn_keyword_parameter('sys_tags', kwargs)
interp_name = interpreter_name()
if interp_name == "cp":
for tag in cpython_tags(warn=warn):
yield tag
if interp_name == 'cp':
yield from cpython_tags(warn=warn)
else:
for tag in generic_tags():
yield tag
yield from generic_tags()
for tag in compatible_tags():
yield tag
yield from compatible_tags()

View file

@ -1,26 +1,28 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import re
from ._typing import TYPE_CHECKING, cast
from .version import InvalidVersion, Version
from ._typing import cast
from ._typing import TYPE_CHECKING
from .version import InvalidVersion
from .version import Version
if TYPE_CHECKING: # pragma: no cover
from typing import NewType, Union
NormalizedName = NewType("NormalizedName", str)
NormalizedName = NewType('NormalizedName', str)
_canonicalize_regex = re.compile(r"[-_.]+")
_canonicalize_regex = re.compile(r'[-_.]+')
def canonicalize_name(name):
# type: (str) -> NormalizedName
# This is taken from PEP 503.
value = _canonicalize_regex.sub("-", name).lower()
return cast("NormalizedName", value)
value = _canonicalize_regex.sub('-', name).lower()
return cast('NormalizedName', value)
def canonicalize_version(_version):
@ -40,26 +42,26 @@ def canonicalize_version(_version):
# Epoch
if version.epoch != 0:
parts.append("{0}!".format(version.epoch))
parts.append(f'{version.epoch}!')
# Release segment
# NB: This strips trailing '.0's to normalize
parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
parts.append(re.sub(r'(\.0)+$', '', '.'.join(str(x) for x in version.release)))
# Pre-release
if version.pre is not None:
parts.append("".join(str(x) for x in version.pre))
parts.append(''.join(str(x) for x in version.pre))
# Post-release
if version.post is not None:
parts.append(".post{0}".format(version.post))
parts.append(f'.post{version.post}')
# Development release
if version.dev is not None:
parts.append(".dev{0}".format(version.dev))
parts.append(f'.dev{version.dev}')
# Local version segment
if version.local is not None:
parts.append("+{0}".format(version.local))
parts.append(f'+{version.local}')
return "".join(parts)
return ''.join(parts)

View file

@ -1,13 +1,14 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import collections
import itertools
import re
from ._structures import Infinity, NegativeInfinity
from ._structures import Infinity
from ._structures import NegativeInfinity
from ._typing import TYPE_CHECKING
if TYPE_CHECKING: # pragma: no cover
@ -30,18 +31,18 @@ if TYPE_CHECKING: # pragma: no cover
],
]
CmpKey = Tuple[
int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType
int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType,
]
LegacyCmpKey = Tuple[int, Tuple[str, ...]]
VersionComparisonMethod = Callable[
[Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool
[Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool,
]
__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
__all__ = ['parse', 'Version', 'LegacyVersion', 'InvalidVersion', 'VERSION_PATTERN']
_Version = collections.namedtuple(
"_Version", ["epoch", "release", "dev", "pre", "post", "local"]
'_Version', ['epoch', 'release', 'dev', 'pre', 'post', 'local'],
)
@ -64,7 +65,7 @@ class InvalidVersion(ValueError):
"""
class _BaseVersion(object):
class _BaseVersion:
_key = None # type: Union[CmpKey, LegacyCmpKey]
def __hash__(self):
@ -115,7 +116,7 @@ class LegacyVersion(_BaseVersion):
def __repr__(self):
# type: () -> str
return "<LegacyVersion({0})>".format(repr(str(self)))
return f'<LegacyVersion({repr(str(self))})>'
@property
def public(self):
@ -173,14 +174,14 @@ class LegacyVersion(_BaseVersion):
return False
_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE)
_legacy_version_component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
_legacy_version_replacement_map = {
"pre": "c",
"preview": "c",
"-": "final-",
"rc": "c",
"dev": "@",
'pre': 'c',
'preview': 'c',
'-': 'final-',
'rc': 'c',
'dev': '@',
}
@ -189,17 +190,17 @@ def _parse_version_parts(s):
for part in _legacy_version_component_re.split(s):
part = _legacy_version_replacement_map.get(part, part)
if not part or part == ".":
if not part or part == '.':
continue
if part[:1] in "0123456789":
if part[:1] in '0123456789':
# pad for numeric comparison
yield part.zfill(8)
else:
yield "*" + part
yield '*' + part
# ensure that alpha/beta/candidate are before final
yield "*final"
yield '*final'
def _legacy_cmpkey(version):
@ -215,14 +216,14 @@ def _legacy_cmpkey(version):
# it's adoption of the packaging library.
parts = [] # type: List[str]
for part in _parse_version_parts(version.lower()):
if part.startswith("*"):
if part.startswith('*'):
# remove "-" before a prerelease tag
if part < "*final":
while parts and parts[-1] == "*final-":
if part < '*final':
while parts and parts[-1] == '*final-':
parts.pop()
# remove trailing zeros from each series of numeric parts
while parts and parts[-1] == "00000000":
while parts and parts[-1] == '00000000':
parts.pop()
parts.append(part)
@ -266,7 +267,7 @@ VERSION_PATTERN = r"""
class Version(_BaseVersion):
_regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r'^\s*' + VERSION_PATTERN + r'\s*$', re.VERBOSE | re.IGNORECASE)
def __init__(self, version):
# type: (str) -> None
@ -274,18 +275,18 @@ class Version(_BaseVersion):
# Validate the version and parse it into pieces
match = self._regex.search(version)
if not match:
raise InvalidVersion("Invalid version: '{0}'".format(version))
raise InvalidVersion(f"Invalid version: '{version}'")
# Store the parsed out pieces of the version
self._version = _Version(
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
release=tuple(int(i) for i in match.group("release").split(".")),
pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
epoch=int(match.group('epoch')) if match.group('epoch') else 0,
release=tuple(int(i) for i in match.group('release').split('.')),
pre=_parse_letter_version(match.group('pre_l'), match.group('pre_n')),
post=_parse_letter_version(
match.group("post_l"), match.group("post_n1") or match.group("post_n2")
match.group('post_l'), match.group('post_n1') or match.group('post_n2'),
),
dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
local=_parse_local_version(match.group("local")),
dev=_parse_letter_version(match.group('dev_l'), match.group('dev_n')),
local=_parse_local_version(match.group('local')),
)
# Generate a key which will be used for sorting
@ -300,7 +301,7 @@ class Version(_BaseVersion):
def __repr__(self):
# type: () -> str
return "<Version({0})>".format(repr(str(self)))
return f'<Version({repr(str(self))})>'
def __str__(self):
# type: () -> str
@ -308,28 +309,28 @@ class Version(_BaseVersion):
# Epoch
if self.epoch != 0:
parts.append("{0}!".format(self.epoch))
parts.append(f'{self.epoch}!')
# Release segment
parts.append(".".join(str(x) for x in self.release))
parts.append('.'.join(str(x) for x in self.release))
# Pre-release
if self.pre is not None:
parts.append("".join(str(x) for x in self.pre))
parts.append(''.join(str(x) for x in self.pre))
# Post-release
if self.post is not None:
parts.append(".post{0}".format(self.post))
parts.append(f'.post{self.post}')
# Development release
if self.dev is not None:
parts.append(".dev{0}".format(self.dev))
parts.append(f'.dev{self.dev}')
# Local version segment
if self.local is not None:
parts.append("+{0}".format(self.local))
parts.append(f'+{self.local}')
return "".join(parts)
return ''.join(parts)
@property
def epoch(self):
@ -363,14 +364,14 @@ class Version(_BaseVersion):
def local(self):
# type: () -> Optional[str]
if self._version.local:
return ".".join(str(x) for x in self._version.local)
return '.'.join(str(x) for x in self._version.local)
else:
return None
@property
def public(self):
# type: () -> str
return str(self).split("+", 1)[0]
return str(self).split('+', 1)[0]
@property
def base_version(self):
@ -379,12 +380,12 @@ class Version(_BaseVersion):
# Epoch
if self.epoch != 0:
parts.append("{0}!".format(self.epoch))
parts.append(f'{self.epoch}!')
# Release segment
parts.append(".".join(str(x) for x in self.release))
parts.append('.'.join(str(x) for x in self.release))
return "".join(parts)
return ''.join(parts)
@property
def is_prerelease(self):
@ -435,27 +436,27 @@ def _parse_letter_version(
# We consider some words to be alternate spellings of other words and
# in those cases we want to normalize the spellings to our preferred
# spelling.
if letter == "alpha":
letter = "a"
elif letter == "beta":
letter = "b"
elif letter in ["c", "pre", "preview"]:
letter = "rc"
elif letter in ["rev", "r"]:
letter = "post"
if letter == 'alpha':
letter = 'a'
elif letter == 'beta':
letter = 'b'
elif letter in ['c', 'pre', 'preview']:
letter = 'rc'
elif letter in ['rev', 'r']:
letter = 'post'
return letter, int(number)
if not letter and number:
# We assume if we are given a number, but we are not given a letter
# then this is using the implicit post release syntax (e.g. 1.0-1)
letter = "post"
letter = 'post'
return letter, int(number)
return None
_local_version_separators = re.compile(r"[\._-]")
_local_version_separators = re.compile(r'[\._-]')
def _parse_local_version(local):
@ -487,7 +488,7 @@ def _cmpkey(
# re-reverse it back into the correct order and make it a tuple and use
# that for our sorting key.
_release = tuple(
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))),
)
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
@ -529,7 +530,7 @@ def _cmpkey(
# - Shorter versions sort before longer versions when the prefixes
# match exactly
_local = tuple(
(i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
(i, '') if isinstance(i, int) else (NegativeInfinity, i) for i in local
)
return epoch, _release, _pre, _post, _dev, _local

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import importlib.util
import sys
@ -42,10 +44,10 @@ class VendorImporter:
pass
else:
raise ImportError(
"The '{target}' package is required; "
"normally this is bundled with this package so if you get "
"this warning, consult the packager of your "
"distribution.".format(**locals())
f"The '{target}' package is required; "
f'normally this is bundled with this package so if you get '
f'this warning, consult the packager of your '
f'distribution.',
)
def create_module(self, spec):

View file

@ -1,6 +1,8 @@
from __future__ import annotations
import setuptools
setuptools.setup(
name="my-test-package",
version="1.0",
name='my-test-package',
version='1.0',
zip_safe=True,
)