diff --git a/_distutils_hack/__init__.py b/_distutils_hack/__init__.py index 5f40996a67e..ce923239b2b 100644 --- a/_distutils_hack/__init__.py +++ b/_distutils_hack/__init__.py @@ -8,9 +8,7 @@ is_pypy = '__pypy__' in sys.builtin_module_names -warnings.filterwarnings('ignore', - r'.+ distutils\b.+ deprecated', - DeprecationWarning) +warnings.filterwarnings('ignore', r'.+ distutils\b.+ deprecated', DeprecationWarning) def warn_distutils_present(): @@ -26,7 +24,8 @@ def warn_distutils_present(): "to undesirable behaviors or errors. To avoid these issues, avoid " "using distutils directly, ensure that setuptools is installed in the " "traditional way (e.g. not an editable install), and/or make sure " - "that setuptools is always imported before distutils.") + "that setuptools is always imported before distutils." + ) def clear_distutils(): @@ -83,7 +82,6 @@ def spec_for_distutils(self): import importlib.util class DistutilsLoader(importlib.abc.Loader): - def create_module(self, spec): return importlib.import_module('setuptools._distutils') @@ -108,6 +106,7 @@ def pip_imported_during_build(): Detect if pip is being imported in a build script. Ref #2355. """ import traceback + return any( frame.f_globals['__file__'].endswith('setup.py') for frame, line in traceback.walk_stack(None) diff --git a/conftest.py b/conftest.py index d5e851fe50b..156f162c113 100644 --- a/conftest.py +++ b/conftest.py @@ -6,7 +6,9 @@ def pytest_addoption(parser): parser.addoption( - "--package_name", action="append", default=[], + "--package_name", + action="append", + default=[], help="list of package_name to pass to test functions", ) diff --git a/pavement.py b/pavement.py index 81ff6f12015..bce43c56227 100644 --- a/pavement.py +++ b/pavement.py @@ -35,21 +35,20 @@ def clean(vendor): Remove all files out of the vendor directory except the meta data (as pip uninstall doesn't support -t). """ - remove_all( - path - for path in vendor.glob('*') - if path.basename() != 'vendored.txt' - ) + remove_all(path for path in vendor.glob('*') if path.basename() != 'vendored.txt') def install(vendor): clean(vendor) install_args = [ sys.executable, - '-m', 'pip', + '-m', + 'pip', 'install', - '-r', str(vendor / 'vendored.txt'), - '-t', str(vendor), + '-r', + str(vendor / 'vendored.txt'), + '-t', + str(vendor), ] subprocess.check_call(install_args) remove_all(vendor.glob('*.dist-info')) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index c84f1dd9e89..1a64a2a4198 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -54,8 +54,10 @@ # capture these to bypass sandboxing from os import utime + try: from os import mkdir, rename, unlink + WRITE_SUPPORT = True except ImportError: # no write support, probably under GAE @@ -66,6 +68,7 @@ try: import importlib.machinery as importlib_machinery + # access attribute to force import under delayed import mechanisms. importlib_machinery.__name__ except ImportError: @@ -73,6 +76,7 @@ from pkg_resources.extern import appdirs from pkg_resources.extern import packaging + __import__('pkg_resources.extern.packaging.version') __import__('pkg_resources.extern.packaging.specifiers') __import__('pkg_resources.extern.packaging.requirements') @@ -185,51 +189,87 @@ def get_supported_platform(): __all__ = [ # Basic resource access and distribution/entry point discovery - 'require', 'run_script', 'get_provider', 'get_distribution', - 'load_entry_point', 'get_entry_map', 'get_entry_info', + 'require', + 'run_script', + 'get_provider', + 'get_distribution', + 'load_entry_point', + 'get_entry_map', + 'get_entry_info', 'iter_entry_points', - 'resource_string', 'resource_stream', 'resource_filename', - 'resource_listdir', 'resource_exists', 'resource_isdir', - + 'resource_string', + 'resource_stream', + 'resource_filename', + 'resource_listdir', + 'resource_exists', + 'resource_isdir', # Environmental control - 'declare_namespace', 'working_set', 'add_activation_listener', - 'find_distributions', 'set_extraction_path', 'cleanup_resources', + 'declare_namespace', + 'working_set', + 'add_activation_listener', + 'find_distributions', + 'set_extraction_path', + 'cleanup_resources', 'get_default_cache', - # Primary implementation classes - 'Environment', 'WorkingSet', 'ResourceManager', - 'Distribution', 'Requirement', 'EntryPoint', - + 'Environment', + 'WorkingSet', + 'ResourceManager', + 'Distribution', + 'Requirement', + 'EntryPoint', # Exceptions - 'ResolutionError', 'VersionConflict', 'DistributionNotFound', - 'UnknownExtra', 'ExtractionError', - + 'ResolutionError', + 'VersionConflict', + 'DistributionNotFound', + 'UnknownExtra', + 'ExtractionError', # Warnings 'PEP440Warning', - # Parsing functions and string utilities - 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', - 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', - 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', - + 'parse_requirements', + 'parse_version', + 'safe_name', + 'safe_version', + 'get_platform', + 'compatible_platforms', + 'yield_lines', + 'split_sections', + 'safe_extra', + 'to_filename', + 'invalid_marker', + 'evaluate_marker', # filesystem utilities - 'ensure_directory', 'normalize_path', - + 'ensure_directory', + 'normalize_path', # Distribution "precedence" constants - 'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST', - + 'EGG_DIST', + 'BINARY_DIST', + 'SOURCE_DIST', + 'CHECKOUT_DIST', + 'DEVELOP_DIST', # "Provider" interfaces, implementations, and registration/lookup APIs - 'IMetadataProvider', 'IResourceProvider', 'FileMetadata', - 'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider', - 'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider', - 'register_finder', 'register_namespace_handler', 'register_loader_type', - 'fixup_namespace_packages', 'get_importer', - + 'IMetadataProvider', + 'IResourceProvider', + 'FileMetadata', + 'PathMetadata', + 'EggMetadata', + 'EmptyProvider', + 'empty_provider', + 'NullProvider', + 'EggProvider', + 'DefaultProvider', + 'ZipProvider', + 'register_finder', + 'register_namespace_handler', + 'register_loader_type', + 'fixup_namespace_packages', + 'get_importer', # Warnings 'PkgResourcesDeprecationWarning', - # Deprecated/backward compatibility only - 'run_main', 'AvailableDistributions', + 'run_main', + 'AvailableDistributions', ] @@ -288,8 +328,10 @@ def required_by(self): 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): @@ -383,7 +425,8 @@ def get_build_platform(): version = _macos_vers() machine = os.uname()[4].replace(" ", "_") return "macosx-%d.%d-%s" % ( - int(version[0]), int(version[1]), + int(version[0]), + int(version[1]), _macos_arch(machine), ) except ValueError: @@ -424,15 +467,18 @@ def compatible_platforms(provided, required): 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": + 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 # are they the same major version and machine type? - if provMac.group(1) != reqMac.group(1) or \ - provMac.group(3) != reqMac.group(3): + if provMac.group(1) != reqMac.group(1) or provMac.group(3) != reqMac.group(3): return False # is the required OS major update >= the provided one? @@ -494,8 +540,8 @@ def get_metadata(name): def get_metadata_lines(name): """Yield named metadata resource as list of non-blank non-comment lines - Leading and trailing whitespace is stripped from each line, and lines - with ``#`` as the first non-blank character are omitted.""" + Leading and trailing whitespace is stripped from each line, and lines + with ``#`` as the first non-blank character are omitted.""" def metadata_isdir(name): """Is the named metadata a directory? (like ``os.path.isdir()``)""" @@ -698,8 +744,14 @@ def add(self, dist, entry=None, insert=True, replace=False): 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`, @@ -764,8 +816,7 @@ def resolve(self, requirements, env=None, installer=None, # noqa: C901 env = Environment([]) ws = WorkingSet([]) dist = best[req.key] = env.best_match( - req, ws, installer, - replace_conflicting=replace_conflicting + req, ws, installer, replace_conflicting=replace_conflicting ) if dist is None: requirers = required_by.get(req, None) @@ -790,8 +841,7 @@ def resolve(self, requirements, env=None, installer=None, # noqa: C901 # return list of distros to activate return to_activate - def find_plugins( - self, plugin_env, full_env=None, installer=None, fallback=True): + def find_plugins(self, plugin_env, full_env=None, installer=None, fallback=True): """Find all activatable distributions in `plugin_env` Example usage:: @@ -910,8 +960,10 @@ def _added_new(self, dist): def __getstate__(self): return ( - self.entries[:], self.entry_keys.copy(), self.by_key.copy(), - self.callbacks[:] + self.entries[:], + self.entry_keys.copy(), + self.by_key.copy(), + self.callbacks[:], ) def __setstate__(self, e_k_b_c): @@ -946,8 +998,8 @@ class Environment: """Searchable snapshot of distributions on a search path""" def __init__( - self, search_path=None, platform=get_supported_platform(), - python=PY_MAJOR): + self, search_path=None, platform=get_supported_platform(), python=PY_MAJOR + ): """Snapshot distributions available on a search path Any distributions found on `search_path` are added to the environment. @@ -1014,16 +1066,14 @@ def __getitem__(self, project_name): return self._distmap.get(distribution_key, []) def add(self, dist): - """Add `dist` if we ``can_add()`` it and it has not already been added - """ + """Add `dist` if we ``can_add()`` it and it has not already been added""" if self.can_add(dist) and dist.has_version(): dists = self._distmap.setdefault(dist.key, []) if dist not in dists: dists.append(dist) dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) - def best_match( - self, req, working_set, installer=None, replace_conflicting=False): + def best_match(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 @@ -1110,6 +1160,7 @@ class ExtractionError(RuntimeError): class ResourceManager: """Manage resource extraction and packages""" + extraction_path = None def __init__(self): @@ -1121,9 +1172,7 @@ def resource_exists(self, package_or_requirement, resource_name): 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 - ) + return get_provider(package_or_requirement).resource_isdir(resource_name) def resource_filename(self, package_or_requirement, resource_name): """Return a true filesystem path for specified resource""" @@ -1145,9 +1194,7 @@ def resource_string(self, package_or_requirement, 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 - ) + return get_provider(package_or_requirement).resource_listdir(resource_name) def extraction_error(self): """Give an error message for problems extracting file(s)""" @@ -1155,7 +1202,8 @@ def extraction_error(self): old_exc = sys.exc_info()[1] cache_path = self.extraction_path or get_default_cache() - tmpl = textwrap.dedent(""" + tmpl = textwrap.dedent( + """ Can't extract file(s) to egg cache The following error occurred while trying to extract file(s) @@ -1170,7 +1218,8 @@ def extraction_error(self): Perhaps your account does not have write access to this directory? You can change the cache directory by setting the PYTHON_EGG_CACHE environment variable to point to an accessible directory. - """).lstrip() + """ + ).lstrip() err = ExtractionError(tmpl.format(**locals())) err.manager = self err.cache_path = cache_path @@ -1269,9 +1318,7 @@ def set_extraction_path(self, path): ``cleanup_resources()``.) """ if self.cached_files: - raise ValueError( - "Can't change extraction path, files already extracted" - ) + raise ValueError("Can't change extraction path, files already extracted") self.extraction_path = path @@ -1295,9 +1342,8 @@ def get_default_cache(): or a platform-relevant user cache dir for an app named "Python-Eggs". """ - return ( - os.environ.get('PYTHON_EGG_CACHE') - or appdirs.user_cache_dir(appname='Python-Eggs') + return os.environ.get('PYTHON_EGG_CACHE') or appdirs.user_cache_dir( + appname='Python-Eggs' ) @@ -1434,8 +1480,9 @@ def run_script(self, script_name, namespace): 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()), + "Script {script!r} not found in metadata at {self.egg_info!r}".format( + **locals() + ), ) script_text = self.get_metadata(script).replace('\r\n', '\n') script_text = script_text.replace('\r', '\n') @@ -1448,8 +1495,12 @@ def run_script(self, script_name, namespace): exec(code, namespace, namespace) 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) @@ -1529,9 +1580,9 @@ def _validate_resource_path(path): AttributeError: ... """ invalid = ( - os.path.pardir in path.split(posixpath.sep) or - posixpath.isabs(path) or - ntpath.isabs(path) + os.path.pardir in path.split(posixpath.sep) + or posixpath.isabs(path) + or ntpath.isabs(path) ) if not invalid: return @@ -1613,7 +1664,10 @@ def _get(self, path): @classmethod def _register(cls): - loader_names = 'SourceFileLoader', 'SourcelessFileLoader', + loader_names = ( + 'SourceFileLoader', + 'SourcelessFileLoader', + ) for name in loader_names: loader_cls = getattr(importlib_machinery, name, type(None)) register_loader_type(loader_cls, cls) @@ -1673,6 +1727,7 @@ class MemoizedZipManifests(ZipManifests): """ Memoized zipfile manifests. """ + manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime') def load(self, path): @@ -1706,20 +1761,16 @@ def _zipinfo_name(self, fspath): if fspath == self.loader.archive: return '' 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) - ) + return fspath[len(self.zip_pre) :] + raise AssertionError("%s is not a subpath of %s" % (fspath, self.zip_pre)) def _parts(self, zip_path): # Convert a zipfile subpath into an egg-relative path part list. # pseudo-fs path fspath = self.zip_pre + zip_path 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) - ) + return fspath[len(self.egg_root) + 1 :].split(os.sep) + raise AssertionError("%s is not a subpath of %s" % (fspath, self.egg_root)) @property def zipinfo(self): @@ -1752,22 +1803,19 @@ def _extract_resource(self, manager, zip_path): # noqa: C901 if zip_path in self._index(): for name in self._index()[zip_path]: - last = self._extract_resource( - manager, os.path.join(zip_path, name) - ) + last = self._extract_resource(manager, os.path.join(zip_path, name)) # return the extracted directory name return os.path.dirname(last) 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 IOError( + '"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) - ) + real_path = manager.get_cache_path(self.egg_name, self._parts(zip_path)) if self._is_current(real_path, zip_path): return real_path @@ -2018,6 +2066,7 @@ def _by_version_descending(names): >>> _by_version_descending(names) ['Setuptools-1.2.3.post1.egg', 'Setuptools-1.2.3b1.egg'] """ + def _by_version(name): """ Parse each component of the filename @@ -2035,25 +2084,17 @@ 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, + metadata=PathMetadata(path_item, os.path.join(path_item, 'EGG-INFO')), ) return - entries = ( - os.path.join(path_item, child) - for child in safe_listdir(path_item) - ) + entries = (os.path.join(path_item, child) for child in safe_listdir(path_item)) # for performance, before sorting by version, # screen entries for only those that will yield # distributions - filtered = ( - entry - for entry in entries - if dist_factory(path_item, entry, only) - ) + filtered = (entry for entry in entries if dist_factory(path_item, entry, only)) # scan for .egg and .egg-info in directory path_item_entries = _by_version_descending(filtered) @@ -2068,19 +2109,18 @@ def dist_factory(path_item, entry, only): """Return a dist_factory for the given entry.""" lower = entry.lower() is_egg_info = lower.endswith('.egg-info') - is_dist_info = ( - lower.endswith('.dist-info') and - os.path.isdir(os.path.join(path_item, entry)) + is_dist_info = lower.endswith('.dist-info') and os.path.isdir( + os.path.join(path_item, entry) ) is_meta = is_egg_info or is_dist_info return ( distributions_from_metadata - if is_meta else - find_distributions - if not only and _is_egg_path(entry) else - resolve_egg_link - if not only and lower.endswith('.egg-link') else - NoDists() + if is_meta + else find_distributions + if not only and _is_egg_path(entry) + else resolve_egg_link + if not only and lower.endswith('.egg-link') + else NoDists() ) @@ -2092,6 +2132,7 @@ class NoDists: >>> list(NoDists()('anything')) [] """ + def __bool__(self): return False @@ -2126,7 +2167,10 @@ def distributions_from_metadata(path): metadata = FileMetadata(path) entry = os.path.basename(path) yield Distribution.from_location( - root, entry, metadata, precedence=DEVELOP_DIST, + root, + entry, + metadata, + precedence=DEVELOP_DIST, ) @@ -2148,8 +2192,7 @@ def resolve_egg_link(path): """ referenced_paths = non_empty_lines(path) resolved_paths = ( - os.path.join(os.path.dirname(path), ref) - for ref in referenced_paths + os.path.join(os.path.dirname(path), ref) for ref in referenced_paths ) dist_groups = map(find_distributions, resolved_paths) return next(dist_groups, ()) @@ -2326,8 +2369,7 @@ def null_ns_handler(importer, path_item, packageName, module): 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 @@ -2358,9 +2400,9 @@ def _is_egg_path(path): def _is_zip_egg(path): return ( - path.lower().endswith('.egg') and - os.path.isfile(path) and - zipfile.is_zipfile(path) + path.lower().endswith('.egg') + and os.path.isfile(path) + and zipfile.is_zipfile(path) ) @@ -2368,9 +2410,8 @@ def _is_unpacked_egg(path): """ Determine if given path appears to be an unpacked egg. """ - return ( - path.lower().endswith('.egg') and - os.path.isfile(os.path.join(path, 'EGG-INFO', 'PKG-INFO')) + return path.lower().endswith('.egg') and os.path.isfile( + os.path.join(path, 'EGG-INFO', 'PKG-INFO') ) @@ -2548,8 +2589,10 @@ def _version_from_file(lines): Given an iterable of lines from a Metadata file, return the value of the Version field, if present, or None otherwise. """ + def is_version_line(line): return line.lower().startswith('version:') + version_lines = filter(is_version_line, lines) line = next(iter(version_lines), '') _, _, value = line.partition(':') @@ -2558,12 +2601,19 @@ def is_version_line(line): class Distribution: """Wrap an actual or potential sys.path entry w/metadata""" + PKG_INFO = 'PKG-INFO' def __init__( - self, location=None, metadata=None, project_name=None, - version=None, py_version=PY_MAJOR, platform=None, - precedence=EGG_DIST): + self, + location=None, + metadata=None, + project_name=None, + version=None, + py_version=PY_MAJOR, + platform=None, + precedence=EGG_DIST, + ): self.project_name = safe_name(project_name or 'Unknown') if version is not None: self._version = safe_version(version) @@ -2586,8 +2636,13 @@ def from_location(cls, location, basename, metadata=None, **kw): 'name', 'ver', 'pyver', 'plat' ) return cls( - location, metadata, project_name=project_name, version=version, - py_version=py_version, platform=platform, **kw + location, + metadata, + project_name=project_name, + version=version, + py_version=py_version, + platform=platform, + **kw )._reload_version() def _reload_version(self): @@ -2662,14 +2717,20 @@ def _warn_legacy_version(self): if not self.version: return - tmpl = textwrap.dedent(""" + tmpl = ( + textwrap.dedent( + """ '{project_name} ({version})' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommended to migrate to PEP 440 compatible versions. - """).strip().replace('\n', ' ') + """ + ) + .strip() + .replace('\n', ' ') + ) warnings.warn(tmpl.format(**vars(self)), PEP440Warning) @@ -2681,9 +2742,9 @@ def version(self): version = self._get_version() if version is None: path = self._get_metadata_path_for_display(self.PKG_INFO) - msg = ( - "Missing 'Version:' header and/or {} file at path: {}" - ).format(self.PKG_INFO, path) + msg = ("Missing 'Version:' header and/or {} file at path: {}").format( + self.PKG_INFO, path + ) raise ValueError(msg, self) from e return version @@ -2712,8 +2773,7 @@ def _filter_extras(dm): 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 = [] @@ -2785,8 +2845,9 @@ def activate(self, path=None, replace=False): def egg_name(self): """Return what this distribution's standard .egg filename should be""" filename = "%s-%s-py%s" % ( - to_filename(self.project_name), to_filename(self.version), - self.py_version or PY_MAJOR + to_filename(self.project_name), + to_filename(self.version), + self.py_version or PY_MAJOR, ) if self.platform: @@ -2816,17 +2877,13 @@ def __getattr__(self, attr): def __dir__(self): return list( set(super(Distribution, self).__dir__()) - | set( - attr for attr in self._provider.__dir__() - if not attr.startswith('_') - ) + | set(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 + _normalize_cached(filename), os.path.basename(filename), metadata, **kw ) def as_requirement(self): @@ -2938,14 +2995,18 @@ def check_version_conflict(self): 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" @@ -2997,6 +3058,7 @@ class DistInfoDistribution(Distribution): Wrap an actual or potential sys.path entry w/metadata, .dist-info style. """ + PKG_INFO = 'METADATA' EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])") @@ -3073,7 +3135,7 @@ def parse_requirements(strs): for line in lines: # Drop comments -- a hash without a space may be in a URL. if ' #' in line: - line = line[:line.find(' #')] + line = line[: line.find(' #')] # If there is a line continuation, drop it, and append the next line. if line.endswith('\\'): line = line[:-2].strip() @@ -3095,8 +3157,7 @@ def __init__(self, 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] + self.specs = [(spec.operator, spec.version) for spec in self.specifier] self.extras = tuple(map(safe_extra, self.extras)) self.hashCmp = ( self.key, @@ -3108,10 +3169,7 @@ def __init__(self, requirement_string): self.__hash = hash(self.hashCmp) def __eq__(self, other): - return ( - isinstance(other, Requirement) and - self.hashCmp == other.hashCmp - ) + return isinstance(other, Requirement) and self.hashCmp == other.hashCmp def __ne__(self, other): return not self == other @@ -3136,7 +3194,7 @@ def __repr__(self): @staticmethod def parse(s): - req, = parse_requirements(s) + (req,) = parse_requirements(s) return req @@ -3265,10 +3323,7 @@ def _initialize_master_working_set(): # ensure that all distributions added to the working set in the future # (e.g. by calling ``require()``) will get activated as well, # with higher priority (replace=True). - tuple( - dist.activate(replace=False) - for dist in working_set - ) + tuple(dist.activate(replace=False) for dist in working_set) add_activation_listener( lambda dist: dist.activate(replace=True), existing=False, diff --git a/pkg_resources/_vendor/appdirs.py b/pkg_resources/_vendor/appdirs.py index ae67001af8b..bc845937e32 100644 --- a/pkg_resources/_vendor/appdirs.py +++ b/pkg_resources/_vendor/appdirs.py @@ -27,12 +27,13 @@ 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 +42,6 @@ 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. @@ -144,9 +144,12 @@ 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'])) - pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + 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: appname = os.path.join(appname, version) @@ -241,7 +244,9 @@ def site_config_dir(appname=None, appauthor=None, version=None, multipath=False) # XDG default for $XDG_CONFIG_DIRS # only first, if multipath is False path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') - pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + pathlist = [ + os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) + ] if appname: if version: appname = os.path.join(appname, version) @@ -386,9 +391,7 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): This can be disabled with the `opinion=False` option. """ if system == "darwin": - path = os.path.join( - os.path.expanduser('~/Library/Logs'), - appname) + path = os.path.join(os.path.expanduser('~/Library/Logs'), appname) elif system == "win32": path = user_data_dir(appname, appauthor, version) version = False @@ -406,8 +409,10 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): class AppDirs(object): """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,41 +421,43 @@ def __init__(self, appname=None, appauthor=None, version=None, @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 -#---- internal support stuff def _get_win_folder_from_registry(csidl_name): """This is a fallback technique at best. I'm not sure if using the @@ -458,9 +465,9 @@ 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", @@ -470,7 +477,7 @@ def _get_win_folder_from_registry(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 @@ -478,6 +485,7 @@ def _get_win_folder_from_registry(csidl_name): def _get_win_folder_with_pywin32(csidl_name): from win32com.shell import shellcon, shell + dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) # Try to make this a unicode path because SHGetFolderPath does # not return unicode strings when there is unicode data in the @@ -495,6 +503,7 @@ def _get_win_folder_with_pywin32(csidl_name): if has_high_char: try: import win32api + dir = win32api.GetShortPathName(dir) except ImportError: pass @@ -529,6 +538,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 @@ -537,7 +547,13 @@ def _get_win_folder_with_jna(csidl_name): buf_size = win32.WinDef.MAX_PATH * 2 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) + shell.SHGetFolderPath( + None, + getattr(win32.ShlObj, csidl_name), + None, + win32.ShlObj.SHGFP_TYPE_CURRENT, + buf, + ) dir = jna.Native.toString(buf.tostring()).rstrip("\0") # Downgrade to short path name if have highbit chars. See @@ -555,35 +571,41 @@ def _get_win_folder_with_jna(csidl_name): return dir + if system == "win32": try: import win32com.shell + _get_win_folder = _get_win_folder_with_pywin32 except ImportError: try: from ctypes import windll + _get_win_folder = _get_win_folder_with_ctypes except ImportError: try: import com.sun.jna + _get_win_folder = _get_win_folder_with_jna except ImportError: _get_win_folder = _get_win_folder_from_registry -#---- self test code +# ---- self test code 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__) diff --git a/pkg_resources/_vendor/packaging/markers.py b/pkg_resources/_vendor/packaging/markers.py index fd1559c10e3..f0de5ce201e 100644 --- a/pkg_resources/_vendor/packaging/markers.py +++ b/pkg_resources/_vendor/packaging/markers.py @@ -8,7 +8,12 @@ import platform import sys -from pkg_resources.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd +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 Literal as L # noqa diff --git a/pkg_resources/_vendor/packaging/requirements.py b/pkg_resources/_vendor/packaging/requirements.py index 9495a1df1e6..b6b6ddaeae3 100644 --- a/pkg_resources/_vendor/packaging/requirements.py +++ b/pkg_resources/_vendor/packaging/requirements.py @@ -6,7 +6,12 @@ import string import re -from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +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 from urllib import parse as urlparse diff --git a/pkg_resources/_vendor/packaging/specifiers.py b/pkg_resources/_vendor/packaging/specifiers.py index fe09bb1dbb2..ef3bdb5011e 100644 --- a/pkg_resources/_vendor/packaging/specifiers.py +++ b/pkg_resources/_vendor/packaging/specifiers.py @@ -317,7 +317,7 @@ def _compare_greater_than(self, prospective, spec): 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) diff --git a/pkg_resources/_vendor/pyparsing.py b/pkg_resources/_vendor/pyparsing.py index 4cae7883870..90ad5be7db8 100644 --- a/pkg_resources/_vendor/pyparsing.py +++ b/pkg_resources/_vendor/pyparsing.py @@ -22,8 +22,7 @@ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__doc__ = \ -""" +__doc__ = """ pyparsing module - Classes and methods to define and execute parsing grammars ============================================================================= @@ -113,27 +112,114 @@ class names, and the use of '+', '|' and '^' operators. except ImportError: _OrderedDict = None -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) +# ~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) __all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', -'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', -'CloseMatch', 'tokenMap', 'pyparsing_common', + 'And', + 'CaselessKeyword', + 'CaselessLiteral', + 'CharsNotIn', + 'Combine', + 'Dict', + 'Each', + 'Empty', + 'FollowedBy', + 'Forward', + 'GoToColumn', + 'Group', + 'Keyword', + 'LineEnd', + 'LineStart', + 'Literal', + 'MatchFirst', + 'NoMatch', + 'NotAny', + 'OneOrMore', + 'OnlyOnce', + 'Optional', + 'Or', + 'ParseBaseException', + 'ParseElementEnhance', + 'ParseException', + 'ParseExpression', + 'ParseFatalException', + 'ParseResults', + 'ParseSyntaxException', + 'ParserElement', + 'QuotedString', + 'RecursiveGrammarException', + 'Regex', + 'SkipTo', + 'StringEnd', + 'StringStart', + 'Suppress', + 'Token', + 'TokenConverter', + 'White', + 'Word', + 'WordEnd', + 'WordStart', + 'ZeroOrMore', + 'alphanums', + 'alphas', + 'alphas8bit', + 'anyCloseTag', + 'anyOpenTag', + 'cStyleComment', + 'col', + 'commaSeparatedList', + 'commonHTMLEntity', + 'countedArray', + 'cppStyleComment', + 'dblQuotedString', + 'dblSlashComment', + 'delimitedList', + 'dictOf', + 'downcaseTokens', + 'empty', + 'hexnums', + 'htmlComment', + 'javaStyleComment', + 'line', + 'lineEnd', + 'lineStart', + 'lineno', + 'makeHTMLTags', + 'makeXMLTags', + 'matchOnlyAtCol', + 'matchPreviousExpr', + 'matchPreviousLiteral', + 'nestedExpr', + 'nullDebugAction', + 'nums', + 'oneOf', + 'opAssoc', + 'operatorPrecedence', + 'printables', + 'punc8bit', + 'pythonStyleComment', + 'quotedString', + 'removeQuotes', + 'replaceHTMLEntity', + 'replaceWith', + 'restOfLine', + 'sglQuotedString', + 'srange', + 'stringEnd', + 'stringStart', + 'traceParseAction', + 'unicodeString', + 'upcaseTokens', + 'withAttribute', + 'indentedBlock', + 'originalTextFor', + 'ungroup', + 'infixNotation', + 'locatedExpr', + 'withClass', + 'CloseMatch', + 'tokenMap', + 'pyparsing_common', ] system_version = tuple(sys.version_info)[:3] @@ -145,7 +231,19 @@ class names, and the use of '+', '|' and '^' operators. _ustr = str # build list of single arg builtins, that can be used as parse actions - singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] + singleArgBuiltins = [ + sum, + len, + sorted, + reversed, + list, + tuple, + set, + any, + all, + min, + max, + ] else: _MAX_INT = sys.maxint @@ -153,10 +251,10 @@ class names, and the use of '+', '|' and '^' operators. def _ustr(obj): """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. + str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It + then < returns the unicode object | encodes it with the default encoding | ... >. """ - if isinstance(obj,unicode): + if isinstance(obj, unicode): return obj try: @@ -174,39 +272,45 @@ def _ustr(obj): # build list of single arg builtins, tolerant of Python version, that can be used as parse actions singleArgBuiltins = [] import __builtin__ + for fname in "sum len sorted reversed list tuple set any all min max".split(): try: - singleArgBuiltins.append(getattr(__builtin__,fname)) + singleArgBuiltins.append(getattr(__builtin__, fname)) except AttributeError: continue - + _generatorType = type((y for y in range(1))) - + + def _xml_escape(data): """Escape &, <, >, ", ', etc. in a string of data.""" # ampersand must be replaced first from_symbols = '&><"\'' - to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) - for from_,to_ in zip(from_symbols, to_symbols): + to_symbols = ('&' + s + ';' for s in "amp gt lt quot apos".split()) + for from_, to_ in zip(from_symbols, to_symbols): data = data.replace(from_, to_) return data + class _Constants(object): pass -alphas = string.ascii_uppercase + string.ascii_lowercase -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) + +alphas = string.ascii_uppercase + string.ascii_lowercase +nums = "0123456789" +hexnums = nums + "ABCDEFabcdef" +alphanums = alphas + nums +_bslash = chr(92) printables = "".join(c for c in string.printable if c not in string.whitespace) + class ParseBaseException(Exception): """base exception class for all parsing runtime exceptions""" + # Performance tuning: we construct a *lot* of these, so keep this # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): + def __init__(self, pstr, loc=0, msg=None, elem=None): self.loc = loc if msg is None: self.msg = pstr @@ -220,44 +324,53 @@ def __init__( self, pstr, loc=0, msg=None, elem=None ): @classmethod def _from_exception(cls, pe): """ - internal factory method to simplify creating one type of ParseException + internal factory method to simplify creating one type of ParseException from another - avoids having __init__ signature conflicts among subclasses """ return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) - def __getattr__( self, aname ): + def __getattr__(self, aname): """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) + if aname == "lineno": + return lineno(self.loc, self.pstr) + elif aname in ("col", "column"): + return col(self.loc, self.pstr) + elif aname == "line": + return line(self.loc, self.pstr) else: raise AttributeError(aname) - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): + def __str__(self): + return "%s (at char %d), (line:%d, col:%d)" % ( + self.msg, + self.loc, + self.lineno, + self.column, + ) + + def __repr__(self): return _ustr(self) - def markInputline( self, markerString = ">!<" ): + + def markInputline(self, markerString=">!<"): """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. + the location of the exception with a special symbol. """ line_str = self.line line_column = self.column - 1 if markerString: - line_str = "".join((line_str[:line_column], - markerString, line_str[line_column:])) + line_str = "".join( + (line_str[:line_column], markerString, line_str[line_column:]) + ) return line_str.strip() + def __dir__(self): return "lineno col line".split() + dir(type(self)) + class ParseException(ParseBaseException): """ Exception thrown when parse expressions don't match class; @@ -265,61 +378,74 @@ class ParseException(ParseBaseException): - lineno - returns the line number of the exception text - col - returns the column number of the exception text - line - returns the line containing the exception text - + Example:: try: Word(nums).setName("integer").parseString("ABC") except ParseException as pe: print(pe) print("column: {}".format(pe.col)) - + prints:: Expected integer (at char 0), (line:1, col:1) column: 1 """ + pass + class ParseFatalException(ParseBaseException): """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" + is found; stops all parsing immediately""" + pass + class ParseSyntaxException(ParseFatalException): """just like L{ParseFatalException}, but thrown internally when an - L{ErrorStop} ('-' operator) indicates that parsing is to stop - immediately because an unbacktrackable syntax error has been found""" + L{ErrorStop} ('-' operator) indicates that parsing is to stop + immediately because an unbacktrackable syntax error has been found""" + pass -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc + +# ~ class ReparseException(ParseBaseException): +# ~ """Experimental class - parse actions can raise this exception to cause +# ~ pyparsing to reparse the input string: +# ~ - with a modified input string, and/or +# ~ - with a modified start location +# ~ Set the values of the ReparseException in the constructor, and raise the +# ~ exception in a parse action to cause pyparsing to use the new string/location. +# ~ Setting the values as None causes no change to be made. +# ~ """ +# ~ def __init_( self, newstring, restartLoc ): +# ~ self.newParseText = newstring +# ~ self.reparseLoc = restartLoc + class RecursiveGrammarException(Exception): """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): + + def __init__(self, parseElementList): self.parseElementTrace = parseElementList - def __str__( self ): + def __str__(self): return "RecursiveGrammarException: %s" % self.parseElementTrace + class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): + def __init__(self, p1, p2): + self.tup = (p1, p2) + + def __getitem__(self, i): return self.tup[i] + def __repr__(self): return repr(self.tup[0]) - def setOffset(self,i): - self.tup = (self.tup[0],i) + + def setOffset(self, i): + self.tup = (self.tup[0], i) + class ParseResults(object): """ @@ -330,8 +456,8 @@ class ParseResults(object): Example:: integer = Word(nums) - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + integer.setResultsName("day")) # equivalent form: # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") @@ -360,7 +486,8 @@ def test(s, fn=repr): - month: 12 - year: 1999 """ - def __new__(cls, toklist=None, name=None, asList=True, modal=True ): + + def __new__(cls, toklist=None, name=None, asList=True, modal=True): if isinstance(toklist, cls): return toklist retobj = object.__new__(cls) @@ -369,7 +496,9 @@ def __new__(cls, toklist=None, name=None, asList=True, modal=True ): # Performance tuning: we construct a *lot* of these, so keep this # constructor as small and fast as possible - def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): + def __init__( + self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance + ): if self.__doinit: self.__doinit = False self.__name = None @@ -390,89 +519,109 @@ def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance if name is not None and name: if not modal: self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency + if isinstance(name, int): + name = _ustr( + name + ) # will always return a str, but use _ustr for consistency self.__name = name - if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): - if isinstance(toklist,basestring): - toklist = [ toklist ] + if not ( + isinstance(toklist, (type(None), basestring, list)) + and toklist in (None, '', []) + ): + if isinstance(toklist, basestring): + toklist = [toklist] if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) + if isinstance(toklist, ParseResults): + self[name] = _ParseResultsWithOffset(toklist.copy(), 0) else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) + self[name] = _ParseResultsWithOffset( + ParseResults(toklist[0]), 0 + ) self[name].__name = name else: try: self[name] = toklist[0] - except (KeyError,TypeError,IndexError): + except (KeyError, TypeError, IndexError): self[name] = toklist - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): + def __getitem__(self, i): + if isinstance(i, (int, slice)): return self.__toklist[i] else: if i not in self.__accumNames: return self.__tokdict[i][-1][0] else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) + return ParseResults([v[0] for v in self.__tokdict[i]]) - def __setitem__( self, k, v, isinstance=isinstance ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] + def __setitem__(self, k, v, isinstance=isinstance): + if isinstance(v, _ParseResultsWithOffset): + self.__tokdict[k] = self.__tokdict.get(k, list()) + [v] sub = v[0] - elif isinstance(k,(int,slice)): + elif isinstance(k, (int, slice)): self.__toklist[k] = v sub = v else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] + self.__tokdict[k] = self.__tokdict.get(k, list()) + [ + _ParseResultsWithOffset(v, 0) + ] sub = v - if isinstance(sub,ParseResults): + if isinstance(sub, ParseResults): sub.__parent = wkref(self) - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) + def __delitem__(self, i): + if isinstance(i, (int, slice)): + mylen = len(self.__toklist) del self.__toklist[i] # convert int to slice if isinstance(i, int): if i < 0: i += mylen - i = slice(i, i+1) + i = slice(i, i + 1) # get removed indices removed = list(range(*i.indices(mylen))) removed.reverse() # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): + for name, occurrences in self.__tokdict.items(): for j in removed: for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) + occurrences[k] = _ParseResultsWithOffset( + value, position - (position > j) + ) else: del self.__tokdict[i] - def __contains__( self, k ): + def __contains__(self, k): return k in self.__tokdict - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return ( not not self.__toklist ) + def __len__(self): + return len(self.__toklist) + + def __bool__(self): + return not not self.__toklist + __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( self.__toklist[::-1] ) - def _iterkeys( self ): + + def __iter__(self): + return iter(self.__toklist) + + def __reversed__(self): + return iter(self.__toklist[::-1]) + + def _iterkeys(self): if hasattr(self.__tokdict, "iterkeys"): return self.__tokdict.iterkeys() else: return iter(self.__tokdict) - def _itervalues( self ): + def _itervalues(self): return (self[k] for k in self._iterkeys()) - - def _iteritems( self ): + + def _iteritems(self): return ((k, self[k]) for k in self._iterkeys()) if PY_3: - keys = _iterkeys + keys = _iterkeys """Returns an iterator of all named result keys (Python 3.x only).""" values = _itervalues @@ -491,32 +640,32 @@ def _iteritems( self ): iteritems = _iteritems """Returns an iterator of all named result key-value tuples (Python 2.x only).""" - def keys( self ): + def keys(self): """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" return list(self.iterkeys()) - def values( self ): + def values(self): """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" return list(self.itervalues()) - - def items( self ): + + def items(self): """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" return list(self.iteritems()) - def haskeys( self ): + def haskeys(self): """Since keys() returns an iterator, this method is helpful in bypassing - code that looks for the existence of any defined results names.""" + code that looks for the existence of any defined results names.""" return bool(self.__tokdict) - - def pop( self, *args, **kwargs): + + def pop(self, *args, **kwargs): """ Removes and returns item at specified index (default=C{last}). Supports both C{list} and C{dict} semantics for C{pop()}. If passed no argument or an integer argument, it will use C{list} semantics - and pop tokens from the list of parsed tokens. If passed a + and pop tokens from the list of parsed tokens. If passed a non-integer argument (most likely a string), it will use C{dict} - semantics and pop the corresponding value from any defined - results names. A second default return value argument is + semantics and pop the corresponding value from any defined + results names. A second default return value argument is supported, just as in C{dict.pop()}. Example:: @@ -544,14 +693,12 @@ def remove_LABEL(tokens): """ if not args: args = [-1] - for k,v in kwargs.items(): + for k, v in kwargs.items(): if k == 'default': args = (args[0], v) else: raise TypeError("pop() got an unexpected keyword argument '%s'" % k) - if (isinstance(args[0], int) or - len(args) == 1 or - args[0] in self): + if isinstance(args[0], int) or len(args) == 1 or args[0] in self: index = args[0] ret = self[index] del self[index] @@ -567,10 +714,10 @@ def get(self, key, defaultValue=None): C{defaultValue} is specified. Similar to C{dict.get()}. - + Example:: integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") result = date_str.parseString("1999/12/31") print(result.get("year")) # -> '1999' @@ -582,10 +729,10 @@ def get(self, key, defaultValue=None): else: return defaultValue - def insert( self, index, insStr ): + def insert(self, index, insStr): """ Inserts new element at location index in the list of parsed tokens. - + Similar to C{list.insert()}. Example:: @@ -598,17 +745,19 @@ def insert_locn(locn, tokens): """ self.__toklist.insert(index, insStr) # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): + for name, occurrences in self.__tokdict.items(): for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) + occurrences[k] = _ParseResultsWithOffset( + value, position + (position > index) + ) - def append( self, item ): + def append(self, item): """ Add single element to end of ParseResults list of elements. Example:: print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - + # use a parse action to compute the sum of the parsed integers, and add it to the end def append_sum(tokens): tokens.append(sum(map(int, tokens))) @@ -616,13 +765,13 @@ def append_sum(tokens): """ self.__toklist.append(item) - def extend( self, itemseq ): + def extend(self, itemseq): """ Add sequence of elements to end of ParseResults list of elements. Example:: patt = OneOrMore(Word(alphas)) - + # use a parse action to append the reverse of the matched strings, to make a palindrome def make_palindrome(tokens): tokens.extend(reversed([t[::-1] for t in tokens])) @@ -634,74 +783,84 @@ def make_palindrome(tokens): else: self.__toklist.extend(itemseq) - def clear( self ): + def clear(self): """ Clear all elements and results names. """ del self.__toklist[:] self.__tokdict.clear() - def __getattr__( self, name ): + def __getattr__(self, name): try: return self[name] except KeyError: return "" - + if name in self.__tokdict: if name not in self.__accumNames: return self.__tokdict[name][-1][0] else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) + return ParseResults([v[0] for v in self.__tokdict[name]]) else: return "" - def __add__( self, other ): + def __add__(self, other): ret = self.copy() ret += other return ret - def __iadd__( self, other ): + def __iadd__(self, other): if other.__tokdict: offset = len(self.__toklist) - addoffset = lambda a: offset if a<0 else a+offset + addoffset = lambda a: offset if a < 0 else a + offset otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: + otherdictitems = [ + (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) + for (k, vlist) in otheritems + for v in vlist + ] + for k, v in otherdictitems: self[k] = v - if isinstance(v[0],ParseResults): + if isinstance(v[0], ParseResults): v[0].__parent = wkref(self) - + self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) + self.__accumNames.update(other.__accumNames) return self def __radd__(self, other): - if isinstance(other,int) and other == 0: + if isinstance(other, int) and other == 0: # useful for merging many ParseResults using sum() builtin return self.copy() else: # this may raise a TypeError - so be it return other + self - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - def __str__( self ): - return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' + def __repr__(self): + return "(%s, %s)" % (repr(self.__toklist), repr(self.__tokdict)) - def _asStringList( self, sep='' ): + def __str__(self): + return ( + '[' + + ', '.join( + _ustr(i) if isinstance(i, ParseResults) else repr(i) + for i in self.__toklist + ) + + ']' + ) + + def _asStringList(self, sep=''): out = [] for item in self.__toklist: if out and sep: out.append(sep) - if isinstance( item, ParseResults ): + if isinstance(item, ParseResults): out += item._asStringList() else: - out.append( _ustr(item) ) + out.append(_ustr(item)) return out - def asList( self ): + def asList(self): """ Returns the parse results as a nested list of matching tokens, all converted to strings. @@ -710,24 +869,27 @@ def asList( self ): result = patt.parseString("sldkj lsdkj sldkj") # even though the result prints in string-like form, it is actually a pyparsing ParseResults print(type(result), result) # -> ['sldkj', 'lsdkj', 'sldkj'] - + # Use asList() to create an actual list result_list = result.asList() print(type(result_list), result_list) # -> ['sldkj', 'lsdkj', 'sldkj'] """ - return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] + return [ + res.asList() if isinstance(res, ParseResults) else res + for res in self.__toklist + ] - def asDict( self ): + def asDict(self): """ Returns the named parse results as a nested dictionary. Example:: integer = Word(nums) date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - + result = date_str.parseString('12/31/1999') print(type(result), repr(result)) # -> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) - + result_dict = result.asDict() print(type(result_dict), repr(result_dict)) # -> {'day': '1999', 'year': '12', 'month': '31'} @@ -740,7 +902,7 @@ def asDict( self ): item_fn = self.items else: item_fn = self.iteritems - + def toItem(obj): if isinstance(obj, ParseResults): if obj.haskeys(): @@ -749,28 +911,29 @@ def toItem(obj): return [toItem(v) for v in obj] else: return obj - - return dict((k,toItem(v)) for k,v in item_fn()) - def copy( self ): + return dict((k, toItem(v)) for k, v in item_fn()) + + def copy(self): """ Returns a new copy of a C{ParseResults} object. """ - ret = ParseResults( self.__toklist ) + ret = ParseResults(self.__toklist) ret.__tokdict = self.__tokdict.copy() ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) + ret.__accumNames.update(self.__accumNames) ret.__name = self.__name return ret - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): + def asXML(self, doctag=None, namedItemsOnly=False, indent="", formatted=True): """ (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. """ nl = "\n" out = [] - namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist) + namedItems = dict( + (v[1], k) for (k, vlist) in self.__tokdict.items() for v in vlist + ) nextLevelIndent = indent + " " # collapse out indents if formatting is not desired @@ -792,20 +955,28 @@ def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): else: selfTag = "ITEM" - out += [ nl, indent, "<", selfTag, ">" ] + out += [nl, indent, "<", selfTag, ">"] - for i,res in enumerate(self.__toklist): - if isinstance(res,ParseResults): + for i, res in enumerate(self.__toklist): + if isinstance(res, ParseResults): if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] + out += [ + res.asXML( + namedItems[i], + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted, + ) + ] else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] + out += [ + res.asXML( + None, + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted, + ) + ] else: # individual token, see if there is a name for it resTag = None @@ -817,34 +988,42 @@ def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): else: resTag = "ITEM" xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "" ] - - out += [ nl, indent, "" ] + out += [ + nl, + nextLevelIndent, + "<", + resTag, + ">", + xmlBodyText, + "", + ] + + out += [nl, indent, ""] return "".join(out) - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: + def __lookup(self, sub): + for k, vlist in self.__tokdict.items(): + for v, loc in vlist: if sub is v: return k return None def getName(self): r""" - Returns the results name for this token expression. Useful when several + Returns the results name for this token expression. Useful when several different expressions might match at a particular location. Example:: integer = Word(nums) ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") house_number_expr = Suppress('#') + Word(nums, alphanums) - user_data = (Group(house_number_expr)("house_number") + user_data = (Group(house_number_expr)("house_number") | Group(ssn_expr)("ssn") | Group(integer)("age")) user_info = OneOrMore(user_data) - + result = user_info.parseString("22 111-22-3333 #221B") for item in result: print(item.getName(), ':', item[0]) @@ -861,9 +1040,11 @@ def getName(self): return par.__lookup(self) else: return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - next(iter(self.__tokdict.values()))[0][1] in (0,-1)): + elif ( + len(self) == 1 + and len(self.__tokdict) == 1 + and next(iter(self.__tokdict.values()))[0][1] in (0, -1) + ): return next(iter(self.__tokdict.keys())) else: return None @@ -877,7 +1058,7 @@ def dump(self, indent='', depth=0, full=True): Example:: integer = Word(nums) date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - + result = date_str.parseString('12/31/1999') print(result.dump()) prints:: @@ -888,35 +1069,55 @@ def dump(self, indent='', depth=0, full=True): """ out = [] NL = '\n' - out.append( indent+_ustr(self.asList()) ) + out.append(indent + _ustr(self.asList())) if full: if self.haskeys(): - items = sorted((str(k), v) for k,v in self.items()) - for k,v in items: + items = sorted((str(k), v) for k, v in self.items()) + for k, v in items: if out: out.append(NL) - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): + out.append("%s%s- %s: " % (indent, (' ' * depth), k)) + if isinstance(v, ParseResults): if v: - out.append( v.dump(indent,depth+1) ) + out.append(v.dump(indent, depth + 1)) else: out.append(_ustr(v)) else: out.append(repr(v)) - elif any(isinstance(vv,ParseResults) for vv in self): + elif any(isinstance(vv, ParseResults) for vv in self): v = self - for i,vv in enumerate(v): - if isinstance(vv,ParseResults): - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) + for i, vv in enumerate(v): + if isinstance(vv, ParseResults): + out.append( + "\n%s%s[%d]:\n%s%s%s" + % ( + indent, + (' ' * (depth)), + i, + indent, + (' ' * (depth + 1)), + vv.dump(indent, depth + 1), + ) + ) else: - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) - + out.append( + "\n%s%s[%d]:\n%s%s%s" + % ( + indent, + (' ' * (depth)), + i, + indent, + (' ' * (depth + 1)), + _ustr(vv), + ) + ) + return "".join(out) def pprint(self, *args, **kwargs): """ Pretty-printer for parsed results as a list, using the C{pprint} module. - Accepts additional positional or keyword args as defined for the + Accepts additional positional or keyword args as defined for the C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) Example:: @@ -938,18 +1139,19 @@ def pprint(self, *args, **kwargs): # add support for pickle protocol def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): + return ( + self.__toklist, + ( + self.__tokdict.copy(), + self.__parent is not None and self.__parent() or None, + self.__accumNames, + self.__name, + ), + ) + + def __setstate__(self, state): self.__toklist = state[0] - (self.__tokdict, - par, - inAccumNames, - self.__name) = state[1] + (self.__tokdict, par, inAccumNames, self.__name) = state[1] self.__accumNames = {} self.__accumNames.update(inAccumNames) if par is not None: @@ -961,115 +1163,136 @@ def __getnewargs__(self): return self.__toklist, self.__name, self.__asList, self.__modal def __dir__(self): - return (dir(type(self)) + list(self.keys())) + return dir(type(self)) + list(self.keys()) + MutableMapping.register(ParseResults) -def col (loc,strg): + +def col(loc, strg): """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}} for more information - on parsing strings containing C{}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ + The first column is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}} for more information + on parsing strings containing C{}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ s = strg - return 1 if 0} for more information - on parsing strings containing C{}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ + The first line is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}} for more information + on parsing strings containing C{}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + return strg.count("\n", 0, loc) + 1 + + +def line(loc, strg): + """Returns the line of text containing loc within a string, counting newlines as line separators.""" lastCR = strg.rfind("\n", 0, loc) nextCR = strg.find("\n", loc) if nextCR >= 0: - return strg[lastCR+1:nextCR] + return strg[lastCR + 1 : nextCR] else: - return strg[lastCR+1:] + return strg[lastCR + 1 :] + -def _defaultStartDebugAction( instring, loc, expr ): - print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) +def _defaultStartDebugAction(instring, loc, expr): + print( + ( + "Match " + + _ustr(expr) + + " at loc " + + _ustr(loc) + + "(%d,%d)" % (lineno(loc, instring), col(loc, instring)) + ) + ) -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) +def _defaultSuccessDebugAction(instring, startloc, endloc, expr, toks): + print("Matched " + _ustr(expr) + " -> " + str(toks.asList())) + + +def _defaultExceptionDebugAction(instring, loc, expr, exc): + print("Exception raised:" + _ustr(exc)) + def nullDebugAction(*args): """'Do-nothing' debug action, to suppress debugging output during parsing.""" pass + # Only works on Python 3.x - nonlocal is toxic to Python 2 installs -#~ 'decorator to trim function calls to match the arity of the target' -#~ def _trim_arity(func, maxargs=3): - #~ if func in singleArgBuiltins: - #~ return lambda s,l,t: func(t) - #~ limit = 0 - #~ foundArity = False - #~ def wrapper(*args): - #~ nonlocal limit,foundArity - #~ while 1: - #~ try: - #~ ret = func(*args[limit:]) - #~ foundArity = True - #~ return ret - #~ except TypeError: - #~ if limit == maxargs or foundArity: - #~ raise - #~ limit += 1 - #~ continue - #~ return wrapper +# ~ 'decorator to trim function calls to match the arity of the target' +# ~ def _trim_arity(func, maxargs=3): +# ~ if func in singleArgBuiltins: +# ~ return lambda s,l,t: func(t) +# ~ limit = 0 +# ~ foundArity = False +# ~ def wrapper(*args): +# ~ nonlocal limit,foundArity +# ~ while 1: +# ~ try: +# ~ ret = func(*args[limit:]) +# ~ foundArity = True +# ~ return ret +# ~ except TypeError: +# ~ if limit == maxargs or foundArity: +# ~ raise +# ~ limit += 1 +# ~ continue +# ~ return wrapper # this version is Python 2.x-3.x cross-compatible 'decorator to trim function calls to match the arity of the target' + + def _trim_arity(func, maxargs=2): if func in singleArgBuiltins: - return lambda s,l,t: func(t) + return lambda s, l, t: func(t) limit = [0] foundArity = [False] - + # traceback return data structure changed in Py3.5 - normalize back to plain tuples - if system_version[:2] >= (3,5): + if system_version[:2] >= (3, 5): + def extract_stack(limit=0): # special handling for Python 3.5.0 - extra deep call stack by 1 - offset = -3 if system_version == (3,5,0) else -2 - frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset] + offset = -3 if system_version == (3, 5, 0) else -2 + frame_summary = traceback.extract_stack(limit=-offset + limit - 1)[offset] return [frame_summary[:2]] + def extract_tb(tb, limit=0): frames = traceback.extract_tb(tb, limit=limit) frame_summary = frames[-1] return [frame_summary[:2]] + else: extract_stack = traceback.extract_stack extract_tb = traceback.extract_tb - - # synthesize what would be returned by traceback.extract_stack at the call to + + # synthesize what would be returned by traceback.extract_stack at the call to # user's parse action 'func', so that we don't incur call penalty at parse time - + LINE_DIFF = 6 - # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND + # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! this_line = extract_stack(limit=2)[-1] - pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) + pa_call_line_synth = (this_line[0], this_line[1] + LINE_DIFF) def wrapper(*args): while 1: try: - ret = func(*args[limit[0]:]) + ret = func(*args[limit[0] :]) foundArity[0] = True return ret except TypeError: @@ -1092,28 +1315,29 @@ def wrapper(*args): # copy func name to wrapper for sensible debug output func_name = "" try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) + func_name = getattr(func, '__name__', getattr(func, '__class__').__name__) except Exception: func_name = str(func) wrapper.__name__ = func_name return wrapper + class ParserElement(object): """Abstract base level parser element class.""" + DEFAULT_WHITE_CHARS = " \n\t\r" verbose_stacktrace = False @staticmethod - def setDefaultWhitespaceChars( chars ): + def setDefaultWhitespaceChars(chars): r""" Overrides the default whitespace chars Example:: # default whitespace chars are space, and newline OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] - + # change to just treat newline as significant ParserElement.setDefaultWhitespaceChars(" \t") OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] @@ -1124,84 +1348,84 @@ def setDefaultWhitespaceChars( chars ): def inlineLiteralsUsing(cls): """ Set class to be used for inclusion of string literals into a parser. - + Example:: # default literal class used is Literal integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] # change to Suppress ParserElement.inlineLiteralsUsing(Suppress) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] """ ParserElement._literalStringClass = cls - def __init__( self, savelist=False ): + def __init__(self, savelist=False): self.parseAction = list() self.failAction = None - #~ self.name = "" # don't define self.name, let subclasses try/except upcall + # ~ self.name = "" # don't define self.name, let subclasses try/except upcall self.strRepr = None self.resultsName = None self.saveAsList = savelist self.skipWhitespace = True self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion + self.mayReturnEmpty = False # used when checking for left-recursion self.keepTabs = False self.ignoreExprs = list() self.debug = False self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index + self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions + self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) + self.debugActions = (None, None, None) # custom debug actions self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse + self.callPreparse = True # used to avoid redundant calls to preParse self.callDuringTry = False - def copy( self ): + def copy(self): """ Make a copy of this C{ParserElement}. Useful for defining different parse actions for the same parsing pattern, using copies of the original parse element. - + Example:: integer = Word(nums).setParseAction(lambda toks: int(toks[0])) integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - + print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) prints:: [5120, 100, 655360, 268435456] Equivalent form of C{expr.copy()} is just C{expr()}:: integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") """ - cpy = copy.copy( self ) + cpy = copy.copy(self) cpy.parseAction = self.parseAction[:] cpy.ignoreExprs = self.ignoreExprs[:] if self.copyDefaultWhiteChars: cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS return cpy - def setName( self, name ): + def setName(self, name): """ Define name for this expression, makes debugging and exception messages clearer. - + Example:: Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) """ self.name = name self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): + if hasattr(self, "exception"): self.exception.msg = self.errmsg return self - def setResultsName( self, name, listAllMatches=False ): + def setResultsName(self, name, listAllMatches=False): """ Define name for referencing matching tokens as a nested attribute of the returned parse results. @@ -1210,12 +1434,12 @@ def setResultsName( self, name, listAllMatches=False ): integer, and reference it in multiple places with different names. You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - + C{expr("name")} in place of C{expr.setResultsName("name")} - see L{I{__call__}<__call__>}. Example:: - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + integer.setResultsName("day")) # equivalent form: @@ -1224,30 +1448,33 @@ def setResultsName( self, name, listAllMatches=False ): newself = self.copy() if name.endswith("*"): name = name[:-1] - listAllMatches=True + listAllMatches = True newself.resultsName = name newself.modalResults = not listAllMatches return newself - def setBreak(self,breakFlag = True): + def setBreak(self, breakFlag=True): """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. + about to be parsed. Set C{breakFlag} to True to enable, False to + disable. """ if breakFlag: _parseMethod = self._parse + def breaker(instring, loc, doActions=True, callPreParse=True): import pdb + pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) + return _parseMethod(instring, loc, doActions, callPreParse) + breaker._originalParseMethod = _parseMethod self._parse = breaker else: - if hasattr(self._parse,"_originalParseMethod"): + if hasattr(self._parse, "_originalParseMethod"): self._parse = self._parse._originalParseMethod return self - def setParseAction( self, *fns, **kwargs ): + def setParseAction(self, *fns, **kwargs): """ Define one or more actions to perform when successfully matching parse element definition. Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, @@ -1267,7 +1494,7 @@ def setParseAction( self, *fns, **kwargs ): on parsing strings containing C{}s, and suggested methods to maintain a consistent view of the parsed string, the parse location, and line and column positions within the parsed string. - + Example:: integer = Word(nums) date_str = integer + '/' + integer + '/' + integer @@ -1285,10 +1512,10 @@ def setParseAction( self, *fns, **kwargs ): self.callDuringTry = kwargs.get("callDuringTry", False) return self - def addParseAction( self, *fns, **kwargs ): + def addParseAction(self, *fns, **kwargs): """ Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}}. - + See examples in L{I{copy}}. """ self.parseAction += list(map(_trim_arity, list(fns))) @@ -1296,14 +1523,14 @@ def addParseAction( self, *fns, **kwargs ): return self def addCondition(self, *fns, **kwargs): - """Add a boolean predicate function to expression's list of parse actions. See - L{I{setParseAction}} for function call signatures. Unlike C{setParseAction}, + """Add a boolean predicate function to expression's list of parse actions. See + L{I{setParseAction}} for function call signatures. Unlike C{setParseAction}, functions passed to C{addCondition} need to return boolean success/fail of the condition. Optional keyword arguments: - message = define a custom message to be used in the raised exception - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException - + Example:: integer = Word(nums).setParseAction(lambda toks: int(toks[0])) year_int = integer.copy() @@ -1315,42 +1542,44 @@ def addCondition(self, *fns, **kwargs): msg = kwargs.get("message", "failed user-defined condition") exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException for fn in fns: - def pa(s,l,t): - if not bool(_trim_arity(fn)(s,l,t)): - raise exc_type(s,l,msg) + + def pa(s, l, t): + if not bool(_trim_arity(fn)(s, l, t)): + raise exc_type(s, l, msg) + self.parseAction.append(pa) self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) return self - def setFailAction( self, fn ): + def setFailAction(self, fn): """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{L{ParseFatalException}} - if it is desired to stop parsing immediately.""" + Fail acton fn is a callable function that takes the arguments + C{fn(s,loc,expr,err)} where: + - s = string being parsed + - loc = location where expression match was attempted and failed + - expr = the parse expression that failed + - err = the exception thrown + The function returns no value. It may throw C{L{ParseFatalException}} + if it is desired to stop parsing immediately.""" self.failAction = fn return self - def _skipIgnorables( self, instring, loc ): + def _skipIgnorables(self, instring, loc): exprsFound = True while exprsFound: exprsFound = False for e in self.ignoreExprs: try: while 1: - loc,dummy = e._parse( instring, loc ) + loc, dummy = e._parse(instring, loc) exprsFound = True except ParseException: pass return loc - def preParse( self, instring, loc ): + def preParse(self, instring, loc): if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) + loc = self._skipIgnorables(instring, loc) if self.skipWhitespace: wt = self.whiteChars @@ -1360,90 +1589,98 @@ def preParse( self, instring, loc ): return loc - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): return loc, [] - def postParse( self, instring, loc, tokenlist ): + def postParse(self, instring, loc, tokenlist): return tokenlist - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) + # ~ @profile + def _parseNoCache(self, instring, loc, doActions=True, callPreParse=True): + debugging = self.debug # and doActions ) if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) + # ~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) + if self.debugActions[0]: + self.debugActions[0](instring, loc, self) if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) + preloc = self.preParse(instring, loc) else: preloc = loc tokensStart = preloc try: try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) + loc, tokens = self.parseImpl(instring, preloc, doActions) except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) + raise ParseException(instring, len(instring), self.errmsg, self) except ParseBaseException as err: - #~ print ("Exception raised:", err) + # ~ print ("Exception raised:", err) if self.debugActions[2]: - self.debugActions[2]( instring, tokensStart, self, err ) + self.debugActions[2](instring, tokensStart, self, err) if self.failAction: - self.failAction( instring, tokensStart, self, err ) + self.failAction(instring, tokensStart, self, err) raise else: if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) + preloc = self.preParse(instring, loc) else: preloc = loc tokensStart = preloc if self.mayIndexError or preloc >= len(instring): try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) + loc, tokens = self.parseImpl(instring, preloc, doActions) except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) + raise ParseException(instring, len(instring), self.errmsg, self) else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) + loc, tokens = self.parseImpl(instring, preloc, doActions) - tokens = self.postParse( instring, loc, tokens ) + tokens = self.postParse(instring, loc, tokens) - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) + retTokens = ParseResults( + tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults + ) if self.parseAction and (doActions or self.callDuringTry): if debugging: try: for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) + tokens = fn(instring, tokensStart, retTokens) if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) + retTokens = ParseResults( + tokens, + self.resultsName, + asList=self.saveAsList + and isinstance(tokens, (ParseResults, list)), + modal=self.modalResults, + ) except ParseBaseException as err: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - self.debugActions[2]( instring, tokensStart, self, err ) + # ~ print "Exception raised in user parse action:", err + if self.debugActions[2]: + self.debugActions[2](instring, tokensStart, self, err) raise else: for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) + tokens = fn(instring, tokensStart, retTokens) if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) + retTokens = ParseResults( + tokens, + self.resultsName, + asList=self.saveAsList + and isinstance(tokens, (ParseResults, list)), + modal=self.modalResults, + ) if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) + # ~ print ("Matched",self,"->",retTokens.asList()) + if self.debugActions[1]: + self.debugActions[1](instring, tokensStart, loc, self, retTokens) return loc, retTokens - def tryParse( self, instring, loc ): + def tryParse(self, instring, loc): try: - return self._parse( instring, loc, doActions=False )[0] + return self._parse(instring, loc, doActions=False)[0] except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - + raise ParseException(instring, loc, self.errmsg, self) + def canParseNext(self, instring, loc): try: self.tryParse(instring, loc) @@ -1465,7 +1702,7 @@ def set(self, key, value): def clear(self): cache.clear() - + def cache_len(self): return len(cache) @@ -1475,6 +1712,7 @@ def cache_len(self): self.__len__ = types.MethodType(cache_len, self) if _OrderedDict is not None: + class _FifoCache(object): def __init__(self, size): self.not_in_cache = not_in_cache = object() @@ -1504,6 +1742,7 @@ def cache_len(self): self.__len__ = types.MethodType(cache_len, self) else: + class _FifoCache(object): def __init__(self, size): self.not_in_cache = not_in_cache = object() @@ -1533,13 +1772,15 @@ def cache_len(self): self.__len__ = types.MethodType(cache_len, self) # argument cache for optimizing repeated calls when backtracking through recursive expressions - packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail + packrat_cache = ( + {} + ) # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail packrat_cache_lock = RLock() packrat_cache_stats = [0, 0] # this method gets repeatedly called during backtracking with the same arguments - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): + def _parseCache(self, instring, loc, doActions=True, callPreParse=True): HIT, MISS = 0, 1 lookup = (self, instring, loc, callPreParse, doActions) with ParserElement.packrat_cache_lock: @@ -1567,35 +1808,38 @@ def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): @staticmethod def resetCache(): ParserElement.packrat_cache.clear() - ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) + ParserElement.packrat_cache_stats[:] = [0] * len( + ParserElement.packrat_cache_stats + ) _packratEnabled = False + @staticmethod def enablePackrat(cache_size_limit=128): """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - Parameters: - - cache_size_limit - (default=C{128}) - if an integer value is provided - will limit the size of the packrat cache; if None is passed, then - the cache size will be unbounded; if 0 is passed, the cache will - be effectively disabled. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - - Example:: - import pyparsing - pyparsing.ParserElement.enablePackrat() + Repeated parse attempts at the same string location (which happens + often in many complex grammars) can immediately return a cached value, + instead of re-executing parsing/validating code. Memoizing is done of + both valid results and parsing exceptions. + + Parameters: + - cache_size_limit - (default=C{128}) - if an integer value is provided + will limit the size of the packrat cache; if None is passed, then + the cache size will be unbounded; if 0 is passed, the cache will + be effectively disabled. + + This speedup may break existing programs that use parse actions that + have side-effects. For this reason, packrat parsing is disabled when + you first import pyparsing. To activate the packrat feature, your + program must call the class method C{ParserElement.enablePackrat()}. If + your program uses C{psyco} to "compile as you go", you must call + C{enablePackrat} before calling C{psyco.full()}. If you do not do this, + Python will crash. For best results, call C{enablePackrat()} immediately + after importing pyparsing. + + Example:: + import pyparsing + pyparsing.ParserElement.enablePackrat() """ if not ParserElement._packratEnabled: ParserElement._packratEnabled = True @@ -1605,7 +1849,7 @@ def enablePackrat(cache_size_limit=128): ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) ParserElement._parse = ParserElement._parseCache - def parseString( self, instring, parseAll=False ): + def parseString(self, instring, parseAll=False): """ Execute the parse expression with the given string. This is the main interface to the client code, once the complete @@ -1627,7 +1871,7 @@ def parseString( self, instring, parseAll=False ): reference the input string using the parse action's C{s} argument - explicitly expand the tabs in your input string before calling C{parseString} - + Example:: Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text @@ -1635,17 +1879,17 @@ def parseString( self, instring, parseAll=False ): ParserElement.resetCache() if not self.streamlined: self.streamline() - #~ self.saveAsList = True + # ~ self.saveAsList = True for e in self.ignoreExprs: e.streamline() if not self.keepTabs: instring = instring.expandtabs() try: - loc, tokens = self._parse( instring, 0 ) + loc, tokens = self._parse(instring, 0) if parseAll: - loc = self.preParse( instring, loc ) + loc = self.preParse(instring, loc) se = Empty() + StringEnd() - se._parse( instring, loc ) + se._parse(instring, loc) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1655,7 +1899,7 @@ def parseString( self, instring, parseAll=False ): else: return tokens - def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): + def scanString(self, instring, maxMatches=_MAX_INT, overlap=False): """ Scan the input string for expression matches. Each match will return the matching tokens, start location, and end location. May be called with optional @@ -1672,9 +1916,9 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): for tokens,start,end in Word(alphas).scanString(source): print(' '*start + '^'*(end-start)) print(' '*start + tokens[0]) - + prints:: - + sldjf123lsdjjkf345sldkjf879lkjsfd987 ^^^^^ sldjf @@ -1701,16 +1945,16 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): try: while loc <= instrlen and matches < maxMatches: try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) + preloc = preparseFn(instring, loc) + nextLoc, tokens = parseFn(instring, preloc, callPreParse=False) except ParseException: - loc = preloc+1 + loc = preloc + 1 else: if nextLoc > loc: matches += 1 yield tokens, preloc, nextLoc if overlap: - nextloc = preparseFn( instring, loc ) + nextloc = preparseFn(instring, loc) if nextloc > loc: loc = nextLoc else: @@ -1718,7 +1962,7 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): else: loc = nextLoc else: - loc = preloc+1 + loc = preloc + 1 except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1726,7 +1970,7 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc - def transformString( self, instring ): + def transformString(self, instring): """ Extension to C{L{scanString}}, to modify matching text with modified tokens that may be returned from a parse action. To use C{transformString}, define a grammar and @@ -1734,11 +1978,11 @@ def transformString( self, instring ): Invoking C{transformString()} on a target string will then scan for matches, and replace the matched text patterns according to the logic in the parse action. C{transformString()} returns the resulting transformed string. - + Example:: wd = Word(alphas) wd.setParseAction(lambda toks: toks[0].title()) - + print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) Prints:: Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. @@ -1749,19 +1993,19 @@ def transformString( self, instring ): # keep string locs straight between transformString and scanString self.keepTabs = True try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) + for t, s, e in self.scanString(instring): + out.append(instring[lastE:s]) if t: - if isinstance(t,ParseResults): + if isinstance(t, ParseResults): out += t.asList() - elif isinstance(t,list): + elif isinstance(t, list): out += t else: out.append(t) lastE = e out.append(instring[lastE:]) out = [o for o in out if o] - return "".join(map(_ustr,_flatten(out))) + return "".join(map(_ustr, _flatten(out))) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1769,16 +2013,16 @@ def transformString( self, instring ): # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc - def searchString( self, instring, maxMatches=_MAX_INT ): + def searchString(self, instring, maxMatches=_MAX_INT): """ Another extension to C{L{scanString}}, simplifying the access to the tokens found to match the given parse expression. May be called with optional C{maxMatches} argument, to clip searching after 'n' matches are found. - + Example:: # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters cap_word = Word(alphas.upper(), alphas.lower()) - + print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) # the sum() builtin can be used to merge results into a single ParseResults object @@ -1788,7 +2032,9 @@ def searchString( self, instring, maxMatches=_MAX_INT ): ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] """ try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) + return ParseResults( + [t for t, s, e in self.scanString(instring, maxMatches)] + ) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1802,8 +2048,8 @@ def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): May be called with optional C{maxsplit} argument, to limit the number of splits; and the optional C{includeSeparators} argument (default=C{False}), if the separating matching text should be included in the split results. - - Example:: + + Example:: punc = oneOf(list(".,;:/-!?")) print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) prints:: @@ -1811,18 +2057,18 @@ def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): """ splits = 0 last = 0 - for t,s,e in self.scanString(instring, maxMatches=maxsplit): + for t, s, e in self.scanString(instring, maxMatches=maxsplit): yield instring[last:s] if includeSeparators: yield t[0] last = e yield instring[last:] - def __add__(self, other ): + def __add__(self, other): """ Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement converts them to L{Literal}s by default. - + Example:: greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" @@ -1830,23 +2076,29 @@ def __add__(self, other ): Prints:: Hello, World! -> ['Hello', ',', 'World', '!'] """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return And( [ self, other ] ) + return And([self, other]) - def __radd__(self, other ): + def __radd__(self, other): """ Implementation of + operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other + self @@ -1854,27 +2106,33 @@ def __sub__(self, other): """ Implementation of - operator, returns C{L{And}} with error stop """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return self + And._ErrorStop() + other - def __rsub__(self, other ): + def __rsub__(self, other): """ Implementation of - operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other - self - def __mul__(self,other): + def __mul__(self, other): """ Implementation of * operator, allows use of C{expr * 3} in place of C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer @@ -1894,162 +2152,190 @@ def __mul__(self,other): occurrences. If this behavior is desired, then write C{expr*(None,n) + ~expr} """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): + if isinstance(other, int): + minElements, optElements = other, 0 + elif isinstance(other, tuple): other = (other + (None, None))[:2] if other[0] is None: other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: + if isinstance(other[0], int) and other[1] is None: if other[0] == 0: return ZeroOrMore(self) if other[0] == 1: return OneOrMore(self) else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): + return self * other[0] + ZeroOrMore(self) + elif isinstance(other[0], int) and isinstance(other[1], int): minElements, optElements = other optElements -= minElements else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) + raise TypeError( + "cannot multiply 'ParserElement' and ('%s','%s') objects", + type(other[0]), + type(other[1]), + ) else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) + raise TypeError( + "cannot multiply 'ParserElement' and '%s' objects", type(other) + ) if minElements < 0: raise ValueError("cannot multiply ParserElement by negative value") if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") + raise ValueError( + "second tuple value must be greater or equal to first tuple value" + ) if minElements == optElements == 0: raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - if (optElements): + if optElements: + def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) + if n > 1: + return Optional(self + makeOptionalList(n - 1)) else: return Optional(self) + if minElements: if minElements == 1: ret = self + makeOptionalList(optElements) else: - ret = And([self]*minElements) + makeOptionalList(optElements) + ret = And([self] * minElements) + makeOptionalList(optElements) else: ret = makeOptionalList(optElements) else: if minElements == 1: ret = self else: - ret = And([self]*minElements) + ret = And([self] * minElements) return ret def __rmul__(self, other): return self.__mul__(other) - def __or__(self, other ): + def __or__(self, other): """ Implementation of | operator - returns C{L{MatchFirst}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return MatchFirst( [ self, other ] ) + return MatchFirst([self, other]) - def __ror__(self, other ): + def __ror__(self, other): """ Implementation of | operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other | self - def __xor__(self, other ): + def __xor__(self, other): """ Implementation of ^ operator - returns C{L{Or}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return Or( [ self, other ] ) + return Or([self, other]) - def __rxor__(self, other ): + def __rxor__(self, other): """ Implementation of ^ operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other ^ self - def __and__(self, other ): + def __and__(self, other): """ Implementation of & operator - returns C{L{Each}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return Each( [ self, other ] ) + return Each([self, other]) - def __rand__(self, other ): + def __rand__(self, other): """ Implementation of & operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other & self - def __invert__( self ): + def __invert__(self): """ Implementation of ~ operator - returns C{L{NotAny}} """ - return NotAny( self ) + return NotAny(self) def __call__(self, name=None): """ Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}. - + If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be passed as C{True}. - + If C{name} is omitted, same as calling C{L{copy}}. Example:: # these are equivalent userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") + userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") """ if name is not None: return self.setResultsName(name) else: return self.copy() - def suppress( self ): + def suppress(self): """ Suppresses the output of this C{ParserElement}; useful to keep punctuation from cluttering up returned output. """ - return Suppress( self ) + return Suppress(self) - def leaveWhitespace( self ): + def leaveWhitespace(self): """ Disables the skipping of whitespace before matching the characters in the C{ParserElement}'s defined pattern. This is normally only used internally by @@ -2058,7 +2344,7 @@ def leaveWhitespace( self ): self.skipWhitespace = False return self - def setWhitespaceChars( self, chars ): + def setWhitespaceChars(self, chars): """ Overrides the default whitespace chars """ @@ -2067,7 +2353,7 @@ def setWhitespaceChars( self, chars ): self.copyDefaultWhiteChars = False return self - def parseWithTabs( self ): + def parseWithTabs(self): """ Overrides default behavior to expand C{}s to spaces before parsing the input string. Must be called before C{parseString} when the input grammar contains elements that @@ -2076,40 +2362,42 @@ def parseWithTabs( self ): self.keepTabs = True return self - def ignore( self, other ): + def ignore(self, other): """ Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns. - + Example:: patt = OneOrMore(Word(alphas)) patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] - + patt.ignore(cStyleComment) patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] """ if isinstance(other, basestring): other = Suppress(other) - if isinstance( other, Suppress ): + if isinstance(other, Suppress): if other not in self.ignoreExprs: self.ignoreExprs.append(other) else: - self.ignoreExprs.append( Suppress( other.copy() ) ) + self.ignoreExprs.append(Suppress(other.copy())) return self - def setDebugActions( self, startAction, successAction, exceptionAction ): + def setDebugActions(self, startAction, successAction, exceptionAction): """ Enable display of debugging messages while doing pattern matching. """ - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) + self.debugActions = ( + startAction or _defaultStartDebugAction, + successAction or _defaultSuccessDebugAction, + exceptionAction or _defaultExceptionDebugAction, + ) self.debug = True return self - def setDebug( self, flag=True ): + def setDebug(self, flag=True): """ Enable display of debugging messages while doing pattern matching. Set C{flag} to True to enable, False to disable. @@ -2118,12 +2406,12 @@ def setDebug( self, flag=True ): wd = Word(alphas).setName("alphaword") integer = Word(nums).setName("numword") term = wd | integer - + # turn on debugging for wd wd.setDebug() OneOrMore(term).parseString("abc 123 xyz 890") - + prints:: Match alphaword at loc 0(1,1) Matched alphaword -> ['abc'] @@ -2145,32 +2433,36 @@ def setDebug( self, flag=True ): name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}. """ if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) + self.setDebugActions( + _defaultStartDebugAction, + _defaultSuccessDebugAction, + _defaultExceptionDebugAction, + ) else: self.debug = False return self - def __str__( self ): + def __str__(self): return self.name - def __repr__( self ): + def __repr__(self): return _ustr(self) - def streamline( self ): + def streamline(self): self.streamlined = True self.strRepr = None return self - def checkRecursion( self, parseElementList ): + def checkRecursion(self, parseElementList): pass - def validate( self, validateTrace=[] ): + def validate(self, validateTrace=[]): """ Check defined expressions for valid structure, check for infinite recursive definitions. """ - self.checkRecursion( [] ) + self.checkRecursion([]) - def parseFile( self, file_or_filename, parseAll=False ): + def parseFile(self, file_or_filename, parseAll=False): """ Execute the parse expression on the given file or filename. If a filename is specified (instead of a file object), @@ -2190,35 +2482,35 @@ def parseFile( self, file_or_filename, parseAll=False ): # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc - def __eq__(self,other): + def __eq__(self, other): if isinstance(other, ParserElement): return self is other or vars(self) == vars(other) elif isinstance(other, basestring): return self.matches(other) else: - return super(ParserElement,self)==other + return super(ParserElement, self) == other - def __ne__(self,other): + def __ne__(self, other): return not (self == other) def __hash__(self): return hash(id(self)) - def __req__(self,other): + def __req__(self, other): return self == other - def __rne__(self,other): + def __rne__(self, other): return not (self == other) def matches(self, testString, parseAll=True): """ - Method for quick testing of a parser against a test string. Good for simple + Method for quick testing of a parser against a test string. Good for simple inline microtests of sub expressions while building up larger parser. - + Parameters: - testString - to test against this expression for a match - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - + Example:: expr = Word(nums) assert expr.matches("100") @@ -2228,17 +2520,25 @@ def matches(self, testString, parseAll=True): return True except ParseBaseException: return False - - def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): + + def runTests( + self, + tests, + parseAll=True, + comment='#', + fullDump=True, + printResults=True, + failureTests=False, + ): """ Execute the parse expression on a series of test strings, showing each test, the parsed results or where the parse failed. Quick and easy way to run a parse expression against a list of sample strings. - + Parameters: - tests - a list of separate test strings, or a multiline string of test strings - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - comment - (default=C{'#'}) - expression for indicating embedded comments in the test + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + - comment - (default=C{'#'}) - expression for indicating embedded comments in the test string; pass None to disable comment filtering - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; if False, only dump nested list @@ -2246,9 +2546,9 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing Returns: a (success, results) tuple, where success indicates that all tests succeeded - (or failed if C{failureTests} is True), and the results contain a list of lines of each + (or failed if C{failureTests} is True), and the results contain a list of lines of each test's output - + Example:: number_expr = pyparsing_common.number.copy() @@ -2291,7 +2591,7 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult [1e-12] Success - + # stray character 100Z ^ @@ -2313,7 +2613,7 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult lines, create a test like this:: expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines") - + (Note that this is a raw string literal, you must include the leading 'r'.) """ if isinstance(tests, basestring): @@ -2332,7 +2632,7 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult out = ['\n'.join(comments), t] comments = [] try: - t = t.replace(r'\n','\n') + t = t.replace(r'\n', '\n') result = self.parseString(t, parseAll=parseAll) out.append(result.dump(full=fullDump)) success = success and not failureTests @@ -2340,9 +2640,9 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" if '\n' in t: out.append(line(pe.loc, t)) - out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) + out.append(' ' * (col(pe.loc, t) - 1) + '^' + fatal) else: - out.append(' '*pe.loc + '^' + fatal) + out.append(' ' * pe.loc + '^' + fatal) out.append("FAIL: " + str(pe)) success = success and failureTests result = pe @@ -2357,24 +2657,26 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult print('\n'.join(out)) allResults.append((t, result)) - + return success, allResults - + class Token(ParserElement): """ Abstract C{ParserElement} subclass, for defining atomic matching patterns. """ - def __init__( self ): - super(Token,self).__init__( savelist=False ) + + def __init__(self): + super(Token, self).__init__(savelist=False) class Empty(Token): """ An empty token, will always match. """ - def __init__( self ): - super(Empty,self).__init__() + + def __init__(self): + super(Empty, self).__init__() self.name = "Empty" self.mayReturnEmpty = True self.mayIndexError = False @@ -2384,40 +2686,45 @@ class NoMatch(Token): """ A token that will never match. """ - def __init__( self ): - super(NoMatch,self).__init__() + + def __init__(self): + super(NoMatch, self).__init__() self.name = "NoMatch" self.mayReturnEmpty = True self.mayIndexError = False self.errmsg = "Unmatchable token" - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): raise ParseException(instring, loc, self.errmsg, self) class Literal(Token): """ Token to exactly match a specified string. - + Example:: Literal('blah').parseString('blah') # -> ['blah'] Literal('blah').parseString('blahfooblah') # -> ['blah'] Literal('blah').parseString('bla') # -> Exception: Expected "blah" - + For case-insensitive matching, use L{CaselessLiteral}. - + For keyword matching (force word break before and after the matched string), use L{Keyword} or L{CaselessKeyword}. """ - def __init__( self, matchString ): - super(Literal,self).__init__() + + def __init__(self, matchString): + super(Literal, self).__init__() self.match = matchString self.matchLen = len(matchString) try: self.firstMatchChar = matchString[0] except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) + warnings.warn( + "null string passed to Literal; use Empty() instead", + SyntaxWarning, + stacklevel=2, + ) self.__class__ = Empty self.name = '"%s"' % _ustr(self.match) self.errmsg = "Expected " + self.name @@ -2427,15 +2734,19 @@ def __init__( self, matchString ): # Performance tuning: this routine gets called a *lot* # if this is a single character match string and the first character matches, # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match + # ~ @profile + def parseImpl(self, instring, loc, doActions=True): + if instring[loc] == self.firstMatchChar and ( + self.matchLen == 1 or instring.startswith(self.match, loc) + ): + return loc + self.matchLen, self.match raise ParseException(instring, loc, self.errmsg, self) + + _L = Literal ParserElement._literalStringClass = Literal + class Keyword(Token): """ Token to exactly match a specified string as a keyword, that is, it must be @@ -2446,17 +2757,18 @@ class Keyword(Token): - C{identChars} is a string of characters that would be valid identifier characters, defaulting to all alphanumerics + "_" and "$" - C{caseless} allows case-insensitive matching, default is C{False}. - + Example:: Keyword("start").parseString("start") # -> ['start'] Keyword("start").parseString("starting") # -> Exception For case-insensitive matching, use L{CaselessKeyword}. """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - def __init__( self, matchString, identChars=None, caseless=False ): - super(Keyword,self).__init__() + DEFAULT_KEYWORD_CHARS = alphanums + "_$" + + def __init__(self, matchString, identChars=None, caseless=False): + super(Keyword, self).__init__() if identChars is None: identChars = Keyword.DEFAULT_KEYWORD_CHARS self.match = matchString @@ -2464,8 +2776,11 @@ def __init__( self, matchString, identChars=None, caseless=False ): try: self.firstMatchChar = matchString[0] except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) + warnings.warn( + "null string passed to Keyword; use Empty() instead", + SyntaxWarning, + stacklevel=2, + ) self.name = '"%s"' % self.match self.errmsg = "Expected " + self.name self.mayReturnEmpty = False @@ -2476,31 +2791,41 @@ def __init__( self, matchString, identChars=None, caseless=False ): identChars = identChars.upper() self.identChars = set(identChars) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match + if ( + (instring[loc : loc + self.matchLen].upper() == self.caselessmatch) + and ( + loc >= len(instring) - self.matchLen + or instring[loc + self.matchLen].upper() not in self.identChars + ) + and (loc == 0 or instring[loc - 1].upper() not in self.identChars) + ): + return loc + self.matchLen, self.match else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match + if ( + instring[loc] == self.firstMatchChar + and (self.matchLen == 1 or instring.startswith(self.match, loc)) + and ( + loc >= len(instring) - self.matchLen + or instring[loc + self.matchLen] not in self.identChars + ) + and (loc == 0 or instring[loc - 1] not in self.identChars) + ): + return loc + self.matchLen, self.match raise ParseException(instring, loc, self.errmsg, self) def copy(self): - c = super(Keyword,self).copy() + c = super(Keyword, self).copy() c.identChars = Keyword.DEFAULT_KEYWORD_CHARS return c @staticmethod - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ + def setDefaultKeywordChars(chars): + """Overrides the default Keyword chars""" Keyword.DEFAULT_KEYWORD_CHARS = chars + class CaselessLiteral(Literal): """ Token to match a specified string, ignoring case of letters. @@ -2509,52 +2834,58 @@ class CaselessLiteral(Literal): Example:: OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] - + (Contrast with example for L{CaselessKeyword}.) """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) + + def __init__(self, matchString): + super(CaselessLiteral, self).__init__(matchString.upper()) # Preserve the defining literal. self.returnString = matchString self.name = "'%s'" % self.returnString self.errmsg = "Expected " + self.name - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString + def parseImpl(self, instring, loc, doActions=True): + if instring[loc : loc + self.matchLen].upper() == self.match: + return loc + self.matchLen, self.returnString raise ParseException(instring, loc, self.errmsg, self) + class CaselessKeyword(Keyword): """ Caseless version of L{Keyword}. Example:: OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] - + (Contrast with example for L{CaselessLiteral}.) """ - def __init__( self, matchString, identChars=None ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match + def __init__(self, matchString, identChars=None): + super(CaselessKeyword, self).__init__(matchString, identChars, caseless=True) + + def parseImpl(self, instring, loc, doActions=True): + if (instring[loc : loc + self.matchLen].upper() == self.caselessmatch) and ( + loc >= len(instring) - self.matchLen + or instring[loc + self.matchLen].upper() not in self.identChars + ): + return loc + self.matchLen, self.match raise ParseException(instring, loc, self.errmsg, self) + class CloseMatch(Token): """ - A variation on L{Literal} which matches "close" matches, that is, + A variation on L{Literal} which matches "close" matches, that is, strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters: - C{match_string} - string to be matched - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match - + The results from a successful parse will contain the matched text from the input string and the following named results: - C{mismatches} - a list of the positions within the match_string where mismatches were found - C{original} - the original match_string used to compare against the input string - + If C{mismatches} is an empty list, then the match was an exact match. - + Example:: patt = CloseMatch("ATCATCGAATGGA") patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) @@ -2567,16 +2898,20 @@ class CloseMatch(Token): patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2) patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) """ + def __init__(self, match_string, maxMismatches=1): - super(CloseMatch,self).__init__() + super(CloseMatch, self).__init__() self.name = match_string self.match_string = match_string self.maxMismatches = maxMismatches - self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches) + self.errmsg = "Expected %r (with up to %d mismatches)" % ( + self.match_string, + self.maxMismatches, + ) self.mayIndexError = False self.mayReturnEmpty = False - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): start = loc instrlen = len(instring) maxloc = start + len(self.match_string) @@ -2587,8 +2922,10 @@ def parseImpl( self, instring, loc, doActions=True ): mismatches = [] maxMismatches = self.maxMismatches - for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)): - src,mat = s_m + for match_stringloc, s_m in enumerate( + zip(instring[loc:maxloc], self.match_string) + ): + src, mat = s_m if src != mat: mismatches.append(match_stringloc) if len(mismatches) > maxMismatches: @@ -2612,14 +2949,14 @@ class Word(Token): maximum, and/or exact length. The default value for C{min} is 1 (a minimum value < 1 is not valid); the default values for C{max} and C{exact} are 0, meaning no maximum or exact length restriction. An optional - C{excludeChars} parameter can list characters that might be found in + C{excludeChars} parameter can list characters that might be found in the input C{bodyChars} string; useful to define a word of all printables except for one or two characters, for instance. - - L{srange} is useful for defining custom character set strings for defining + + L{srange} is useful for defining custom character set strings for defining C{Word} expressions, using range notation from regular expression character sets. - - A common mistake is to use C{Word} to match a specific literal string, as in + + A common mistake is to use C{Word} to match a specific literal string, as in C{Word("Address")}. Remember that C{Word} uses the string argument to define I{sets} of matchable characters. This expression would match "Add", "AAA", "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. @@ -2637,28 +2974,38 @@ class Word(Token): Example:: # a word composed of digits integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) - + # a word with a leading capital, and zero or more lowercase capital_word = Word(alphas.upper(), alphas.lower()) # hostnames are alphanumeric, with leading alpha, and '-' hostname = Word(alphas, alphanums+'-') - + # roman numeral (not a strict parser, accepts invalid mix of characters) roman = Word("IVXLCDM") - + # any string of non-whitespace characters, except for ',' csv_value = Word(printables, excludeChars=",") """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): - super(Word,self).__init__() + + def __init__( + self, + initChars, + bodyChars=None, + min=1, + max=0, + exact=0, + asKeyword=False, + excludeChars=None, + ): + super(Word, self).__init__() if excludeChars: initChars = ''.join(c for c in initChars if c not in excludeChars) if bodyChars: bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) self.initCharsOrig = initChars self.initChars = set(initChars) - if bodyChars : + if bodyChars: self.bodyCharsOrig = bodyChars self.bodyChars = set(bodyChars) else: @@ -2668,7 +3015,9 @@ def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword= self.maxSpecified = max > 0 if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") + raise ValueError( + "cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted" + ) self.minLen = min @@ -2686,34 +3035,38 @@ def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword= self.mayIndexError = False self.asKeyword = asKeyword - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): + if ' ' not in self.initCharsOrig + self.bodyCharsOrig and ( + min == 1 and max == 0 and exact == 0 + ): if self.bodyCharsOrig == self.initCharsOrig: self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) elif len(self.initCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) + self.reString = "%s[%s]*" % ( + re.escape(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig), + ) else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) + self.reString = "[%s][%s]*" % ( + _escapeRegexRangeChars(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig), + ) if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" + self.reString = r"\b" + self.reString + r"\b" try: - self.re = re.compile( self.reString ) + self.re = re.compile(self.reString) except Exception: self.re = None - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.re: - result = self.re.match(instring,loc) + result = self.re.match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) loc = result.end() return loc, result.group() - if not(instring[ loc ] in self.initChars): + if not (instring[loc] in self.initChars): raise ParseException(instring, loc, self.errmsg, self) start = loc @@ -2721,7 +3074,7 @@ def parseImpl( self, instring, loc, doActions=True ): instrlen = len(instring) bodychars = self.bodyChars maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) + maxloc = min(maxloc, instrlen) while loc < maxloc and instring[loc] in bodychars: loc += 1 @@ -2731,7 +3084,9 @@ def parseImpl( self, instring, loc, doActions=True ): if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: throwException = True if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc 0 and instring[start - 1] in bodychars) or ( + loc < instrlen and instring[loc] in bodychars + ): throwException = True if throwException: @@ -2739,23 +3094,25 @@ def parseImpl( self, instring, loc, doActions=True ): return loc, instring[start:loc] - def __str__( self ): + def __str__(self): try: - return super(Word,self).__str__() + return super(Word, self).__str__() except Exception: pass - if self.strRepr is None: def charsAsStr(s): - if len(s)>4: - return s[:4]+"..." + if len(s) > 4: + return s[:4] + "..." else: return s - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) + if self.initCharsOrig != self.bodyCharsOrig: + self.strRepr = "W:(%s,%s)" % ( + charsAsStr(self.initCharsOrig), + charsAsStr(self.bodyCharsOrig), + ) else: self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) @@ -2766,7 +3123,7 @@ class Regex(Token): r""" Token for matching strings that match a given regular expression. Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - If the given regex contains named groups (defined using C{(?P...)}), these will be preserved as + If the given regex contains named groups (defined using C{(?P...)}), these will be preserved as named parse results. Example:: @@ -2776,14 +3133,18 @@ class Regex(Token): roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") """ compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): + + def __init__(self, pattern, flags=0): """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() + super(Regex, self).__init__() if isinstance(pattern, basestring): if not pattern: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) + warnings.warn( + "null string passed to Regex; use Empty() instead", + SyntaxWarning, + stacklevel=2, + ) self.pattern = pattern self.flags = flags @@ -2792,26 +3153,30 @@ def __init__( self, pattern, flags=0): self.re = re.compile(self.pattern, self.flags) self.reString = self.pattern except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) + warnings.warn( + "invalid pattern (%s) passed to Regex" % pattern, + SyntaxWarning, + stacklevel=2, + ) raise elif isinstance(pattern, Regex.compiledREtype): self.re = pattern - self.pattern = \ - self.reString = str(pattern) + self.pattern = self.reString = str(pattern) self.flags = flags - + else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") + raise ValueError( + "Regex may only be constructed with a string or a compiled RE object" + ) self.name = _ustr(self) self.errmsg = "Expected " + self.name self.mayIndexError = False self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) + def parseImpl(self, instring, loc, doActions=True): + result = self.re.match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -2821,11 +3186,11 @@ def parseImpl( self, instring, loc, doActions=True ): if d: for k in d: ret[k] = d[k] - return loc,ret + return loc, ret - def __str__( self ): + def __str__(self): try: - return super(Regex,self).__str__() + return super(Regex, self).__str__() except Exception: pass @@ -2838,7 +3203,7 @@ def __str__( self ): class QuotedString(Token): r""" Token for matching strings that are delimited by quoting characters. - + Defined with the following parameters: - quoteChar - string of one or more characters defining the quote delimiting string - escChar - character to escape quotes, typically backslash (default=C{None}) @@ -2860,13 +3225,25 @@ class QuotedString(Token): [['This is the "quote"']] [['This is the quote with "embedded" quotes']] """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): - super(QuotedString,self).__init__() + + def __init__( + self, + quoteChar, + escChar=None, + escQuote=None, + multiline=False, + unquoteResults=True, + endQuoteChar=None, + convertWhitespaceEscapes=True, + ): + super(QuotedString, self).__init__() # remove white space from quote chars - wont work anyway quoteChar = quoteChar.strip() if not quoteChar: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + warnings.warn( + "quoteChar cannot be the empty string", SyntaxWarning, stacklevel=2 + ) raise SyntaxError() if endQuoteChar is None: @@ -2874,7 +3251,11 @@ def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unq else: endQuoteChar = endQuoteChar.strip() if not endQuoteChar: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + warnings.warn( + "endQuoteChar cannot be the empty string", + SyntaxWarning, + stacklevel=2, + ) raise SyntaxError() self.quoteChar = quoteChar @@ -2889,35 +3270,47 @@ def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unq if multiline: self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + self.pattern = r'%s(?:[^%s%s]' % ( + re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or ''), + ) else: self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + self.pattern = r'%s(?:[^%s\n\r%s]' % ( + re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or ''), + ) if len(self.endQuoteChar) > 1: self.pattern += ( - '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' + '|(?:' + + ')|(?:'.join( + "%s[^%s]" + % ( + re.escape(self.endQuoteChar[:i]), + _escapeRegexRangeChars(self.endQuoteChar[i]), + ) + for i in range(len(self.endQuoteChar) - 1, 0, -1) ) + + ')' + ) if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) + self.pattern += r'|(?:%s)' % re.escape(escQuote) if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - self.escCharReplacePattern = re.escape(self.escChar)+"(.)" - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) + self.pattern += r'|(?:%s.)' % re.escape(escChar) + self.escCharReplacePattern = re.escape(self.escChar) + "(.)" + self.pattern += r')*%s' % re.escape(self.endQuoteChar) try: self.re = re.compile(self.pattern, self.flags) self.reString = self.pattern except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) + warnings.warn( + "invalid pattern (%s) passed to Regex" % self.pattern, + SyntaxWarning, + stacklevel=2, + ) raise self.name = _ustr(self) @@ -2925,8 +3318,12 @@ def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unq self.mayIndexError = False self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None + def parseImpl(self, instring, loc, doActions=True): + result = ( + instring[loc] == self.firstQuoteChar + and self.re.match(instring, loc) + or None + ) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -2936,18 +3333,18 @@ def parseImpl( self, instring, loc, doActions=True ): if self.unquoteResults: # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] + ret = ret[self.quoteCharLen : -self.endQuoteCharLen] - if isinstance(ret,basestring): + if isinstance(ret, basestring): # replace escaped whitespace if '\\' in ret and self.convertWhitespaceEscapes: ws_map = { - r'\t' : '\t', - r'\n' : '\n', - r'\f' : '\f', - r'\r' : '\r', + r'\t': '\t', + r'\n': '\n', + r'\f': '\f', + r'\r': '\r', } - for wslit,wschar in ws_map.items(): + for wslit, wschar in ws_map.items(): ret = ret.replace(wslit, wschar) # replace escaped characters @@ -2960,14 +3357,17 @@ def parseImpl( self, instring, loc, doActions=True ): return loc, ret - def __str__( self ): + def __str__(self): try: - return super(QuotedString,self).__str__() + return super(QuotedString, self).__str__() except Exception: pass if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) + self.strRepr = "quoted string, starting with %s ending with %s" % ( + self.quoteChar, + self.endQuoteChar, + ) return self.strRepr @@ -2988,13 +3388,16 @@ class CharsNotIn(Token): prints:: ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() + + def __init__(self, notChars, min=1, max=0, exact=0): + super(CharsNotIn, self).__init__() self.skipWhitespace = False self.notChars = notChars if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") + raise ValueError( + "cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted" + ) self.minLen = min @@ -3009,19 +3412,18 @@ def __init__( self, notChars, min=1, max=0, exact=0 ): self.name = _ustr(self) self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) + self.mayReturnEmpty = self.minLen == 0 self.mayIndexError = False - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if instring[loc] in self.notChars: raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): + maxlen = min(start + self.maxLen, len(instring)) + while loc < maxlen and (instring[loc] not in notchars): loc += 1 if loc - start < self.minLen: @@ -3029,7 +3431,7 @@ def parseImpl( self, instring, loc, doActions=True ): return loc, instring[start:loc] - def __str__( self ): + def __str__(self): try: return super(CharsNotIn, self).__str__() except Exception: @@ -3043,6 +3445,7 @@ def __str__( self ): return self.strRepr + class White(Token): """ Special matching class for matching whitespace. Normally, whitespace is ignored @@ -3051,19 +3454,23 @@ class White(Token): matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, as defined for the C{L{Word}} class. """ + whiteStrs = { - " " : "", + " ": "", "\t": "", "\n": "", "\r": "", "\f": "", - } + } + def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() + super(White, self).__init__() self.matchWhite = ws - self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) - #~ self.leaveWhitespace() - self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) + self.setWhitespaceChars( + "".join(c for c in self.whiteChars if c not in self.matchWhite) + ) + # ~ self.leaveWhitespace() + self.name = "".join(White.whiteStrs[c] for c in self.matchWhite) self.mayReturnEmpty = True self.errmsg = "Expected " + self.name @@ -3078,13 +3485,13 @@ def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): self.maxLen = exact self.minLen = exact - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): + def parseImpl(self, instring, loc, doActions=True): + if not (instring[loc] in self.matchWhite): raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) + maxloc = min(maxloc, len(instring)) while loc < maxloc and instring[loc] in self.matchWhite: loc += 1 @@ -3095,35 +3502,41 @@ def parseImpl( self, instring, loc, doActions=True ): class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ + def __init__(self): + super(_PositionToken, self).__init__() + self.name = self.__class__.__name__ self.mayReturnEmpty = True self.mayIndexError = False + class GoToColumn(_PositionToken): """ Token to advance to a specific column of input text; useful for tabular report scraping. """ - def __init__( self, colno ): - super(GoToColumn,self).__init__() + + def __init__(self, colno): + super(GoToColumn, self).__init__() self.col = colno - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: + def preParse(self, instring, loc): + if col(loc, instring) != self.col: instrlen = len(instring) if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : + loc = self._skipIgnorables(instring, loc) + while ( + loc < instrlen + and instring[loc].isspace() + and col(loc, instring) != self.col + ): loc += 1 return loc - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) + def parseImpl(self, instring, loc, doActions=True): + thiscol = col(loc, instring) if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) + raise ParseException(instring, loc, "Text not in expected column", self) newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] + ret = instring[loc:newloc] return newloc, ret @@ -3148,68 +3561,76 @@ class LineStart(_PositionToken): ['AAA', ' and this line'] """ - def __init__( self ): - super(LineStart,self).__init__() + + def __init__(self): + super(LineStart, self).__init__() self.errmsg = "Expected start of line" - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if col(loc, instring) == 1: return loc, [] raise ParseException(instring, loc, self.errmsg, self) + class LineEnd(_PositionToken): """ Matches if current position is at the end of a line within the parse string """ - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) + + def __init__(self): + super(LineEnd, self).__init__() + self.setWhitespaceChars(ParserElement.DEFAULT_WHITE_CHARS.replace("\n", "")) self.errmsg = "Expected end of line" - def parseImpl( self, instring, loc, doActions=True ): - if loc len(instring): return loc, [] else: raise ParseException(instring, loc, self.errmsg, self) + class WordStart(_PositionToken): """ Matches if the current position is at the beginning of a Word, and @@ -3218,18 +3639,22 @@ class WordStart(_PositionToken): use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of the string being parsed, or at the beginning of a line. """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() + + def __init__(self, wordChars=printables): + super(WordStart, self).__init__() self.wordChars = set(wordChars) self.errmsg = "Not at the start of a word" - def parseImpl(self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): + if ( + instring[loc - 1] in self.wordChars + or instring[loc] not in self.wordChars + ): raise ParseException(instring, loc, self.errmsg, self) return loc, [] + class WordEnd(_PositionToken): """ Matches if the current position is at the end of a Word, and @@ -3238,17 +3663,20 @@ class WordEnd(_PositionToken): use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of the string being parsed, or at the end of a line. """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() + + def __init__(self, wordChars=printables): + super(WordEnd, self).__init__() self.wordChars = set(wordChars) self.skipWhitespace = False self.errmsg = "Not at the end of a word" - def parseImpl(self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): instrlen = len(instring) - if instrlen>0 and loc 0 and loc < instrlen: + if ( + instring[loc] in self.wordChars + or instring[loc - 1] not in self.wordChars + ): raise ParseException(instring, loc, self.errmsg, self) return loc, [] @@ -3257,14 +3685,15 @@ class ParseExpression(ParserElement): """ Abstract subclass of ParserElement, for combining and post-processing parsed tokens. """ - def __init__( self, exprs, savelist = False ): - super(ParseExpression,self).__init__(savelist) - if isinstance( exprs, _generatorType ): + + def __init__(self, exprs, savelist=False): + super(ParseExpression, self).__init__(savelist) + if isinstance(exprs, _generatorType): exprs = list(exprs) - if isinstance( exprs, basestring ): - self.exprs = [ ParserElement._literalStringClass( exprs ) ] - elif isinstance( exprs, Iterable ): + if isinstance(exprs, basestring): + self.exprs = [ParserElement._literalStringClass(exprs)] + elif isinstance(exprs, Iterable): exprs = list(exprs) # if sequence of strings provided, wrap with Literal if all(isinstance(expr, basestring) for expr in exprs): @@ -3272,52 +3701,52 @@ def __init__( self, exprs, savelist = False ): self.exprs = list(exprs) else: try: - self.exprs = list( exprs ) + self.exprs = list(exprs) except TypeError: - self.exprs = [ exprs ] + self.exprs = [exprs] self.callPreparse = False - def __getitem__( self, i ): + def __getitem__(self, i): return self.exprs[i] - def append( self, other ): - self.exprs.append( other ) + def append(self, other): + self.exprs.append(other) self.strRepr = None return self - def leaveWhitespace( self ): + def leaveWhitespace(self): """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on - all contained expressions.""" + all contained expressions.""" self.skipWhitespace = False - self.exprs = [ e.copy() for e in self.exprs ] + self.exprs = [e.copy() for e in self.exprs] for e in self.exprs: e.leaveWhitespace() return self - def ignore( self, other ): - if isinstance( other, Suppress ): + def ignore(self, other): + if isinstance(other, Suppress): if other not in self.ignoreExprs: - super( ParseExpression, self).ignore( other ) + super(ParseExpression, self).ignore(other) for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) + e.ignore(self.ignoreExprs[-1]) else: - super( ParseExpression, self).ignore( other ) + super(ParseExpression, self).ignore(other) for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) + e.ignore(self.ignoreExprs[-1]) return self - def __str__( self ): + def __str__(self): try: - return super(ParseExpression,self).__str__() + return super(ParseExpression, self).__str__() except Exception: pass if self.strRepr is None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) ) + self.strRepr = "%s:(%s)" % (self.__class__.__name__, _ustr(self.exprs)) return self.strRepr - def streamline( self ): - super(ParseExpression,self).streamline() + def streamline(self): + super(ParseExpression, self).streamline() for e in self.exprs: e.streamline() @@ -3325,46 +3754,51 @@ def streamline( self ): # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d ) # but only if there are no parse actions or resultsNames on the nested And's # (likewise for Or's and MatchFirst's) - if ( len(self.exprs) == 2 ): + if len(self.exprs) == 2: other = self.exprs[0] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): - self.exprs = other.exprs[:] + [ self.exprs[1] ] + if ( + isinstance(other, self.__class__) + and not (other.parseAction) + and other.resultsName is None + and not other.debug + ): + self.exprs = other.exprs[:] + [self.exprs[1]] self.strRepr = None self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError + self.mayIndexError |= other.mayIndexError other = self.exprs[-1] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): + if ( + isinstance(other, self.__class__) + and not (other.parseAction) + and other.resultsName is None + and not other.debug + ): self.exprs = self.exprs[:-1] + other.exprs[:] self.strRepr = None self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError + self.mayIndexError |= other.mayIndexError self.errmsg = "Expected " + _ustr(self) - + return self - def setResultsName( self, name, listAllMatches=False ): - ret = super(ParseExpression,self).setResultsName(name,listAllMatches) + def setResultsName(self, name, listAllMatches=False): + ret = super(ParseExpression, self).setResultsName(name, listAllMatches) return ret - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] + def validate(self, validateTrace=[]): + tmp = validateTrace[:] + [self] for e in self.exprs: e.validate(tmp) - self.checkRecursion( [] ) - + self.checkRecursion([]) + def copy(self): - ret = super(ParseExpression,self).copy() + ret = super(ParseExpression, self).copy() ret.exprs = [e.copy() for e in self.exprs] return ret + class And(ParseExpression): """ Requires all given C{ParseExpression}s to be found in the given order. @@ -3383,21 +3817,23 @@ class And(ParseExpression): class _ErrorStop(Empty): def __init__(self, *args, **kwargs): - super(And._ErrorStop,self).__init__(*args, **kwargs) + super(And._ErrorStop, self).__init__(*args, **kwargs) self.name = '-' self.leaveWhitespace() - def __init__( self, exprs, savelist = True ): - super(And,self).__init__(exprs, savelist) + def __init__(self, exprs, savelist=True): + super(And, self).__init__(exprs, savelist) self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - self.setWhitespaceChars( self.exprs[0].whiteChars ) + self.setWhitespaceChars(self.exprs[0].whiteChars) self.skipWhitespace = self.exprs[0].skipWhitespace self.callPreparse = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): # pass False as last arg to _parse for first element, since we already # pre-parsed the string as part of our And pre-parsing - loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False ) + loc, resultlist = self.exprs[0]._parse( + instring, loc, doActions, callPreParse=False + ) errorStop = False for e in self.exprs[1:]: if isinstance(e, And._ErrorStop): @@ -3405,34 +3841,36 @@ def parseImpl( self, instring, loc, doActions=True ): continue if errorStop: try: - loc, exprtokens = e._parse( instring, loc, doActions ) + loc, exprtokens = e._parse(instring, loc, doActions) except ParseSyntaxException: raise except ParseBaseException as pe: pe.__traceback__ = None raise ParseSyntaxException._from_exception(pe) except IndexError: - raise ParseSyntaxException(instring, len(instring), self.errmsg, self) + raise ParseSyntaxException( + instring, len(instring), self.errmsg, self + ) else: - loc, exprtokens = e._parse( instring, loc, doActions ) + loc, exprtokens = e._parse(instring, loc, doActions) if exprtokens or exprtokens.haskeys(): resultlist += exprtokens return loc, resultlist - def __iadd__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #And( [ self, other ] ) + def __iadd__(self, other): + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + return self.append(other) # And( [ self, other ] ) - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) if not e.mayReturnEmpty: break - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3449,26 +3887,27 @@ class Or(ParseExpression): Example:: # construct Or using '^' operator - + number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) print(number.searchString("123 3.1416 789")) prints:: [['123'], ['3.1416'], ['789']] """ - def __init__( self, exprs, savelist = False ): - super(Or,self).__init__(exprs, savelist) + + def __init__(self, exprs, savelist=False): + super(Or, self).__init__(exprs, savelist) if self.exprs: self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) else: self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): maxExcLoc = -1 maxException = None matches = [] for e in self.exprs: try: - loc2 = e.tryParse( instring, loc ) + loc2 = e.tryParse(instring, loc) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: @@ -3476,7 +3915,9 @@ def parseImpl( self, instring, loc, doActions=True ): maxExcLoc = err.loc except IndexError: if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) + maxException = ParseException( + instring, len(instring), e.errmsg, self + ) maxExcLoc = len(instring) else: # save match among all matches, to retry longest to shortest @@ -3484,9 +3925,9 @@ def parseImpl( self, instring, loc, doActions=True ): if matches: matches.sort(key=lambda x: -x[0]) - for _,e in matches: + for _, e in matches: try: - return e._parse( instring, loc, doActions ) + return e._parse(instring, loc, doActions) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: @@ -3497,16 +3938,17 @@ def parseImpl( self, instring, loc, doActions=True ): maxException.msg = self.errmsg raise maxException else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - + raise ParseException( + instring, loc, "no defined alternatives to match", self + ) - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #Or( [ self, other ] ) + def __ixor__(self, other): + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + return self.append(other) # Or( [ self, other ] ) - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3514,10 +3956,10 @@ def __str__( self ): return self.strRepr - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) class MatchFirst(ParseExpression): @@ -3528,7 +3970,7 @@ class MatchFirst(ParseExpression): Example:: # construct MatchFirst using '|' operator - + # watch the order of expressions to match number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] @@ -3537,19 +3979,20 @@ class MatchFirst(ParseExpression): number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) + + def __init__(self, exprs, savelist=False): + super(MatchFirst, self).__init__(exprs, savelist) if self.exprs: self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) else: self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): maxExcLoc = -1 maxException = None for e in self.exprs: try: - ret = e._parse( instring, loc, doActions ) + ret = e._parse(instring, loc, doActions) return ret except ParseException as err: if err.loc > maxExcLoc: @@ -3557,7 +4000,9 @@ def parseImpl( self, instring, loc, doActions=True ): maxExcLoc = err.loc except IndexError: if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) + maxException = ParseException( + instring, len(instring), e.errmsg, self + ) maxExcLoc = len(instring) # only got here if no expression matched, raise exception for match that made it the furthest @@ -3566,15 +4011,17 @@ def parseImpl( self, instring, loc, doActions=True ): maxException.msg = self.errmsg raise maxException else: - raise ParseException(instring, loc, "no defined alternatives to match", self) + raise ParseException( + instring, loc, "no defined alternatives to match", self + ) - def __ior__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) + def __ior__(self, other): + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + return self.append(other) # MatchFirst( [ self, other ] ) - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3582,10 +4029,10 @@ def __str__( self ): return self.strRepr - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) class Each(ParseExpression): @@ -3603,7 +4050,7 @@ class Each(ParseExpression): color_attr = "color:" + color("color") size_attr = "size:" + integer("size") - # use Each (using operator '&') to accept attributes in any order + # use Each (using operator '&') to accept attributes in any order # (shape and posn are required, color and size are optional) shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) @@ -3642,26 +4089,41 @@ class Each(ParseExpression): - shape: TRIANGLE - size: 20 """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) + + def __init__(self, exprs, savelist=True): + super(Each, self).__init__(exprs, savelist) self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = True self.initExprGroups = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.initExprGroups: - self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] + self.opt1map = dict( + (id(e.expr), e) for e in self.exprs if isinstance(e, Optional) + ) + opt1 = [e.expr for e in self.exprs if isinstance(e, Optional)] + opt2 = [ + e + for e in self.exprs + if e.mayReturnEmpty and not isinstance(e, Optional) + ] self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] + self.multioptionals = [ + e.expr for e in self.exprs if isinstance(e, ZeroOrMore) + ] + self.multirequired = [ + e.expr for e in self.exprs if isinstance(e, OneOrMore) + ] + self.required = [ + e + for e in self.exprs + if not isinstance(e, (Optional, ZeroOrMore, OneOrMore)) + ] self.required += self.multirequired self.initExprGroups = False tmpLoc = loc tmpReqd = self.required[:] - tmpOpt = self.optionals[:] + tmpOpt = self.optionals[:] matchOrder = [] keepMatching = True @@ -3670,11 +4132,11 @@ def parseImpl( self, instring, loc, doActions=True ): failed = [] for e in tmpExprs: try: - tmpLoc = e.tryParse( instring, tmpLoc ) + tmpLoc = e.tryParse(instring, tmpLoc) except ParseException: failed.append(e) else: - matchOrder.append(self.opt1map.get(id(e),e)) + matchOrder.append(self.opt1map.get(id(e), e)) if e in tmpReqd: tmpReqd.remove(e) elif e in tmpOpt: @@ -3684,21 +4146,25 @@ def parseImpl( self, instring, loc, doActions=True ): if tmpReqd: missing = ", ".join(_ustr(e) for e in tmpReqd) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) + raise ParseException( + instring, loc, "Missing one or more required elements (%s)" % missing + ) # add any unmatched Optionals, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] + matchOrder += [ + e for e in self.exprs if isinstance(e, Optional) and e.expr in tmpOpt + ] resultlist = [] for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) + loc, results = e._parse(instring, loc, doActions) resultlist.append(results) finalResults = sum(resultlist, ParseResults([])) return loc, finalResults - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3706,19 +4172,20 @@ def __str__( self ): return self.strRepr - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) class ParseElementEnhance(ParserElement): """ Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. """ - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): + + def __init__(self, expr, savelist=False): + super(ParseElementEnhance, self).__init__(savelist) + if isinstance(expr, basestring): if issubclass(ParserElement._literalStringClass, Token): expr = ParserElement._literalStringClass(expr) else: @@ -3728,64 +4195,64 @@ def __init__( self, expr, savelist=False ): if expr is not None: self.mayIndexError = expr.mayIndexError self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) + self.setWhitespaceChars(expr.whiteChars) self.skipWhitespace = expr.skipWhitespace self.saveAsList = expr.saveAsList self.callPreparse = expr.callPreparse self.ignoreExprs.extend(expr.ignoreExprs) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) + return self.expr._parse(instring, loc, doActions, callPreParse=False) else: - raise ParseException("",loc,self.errmsg,self) + raise ParseException("", loc, self.errmsg, self) - def leaveWhitespace( self ): + def leaveWhitespace(self): self.skipWhitespace = False self.expr = self.expr.copy() if self.expr is not None: self.expr.leaveWhitespace() return self - def ignore( self, other ): - if isinstance( other, Suppress ): + def ignore(self, other): + if isinstance(other, Suppress): if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) + super(ParseElementEnhance, self).ignore(other) if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) + self.expr.ignore(self.ignoreExprs[-1]) else: - super( ParseElementEnhance, self).ignore( other ) + super(ParseElementEnhance, self).ignore(other) if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) + self.expr.ignore(self.ignoreExprs[-1]) return self - def streamline( self ): - super(ParseElementEnhance,self).streamline() + def streamline(self): + super(ParseElementEnhance, self).streamline() if self.expr is not None: self.expr.streamline() return self - def checkRecursion( self, parseElementList ): + def checkRecursion(self, parseElementList): if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] + raise RecursiveGrammarException(parseElementList + [self]) + subRecCheckList = parseElementList[:] + [self] if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) + self.expr.checkRecursion(subRecCheckList) - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] + def validate(self, validateTrace=[]): + tmp = validateTrace[:] + [self] if self.expr is not None: self.expr.validate(tmp) - self.checkRecursion( [] ) + self.checkRecursion([]) - def __str__( self ): + def __str__(self): try: - return super(ParseElementEnhance,self).__str__() + return super(ParseElementEnhance, self).__str__() except Exception: pass if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) + self.strRepr = "%s:(%s)" % (self.__class__.__name__, _ustr(self.expr)) return self.strRepr @@ -3801,17 +4268,18 @@ class FollowedBy(ParseElementEnhance): data_word = Word(alphas) label = data_word + FollowedBy(':') attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - + OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() prints:: [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] """ - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) + + def __init__(self, expr): + super(FollowedBy, self).__init__(expr) self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) + def parseImpl(self, instring, loc, doActions=True): + self.expr.tryParse(instring, loc) return loc, [] @@ -3824,22 +4292,25 @@ class NotAny(ParseElementEnhance): always returns a null token list. May be constructed using the '~' operator. Example:: - + """ - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs + + def __init__(self, expr): + super(NotAny, self).__init__(expr) + # ~ self.leaveWhitespace() + self.skipWhitespace = ( + False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs + ) self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) + self.errmsg = "Found unwanted token, " + _ustr(self.expr) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.expr.canParseNext(instring, loc): raise ParseException(instring, loc, self.errmsg, self) return loc, [] - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3847,8 +4318,9 @@ def __str__( self ): return self.strRepr + class _MultipleMatch(ParseElementEnhance): - def __init__( self, expr, stopOn=None): + def __init__(self, expr, stopOn=None): super(_MultipleMatch, self).__init__(expr) self.saveAsList = True ender = stopOn @@ -3856,44 +4328,45 @@ def __init__( self, expr, stopOn=None): ender = ParserElement._literalStringClass(ender) self.not_ender = ~ender if ender is not None else None - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): self_expr_parse = self.expr._parse self_skip_ignorables = self._skipIgnorables check_ender = self.not_ender is not None if check_ender: try_not_ender = self.not_ender.tryParse - + # must be at least one (but first see if we are the stopOn sentinel; # if so, fail) if check_ender: try_not_ender(instring, loc) - loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) + loc, tokens = self_expr_parse(instring, loc, doActions, callPreParse=False) try: - hasIgnoreExprs = (not not self.ignoreExprs) + hasIgnoreExprs = not not self.ignoreExprs while 1: if check_ender: try_not_ender(instring, loc) if hasIgnoreExprs: - preloc = self_skip_ignorables( instring, loc ) + preloc = self_skip_ignorables(instring, loc) else: preloc = loc - loc, tmptokens = self_expr_parse( instring, preloc, doActions ) + loc, tmptokens = self_expr_parse(instring, preloc, doActions) if tmptokens or tmptokens.haskeys(): tokens += tmptokens - except (ParseException,IndexError): + except (ParseException, IndexError): pass return loc, tokens - + + class OneOrMore(_MultipleMatch): """ Repetition of one or more of the given expression. - + Parameters: - expr - expression that must match one or more times - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) + (only required if the sentinel would ordinarily match the repetition + expression) Example:: data_word = Word(alphas) @@ -3906,13 +4379,13 @@ class OneOrMore(_MultipleMatch): # use stopOn attribute for OneOrMore to avoid reading label string as part of the data attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] - + # could also be written as (attr_expr * (1,)).parseString(text).pprint() """ - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3920,30 +4393,32 @@ def __str__( self ): return self.strRepr + class ZeroOrMore(_MultipleMatch): """ Optional repetition of zero or more of the given expression. - + Parameters: - expr - expression that must match zero or more times - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) + (only required if the sentinel would ordinarily match the repetition + expression) Example: similar to L{OneOrMore} """ - def __init__( self, expr, stopOn=None): - super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) + + def __init__(self, expr, stopOn=None): + super(ZeroOrMore, self).__init__(expr, stopOn=stopOn) self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): + + def parseImpl(self, instring, loc, doActions=True): try: return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) - except (ParseException,IndexError): + except (ParseException, IndexError): return loc, [] - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3951,14 +4426,20 @@ def __str__( self ): return self.strRepr + class _NullToken(object): def __bool__(self): return False + __nonzero__ = __bool__ + def __str__(self): return "" + _optionalNotMatched = _NullToken() + + class Optional(ParseElementEnhance): """ Optional matching of the given expression. @@ -3973,10 +4454,10 @@ class Optional(ParseElementEnhance): zip.runTests(''' # traditional ZIP code 12345 - + # ZIP+4 form 12101-0001 - + # invalid ZIP 98765- ''') @@ -3994,28 +4475,29 @@ class Optional(ParseElementEnhance): ^ FAIL: Expected end of text (at char 5), (line:1, col:6) """ - def __init__( self, expr, default=_optionalNotMatched ): - super(Optional,self).__init__( expr, savelist=False ) + + def __init__(self, expr, default=_optionalNotMatched): + super(Optional, self).__init__(expr, savelist=False) self.saveAsList = self.expr.saveAsList self.defaultValue = default self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): + loc, tokens = self.expr._parse(instring, loc, doActions, callPreParse=False) + except (ParseException, IndexError): if self.defaultValue is not _optionalNotMatched: if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) + tokens = ParseResults([self.defaultValue]) tokens[self.expr.resultsName] = self.defaultValue else: - tokens = [ self.defaultValue ] + tokens = [self.defaultValue] else: tokens = [] return loc, tokens - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -4023,18 +4505,19 @@ def __str__( self ): return self.strRepr + class SkipTo(ParseElementEnhance): """ Token for skipping over all undefined text until the matched expression is found. Parameters: - expr - target expression marking the end of the data to be skipped - - include - (default=C{False}) if True, the target expression is also parsed + - include - (default=C{False}) if True, the target expression is also parsed (the skipped text and target expression are returned as a 2-element list). - - ignore - (default=C{None}) used to define grammars (typically quoted strings and + - ignore - (default=C{None}) used to define grammars (typically quoted strings and comments) that might contain false matches to the target expression - - failOn - (default=C{None}) define expressions that are not allowed to be - included in the skipped test; if found before the target expression is found, + - failOn - (default=C{None}) define expressions that are not allowed to be + included in the skipped test; if found before the target expression is found, the SkipTo is not a match Example:: @@ -4054,11 +4537,11 @@ class SkipTo(ParseElementEnhance): # - parse action will call token.strip() for each matched token, i.e., the description body string_data = SkipTo(SEP, ignore=quotedString) string_data.setParseAction(tokenMap(str.strip)) - ticket_expr = (integer("issue_num") + SEP - + string_data("sev") + SEP - + string_data("desc") + SEP + ticket_expr = (integer("issue_num") + SEP + + string_data("sev") + SEP + + string_data("desc") + SEP + integer("days_open")) - + for tkt in ticket_expr.searchString(report): print tkt.dump() prints:: @@ -4078,8 +4561,9 @@ class SkipTo(ParseElementEnhance): - issue_num: 79 - sev: Minor """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) + + def __init__(self, other, include=False, ignore=None, failOn=None): + super(SkipTo, self).__init__(other) self.ignoreExpr = ignore self.mayReturnEmpty = True self.mayIndexError = False @@ -4089,23 +4573,27 @@ def __init__( self, other, include=False, ignore=None, failOn=None ): self.failOn = ParserElement._literalStringClass(failOn) else: self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) + self.errmsg = "No match found for " + _ustr(self.expr) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): startloc = loc instrlen = len(instring) expr = self.expr expr_parse = self.expr._parse - self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None - self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None - + self_failOn_canParseNext = ( + self.failOn.canParseNext if self.failOn is not None else None + ) + self_ignoreExpr_tryParse = ( + self.ignoreExpr.tryParse if self.ignoreExpr is not None else None + ) + tmploc = loc while tmploc <= instrlen: if self_failOn_canParseNext is not None: # break if failOn expression matches if self_failOn_canParseNext(instring, tmploc): break - + if self_ignoreExpr_tryParse is not None: # advance past ignore expressions while 1: @@ -4113,7 +4601,7 @@ def parseImpl( self, instring, loc, doActions=True ): tmploc = self_ignoreExpr_tryParse(instring, tmploc) except ParseBaseException: break - + try: expr_parse(instring, tmploc, doActions=False, callPreParse=False) except (ParseException, IndexError): @@ -4131,13 +4619,14 @@ def parseImpl( self, instring, loc, doActions=True ): loc = tmploc skiptext = instring[startloc:loc] skipresult = ParseResults(skiptext) - + if self.includeMatch: - loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) + loc, mat = expr_parse(instring, loc, doActions, callPreParse=False) skipresult += mat return loc, skipresult + class Forward(ParseElementEnhance): """ Forward declaration of an expression to be defined later - @@ -4157,45 +4646,46 @@ class Forward(ParseElementEnhance): See L{ParseResults.pprint} for an example of a recursive parser created using C{Forward}. """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - def __lshift__( self, other ): - if isinstance( other, basestring ): + def __init__(self, other=None): + super(Forward, self).__init__(other, savelist=False) + + def __lshift__(self, other): + if isinstance(other, basestring): other = ParserElement._literalStringClass(other) self.expr = other self.strRepr = None self.mayIndexError = self.expr.mayIndexError self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) + self.setWhitespaceChars(self.expr.whiteChars) self.skipWhitespace = self.expr.skipWhitespace self.saveAsList = self.expr.saveAsList self.ignoreExprs.extend(self.expr.ignoreExprs) return self - + def __ilshift__(self, other): return self << other - - def leaveWhitespace( self ): + + def leaveWhitespace(self): self.skipWhitespace = False return self - def streamline( self ): + def streamline(self): if not self.streamlined: self.streamlined = True if self.expr is not None: self.expr.streamline() return self - def validate( self, validateTrace=[] ): + def validate(self, validateTrace=[]): if self not in validateTrace: - tmp = validateTrace[:]+[self] + tmp = validateTrace[:] + [self] if self.expr is not None: self.expr.validate(tmp) self.checkRecursion([]) - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name return self.__class__.__name__ + ": ..." @@ -4213,24 +4703,28 @@ def __str__( self ): def copy(self): if self.expr is not None: - return super(Forward,self).copy() + return super(Forward, self).copy() else: ret = Forward() ret <<= self return ret + class _ForwardNoRecurse(Forward): - def __str__( self ): + def __str__(self): return "..." + class TokenConverter(ParseElementEnhance): """ Abstract subclass of C{ParseExpression}, for converting parsed results. """ - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) + + def __init__(self, expr, savelist=False): + super(TokenConverter, self).__init__(expr) # , savelist ) self.saveAsList = False + class Combine(TokenConverter): """ Converter to concatenate all matching tokens to a single string. @@ -4248,8 +4742,9 @@ class Combine(TokenConverter): # no match when there are internal spaces print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) + + def __init__(self, expr, joinString="", adjacent=True): + super(Combine, self).__init__(expr) # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself if adjacent: self.leaveWhitespace() @@ -4258,23 +4753,26 @@ def __init__( self, expr, joinString="", adjacent=True ): self.joinString = joinString self.callPreparse = True - def ignore( self, other ): + def ignore(self, other): if self.adjacent: ParserElement.ignore(self, other) else: - super( Combine, self).ignore( other ) + super(Combine, self).ignore(other) return self - def postParse( self, instring, loc, tokenlist ): + def postParse(self, instring, loc, tokenlist): retToks = tokenlist.copy() del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) + retToks += ParseResults( + ["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults + ) if self.resultsName and retToks.haskeys(): - return [ retToks ] + return [retToks] else: return retToks + class Group(TokenConverter): """ Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. @@ -4289,12 +4787,14 @@ class Group(TokenConverter): func = ident + Group(Optional(delimitedList(term))) print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] """ - def __init__( self, expr ): - super(Group,self).__init__( expr ) + + def __init__(self, expr): + super(Group, self).__init__(expr) self.saveAsList = True - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] + def postParse(self, instring, loc, tokenlist): + return [tokenlist] + class Dict(TokenConverter): """ @@ -4309,16 +4809,16 @@ class Dict(TokenConverter): text = "shape: SQUARE posn: upper left color: light blue texture: burlap" attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - + # print attributes as plain groups print(OneOrMore(attr_expr).parseString(text).dump()) - + # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names result = Dict(OneOrMore(Group(attr_expr))).parseString(text) print(result.dump()) - + # access named fields as dict entries, or output as dict - print(result['shape']) + print(result['shape']) print(result.asDict()) prints:: ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] @@ -4332,31 +4832,34 @@ class Dict(TokenConverter): {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} See more examples at L{ParseResults} of accessing fields by results name. """ - def __init__( self, expr ): - super(Dict,self).__init__( expr ) + + def __init__(self, expr): + super(Dict, self).__init__(expr) self.saveAsList = True - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): + def postParse(self, instring, loc, tokenlist): + for i, tok in enumerate(tokenlist): if len(tok) == 0: continue ikey = tok[0] - if isinstance(ikey,int): + if isinstance(ikey, int): ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) + if len(tok) == 1: + tokenlist[ikey] = _ParseResultsWithOffset("", i) + elif len(tok) == 2 and not isinstance(tok[1], ParseResults): + tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i) else: - dictvalue = tok.copy() #ParseResults(i) + dictvalue = tok.copy() # ParseResults(i) del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) + if len(dictvalue) != 1 or ( + isinstance(dictvalue, ParseResults) and dictvalue.haskeys() + ): + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i) else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i) if self.resultsName: - return [ tokenlist ] + return [tokenlist] else: return tokenlist @@ -4380,10 +4883,11 @@ class Suppress(TokenConverter): ['a', 'b', 'c', 'd'] (See also L{delimitedList}.) """ - def postParse( self, instring, loc, tokenlist ): + + def postParse(self, instring, loc, tokenlist): return [] - def suppress( self ): + def suppress(self): return self @@ -4391,22 +4895,26 @@ class OnlyOnce(object): """ Wrapper for parse actions, to ensure they are only called once. """ + def __init__(self, methodCall): self.callable = _trim_arity(methodCall) self.called = False - def __call__(self,s,l,t): + + def __call__(self, s, l, t): if not self.called: - results = self.callable(s,l,t) + results = self.callable(s, l, t) self.called = True return results - raise ParseException(s,l,"") + raise ParseException(s, l, "") + def reset(self): self.called = False + def traceParseAction(f): """ - Decorator for debugging parse actions. - + Decorator for debugging parse actions. + When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".} When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised. @@ -4425,29 +4933,34 @@ def remove_duplicate_chars(tokens): ['dfjkls'] """ f = _trim_arity(f) + def z(*paArgs): thisFunc = f.__name__ - s,l,t = paArgs[-3:] - if len(paArgs)>3: + s, l, t = paArgs[-3:] + if len(paArgs) > 3: thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) + sys.stderr.write( + ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc, line(l, s), l, t) + ) try: ret = f(*paArgs) except Exception as exc: - sys.stderr.write( "< ['aa', 'bb', 'cc'] delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] """ - dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." + dlName = _ustr(expr) + " [" + _ustr(delim) + " " + _ustr(expr) + "]..." if combine: - return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) + return Combine(expr + ZeroOrMore(delim + expr)).setName(dlName) else: - return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) + return (expr + ZeroOrMore(Suppress(delim) + expr)).setName(dlName) + -def countedArray( expr, intExpr=None ): +def countedArray(expr, intExpr=None): """ Helper to define a counted list of expressions. This helper defines a pattern of the form:: integer expr expr expr... where the leading integer tells how many expr expressions follow. The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. - + If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value. Example:: @@ -4485,27 +4999,31 @@ def countedArray( expr, intExpr=None ): countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd'] """ arrayExpr = Forward() - def countFieldParseAction(s,l,t): + + def countFieldParseAction(s, l, t): n = t[0] - arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) + arrayExpr << (n and Group(And([expr] * n)) or Group(empty)) return [] + if intExpr is None: - intExpr = Word(nums).setParseAction(lambda t:int(t[0])) + intExpr = Word(nums).setParseAction(lambda t: int(t[0])) else: intExpr = intExpr.copy() intExpr.setName("arrayLen") intExpr.addParseAction(countFieldParseAction, callDuringTry=True) - return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') + return (intExpr + arrayExpr).setName('(len) ' + _ustr(expr) + '...') + def _flatten(L): ret = [] for i in L: - if isinstance(i,list): + if isinstance(i, list): ret.extend(_flatten(i)) else: ret.append(i) return ret + def matchPreviousLiteral(expr): """ Helper to define an expression that is indirectly defined from @@ -4520,7 +5038,8 @@ def matchPreviousLiteral(expr): Do I{not} use with packrat parsing enabled. """ rep = Forward() - def copyTokenToRepeater(s,l,t): + + def copyTokenToRepeater(s, l, t): if t: if len(t) == 1: rep << t[0] @@ -4530,10 +5049,12 @@ def copyTokenToRepeater(s,l,t): rep << And(Literal(tt) for tt in tflat) else: rep << Empty() + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) rep.setName('(prev) ' + _ustr(expr)) return rep + def matchPreviousExpr(expr): """ Helper to define an expression that is indirectly defined from @@ -4551,26 +5072,32 @@ def matchPreviousExpr(expr): rep = Forward() e2 = expr.copy() rep <<= e2 - def copyTokenToRepeater(s,l,t): + + def copyTokenToRepeater(s, l, t): matchTokens = _flatten(t.asList()) - def mustMatchTheseTokens(s,l,t): + + def mustMatchTheseTokens(s, l, t): theseTokens = _flatten(t.asList()) - if theseTokens != matchTokens: - raise ParseException("",0,"") - rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) + if theseTokens != matchTokens: + raise ParseException("", 0, "") + + rep.setParseAction(mustMatchTheseTokens, callDuringTry=True) + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) rep.setName('(prev) ' + _ustr(expr)) return rep + def _escapeRegexRangeChars(s): - #~ escape these chars: ^-] + # ~ escape these chars: ^-] for c in r"\^-]": - s = s.replace(c,_bslash+c) - s = s.replace("\n",r"\n") - s = s.replace("\t",r"\t") + s = s.replace(c, _bslash + c) + s = s.replace("\n", r"\n") + s = s.replace("\t", r"\t") return _ustr(s) -def oneOf( strs, caseless=False, useRegex=True ): + +def oneOf(strs, caseless=False, useRegex=True): """ Helper to quickly define a set of alternative Literals, and makes sure to do longest-first testing when there is a conflict, regardless of the input order, @@ -4594,56 +5121,68 @@ def oneOf( strs, caseless=False, useRegex=True ): [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] """ if caseless: - isequal = ( lambda a,b: a.upper() == b.upper() ) - masks = ( lambda a,b: b.upper().startswith(a.upper()) ) + isequal = lambda a, b: a.upper() == b.upper() + masks = lambda a, b: b.upper().startswith(a.upper()) parseElementClass = CaselessLiteral else: - isequal = ( lambda a,b: a == b ) - masks = ( lambda a,b: b.startswith(a) ) + isequal = lambda a, b: a == b + masks = lambda a, b: b.startswith(a) parseElementClass = Literal symbols = [] - if isinstance(strs,basestring): + if isinstance(strs, basestring): symbols = strs.split() elif isinstance(strs, Iterable): symbols = list(strs) else: - warnings.warn("Invalid argument to oneOf, expected string or iterable", - SyntaxWarning, stacklevel=2) + warnings.warn( + "Invalid argument to oneOf, expected string or iterable", + SyntaxWarning, + stacklevel=2, + ) if not symbols: return NoMatch() i = 0 - while i < len(symbols)-1: + while i < len(symbols) - 1: cur = symbols[i] - for j,other in enumerate(symbols[i+1:]): - if ( isequal(other, cur) ): - del symbols[i+j+1] + for j, other in enumerate(symbols[i + 1 :]): + if isequal(other, cur): + del symbols[i + j + 1] break - elif ( masks(cur, other) ): - del symbols[i+j+1] - symbols.insert(i,other) + elif masks(cur, other): + del symbols[i + j + 1] + symbols.insert(i, other) cur = other break else: i += 1 if not caseless and useRegex: - #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) + # ~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) + if len(symbols) == len("".join(symbols)): + return Regex( + "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) + ).setName(' | '.join(symbols)) else: - return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) + return Regex("|".join(re.escape(sym) for sym in symbols)).setName( + ' | '.join(symbols) + ) except Exception: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - + warnings.warn( + "Exception creating Regex for oneOf, building MatchFirst", + SyntaxWarning, + stacklevel=2, + ) # last resort, just use MatchFirst - return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) + return MatchFirst(parseElementClass(sym) for sym in symbols).setName( + ' | '.join(symbols) + ) -def dictOf( key, value ): + +def dictOf(key, value): """ Helper to easily and clearly define a dictionary by specifying the respective patterns for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens @@ -4656,7 +5195,7 @@ def dictOf( key, value ): text = "shape: SQUARE posn: upper left color: light blue texture: burlap" attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) print(OneOrMore(attr_expr).parseString(text).dump()) - + attr_label = label attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) @@ -4676,18 +5215,19 @@ def dictOf( key, value ): SQUARE {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) + return Dict(ZeroOrMore(Group(key + value))) + def originalTextFor(expr, asString=True): """ Helper to return the original, untokenized text for a given expression. Useful to restore the parsed fields of an HTML start tag into the raw tag text itself, or to revert separate tokens with intervening whitespace back to the original matching - input text. By default, returns astring containing the original parsed text. - - If the optional C{asString} argument is passed as C{False}, then the return value is a - C{L{ParseResults}} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if + input text. By default, returns astring containing the original parsed text. + + If the optional C{asString} argument is passed as C{False}, then the return value is a + C{L{ParseResults}} containing any results names that were originally matched, and a + single token containing the original matched text from the input string. So if the expression passed to C{L{originalTextFor}} contains expressions with defined results names, you must set C{asString} to C{False} if you want to preserve those results name values. @@ -4702,25 +5242,29 @@ def originalTextFor(expr, asString=True): [' bold text '] ['text'] """ - locMarker = Empty().setParseAction(lambda s,loc,t: loc) + locMarker = Empty().setParseAction(lambda s, loc, t: loc) endlocMarker = locMarker.copy() endlocMarker.callPreparse = False matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] + extractText = lambda s, l, t: s[t._original_start : t._original_end] else: - def extractText(s,l,t): - t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] + + def extractText(s, l, t): + t[:] = [s[t.pop('_original_start') : t.pop('_original_end')]] + matchExpr.setParseAction(extractText) matchExpr.ignoreExprs = expr.ignoreExprs return matchExpr -def ungroup(expr): + +def ungroup(expr): """ Helper to undo pyparsing's default grouping of And expressions, even if all but one are non-empty. """ - return TokenConverter(expr).setParseAction(lambda t:t[0]) + return TokenConverter(expr).setParseAction(lambda t: t[0]) + def locatedExpr(expr): """ @@ -4742,23 +5286,41 @@ def locatedExpr(expr): [[8, 'lksdjjf', 15]] [[18, 'lkkjj', 23]] """ - locator = Empty().setParseAction(lambda s,l,t: l) - return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) + locator = Empty().setParseAction(lambda s, l, t: l) + return Group( + locator("locn_start") + + expr("value") + + locator.copy().leaveWhitespace()("locn_end") + ) # convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") +empty = Empty().setName("empty") +lineStart = LineStart().setName("lineStart") +lineEnd = LineEnd().setName("lineEnd") stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) -_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1) +stringEnd = StringEnd().setName("stringEnd") + +_escapedPunc = Word(_bslash, r"\[]-*.$+^?()~ ", exact=2).setParseAction( + lambda s, l, t: t[0][1] +) +_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction( + lambda s, l, t: unichr(int(t[0].lstrip(r'\0x'), 16)) +) +_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction( + lambda s, l, t: unichr(int(t[0][1:], 8)) +) +_singleChar = ( + _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1) +) _charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" +_reBracketExpr = ( + Literal("[") + + Optional("^").setResultsName("negate") + + Group(OneOrMore(_charRange | _singleChar)).setResultsName("body") + + "]" +) + def srange(s): r""" @@ -4772,28 +5334,36 @@ def srange(s): The values enclosed in the []'s may be: - a single character - an escaped character with a leading backslash (such as C{\-} or C{\]}) - - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) - (C{\0x##} is also supported for backwards compatibility) + - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) + (C{\0x##} is also supported for backwards compatibility) - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) - a range of any of the above, separated by a dash (C{'a-z'}, etc.) - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) """ - _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) + _expanded = ( + lambda p: p + if not isinstance(p, ParseResults) + else ''.join(unichr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) + ) try: return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) except Exception: return "" + def matchOnlyAtCol(n): """ Helper method for defining parse actions that require matching at a specific column in the input text. """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) + + def verifyCol(strg, locn, toks): + if col(locn, strg) != n: + raise ParseException(strg, locn, "matched token not at column %d" % n) + return verifyCol + def replaceWith(replStr): """ Helper method for common parse actions that simply return a literal value. Especially @@ -4803,12 +5373,13 @@ def replaceWith(replStr): num = Word(nums).setParseAction(lambda toks: int(toks[0])) na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) term = na | num - + OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] """ - return lambda s,l,t: [replStr] + return lambda s, l, t: [replStr] -def removeQuotes(s,l,t): + +def removeQuotes(s, l, t): """ Helper parse action for removing quotation marks from parsed quoted strings. @@ -4822,9 +5393,10 @@ def removeQuotes(s,l,t): """ return t[0][1:-1] + def tokenMap(func, *args): """ - Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional + Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional args are passed, they are forwarded to the given function as additional arguments after the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the parsed data to an integer using base 16. @@ -4834,7 +5406,7 @@ def tokenMap(func, *args): hex_ints.runTests(''' 00 11 22 aa FF 0a 0d 1a ''') - + upperword = Word(alphas).setParseAction(tokenMap(str.upper)) OneOrMore(upperword).runTests(''' my kingdom for a horse @@ -4854,53 +5426,80 @@ def tokenMap(func, *args): now is the winter of our discontent made glorious summer by this sun of york ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] """ - def pa(s,l,t): + + def pa(s, l, t): return [func(tokn, *args) for tokn in t] try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) + func_name = getattr(func, '__name__', getattr(func, '__class__').__name__) except Exception: func_name = str(func) pa.__name__ = func_name return pa + upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) """(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}""" downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) """(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}""" - + + def _makeTags(tagStr, xml): """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): + if isinstance(tagStr, basestring): resname = tagStr tagStr = Keyword(tagStr, caseless=not xml) else: resname = tagStr.name - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + tagAttrName = Word(alphas, alphanums + "_-:") + if xml: + tagAttrValue = dblQuotedString.copy().setParseAction(removeQuotes) + openTag = ( + Suppress("<") + + tagStr("tag") + + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue))) + + Optional("/", default=[False]) + .setResultsName("empty") + .setParseAction(lambda s, l, t: t[0] == '/') + + Suppress(">") + ) else: printablesLessRAbrack = "".join(c for c in printables if c not in ">") - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + tagAttrValue = quotedString.copy().setParseAction(removeQuotes) | Word( + printablesLessRAbrack + ) + openTag = ( + Suppress("<") + + tagStr("tag") + + Dict( + ZeroOrMore( + Group( + tagAttrName.setParseAction(downcaseTokens) + + Optional(Suppress("=") + tagAttrValue) + ) + ) + ) + + Optional("/", default=[False]) + .setResultsName("empty") + .setParseAction(lambda s, l, t: t[0] == '/') + + Suppress(">") + ) closeTag = Combine(_L("") - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % resname) + openTag = openTag.setResultsName( + "start" + "".join(resname.replace(":", " ").title().split()) + ).setName("<%s>" % resname) + closeTag = closeTag.setResultsName( + "end" + "".join(resname.replace(":", " ").title().split()) + ).setName("" % resname) openTag.tag = resname closeTag.tag = resname return openTag, closeTag + def makeHTMLTags(tagStr): """ Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches @@ -4911,14 +5510,15 @@ def makeHTMLTags(tagStr): # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple a,a_end = makeHTMLTags("A") link_expr = a + SkipTo(a_end)("link_text") + a_end - + for link in link_expr.searchString(text): # attributes in the tag (like "href" shown here) are also accessible as named results print(link.link_text, '->', link.href) prints:: pyparsing -> http://pyparsing.wikispaces.com """ - return _makeTags( tagStr, False ) + return _makeTags(tagStr, False) + def makeXMLTags(tagStr): """ @@ -4927,9 +5527,10 @@ def makeXMLTags(tagStr): Example: similar to L{makeHTMLTags} """ - return _makeTags( tagStr, True ) + return _makeTags(tagStr, True) + -def withAttribute(*args,**attrDict): +def withAttribute(*args, **attrDict): """ Helper to create a validating parse action to be used with start tags created with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag @@ -4944,7 +5545,7 @@ def withAttribute(*args,**attrDict): - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) For attribute names with a namespace prefix, you must use the second form. Attribute names are matched insensitive to upper/lower case. - + If just testing for C{class} (with or without a namespace), use C{L{withClass}}. To verify that the attribute exists, but without specifying a value, pass @@ -4958,7 +5559,7 @@ def withAttribute(*args,**attrDict):
1,3 2,3 1,1
this has no type
- + ''' div,div_end = makeHTMLTags("div") @@ -4967,7 +5568,7 @@ def withAttribute(*args,**attrDict): grid_expr = div_grid + SkipTo(div | div_end)("body") for grid_header in grid_expr.searchString(html): print(grid_header.body) - + # construct a match with any div tag having a type attribute, regardless of the value div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) div_expr = div_any_type + SkipTo(div | div_end)("body") @@ -4983,17 +5584,26 @@ def withAttribute(*args,**attrDict): attrs = args[:] else: attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: + attrs = [(k, v) for k, v in attrs] + + def pa(s, l, tokens): + for attrName, attrValue in attrs: if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) + raise ParseException(s, l, "no matching attribute " + attrName) if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) + raise ParseException( + s, + l, + "attribute '%s' has value '%s', must be '%s'" + % (attrName, tokens[attrName], attrValue), + ) + return pa + + withAttribute.ANY_VALUE = object() + def withClass(classname, namespace=''): """ Simplified version of C{L{withAttribute}} when matching on a div class - made @@ -5007,15 +5617,15 @@ def withClass(classname, namespace=''):
1,3 2,3 1,1
this <div> has no class
- + ''' div,div_end = makeHTMLTags("div") div_grid = div().setParseAction(withClass("grid")) - + grid_expr = div_grid + SkipTo(div | div_end)("body") for grid_header in grid_expr.searchString(html): print(grid_header.body) - + div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) div_expr = div_any_type + SkipTo(div | div_end)("body") for div_header in div_expr.searchString(html): @@ -5027,20 +5637,22 @@ def withClass(classname, namespace=''): 1,3 2,3 1,1 """ classattr = "%s:class" % namespace if namespace else "class" - return withAttribute(**{classattr : classname}) + return withAttribute(**{classattr: classname}) + opAssoc = _Constants() opAssoc.LEFT = object() opAssoc.RIGHT = object() -def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): + +def infixNotation(baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')')): """ Helper method for constructing grammars of expressions made up of operators working in a precedence hierarchy. Operators may be unary or binary, left- or right-associative. Parse actions can also be attached - to operator expressions. The generated parser will also recognize the use + to operator expressions. The generated parser will also recognize the use of parentheses to override operator precedences (see example below). - + Note: if you define a deep operator list, you may see performance issues when using infixNotation. See L{ParserElement.enablePackrat} for a mechanism to potentially improve your parser performance. @@ -5070,15 +5682,15 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): Example:: # simple example of four-function arithmetic with ints and variable names integer = pyparsing_common.signed_integer - varname = pyparsing_common.identifier - + varname = pyparsing_common.identifier + arith_expr = infixNotation(integer | varname, [ ('-', 1, opAssoc.RIGHT), (oneOf('* /'), 2, opAssoc.LEFT), (oneOf('+ -'), 2, opAssoc.LEFT), ]) - + arith_expr.runTests(''' 5+3*6 (5+3)*6 @@ -5095,44 +5707,64 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): [[['-', 2], '-', ['-', 11]]] """ ret = Forward() - lastExpr = baseExpr | ( lpar + ret + rpar ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] + lastExpr = baseExpr | (lpar + ret + rpar) + for i, operDef in enumerate(opList): + opExpr, arity, rightLeftAssoc, pa = (operDef + (None,))[:4] termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr if arity == 3: if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") + raise ValueError( + "if numterms=3, opExpr must be a tuple or list of two expressions" + ) opExpr1, opExpr2 = opExpr thisExpr = Forward().setName(termName) if rightLeftAssoc == opAssoc.LEFT: if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) + matchExpr = FollowedBy(lastExpr + opExpr) + Group( + lastExpr + OneOrMore(opExpr) + ) elif arity == 2: if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) + matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( + lastExpr + OneOrMore(opExpr + lastExpr) + ) else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) + matchExpr = FollowedBy(lastExpr + lastExpr) + Group( + lastExpr + OneOrMore(lastExpr) + ) elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) + matchExpr = FollowedBy( + lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr + ) + Group(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + raise ValueError( + "operator must be unary (1), binary (2), or ternary (3)" + ) elif rightLeftAssoc == opAssoc.RIGHT: if arity == 1: # try to avoid LR with this extra test if not isinstance(opExpr, Optional): opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) + matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( + opExpr + thisExpr + ) elif arity == 2: if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) + matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( + lastExpr + OneOrMore(opExpr + thisExpr) + ) else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) + matchExpr = FollowedBy(lastExpr + thisExpr) + Group( + lastExpr + OneOrMore(thisExpr) + ) elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) + matchExpr = FollowedBy( + lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr + ) + Group(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + raise ValueError( + "operator must be unary (1), binary (2), or ternary (3)" + ) else: raise ValueError("operator must indicate right or left associativity") if pa: @@ -5140,20 +5772,28 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): matchExpr.setParseAction(*pa) else: matchExpr.setParseAction(pa) - thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) + thisExpr <<= matchExpr.setName(termName) | lastExpr lastExpr = thisExpr ret <<= lastExpr return ret + operatorPrecedence = infixNotation """(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" -dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") -sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") -quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| - Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") +dblQuotedString = Combine( + Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' +).setName("string enclosed in double quotes") +sglQuotedString = Combine( + Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" +).setName("string enclosed in single quotes") +quotedString = Combine( + Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' + | Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" +).setName("quotedString using single or double quotes") unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") + def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): """ Helper method for defining nested lists enclosed in opening and closing @@ -5186,23 +5826,23 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.cop code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) - c_function = (decl_data_type("type") + c_function = (decl_data_type("type") + ident("name") - + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + code_body("body")) c_function.ignore(cStyleComment) - + source_code = ''' - int is_odd(int x) { - return (x%2); + int is_odd(int x) { + return (x%2); } - - int dec_to_hex(char hchar) { - if (hchar >= '0' && hchar <= '9') { - return (ord(hchar)-ord('0')); - } else { + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { return (10+ord(hchar)-ord('A')); - } + } } ''' for func in c_function.searchString(source_code): @@ -5215,35 +5855,55 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.cop if opener == closer: raise ValueError("opening and closing strings cannot be the same") if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: + if isinstance(opener, basestring) and isinstance(closer, basestring): + if len(opener) == 1 and len(closer) == 1: if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) + content = Combine( + OneOrMore( + ~ignoreExpr + + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS, + exact=1, + ) + ) + ).setParseAction(lambda t: t[0].strip()) else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) + content = empty.copy() + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS + ).setParseAction(lambda t: t[0].strip()) else: if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) + content = Combine( + OneOrMore( + ~ignoreExpr + + ~Literal(opener) + + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) + ) + ).setParseAction(lambda t: t[0].strip()) else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) + content = Combine( + OneOrMore( + ~Literal(opener) + + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) + ) + ).setParseAction(lambda t: t[0].strip()) else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") + raise ValueError( + "opening and closing arguments must be strings if no content expression is given" + ) ret = Forward() if ignoreExpr is not None: - ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) + ret <<= Group( + Suppress(opener) + ZeroOrMore(ignoreExpr | ret | content) + Suppress(closer) + ) else: - ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - ret.setName('nested %s%s expression' % (opener,closer)) + ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer)) + ret.setName('nested %s%s expression' % (opener, closer)) return ret + def indentedBlock(blockStatementExpr, indentStack, indent=True): """ Helper method for defining space-delimited indentation blocks, such as @@ -5320,56 +5980,75 @@ def eggs(z): 'spam', ['(', 'x', 'y', ')'], ':', - [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) + + def checkPeerIndent(s, l, t): + if l >= len(s): + return + curCol = col(l, s) if curCol != indentStack[-1]: if curCol > indentStack[-1]: - raise ParseFatalException(s,l,"illegal nesting") - raise ParseException(s,l,"not a peer entry") + raise ParseFatalException(s, l, "illegal nesting") + raise ParseException(s, l, "not a peer entry") - def checkSubIndent(s,l,t): - curCol = col(l,s) + def checkSubIndent(s, l, t): + curCol = col(l, s) if curCol > indentStack[-1]: - indentStack.append( curCol ) + indentStack.append(curCol) else: - raise ParseException(s,l,"not a subentry") - - def checkUnindent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") + raise ParseException(s, l, "not a subentry") + + def checkUnindent(s, l, t): + if l >= len(s): + return + curCol = col(l, s) + if not (indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): + raise ParseException(s, l, "not an unindent") indentStack.pop() NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') - PEER = Empty().setParseAction(checkPeerIndent).setName('') + PEER = Empty().setParseAction(checkPeerIndent).setName('') UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) + smExpr = Group( + Optional(NL) + + + # ~ FollowedBy(blockStatementExpr) + + INDENT + + (OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL))) + + UNDENT + ) else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) + smExpr = Group( + Optional(NL) + (OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL))) + ) blockStatementExpr.ignore(_bslash + LineEnd()) return smExpr.setName('indented block') + alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) -_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) -commonHTMLEntity = Regex('&(?P' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") +anyOpenTag, anyCloseTag = makeHTMLTags( + Word(alphas, alphanums + "_:").setName('any tag') +) +_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(), '><& "\'')) +commonHTMLEntity = Regex( + '&(?P' + '|'.join(_htmlEntityMap.keys()) + ");" +).setName("common HTML entity") + + def replaceHTMLEntity(t): """Helper parser action to replace common HTML entities with their special characters""" return _htmlEntityMap.get(t.entity) + # it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") +cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName( + "C style comment" +) "Comment of the form C{/* ... */}" htmlComment = Regex(r"").setName("HTML comment") @@ -5379,7 +6058,9 @@ def replaceHTMLEntity(t): dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") "Comment of the form C{// ... (to end of line)}" -cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") +cppStyleComment = Combine( + Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/' | dblSlashComment +).setName("C++ style comment") "Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" javaStyleComment = cppStyleComment @@ -5388,10 +6069,19 @@ def replaceHTMLEntity(t): pythonStyleComment = Regex(r"#.*").setName("Python style comment") "Comment of the form C{# ... (to end of line)}" -_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + - Optional( Word(" \t") + - ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") -commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") +_commasepitem = ( + Combine( + OneOrMore( + Word(printables, excludeChars=',') + + Optional(Word(" \t") + ~Literal(",") + ~LineEnd()) + ) + ) + .streamline() + .setName("commaItem") +) +commaSeparatedList = delimitedList( + Optional(quotedString.copy() | _commasepitem, default="") +).setName("commaSeparatedList") """(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" @@ -5545,48 +6235,80 @@ class pyparsing_common: integer = Word(nums).setName("integer").setParseAction(convertToInteger) """expression that parses an unsigned integer, returns an int""" - hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) + hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int, 16)) """expression that parses a hexadecimal integer, returns an int""" - signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + signed_integer = ( + Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + ) """expression that parses an integer with optional leading sign, returns an int""" - fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") + fraction = ( + signed_integer().setParseAction(convertToFloat) + + '/' + + signed_integer().setParseAction(convertToFloat) + ).setName("fraction") """fractional expression of an integer divided by an integer, returns a float""" - fraction.addParseAction(lambda t: t[0]/t[-1]) + fraction.addParseAction(lambda t: t[0] / t[-1]) - mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") + mixed_integer = ( + fraction | signed_integer + Optional(Optional('-').suppress() + fraction) + ).setName("fraction or mixed integer-fraction") """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" mixed_integer.addParseAction(sum) real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) """expression that parses a floating point number and returns a float""" - sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) + sci_real = ( + Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)') + .setName("real number with scientific notation") + .setParseAction(convertToFloat) + ) """expression that parses a floating point number with optional scientific notation and returns a float""" # streamlining this expression makes the docs nicer-looking number = (sci_real | real | signed_integer).streamline() """any numeric expression, returns the corresponding Python type""" - fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) + fnumber = ( + Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?') + .setName("fnumber") + .setParseAction(convertToFloat) + ) """any int or real number, returned as float""" - - identifier = Word(alphas+'_', alphanums+'_').setName("identifier") + + identifier = Word(alphas + '_', alphanums + '_').setName("identifier") """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" - - ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") + + ipv4_address = Regex( + r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}' + ).setName("IPv4 address") "IPv4 address (C{0.0.0.0 - 255.255.255.255})" _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") - _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") - _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") - _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) + _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part) * 7).setName( + "full IPv6 address" + ) + _short_ipv6_address = ( + Optional(_ipv6_part + (':' + _ipv6_part) * (0, 6)) + + "::" + + Optional(_ipv6_part + (':' + _ipv6_part) * (0, 6)) + ).setName("short IPv6 address") + _short_ipv6_address.addCondition( + lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8 + ) _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") - ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") + ipv6_address = Combine( + (_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName( + "IPv6 address" + ) + ).setName("IPv6 address") "IPv6 address (long, short, or mixed form)" - - mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") + + mac_address = Regex( + r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}' + ).setName("MAC address") "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" @staticmethod @@ -5604,11 +6326,13 @@ def convertToDate(fmt="%Y-%m-%d"): prints:: [datetime.date(1999, 12, 31)] """ - def cvt_fn(s,l,t): + + def cvt_fn(s, l, t): try: return datetime.strptime(t[0], fmt).date() except ValueError as ve: raise ParseException(s, l, str(ve)) + return cvt_fn @staticmethod @@ -5626,41 +6350,60 @@ def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): prints:: [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] """ - def cvt_fn(s,l,t): + + def cvt_fn(s, l, t): try: return datetime.strptime(t[0], fmt) except ValueError as ve: raise ParseException(s, l, str(ve)) + return cvt_fn - iso8601_date = Regex(r'(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?').setName("ISO8601 date") + iso8601_date = Regex( + r'(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?' + ).setName("ISO8601 date") "ISO8601 date (C{yyyy-mm-dd})" - iso8601_datetime = Regex(r'(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") + iso8601_datetime = Regex( + r'(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?' + ).setName("ISO8601 datetime") "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() + @staticmethod def stripHTMLTags(s, l, tokens): """ Parse action to remove HTML tags from web page HTML source Example:: - # strip HTML links from normal text + # strip HTML links from normal text text = 'More info at the
pyparsing wiki page' td,td_end = makeHTMLTags("TD") table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end - + print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' """ return pyparsing_common._html_stripper.transformString(tokens[0]) - _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') - + Optional( White(" \t") ) ) ).streamline().setName("commaItem") - comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") + _commasepitem = ( + Combine( + OneOrMore( + ~Literal(",") + + ~LineEnd() + + Word(printables, excludeChars=',') + + Optional(White(" \t")) + ) + ) + .streamline() + .setName("commaItem") + ) + comma_separated_list = delimitedList( + Optional(quotedString.copy() | _commasepitem, default="") + ).setName("comma separated list") """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) @@ -5672,22 +6415,28 @@ def stripHTMLTags(s, l, tokens): if __name__ == "__main__": - selectToken = CaselessLiteral("select") - fromToken = CaselessLiteral("from") + selectToken = CaselessLiteral("select") + fromToken = CaselessLiteral("from") - ident = Word(alphas, alphanums + "_$") + ident = Word(alphas, alphanums + "_$") - columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) columnNameList = Group(delimitedList(columnName)).setName("columns") - columnSpec = ('*' | columnNameList) + columnSpec = '*' | columnNameList - tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - tableNameList = Group(delimitedList(tableName)).setName("tables") - - simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") + tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + tableNameList = Group(delimitedList(tableName)).setName("tables") + + simpleSQL = ( + selectToken("command") + + columnSpec("columns") + + fromToken + + tableNameList("tables") + ) # demo runTests method, including embedded comments in test string - simpleSQL.runTests(""" + simpleSQL.runTests( + """ # '*' as column list and dotted table name select * from SYS.XYZZY @@ -5709,34 +6458,44 @@ def stripHTMLTags(s, l, tokens): # invalid column name - should fail Select ^^^ frox Sys.dual - """) + """ + ) - pyparsing_common.number.runTests(""" + pyparsing_common.number.runTests( + """ 100 -100 +100 3.14159 6.02e23 1e-12 - """) + """ + ) # any int or real number, returned as float - pyparsing_common.fnumber.runTests(""" + pyparsing_common.fnumber.runTests( + """ 100 -100 +100 3.14159 6.02e23 1e-12 - """) + """ + ) - pyparsing_common.hex_integer.runTests(""" + pyparsing_common.hex_integer.runTests( + """ 100 FF - """) + """ + ) import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(""" + pyparsing_common.uuid.runTests( + """ 12345678-1234-5678-1234-567812345678 - """) + """ + ) diff --git a/pkg_resources/extern/__init__.py b/pkg_resources/extern/__init__.py index fed59295403..8128ade8ec6 100644 --- a/pkg_resources/extern/__init__.py +++ b/pkg_resources/extern/__init__.py @@ -58,7 +58,8 @@ def find_spec(self, fullname, path=None, target=None): """Return a module spec for vendored names.""" return ( importlib.util.spec_from_loader(fullname, self) - if self._module_matches_namespace(fullname) else None + if self._module_matches_namespace(fullname) + else None ) def install(self): diff --git a/pkg_resources/tests/data/my-test-package-source/setup.py b/pkg_resources/tests/data/my-test-package-source/setup.py index fe80d28f465..ce9080640c0 100644 --- a/pkg_resources/tests/data/my-test-package-source/setup.py +++ b/pkg_resources/tests/data/my-test-package-source/setup.py @@ -1,4 +1,5 @@ import setuptools + setuptools.setup( name="my-test-package", version="1.0", diff --git a/pkg_resources/tests/test_find_distributions.py b/pkg_resources/tests/test_find_distributions.py index b01b4827a7d..4ffcdf3b585 100644 --- a/pkg_resources/tests/test_find_distributions.py +++ b/pkg_resources/tests/test_find_distributions.py @@ -7,7 +7,6 @@ class TestFindDistributions: - @pytest.fixture def target_dir(self, tmpdir): target_dir = tmpdir.mkdir('target') @@ -36,8 +35,10 @@ def test_zipped_egg(self, target_dir): def test_zipped_sdist_one_level_removed(self, target_dir): (TESTS_DATA_DIR / 'my-test-package-zip').copy(target_dir) dists = pkg_resources.find_distributions( - str(target_dir / "my-test-package.zip")) + str(target_dir / "my-test-package.zip") + ) assert [dist.project_name for dist in dists] == ['my-test-package'] dists = pkg_resources.find_distributions( - str(target_dir / "my-test-package.zip"), only=True) + str(target_dir / "my-test-package.zip"), only=True + ) assert not list(dists) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 6518820e6f3..bf59f2550fc 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -15,7 +15,9 @@ import mock from pkg_resources import ( - DistInfoDistribution, Distribution, EggInfoDistribution, + DistInfoDistribution, + Distribution, + EggInfoDistribution, ) import pytest @@ -85,6 +87,7 @@ def teardown_class(cls): def test_resource_listdir(self): import mod + zp = pkg_resources.ZipProvider(mod) expected_root = ['data.dat', 'mod.py', 'subdir'] @@ -98,6 +101,7 @@ def test_resource_listdir(self): assert zp.resource_listdir('nonexistent/') == [] import mod2 + zp2 = pkg_resources.ZipProvider(mod2) assert sorted(zp2.resource_listdir('')) == expected_subdir @@ -113,6 +117,7 @@ def test_resource_filename_rewrites_on_change(self): subsequent call to get_resource_filename. """ import mod + manager = pkg_resources.ResourceManager() zp = pkg_resources.ZipProvider(mod) filename = zp.get_resource_filename(manager, 'data.dat') @@ -177,10 +182,7 @@ def test_setuptools_not_imported(self): lines = ( 'import pkg_resources', 'import sys', - ( - 'assert "setuptools" not in sys.modules, ' - '"setuptools was imported"' - ), + ('assert "setuptools" not in sys.modules, ' '"setuptools was imported"'), ) cmd = [sys.executable, '-c', '; '.join(lines)] subprocess.check_call(cmd) @@ -201,7 +203,7 @@ def make_test_distribution(metadata_path, metadata): with open(metadata_path, 'wb') as f: f.write(metadata) dists = list(pkg_resources.distributions_from_metadata(dist_dir)) - dist, = dists + (dist,) = dists return dist @@ -247,7 +249,7 @@ def make_distribution_no_version(tmpdir, basename): dists = list(pkg_resources.distributions_from_metadata(dist_dir)) assert len(dists) == 1 - dist, = dists + (dist,) = dists return dist, dist_dir @@ -260,16 +262,17 @@ def make_distribution_no_version(tmpdir, basename): ], ) def test_distribution_version_missing( - tmpdir, suffix, expected_filename, expected_dist_type): + tmpdir, suffix, expected_filename, expected_dist_type +): """ Test Distribution.version when the "Version" header is missing. """ basename = 'foo.{}'.format(suffix) dist, dist_dir = make_distribution_no_version(tmpdir, basename) - expected_text = ( - "Missing 'Version:' header and/or {} file at path: " - ).format(expected_filename) + expected_text = ("Missing 'Version:' header and/or {} file at path: ").format( + expected_filename + ) metadata_path = os.path.join(dist_dir, expected_filename) # Now check the exception raised when the "version" attribute is accessed. @@ -302,8 +305,7 @@ def test_distribution_version_missing_undetected_path(): msg, dist = excinfo.value.args expected = ( - "Missing 'Version:' header and/or PKG-INFO file at path: " - '[could not detect]' + "Missing 'Version:' header and/or PKG-INFO file at path: " '[could not detect]' ) assert msg == expected @@ -330,10 +332,7 @@ class Environment(str): env = Environment(tmpdir) tmpdir.chmod(stat.S_IRWXU) subs = 'home', 'lib', 'scripts', 'data', 'egg-base' - env.paths = dict( - (dirname, str(tmpdir / dirname)) - for dirname in subs - ) + env.paths = dict((dirname, str(tmpdir / dirname)) for dirname in subs) list(map(os.mkdir, env.paths.values())) return env @@ -390,8 +389,7 @@ def test_normalize_path_trailing_sep(self, unnormalized, normalized): ], ) def test_normalize_path_normcase(self, unnormalized, normalized): - """Ensure mixed case is normalized on case-insensitive filesystems. - """ + """Ensure mixed case is normalized on case-insensitive filesystems.""" result_from_unnormalized = pkg_resources.normalize_path(unnormalized) result_from_normalized = pkg_resources.normalize_path(normalized) assert result_from_unnormalized == result_from_normalized @@ -409,7 +407,6 @@ def test_normalize_path_normcase(self, unnormalized, normalized): ], ) def test_normalize_path_backslash_sep(self, unnormalized, expected): - """Ensure path seps are cleaned on backslash path sep systems. - """ + """Ensure path seps are cleaned on backslash path sep systems.""" result = pkg_resources.normalize_path(unnormalized) assert result.endswith(expected) diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 965a7c00897..4f94144d761 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -9,9 +9,16 @@ import pkg_resources from pkg_resources import ( - parse_requirements, VersionConflict, parse_version, - Distribution, EntryPoint, Requirement, safe_version, safe_name, - WorkingSet) + parse_requirements, + VersionConflict, + parse_version, + Distribution, + EntryPoint, + Requirement, + safe_version, + safe_name, + WorkingSet, +) # from Python 3.6 docs. @@ -71,7 +78,7 @@ def testCollection(self): ws = WorkingSet([]) foo12 = dist_from_fn("FooPkg-1.2-py2.4.egg") foo14 = dist_from_fn("FooPkg-1.4-py2.4-win32.egg") - req, = parse_requirements("FooPkg>=1.3") + (req,) = parse_requirements("FooPkg>=1.3") # Nominal case: no distros on path, should yield all applicable assert ad.best_match(req, ws).version == '1.9' @@ -123,11 +130,11 @@ def testDistroParse(self): def testDistroMetadata(self): d = Distribution( - "/some/path", project_name="FooPkg", - py_version="2.4", platform="win32", - metadata=Metadata( - ('PKG-INFO', "Metadata-Version: 1.0\nVersion: 1.3-1\n") - ), + "/some/path", + project_name="FooPkg", + py_version="2.4", + platform="win32", + metadata=Metadata(('PKG-INFO', "Metadata-Version: 1.0\nVersion: 1.3-1\n")), ) self.checkFooPkg(d) @@ -181,7 +188,7 @@ def testResolve(self): Foo = Distribution.from_filename( "/foo_dir/Foo-1.2.egg", - metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0")) + metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0")), ) ad.add(Foo) ad.add(Distribution.from_filename("Foo-0.9.egg")) @@ -204,10 +211,7 @@ def testResolve(self): ad.add(Baz) # Activation list now includes resolved dependency - assert ( - list(ws.resolve(parse_requirements("Foo[bar]"), ad)) - == [Foo, Baz] - ) + assert list(ws.resolve(parse_requirements("Foo[bar]"), ad)) == [Foo, Baz] # Requests for conflicting versions produce VersionConflict with pytest.raises(VersionConflict) as vc: ws.resolve(parse_requirements("Foo==1.2\nFoo!=1.2"), ad) @@ -235,13 +239,13 @@ def test_environment_marker_evaluation_called(self): If one package foo requires bar without any extras, markers should pass for bar without extras. """ - parent_req, = parse_requirements("foo") - req, = parse_requirements("bar;python_version>='2'") + (parent_req,) = parse_requirements("foo") + (req,) = parse_requirements("bar;python_version>='2'") req_extras = pkg_resources._ReqExtras({req: parent_req.extras}) assert req_extras.markers_pass(req) - parent_req, = parse_requirements("foo[]") - req, = parse_requirements("bar;python_version>='2'") + (parent_req,) = parse_requirements("foo[]") + (req,) = parse_requirements("bar;python_version>='2'") req_extras = pkg_resources._ReqExtras({req: parent_req.extras}) assert req_extras.markers_pass(req) @@ -251,8 +255,12 @@ def test_marker_evaluation_with_extras(self): ws = WorkingSet([]) Foo = Distribution.from_filename( "/foo_dir/Foo-1.2.dist-info", - metadata=Metadata(("METADATA", "Provides-Extra: baz\n" - "Requires-Dist: quux; extra=='baz'")) + metadata=Metadata( + ( + "METADATA", + "Provides-Extra: baz\n" "Requires-Dist: quux; extra=='baz'", + ) + ), ) ad.add(Foo) assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo] @@ -267,8 +275,13 @@ def test_marker_evaluation_with_extras_normlized(self): ws = WorkingSet([]) Foo = Distribution.from_filename( "/foo_dir/Foo-1.2.dist-info", - metadata=Metadata(("METADATA", "Provides-Extra: baz-lightyear\n" - "Requires-Dist: quux; extra=='baz-lightyear'")) + metadata=Metadata( + ( + "METADATA", + "Provides-Extra: baz-lightyear\n" + "Requires-Dist: quux; extra=='baz-lightyear'", + ) + ), ) ad.add(Foo) assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo] @@ -282,10 +295,15 @@ def test_marker_evaluation_with_multiple_extras(self): ws = WorkingSet([]) Foo = Distribution.from_filename( "/foo_dir/Foo-1.2.dist-info", - metadata=Metadata(("METADATA", "Provides-Extra: baz\n" - "Requires-Dist: quux; extra=='baz'\n" - "Provides-Extra: bar\n" - "Requires-Dist: fred; extra=='bar'\n")) + metadata=Metadata( + ( + "METADATA", + "Provides-Extra: baz\n" + "Requires-Dist: quux; extra=='baz'\n" + "Provides-Extra: bar\n" + "Requires-Dist: fred; extra=='bar'\n", + ) + ), ) ad.add(Foo) quux = Distribution.from_filename("/foo_dir/quux-1.0.dist-info") @@ -300,18 +318,23 @@ def test_marker_evaluation_with_extras_loop(self): ws = WorkingSet([]) a = Distribution.from_filename( "/foo_dir/a-0.2.dist-info", - metadata=Metadata(("METADATA", "Requires-Dist: c[a]")) + metadata=Metadata(("METADATA", "Requires-Dist: c[a]")), ) b = Distribution.from_filename( "/foo_dir/b-0.3.dist-info", - metadata=Metadata(("METADATA", "Requires-Dist: c[b]")) + metadata=Metadata(("METADATA", "Requires-Dist: c[b]")), ) c = Distribution.from_filename( "/foo_dir/c-1.0.dist-info", - metadata=Metadata(("METADATA", "Provides-Extra: a\n" - "Requires-Dist: b;extra=='a'\n" - "Provides-Extra: b\n" - "Requires-Dist: foo;extra=='b'")) + metadata=Metadata( + ( + "METADATA", + "Provides-Extra: a\n" + "Requires-Dist: b;extra=='a'\n" + "Provides-Extra: b\n" + "Requires-Dist: foo;extra=='b'", + ) + ), ) foo = Distribution.from_filename("/foo_dir/foo-0.1.dist-info") for dist in (a, b, c, foo): @@ -320,27 +343,29 @@ def test_marker_evaluation_with_extras_loop(self): assert res == [a, c, b, foo] def testDistroDependsOptions(self): - d = self.distRequires(""" + d = self.distRequires( + """ Twisted>=1.5 [docgen] ZConfig>=2.0 docutils>=0.3 [fastcgi] - fcgiapp>=0.1""") + fcgiapp>=0.1""" + ) self.checkRequires(d, "Twisted>=1.5") self.checkRequires( d, "Twisted>=1.5 ZConfig>=2.0 docutils>=0.3".split(), ["docgen"] ) + self.checkRequires(d, "Twisted>=1.5 fcgiapp>=0.1".split(), ["fastcgi"]) self.checkRequires( - d, "Twisted>=1.5 fcgiapp>=0.1".split(), ["fastcgi"] + d, + "Twisted>=1.5 ZConfig>=2.0 docutils>=0.3 fcgiapp>=0.1".split(), + ["docgen", "fastcgi"], ) self.checkRequires( - d, "Twisted>=1.5 ZConfig>=2.0 docutils>=0.3 fcgiapp>=0.1".split(), - ["docgen", "fastcgi"] - ) - self.checkRequires( - d, "Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(), - ["fastcgi", "docgen"] + d, + "Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(), + ["fastcgi", "docgen"], ) with pytest.raises(pkg_resources.UnknownExtra): d.requires(["foo"]) @@ -400,12 +425,16 @@ def assertfields(self, ep): def setup_method(self, method): self.dist = Distribution.from_filename( - "FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt', '[x]'))) + "FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt', '[x]')) + ) def testBasics(self): ep = EntryPoint( - "foo", "pkg_resources.tests.test_resources", ["TestEntryPoints"], - ["x"], self.dist + "foo", + "pkg_resources.tests.test_resources", + ["TestEntryPoints"], + ["x"], + self.dist, ) self.assertfields(ep) @@ -459,8 +488,9 @@ def checkSubMap(self, m): submap_expect = dict( feature1=EntryPoint('feature1', 'somemodule', ['somefunction']), feature2=EntryPoint( - 'feature2', 'another.module', ['SomeClass'], ['extra1', 'extra2']), - feature3=EntryPoint('feature3', 'this.module', extras=['something']) + 'feature2', 'another.module', ['SomeClass'], ['extra1', 'extra2'] + ), + feature3=EntryPoint('feature3', 'this.module', extras=['something']), ) submap_str = """ # define features for blah blah @@ -490,8 +520,7 @@ def testParseMap(self): def testDeprecationWarnings(self): ep = EntryPoint( - "foo", "pkg_resources.tests.test_resources", ["TestEntryPoints"], - ["x"] + "foo", "pkg_resources.tests.test_resources", ["TestEntryPoints"], ["x"] ) with pytest.warns(pkg_resources.PkgResourcesDeprecationWarning): ep.load(require=False) @@ -515,10 +544,8 @@ def testOrdering(self): assert r1 == r2 assert str(r1) == str(r2) assert str(r2) == "Twisted==1.2c1,>=1.2" - assert ( - Requirement("Twisted") - != - Requirement("Twisted @ https://localhost/twisted.zip") + assert Requirement("Twisted") != Requirement( + "Twisted @ https://localhost/twisted.zip" ) def testBasicContains(self): @@ -541,27 +568,25 @@ def testOptionsAndHashing(self): assert set(r1.extras) == set(("foo", "bar")) assert set(r2.extras) == set(("foo", "bar")) assert hash(r1) == hash(r2) - assert ( - hash(r1) - == - hash(( + assert hash(r1) == hash( + ( "twisted", None, packaging.specifiers.SpecifierSet(">=1.2"), frozenset(["foo", "bar"]), - None - )) + None, + ) ) - assert ( - hash(Requirement.parse("Twisted @ https://localhost/twisted.zip")) - == - hash(( + assert hash( + Requirement.parse("Twisted @ https://localhost/twisted.zip") + ) == hash( + ( "twisted", "https://localhost/twisted.zip", packaging.specifiers.SpecifierSet(), frozenset(), - None - )) + None, + ) ) def testVersionEquality(self): @@ -583,21 +608,11 @@ def testSetuptoolsProjectName(self): The setuptools project should implement the setuptools package. """ - assert ( - Requirement.parse('setuptools').project_name == 'setuptools') + assert Requirement.parse('setuptools').project_name == 'setuptools' # setuptools 0.7 and higher means setuptools. - assert ( - Requirement.parse('setuptools == 0.7').project_name - == 'setuptools' - ) - assert ( - Requirement.parse('setuptools == 0.7a1').project_name - == 'setuptools' - ) - assert ( - Requirement.parse('setuptools >= 0.7').project_name - == 'setuptools' - ) + assert Requirement.parse('setuptools == 0.7').project_name == 'setuptools' + assert Requirement.parse('setuptools == 0.7a1').project_name == 'setuptools' + assert Requirement.parse('setuptools >= 0.7').project_name == 'setuptools' class TestParsing: @@ -606,7 +621,10 @@ def testEmptyParse(self): def testYielding(self): for inp, out in [ - ([], []), ('x', ['x']), ([[]], []), (' x\n y', ['x', 'y']), + ([], []), + ('x', ['x']), + ([[]], []), + (' x\n y', ['x', 'y']), (['x\n\n', 'y'], ['x', 'y']), ]: assert list(pkg_resources.yield_lines(inp)) == out @@ -625,17 +643,13 @@ def testSplitting(self): [q] v """ - assert ( - list(pkg_resources.split_sections(sample)) - == - [ - (None, ["x"]), - ("Y", ["z", "a"]), - ("b", ["c"]), - ("d", []), - ("q", ["v"]), - ] - ) + assert list(pkg_resources.split_sections(sample)) == [ + (None, ["x"]), + ("Y", ["z", "a"]), + ("b", ["c"]), + ("d", []), + ("q", ["v"]), + ] with pytest.raises(ValueError): list(pkg_resources.split_sections("[foo")) @@ -654,21 +668,13 @@ def testSafeVersion(self): assert safe_version("peak.web") == "peak.web" def testSimpleRequirements(self): - assert ( - list(parse_requirements('Twis-Ted>=1.2-1')) - == - [Requirement('Twis-Ted>=1.2-1')] - ) - assert ( - list(parse_requirements('Twisted >=1.2, \\ # more\n<2.0')) - == - [Requirement('Twisted>=1.2,<2.0')] - ) - assert ( - Requirement.parse("FooBar==1.99a3") - == - Requirement("FooBar==1.99a3") - ) + assert list(parse_requirements('Twis-Ted>=1.2-1')) == [ + Requirement('Twis-Ted>=1.2-1') + ] + assert list(parse_requirements('Twisted >=1.2, \\ # more\n<2.0')) == [ + Requirement('Twisted>=1.2,<2.0') + ] + assert Requirement.parse("FooBar==1.99a3") == Requirement("FooBar==1.99a3") with pytest.raises(ValueError): Requirement.parse(">=2.3") with pytest.raises(ValueError): @@ -681,33 +687,25 @@ def testSimpleRequirements(self): Requirement.parse("#") def test_requirements_with_markers(self): - assert ( - Requirement.parse("foobar;os_name=='a'") - == - Requirement.parse("foobar;os_name=='a'") - ) - assert ( - Requirement.parse("name==1.1;python_version=='2.7'") - != - Requirement.parse("name==1.1;python_version=='3.6'") - ) - assert ( - Requirement.parse("name==1.0;python_version=='2.7'") - != - Requirement.parse("name==1.2;python_version=='2.7'") - ) - assert ( - Requirement.parse("name[foo]==1.0;python_version=='3.6'") - != - Requirement.parse("name[foo,bar]==1.0;python_version=='3.6'") - ) + assert Requirement.parse("foobar;os_name=='a'") == Requirement.parse( + "foobar;os_name=='a'" + ) + assert Requirement.parse( + "name==1.1;python_version=='2.7'" + ) != Requirement.parse("name==1.1;python_version=='3.6'") + assert Requirement.parse( + "name==1.0;python_version=='2.7'" + ) != Requirement.parse("name==1.2;python_version=='2.7'") + assert Requirement.parse( + "name[foo]==1.0;python_version=='3.6'" + ) != Requirement.parse("name[foo,bar]==1.0;python_version=='3.6'") def test_local_version(self): - req, = parse_requirements('foo==1.0.org1') + (req,) = parse_requirements('foo==1.0.org1') def test_spaces_between_multiple_versions(self): - req, = parse_requirements('foo>=1.0, <3') - req, = parse_requirements('foo >= 1.0, < 3') + (req,) = parse_requirements('foo>=1.0, <3') + (req,) = parse_requirements('foo >= 1.0, < 3') @pytest.mark.parametrize( ['lower', 'upper'], @@ -752,7 +750,8 @@ def testVersionEquality(self, lower, upper): ('0post1', '0.4post1'), ('2.1.0-rc1', '2.1.0'), ('2.1dev', '2.1a0'), - ] + list(pairwise(reversed(torture.split()))), + ] + + list(pairwise(reversed(torture.split()))), ) def testVersionOrdering(self, lower, upper): assert parse_version(lower) < parse_version(upper) @@ -762,11 +761,7 @@ def testVersionHashable(self): Ensure that our versions stay hashable even though we've subclassed them and added some shim code to them. """ - assert ( - hash(parse_version("1.0")) - == - hash(parse_version("1.0")) - ) + assert hash(parse_version("1.0")) == hash(parse_version("1.0")) class TestNamespaces: @@ -831,9 +826,11 @@ def test_two_levels_deep(self, symlinked_tmpdir): (pkg1 / '__init__.py').write_text(self.ns_str, encoding='utf-8') (pkg2 / '__init__.py').write_text(self.ns_str, encoding='utf-8') import pkg1 + assert "pkg1" in pkg_resources._namespace_packages # attempt to import pkg2 from site-pkgs2 import pkg1.pkg2 + # check the _namespace_packages dict assert "pkg1.pkg2" in pkg_resources._namespace_packages assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"] @@ -871,14 +868,11 @@ def test_path_order(self, symlinked_tmpdir): subpkg = nspkg / 'subpkg' subpkg.ensure_dir() (nspkg / '__init__.py').write_text(self.ns_str, encoding='utf-8') - (subpkg / '__init__.py').write_text( - vers_str % number, encoding='utf-8') + (subpkg / '__init__.py').write_text(vers_str % number, encoding='utf-8') import nspkg.subpkg import nspkg - expected = [ - str(site.realpath() / 'nspkg') - for site in site_dirs - ] + + expected = [str(site.realpath() / 'nspkg') for site in site_dirs] assert nspkg.__path__ == expected assert nspkg.subpkg.__version__ == 1 diff --git a/pkg_resources/tests/test_working_set.py b/pkg_resources/tests/test_working_set.py index db13c7149bd..1e2dc06c671 100644 --- a/pkg_resources/tests/test_working_set.py +++ b/pkg_resources/tests/test_working_set.py @@ -12,13 +12,14 @@ def strip_comments(s): return '\n'.join( - line for line in s.split('\n') + line + for line in s.split('\n') if line.strip() and not line.strip().startswith('#') ) def parse_distributions(s): - ''' + """ Parse a series of distribution specs of the form: {project_name}-{version} [optional, indented requirements specification] @@ -35,7 +36,7 @@ def parse_distributions(s): - project_name=foo, version=0.2 - project_name=bar, version=1.0, requires=['foo>=3.0', 'baz; extra=="feature"'] - ''' + """ s = s.strip() for spec in re.split(r'\n(?=[^\s])', s): if not spec: @@ -48,20 +49,20 @@ def parse_distributions(s): metadata = Metadata(('requires.txt', requires)) else: metadata = None - dist = pkg_resources.Distribution(project_name=name, - version=version, - metadata=metadata) + dist = pkg_resources.Distribution( + project_name=name, version=version, metadata=metadata + ) yield dist class FakeInstaller: - def __init__(self, installable_dists): self._installable_dists = installable_dists def __call__(self, req): - return next(iter(filter(lambda dist: dist in req, - self._installable_dists)), None) + return next( + iter(filter(lambda dist: dist in req, self._installable_dists)), None + ) def parametrize_test_working_set_resolve(*test_list): @@ -73,10 +74,11 @@ def parametrize_test_working_set_resolve(*test_list): installed_dists, installable_dists, requirements, - expected1, expected2 + expected1, + expected2, ) = [ - strip_comments(s.lstrip()) for s in - textwrap.dedent(test).lstrip().split('\n\n', 5) + strip_comments(s.lstrip()) + for s in textwrap.dedent(test).lstrip().split('\n\n', 5) ] installed_dists = list(parse_distributions(installed_dists)) installable_dists = list(parse_distributions(installable_dists)) @@ -92,13 +94,22 @@ def parametrize_test_working_set_resolve(*test_list): assert issubclass(expected, Exception) else: expected = list(parse_distributions(expected)) - argvalues.append(pytest.param(installed_dists, installable_dists, - requirements, replace_conflicting, - expected)) - return pytest.mark.parametrize('installed_dists,installable_dists,' - 'requirements,replace_conflicting,' - 'resolved_dists_or_exception', - argvalues, ids=idlist) + argvalues.append( + pytest.param( + installed_dists, + installable_dists, + requirements, + replace_conflicting, + expected, + ) + ) + return pytest.mark.parametrize( + 'installed_dists,installable_dists,' + 'requirements,replace_conflicting,' + 'resolved_dists_or_exception', + argvalues, + ids=idlist, + ) @parametrize_test_working_set_resolve( @@ -116,7 +127,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] ''', - ''' # id already_installed @@ -135,7 +145,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] foo-3.0 ''', - ''' # id installable_not_installed @@ -155,7 +164,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] foo-3.0 ''', - ''' # id not_installable @@ -173,7 +181,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] DistributionNotFound ''', - ''' # id no_matching_version @@ -192,7 +199,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] DistributionNotFound ''', - ''' # id installable_with_installed_conflict @@ -212,7 +218,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] foo-3.5 ''', - ''' # id not_installable_with_installed_conflict @@ -231,7 +236,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] DistributionNotFound ''', - ''' # id installed_with_installed_require @@ -254,7 +258,6 @@ def parametrize_test_working_set_resolve(*test_list): foo-3.9 baz-0.1 ''', - ''' # id installed_with_conflicting_installed_require @@ -275,7 +278,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] DistributionNotFound ''', - ''' # id installed_with_installable_conflicting_require @@ -298,7 +300,6 @@ def parametrize_test_working_set_resolve(*test_list): baz-0.1 foo-2.9 ''', - ''' # id installed_with_installable_require @@ -321,7 +322,6 @@ def parametrize_test_working_set_resolve(*test_list): foo-3.9 baz-0.1 ''', - ''' # id installable_with_installed_require @@ -344,7 +344,6 @@ def parametrize_test_working_set_resolve(*test_list): foo-3.9 baz-0.1 ''', - ''' # id installable_with_installable_require @@ -367,7 +366,6 @@ def parametrize_test_working_set_resolve(*test_list): foo-3.9 baz-0.1 ''', - ''' # id installable_with_conflicting_installable_require @@ -390,7 +388,6 @@ def parametrize_test_working_set_resolve(*test_list): baz-0.1 foo-2.9 ''', - ''' # id conflicting_installables @@ -411,7 +408,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] VersionConflict ''', - ''' # id installables_with_conflicting_requires @@ -436,7 +432,6 @@ def parametrize_test_working_set_resolve(*test_list): # resolved [replace conflicting] VersionConflict ''', - ''' # id installables_with_conflicting_nested_requires @@ -466,13 +461,19 @@ def parametrize_test_working_set_resolve(*test_list): VersionConflict ''', ) -def test_working_set_resolve(installed_dists, installable_dists, requirements, - replace_conflicting, resolved_dists_or_exception): +def test_working_set_resolve( + installed_dists, + installable_dists, + requirements, + replace_conflicting, + resolved_dists_or_exception, +): ws = pkg_resources.WorkingSet([]) list(map(ws.add, installed_dists)) resolve_call = functools.partial( ws.resolve, - requirements, installer=FakeInstaller(installable_dists), + requirements, + installer=FakeInstaller(installable_dists), replace_conflicting=replace_conflicting, ) if inspect.isclass(resolved_dists_or_exception): diff --git a/setup.py b/setup.py index c6affe9779f..ee976615de6 100755 --- a/setup.py +++ b/setup.py @@ -14,10 +14,9 @@ setuptools=['script (dev).tmpl', 'script.tmpl', 'site-patch.py'], ) -force_windows_specific_files = ( - os.environ.get("SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES", "1").lower() - not in ("", "0", "false", "no") -) +force_windows_specific_files = os.environ.get( + "SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES", "1" +).lower() not in ("", "0", "false", "no") include_windows_files = sys.platform == 'win32' or force_windows_specific_files @@ -51,12 +50,18 @@ class install_with_pth(install): """ _pth_name = 'distutils-precedence' - _pth_contents = textwrap.dedent(""" + _pth_contents = ( + textwrap.dedent( + """ import os var = 'SETUPTOOLS_USE_DISTUTILS' enabled = os.environ.get(var, 'stdlib') == 'local' enabled and __import__('_distutils_hack').add_shim() - """).lstrip().replace('\n', '; ') + """ + ) + .lstrip() + .replace('\n', '; ') + ) def initialize_options(self): install.initialize_options(self) diff --git a/setuptools/__init__.py b/setuptools/__init__.py index 4d9b835729d..7a3edc7383e 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -21,9 +21,14 @@ __all__ = [ - 'setup', 'Distribution', 'Command', 'Extension', 'Require', + 'setup', + 'Distribution', + 'Command', + 'Extension', + 'Require', 'SetuptoolsDeprecationWarning', - 'find_packages', 'find_namespace_packages', + 'find_packages', + 'find_namespace_packages', ] __version__ = setuptools.version.__version__ @@ -60,10 +65,13 @@ def find(cls, where='.', exclude=(), include=('*',)): shell style wildcard patterns just like 'exclude'. """ - return list(cls._find_packages_iter( - convert_path(where), - cls._build_filter('ez_setup', '*__pycache__', *exclude), - cls._build_filter(*include))) + return list( + cls._find_packages_iter( + convert_path(where), + cls._build_filter('ez_setup', '*__pycache__', *exclude), + cls._build_filter(*include), + ) + ) @classmethod def _find_packages_iter(cls, where, exclude, include): @@ -82,7 +90,7 @@ def _find_packages_iter(cls, where, exclude, include): package = rel_path.replace(os.path.sep, '.') # Skip directory trees that are not valid packages - if ('.' in dir or not cls._looks_like_package(full_path)): + if '.' in dir or not cls._looks_like_package(full_path): continue # Should this package be included? @@ -125,12 +133,10 @@ class MinimalDistribution(distutils.core.Distribution): A minimal version of a distribution for supporting the fetch_build_eggs interface. """ + def __init__(self, attrs): _incl = 'dependency_links', 'setup_requires' - filtered = { - k: attrs[k] - for k in set(_incl) & set(attrs) - } + filtered = {k: attrs[k] for k in set(_incl) & set(attrs)} distutils.core.Distribution.__init__(self, filtered) def finalize_options(self): @@ -178,8 +184,9 @@ def _ensure_stringlike(self, option, what, default=None): setattr(self, option, default) return default elif not isinstance(val, str): - raise DistutilsOptionError("'%s' must be a %s (got `%s`)" - % (option, what, val)) + raise DistutilsOptionError( + "'%s' must be a %s (got `%s`)" % (option, what, val) + ) return val def ensure_string_list(self, option): @@ -200,8 +207,8 @@ def ensure_string_list(self, option): ok = False if not ok: raise DistutilsOptionError( - "'%s' must be a list of strings (got %r)" - % (option, val)) + "'%s' must be a list of strings (got %r)" % (option, val) + ) def reinitialize_command(self, command, reinit_subcommands=0, **kw): cmd = _Command.reinitialize_command(self, command, reinit_subcommands) diff --git a/setuptools/_distutils/__init__.py b/setuptools/_distutils/__init__.py index 7dac55b601e..568680c0ef9 100644 --- a/setuptools/_distutils/__init__.py +++ b/setuptools/_distutils/__init__.py @@ -10,6 +10,6 @@ import sys -__version__ = sys.version[:sys.version.index(' ')] +__version__ = sys.version[: sys.version.index(' ')] local = True diff --git a/setuptools/_distutils/_msvccompiler.py b/setuptools/_distutils/_msvccompiler.py index b7a06082ae7..1466ed048b4 100644 --- a/setuptools/_distutils/_msvccompiler.py +++ b/setuptools/_distutils/_msvccompiler.py @@ -18,23 +18,30 @@ import contextlib import warnings import unittest.mock + with contextlib.suppress(ImportError): import winreg -from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ - CompileError, LibError, LinkError +from distutils.errors import ( + DistutilsExecError, + DistutilsPlatformError, + CompileError, + LibError, + LinkError, +) from distutils.ccompiler import CCompiler, gen_lib_options from distutils import log from distutils.util import get_platform from itertools import count + def _find_vc2015(): try: key = winreg.OpenKeyEx( winreg.HKEY_LOCAL_MACHINE, r"Software\Microsoft\VisualStudio\SxS\VC7", - access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY + access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY, ) except OSError: log.debug("Visual C++ is not registered") @@ -57,6 +64,7 @@ def _find_vc2015(): best_version, best_dir = version, vc_dir return best_version, best_dir + def _find_vc2017(): """Returns "15, path" based on the result of invoking vswhere.exe If no install is found, returns "None, None" @@ -72,14 +80,23 @@ def _find_vc2017(): return None, None try: - path = subprocess.check_output([ - os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), - "-latest", - "-prerelease", - "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", - "-property", "installationPath", - "-products", "*", - ], encoding="mbcs", errors="strict").strip() + path = subprocess.check_output( + [ + os.path.join( + root, "Microsoft Visual Studio", "Installer", "vswhere.exe" + ), + "-latest", + "-prerelease", + "-requires", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", + "installationPath", + "-products", + "*", + ], + encoding="mbcs", + errors="strict", + ).strip() except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): return None, None @@ -89,13 +106,15 @@ def _find_vc2017(): return None, None + PLAT_SPEC_TO_RUNTIME = { - 'x86' : 'x86', - 'x86_amd64' : 'x64', - 'x86_arm' : 'arm', - 'x86_arm64' : 'arm64' + 'x86': 'x86', + 'x86_amd64': 'x64', + 'x86_arm': 'arm', + 'x86_arm64': 'arm64', } + def _find_vcvarsall(plat_spec): # bpo-38597: Removed vcruntime return value _, best_dir = _find_vc2017() @@ -114,12 +133,10 @@ def _find_vcvarsall(plat_spec): return vcvarsall, None + def _get_vc_env(plat_spec): if os.getenv("DISTUTILS_USE_SDK"): - return { - key.lower(): value - for key, value in os.environ.items() - } + return {key.lower(): value for key, value in os.environ.items()} vcvarsall, _ = _find_vcvarsall(plat_spec) if not vcvarsall: @@ -132,18 +149,17 @@ def _get_vc_env(plat_spec): ).decode('utf-16le', errors='replace') except subprocess.CalledProcessError as exc: log.error(exc.output) - raise DistutilsPlatformError("Error executing {}" - .format(exc.cmd)) + raise DistutilsPlatformError("Error executing {}".format(exc.cmd)) env = { key.lower(): value - for key, _, value in - (line.partition('=') for line in out.splitlines()) + for key, _, value in (line.partition('=') for line in out.splitlines()) if key and value } return env + def _find_exe(exe, paths=None): """Return path to an MSVC executable program. @@ -161,19 +177,21 @@ def _find_exe(exe, paths=None): return fn return exe + # A map keyed by get_platform() return values to values accepted by # 'vcvarsall.bat'. Always cross-compile from x86 to work with the # lighter-weight MSVC installs that do not include native 64-bit tools. PLAT_TO_VCVARS = { - 'win32' : 'x86', - 'win-amd64' : 'x86_amd64', - 'win-arm32' : 'x86_arm', - 'win-arm64' : 'x86_arm64' + 'win32': 'x86', + 'win-amd64': 'x86_amd64', + 'win-arm32': 'x86_arm', + 'win-arm64': 'x86_arm64', } -class MSVCCompiler(CCompiler) : + +class MSVCCompiler(CCompiler): """Concrete class that implements an interface to Microsoft Visual C++, - as defined by the CCompiler abstract class.""" + as defined by the CCompiler abstract class.""" compiler_type = 'msvc' @@ -192,8 +210,7 @@ class MSVCCompiler(CCompiler) : # Needed for the filename generation methods provided by the # base class, CCompiler. - src_extensions = (_c_extensions + _cpp_extensions + - _rc_extensions + _mc_extensions) + src_extensions = _c_extensions + _cpp_extensions + _rc_extensions + _mc_extensions res_extension = '.res' obj_extension = '.obj' static_lib_extension = '.lib' @@ -201,9 +218,8 @@ class MSVCCompiler(CCompiler) : static_lib_format = shared_lib_format = '%s%s' exe_extension = '.exe' - def __init__(self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) + CCompiler.__init__(self, verbose, dry_run, force) # target platform (.plat_name is consistent with 'bdist') self.plat_name = None self.initialized = False @@ -215,25 +231,27 @@ def initialize(self, plat_name=None): plat_name = get_platform() # sanity check for platforms to prevent obscure errors later. if plat_name not in PLAT_TO_VCVARS: - raise DistutilsPlatformError("--plat-name must be one of {}" - .format(tuple(PLAT_TO_VCVARS))) + raise DistutilsPlatformError( + "--plat-name must be one of {}".format(tuple(PLAT_TO_VCVARS)) + ) # Get the vcvarsall.bat spec for the requested platform. plat_spec = PLAT_TO_VCVARS[plat_name] vc_env = _get_vc_env(plat_spec) if not vc_env: - raise DistutilsPlatformError("Unable to find a compatible " - "Visual Studio installation.") + raise DistutilsPlatformError( + "Unable to find a compatible " "Visual Studio installation." + ) self._paths = vc_env.get('path', '') paths = self._paths.split(os.pathsep) self.cc = _find_exe("cl.exe", paths) self.linker = _find_exe("link.exe", paths) self.lib = _find_exe("lib.exe", paths) - self.rc = _find_exe("rc.exe", paths) # resource compiler - self.mc = _find_exe("mc.exe", paths) # message compiler - self.mt = _find_exe("mt.exe", paths) # message compiler + self.rc = _find_exe("rc.exe", paths) # resource compiler + self.mc = _find_exe("mc.exe", paths) # message compiler + self.mt = _find_exe("mt.exe", paths) # message compiler for dir in vc_env.get('include', '').split(os.pathsep): if dir: @@ -247,26 +265,35 @@ def initialize(self, plat_name=None): # bpo-38597: Always compile with dynamic linking # Future releases of Python 3.x will include all past # versions of vcruntime*.dll for compatibility. - self.compile_options = [ - '/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD' - ] + self.compile_options = ['/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD'] self.compile_options_debug = [ - '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' + '/nologo', + '/Od', + '/MDd', + '/Zi', + '/W3', + '/D_DEBUG', ] - ldflags = [ - '/nologo', '/INCREMENTAL:NO', '/LTCG' - ] + ldflags = ['/nologo', '/INCREMENTAL:NO', '/LTCG'] - ldflags_debug = [ - '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL' - ] + ldflags_debug = ['/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'] self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1'] - self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] - self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO'] + self.ldflags_shared = [ + *ldflags, + '/DLL', + '/MANIFEST:EMBED,ID=2', + '/MANIFESTUAC:NO', + ] + self.ldflags_shared_debug = [ + *ldflags_debug, + '/DLL', + '/MANIFEST:EMBED,ID=2', + '/MANIFESTUAC:NO', + ] self.ldflags_static = [*ldflags] self.ldflags_static_debug = [*ldflags_debug] @@ -286,13 +313,13 @@ def initialize(self, plat_name=None): # -- Worker methods ------------------------------------------------ - def object_filenames(self, - source_filenames, - strip_dir=0, - output_dir=''): + def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): ext_map = { **{ext: self.obj_extension for ext in self.src_extensions}, - **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions}, + **{ + ext: self.res_extension + for ext in self._rc_extensions + self._mc_extensions + }, } output_dir = output_dir or '' @@ -318,15 +345,23 @@ def make_out_path(p): return list(map(make_out_path, source_filenames)) - - def compile(self, sources, - output_dir=None, macros=None, include_dirs=None, debug=0, - extra_preargs=None, extra_postargs=None, depends=None): + def compile( + self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None, + ): if not self.initialized: self.initialize() - compile_info = self._setup_compile(output_dir, macros, include_dirs, - sources, depends, extra_postargs) + compile_info = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs + ) macros, objects, extra_postargs, pp_opts, build = compile_info compile_opts = extra_preargs or [] @@ -336,7 +371,6 @@ def compile(self, sources, else: compile_opts.extend(self.compile_options) - add_cpp_opts = False for obj in objects: @@ -381,7 +415,7 @@ def compile(self, sources, try: # first compile .MC to .RC and .H file self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src]) - base, _ = os.path.splitext(os.path.basename (src)) + base, _ = os.path.splitext(os.path.basename(src)) rc_file = os.path.join(rc_dir, base + '.rc') # then compile .RC to .RES file self.spawn([self.rc, "/fo" + obj, rc_file]) @@ -391,8 +425,9 @@ def compile(self, sources, continue else: # how to handle this file? - raise CompileError("Don't know how to compile {} to {}" - .format(src, obj)) + raise CompileError( + "Don't know how to compile {} to {}".format(src, obj) + ) args = [self.cc] + compile_opts + pp_opts if add_cpp_opts: @@ -408,24 +443,19 @@ def compile(self, sources, return objects - - def create_static_lib(self, - objects, - output_libname, - output_dir=None, - debug=0, - target_lang=None): + def create_static_lib( + self, objects, output_libname, output_dir=None, debug=0, target_lang=None + ): if not self.initialized: self.initialize() objects, output_dir = self._fix_object_args(objects, output_dir) - output_filename = self.library_filename(output_libname, - output_dir=output_dir) + output_filename = self.library_filename(output_libname, output_dir=output_dir) if self._need_link(objects, output_filename): lib_args = objects + ['/OUT:' + output_filename] if debug: - pass # XXX what goes here? + pass # XXX what goes here? try: log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args)) self.spawn([self.lib] + lib_args) @@ -434,36 +464,36 @@ def create_static_lib(self, else: log.debug("skipping %s (up-to-date)", output_filename) - - def link(self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): if not self.initialized: self.initialize() objects, output_dir = self._fix_object_args(objects, output_dir) - fixed_args = self._fix_lib_args(libraries, library_dirs, - runtime_library_dirs) + fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) libraries, library_dirs, runtime_library_dirs = fixed_args if runtime_library_dirs: - self.warn("I don't know what to do with 'runtime_library_dirs': " - + str(runtime_library_dirs)) + self.warn( + "I don't know what to do with 'runtime_library_dirs': " + + str(runtime_library_dirs) + ) - lib_opts = gen_lib_options(self, - library_dirs, runtime_library_dirs, - libraries) + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries) if output_dir is not None: output_filename = os.path.join(output_dir, output_filename) @@ -472,8 +502,9 @@ def link(self, export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])] - ld_args = (ldflags + lib_opts + export_opts + - objects + ['/OUT:' + output_filename]) + ld_args = ( + ldflags + lib_opts + export_opts + objects + ['/OUT:' + output_filename] + ) # The MSVC linker generates .lib and .exp files, which cannot be # suppressed by any linker switches. The .lib files may even be @@ -483,11 +514,10 @@ def link(self, build_temp = os.path.dirname(objects[0]) if export_symbols is not None: (dll_name, dll_ext) = os.path.splitext( - os.path.basename(output_filename)) - implib_file = os.path.join( - build_temp, - self.library_filename(dll_name)) - ld_args.append ('/IMPLIB:' + implib_file) + os.path.basename(output_filename) + ) + implib_file = os.path.join(build_temp, self.library_filename(dll_name)) + ld_args.append('/IMPLIB:' + implib_file) if extra_preargs: ld_args[:0] = extra_preargs @@ -525,8 +555,7 @@ def _fallback_spawn(self, cmd, env): raise else: return - warnings.warn( - "Fallback spawn triggered. Please update distutils monkeypatch.") + warnings.warn("Fallback spawn triggered. Please update distutils monkeypatch.") with unittest.mock.patch('os.environ', env): bag.value = super().spawn(cmd) @@ -539,7 +568,8 @@ def library_dir_option(self, dir): def runtime_library_dir_option(self, dir): raise DistutilsPlatformError( - "don't know how to set runtime library search path for MSVC") + "don't know how to set runtime library search path for MSVC" + ) def library_option(self, lib): return self.library_filename(lib) diff --git a/setuptools/_distutils/archive_util.py b/setuptools/_distutils/archive_util.py index 565a3117b4b..5a70c32c2f8 100644 --- a/setuptools/_distutils/archive_util.py +++ b/setuptools/_distutils/archive_util.py @@ -28,6 +28,7 @@ except ImportError: getgrnam = None + def _get_gid(name): """Returns a gid, given a group name.""" if getgrnam is None or name is None: @@ -40,6 +41,7 @@ def _get_gid(name): return result[2] return None + def _get_uid(name): """Returns an uid, given a user name.""" if getpwnam is None or name is None: @@ -52,8 +54,10 @@ def _get_uid(name): return result[2] return None -def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, - owner=None, group=None): + +def make_tarball( + base_name, base_dir, compress="gzip", verbose=0, dry_run=0, owner=None, group=None +): """Create a (possibly compressed) tar file from all the files under 'base_dir'. @@ -69,16 +73,21 @@ def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, Returns the output filename. """ - tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '', - 'compress': ''} - compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz', - 'compress': '.Z'} + tar_compression = { + 'gzip': 'gz', + 'bzip2': 'bz2', + 'xz': 'xz', + None: '', + 'compress': '', + } + compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz', 'compress': '.Z'} # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext.keys(): raise ValueError( - "bad value for 'compress': must be None, 'gzip', 'bzip2', " - "'xz' or 'compress'") + "bad value for 'compress': must be None, 'gzip', 'bzip2', " + "'xz' or 'compress'" + ) archive_name = base_name + '.tar' if compress != 'compress': @@ -124,6 +133,7 @@ def _set_uid_gid(tarinfo): return archive_name + def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): """Create a zip file from all the files under 'base_dir'. @@ -145,26 +155,29 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): zipoptions = "-rq" try: - spawn(["zip", zipoptions, zip_filename, base_dir], - dry_run=dry_run) + spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) except DistutilsExecError: # XXX really should distinguish between "couldn't find # external 'zip' command" and "zip failed". - raise DistutilsExecError(("unable to create zip file '%s': " - "could neither import the 'zipfile' module nor " - "find a standalone zip utility") % zip_filename) + raise DistutilsExecError( + ( + "unable to create zip file '%s': " + "could neither import the 'zipfile' module nor " + "find a standalone zip utility" + ) + % zip_filename + ) else: - log.info("creating '%s' and adding '%s' to it", - zip_filename, base_dir) + log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir) if not dry_run: try: - zip = zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_DEFLATED) + zip = zipfile.ZipFile( + zip_filename, "w", compression=zipfile.ZIP_DEFLATED + ) except RuntimeError: - zip = zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_STORED) + zip = zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_STORED) with zip: if base_dir != os.curdir: @@ -184,14 +197,16 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): return zip_filename + ARCHIVE_FORMATS = { 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), 'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"), - 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"), - 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (make_zipfile, [],"ZIP file") - } + 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"), + 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"), + 'zip': (make_zipfile, [], "ZIP file"), +} + def check_archive_formats(formats): """Returns the first format from the 'format' list that is unknown. @@ -203,8 +218,17 @@ def check_archive_formats(formats): return format return None -def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, - dry_run=0, owner=None, group=None): + +def make_archive( + base_name, + format, + root_dir=None, + base_dir=None, + verbose=0, + dry_run=0, + owner=None, + group=None, +): """Create an archive file (eg. zip or tar). 'base_name' is the name of the file to create, minus any format-specific diff --git a/setuptools/_distutils/bcppcompiler.py b/setuptools/_distutils/bcppcompiler.py index 071fea5d038..a44fc2d63b0 100644 --- a/setuptools/_distutils/bcppcompiler.py +++ b/setuptools/_distutils/bcppcompiler.py @@ -13,16 +13,20 @@ import os -from distutils.errors import \ - DistutilsExecError, \ - CompileError, LibError, LinkError, UnknownFileError -from distutils.ccompiler import \ - CCompiler, gen_preprocess_options +from distutils.errors import ( + DistutilsExecError, + CompileError, + LibError, + LinkError, + UnknownFileError, +) +from distutils.ccompiler import CCompiler, gen_preprocess_options from distutils.file_util import write_file from distutils.dep_util import newer from distutils import log -class BCPPCompiler(CCompiler) : + +class BCPPCompiler(CCompiler): """Concrete class that implements an interface to the Borland C/C++ compiler, as defined by the CCompiler abstract class. """ @@ -49,13 +53,9 @@ class BCPPCompiler(CCompiler) : static_lib_format = shared_lib_format = '%s%s' exe_extension = '.exe' + def __init__(self, verbose=0, dry_run=0, force=0): - def __init__ (self, - verbose=0, - dry_run=0, - force=0): - - CCompiler.__init__ (self, verbose, dry_run, force) + CCompiler.__init__(self, verbose, dry_run, force) # These executables are assumed to all be in the path. # Borland doesn't seem to use any special registry settings to @@ -73,24 +73,31 @@ def __init__ (self, self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x'] self.ldflags_static = [] self.ldflags_exe = ['/Gn', '/q', '/x'] - self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r'] - + self.ldflags_exe_debug = ['/Gn', '/q', '/x', '/r'] # -- Worker methods ------------------------------------------------ - def compile(self, sources, - output_dir=None, macros=None, include_dirs=None, debug=0, - extra_preargs=None, extra_postargs=None, depends=None): - - macros, objects, extra_postargs, pp_opts, build = \ - self._setup_compile(output_dir, macros, include_dirs, sources, - depends, extra_postargs) + def compile( + self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None, + ): + + macros, objects, extra_postargs, pp_opts, build = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs + ) compile_opts = extra_preargs or [] - compile_opts.append ('-c') + compile_opts.append('-c') if debug: - compile_opts.extend (self.compile_options_debug) + compile_opts.extend(self.compile_options_debug) else: - compile_opts.extend (self.compile_options) + compile_opts.extend(self.compile_options) for obj in objects: try: @@ -106,14 +113,14 @@ def compile(self, sources, if ext == '.res': # This is already a binary file -- skip it. - continue # the 'for' loop + continue # the 'for' loop if ext == '.rc': # This needs to be compiled to a .res file -- do it now. try: - self.spawn (["brcc32", "-fo", obj, src]) + self.spawn(["brcc32", "-fo", obj, src]) except DistutilsExecError as msg: raise CompileError(msg) - continue # the 'for' loop + continue # the 'for' loop # The next two are both for the real compiler. if ext in self._c_extensions: @@ -132,9 +139,14 @@ def compile(self, sources, # Note that the source file names must appear at the end of # the command line. try: - self.spawn ([self.cc] + compile_opts + pp_opts + - [input_opt, output_opt] + - extra_postargs + [src]) + self.spawn( + [self.cc] + + compile_opts + + pp_opts + + [input_opt, output_opt] + + extra_postargs + + [src] + ) except DistutilsExecError as msg: raise CompileError(msg) @@ -142,24 +154,19 @@ def compile(self, sources, # compile () + def create_static_lib( + self, objects, output_libname, output_dir=None, debug=0, target_lang=None + ): - def create_static_lib (self, - objects, - output_libname, - output_dir=None, - debug=0, - target_lang=None): - - (objects, output_dir) = self._fix_object_args (objects, output_dir) - output_filename = \ - self.library_filename (output_libname, output_dir=output_dir) + (objects, output_dir) = self._fix_object_args(objects, output_dir) + output_filename = self.library_filename(output_libname, output_dir=output_dir) - if self._need_link (objects, output_filename): + if self._need_link(objects, output_filename): lib_args = [output_filename, '/u'] + objects if debug: - pass # XXX what goes here? + pass # XXX what goes here? try: - self.spawn ([self.lib] + lib_args) + self.spawn([self.lib] + lib_args) except DistutilsExecError as msg: raise LibError(msg) else: @@ -167,37 +174,41 @@ def create_static_lib (self, # create_static_lib () - - def link (self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): # XXX this ignores 'build_temp'! should follow the lead of # msvccompiler.py - (objects, output_dir) = self._fix_object_args (objects, output_dir) - (libraries, library_dirs, runtime_library_dirs) = \ - self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) + (objects, output_dir) = self._fix_object_args(objects, output_dir) + (libraries, library_dirs, runtime_library_dirs) = self._fix_lib_args( + libraries, library_dirs, runtime_library_dirs + ) if runtime_library_dirs: - log.warn("I don't know what to do with 'runtime_library_dirs': %s", - str(runtime_library_dirs)) + log.warn( + "I don't know what to do with 'runtime_library_dirs': %s", + str(runtime_library_dirs), + ) if output_dir is not None: - output_filename = os.path.join (output_dir, output_filename) + output_filename = os.path.join(output_dir, output_filename) - if self._need_link (objects, output_filename): + if self._need_link(objects, output_filename): # Figure out linker args based on type of target. if target_desc == CCompiler.EXECUTABLE: @@ -213,20 +224,18 @@ def link (self, else: ld_args = self.ldflags_shared[:] - # Create a temporary exports file for use by the linker if export_symbols is None: def_file = '' else: - head, tail = os.path.split (output_filename) - modname, ext = os.path.splitext (tail) - temp_dir = os.path.dirname(objects[0]) # preserve tree structure - def_file = os.path.join (temp_dir, '%s.def' % modname) + head, tail = os.path.split(output_filename) + modname, ext = os.path.splitext(tail) + temp_dir = os.path.dirname(objects[0]) # preserve tree structure + def_file = os.path.join(temp_dir, '%s.def' % modname) contents = ['EXPORTS'] - for sym in (export_symbols or []): + for sym in export_symbols or []: contents.append(' %s=_%s' % (sym, sym)) - self.execute(write_file, (def_file, contents), - "writing %s" % def_file) + self.execute(write_file, (def_file, contents), "writing %s" % def_file) # Borland C++ has problems with '/' in paths objects2 = map(os.path.normpath, objects) @@ -241,10 +250,9 @@ def link (self, else: objects.append(file) - for l in library_dirs: ld_args.append("/L%s" % os.path.normpath(l)) - ld_args.append("/L.") # we sometimes use relative paths + ld_args.append("/L.") # we sometimes use relative paths # list of object files ld_args.extend(objects) @@ -260,7 +268,7 @@ def link (self, # them. Arghghh!. Apparently it works fine as coded... # name of dll/exe file - ld_args.extend([',',output_filename]) + ld_args.extend([',', output_filename]) # no map file and start libraries ld_args.append(',,') @@ -276,24 +284,23 @@ def link (self, ld_args.append(libfile) # some default libraries - ld_args.append ('import32') - ld_args.append ('cw32mt') + ld_args.append('import32') + ld_args.append('cw32mt') # def file for export symbols - ld_args.extend([',',def_file]) + ld_args.extend([',', def_file]) # add resource files ld_args.append(',') ld_args.extend(resources) - if extra_preargs: ld_args[:0] = extra_preargs if extra_postargs: ld_args.extend(extra_postargs) - self.mkpath (os.path.dirname (output_filename)) + self.mkpath(os.path.dirname(output_filename)) try: - self.spawn ([self.linker] + ld_args) + self.spawn([self.linker] + ld_args) except DistutilsExecError as msg: raise LinkError(msg) @@ -304,8 +311,7 @@ def link (self, # -- Miscellaneous methods ----------------------------------------- - - def find_library_file (self, dirs, lib, debug=0): + def find_library_file(self, dirs, lib, debug=0): # List of effective library names to try, in order of preference: # xxx_bcpp.lib is better than xxx.lib # and xxx_d.lib is better than xxx.lib if debug is set @@ -316,7 +322,7 @@ def find_library_file (self, dirs, lib, debug=0): # compiler they care about, since (almost?) every Windows compiler # seems to have a different format for static libraries. if debug: - dlib = (lib + "_d") + dlib = lib + "_d" try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib) else: try_names = (lib + "_bcpp", lib) @@ -331,43 +337,42 @@ def find_library_file (self, dirs, lib, debug=0): return None # overwrite the one from CCompiler to support rc and res-files - def object_filenames (self, - source_filenames, - strip_dir=0, - output_dir=''): - if output_dir is None: output_dir = '' + def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): + if output_dir is None: + output_dir = '' obj_names = [] for src_name in source_filenames: # use normcase to make sure '.rc' is really '.rc' and not '.RC' - (base, ext) = os.path.splitext (os.path.normcase(src_name)) - if ext not in (self.src_extensions + ['.rc','.res']): - raise UnknownFileError("unknown file type '%s' (from '%s')" % \ - (ext, src_name)) + (base, ext) = os.path.splitext(os.path.normcase(src_name)) + if ext not in (self.src_extensions + ['.rc', '.res']): + raise UnknownFileError( + "unknown file type '%s' (from '%s')" % (ext, src_name) + ) if strip_dir: - base = os.path.basename (base) + base = os.path.basename(base) if ext == '.res': # these can go unchanged - obj_names.append (os.path.join (output_dir, base + ext)) + obj_names.append(os.path.join(output_dir, base + ext)) elif ext == '.rc': # these need to be compiled to .res-files - obj_names.append (os.path.join (output_dir, base + '.res')) + obj_names.append(os.path.join(output_dir, base + '.res')) else: - obj_names.append (os.path.join (output_dir, - base + self.obj_extension)) + obj_names.append(os.path.join(output_dir, base + self.obj_extension)) return obj_names # object_filenames () - def preprocess (self, - source, - output_file=None, - macros=None, - include_dirs=None, - extra_preargs=None, - extra_postargs=None): - - (_, macros, include_dirs) = \ - self._fix_compile_args(None, macros, include_dirs) + def preprocess( + self, + source, + output_file=None, + macros=None, + include_dirs=None, + extra_preargs=None, + extra_postargs=None, + ): + + (_, macros, include_dirs) = self._fix_compile_args(None, macros, include_dirs) pp_opts = gen_preprocess_options(macros, include_dirs) pp_args = ['cpp32.exe'] + pp_opts if output_file is not None: diff --git a/setuptools/_distutils/ccompiler.py b/setuptools/_distutils/ccompiler.py index 48d160d27a5..f3a215397a1 100644 --- a/setuptools/_distutils/ccompiler.py +++ b/setuptools/_distutils/ccompiler.py @@ -12,6 +12,7 @@ from distutils.util import split_quoted, execute from distutils import log + class CCompiler: """Abstract base class to define the interface that must be implemented by real compiler classes. Also has some utility methods used by @@ -56,17 +57,16 @@ class CCompiler: # think this is useless without the ability to null out the # library search path anyways. - # Subclasses that rely on the standard filename generation methods # implemented below should override these; see the comment near # those methods ('object_filenames()' et. al.) for details: - src_extensions = None # list of strings - obj_extension = None # string + src_extensions = None # list of strings + obj_extension = None # string static_lib_extension = None - shared_lib_extension = None # string - static_lib_format = None # format string - shared_lib_format = None # prob. same as static_lib_format - exe_extension = None # string + shared_lib_extension = None # string + static_lib_format = None # format string + shared_lib_format = None # prob. same as static_lib_format + exe_extension = None # string # Default language settings. language_map is used to detect a source # file or Extension target language, checking source filenames. @@ -74,12 +74,13 @@ class CCompiler: # what language to use when mixing source types. For example, if some # extension has two files with ".c" extension, and one with ".cpp", it # is still linked as c++. - language_map = {".c" : "c", - ".cc" : "c++", - ".cpp" : "c++", - ".cxx" : "c++", - ".m" : "objc", - } + language_map = { + ".c": "c", + ".cc": "c++", + ".cpp": "c++", + ".cxx": "c++", + ".m": "objc", + } language_order = ["c++", "objc", "c"] def __init__(self, verbose=0, dry_run=0, force=0): @@ -146,8 +147,10 @@ class (via the 'executables' class attribute), but most will have: for key in kwargs: if key not in self.executables: - raise ValueError("unknown executable '%s' for class %s" % - (key, self.__class__.__name__)) + raise ValueError( + "unknown executable '%s' for class %s" + % (key, self.__class__.__name__) + ) self.set_executable(key, kwargs[key]) def set_executable(self, key, value): @@ -170,14 +173,19 @@ def _check_macro_definitions(self, definitions): nothing if all definitions are OK, raise TypeError otherwise. """ for defn in definitions: - if not (isinstance(defn, tuple) and - (len(defn) in (1, 2) and - (isinstance (defn[1], str) or defn[1] is None)) and - isinstance (defn[0], str)): - raise TypeError(("invalid macro definition '%s': " % defn) + \ - "must be tuple (string,), (string, string), or " + \ - "(string, None)") - + if not ( + isinstance(defn, tuple) + and ( + len(defn) in (1, 2) + and (isinstance(defn[1], str) or defn[1] is None) + ) + and isinstance(defn[0], str) + ): + raise TypeError( + ("invalid macro definition '%s': " % defn) + + "must be tuple (string,), (string, string), or " + + "(string, None)" + ) # -- Bookkeeping methods ------------------------------------------- @@ -190,7 +198,7 @@ def define_macro(self, name, value=None): """ # Delete from the list of macro definitions/undefinitions if # already there (so that this one will take precedence). - i = self._find_macro (name) + i = self._find_macro(name) if i is not None: del self.macros[i] @@ -207,7 +215,7 @@ def undefine_macro(self, name): """ # Delete from the list of macro definitions/undefinitions if # already there (so that this one will take precedence). - i = self._find_macro (name) + i = self._find_macro(name) if i is not None: del self.macros[i] @@ -301,14 +309,12 @@ def set_link_objects(self, objects): """ self.objects = objects[:] - # -- Private utility methods -------------------------------------- # (here for the convenience of subclasses) # Helper method to prep compiler in subclass compile() methods - def _setup_compile(self, outdir, macros, incdirs, sources, depends, - extra): + def _setup_compile(self, outdir, macros, incdirs, sources, depends, extra): """Process arguments and decide which source files to compile.""" if outdir is None: outdir = self.output_dir @@ -327,15 +333,13 @@ def _setup_compile(self, outdir, macros, incdirs, sources, depends, elif isinstance(incdirs, (list, tuple)): incdirs = list(incdirs) + (self.include_dirs or []) else: - raise TypeError( - "'include_dirs' (if supplied) must be a list of strings") + raise TypeError("'include_dirs' (if supplied) must be a list of strings") if extra is None: extra = [] # Get the list of expected output (object) files - objects = self.object_filenames(sources, strip_dir=0, - output_dir=outdir) + objects = self.object_filenames(sources, strip_dir=0, output_dir=outdir) assert len(objects) == len(sources) pp_opts = gen_preprocess_options(macros, incdirs) @@ -386,8 +390,7 @@ def _fix_compile_args(self, output_dir, macros, include_dirs): elif isinstance(include_dirs, (list, tuple)): include_dirs = list(include_dirs) + (self.include_dirs or []) else: - raise TypeError( - "'include_dirs' (if supplied) must be a list of strings") + raise TypeError("'include_dirs' (if supplied) must be a list of strings") return output_dir, macros, include_dirs @@ -434,27 +437,27 @@ def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): if libraries is None: libraries = self.libraries elif isinstance(libraries, (list, tuple)): - libraries = list (libraries) + (self.libraries or []) + libraries = list(libraries) + (self.libraries or []) else: - raise TypeError( - "'libraries' (if supplied) must be a list of strings") + raise TypeError("'libraries' (if supplied) must be a list of strings") if library_dirs is None: library_dirs = self.library_dirs elif isinstance(library_dirs, (list, tuple)): - library_dirs = list (library_dirs) + (self.library_dirs or []) + library_dirs = list(library_dirs) + (self.library_dirs or []) else: - raise TypeError( - "'library_dirs' (if supplied) must be a list of strings") + raise TypeError("'library_dirs' (if supplied) must be a list of strings") if runtime_library_dirs is None: runtime_library_dirs = self.runtime_library_dirs elif isinstance(runtime_library_dirs, (list, tuple)): - runtime_library_dirs = (list(runtime_library_dirs) + - (self.runtime_library_dirs or [])) + runtime_library_dirs = list(runtime_library_dirs) + ( + self.runtime_library_dirs or [] + ) else: - raise TypeError("'runtime_library_dirs' (if supplied) " - "must be a list of strings") + raise TypeError( + "'runtime_library_dirs' (if supplied) " "must be a list of strings" + ) return (libraries, library_dirs, runtime_library_dirs) @@ -466,9 +469,9 @@ def _need_link(self, objects, output_file): return True else: if self.dry_run: - newer = newer_group (objects, output_file, missing='newer') + newer = newer_group(objects, output_file, missing='newer') else: - newer = newer_group (objects, output_file) + newer = newer_group(objects, output_file) return newer def detect_language(self, sources): @@ -491,12 +494,18 @@ def detect_language(self, sources): pass return lang - # -- Worker methods ------------------------------------------------ # (must be implemented by subclasses) - def preprocess(self, source, output_file=None, macros=None, - include_dirs=None, extra_preargs=None, extra_postargs=None): + def preprocess( + self, + source, + output_file=None, + macros=None, + include_dirs=None, + extra_preargs=None, + extra_postargs=None, + ): """Preprocess a single C/C++ source file, named in 'source'. Output will be written to file named 'output_file', or stdout if 'output_file' not supplied. 'macros' is a list of macro @@ -508,9 +517,17 @@ def preprocess(self, source, output_file=None, macros=None, """ pass - def compile(self, sources, output_dir=None, macros=None, - include_dirs=None, debug=0, extra_preargs=None, - extra_postargs=None, depends=None): + def compile( + self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None, + ): """Compile one or more source files. 'sources' must be a list of filenames, most likely C/C++ @@ -561,9 +578,9 @@ def compile(self, sources, output_dir=None, macros=None, """ # A concrete compiler class can either override this method # entirely or implement _compile(). - macros, objects, extra_postargs, pp_opts, build = \ - self._setup_compile(output_dir, macros, include_dirs, sources, - depends, extra_postargs) + macros, objects, extra_postargs, pp_opts, build = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs + ) cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) for obj in objects: @@ -582,8 +599,9 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): # should implement _compile(). pass - def create_static_lib(self, objects, output_libname, output_dir=None, - debug=0, target_lang=None): + def create_static_lib( + self, objects, output_libname, output_dir=None, debug=0, target_lang=None + ): """Link a bunch of stuff together to create a static library file. The "bunch of stuff" consists of the list of object files supplied as 'objects', the extra object files supplied to @@ -608,26 +626,27 @@ def create_static_lib(self, objects, output_libname, output_dir=None, """ pass - # values for target_desc parameter in link() SHARED_OBJECT = "shared_object" SHARED_LIBRARY = "shared_library" EXECUTABLE = "executable" - def link(self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): """Link a bunch of stuff together to create an executable or shared library file. @@ -673,66 +692,98 @@ def link(self, """ raise NotImplementedError - # Old 'link_*()' methods, rewritten to use the new 'link()' method. - def link_shared_lib(self, - objects, - output_libname, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): - self.link(CCompiler.SHARED_LIBRARY, objects, - self.library_filename(output_libname, lib_type='shared'), - output_dir, - libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, - extra_preargs, extra_postargs, build_temp, target_lang) - - - def link_shared_object(self, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): - self.link(CCompiler.SHARED_OBJECT, objects, - output_filename, output_dir, - libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, - extra_preargs, extra_postargs, build_temp, target_lang) - - - def link_executable(self, - objects, - output_progname, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - target_lang=None): - self.link(CCompiler.EXECUTABLE, objects, - self.executable_filename(output_progname), output_dir, - libraries, library_dirs, runtime_library_dirs, None, - debug, extra_preargs, extra_postargs, None, target_lang) - + def link_shared_lib( + self, + objects, + output_libname, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): + self.link( + CCompiler.SHARED_LIBRARY, + objects, + self.library_filename(output_libname, lib_type='shared'), + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + export_symbols, + debug, + extra_preargs, + extra_postargs, + build_temp, + target_lang, + ) + + def link_shared_object( + self, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): + self.link( + CCompiler.SHARED_OBJECT, + objects, + output_filename, + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + export_symbols, + debug, + extra_preargs, + extra_postargs, + build_temp, + target_lang, + ) + + def link_executable( + self, + objects, + output_progname, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + target_lang=None, + ): + self.link( + CCompiler.EXECUTABLE, + objects, + self.executable_filename(output_progname), + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + None, + debug, + extra_preargs, + extra_postargs, + None, + target_lang, + ) # -- Miscellaneous methods ----------------------------------------- # These are all used by the 'gen_lib_options() function; there is @@ -757,8 +808,14 @@ def library_option(self, lib): """ raise NotImplementedError - def has_function(self, funcname, includes=None, include_dirs=None, - libraries=None, library_dirs=None): + def has_function( + self, + funcname, + includes=None, + include_dirs=None, + libraries=None, + library_dirs=None, + ): """Return a boolean indicating whether funcname is supported on the current platform. The optional arguments can be used to augment the compilation environment. @@ -767,6 +824,7 @@ def has_function(self, funcname, includes=None, include_dirs=None, # import math which might not be available at that point - maybe # the necessary logic should just be inlined? import tempfile + if includes is None: includes = [] if include_dirs is None: @@ -780,12 +838,15 @@ def has_function(self, funcname, includes=None, include_dirs=None, try: for incl in includes: f.write("""#include "%s"\n""" % incl) - f.write("""\ + f.write( + """\ int main (int argc, char **argv) { %s(); return 0; } -""" % funcname) +""" + % funcname + ) finally: f.close() try: @@ -796,9 +857,9 @@ def has_function(self, funcname, includes=None, include_dirs=None, os.remove(fname) try: - self.link_executable(objects, "a.out", - libraries=libraries, - library_dirs=library_dirs) + self.link_executable( + objects, "a.out", libraries=libraries, library_dirs=library_dirs + ) except (LinkError, TypeError): return False else: @@ -808,7 +869,7 @@ def has_function(self, funcname, includes=None, include_dirs=None, os.remove(fn) return True - def find_library_file (self, dirs, lib, debug=0): + def find_library_file(self, dirs, lib, debug=0): """Search the specified list of directories for a static or shared library file 'lib' and return the full path to that file. If 'debug' true, look for a debugging version (if that makes sense on @@ -857,15 +918,15 @@ def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): obj_names = [] for src_name in source_filenames: base, ext = os.path.splitext(src_name) - base = os.path.splitdrive(base)[1] # Chop off the drive - base = base[os.path.isabs(base):] # If abs, chop off leading / + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base) :] # If abs, chop off leading / if ext not in self.src_extensions: raise UnknownFileError( - "unknown file type '%s' (from '%s')" % (ext, src_name)) + "unknown file type '%s' (from '%s')" % (ext, src_name) + ) if strip_dir: base = os.path.basename(base) - obj_names.append(os.path.join(output_dir, - base + self.obj_extension)) + obj_names.append(os.path.join(output_dir, base + self.obj_extension)) return obj_names def shared_object_filename(self, basename, strip_dir=0, output_dir=''): @@ -880,12 +941,14 @@ def executable_filename(self, basename, strip_dir=0, output_dir=''): basename = os.path.basename(basename) return os.path.join(output_dir, basename + (self.exe_extension or '')) - def library_filename(self, libname, lib_type='static', # or 'shared' - strip_dir=0, output_dir=''): + def library_filename( + self, libname, lib_type='static', strip_dir=0, output_dir='' # or 'shared' + ): assert output_dir is not None if lib_type not in ("static", "shared", "dylib", "xcode_stub"): raise ValueError( - "'lib_type' must be \"static\", \"shared\", \"dylib\", or \"xcode_stub\"") + "'lib_type' must be \"static\", \"shared\", \"dylib\", or \"xcode_stub\"" + ) fmt = getattr(self, lib_type + "_lib_format") ext = getattr(self, lib_type + "_lib_extension") @@ -896,7 +959,6 @@ def library_filename(self, libname, lib_type='static', # or 'shared' return os.path.join(output_dir, dir, filename) - # -- Utility methods ----------------------------------------------- def announce(self, msg, level=1): @@ -904,6 +966,7 @@ def announce(self, msg, level=1): def debug_print(self, msg): from distutils.debug import DEBUG + if DEBUG: print(msg) @@ -919,7 +982,7 @@ def spawn(self, cmd, **kwargs): def move_file(self, src, dst): return move_file(src, dst, dry_run=self.dry_run) - def mkpath (self, name, mode=0o777): + def mkpath(self, name, mode=0o777): mkpath(name, mode, dry_run=self.dry_run) @@ -928,54 +991,59 @@ def mkpath (self, name, mode=0o777): # patterns. Order is important; platform mappings are preferred over # OS names. _default_compilers = ( - # Platform string mappings - # on a cygwin built python we can use gcc like an ordinary UNIXish # compiler ('cygwin.*', 'unix'), - # OS name mappings ('posix', 'unix'), ('nt', 'msvc'), +) - ) def get_default_compiler(osname=None, platform=None): """Determine the default compiler to use for the given platform. - osname should be one of the standard Python OS names (i.e. the - ones returned by os.name) and platform the common value - returned by sys.platform for the platform in question. + osname should be one of the standard Python OS names (i.e. the + ones returned by os.name) and platform the common value + returned by sys.platform for the platform in question. - The default values are os.name and sys.platform in case the - parameters are not given. + The default values are os.name and sys.platform in case the + parameters are not given. """ if osname is None: osname = os.name if platform is None: platform = sys.platform for pattern, compiler in _default_compilers: - if re.match(pattern, platform) is not None or \ - re.match(pattern, osname) is not None: + if ( + re.match(pattern, platform) is not None + or re.match(pattern, osname) is not None + ): return compiler # Default to Unix compiler return 'unix' + # Map compiler types to (module_name, class_name) pairs -- ie. where to # find the code that implements an interface to this compiler. (The module # is assumed to be in the 'distutils' package.) -compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler', - "standard UNIX-style compiler"), - 'msvc': ('_msvccompiler', 'MSVCCompiler', - "Microsoft Visual C++"), - 'cygwin': ('cygwinccompiler', 'CygwinCCompiler', - "Cygwin port of GNU C Compiler for Win32"), - 'mingw32': ('cygwinccompiler', 'Mingw32CCompiler', - "Mingw32 port of GNU C Compiler for Win32"), - 'bcpp': ('bcppcompiler', 'BCPPCompiler', - "Borland C++ Compiler"), - } +compiler_class = { + 'unix': ('unixccompiler', 'UnixCCompiler', "standard UNIX-style compiler"), + 'msvc': ('_msvccompiler', 'MSVCCompiler', "Microsoft Visual C++"), + 'cygwin': ( + 'cygwinccompiler', + 'CygwinCCompiler', + "Cygwin port of GNU C Compiler for Win32", + ), + 'mingw32': ( + 'cygwinccompiler', + 'Mingw32CCompiler', + "Mingw32 port of GNU C Compiler for Win32", + ), + 'bcpp': ('bcppcompiler', 'BCPPCompiler', "Borland C++ Compiler"), +} + def show_compilers(): """Print list of available compilers (used by the "--help-compiler" @@ -985,10 +1053,10 @@ def show_compilers(): # "--compiler", which just happens to be the case for the three # commands that use it. from distutils.fancy_getopt import FancyGetopt + compilers = [] for compiler in compiler_class.keys(): - compilers.append(("compiler="+compiler, None, - compiler_class[compiler][2])) + compilers.append(("compiler=" + compiler, None, compiler_class[compiler][2])) compilers.sort() pretty_printer = FancyGetopt(compilers) pretty_printer.print_help("List of available compilers:") @@ -1021,17 +1089,18 @@ def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0): try: module_name = "distutils." + module_name - __import__ (module_name) + __import__(module_name) module = sys.modules[module_name] klass = vars(module)[class_name] except ImportError: raise DistutilsModuleError( - "can't compile C/C++ code: unable to load module '%s'" % \ - module_name) + "can't compile C/C++ code: unable to load module '%s'" % module_name + ) except KeyError: raise DistutilsModuleError( - "can't compile C/C++ code: unable to find class '%s' " - "in module '%s'" % (class_name, module_name)) + "can't compile C/C++ code: unable to find class '%s' " + "in module '%s'" % (class_name, module_name) + ) # XXX The None is necessary to preserve backwards compatibility # with classes that expect verbose to be the first positional @@ -1064,14 +1133,14 @@ def gen_preprocess_options(macros, include_dirs): for macro in macros: if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2): raise TypeError( - "bad macro definition '%s': " - "each element of 'macros' list must be a 1- or 2-tuple" - % macro) + "bad macro definition '%s': " + "each element of 'macros' list must be a 1- or 2-tuple" % macro + ) - if len(macro) == 1: # undefine this macro + if len(macro) == 1: # undefine this macro pp_opts.append("-U%s" % macro[0]) elif len(macro) == 2: - if macro[1] is None: # define with no explicit value + if macro[1] is None: # define with no explicit value pp_opts.append("-D%s" % macro[0]) else: # XXX *don't* need to be clever about quoting the @@ -1084,7 +1153,7 @@ def gen_preprocess_options(macros, include_dirs): return pp_opts -def gen_lib_options (compiler, library_dirs, runtime_library_dirs, libraries): +def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries): """Generate linker options for searching library directories and linking with specific libraries. 'libraries' and 'library_dirs' are, respectively, lists of library names (not filenames!) and search @@ -1116,8 +1185,9 @@ def gen_lib_options (compiler, library_dirs, runtime_library_dirs, libraries): if lib_file: lib_opts.append(lib_file) else: - compiler.warn("no library file corresponding to " - "'%s' found (skipping)" % lib) + compiler.warn( + "no library file corresponding to " "'%s' found (skipping)" % lib + ) else: - lib_opts.append(compiler.library_option (lib)) + lib_opts.append(compiler.library_option(lib)) return lib_opts diff --git a/setuptools/_distutils/cmd.py b/setuptools/_distutils/cmd.py index dba3191e584..4a9bcc2a733 100644 --- a/setuptools/_distutils/cmd.py +++ b/setuptools/_distutils/cmd.py @@ -9,6 +9,7 @@ from distutils import util, dir_util, file_util, archive_util, dep_util from distutils import log + class Command: """Abstract base class for defining command classes, the "worker bees" of the Distutils. A useful analogy for command classes is to think of @@ -41,7 +42,6 @@ class Command: # defined. The canonical example is the "install" command. sub_commands = [] - # -- Creation/initialization methods ------------------------------- def __init__(self, dist): @@ -130,8 +130,9 @@ def initialize_options(self): This method must be implemented by all command classes. """ - raise RuntimeError("abstract method -- subclass %s must override" - % self.__class__) + raise RuntimeError( + "abstract method -- subclass %s must override" % self.__class__ + ) def finalize_options(self): """Set final values for all the options that this command supports. @@ -144,12 +145,13 @@ def finalize_options(self): This method must be implemented by all command classes. """ - raise RuntimeError("abstract method -- subclass %s must override" - % self.__class__) - + raise RuntimeError( + "abstract method -- subclass %s must override" % self.__class__ + ) def dump_options(self, header=None, indent=""): from distutils.fancy_getopt import longopt_xlate + if header is None: header = "command options for '%s':" % self.get_command_name() self.announce(indent + header, level=log.INFO) @@ -159,8 +161,7 @@ def dump_options(self, header=None, indent=""): if option[-1] == "=": option = option[:-1] value = getattr(self, option) - self.announce(indent + "%s = %s" % (option, value), - level=log.INFO) + self.announce(indent + "%s = %s" % (option, value), level=log.INFO) def run(self): """A command's raison d'etre: carry out the action it exists to @@ -172,8 +173,9 @@ def run(self): This method must be implemented by all command classes. """ - raise RuntimeError("abstract method -- subclass %s must override" - % self.__class__) + raise RuntimeError( + "abstract method -- subclass %s must override" % self.__class__ + ) def announce(self, msg, level=1): """If the current verbosity level is of greater than or equal to @@ -186,11 +188,11 @@ def debug_print(self, msg): DISTUTILS_DEBUG environment variable) flag is true. """ from distutils.debug import DEBUG + if DEBUG: print(msg) sys.stdout.flush() - # -- Option validation methods ------------------------------------- # (these are very handy in writing the 'finalize_options()' method) # @@ -210,8 +212,9 @@ def _ensure_stringlike(self, option, what, default=None): setattr(self, option, default) return default elif not isinstance(val, str): - raise DistutilsOptionError("'%s' must be a %s (got `%s`)" - % (option, what, val)) + raise DistutilsOptionError( + "'%s' must be a %s (got `%s`)" % (option, what, val) + ) return val def ensure_string(self, option, default=None): @@ -238,27 +241,29 @@ def ensure_string_list(self, option): ok = False if not ok: raise DistutilsOptionError( - "'%s' must be a list of strings (got %r)" - % (option, val)) + "'%s' must be a list of strings (got %r)" % (option, val) + ) - def _ensure_tested_string(self, option, tester, what, error_fmt, - default=None): + def _ensure_tested_string(self, option, tester, what, error_fmt, default=None): val = self._ensure_stringlike(option, what, default) if val is not None and not tester(val): - raise DistutilsOptionError(("error in '%s' option: " + error_fmt) - % (option, val)) + raise DistutilsOptionError( + ("error in '%s' option: " + error_fmt) % (option, val) + ) def ensure_filename(self, option): """Ensure that 'option' is the name of an existing file.""" - self._ensure_tested_string(option, os.path.isfile, - "filename", - "'%s' does not exist or is not a file") + self._ensure_tested_string( + option, os.path.isfile, "filename", "'%s' does not exist or is not a file" + ) def ensure_dirname(self, option): - self._ensure_tested_string(option, os.path.isdir, - "directory name", - "'%s' does not exist or is not a directory") - + self._ensure_tested_string( + option, + os.path.isdir, + "directory name", + "'%s' does not exist or is not a directory", + ) # -- Convenience methods for commands ------------------------------ @@ -302,8 +307,7 @@ def get_finalized_command(self, command, create=1): # XXX rename to 'get_reinitialized_command()'? (should do the # same in dist.py, if so) def reinitialize_command(self, command, reinit_subcommands=0): - return self.distribution.reinitialize_command(command, - reinit_subcommands) + return self.distribution.reinitialize_command(command, reinit_subcommands) def run_command(self, command): """Run some other command: uses the 'run_command()' method of @@ -325,7 +329,6 @@ def get_sub_commands(self): commands.append(cmd_name) return commands - # -- External world manipulation ----------------------------------- def warn(self, msg): @@ -337,41 +340,70 @@ def execute(self, func, args, msg=None, level=1): def mkpath(self, name, mode=0o777): dir_util.mkpath(name, mode, dry_run=self.dry_run) - def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, - link=None, level=1): + def copy_file( + self, infile, outfile, preserve_mode=1, preserve_times=1, link=None, level=1 + ): """Copy a file respecting verbose, dry-run and force flags. (The former two default to whatever is in the Distribution object, and the latter defaults to false for commands that don't define it.)""" - return file_util.copy_file(infile, outfile, preserve_mode, - preserve_times, not self.force, link, - dry_run=self.dry_run) - - def copy_tree(self, infile, outfile, preserve_mode=1, preserve_times=1, - preserve_symlinks=0, level=1): + return file_util.copy_file( + infile, + outfile, + preserve_mode, + preserve_times, + not self.force, + link, + dry_run=self.dry_run, + ) + + def copy_tree( + self, + infile, + outfile, + preserve_mode=1, + preserve_times=1, + preserve_symlinks=0, + level=1, + ): """Copy an entire directory tree respecting verbose, dry-run, and force flags. """ - return dir_util.copy_tree(infile, outfile, preserve_mode, - preserve_times, preserve_symlinks, - not self.force, dry_run=self.dry_run) - - def move_file (self, src, dst, level=1): + return dir_util.copy_tree( + infile, + outfile, + preserve_mode, + preserve_times, + preserve_symlinks, + not self.force, + dry_run=self.dry_run, + ) + + def move_file(self, src, dst, level=1): """Move a file respecting dry-run flag.""" return file_util.move_file(src, dst, dry_run=self.dry_run) def spawn(self, cmd, search_path=1, level=1): """Spawn an external command respecting dry-run flag.""" from distutils.spawn import spawn - spawn(cmd, search_path, dry_run=self.dry_run) - def make_archive(self, base_name, format, root_dir=None, base_dir=None, - owner=None, group=None): - return archive_util.make_archive(base_name, format, root_dir, base_dir, - dry_run=self.dry_run, - owner=owner, group=group) + spawn(cmd, search_path, dry_run=self.dry_run) - def make_file(self, infiles, outfile, func, args, - exec_msg=None, skip_msg=None, level=1): + def make_archive( + self, base_name, format, root_dir=None, base_dir=None, owner=None, group=None + ): + return archive_util.make_archive( + base_name, + format, + root_dir, + base_dir, + dry_run=self.dry_run, + owner=owner, + group=group, + ) + + def make_file( + self, infiles, outfile, func, args, exec_msg=None, skip_msg=None, level=1 + ): """Special case of 'execute()' for operations that process one or more input files and generate one output file. Works just like 'execute()', except the operation is skipped and a different @@ -387,8 +419,7 @@ def make_file(self, infiles, outfile, func, args, if isinstance(infiles, str): infiles = (infiles,) elif not isinstance(infiles, (list, tuple)): - raise TypeError( - "'infiles' must be a string, or a list or tuple of strings") + raise TypeError("'infiles' must be a string, or a list or tuple of strings") if exec_msg is None: exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles)) diff --git a/setuptools/_distutils/command/__init__.py b/setuptools/_distutils/command/__init__.py index 481eea9fd4b..d199c24277d 100644 --- a/setuptools/_distutils/command/__init__.py +++ b/setuptools/_distutils/command/__init__.py @@ -3,29 +3,30 @@ Package containing implementation of all the standard Distutils commands.""" -__all__ = ['build', - 'build_py', - 'build_ext', - 'build_clib', - 'build_scripts', - 'clean', - 'install', - 'install_lib', - 'install_headers', - 'install_scripts', - 'install_data', - 'sdist', - 'register', - 'bdist', - 'bdist_dumb', - 'bdist_rpm', - 'bdist_wininst', - 'check', - 'upload', - # These two are reserved for future use: - #'bdist_sdux', - #'bdist_pkgtool', - # Note: - # bdist_packager is not included because it only provides - # an abstract base class - ] +__all__ = [ + 'build', + 'build_py', + 'build_ext', + 'build_clib', + 'build_scripts', + 'clean', + 'install', + 'install_lib', + 'install_headers', + 'install_scripts', + 'install_data', + 'sdist', + 'register', + 'bdist', + 'bdist_dumb', + 'bdist_rpm', + 'bdist_wininst', + 'check', + 'upload', + # These two are reserved for future use: + #'bdist_sdux', + #'bdist_pkgtool', + # Note: + # bdist_packager is not included because it only provides + # an abstract base class +] diff --git a/setuptools/_distutils/command/bdist.py b/setuptools/_distutils/command/bdist.py index 014871d280e..2a639761c03 100644 --- a/setuptools/_distutils/command/bdist.py +++ b/setuptools/_distutils/command/bdist.py @@ -10,13 +10,12 @@ def show_formats(): - """Print list of available formats (arguments to "--format" option). - """ + """Print list of available formats (arguments to "--format" option).""" from distutils.fancy_getopt import FancyGetopt + formats = [] for format in bdist.format_commands: - formats.append(("formats=" + format, None, - bdist.format_command[format][1])) + formats.append(("formats=" + format, None, bdist.format_command[format][1])) pretty_printer = FancyGetopt(formats) pretty_printer.print_help("List of available distribution formats:") @@ -25,58 +24,71 @@ class bdist(Command): description = "create a built (binary) distribution" - user_options = [('bdist-base=', 'b', - "temporary directory for creating built distributions"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('formats=', None, - "formats for distribution (comma-separated list)"), - ('dist-dir=', 'd', - "directory to put final built distributions in " - "[default: dist]"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('owner=', 'u', - "Owner name used when creating a tar file" - " [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file" - " [default: current group]"), - ] + user_options = [ + ('bdist-base=', 'b', "temporary directory for creating built distributions"), + ( + 'plat-name=', + 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform(), + ), + ('formats=', None, "formats for distribution (comma-separated list)"), + ( + 'dist-dir=', + 'd', + "directory to put final built distributions in " "[default: dist]", + ), + ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), + ( + 'owner=', + 'u', + "Owner name used when creating a tar file" " [default: current user]", + ), + ( + 'group=', + 'g', + "Group name used when creating a tar file" " [default: current group]", + ), + ] boolean_options = ['skip-build'] help_options = [ - ('help-formats', None, - "lists available distribution formats", show_formats), - ] + ('help-formats', None, "lists available distribution formats", show_formats), + ] # The following commands do not take a format option from bdist no_format_option = ('bdist_rpm',) # This won't do in reality: will need to distinguish RPM-ish Linux, # Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS. - default_format = {'posix': 'gztar', - 'nt': 'zip'} + default_format = {'posix': 'gztar', 'nt': 'zip'} # Establish the preferred order (for the --help-formats option). - format_commands = ['rpm', 'gztar', 'bztar', 'xztar', 'ztar', 'tar', - 'wininst', 'zip', 'msi'] + format_commands = [ + 'rpm', + 'gztar', + 'bztar', + 'xztar', + 'ztar', + 'tar', + 'wininst', + 'zip', + 'msi', + ] # And the real information. - format_command = {'rpm': ('bdist_rpm', "RPM distribution"), - 'gztar': ('bdist_dumb', "gzip'ed tar file"), - 'bztar': ('bdist_dumb', "bzip2'ed tar file"), - 'xztar': ('bdist_dumb', "xz'ed tar file"), - 'ztar': ('bdist_dumb', "compressed tar file"), - 'tar': ('bdist_dumb', "tar file"), - 'wininst': ('bdist_wininst', - "Windows executable installer"), - 'zip': ('bdist_dumb', "ZIP file"), - 'msi': ('bdist_msi', "Microsoft Installer") - } - + format_command = { + 'rpm': ('bdist_rpm', "RPM distribution"), + 'gztar': ('bdist_dumb', "gzip'ed tar file"), + 'bztar': ('bdist_dumb', "bzip2'ed tar file"), + 'xztar': ('bdist_dumb', "xz'ed tar file"), + 'ztar': ('bdist_dumb', "compressed tar file"), + 'tar': ('bdist_dumb', "tar file"), + 'wininst': ('bdist_wininst', "Windows executable installer"), + 'zip': ('bdist_dumb', "ZIP file"), + 'msi': ('bdist_msi', "Microsoft Installer"), + } def initialize_options(self): self.bdist_base = None @@ -100,8 +112,7 @@ def finalize_options(self): # "build/bdist./dumb", "build/bdist./rpm", etc.) if self.bdist_base is None: build_base = self.get_finalized_command('build').build_base - self.bdist_base = os.path.join(build_base, - 'bdist.' + self.plat_name) + self.bdist_base = os.path.join(build_base, 'bdist.' + self.plat_name) self.ensure_string_list('formats') if self.formats is None: @@ -109,8 +120,9 @@ def finalize_options(self): self.formats = [self.default_format[os.name]] except KeyError: raise DistutilsPlatformError( - "don't know how to create built distributions " - "on platform %s" % os.name) + "don't know how to create built distributions " + "on platform %s" % os.name + ) if self.dist_dir is None: self.dist_dir = "dist" @@ -138,6 +150,6 @@ def run(self): # If we're going to need to run this command again, tell it to # keep its temporary files around so subsequent runs go faster. - if cmd_name in commands[i+1:]: + if cmd_name in commands[i + 1 :]: sub_cmd.keep_temp = 1 self.run_command(cmd_name) diff --git a/setuptools/_distutils/command/bdist_dumb.py b/setuptools/_distutils/command/bdist_dumb.py index f0d6b5b8cd8..3c387828670 100644 --- a/setuptools/_distutils/command/bdist_dumb.py +++ b/setuptools/_distutils/command/bdist_dumb.py @@ -12,40 +12,52 @@ from distutils.sysconfig import get_python_version from distutils import log + class bdist_dumb(Command): description = "create a \"dumb\" built distribution" - user_options = [('bdist-dir=', 'd', - "temporary directory for creating the distribution"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('format=', 'f', - "archive format to create (tar, gztar, bztar, xztar, " - "ztar, zip)"), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('relative', None, - "build the archive using relative paths " - "(default: false)"), - ('owner=', 'u', - "Owner name used when creating a tar file" - " [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file" - " [default: current group]"), - ] + user_options = [ + ('bdist-dir=', 'd', "temporary directory for creating the distribution"), + ( + 'plat-name=', + 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform(), + ), + ( + 'format=', + 'f', + "archive format to create (tar, gztar, bztar, xztar, " "ztar, zip)", + ), + ( + 'keep-temp', + 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive", + ), + ('dist-dir=', 'd', "directory to put final built distributions in"), + ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), + ( + 'relative', + None, + "build the archive using relative paths " "(default: false)", + ), + ( + 'owner=', + 'u', + "Owner name used when creating a tar file" " [default: current user]", + ), + ( + 'group=', + 'g', + "Group name used when creating a tar file" " [default: current group]", + ), + ] boolean_options = ['keep-temp', 'skip-build', 'relative'] - default_format = { 'posix': 'gztar', - 'nt': 'zip' } + default_format = {'posix': 'gztar', 'nt': 'zip'} def initialize_options(self): self.bdist_dir = None @@ -68,13 +80,16 @@ def finalize_options(self): self.format = self.default_format[os.name] except KeyError: raise DistutilsPlatformError( - "don't know how to create dumb built distributions " - "on platform %s" % os.name) + "don't know how to create dumb built distributions " + "on platform %s" % os.name + ) - self.set_undefined_options('bdist', - ('dist_dir', 'dist_dir'), - ('plat_name', 'plat_name'), - ('skip_build', 'skip_build')) + self.set_undefined_options( + 'bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ('skip_build', 'skip_build'), + ) def run(self): if not self.skip_build: @@ -90,34 +105,38 @@ def run(self): # And make an archive relative to the root of the # pseudo-installation tree. - archive_basename = "%s.%s" % (self.distribution.get_fullname(), - self.plat_name) + archive_basename = "%s.%s" % (self.distribution.get_fullname(), self.plat_name) pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) if not self.relative: archive_root = self.bdist_dir else: - if (self.distribution.has_ext_modules() and - (install.install_base != install.install_platbase)): + if self.distribution.has_ext_modules() and ( + install.install_base != install.install_platbase + ): raise DistutilsPlatformError( - "can't make a dumb built distribution where " - "base and platbase are different (%s, %s)" - % (repr(install.install_base), - repr(install.install_platbase))) + "can't make a dumb built distribution where " + "base and platbase are different (%s, %s)" + % (repr(install.install_base), repr(install.install_platbase)) + ) else: - archive_root = os.path.join(self.bdist_dir, - ensure_relative(install.install_base)) + archive_root = os.path.join( + self.bdist_dir, ensure_relative(install.install_base) + ) # Make the archive - filename = self.make_archive(pseudoinstall_root, - self.format, root_dir=archive_root, - owner=self.owner, group=self.group) + filename = self.make_archive( + pseudoinstall_root, + self.format, + root_dir=archive_root, + owner=self.owner, + group=self.group, + ) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' - self.distribution.dist_files.append(('bdist_dumb', pyversion, - filename)) + self.distribution.dist_files.append(('bdist_dumb', pyversion, filename)) if not self.keep_temp: remove_tree(self.bdist_dir, dry_run=self.dry_run) diff --git a/setuptools/_distutils/command/bdist_msi.py b/setuptools/_distutils/command/bdist_msi.py index 0863a1883e7..14e405d0243 100644 --- a/setuptools/_distutils/command/bdist_msi.py +++ b/setuptools/_distutils/command/bdist_msi.py @@ -20,17 +20,19 @@ from msilib import schema, sequence, text from msilib import Directory, Feature, Dialog, add_data + class PyDialog(Dialog): """Dialog class with a fixed layout: controls at the top, then a ruler, then a list of buttons: back, next, cancel. Optionally a bitmap at the left.""" + def __init__(self, *args, **kw): """Dialog(database, name, x, y, w, h, attributes, title, first, default, cancel, bitmap=true)""" Dialog.__init__(self, *args) ruler = self.h - 36 - bmwidth = 152*ruler/328 - #if kw.get("bitmap", True): + bmwidth = 152 * ruler / 328 + # if kw.get("bitmap", True): # self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") self.line("BottomLine", 0, ruler, self.w, 0) @@ -38,41 +40,40 @@ def title(self, title): "Set the title text of the dialog at the top." # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, # text, in VerdanaBold10 - self.text("Title", 15, 10, 320, 60, 0x30003, - r"{\VerdanaBold10}%s" % title) + self.text("Title", 15, 10, 320, 60, 0x30003, r"{\VerdanaBold10}%s" % title) - def back(self, title, next, name = "Back", active = 1): + def back(self, title, next, name="Back", active=1): """Add a back button with a given title, the tab-next button, its name in the Control table, possibly initially disabled. Return the button, so that events can be associated""" if active: - flags = 3 # Visible|Enabled + flags = 3 # Visible|Enabled else: - flags = 1 # Visible - return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) + flags = 1 # Visible + return self.pushbutton(name, 180, self.h - 27, 56, 17, flags, title, next) - def cancel(self, title, next, name = "Cancel", active = 1): + def cancel(self, title, next, name="Cancel", active=1): """Add a cancel button with a given title, the tab-next button, its name in the Control table, possibly initially disabled. Return the button, so that events can be associated""" if active: - flags = 3 # Visible|Enabled + flags = 3 # Visible|Enabled else: - flags = 1 # Visible - return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) + flags = 1 # Visible + return self.pushbutton(name, 304, self.h - 27, 56, 17, flags, title, next) - def next(self, title, next, name = "Next", active = 1): + def next(self, title, next, name="Next", active=1): """Add a Next button with a given title, the tab-next button, its name in the Control table, possibly initially disabled. Return the button, so that events can be associated""" if active: - flags = 3 # Visible|Enabled + flags = 3 # Visible|Enabled else: - flags = 1 # Visible - return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) + flags = 1 # Visible + return self.pushbutton(name, 236, self.h - 27, 56, 17, flags, title, next) def xbutton(self, name, title, next, xpos): """Add a button with a given title, the tab-next button, @@ -80,55 +81,96 @@ def xbutton(self, name, title, next, xpos): y-position is aligned with the other buttons. Return the button, so that events can be associated""" - return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) + return self.pushbutton( + name, int(self.w * xpos - 28), self.h - 27, 56, 17, 3, title, next + ) + class bdist_msi(Command): description = "create a Microsoft Installer (.msi) binary distribution" - user_options = [('bdist-dir=', None, - "temporary directory for creating the distribution"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('target-version=', None, - "require a specific python version" + - " on the target system"), - ('no-target-compile', 'c', - "do not compile .py to .pyc on the target system"), - ('no-target-optimize', 'o', - "do not compile .py to .pyo (optimized) " - "on the target system"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('install-script=', None, - "basename of installation script to be run after " - "installation or before deinstallation"), - ('pre-install-script=', None, - "Fully qualified filename of a script to be run before " - "any files are installed. This script need not be in the " - "distribution"), - ] - - boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', - 'skip-build'] - - all_versions = ['2.0', '2.1', '2.2', '2.3', '2.4', - '2.5', '2.6', '2.7', '2.8', '2.9', - '3.0', '3.1', '3.2', '3.3', '3.4', - '3.5', '3.6', '3.7', '3.8', '3.9'] + user_options = [ + ('bdist-dir=', None, "temporary directory for creating the distribution"), + ( + 'plat-name=', + 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform(), + ), + ( + 'keep-temp', + 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive", + ), + ( + 'target-version=', + None, + "require a specific python version" + " on the target system", + ), + ('no-target-compile', 'c', "do not compile .py to .pyc on the target system"), + ( + 'no-target-optimize', + 'o', + "do not compile .py to .pyo (optimized) " "on the target system", + ), + ('dist-dir=', 'd', "directory to put final built distributions in"), + ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), + ( + 'install-script=', + None, + "basename of installation script to be run after " + "installation or before deinstallation", + ), + ( + 'pre-install-script=', + None, + "Fully qualified filename of a script to be run before " + "any files are installed. This script need not be in the " + "distribution", + ), + ] + + boolean_options = [ + 'keep-temp', + 'no-target-compile', + 'no-target-optimize', + 'skip-build', + ] + + all_versions = [ + '2.0', + '2.1', + '2.2', + '2.3', + '2.4', + '2.5', + '2.6', + '2.7', + '2.8', + '2.9', + '3.0', + '3.1', + '3.2', + '3.3', + '3.4', + '3.5', + '3.6', + '3.7', + '3.8', + '3.9', + ] other_version = 'X' def __init__(self, *args, **kw): super().__init__(*args, **kw) - warnings.warn("bdist_msi command is deprecated since Python 3.9, " - "use bdist_wheel (wheel packages) instead", - DeprecationWarning, 2) + warnings.warn( + "bdist_msi command is deprecated since Python 3.9, " + "use bdist_wheel (wheel packages) instead", + DeprecationWarning, + 2, + ) def initialize_options(self): self.bdist_dir = None @@ -156,22 +198,28 @@ def finalize_options(self): if self.target_version: self.versions = [self.target_version] - if not self.skip_build and self.distribution.has_ext_modules()\ - and self.target_version != short_version: + if ( + not self.skip_build + and self.distribution.has_ext_modules() + and self.target_version != short_version + ): raise DistutilsOptionError( - "target version can only be %s, or the '--skip-build'" - " option must be specified" % (short_version,)) + "target version can only be %s, or the '--skip-build'" + " option must be specified" % (short_version,) + ) else: self.versions = list(self.all_versions) - self.set_undefined_options('bdist', - ('dist_dir', 'dist_dir'), - ('plat_name', 'plat_name'), - ) + self.set_undefined_options( + 'bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ) if self.pre_install_script: raise DistutilsOptionError( - "the pre-install-script feature is not yet implemented") + "the pre-install-script feature is not yet implemented" + ) if self.install_script: for script in self.distribution.scripts: @@ -179,8 +227,8 @@ def finalize_options(self): break else: raise DistutilsOptionError( - "install_script '%s' not found in scripts" - % self.install_script) + "install_script '%s' not found in scripts" % self.install_script + ) self.install_script_key = None def run(self): @@ -210,8 +258,7 @@ def run(self): target_version = '%d.%d' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') - build.build_lib = os.path.join(build.build_base, - 'lib' + plat_specifier) + build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) log.info("installing to %s", self.bdist_dir) install.ensure_finalized() @@ -228,7 +275,8 @@ def run(self): fullname = self.distribution.get_fullname() installer_name = self.get_installer_filename(fullname) installer_name = os.path.abspath(installer_name) - if os.path.exists(installer_name): os.unlink(installer_name) + if os.path.exists(installer_name): + os.unlink(installer_name) metadata = self.distribution.metadata author = metadata.author @@ -248,9 +296,9 @@ def run(self): product_name = "Python %s %s" % (self.target_version, fullname) else: product_name = "Python %s" % (fullname) - self.db = msilib.init_database(installer_name, schema, - product_name, msilib.gen_uuid(), - sversion, author) + self.db = msilib.init_database( + installer_name, schema, product_name, msilib.gen_uuid(), sversion, author + ) msilib.add_tables(self.db, sequence) props = [('DistVersion', version)] email = metadata.author_email or metadata.maintainer_email @@ -280,8 +328,7 @@ def add_files(self): rootdir = os.path.abspath(self.bdist_dir) root = Directory(db, cab, None, rootdir, "TARGETDIR", "SourceDir") - f = Feature(db, "Python", "Python", "Everything", - 0, 1, directory="TARGETDIR") + f = Feature(db, "Python", "Python", "Everything", 0, 1, directory="TARGETDIR") items = [(f, root, '')] for version in self.versions + [self.other_version]: @@ -316,15 +363,27 @@ def add_files(self): dir.start_component(dir.logical, feature, 0) if afile not in seen: key = seen[afile] = dir.add_file(file) - if file==self.install_script: + if file == self.install_script: if self.install_script_key: raise DistutilsOptionError( - "Multiple files with name %s" % file) + "Multiple files with name %s" % file + ) self.install_script_key = '[#%s]' % key else: key = seen[afile] - add_data(self.db, "DuplicateFile", - [(key + version, dir.component, key, None, dir.logical)]) + add_data( + self.db, + "DuplicateFile", + [ + ( + key + version, + dir.component, + key, + None, + dir.logical, + ) + ], + ) db.Commit() cab.commit(db) @@ -353,32 +412,60 @@ def add_find_python(self): exe_prop = "PYTHON" + ver if msilib.Win64: # type: msidbLocatorTypeRawValue + msidbLocatorType64bit - Type = 2+16 + Type = 2 + 16 else: Type = 2 - add_data(self.db, "RegLocator", - [(machine_reg, 2, install_path, None, Type), - (user_reg, 1, install_path, None, Type)]) - add_data(self.db, "AppSearch", - [(machine_prop, machine_reg), - (user_prop, user_reg)]) - add_data(self.db, "CustomAction", - [(machine_action, 51+256, target_dir_prop, "[" + machine_prop + "]"), - (user_action, 51+256, target_dir_prop, "[" + user_prop + "]"), - (exe_action, 51+256, exe_prop, "[" + target_dir_prop + "]\\python.exe"), - ]) - add_data(self.db, "InstallExecuteSequence", - [(machine_action, machine_prop, start), - (user_action, user_prop, start + 1), - (exe_action, None, start + 2), - ]) - add_data(self.db, "InstallUISequence", - [(machine_action, machine_prop, start), - (user_action, user_prop, start + 1), - (exe_action, None, start + 2), - ]) - add_data(self.db, "Condition", - [("Python" + ver, 0, "NOT TARGETDIR" + ver)]) + add_data( + self.db, + "RegLocator", + [ + (machine_reg, 2, install_path, None, Type), + (user_reg, 1, install_path, None, Type), + ], + ) + add_data( + self.db, + "AppSearch", + [(machine_prop, machine_reg), (user_prop, user_reg)], + ) + add_data( + self.db, + "CustomAction", + [ + ( + machine_action, + 51 + 256, + target_dir_prop, + "[" + machine_prop + "]", + ), + (user_action, 51 + 256, target_dir_prop, "[" + user_prop + "]"), + ( + exe_action, + 51 + 256, + exe_prop, + "[" + target_dir_prop + "]\\python.exe", + ), + ], + ) + add_data( + self.db, + "InstallExecuteSequence", + [ + (machine_action, machine_prop, start), + (user_action, user_prop, start + 1), + (exe_action, None, start + 2), + ], + ) + add_data( + self.db, + "InstallUISequence", + [ + (machine_action, machine_prop, start), + (user_action, user_prop, start + 1), + (exe_action, None, start + 2), + ], + ) + add_data(self.db, "Condition", [("Python" + ver, 0, "NOT TARGETDIR" + ver)]) start += 4 assert start < 500 @@ -388,10 +475,16 @@ def add_scripts(self): for ver in self.versions + [self.other_version]: install_action = "install_script." + ver exe_prop = "PYTHON" + ver - add_data(self.db, "CustomAction", - [(install_action, 50, exe_prop, self.install_script_key)]) - add_data(self.db, "InstallExecuteSequence", - [(install_action, "&Python%s=3" % ver, start)]) + add_data( + self.db, + "CustomAction", + [(install_action, 50, exe_prop, self.install_script_key)], + ) + add_data( + self.db, + "InstallExecuteSequence", + [(install_action, "&Python%s=3" % ver, start)], + ) start += 1 # XXX pre-install scripts are currently refused in finalize_options() # but if this feature is completed, it will also need to add @@ -410,15 +503,13 @@ def add_scripts(self): f.write('rem ="""\n%1 %0\nexit\n"""\n') with open(self.pre_install_script) as fin: f.write(fin.read()) - add_data(self.db, "Binary", - [("PreInstall", msilib.Binary(scriptfn)) - ]) - add_data(self.db, "CustomAction", - [("PreInstall", 2, "PreInstall", None) - ]) - add_data(self.db, "InstallExecuteSequence", - [("PreInstall", "NOT Installed", 450)]) - + add_data(self.db, "Binary", [("PreInstall", msilib.Binary(scriptfn))]) + add_data(self.db, "CustomAction", [("PreInstall", 2, "PreInstall", None)]) + add_data( + self.db, + "InstallExecuteSequence", + [("PreInstall", "NOT Installed", 450)], + ) def add_ui(self): db = self.db @@ -428,168 +519,322 @@ def add_ui(self): title = "[ProductName] Setup" # see "Dialog Style Bits" - modal = 3 # visible | modal - modeless = 1 # visible + modal = 3 # visible | modal + modeless = 1 # visible track_disk_space = 32 # UI customization properties - add_data(db, "Property", - # See "DefaultUIFont Property" - [("DefaultUIFont", "DlgFont8"), - # See "ErrorDialog Style Bit" - ("ErrorDialog", "ErrorDlg"), - ("Progress1", "Install"), # modified in maintenance type dlg - ("Progress2", "installs"), - ("MaintenanceForm_Action", "Repair"), - # possible values: ALL, JUSTME - ("WhichUsers", "ALL") - ]) + add_data( + db, + "Property", + # See "DefaultUIFont Property" + [ + ("DefaultUIFont", "DlgFont8"), + # See "ErrorDialog Style Bit" + ("ErrorDialog", "ErrorDlg"), + ("Progress1", "Install"), # modified in maintenance type dlg + ("Progress2", "installs"), + ("MaintenanceForm_Action", "Repair"), + # possible values: ALL, JUSTME + ("WhichUsers", "ALL"), + ], + ) # Fonts, see "TextStyle Table" - add_data(db, "TextStyle", - [("DlgFont8", "Tahoma", 9, None, 0), - ("DlgFontBold8", "Tahoma", 8, None, 1), #bold - ("VerdanaBold10", "Verdana", 10, None, 1), - ("VerdanaRed9", "Verdana", 9, 255, 0), - ]) + add_data( + db, + "TextStyle", + [ + ("DlgFont8", "Tahoma", 9, None, 0), + ("DlgFontBold8", "Tahoma", 8, None, 1), # bold + ("VerdanaBold10", "Verdana", 10, None, 1), + ("VerdanaRed9", "Verdana", 9, 255, 0), + ], + ) # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" # Numbers indicate sequence; see sequence.py for how these action integrate - add_data(db, "InstallUISequence", - [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), - ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), - # In the user interface, assume all-users installation if privileged. - ("SelectFeaturesDlg", "Not Installed", 1230), - # XXX no support for resume installations yet - #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), - ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), - ("ProgressDlg", None, 1280)]) + add_data( + db, + "InstallUISequence", + [ + ("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), + ( + "WhichUsersDlg", + "Privileged and not Windows9x and not Installed", + 141, + ), + # In the user interface, assume all-users installation if privileged. + ("SelectFeaturesDlg", "Not Installed", 1230), + # XXX no support for resume installations yet + # ("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), + ( + "MaintenanceTypeDlg", + "Installed AND NOT RESUME AND NOT Preselected", + 1250, + ), + ("ProgressDlg", None, 1280), + ], + ) add_data(db, 'ActionText', text.ActionText) add_data(db, 'UIText', text.UIText) ##################################################################### # Standard dialogs: FatalError, UserExit, ExitDialog - fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") + fatal = PyDialog( + db, "FatalError", x, y, w, h, modal, title, "Finish", "Finish", "Finish" + ) fatal.title("[ProductName] Installer ended prematurely") - fatal.back("< Back", "Finish", active = 0) - fatal.cancel("Cancel", "Back", active = 0) - fatal.text("Description1", 15, 70, 320, 80, 0x30003, - "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.") - fatal.text("Description2", 15, 155, 320, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c=fatal.next("Finish", "Cancel", name="Finish") + fatal.back("< Back", "Finish", active=0) + fatal.cancel("Cancel", "Back", active=0) + fatal.text( + "Description1", + 15, + 70, + 320, + 80, + 0x30003, + "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.", + ) + fatal.text( + "Description2", + 15, + 155, + 320, + 20, + 0x30003, + "Click the Finish button to exit the Installer.", + ) + c = fatal.next("Finish", "Cancel", name="Finish") c.event("EndDialog", "Exit") - user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") + user_exit = PyDialog( + db, "UserExit", x, y, w, h, modal, title, "Finish", "Finish", "Finish" + ) user_exit.title("[ProductName] Installer was interrupted") - user_exit.back("< Back", "Finish", active = 0) - user_exit.cancel("Cancel", "Back", active = 0) - user_exit.text("Description1", 15, 70, 320, 80, 0x30003, - "[ProductName] setup was interrupted. Your system has not been modified. " - "To install this program at a later time, please run the installation again.") - user_exit.text("Description2", 15, 155, 320, 20, 0x30003, - "Click the Finish button to exit the Installer.") + user_exit.back("< Back", "Finish", active=0) + user_exit.cancel("Cancel", "Back", active=0) + user_exit.text( + "Description1", + 15, + 70, + 320, + 80, + 0x30003, + "[ProductName] setup was interrupted. Your system has not been modified. " + "To install this program at a later time, please run the installation again.", + ) + user_exit.text( + "Description2", + 15, + 155, + 320, + 20, + 0x30003, + "Click the Finish button to exit the Installer.", + ) c = user_exit.next("Finish", "Cancel", name="Finish") c.event("EndDialog", "Exit") - exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") + exit_dialog = PyDialog( + db, "ExitDialog", x, y, w, h, modal, title, "Finish", "Finish", "Finish" + ) exit_dialog.title("Completing the [ProductName] Installer") - exit_dialog.back("< Back", "Finish", active = 0) - exit_dialog.cancel("Cancel", "Back", active = 0) - exit_dialog.text("Description", 15, 235, 320, 20, 0x30003, - "Click the Finish button to exit the Installer.") + exit_dialog.back("< Back", "Finish", active=0) + exit_dialog.cancel("Cancel", "Back", active=0) + exit_dialog.text( + "Description", + 15, + 235, + 320, + 20, + 0x30003, + "Click the Finish button to exit the Installer.", + ) c = exit_dialog.next("Finish", "Cancel", name="Finish") c.event("EndDialog", "Return") ##################################################################### # Required dialog: FilesInUse, ErrorDlg - inuse = PyDialog(db, "FilesInUse", - x, y, w, h, - 19, # KeepModeless|Modal|Visible - title, - "Retry", "Retry", "Retry", bitmap=False) - inuse.text("Title", 15, 6, 200, 15, 0x30003, - r"{\DlgFontBold8}Files in Use") - inuse.text("Description", 20, 23, 280, 20, 0x30003, - "Some files that need to be updated are currently in use.") - inuse.text("Text", 20, 55, 330, 50, 3, - "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.") - inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", - None, None, None) - c=inuse.back("Exit", "Ignore", name="Exit") + inuse = PyDialog( + db, + "FilesInUse", + x, + y, + w, + h, + 19, # KeepModeless|Modal|Visible + title, + "Retry", + "Retry", + "Retry", + bitmap=False, + ) + inuse.text("Title", 15, 6, 200, 15, 0x30003, r"{\DlgFontBold8}Files in Use") + inuse.text( + "Description", + 20, + 23, + 280, + 20, + 0x30003, + "Some files that need to be updated are currently in use.", + ) + inuse.text( + "Text", + 20, + 55, + 330, + 50, + 3, + "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.", + ) + inuse.control( + "List", + "ListBox", + 20, + 107, + 330, + 130, + 7, + "FileInUseProcess", + None, + None, + None, + ) + c = inuse.back("Exit", "Ignore", name="Exit") c.event("EndDialog", "Exit") - c=inuse.next("Ignore", "Retry", name="Ignore") + c = inuse.next("Ignore", "Retry", name="Ignore") c.event("EndDialog", "Ignore") - c=inuse.cancel("Retry", "Exit", name="Retry") - c.event("EndDialog","Retry") + c = inuse.cancel("Retry", "Exit", name="Retry") + c.event("EndDialog", "Retry") # See "Error Dialog". See "ICE20" for the required names of the controls. - error = Dialog(db, "ErrorDlg", - 50, 10, 330, 101, - 65543, # Error|Minimize|Modal|Visible - title, - "ErrorText", None, None) - error.text("ErrorText", 50,9,280,48,3, "") - #error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) - error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") - error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") - error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") - error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") - error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") - error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") - error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") + error = Dialog( + db, + "ErrorDlg", + 50, + 10, + 330, + 101, + 65543, # Error|Minimize|Modal|Visible + title, + "ErrorText", + None, + None, + ) + error.text("ErrorText", 50, 9, 280, 48, 3, "") + # error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) + error.pushbutton("N", 120, 72, 81, 21, 3, "No", None).event( + "EndDialog", "ErrorNo" + ) + error.pushbutton("Y", 240, 72, 81, 21, 3, "Yes", None).event( + "EndDialog", "ErrorYes" + ) + error.pushbutton("A", 0, 72, 81, 21, 3, "Abort", None).event( + "EndDialog", "ErrorAbort" + ) + error.pushbutton("C", 42, 72, 81, 21, 3, "Cancel", None).event( + "EndDialog", "ErrorCancel" + ) + error.pushbutton("I", 81, 72, 81, 21, 3, "Ignore", None).event( + "EndDialog", "ErrorIgnore" + ) + error.pushbutton("O", 159, 72, 81, 21, 3, "Ok", None).event( + "EndDialog", "ErrorOk" + ) + error.pushbutton("R", 198, 72, 81, 21, 3, "Retry", None).event( + "EndDialog", "ErrorRetry" + ) ##################################################################### # Global "Query Cancel" dialog - cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, - "No", "No", "No") - cancel.text("Text", 48, 15, 194, 30, 3, - "Are you sure you want to cancel [ProductName] installation?") - #cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, + cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, "No", "No", "No") + cancel.text( + "Text", + 48, + 15, + 194, + 30, + 3, + "Are you sure you want to cancel [ProductName] installation?", + ) + # cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, # "py.ico", None, None) - c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") + c = cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") c.event("EndDialog", "Exit") - c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") + c = cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") c.event("EndDialog", "Return") ##################################################################### # Global "Wait for costing" dialog - costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, - "Return", "Return", "Return") - costing.text("Text", 48, 15, 194, 30, 3, - "Please wait while the installer finishes determining your disk space requirements.") + costing = Dialog( + db, + "WaitForCostingDlg", + 50, + 10, + 260, + 85, + modal, + title, + "Return", + "Return", + "Return", + ) + costing.text( + "Text", + 48, + 15, + 194, + 30, + 3, + "Please wait while the installer finishes determining your disk space requirements.", + ) c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) c.event("EndDialog", "Exit") ##################################################################### # Preparation dialog: no user input except cancellation - prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel") - prep.text("Description", 15, 70, 320, 40, 0x30003, - "Please wait while the Installer prepares to guide you through the installation.") + prep = PyDialog( + db, "PrepareDlg", x, y, w, h, modeless, title, "Cancel", "Cancel", "Cancel" + ) + prep.text( + "Description", + 15, + 70, + 320, + 40, + 0x30003, + "Please wait while the Installer prepares to guide you through the installation.", + ) prep.title("Welcome to the [ProductName] Installer") - c=prep.text("ActionText", 15, 110, 320, 20, 0x30003, "Pondering...") + c = prep.text("ActionText", 15, 110, 320, 20, 0x30003, "Pondering...") c.mapping("ActionText", "Text") - c=prep.text("ActionData", 15, 135, 320, 30, 0x30003, None) + c = prep.text("ActionData", 15, 135, 320, 30, 0x30003, None) c.mapping("ActionData", "Text") prep.back("Back", None, active=0) prep.next("Next", None, active=0) - c=prep.cancel("Cancel", None) + c = prep.cancel("Cancel", None) c.event("SpawnDialog", "CancelDlg") ##################################################################### # Feature (Python directory) selection - seldlg = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") + seldlg = PyDialog( + db, "SelectFeaturesDlg", x, y, w, h, modal, title, "Next", "Next", "Cancel" + ) seldlg.title("Select Python Installations") - seldlg.text("Hint", 15, 30, 300, 20, 3, - "Select the Python locations where %s should be installed." - % self.distribution.get_fullname()) + seldlg.text( + "Hint", + 15, + 30, + 300, + 20, + 3, + "Select the Python locations where %s should be installed." + % self.distribution.get_fullname(), + ) seldlg.back("< Back", None, active=0) c = seldlg.next("Next >", "Cancel") @@ -597,30 +842,56 @@ def add_ui(self): c.event("[TARGETDIR]", "[SourceDir]", ordering=order) for version in self.versions + [self.other_version]: order += 1 - c.event("[TARGETDIR]", "[TARGETDIR%s]" % version, - "FEATURE_SELECTED AND &Python%s=3" % version, - ordering=order) + c.event( + "[TARGETDIR]", + "[TARGETDIR%s]" % version, + "FEATURE_SELECTED AND &Python%s=3" % version, + ordering=order, + ) c.event("SpawnWaitDialog", "WaitForCostingDlg", ordering=order + 1) c.event("EndDialog", "Return", ordering=order + 2) c = seldlg.cancel("Cancel", "Features") c.event("SpawnDialog", "CancelDlg") - c = seldlg.control("Features", "SelectionTree", 15, 60, 300, 120, 3, - "FEATURE", None, "PathEdit", None) + c = seldlg.control( + "Features", + "SelectionTree", + 15, + 60, + 300, + 120, + 3, + "FEATURE", + None, + "PathEdit", + None, + ) c.event("[FEATURE_SELECTED]", "1") ver = self.other_version install_other_cond = "FEATURE_SELECTED AND &Python%s=3" % ver dont_install_other_cond = "FEATURE_SELECTED AND &Python%s<>3" % ver - c = seldlg.text("Other", 15, 200, 300, 15, 3, - "Provide an alternate Python location") + c = seldlg.text( + "Other", 15, 200, 300, 15, 3, "Provide an alternate Python location" + ) c.condition("Enable", install_other_cond) c.condition("Show", install_other_cond) c.condition("Disable", dont_install_other_cond) c.condition("Hide", dont_install_other_cond) - c = seldlg.control("PathEdit", "PathEdit", 15, 215, 300, 16, 1, - "TARGETDIR" + ver, None, "Next", None) + c = seldlg.control( + "PathEdit", + "PathEdit", + 15, + 215, + 300, + 16, + 1, + "TARGETDIR" + ver, + None, + "Next", + None, + ) c.condition("Enable", install_other_cond) c.condition("Show", install_other_cond) c.condition("Disable", dont_install_other_cond) @@ -628,20 +899,47 @@ def add_ui(self): ##################################################################### # Disk cost - cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, - "OK", "OK", "OK", bitmap=False) - cost.text("Title", 15, 6, 200, 15, 0x30003, - r"{\DlgFontBold8}Disk Space Requirements") - cost.text("Description", 20, 20, 280, 20, 0x30003, - "The disk space required for the installation of the selected features.") - cost.text("Text", 20, 53, 330, 60, 3, - "The highlighted volumes (if any) do not have enough disk space " - "available for the currently selected features. You can either " - "remove some files from the highlighted volumes, or choose to " - "install less features onto local drive(s), or select different " - "destination drive(s).") - cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, - None, "{120}{70}{70}{70}{70}", None, None) + cost = PyDialog( + db, "DiskCostDlg", x, y, w, h, modal, title, "OK", "OK", "OK", bitmap=False + ) + cost.text( + "Title", 15, 6, 200, 15, 0x30003, r"{\DlgFontBold8}Disk Space Requirements" + ) + cost.text( + "Description", + 20, + 20, + 280, + 20, + 0x30003, + "The disk space required for the installation of the selected features.", + ) + cost.text( + "Text", + 20, + 53, + 330, + 60, + 3, + "The highlighted volumes (if any) do not have enough disk space " + "available for the currently selected features. You can either " + "remove some files from the highlighted volumes, or choose to " + "install less features onto local drive(s), or select different " + "destination drive(s).", + ) + cost.control( + "VolumeList", + "VolumeCostList", + 20, + 100, + 330, + 150, + 393223, + None, + "{120}{70}{70}{70}{70}", + None, + None, + ) cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") ##################################################################### @@ -655,12 +953,26 @@ def add_ui(self): # On Windows9x, the ALLUSERS property is ignored on the command line # and in the Property table, but installer fails according to the documentation # if a dialog attempts to set ALLUSERS. - whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, - "AdminInstall", "Next", "Cancel") - whichusers.title("Select whether to install [ProductName] for all users of this computer.") + whichusers = PyDialog( + db, + "WhichUsersDlg", + x, + y, + w, + h, + modal, + title, + "AdminInstall", + "Next", + "Cancel", + ) + whichusers.title( + "Select whether to install [ProductName] for all users of this computer." + ) # A radio group with two options: allusers, justme - g = whichusers.radiogroup("AdminInstall", 15, 60, 260, 50, 3, - "WhichUsers", "", "Next") + g = whichusers.radiogroup( + "AdminInstall", 15, 60, 260, 50, 3, "WhichUsers", "", "Next" + ) g.add("ALL", 0, 5, 150, 20, "Install for all users") g.add("JUSTME", 0, 25, 150, 20, "Install just for me") @@ -668,30 +980,67 @@ def add_ui(self): c = whichusers.next("Next >", "Cancel") c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) - c.event("EndDialog", "Return", ordering = 2) + c.event("EndDialog", "Return", ordering=2) c = whichusers.cancel("Cancel", "AdminInstall") c.event("SpawnDialog", "CancelDlg") ##################################################################### # Installation Progress dialog (modeless) - progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel", bitmap=False) - progress.text("Title", 20, 15, 200, 15, 0x30003, - r"{\DlgFontBold8}[Progress1] [ProductName]") - progress.text("Text", 35, 65, 300, 30, 3, - "Please wait while the Installer [Progress2] [ProductName]. " - "This may take several minutes.") + progress = PyDialog( + db, + "ProgressDlg", + x, + y, + w, + h, + modeless, + title, + "Cancel", + "Cancel", + "Cancel", + bitmap=False, + ) + progress.text( + "Title", + 20, + 15, + 200, + 15, + 0x30003, + r"{\DlgFontBold8}[Progress1] [ProductName]", + ) + progress.text( + "Text", + 35, + 65, + 300, + 30, + 3, + "Please wait while the Installer [Progress2] [ProductName]. " + "This may take several minutes.", + ) progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") - c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") + c = progress.text("ActionText", 70, 100, w - 70, 20, 3, "Pondering...") c.mapping("ActionText", "Text") - #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) - #c.mapping("ActionData", "Text") - - c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, - None, "Progress done", None, None) + # c=progress.text("ActionData", 35, 140, 300, 20, 3, None) + # c.mapping("ActionData", "Text") + + c = progress.control( + "ProgressBar", + "ProgressBar", + 35, + 120, + 300, + 10, + 65537, + None, + "Progress done", + None, + None, + ) c.mapping("SetProgress", "Progress") progress.back("< Back", "Next", active=False) @@ -700,23 +1049,40 @@ def add_ui(self): ################################################################### # Maintenance type: repair/uninstall - maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") + maint = PyDialog( + db, "MaintenanceTypeDlg", x, y, w, h, modal, title, "Next", "Next", "Cancel" + ) maint.title("Welcome to the [ProductName] Setup Wizard") - maint.text("BodyText", 15, 63, 330, 42, 3, - "Select whether you want to repair or remove [ProductName].") - g=maint.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3, - "MaintenanceForm_Action", "", "Next") - #g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") + maint.text( + "BodyText", + 15, + 63, + 330, + 42, + 3, + "Select whether you want to repair or remove [ProductName].", + ) + g = maint.radiogroup( + "RepairRadioGroup", + 15, + 108, + 330, + 60, + 3, + "MaintenanceForm_Action", + "", + "Next", + ) + # g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") maint.back("< Back", None, active=False) - c=maint.next("Finish", "Cancel") + c = maint.next("Finish", "Cancel") # Change installation: Change progress dialog to "Change", then ask # for feature selection - #c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) - #c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) + # c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) + # c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) # Reinstall: Change progress dialog to "Repair", then invoke reinstall # Also set list of reinstalled features to "ALL" @@ -734,15 +1100,18 @@ def add_ui(self): # Close dialog when maintenance action scheduled c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) - #c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) + # c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") def get_installer_filename(self, fullname): # Factored out to allow overriding in subclasses if self.target_version: - base_name = "%s.%s-py%s.msi" % (fullname, self.plat_name, - self.target_version) + base_name = "%s.%s-py%s.msi" % ( + fullname, + self.plat_name, + self.target_version, + ) else: base_name = "%s.%s.msi" % (fullname, self.plat_name) installer_name = os.path.join(self.dist_dir, base_name) diff --git a/setuptools/_distutils/command/bdist_rpm.py b/setuptools/_distutils/command/bdist_rpm.py index 550cbfa1e28..60fab01de63 100644 --- a/setuptools/_distutils/command/bdist_rpm.py +++ b/setuptools/_distutils/command/bdist_rpm.py @@ -11,126 +11,137 @@ from distutils.sysconfig import get_python_version from distutils import log + class bdist_rpm(Command): description = "create an RPM distribution" user_options = [ - ('bdist-base=', None, - "base directory for creating built distributions"), - ('rpm-base=', None, - "base directory for creating RPMs (defaults to \"rpm\" under " - "--bdist-base; must be specified for RPM 2)"), - ('dist-dir=', 'd', - "directory to put final RPM files in " - "(and .spec files if --spec-only)"), - ('python=', None, - "path to Python interpreter to hard-code in the .spec file " - "(default: \"python\")"), - ('fix-python', None, - "hard-code the exact path to the current Python interpreter in " - "the .spec file"), - ('spec-only', None, - "only regenerate spec file"), - ('source-only', None, - "only generate source RPM"), - ('binary-only', None, - "only generate binary RPM"), - ('use-bzip2', None, - "use bzip2 instead of gzip to create source distribution"), - + ('bdist-base=', None, "base directory for creating built distributions"), + ( + 'rpm-base=', + None, + "base directory for creating RPMs (defaults to \"rpm\" under " + "--bdist-base; must be specified for RPM 2)", + ), + ( + 'dist-dir=', + 'd', + "directory to put final RPM files in " "(and .spec files if --spec-only)", + ), + ( + 'python=', + None, + "path to Python interpreter to hard-code in the .spec file " + "(default: \"python\")", + ), + ( + 'fix-python', + None, + "hard-code the exact path to the current Python interpreter in " + "the .spec file", + ), + ('spec-only', None, "only regenerate spec file"), + ('source-only', None, "only generate source RPM"), + ('binary-only', None, "only generate binary RPM"), + ('use-bzip2', None, "use bzip2 instead of gzip to create source distribution"), # More meta-data: too RPM-specific to put in the setup script, # but needs to go in the .spec file -- so we make these options # to "bdist_rpm". The idea is that packagers would put this # info in setup.cfg, although they are of course free to # supply it on the command line. - ('distribution-name=', None, - "name of the (Linux) distribution to which this " - "RPM applies (*not* the name of the module distribution!)"), - ('group=', None, - "package classification [default: \"Development/Libraries\"]"), - ('release=', None, - "RPM release number"), - ('serial=', None, - "RPM serial number"), - ('vendor=', None, - "RPM \"vendor\" (eg. \"Joe Blow \") " - "[default: maintainer or author from setup script]"), - ('packager=', None, - "RPM packager (eg. \"Jane Doe \") " - "[default: vendor]"), - ('doc-files=', None, - "list of documentation files (space or comma-separated)"), - ('changelog=', None, - "RPM changelog"), - ('icon=', None, - "name of icon file"), - ('provides=', None, - "capabilities provided by this package"), - ('requires=', None, - "capabilities required by this package"), - ('conflicts=', None, - "capabilities which conflict with this package"), - ('build-requires=', None, - "capabilities required to build this package"), - ('obsoletes=', None, - "capabilities made obsolete by this package"), - ('no-autoreq', None, - "do not automatically calculate dependencies"), - + ( + 'distribution-name=', + None, + "name of the (Linux) distribution to which this " + "RPM applies (*not* the name of the module distribution!)", + ), + ('group=', None, "package classification [default: \"Development/Libraries\"]"), + ('release=', None, "RPM release number"), + ('serial=', None, "RPM serial number"), + ( + 'vendor=', + None, + "RPM \"vendor\" (eg. \"Joe Blow \") " + "[default: maintainer or author from setup script]", + ), + ( + 'packager=', + None, + "RPM packager (eg. \"Jane Doe \") " "[default: vendor]", + ), + ('doc-files=', None, "list of documentation files (space or comma-separated)"), + ('changelog=', None, "RPM changelog"), + ('icon=', None, "name of icon file"), + ('provides=', None, "capabilities provided by this package"), + ('requires=', None, "capabilities required by this package"), + ('conflicts=', None, "capabilities which conflict with this package"), + ('build-requires=', None, "capabilities required to build this package"), + ('obsoletes=', None, "capabilities made obsolete by this package"), + ('no-autoreq', None, "do not automatically calculate dependencies"), # Actions to take when building RPM - ('keep-temp', 'k', - "don't clean up RPM build directory"), - ('no-keep-temp', None, - "clean up RPM build directory [default]"), - ('use-rpm-opt-flags', None, - "compile with RPM_OPT_FLAGS when building from source RPM"), - ('no-rpm-opt-flags', None, - "do not pass any RPM CFLAGS to compiler"), - ('rpm3-mode', None, - "RPM 3 compatibility mode (default)"), - ('rpm2-mode', None, - "RPM 2 compatibility mode"), - + ('keep-temp', 'k', "don't clean up RPM build directory"), + ('no-keep-temp', None, "clean up RPM build directory [default]"), + ( + 'use-rpm-opt-flags', + None, + "compile with RPM_OPT_FLAGS when building from source RPM", + ), + ('no-rpm-opt-flags', None, "do not pass any RPM CFLAGS to compiler"), + ('rpm3-mode', None, "RPM 3 compatibility mode (default)"), + ('rpm2-mode', None, "RPM 2 compatibility mode"), # Add the hooks necessary for specifying custom scripts - ('prep-script=', None, - "Specify a script for the PREP phase of RPM building"), - ('build-script=', None, - "Specify a script for the BUILD phase of RPM building"), - - ('pre-install=', None, - "Specify a script for the pre-INSTALL phase of RPM building"), - ('install-script=', None, - "Specify a script for the INSTALL phase of RPM building"), - ('post-install=', None, - "Specify a script for the post-INSTALL phase of RPM building"), - - ('pre-uninstall=', None, - "Specify a script for the pre-UNINSTALL phase of RPM building"), - ('post-uninstall=', None, - "Specify a script for the post-UNINSTALL phase of RPM building"), - - ('clean-script=', None, - "Specify a script for the CLEAN phase of RPM building"), - - ('verify-script=', None, - "Specify a script for the VERIFY phase of the RPM build"), - + ('prep-script=', None, "Specify a script for the PREP phase of RPM building"), + ('build-script=', None, "Specify a script for the BUILD phase of RPM building"), + ( + 'pre-install=', + None, + "Specify a script for the pre-INSTALL phase of RPM building", + ), + ( + 'install-script=', + None, + "Specify a script for the INSTALL phase of RPM building", + ), + ( + 'post-install=', + None, + "Specify a script for the post-INSTALL phase of RPM building", + ), + ( + 'pre-uninstall=', + None, + "Specify a script for the pre-UNINSTALL phase of RPM building", + ), + ( + 'post-uninstall=', + None, + "Specify a script for the post-UNINSTALL phase of RPM building", + ), + ('clean-script=', None, "Specify a script for the CLEAN phase of RPM building"), + ( + 'verify-script=', + None, + "Specify a script for the VERIFY phase of the RPM build", + ), # Allow a packager to explicitly force an architecture - ('force-arch=', None, - "Force an architecture onto the RPM build process"), - - ('quiet', 'q', - "Run the INSTALL phase of RPM building in quiet mode"), - ] - - boolean_options = ['keep-temp', 'use-rpm-opt-flags', 'rpm3-mode', - 'no-autoreq', 'quiet'] - - negative_opt = {'no-keep-temp': 'keep-temp', - 'no-rpm-opt-flags': 'use-rpm-opt-flags', - 'rpm2-mode': 'rpm3-mode'} - + ('force-arch=', None, "Force an architecture onto the RPM build process"), + ('quiet', 'q', "Run the INSTALL phase of RPM building in quiet mode"), + ] + + boolean_options = [ + 'keep-temp', + 'use-rpm-opt-flags', + 'rpm3-mode', + 'no-autoreq', + 'quiet', + ] + + negative_opt = { + 'no-keep-temp': 'keep-temp', + 'no-rpm-opt-flags': 'use-rpm-opt-flags', + 'rpm2-mode': 'rpm3-mode', + } def initialize_options(self): self.bdist_base = None @@ -181,8 +192,7 @@ def finalize_options(self): self.set_undefined_options('bdist', ('bdist_base', 'bdist_base')) if self.rpm_base is None: if not self.rpm3_mode: - raise DistutilsOptionError( - "you must specify --rpm-base in RPM 2 mode") + raise DistutilsOptionError("you must specify --rpm-base in RPM 2 mode") self.rpm_base = os.path.join(self.bdist_base, "rpm") if self.python is None: @@ -192,14 +202,17 @@ def finalize_options(self): self.python = "python3" elif self.fix_python: raise DistutilsOptionError( - "--python and --fix-python are mutually exclusive options") + "--python and --fix-python are mutually exclusive options" + ) if os.name != 'posix': - raise DistutilsPlatformError("don't know how to create RPM " - "distributions on platform %s" % os.name) + raise DistutilsPlatformError( + "don't know how to create RPM " "distributions on platform %s" % os.name + ) if self.binary_only and self.source_only: raise DistutilsOptionError( - "cannot supply both '--source-only' and '--binary-only'") + "cannot supply both '--source-only' and '--binary-only'" + ) # don't pass CFLAGS to pure python distributions if not self.distribution.has_ext_modules(): @@ -210,9 +223,11 @@ def finalize_options(self): def finalize_package_data(self): self.ensure_string('group', "Development/Libraries") - self.ensure_string('vendor', - "%s <%s>" % (self.distribution.get_contact(), - self.distribution.get_contact_email())) + self.ensure_string( + 'vendor', + "%s <%s>" + % (self.distribution.get_contact(), self.distribution.get_contact_email()), + ) self.ensure_string('packager') self.ensure_string_list('doc_files') if isinstance(self.doc_files, list): @@ -221,12 +236,12 @@ def finalize_package_data(self): self.doc_files.append(readme) self.ensure_string('release', "1") - self.ensure_string('serial') # should it be an int? + self.ensure_string('serial') # should it be an int? self.ensure_string('distribution_name') self.ensure_string('changelog') - # Format changelog correctly + # Format changelog correctly self.changelog = self._format_changelog(self.changelog) self.ensure_filename('icon') @@ -274,14 +289,12 @@ def run(self): # Spec file goes into 'dist_dir' if '--spec-only specified', # build/rpm. otherwise. - spec_path = os.path.join(spec_dir, - "%s.spec" % self.distribution.get_name()) - self.execute(write_file, - (spec_path, - self._make_spec_file()), - "writing '%s'" % spec_path) - - if self.spec_only: # stop if requested + spec_path = os.path.join(spec_dir, "%s.spec" % self.distribution.get_name()) + self.execute( + write_file, (spec_path, self._make_spec_file()), "writing '%s'" % spec_path + ) + + if self.spec_only: # stop if requested return # Make a source distribution and copy to SOURCES directory with @@ -303,14 +316,13 @@ def run(self): if os.path.exists(self.icon): self.copy_file(self.icon, source_dir) else: - raise DistutilsFileError( - "icon file '%s' does not exist" % self.icon) + raise DistutilsFileError("icon file '%s' does not exist" % self.icon) # build package log.info("building RPMs") rpm_cmd = ['rpmbuild'] - if self.source_only: # what kind of RPMs? + if self.source_only: # what kind of RPMs? rpm_cmd.append('-bs') elif self.binary_only: rpm_cmd.append('-bb') @@ -318,8 +330,7 @@ def run(self): rpm_cmd.append('-ba') rpm_cmd.extend(['--define', '__python %s' % self.python]) if self.rpm3_mode: - rpm_cmd.extend(['--define', - '_topdir %s' % os.path.abspath(self.rpm_base)]) + rpm_cmd.extend(['--define', '_topdir %s' % os.path.abspath(self.rpm_base)]) if not self.keep_temp: rpm_cmd.append('--clean') @@ -335,7 +346,10 @@ def run(self): src_rpm = nvr_string + ".src.rpm" non_src_rpm = "%{arch}/" + nvr_string + ".%{arch}.rpm" q_cmd = r"rpm -q --qf '%s %s\n' --specfile '%s'" % ( - src_rpm, non_src_rpm, spec_path) + src_rpm, + non_src_rpm, + spec_path, + ) out = os.popen(q_cmd) try: @@ -346,7 +360,7 @@ def run(self): if not line: break l = line.strip().split() - assert(len(l) == 2) + assert len(l) == 2 binary_rpms.append(l[1]) # The source rpm is named after the first entry in the spec file if source_rpm is None: @@ -369,21 +383,20 @@ def run(self): if not self.binary_only: srpm = os.path.join(rpm_dir['SRPMS'], source_rpm) - assert(os.path.exists(srpm)) + assert os.path.exists(srpm) self.move_file(srpm, self.dist_dir) filename = os.path.join(self.dist_dir, source_rpm) - self.distribution.dist_files.append( - ('bdist_rpm', pyversion, filename)) + self.distribution.dist_files.append(('bdist_rpm', pyversion, filename)) if not self.source_only: for rpm in binary_rpms: rpm = os.path.join(rpm_dir['RPMS'], rpm) if os.path.exists(rpm): self.move_file(rpm, self.dist_dir) - filename = os.path.join(self.dist_dir, - os.path.basename(rpm)) + filename = os.path.join(self.dist_dir, os.path.basename(rpm)) self.distribution.dist_files.append( - ('bdist_rpm', pyversion, filename)) + ('bdist_rpm', pyversion, filename) + ) def _dist_path(self, path): return os.path.join(self.dist_dir, os.path.basename(path)) @@ -395,12 +408,12 @@ def _make_spec_file(self): # definitions and headers spec_file = [ '%define name ' + self.distribution.get_name(), - '%define version ' + self.distribution.get_version().replace('-','_'), + '%define version ' + self.distribution.get_version().replace('-', '_'), '%define unmangled_version ' + self.distribution.get_version(), - '%define release ' + self.release.replace('-','_'), + '%define release ' + self.release.replace('-', '_'), '', 'Summary: ' + self.distribution.get_description(), - ] + ] # Workaround for #14443 which affects some RPM based systems such as # RHEL6 (and probably derivatives) @@ -408,8 +421,9 @@ def _make_spec_file(self): # Generate a potential replacement value for __os_install_post (whilst # normalizing the whitespace to simplify the test for whether the # invocation of brp-python-bytecompile passes in __python): - vendor_hook = '\n'.join([' %s \\' % line.strip() - for line in vendor_hook.splitlines()]) + vendor_hook = '\n'.join( + [' %s \\' % line.strip() for line in vendor_hook.splitlines()] + ) problem = "brp-python-bytecompile \\\n" fixed = "brp-python-bytecompile %{__python} \\\n" fixed_hook = vendor_hook.replace(problem, fixed) @@ -420,14 +434,17 @@ def _make_spec_file(self): # put locale summaries into spec file # XXX not supported for now (hard to put a dictionary # in a config file -- arg!) - #for locale in self.summaries.keys(): + # for locale in self.summaries.keys(): # spec_file.append('Summary(%s): %s' % (locale, # self.summaries[locale])) - spec_file.extend([ - 'Name: %{name}', - 'Version: %{version}', - 'Release: %{release}',]) + spec_file.extend( + [ + 'Name: %{name}', + 'Version: %{version}', + 'Release: %{release}', + ] + ) # XXX yuck! this filename is available from the "sdist" command, # but only after it has run: and we create the spec file before @@ -437,33 +454,36 @@ def _make_spec_file(self): else: spec_file.append('Source0: %{name}-%{unmangled_version}.tar.gz') - spec_file.extend([ - 'License: ' + self.distribution.get_license(), - 'Group: ' + self.group, - 'BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot', - 'Prefix: %{_prefix}', ]) + spec_file.extend( + [ + 'License: ' + self.distribution.get_license(), + 'Group: ' + self.group, + 'BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot', + 'Prefix: %{_prefix}', + ] + ) if not self.force_arch: # noarch if no extension modules if not self.distribution.has_ext_modules(): spec_file.append('BuildArch: noarch') else: - spec_file.append( 'BuildArch: %s' % self.force_arch ) - - for field in ('Vendor', - 'Packager', - 'Provides', - 'Requires', - 'Conflicts', - 'Obsoletes', - ): + spec_file.append('BuildArch: %s' % self.force_arch) + + for field in ( + 'Vendor', + 'Packager', + 'Provides', + 'Requires', + 'Conflicts', + 'Obsoletes', + ): val = getattr(self, field.lower()) if isinstance(val, list): spec_file.append('%s: %s' % (field, ' '.join(val))) elif val is not None: spec_file.append('%s: %s' % (field, val)) - if self.distribution.get_url() != 'UNKNOWN': spec_file.append('Url: ' + self.distribution.get_url()) @@ -471,8 +491,7 @@ def _make_spec_file(self): spec_file.append('Distribution: ' + self.distribution_name) if self.build_requires: - spec_file.append('BuildRequires: ' + - ' '.join(self.build_requires)) + spec_file.append('BuildRequires: ' + ' '.join(self.build_requires)) if self.icon: spec_file.append('Icon: ' + os.path.basename(self.icon)) @@ -480,16 +499,12 @@ def _make_spec_file(self): if self.no_autoreq: spec_file.append('AutoReq: 0') - spec_file.extend([ - '', - '%description', - self.distribution.get_long_description() - ]) + spec_file.extend(['', '%description', self.distribution.get_long_description()]) # put locale descriptions into spec file # XXX again, suppressed because config file syntax doesn't # easily support this ;-( - #for locale in self.descriptions.keys(): + # for locale in self.descriptions.keys(): # spec_file.extend([ # '', # '%description -l ' + locale, @@ -498,7 +513,7 @@ def _make_spec_file(self): # rpm scripts # figure out default build script - def_setup_call = "%s %s" % (self.python,os.path.basename(sys.argv[0])) + def_setup_call = "%s %s" % (self.python, os.path.basename(sys.argv[0])) def_build = "%s build" % def_setup_call if self.use_rpm_opt_flags: def_build = 'env CFLAGS="$RPM_OPT_FLAGS" ' + def_build @@ -509,8 +524,9 @@ def _make_spec_file(self): # that we open and interpolate into the spec file, but the defaults # are just text that we drop in as-is. Hmmm. - install_cmd = ('%s install -O1 --root=$RPM_BUILD_ROOT ' - '--record=INSTALLED_FILES') % def_setup_call + install_cmd = ( + '%s install -O1 --root=$RPM_BUILD_ROOT ' '--record=INSTALLED_FILES' + ) % def_setup_call script_options = [ ('prep', 'prep_script', "%setup -n %{name}-%{unmangled_version}"), @@ -529,37 +545,43 @@ def _make_spec_file(self): # use 'default' as contents of script val = getattr(self, attr) if val or default: - spec_file.extend([ - '', - '%' + rpm_opt,]) + spec_file.extend( + [ + '', + '%' + rpm_opt, + ] + ) if val: with open(val) as f: spec_file.extend(f.read().split('\n')) else: spec_file.append(default) - # files section - spec_file.extend([ - '', - '%files -f INSTALLED_FILES', - '%defattr(-,root,root)', - ]) + spec_file.extend( + [ + '', + '%files -f INSTALLED_FILES', + '%defattr(-,root,root)', + ] + ) if self.doc_files: spec_file.append('%doc ' + ' '.join(self.doc_files)) if self.changelog: - spec_file.extend([ - '', - '%changelog',]) + spec_file.extend( + [ + '', + '%changelog', + ] + ) spec_file.extend(self.changelog) return spec_file def _format_changelog(self, changelog): - """Format the changelog correctly and convert it to a list of strings - """ + """Format the changelog correctly and convert it to a list of strings""" if not changelog: return changelog new_changelog = [] diff --git a/setuptools/_distutils/command/bdist_wininst.py b/setuptools/_distutils/command/bdist_wininst.py index 0e9ddaa2141..76b8a890df2 100644 --- a/setuptools/_distutils/command/bdist_wininst.py +++ b/setuptools/_distutils/command/bdist_wininst.py @@ -13,58 +13,88 @@ from distutils.sysconfig import get_python_version from distutils import log + class bdist_wininst(Command): description = "create an executable installer for MS Windows" - user_options = [('bdist-dir=', None, - "temporary directory for creating the distribution"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('target-version=', None, - "require a specific python version" + - " on the target system"), - ('no-target-compile', 'c', - "do not compile .py to .pyc on the target system"), - ('no-target-optimize', 'o', - "do not compile .py to .pyo (optimized) " - "on the target system"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('bitmap=', 'b', - "bitmap to use for the installer instead of python-powered logo"), - ('title=', 't', - "title to display on the installer background instead of default"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('install-script=', None, - "basename of installation script to be run after " - "installation or before deinstallation"), - ('pre-install-script=', None, - "Fully qualified filename of a script to be run before " - "any files are installed. This script need not be in the " - "distribution"), - ('user-access-control=', None, - "specify Vista's UAC handling - 'none'/default=no " - "handling, 'auto'=use UAC if target Python installed for " - "all users, 'force'=always use UAC"), - ] - - boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', - 'skip-build'] + user_options = [ + ('bdist-dir=', None, "temporary directory for creating the distribution"), + ( + 'plat-name=', + 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform(), + ), + ( + 'keep-temp', + 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive", + ), + ( + 'target-version=', + None, + "require a specific python version" + " on the target system", + ), + ('no-target-compile', 'c', "do not compile .py to .pyc on the target system"), + ( + 'no-target-optimize', + 'o', + "do not compile .py to .pyo (optimized) " "on the target system", + ), + ('dist-dir=', 'd', "directory to put final built distributions in"), + ( + 'bitmap=', + 'b', + "bitmap to use for the installer instead of python-powered logo", + ), + ( + 'title=', + 't', + "title to display on the installer background instead of default", + ), + ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), + ( + 'install-script=', + None, + "basename of installation script to be run after " + "installation or before deinstallation", + ), + ( + 'pre-install-script=', + None, + "Fully qualified filename of a script to be run before " + "any files are installed. This script need not be in the " + "distribution", + ), + ( + 'user-access-control=', + None, + "specify Vista's UAC handling - 'none'/default=no " + "handling, 'auto'=use UAC if target Python installed for " + "all users, 'force'=always use UAC", + ), + ] + + boolean_options = [ + 'keep-temp', + 'no-target-compile', + 'no-target-optimize', + 'skip-build', + ] # bpo-10945: bdist_wininst requires mbcs encoding only available on Windows - _unsupported = (sys.platform != "win32") + _unsupported = sys.platform != "win32" def __init__(self, *args, **kw): super().__init__(*args, **kw) - warnings.warn("bdist_wininst command is deprecated since Python 3.8, " - "use bdist_wheel (wheel packages) instead", - DeprecationWarning, 2) + warnings.warn( + "bdist_wininst command is deprecated since Python 3.8, " + "use bdist_wheel (wheel packages) instead", + DeprecationWarning, + 2, + ) def initialize_options(self): self.bdist_dir = None @@ -81,7 +111,6 @@ def initialize_options(self): self.pre_install_script = None self.user_access_control = None - def finalize_options(self): self.set_undefined_options('bdist', ('skip_build', 'skip_build')) @@ -102,14 +131,16 @@ def finalize_options(self): short_version = get_python_version() if self.target_version and self.target_version != short_version: raise DistutilsOptionError( - "target version can only be %s, or the '--skip-build'" \ - " option must be specified" % (short_version,)) + "target version can only be %s, or the '--skip-build'" + " option must be specified" % (short_version,) + ) self.target_version = short_version - self.set_undefined_options('bdist', - ('dist_dir', 'dist_dir'), - ('plat_name', 'plat_name'), - ) + self.set_undefined_options( + 'bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ) if self.install_script: for script in self.distribution.scripts: @@ -117,16 +148,17 @@ def finalize_options(self): break else: raise DistutilsOptionError( - "install_script '%s' not found in scripts" - % self.install_script) + "install_script '%s' not found in scripts" % self.install_script + ) def run(self): - if (sys.platform != "win32" and - (self.distribution.has_ext_modules() or - self.distribution.has_c_libraries())): - raise DistutilsPlatformError \ - ("distribution contains extensions and/or C libraries; " - "must be compiled on a Windows 32 platform") + if sys.platform != "win32" and ( + self.distribution.has_ext_modules() or self.distribution.has_c_libraries() + ): + raise DistutilsPlatformError( + "distribution contains extensions and/or C libraries; " + "must be compiled on a Windows 32 platform" + ) if not self.skip_build: self.run_command('build') @@ -155,8 +187,7 @@ def run(self): target_version = '%d.%d' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') - build.build_lib = os.path.join(build.build_base, - 'lib' + plat_specifier) + build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) # Use a custom scheme for the zip-file, because we have to decide # at installation time which scheme to use. @@ -164,9 +195,7 @@ def run(self): value = key.upper() if key == 'headers': value = value + '/Include/$dist_name' - setattr(install, - 'install_' + key, - value) + setattr(install, 'install_' + key, value) log.info("installing to %s", self.bdist_dir) install.ensure_finalized() @@ -182,18 +211,19 @@ def run(self): # And make an archive relative to the root of the # pseudo-installation tree. from tempfile import mktemp + archive_basename = mktemp() fullname = self.distribution.get_fullname() - arcname = self.make_archive(archive_basename, "zip", - root_dir=self.bdist_dir) + arcname = self.make_archive(archive_basename, "zip", root_dir=self.bdist_dir) # create an exe containing the zip-file self.create_exe(arcname, fullname, self.bitmap) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' - self.distribution.dist_files.append(('bdist_wininst', pyversion, - self.get_installer_filename(fullname))) + self.distribution.dist_files.append( + ('bdist_wininst', pyversion, self.get_installer_filename(fullname)) + ) # remove the zip-file again log.debug("removing temporary file '%s'", arcname) os.remove(arcname) @@ -217,12 +247,19 @@ def get_inidata(self): def escape(s): return s.replace("\n", "\\n") - for name in ["author", "author_email", "description", "maintainer", - "maintainer_email", "name", "url", "version"]: + for name in [ + "author", + "author_email", + "description", + "maintainer", + "maintainer_email", + "name", + "url", + "version", + ]: data = getattr(metadata, name, "") if data: - info = info + ("\n %s: %s" % \ - (name.capitalize(), escape(data))) + info = info + ("\n %s: %s" % (name.capitalize(), escape(data))) lines.append("%s=%s" % (name, escape(data))) # The [setup] section contains entries controlling @@ -242,8 +279,11 @@ def escape(s): lines.append("title=%s" % escape(title)) import time import distutils - build_info = "Built %s with distutils-%s" % \ - (time.ctime(time.time()), distutils.__version__) + + build_info = "Built %s with distutils-%s" % ( + time.ctime(time.time()), + distutils.__version__, + ) lines.append("build_info=%s" % build_info) return "\n".join(lines) @@ -279,8 +319,7 @@ def create_exe(self, arcname, fullname, bitmap=None): # We need to normalize newlines, so we open in text mode and # convert back to bytes. "latin-1" simply avoids any possible # failures. - with open(self.pre_install_script, "r", - encoding="latin-1") as script: + with open(self.pre_install_script, "r", encoding="latin-1") as script: script_data = script.read().encode("latin-1") cfgdata = cfgdata + script_data + b"\n\0" else: @@ -293,11 +332,12 @@ def create_exe(self, arcname, fullname, bitmap=None): # expects. If the layout changes, increment that number, make # the corresponding changes to the wininst.exe sources, and # recompile them. - header = struct.pack("" if self.build_temp is None: - self.build_temp = os.path.join(self.build_base, - 'temp' + plat_specifier) + self.build_temp = os.path.join(self.build_base, 'temp' + plat_specifier) if self.build_scripts is None: - self.build_scripts = os.path.join(self.build_base, - 'scripts-%d.%d' % sys.version_info[:2]) + self.build_scripts = os.path.join( + self.build_base, 'scripts-%d.%d' % sys.version_info[:2] + ) if self.executable is None and sys.executable: self.executable = os.path.normpath(sys.executable) @@ -134,7 +130,6 @@ def run(self): for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) - # -- Predicates for the sub-command list --------------------------- def has_pure_modules(self): @@ -149,9 +144,9 @@ def has_ext_modules(self): def has_scripts(self): return self.distribution.has_scripts() - - sub_commands = [('build_py', has_pure_modules), - ('build_clib', has_c_libraries), - ('build_ext', has_ext_modules), - ('build_scripts', has_scripts), - ] + sub_commands = [ + ('build_py', has_pure_modules), + ('build_clib', has_c_libraries), + ('build_ext', has_ext_modules), + ('build_scripts', has_scripts), + ] diff --git a/setuptools/_distutils/command/build_clib.py b/setuptools/_distutils/command/build_clib.py index 3e20ef23cd8..003499fa976 100644 --- a/setuptools/_distutils/command/build_clib.py +++ b/setuptools/_distutils/command/build_clib.py @@ -20,8 +20,10 @@ from distutils.sysconfig import customize_compiler from distutils import log + def show_compilers(): from distutils.ccompiler import show_compilers + show_compilers() @@ -30,24 +32,18 @@ class build_clib(Command): description = "build C/C++ libraries used by Python extensions" user_options = [ - ('build-clib=', 'b', - "directory to build C/C++ libraries to"), - ('build-temp=', 't', - "directory to put temporary build by-products"), - ('debug', 'g', - "compile with debugging information"), - ('force', 'f', - "forcibly build everything (ignore file timestamps)"), - ('compiler=', 'c', - "specify the compiler type"), - ] + ('build-clib=', 'b', "directory to build C/C++ libraries to"), + ('build-temp=', 't', "directory to put temporary build by-products"), + ('debug', 'g', "compile with debugging information"), + ('force', 'f', "forcibly build everything (ignore file timestamps)"), + ('compiler=', 'c', "specify the compiler type"), + ] boolean_options = ['debug', 'force'] help_options = [ - ('help-compiler', None, - "list available compilers", show_compilers), - ] + ('help-compiler', None, "list available compilers", show_compilers), + ] def initialize_options(self): self.build_clib = None @@ -64,19 +60,20 @@ def initialize_options(self): self.force = 0 self.compiler = None - def finalize_options(self): # This might be confusing: both build-clib and build-temp default # to build-temp as defined by the "build" command. This is because # I think that C libraries are really just temporary build # by-products, at least from the point of view of building Python # extensions -- but I want to keep my options open. - self.set_undefined_options('build', - ('build_temp', 'build_clib'), - ('build_temp', 'build_temp'), - ('compiler', 'compiler'), - ('debug', 'debug'), - ('force', 'force')) + self.set_undefined_options( + 'build', + ('build_temp', 'build_clib'), + ('build_temp', 'build_temp'), + ('compiler', 'compiler'), + ('debug', 'debug'), + ('force', 'force'), + ) self.libraries = self.distribution.libraries if self.libraries: @@ -90,23 +87,23 @@ def finalize_options(self): # XXX same as for build_ext -- what about 'self.define' and # 'self.undef' ? - def run(self): if not self.libraries: return # Yech -- this is cut 'n pasted from build_ext.py! from distutils.ccompiler import new_compiler - self.compiler = new_compiler(compiler=self.compiler, - dry_run=self.dry_run, - force=self.force) + + self.compiler = new_compiler( + compiler=self.compiler, dry_run=self.dry_run, force=self.force + ) customize_compiler(self.compiler) if self.include_dirs is not None: self.compiler.set_include_dirs(self.include_dirs) if self.define is not None: # 'define' option is a list of (name,value) tuples - for (name,value) in self.define: + for (name, value) in self.define: self.compiler.define_macro(name, value) if self.undef is not None: for macro in self.undef: @@ -114,7 +111,6 @@ def run(self): self.build_libraries(self.libraries) - def check_library_list(self, libraries): """Ensure that the list of libraries is valid. @@ -126,30 +122,31 @@ def check_library_list(self, libraries): just returns otherwise. """ if not isinstance(libraries, list): - raise DistutilsSetupError( - "'libraries' option must be a list of tuples") + raise DistutilsSetupError("'libraries' option must be a list of tuples") for lib in libraries: if not isinstance(lib, tuple) and len(lib) != 2: - raise DistutilsSetupError( - "each element of 'libraries' must a 2-tuple") + raise DistutilsSetupError("each element of 'libraries' must a 2-tuple") name, build_info = lib if not isinstance(name, str): raise DistutilsSetupError( - "first element of each tuple in 'libraries' " - "must be a string (the library name)") + "first element of each tuple in 'libraries' " + "must be a string (the library name)" + ) if '/' in name or (os.sep != '/' and os.sep in name): - raise DistutilsSetupError("bad library name '%s': " - "may not contain directory separators" % lib[0]) + raise DistutilsSetupError( + "bad library name '%s': " + "may not contain directory separators" % lib[0] + ) if not isinstance(build_info, dict): raise DistutilsSetupError( - "second element of each tuple in 'libraries' " - "must be a dictionary (build info)") - + "second element of each tuple in 'libraries' " + "must be a dictionary (build info)" + ) def get_library_names(self): # Assume the library list is valid -- 'check_library_list()' is @@ -162,7 +159,6 @@ def get_library_names(self): lib_names.append(lib_name) return lib_names - def get_source_files(self): self.check_library_list(self.libraries) filenames = [] @@ -170,22 +166,23 @@ def get_source_files(self): sources = build_info.get('sources') if sources is None or not isinstance(sources, (list, tuple)): raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'sources' must be present and must be " - "a list of source filenames" % lib_name) + "in 'libraries' option (library '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % lib_name + ) filenames.extend(sources) return filenames - def build_libraries(self, libraries): for (lib_name, build_info) in libraries: sources = build_info.get('sources') if sources is None or not isinstance(sources, (list, tuple)): raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'sources' must be present and must be " - "a list of source filenames" % lib_name) + "in 'libraries' option (library '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % lib_name + ) sources = list(sources) log.info("building '%s' library", lib_name) @@ -195,15 +192,17 @@ def build_libraries(self, libraries): # files in a temporary build directory.) macros = build_info.get('macros') include_dirs = build_info.get('include_dirs') - objects = self.compiler.compile(sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=include_dirs, - debug=self.debug) + objects = self.compiler.compile( + sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + ) # Now "link" the object files together into a static library. # (On Unix at least, this isn't really linking -- it just # builds an archive. Whatever.) - self.compiler.create_static_lib(objects, lib_name, - output_dir=self.build_clib, - debug=self.debug) + self.compiler.create_static_lib( + objects, lib_name, output_dir=self.build_clib, debug=self.debug + ) diff --git a/setuptools/_distutils/command/build_ext.py b/setuptools/_distutils/command/build_ext.py index f7ab32cfe1d..4a171ded417 100644 --- a/setuptools/_distutils/command/build_ext.py +++ b/setuptools/_distutils/command/build_ext.py @@ -22,12 +22,12 @@ # An extension name is just a dot-separated list of Python NAMEs (ie. # the same as a fully-qualified module name). -extension_name_re = re.compile \ - (r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$') +extension_name_re = re.compile(r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$') -def show_compilers (): +def show_compilers(): from distutils.ccompiler import show_compilers + show_compilers() @@ -55,54 +55,50 @@ class build_ext(Command): sep_by = " (separated by '%s')" % os.pathsep user_options = [ - ('build-lib=', 'b', - "directory for compiled extension modules"), - ('build-temp=', 't', - "directory for temporary files (build by-products)"), - ('plat-name=', 'p', - "platform name to cross-compile for, if supported " - "(default: %s)" % get_platform()), - ('inplace', 'i', - "ignore build-lib and put compiled extensions into the source " + - "directory alongside your pure Python modules"), - ('include-dirs=', 'I', - "list of directories to search for header files" + sep_by), - ('define=', 'D', - "C preprocessor macros to define"), - ('undef=', 'U', - "C preprocessor macros to undefine"), - ('libraries=', 'l', - "external C libraries to link with"), - ('library-dirs=', 'L', - "directories to search for external C libraries" + sep_by), - ('rpath=', 'R', - "directories to search for shared C libraries at runtime"), - ('link-objects=', 'O', - "extra explicit link objects to include in the link"), - ('debug', 'g', - "compile/link with debugging information"), - ('force', 'f', - "forcibly build everything (ignore file timestamps)"), - ('compiler=', 'c', - "specify the compiler type"), - ('parallel=', 'j', - "number of parallel build jobs"), - ('swig-cpp', None, - "make SWIG create C++ files (default is C)"), - ('swig-opts=', None, - "list of SWIG command line options"), - ('swig=', None, - "path to the SWIG executable"), - ('user', None, - "add user include, library and rpath") - ] + ('build-lib=', 'b', "directory for compiled extension modules"), + ('build-temp=', 't', "directory for temporary files (build by-products)"), + ( + 'plat-name=', + 'p', + "platform name to cross-compile for, if supported " + "(default: %s)" % get_platform(), + ), + ( + 'inplace', + 'i', + "ignore build-lib and put compiled extensions into the source " + + "directory alongside your pure Python modules", + ), + ( + 'include-dirs=', + 'I', + "list of directories to search for header files" + sep_by, + ), + ('define=', 'D', "C preprocessor macros to define"), + ('undef=', 'U', "C preprocessor macros to undefine"), + ('libraries=', 'l', "external C libraries to link with"), + ( + 'library-dirs=', + 'L', + "directories to search for external C libraries" + sep_by, + ), + ('rpath=', 'R', "directories to search for shared C libraries at runtime"), + ('link-objects=', 'O', "extra explicit link objects to include in the link"), + ('debug', 'g', "compile/link with debugging information"), + ('force', 'f', "forcibly build everything (ignore file timestamps)"), + ('compiler=', 'c', "specify the compiler type"), + ('parallel=', 'j', "number of parallel build jobs"), + ('swig-cpp', None, "make SWIG create C++ files (default is C)"), + ('swig-opts=', None, "list of SWIG command line options"), + ('swig=', None, "path to the SWIG executable"), + ('user', None, "add user include, library and rpath"), + ] boolean_options = ['inplace', 'debug', 'force', 'swig-cpp', 'user'] help_options = [ - ('help-compiler', None, - "list available compilers", show_compilers), - ] + ('help-compiler', None, "list available compilers", show_compilers), + ] def initialize_options(self): self.extensions = None @@ -131,15 +127,16 @@ def initialize_options(self): def finalize_options(self): from distutils import sysconfig - self.set_undefined_options('build', - ('build_lib', 'build_lib'), - ('build_temp', 'build_temp'), - ('compiler', 'compiler'), - ('debug', 'debug'), - ('force', 'force'), - ('parallel', 'parallel'), - ('plat_name', 'plat_name'), - ) + self.set_undefined_options( + 'build', + ('build_lib', 'build_lib'), + ('build_temp', 'build_temp'), + ('compiler', 'compiler'), + ('debug', 'debug'), + ('force', 'force'), + ('parallel', 'parallel'), + ('plat_name', 'plat_name'), + ) if self.package is None: self.package = self.distribution.ext_package @@ -164,8 +161,7 @@ def finalize_options(self): # any local include dirs take precedence. self.include_dirs.extend(py_include.split(os.path.pathsep)) if plat_py_include != py_include: - self.include_dirs.extend( - plat_py_include.split(os.path.pathsep)) + self.include_dirs.extend(plat_py_include.split(os.path.pathsep)) self.ensure_string_list('libraries') self.ensure_string_list('link_objects') @@ -222,9 +218,11 @@ def finalize_options(self): if sys.platform[:6] == 'cygwin': if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")): # building third party extensions - self.library_dirs.append(os.path.join(sys.prefix, "lib", - "python" + get_python_version(), - "config")) + self.library_dirs.append( + os.path.join( + sys.prefix, "lib", "python" + get_python_version(), "config" + ) + ) else: # building python standard extensions self.library_dirs.append('.') @@ -232,7 +230,7 @@ def finalize_options(self): # For building extensions with a shared Python library, # Python's library directory must be appended to library_dirs # See Issues: #1600860, #4366 - if (sysconfig.get_config_var('Py_ENABLE_SHARED')): + if sysconfig.get_config_var('Py_ENABLE_SHARED'): if not sysconfig.python_build: # building third party extensions self.library_dirs.append(sysconfig.get_config_var('LIBDIR')) @@ -304,10 +302,12 @@ def run(self): # Setup the CCompiler object that we'll use to do all the # compiling and linking - self.compiler = new_compiler(compiler=self.compiler, - verbose=self.verbose, - dry_run=self.dry_run, - force=self.force) + self.compiler = new_compiler( + compiler=self.compiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + ) customize_compiler(self.compiler) # If we are cross-compiling, init the compiler now (if we are not # cross-compiling, init would not hurt, but people may rely on @@ -352,34 +352,40 @@ def check_extensions_list(self, extensions): """ if not isinstance(extensions, list): raise DistutilsSetupError( - "'ext_modules' option must be a list of Extension instances") + "'ext_modules' option must be a list of Extension instances" + ) for i, ext in enumerate(extensions): if isinstance(ext, Extension): - continue # OK! (assume type-checking done - # by Extension constructor) + continue # OK! (assume type-checking done + # by Extension constructor) if not isinstance(ext, tuple) or len(ext) != 2: raise DistutilsSetupError( - "each element of 'ext_modules' option must be an " - "Extension instance or 2-tuple") + "each element of 'ext_modules' option must be an " + "Extension instance or 2-tuple" + ) ext_name, build_info = ext - log.warn("old-style (ext_name, build_info) tuple found in " - "ext_modules for extension '%s' " - "-- please convert to Extension instance", ext_name) + log.warn( + "old-style (ext_name, build_info) tuple found in " + "ext_modules for extension '%s' " + "-- please convert to Extension instance", + ext_name, + ) - if not (isinstance(ext_name, str) and - extension_name_re.match(ext_name)): + if not (isinstance(ext_name, str) and extension_name_re.match(ext_name)): raise DistutilsSetupError( - "first element of each tuple in 'ext_modules' " - "must be the extension name (a string)") + "first element of each tuple in 'ext_modules' " + "must be the extension name (a string)" + ) if not isinstance(build_info, dict): raise DistutilsSetupError( - "second element of each tuple in 'ext_modules' " - "must be a dictionary (build info)") + "second element of each tuple in 'ext_modules' " + "must be a dictionary (build info)" + ) # OK, the (ext_name, build_info) dict is type-safe: convert it # to an Extension instance. @@ -387,9 +393,14 @@ def check_extensions_list(self, extensions): # Easy stuff: one-to-one mapping from dict elements to # instance attributes. - for key in ('include_dirs', 'library_dirs', 'libraries', - 'extra_objects', 'extra_compile_args', - 'extra_link_args'): + for key in ( + 'include_dirs', + 'library_dirs', + 'libraries', + 'extra_objects', + 'extra_compile_args', + 'extra_link_args', + ): val = build_info.get(key) if val is not None: setattr(ext, key, val) @@ -397,8 +408,7 @@ def check_extensions_list(self, extensions): # Medium-easy stuff: same syntax/semantics, different names. ext.runtime_library_dirs = build_info.get('rpath') if 'def_file' in build_info: - log.warn("'def_file' element of build info dict " - "no longer supported") + log.warn("'def_file' element of build info dict " "no longer supported") # Non-trivial stuff: 'macros' split into 'define_macros' # and 'undef_macros'. @@ -409,8 +419,9 @@ def check_extensions_list(self, extensions): for macro in macros: if not (isinstance(macro, tuple) and len(macro) in (1, 2)): raise DistutilsSetupError( - "'macros' element of build info dict " - "must be 1- or 2-tuple") + "'macros' element of build info dict " + "must be 1- or 2-tuple" + ) if len(macro) == 1: ext.undef_macros.append(macro[0]) elif len(macro) == 2: @@ -463,8 +474,9 @@ def _build_extensions_parallel(self): return with ThreadPoolExecutor(max_workers=workers) as executor: - futures = [executor.submit(self.build_extension, ext) - for ext in self.extensions] + futures = [ + executor.submit(self.build_extension, ext) for ext in self.extensions + ] for ext, fut in zip(self.extensions, futures): with self._filter_build_errors(ext): fut.result() @@ -481,16 +493,16 @@ def _filter_build_errors(self, ext): except (CCompilerError, DistutilsError, CompileError) as e: if not ext.optional: raise - self.warn('building extension "%s" failed: %s' % - (ext.name, e)) + self.warn('building extension "%s" failed: %s' % (ext.name, e)) def build_extension(self, ext): sources = ext.sources if sources is None or not isinstance(sources, (list, tuple)): raise DistutilsSetupError( - "in 'ext_modules' option (extension '%s'), " - "'sources' must be present and must be " - "a list of source filenames" % ext.name) + "in 'ext_modules' option (extension '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % ext.name + ) # sort to make the resulting .so file build reproducible sources = sorted(sources) @@ -527,13 +539,15 @@ def build_extension(self, ext): for undef in ext.undef_macros: macros.append((undef,)) - objects = self.compiler.compile(sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=ext.include_dirs, - debug=self.debug, - extra_postargs=extra_args, - depends=ext.depends) + objects = self.compiler.compile( + sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=ext.include_dirs, + debug=self.debug, + extra_postargs=extra_args, + depends=ext.depends, + ) # XXX outdated variable, kept here in case third-part code # needs it. @@ -550,7 +564,8 @@ def build_extension(self, ext): language = ext.language or self.compiler.detect_language(sources) self.compiler.link_shared_object( - objects, ext_path, + objects, + ext_path, libraries=self.get_libraries(ext), library_dirs=ext.library_dirs, runtime_library_dirs=ext.runtime_library_dirs, @@ -558,7 +573,8 @@ def build_extension(self, ext): export_symbols=self.get_export_symbols(ext), debug=self.debug, build_temp=self.build_temp, - target_lang=language) + target_lang=language, + ) def swig_sources(self, sources, extension): """Walk the list of source files in 'sources', looking for SWIG @@ -578,15 +594,18 @@ def swig_sources(self, sources, extension): if self.swig_cpp: log.warn("--swig-cpp is deprecated - use --swig-opts=-c++") - if self.swig_cpp or ('-c++' in self.swig_opts) or \ - ('-c++' in extension.swig_opts): + if ( + self.swig_cpp + or ('-c++' in self.swig_opts) + or ('-c++' in extension.swig_opts) + ): target_ext = '.cpp' else: target_ext = '.c' for source in sources: (base, ext) = os.path.splitext(source) - if ext == ".i": # SWIG interface file + if ext == ".i": # SWIG interface file new_sources.append(base + '_wrap' + target_ext) swig_sources.append(source) swig_targets[source] = new_sources[-1] @@ -633,8 +652,9 @@ def find_swig(self): return "swig.exe" else: raise DistutilsPlatformError( - "I don't know how to find (much less run) SWIG " - "on platform '%s'" % os.name) + "I don't know how to find (much less run) SWIG " + "on platform '%s'" % os.name + ) # -- Name generators ----------------------------------------------- # (extension names, filenames, whatever) @@ -652,7 +672,7 @@ def get_ext_fullpath(self, ext_name): # no further work needed # returning : # build_dir/package/path/filename - filename = os.path.join(*modpath[:-1]+[filename]) + filename = os.path.join(*modpath[:-1] + [filename]) return os.path.join(self.build_lib, filename) # the inplace option requires to find the package directory @@ -680,6 +700,7 @@ def get_ext_filename(self, ext_name): "foo\bar.pyd"). """ from distutils.sysconfig import get_config_var + ext_path = ext_name.split('.') ext_suffix = get_config_var('EXT_SUFFIX') return os.path.join(*ext_path) + ext_suffix @@ -717,12 +738,15 @@ def get_libraries(self, ext): # Append '_d' to the python import library on debug builds. if sys.platform == "win32": from distutils._msvccompiler import MSVCCompiler + if not isinstance(self.compiler, MSVCCompiler): template = "python%d%d" if self.debug: template = template + '_d' - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + pythonlib = template % ( + sys.hexversion >> 24, + (sys.hexversion >> 16) & 0xFF, + ) # don't extend ext.libraries, it may be shared with other # extensions, it is a reference to the original list return ext.libraries + [pythonlib] @@ -736,6 +760,7 @@ def get_libraries(self, ext): # Windows like MinGW) it is simply necessary that all symbols in # shared libraries are resolved at link time. from distutils.sysconfig import get_config_var + link_libpython = False if get_config_var('Py_ENABLE_SHARED'): # A native build on an Android device or on Cygwin diff --git a/setuptools/_distutils/command/build_py.py b/setuptools/_distutils/command/build_py.py index edc2171cd12..1b852d783e8 100644 --- a/setuptools/_distutils/command/build_py.py +++ b/setuptools/_distutils/command/build_py.py @@ -12,7 +12,8 @@ from distutils.util import convert_path, Mixin2to3 from distutils import log -class build_py (Command): + +class build_py(Command): description = "\"build\" pure Python modules (copy to build directory)" @@ -20,14 +21,17 @@ class build_py (Command): ('build-lib=', 'd', "directory to \"build\" (copy) to"), ('compile', 'c', "compile .py to .pyc"), ('no-compile', None, "don't compile .py files [default]"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ( + 'optimize=', + 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]", + ), ('force', 'f', "forcibly build everything (ignore file timestamps)"), - ] + ] boolean_options = ['compile', 'force'] - negative_opt = {'no-compile' : 'compile'} + negative_opt = {'no-compile': 'compile'} def initialize_options(self): self.build_lib = None @@ -40,9 +44,9 @@ def initialize_options(self): self.force = None def finalize_options(self): - self.set_undefined_options('build', - ('build_lib', 'build_lib'), - ('force', 'force')) + self.set_undefined_options( + 'build', ('build_lib', 'build_lib'), ('force', 'force') + ) # Get the distribution options that are aliases for build_py # options -- list of packages and list of modules. @@ -109,26 +113,26 @@ def get_data_files(self): # Length of path to strip from found files plen = 0 if src_dir: - plen = len(src_dir)+1 + plen = len(src_dir) + 1 # Strip directory from globbed filenames - filenames = [ - file[plen:] for file in self.find_data_files(package, src_dir) - ] + filenames = [file[plen:] for file in self.find_data_files(package, src_dir)] data.append((package, src_dir, build_dir, filenames)) return data def find_data_files(self, package, src_dir): """Return filenames for package's data files in 'src_dir'""" - globs = (self.package_data.get('', []) - + self.package_data.get(package, [])) + globs = self.package_data.get('', []) + self.package_data.get(package, []) files = [] for pattern in globs: # Each pattern has to be converted to a platform-specific path - filelist = glob.glob(os.path.join(glob.escape(src_dir), convert_path(pattern))) + filelist = glob.glob( + os.path.join(glob.escape(src_dir), convert_path(pattern)) + ) # Files that match more than one pattern are only added once - files.extend([fn for fn in filelist if fn not in files - and os.path.isfile(fn)]) + files.extend( + [fn for fn in filelist if fn not in files and os.path.isfile(fn)] + ) return files def build_package_data(self): @@ -138,13 +142,14 @@ def build_package_data(self): for filename in filenames: target = os.path.join(build_dir, filename) self.mkpath(os.path.dirname(target)) - self.copy_file(os.path.join(src_dir, filename), target, - preserve_mode=False) + self.copy_file( + os.path.join(src_dir, filename), target, preserve_mode=False + ) def get_package_dir(self, package): """Return the directory, relative to the top of the source - distribution, where package 'package' should be found - (at least according to the 'package_dir' option, if any).""" + distribution, where package 'package' should be found + (at least according to the 'package_dir' option, if any).""" path = package.split('.') if not self.package_dir: @@ -188,11 +193,13 @@ def check_package(self, package, package_dir): if package_dir != "": if not os.path.exists(package_dir): raise DistutilsFileError( - "package directory '%s' does not exist" % package_dir) + "package directory '%s' does not exist" % package_dir + ) if not os.path.isdir(package_dir): raise DistutilsFileError( - "supposed package directory '%s' exists, " - "but is not a directory" % package_dir) + "supposed package directory '%s' exists, " + "but is not a directory" % package_dir + ) # Require __init__.py for all but the "root package" if package: @@ -200,8 +207,10 @@ def check_package(self, package, package_dir): if os.path.isfile(init_py): return init_py else: - log.warn(("package init file '%s' not found " + - "(or not a regular file)"), init_py) + log.warn( + ("package init file '%s' not found " + "(or not a regular file)"), + init_py, + ) # Either not in a package at all (__init__.py not expected), or # __init__.py doesn't exist -- so don't return the filename. @@ -313,17 +322,21 @@ def get_outputs(self, include_bytecode=1): outputs.append(filename) if include_bytecode: if self.compile: - outputs.append(importlib.util.cache_from_source( - filename, optimization='')) + outputs.append( + importlib.util.cache_from_source(filename, optimization='') + ) if self.optimize > 0: - outputs.append(importlib.util.cache_from_source( - filename, optimization=self.optimize)) + outputs.append( + importlib.util.cache_from_source( + filename, optimization=self.optimize + ) + ) outputs += [ os.path.join(build_dir, filename) for package, src_dir, build_dir, filenames in self.data_files for filename in filenames - ] + ] return outputs @@ -332,7 +345,8 @@ def build_module(self, module, module_file, package): package = package.split('.') elif not isinstance(package, (list, tuple)): raise TypeError( - "'package' must be a string (dot-separated), list, or tuple") + "'package' must be a string (dot-separated), list, or tuple" + ) # Now put the module source file into the "build" area -- this is # easy, we just copy it somewhere under self.build_lib (the build @@ -377,6 +391,7 @@ def byte_compile(self, files): return from distutils.util import byte_compile + prefix = self.build_lib if prefix[-1] != os.sep: prefix = prefix + os.sep @@ -385,11 +400,18 @@ def byte_compile(self, files): # method of the "install_lib" command, except for the determination # of the 'prefix' string. Hmmm. if self.compile: - byte_compile(files, optimize=0, - force=self.force, prefix=prefix, dry_run=self.dry_run) + byte_compile( + files, optimize=0, force=self.force, prefix=prefix, dry_run=self.dry_run + ) if self.optimize > 0: - byte_compile(files, optimize=self.optimize, - force=self.force, prefix=prefix, dry_run=self.dry_run) + byte_compile( + files, + optimize=self.optimize, + force=self.force, + prefix=prefix, + dry_run=self.dry_run, + ) + class build_py_2to3(build_py, Mixin2to3): def run(self): diff --git a/setuptools/_distutils/command/build_scripts.py b/setuptools/_distutils/command/build_scripts.py index ccc70e64650..5901d9fc8cb 100644 --- a/setuptools/_distutils/command/build_scripts.py +++ b/setuptools/_distutils/command/build_scripts.py @@ -14,6 +14,7 @@ # check if Python is called on the first line with this expression first_line_re = re.compile(b'^#!.*python[0-9.]*([ \t].*)?$') + class build_scripts(Command): description = "\"build\" scripts (copy and fixup #! line)" @@ -22,11 +23,10 @@ class build_scripts(Command): ('build-dir=', 'd', "directory to \"build\" (copy) to"), ('force', 'f', "forcibly build everything (ignore file timestamps"), ('executable=', 'e', "specify final destination interpreter path"), - ] + ] boolean_options = ['force'] - def initialize_options(self): self.build_dir = None self.scripts = None @@ -35,10 +35,12 @@ def initialize_options(self): self.outfiles = None def finalize_options(self): - self.set_undefined_options('build', - ('build_scripts', 'build_dir'), - ('force', 'force'), - ('executable', 'executable')) + self.set_undefined_options( + 'build', + ('build_scripts', 'build_dir'), + ('force', 'force'), + ('executable', 'executable'), + ) self.scripts = self.distribution.scripts def get_source_files(self): @@ -49,7 +51,6 @@ def run(self): return self.copy_scripts() - def copy_scripts(self): r"""Copy each script listed in 'self.scripts'; if it's marked as a Python script in the Unix way (first line matches 'first_line_re', @@ -92,8 +93,7 @@ def copy_scripts(self): post_interp = match.group(1) or b'' if adjust: - log.info("copying and adjusting %s -> %s", script, - self.build_dir) + log.info("copying and adjusting %s -> %s", script, self.build_dir) updated_files.append(outfile) if not self.dry_run: if not sysconfig.python_build: @@ -101,8 +101,12 @@ def copy_scripts(self): else: executable = os.path.join( sysconfig.get_config_var("BINDIR"), - "python%s%s" % (sysconfig.get_config_var("VERSION"), - sysconfig.get_config_var("EXE"))) + "python%s%s" + % ( + sysconfig.get_config_var("VERSION"), + sysconfig.get_config_var("EXE"), + ), + ) executable = os.fsencode(executable) shebang = b"#!" + executable + post_interp + b"\n" # Python parser starts to read a script using UTF-8 until @@ -115,7 +119,8 @@ def copy_scripts(self): except UnicodeDecodeError: raise ValueError( "The shebang ({!r}) is not decodable " - "from utf-8".format(shebang)) + "from utf-8".format(shebang) + ) # If the script is encoded to a custom encoding (use a # #coding:xxx cookie), the shebang has to be decodable from # the script encoding too. @@ -124,8 +129,8 @@ def copy_scripts(self): except UnicodeDecodeError: raise ValueError( "The shebang ({!r}) is not decodable " - "from the script encoding ({})" - .format(shebang, encoding)) + "from the script encoding ({})".format(shebang, encoding) + ) with open(outfile, "wb") as outf: outf.write(shebang) outf.writelines(f.readlines()) @@ -145,14 +150,15 @@ def copy_scripts(self): oldmode = os.stat(file)[ST_MODE] & 0o7777 newmode = (oldmode | 0o555) & 0o7777 if newmode != oldmode: - log.info("changing mode of %s from %o to %o", - file, oldmode, newmode) + log.info( + "changing mode of %s from %o to %o", file, oldmode, newmode + ) os.chmod(file, newmode) # XXX should we modify self.outfiles? return outfiles, updated_files -class build_scripts_2to3(build_scripts, Mixin2to3): +class build_scripts_2to3(build_scripts, Mixin2to3): def copy_scripts(self): outfiles, updated_files = build_scripts.copy_scripts(self) if not self.dry_run: diff --git a/setuptools/_distutils/command/check.py b/setuptools/_distutils/command/check.py index ada25006467..c88f5fbe882 100644 --- a/setuptools/_distutils/command/check.py +++ b/setuptools/_distutils/command/check.py @@ -13,18 +13,33 @@ from docutils import nodes class SilentReporter(Reporter): - - def __init__(self, source, report_level, halt_level, stream=None, - debug=0, encoding='ascii', error_handler='replace'): + def __init__( + self, + source, + report_level, + halt_level, + stream=None, + debug=0, + encoding='ascii', + error_handler='replace', + ): self.messages = [] - Reporter.__init__(self, source, report_level, halt_level, stream, - debug, encoding, error_handler) + Reporter.__init__( + self, + source, + report_level, + halt_level, + stream, + debug, + encoding, + error_handler, + ) def system_message(self, level, message, *children, **kwargs): self.messages.append((level, message, children, kwargs)) - return nodes.system_message(message, level=level, - type=self.levels[level], - *children, **kwargs) + return nodes.system_message( + message, level=level, type=self.levels[level], *children, **kwargs + ) HAS_DOCUTILS = True except Exception: @@ -32,16 +47,23 @@ def system_message(self, level, message, *children, **kwargs): # indicate that docutils is not ported to Py3k. HAS_DOCUTILS = False + class check(Command): - """This command checks the meta-data of the package. - """ - description = ("perform some checks on the package") - user_options = [('metadata', 'm', 'Verify meta-data'), - ('restructuredtext', 'r', - ('Checks if long string meta-data syntax ' - 'are reStructuredText-compliant')), - ('strict', 's', - 'Will exit with an error if a check fails')] + """This command checks the meta-data of the package.""" + + description = "perform some checks on the package" + user_options = [ + ('metadata', 'm', 'Verify meta-data'), + ( + 'restructuredtext', + 'r', + ( + 'Checks if long string meta-data syntax ' + 'are reStructuredText-compliant' + ), + ), + ('strict', 's', 'Will exit with an error if a check fails'), + ] boolean_options = ['metadata', 'restructuredtext', 'strict'] @@ -95,19 +117,25 @@ def check_metadata(self): missing.append(attr) if missing: - self.warn("missing required meta-data: %s" % ', '.join(missing)) + self.warn("missing required meta-data: %s" % ', '.join(missing)) if metadata.author: if not metadata.author_email: - self.warn("missing meta-data: if 'author' supplied, " + - "'author_email' should be supplied too") + self.warn( + "missing meta-data: if 'author' supplied, " + + "'author_email' should be supplied too" + ) elif metadata.maintainer: if not metadata.maintainer_email: - self.warn("missing meta-data: if 'maintainer' supplied, " + - "'maintainer_email' should be supplied too") + self.warn( + "missing meta-data: if 'maintainer' supplied, " + + "'maintainer_email' should be supplied too" + ) else: - self.warn("missing meta-data: either (author and author_email) " + - "or (maintainer and maintainer_email) " + - "should be supplied") + self.warn( + "missing meta-data: either (author and author_email) " + + "or (maintainer and maintainer_email) " + + "should be supplied" + ) def check_restructuredtext(self): """Checks if the long string fields are reST-compliant.""" @@ -129,13 +157,15 @@ def _check_rst_data(self, data): settings.tab_width = 4 settings.pep_references = None settings.rfc_references = None - reporter = SilentReporter(source_path, - settings.report_level, - settings.halt_level, - stream=settings.warning_stream, - debug=settings.debug, - encoding=settings.error_encoding, - error_handler=settings.error_encoding_error_handler) + reporter = SilentReporter( + source_path, + settings.report_level, + settings.halt_level, + stream=settings.warning_stream, + debug=settings.debug, + encoding=settings.error_encoding, + error_handler=settings.error_encoding_error_handler, + ) document = nodes.document(settings, reporter, source=source_path) document.note_source(source_path, -1) @@ -143,6 +173,7 @@ def _check_rst_data(self, data): parser.parse(data, document) except AttributeError as e: reporter.messages.append( - (-1, 'Could not finish the parsing: %s.' % e, '', {})) + (-1, 'Could not finish the parsing: %s.' % e, '', {}) + ) return reporter.messages diff --git a/setuptools/_distutils/command/clean.py b/setuptools/_distutils/command/clean.py index 0cb27016621..b731b606096 100644 --- a/setuptools/_distutils/command/clean.py +++ b/setuptools/_distutils/command/clean.py @@ -9,22 +9,25 @@ from distutils.dir_util import remove_tree from distutils import log + class clean(Command): description = "clean up temporary files from 'build' command" user_options = [ - ('build-base=', 'b', - "base build directory (default: 'build.build-base')"), - ('build-lib=', None, - "build directory for all modules (default: 'build.build-lib')"), - ('build-temp=', 't', - "temporary build directory (default: 'build.build-temp')"), - ('build-scripts=', None, - "build directory for scripts (default: 'build.build-scripts')"), - ('bdist-base=', None, - "temporary directory for built distributions"), - ('all', 'a', - "remove all build output, not just temporary by-products") + ('build-base=', 'b', "base build directory (default: 'build.build-base')"), + ( + 'build-lib=', + None, + "build directory for all modules (default: 'build.build-lib')", + ), + ('build-temp=', 't', "temporary build directory (default: 'build.build-temp')"), + ( + 'build-scripts=', + None, + "build directory for scripts (default: 'build.build-scripts')", + ), + ('bdist-base=', None, "temporary directory for built distributions"), + ('all', 'a', "remove all build output, not just temporary by-products"), ] boolean_options = ['all'] @@ -38,13 +41,14 @@ def initialize_options(self): self.all = None def finalize_options(self): - self.set_undefined_options('build', - ('build_base', 'build_base'), - ('build_lib', 'build_lib'), - ('build_scripts', 'build_scripts'), - ('build_temp', 'build_temp')) - self.set_undefined_options('bdist', - ('bdist_base', 'bdist_base')) + self.set_undefined_options( + 'build', + ('build_base', 'build_base'), + ('build_lib', 'build_lib'), + ('build_scripts', 'build_scripts'), + ('build_temp', 'build_temp'), + ) + self.set_undefined_options('bdist', ('bdist_base', 'bdist_base')) def run(self): # remove the build/temp. directory (unless it's already @@ -52,19 +56,15 @@ def run(self): if os.path.exists(self.build_temp): remove_tree(self.build_temp, dry_run=self.dry_run) else: - log.debug("'%s' does not exist -- can't clean it", - self.build_temp) + log.debug("'%s' does not exist -- can't clean it", self.build_temp) if self.all: # remove build directories - for directory in (self.build_lib, - self.bdist_base, - self.build_scripts): + for directory in (self.build_lib, self.bdist_base, self.build_scripts): if os.path.exists(directory): remove_tree(directory, dry_run=self.dry_run) else: - log.warn("'%s' does not exist -- can't clean it", - directory) + log.warn("'%s' does not exist -- can't clean it", directory) # just for the heck of it, try to remove the base build directory: # we might have emptied it right now, but if not we don't care diff --git a/setuptools/_distutils/command/config.py b/setuptools/_distutils/command/config.py index aeda408e731..73de1d3ec81 100644 --- a/setuptools/_distutils/command/config.py +++ b/setuptools/_distutils/command/config.py @@ -18,32 +18,26 @@ LANG_EXT = {"c": ".c", "c++": ".cxx"} + class config(Command): description = "prepare to build" user_options = [ - ('compiler=', None, - "specify the compiler type"), - ('cc=', None, - "specify the compiler executable"), - ('include-dirs=', 'I', - "list of directories to search for header files"), - ('define=', 'D', - "C preprocessor macros to define"), - ('undef=', 'U', - "C preprocessor macros to undefine"), - ('libraries=', 'l', - "external C libraries to link with"), - ('library-dirs=', 'L', - "directories to search for external C libraries"), - - ('noisy', None, - "show every action (compile, link, run, ...) taken"), - ('dump-source', None, - "dump generated source files before attempting to compile them"), - ] - + ('compiler=', None, "specify the compiler type"), + ('cc=', None, "specify the compiler executable"), + ('include-dirs=', 'I', "list of directories to search for header files"), + ('define=', 'D', "C preprocessor macros to define"), + ('undef=', 'U', "C preprocessor macros to undefine"), + ('libraries=', 'l', "external C libraries to link with"), + ('library-dirs=', 'L', "directories to search for external C libraries"), + ('noisy', None, "show every action (compile, link, run, ...) taken"), + ( + 'dump-source', + None, + "dump generated source files before attempting to compile them", + ), + ] # The three standard command methods: since the "config" command # does nothing by default, these are empty. @@ -93,9 +87,11 @@ def _check_compiler(self): # We do this late, and only on-demand, because this is an expensive # import. from distutils.ccompiler import CCompiler, new_compiler + if not isinstance(self.compiler, CCompiler): - self.compiler = new_compiler(compiler=self.compiler, - dry_run=self.dry_run, force=1) + self.compiler = new_compiler( + compiler=self.compiler, dry_run=self.dry_run, force=1 + ) customize_compiler(self.compiler) if self.include_dirs: self.compiler.set_include_dirs(self.include_dirs) @@ -132,14 +128,16 @@ def _compile(self, body, headers, include_dirs, lang): self.compiler.compile([src], include_dirs=include_dirs) return (src, obj) - def _link(self, body, headers, include_dirs, libraries, library_dirs, - lang): + def _link(self, body, headers, include_dirs, libraries, library_dirs, lang): (src, obj) = self._compile(body, headers, include_dirs, lang) prog = os.path.splitext(os.path.basename(src))[0] - self.compiler.link_executable([obj], prog, - libraries=libraries, - library_dirs=library_dirs, - target_lang=lang) + self.compiler.link_executable( + [obj], + prog, + libraries=libraries, + library_dirs=library_dirs, + target_lang=lang, + ) if self.compiler.exe_extension is not None: prog = prog + self.compiler.exe_extension @@ -158,7 +156,6 @@ def _clean(self, *filenames): except OSError: pass - # XXX these ignore the dry-run flag: what to do, what to do? even if # you want a dry-run build, you still need some sort of configuration # info. My inclination is to make it up to the real config command to @@ -177,6 +174,7 @@ def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"): ('body' probably isn't of much use, but what the heck.) """ from distutils.ccompiler import CompileError + self._check_compiler() ok = True try: @@ -187,8 +185,7 @@ def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"): self._clean() return ok - def search_cpp(self, pattern, body=None, headers=None, include_dirs=None, - lang="c"): + def search_cpp(self, pattern, body=None, headers=None, include_dirs=None, lang="c"): """Construct a source file (just like 'try_cpp()'), run it through the preprocessor, and return true if any line of the output matches 'pattern'. 'pattern' should either be a compiled regex object or a @@ -220,6 +217,7 @@ def try_compile(self, body, headers=None, include_dirs=None, lang="c"): Return true on success, false otherwise. """ from distutils.ccompiler import CompileError + self._check_compiler() try: self._compile(body, headers, include_dirs, lang) @@ -231,17 +229,24 @@ def try_compile(self, body, headers=None, include_dirs=None, lang="c"): self._clean() return ok - def try_link(self, body, headers=None, include_dirs=None, libraries=None, - library_dirs=None, lang="c"): + def try_link( + self, + body, + headers=None, + include_dirs=None, + libraries=None, + library_dirs=None, + lang="c", + ): """Try to compile and link a source file, built from 'body' and 'headers', to executable form. Return true on success, false otherwise. """ from distutils.ccompiler import CompileError, LinkError + self._check_compiler() try: - self._link(body, headers, include_dirs, - libraries, library_dirs, lang) + self._link(body, headers, include_dirs, libraries, library_dirs, lang) ok = True except (CompileError, LinkError): ok = False @@ -250,17 +255,26 @@ def try_link(self, body, headers=None, include_dirs=None, libraries=None, self._clean() return ok - def try_run(self, body, headers=None, include_dirs=None, libraries=None, - library_dirs=None, lang="c"): + def try_run( + self, + body, + headers=None, + include_dirs=None, + libraries=None, + library_dirs=None, + lang="c", + ): """Try to compile, link to an executable, and run a program built from 'body' and 'headers'. Return true on success, false otherwise. """ from distutils.ccompiler import CompileError, LinkError + self._check_compiler() try: - src, obj, exe = self._link(body, headers, include_dirs, - libraries, library_dirs, lang) + src, obj, exe = self._link( + body, headers, include_dirs, libraries, library_dirs, lang + ) self.spawn([exe]) ok = True except (CompileError, LinkError, DistutilsExecError): @@ -270,13 +284,20 @@ def try_run(self, body, headers=None, include_dirs=None, libraries=None, self._clean() return ok - # -- High-level methods -------------------------------------------- # (these are the ones that are actually likely to be useful # when implementing a real-world config command!) - def check_func(self, func, headers=None, include_dirs=None, - libraries=None, library_dirs=None, decl=0, call=0): + def check_func( + self, + func, + headers=None, + include_dirs=None, + libraries=None, + library_dirs=None, + decl=0, + call=0, + ): """Determine if function 'func' is available by constructing a source file that refers to 'func', and compiles and links it. If everything succeeds, returns true; otherwise returns false. @@ -302,11 +323,16 @@ def check_func(self, func, headers=None, include_dirs=None, body.append("}") body = "\n".join(body) + "\n" - return self.try_link(body, headers, include_dirs, - libraries, library_dirs) + return self.try_link(body, headers, include_dirs, libraries, library_dirs) - def check_lib(self, library, library_dirs=None, headers=None, - include_dirs=None, other_libraries=[]): + def check_lib( + self, + library, + library_dirs=None, + headers=None, + include_dirs=None, + other_libraries=[], + ): """Determine if 'library' is available to be linked against, without actually checking that any particular symbols are provided by it. 'headers' will be used in constructing the source file to @@ -316,17 +342,23 @@ def check_lib(self, library, library_dirs=None, headers=None, has symbols that depend on other libraries. """ self._check_compiler() - return self.try_link("int main (void) { }", headers, include_dirs, - [library] + other_libraries, library_dirs) - - def check_header(self, header, include_dirs=None, library_dirs=None, - lang="c"): + return self.try_link( + "int main (void) { }", + headers, + include_dirs, + [library] + other_libraries, + library_dirs, + ) + + def check_header(self, header, include_dirs=None, library_dirs=None, lang="c"): """Determine if the system header file named by 'header_file' exists and can be found by the preprocessor; return true if so, false otherwise. """ - return self.try_cpp(body="/* No body */", headers=[header], - include_dirs=include_dirs) + return self.try_cpp( + body="/* No body */", headers=[header], include_dirs=include_dirs + ) + def dump_file(filename, head=None): """Dumps a file content into log.info. diff --git a/setuptools/_distutils/command/install.py b/setuptools/_distutils/command/install.py index 400fb45dd08..eee125f0c18 100644 --- a/setuptools/_distutils/command/install.py +++ b/setuptools/_distutils/command/install.py @@ -17,6 +17,7 @@ from site import USER_BASE from site import USER_SITE + HAS_USER_SITE = True WINDOWS_SCHEME = { @@ -24,7 +25,7 @@ 'platlib': '$base/Lib/site-packages', 'headers': '$base/Include/$dist_name', 'scripts': '$base/Scripts', - 'data' : '$base', + 'data': '$base', } INSTALL_SCHEMES = { @@ -33,31 +34,31 @@ 'platlib': '$platbase/$platlibdir/python$py_version_short/site-packages', 'headers': '$base/include/python$py_version_short$abiflags/$dist_name', 'scripts': '$base/bin', - 'data' : '$base', - }, + 'data': '$base', + }, 'unix_home': { 'purelib': '$base/lib/python', 'platlib': '$base/$platlibdir/python', 'headers': '$base/include/python/$dist_name', 'scripts': '$base/bin', - 'data' : '$base', - }, + 'data': '$base', + }, 'nt': WINDOWS_SCHEME, 'pypy': { 'purelib': '$base/site-packages', 'platlib': '$base/site-packages', 'headers': '$base/include/$dist_name', 'scripts': '$base/bin', - 'data' : '$base', - }, + 'data': '$base', + }, 'pypy_nt': { 'purelib': '$base/site-packages', 'platlib': '$base/site-packages', 'headers': '$base/include/$dist_name', 'scripts': '$base/Scripts', - 'data' : '$base', - }, - } + 'data': '$base', + }, +} # user site schemes if HAS_USER_SITE: @@ -66,17 +67,16 @@ 'platlib': '$usersite', 'headers': '$userbase/Python$py_version_nodot/Include/$dist_name', 'scripts': '$userbase/Python$py_version_nodot/Scripts', - 'data' : '$userbase', - } + 'data': '$userbase', + } INSTALL_SCHEMES['unix_user'] = { 'purelib': '$usersite', 'platlib': '$usersite', - 'headers': - '$userbase/include/python$py_version_short$abiflags/$dist_name', + 'headers': '$userbase/include/python$py_version_short$abiflags/$dist_name', 'scripts': '$userbase/bin', - 'data' : '$userbase', - } + 'data': '$userbase', + } # The keys to an installation scheme; if any new types of files are to be # installed, be sure to add an entry to every installation scheme above, @@ -90,72 +90,73 @@ class install(Command): user_options = [ # Select installation scheme and set base director(y|ies) - ('prefix=', None, - "installation prefix"), - ('exec-prefix=', None, - "(Unix only) prefix for platform-specific files"), - ('home=', None, - "(Unix only) home directory to install under"), - + ('prefix=', None, "installation prefix"), + ('exec-prefix=', None, "(Unix only) prefix for platform-specific files"), + ('home=', None, "(Unix only) home directory to install under"), # Or, just set the base director(y|ies) - ('install-base=', None, - "base installation directory (instead of --prefix or --home)"), - ('install-platbase=', None, - "base installation directory for platform-specific files " + - "(instead of --exec-prefix or --home)"), - ('root=', None, - "install everything relative to this alternate root directory"), - + ( + 'install-base=', + None, + "base installation directory (instead of --prefix or --home)", + ), + ( + 'install-platbase=', + None, + "base installation directory for platform-specific files " + + "(instead of --exec-prefix or --home)", + ), + ('root=', None, "install everything relative to this alternate root directory"), # Or, explicitly set the installation scheme - ('install-purelib=', None, - "installation directory for pure Python module distributions"), - ('install-platlib=', None, - "installation directory for non-pure module distributions"), - ('install-lib=', None, - "installation directory for all module distributions " + - "(overrides --install-purelib and --install-platlib)"), - - ('install-headers=', None, - "installation directory for C/C++ headers"), - ('install-scripts=', None, - "installation directory for Python scripts"), - ('install-data=', None, - "installation directory for data files"), - + ( + 'install-purelib=', + None, + "installation directory for pure Python module distributions", + ), + ( + 'install-platlib=', + None, + "installation directory for non-pure module distributions", + ), + ( + 'install-lib=', + None, + "installation directory for all module distributions " + + "(overrides --install-purelib and --install-platlib)", + ), + ('install-headers=', None, "installation directory for C/C++ headers"), + ('install-scripts=', None, "installation directory for Python scripts"), + ('install-data=', None, "installation directory for data files"), # Byte-compilation options -- see install_lib.py for details, as # these are duplicated from there (but only install_lib does # anything with them). ('compile', 'c', "compile .py to .pyc [default]"), ('no-compile', None, "don't compile .py files"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), - + ( + 'optimize=', + 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]", + ), # Miscellaneous control options - ('force', 'f', - "force installation (overwrite any existing files)"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - + ('force', 'f', "force installation (overwrite any existing files)"), + ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), # Where to install documentation (eventually!) - #('doc-format=', None, "format of documentation to generate"), - #('install-man=', None, "directory for Unix man pages"), - #('install-html=', None, "directory for HTML documentation"), - #('install-info=', None, "directory for GNU info files"), - - ('record=', None, - "filename in which to record list of installed files"), - ] + # ('doc-format=', None, "format of documentation to generate"), + # ('install-man=', None, "directory for Unix man pages"), + # ('install-html=', None, "directory for HTML documentation"), + # ('install-info=', None, "directory for GNU info files"), + ('record=', None, "filename in which to record list of installed files"), + ] boolean_options = ['compile', 'force', 'skip-build'] if HAS_USER_SITE: - user_options.append(('user', None, - "install in user site-package '%s'" % USER_SITE)) + user_options.append( + ('user', None, "install in user site-package '%s'" % USER_SITE) + ) boolean_options.append('user') - negative_opt = {'no-compile' : 'compile'} - + negative_opt = {'no-compile': 'compile'} def initialize_options(self): """Initializes options.""" @@ -177,10 +178,10 @@ def initialize_options(self): # supplied by the user, they are filled in using the installation # scheme implied by prefix/exec-prefix/home and the contents of # that installation scheme. - self.install_purelib = None # for pure module distributions - self.install_platlib = None # non-pure (dists w/ extensions) - self.install_headers = None # for C/C++ headers - self.install_lib = None # set to either purelib or platlib + self.install_purelib = None # for pure module distributions + self.install_platlib = None # non-pure (dists w/ extensions) + self.install_headers = None # for C/C++ headers + self.install_lib = None # set to either purelib or platlib self.install_scripts = None self.install_data = None self.install_userbase = USER_BASE @@ -222,13 +223,12 @@ def initialize_options(self): # Not defined yet because we don't know anything about # documentation yet. - #self.install_man = None - #self.install_html = None - #self.install_info = None + # self.install_man = None + # self.install_html = None + # self.install_info = None self.record = None - # -- Option finalizing methods ------------------------------------- # (This is rather more involved than for most commands, # because this is where the policy for installing third- @@ -251,20 +251,30 @@ def finalize_options(self): # Check for errors/inconsistencies in the options; first, stuff # that's wrong on any platform. - if ((self.prefix or self.exec_prefix or self.home) and - (self.install_base or self.install_platbase)): + if (self.prefix or self.exec_prefix or self.home) and ( + self.install_base or self.install_platbase + ): raise DistutilsOptionError( - "must supply either prefix/exec-prefix/home or " + - "install-base/install-platbase -- not both") + "must supply either prefix/exec-prefix/home or " + + "install-base/install-platbase -- not both" + ) if self.home and (self.prefix or self.exec_prefix): raise DistutilsOptionError( - "must supply either home or prefix/exec-prefix -- not both") + "must supply either home or prefix/exec-prefix -- not both" + ) - if self.user and (self.prefix or self.exec_prefix or self.home or - self.install_base or self.install_platbase): - raise DistutilsOptionError("can't combine user with prefix, " - "exec_prefix/home, or install_(plat)base") + if self.user and ( + self.prefix + or self.exec_prefix + or self.home + or self.install_base + or self.install_platbase + ): + raise DistutilsOptionError( + "can't combine user with prefix, " + "exec_prefix/home, or install_(plat)base" + ) # Next, stuff that's wrong (or dubious) only on certain platforms. if os.name != "posix": @@ -301,19 +311,20 @@ def finalize_options(self): except AttributeError: # sys.abiflags may not be defined on all platforms. abiflags = '' - self.config_vars = {'dist_name': self.distribution.get_name(), - 'dist_version': self.distribution.get_version(), - 'dist_fullname': self.distribution.get_fullname(), - 'py_version': py_version, - 'py_version_short': '%d.%d' % sys.version_info[:2], - 'py_version_nodot': '%d%d' % sys.version_info[:2], - 'sys_prefix': prefix, - 'prefix': prefix, - 'sys_exec_prefix': exec_prefix, - 'exec_prefix': exec_prefix, - 'abiflags': abiflags, - 'platlibdir': getattr(sys, 'platlibdir', 'lib'), - } + self.config_vars = { + 'dist_name': self.distribution.get_name(), + 'dist_version': self.distribution.get_version(), + 'dist_fullname': self.distribution.get_fullname(), + 'py_version': py_version, + 'py_version_short': '%d.%d' % sys.version_info[:2], + 'py_version_nodot': '%d%d' % sys.version_info[:2], + 'sys_prefix': prefix, + 'prefix': prefix, + 'sys_exec_prefix': exec_prefix, + 'exec_prefix': exec_prefix, + 'abiflags': abiflags, + 'platlibdir': getattr(sys, 'platlibdir', 'lib'), + } if HAS_USER_SITE: self.config_vars['userbase'] = self.install_userbase @@ -330,6 +341,7 @@ def finalize_options(self): if DEBUG: from pprint import pprint + print("config vars:") pprint(self.config_vars) @@ -348,17 +360,23 @@ def finalize_options(self): # module distribution is pure or not. Of course, if the user # already specified install_lib, use their selection. if self.install_lib is None: - if self.distribution.has_ext_modules(): # has extensions: non-pure + if self.distribution.has_ext_modules(): # has extensions: non-pure self.install_lib = self.install_platlib else: self.install_lib = self.install_purelib - # Convert directories from Unix /-separated syntax to the local # convention. - self.convert_paths('lib', 'purelib', 'platlib', - 'scripts', 'data', 'headers', - 'userbase', 'usersite') + self.convert_paths( + 'lib', + 'purelib', + 'platlib', + 'scripts', + 'data', + 'headers', + 'userbase', + 'usersite', + ) # Deprecated # Well, we're not actually fully completely finalized yet: we still @@ -366,21 +384,22 @@ def finalize_options(self): # non-packagized module distributions (hello, Numerical Python!) to # get their own directories. self.handle_extra_path() - self.install_libbase = self.install_lib # needed for .pth file + self.install_libbase = self.install_lib # needed for .pth file self.install_lib = os.path.join(self.install_lib, self.extra_dirs) # If a new root directory was supplied, make all the installation # dirs relative to it. if self.root is not None: - self.change_roots('libbase', 'lib', 'purelib', 'platlib', - 'scripts', 'data', 'headers') + self.change_roots( + 'libbase', 'lib', 'purelib', 'platlib', 'scripts', 'data', 'headers' + ) self.dump_dirs("after prepending root") # Find out the build directories, ie. where to install from. - self.set_undefined_options('build', - ('build_base', 'build_base'), - ('build_lib', 'build_lib')) + self.set_undefined_options( + 'build', ('build_base', 'build_base'), ('build_lib', 'build_lib') + ) # Punt on doc directories for now -- after all, we're punting on # documentation completely! @@ -390,6 +409,7 @@ def dump_dirs(self, msg): if not DEBUG: return from distutils.fancy_getopt import longopt_xlate + log.debug(msg + ":") for opt in self.user_options: opt_name = opt[0] @@ -407,21 +427,25 @@ def dump_dirs(self, msg): def finalize_unix(self): """Finalizes options for posix platforms.""" if self.install_base is not None or self.install_platbase is not None: - if ((self.install_lib is None and - self.install_purelib is None and - self.install_platlib is None) or - self.install_headers is None or - self.install_scripts is None or - self.install_data is None): + if ( + ( + self.install_lib is None + and self.install_purelib is None + and self.install_platlib is None + ) + or self.install_headers is None + or self.install_scripts is None + or self.install_data is None + ): raise DistutilsOptionError( - "install-base or install-platbase supplied, but " - "installation scheme is incomplete") + "install-base or install-platbase supplied, but " + "installation scheme is incomplete" + ) return if self.user: if self.install_userbase is None: - raise DistutilsPlatformError( - "User base directory is not specified") + raise DistutilsPlatformError("User base directory is not specified") self.install_base = self.install_platbase = self.install_userbase self.select_scheme("unix_user") elif self.home is not None: @@ -431,7 +455,8 @@ def finalize_unix(self): if self.prefix is None: if self.exec_prefix is not None: raise DistutilsOptionError( - "must not supply exec-prefix without prefix") + "must not supply exec-prefix without prefix" + ) self.prefix = os.path.normpath(sys.prefix) self.exec_prefix = os.path.normpath(sys.exec_prefix) @@ -448,8 +473,7 @@ def finalize_other(self): """Finalizes options for non-posix platforms""" if self.user: if self.install_userbase is None: - raise DistutilsPlatformError( - "User base directory is not specified") + raise DistutilsPlatformError("User base directory is not specified") self.install_base = self.install_platbase = self.install_userbase self.select_scheme(os.name + "_user") elif self.home is not None: @@ -464,13 +488,13 @@ def finalize_other(self): self.select_scheme(os.name) except KeyError: raise DistutilsPlatformError( - "I don't know how to install stuff on '%s'" % os.name) + "I don't know how to install stuff on '%s'" % os.name + ) def select_scheme(self, name): """Sets the install directories by applying the install schemes.""" # it's the caller's problem if they supply a bad name! - if (hasattr(sys, 'pypy_version_info') and - not name.endswith(('_user', '_home'))): + if hasattr(sys, 'pypy_version_info') and not name.endswith(('_user', '_home')): if os.name == 'nt': name = 'pypy_nt' else: @@ -497,9 +521,16 @@ def expand_basedirs(self): def expand_dirs(self): """Calls `os.path.expanduser` on install dirs.""" - self._expand_attrs(['install_purelib', 'install_platlib', - 'install_lib', 'install_headers', - 'install_scripts', 'install_data',]) + self._expand_attrs( + [ + 'install_purelib', + 'install_platlib', + 'install_lib', + 'install_headers', + 'install_scripts', + 'install_data', + ] + ) def convert_paths(self, *names): """Call `convert_path` over `names`.""" @@ -526,8 +557,9 @@ def handle_extra_path(self): path_file, extra_dirs = self.extra_path else: raise DistutilsOptionError( - "'extra_path' option must be a list, tuple, or " - "comma-separated string with 1 or 2 elements") + "'extra_path' option must be a list, tuple, or " + "comma-separated string with 1 or 2 elements" + ) # convert to local form in case Unix notation used (as it # should be in setup scripts) @@ -570,8 +602,7 @@ def run(self): # internally, and not to sys.path, so we don't check the platform # matches what we are running. if self.warn_dir and build_plat != get_platform(): - raise DistutilsPlatformError("Can't install when " - "cross-compiling") + raise DistutilsPlatformError("Can't install when " "cross-compiling") # Run all sub-commands (at least those that need to be run) for cmd_name in self.get_sub_commands(): @@ -583,38 +614,43 @@ def run(self): # write list of installed files, if requested. if self.record: outputs = self.get_outputs() - if self.root: # strip any package prefix + if self.root: # strip any package prefix root_len = len(self.root) for counter in range(len(outputs)): outputs[counter] = outputs[counter][root_len:] - self.execute(write_file, - (self.record, outputs), - "writing list of installed files to '%s'" % - self.record) + self.execute( + write_file, + (self.record, outputs), + "writing list of installed files to '%s'" % self.record, + ) sys_path = map(os.path.normpath, sys.path) sys_path = map(os.path.normcase, sys_path) install_lib = os.path.normcase(os.path.normpath(self.install_lib)) - if (self.warn_dir and - not (self.path_file and self.install_path_file) and - install_lib not in sys_path): - log.debug(("modules installed to '%s', which is not in " - "Python's module search path (sys.path) -- " - "you'll have to change the search path yourself"), - self.install_lib) + if ( + self.warn_dir + and not (self.path_file and self.install_path_file) + and install_lib not in sys_path + ): + log.debug( + ( + "modules installed to '%s', which is not in " + "Python's module search path (sys.path) -- " + "you'll have to change the search path yourself" + ), + self.install_lib, + ) def create_path_file(self): """Creates the .pth file""" - filename = os.path.join(self.install_libbase, - self.path_file + ".pth") + filename = os.path.join(self.install_libbase, self.path_file + ".pth") if self.install_path_file: - self.execute(write_file, - (filename, [self.extra_dirs]), - "creating %s" % filename) + self.execute( + write_file, (filename, [self.extra_dirs]), "creating %s" % filename + ) else: self.warn("path file '%s' not created" % filename) - # -- Reporting methods --------------------------------------------- def get_outputs(self): @@ -629,8 +665,7 @@ def get_outputs(self): outputs.append(filename) if self.path_file and self.install_path_file: - outputs.append(os.path.join(self.install_libbase, - self.path_file + ".pth")) + outputs.append(os.path.join(self.install_libbase, self.path_file + ".pth")) return outputs @@ -649,8 +684,9 @@ def get_inputs(self): def has_lib(self): """Returns true if the current distribution has any Python modules to install.""" - return (self.distribution.has_pure_modules() or - self.distribution.has_ext_modules()) + return ( + self.distribution.has_pure_modules() or self.distribution.has_ext_modules() + ) def has_headers(self): """Returns true if the current distribution has any headers to @@ -669,9 +705,10 @@ def has_data(self): # 'sub_commands': a list of commands this command might have to run to # get its work done. See cmd.py for more info. - sub_commands = [('install_lib', has_lib), - ('install_headers', has_headers), - ('install_scripts', has_scripts), - ('install_data', has_data), - ('install_egg_info', lambda self:True), - ] + sub_commands = [ + ('install_lib', has_lib), + ('install_headers', has_headers), + ('install_scripts', has_scripts), + ('install_data', has_data), + ('install_egg_info', lambda self: True), + ] diff --git a/setuptools/_distutils/command/install_data.py b/setuptools/_distutils/command/install_data.py index 947cd76a99e..23d91aded26 100644 --- a/setuptools/_distutils/command/install_data.py +++ b/setuptools/_distutils/command/install_data.py @@ -9,18 +9,21 @@ from distutils.core import Command from distutils.util import change_root, convert_path + class install_data(Command): description = "install data files" user_options = [ - ('install-dir=', 'd', - "base directory for installing data files " - "(default: installation base dir)"), - ('root=', None, - "install everything relative to this alternate root directory"), + ( + 'install-dir=', + 'd', + "base directory for installing data files " + "(default: installation base dir)", + ), + ('root=', None, "install everything relative to this alternate root directory"), ('force', 'f', "force installation (overwrite existing files)"), - ] + ] boolean_options = ['force'] @@ -33,11 +36,12 @@ def initialize_options(self): self.warn_dir = 1 def finalize_options(self): - self.set_undefined_options('install', - ('install_data', 'install_dir'), - ('root', 'root'), - ('force', 'force'), - ) + self.set_undefined_options( + 'install', + ('install_data', 'install_dir'), + ('root', 'root'), + ('force', 'force'), + ) def run(self): self.mkpath(self.install_dir) @@ -46,9 +50,10 @@ def run(self): # it's a simple file, so copy it f = convert_path(f) if self.warn_dir: - self.warn("setup script did not provide a directory for " - "'%s' -- installing right in '%s'" % - (f, self.install_dir)) + self.warn( + "setup script did not provide a directory for " + "'%s' -- installing right in '%s'" % (f, self.install_dir) + ) (out, _) = self.copy_file(f, self.install_dir) self.outfiles.append(out) else: diff --git a/setuptools/_distutils/command/install_egg_info.py b/setuptools/_distutils/command/install_egg_info.py index 0ddc7367cc6..e97a880ceb6 100644 --- a/setuptools/_distutils/command/install_egg_info.py +++ b/setuptools/_distutils/command/install_egg_info.py @@ -8,6 +8,7 @@ from distutils import log, dir_util import os, sys, re + class install_egg_info(Command): """Install an .egg-info file for the package""" @@ -20,11 +21,11 @@ def initialize_options(self): self.install_dir = None def finalize_options(self): - self.set_undefined_options('install_lib',('install_dir','install_dir')) + self.set_undefined_options('install_lib', ('install_dir', 'install_dir')) basename = "%s-%s-py%d.%d.egg-info" % ( to_filename(safe_name(self.distribution.get_name())), to_filename(safe_version(self.distribution.get_version())), - *sys.version_info[:2] + *sys.version_info[:2], ) self.target = os.path.join(self.install_dir, basename) self.outputs = [self.target] @@ -34,10 +35,11 @@ def run(self): if os.path.isdir(target) and not os.path.islink(target): dir_util.remove_tree(target, dry_run=self.dry_run) elif os.path.exists(target): - self.execute(os.unlink,(self.target,),"Removing "+target) + self.execute(os.unlink, (self.target,), "Removing " + target) elif not os.path.isdir(self.install_dir): - self.execute(os.makedirs, (self.install_dir,), - "Creating "+self.install_dir) + self.execute( + os.makedirs, (self.install_dir,), "Creating " + self.install_dir + ) log.info("Writing %s", target) if not self.dry_run: with open(target, 'w', encoding='UTF-8') as f: @@ -51,6 +53,7 @@ def get_outputs(self): # can be replaced by importing them from pkg_resources once it is included # in the stdlib. + def safe_name(name): """Convert an arbitrary string to a standard distribution name @@ -65,7 +68,7 @@ def safe_version(version): Spaces become dots, and all other non-alphanumeric characters become dashes, with runs of multiple dashes condensed to a single dash. """ - version = version.replace(' ','.') + version = version.replace(' ', '.') return re.sub('[^A-Za-z0-9.]+', '-', version) @@ -74,4 +77,4 @@ def to_filename(name): Any '-' characters are currently replaced with '_'. """ - return name.replace('-','_') + return name.replace('-', '_') diff --git a/setuptools/_distutils/command/install_headers.py b/setuptools/_distutils/command/install_headers.py index 9bb0b18dc0d..87046ab391b 100644 --- a/setuptools/_distutils/command/install_headers.py +++ b/setuptools/_distutils/command/install_headers.py @@ -11,11 +11,10 @@ class install_headers(Command): description = "install C/C++ header files" - user_options = [('install-dir=', 'd', - "directory to install header files to"), - ('force', 'f', - "force installation (overwrite existing files)"), - ] + user_options = [ + ('install-dir=', 'd', "directory to install header files to"), + ('force', 'f', "force installation (overwrite existing files)"), + ] boolean_options = ['force'] @@ -25,10 +24,9 @@ def initialize_options(self): self.outfiles = [] def finalize_options(self): - self.set_undefined_options('install', - ('install_headers', 'install_dir'), - ('force', 'force')) - + self.set_undefined_options( + 'install', ('install_headers', 'install_dir'), ('force', 'force') + ) def run(self): headers = self.distribution.headers diff --git a/setuptools/_distutils/command/install_lib.py b/setuptools/_distutils/command/install_lib.py index 6154cf09431..ad3089c8b14 100644 --- a/setuptools/_distutils/command/install_lib.py +++ b/setuptools/_distutils/command/install_lib.py @@ -14,6 +14,7 @@ # Extension for Python source files. PYTHON_SOURCE_EXTENSION = ".py" + class install_lib(Command): description = "install all Python modules (extensions and pure Python)" @@ -35,18 +36,21 @@ class install_lib(Command): user_options = [ ('install-dir=', 'd', "directory to install to"), - ('build-dir=','b', "build directory (where to install from)"), + ('build-dir=', 'b', "build directory (where to install from)"), ('force', 'f', "force installation (overwrite existing files)"), ('compile', 'c', "compile .py to .pyc [default]"), ('no-compile', None, "don't compile .py files"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ( + 'optimize=', + 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]", + ), ('skip-build', None, "skip the build steps"), - ] + ] boolean_options = ['force', 'compile', 'skip-build'] - negative_opt = {'no-compile' : 'compile'} + negative_opt = {'no-compile': 'compile'} def initialize_options(self): # let the 'install' command dictate our installation directory @@ -61,14 +65,15 @@ def finalize_options(self): # Get all the information we need to install pure Python modules # from the umbrella 'install' command -- build (source) directory, # install (target) directory, and whether to compile .py files. - self.set_undefined_options('install', - ('build_lib', 'build_dir'), - ('install_lib', 'install_dir'), - ('force', 'force'), - ('compile', 'compile'), - ('optimize', 'optimize'), - ('skip_build', 'skip_build'), - ) + self.set_undefined_options( + 'install', + ('build_lib', 'build_dir'), + ('install_lib', 'install_dir'), + ('force', 'force'), + ('compile', 'compile'), + ('optimize', 'optimize'), + ('skip_build', 'skip_build'), + ) if self.compile is None: self.compile = True @@ -110,8 +115,9 @@ def install(self): if os.path.isdir(self.build_dir): outfiles = self.copy_tree(self.build_dir, self.install_dir) else: - self.warn("'%s' does not exist -- no Python modules to install" % - self.build_dir) + self.warn( + "'%s' does not exist -- no Python modules to install" % self.build_dir + ) return return outfiles @@ -129,14 +135,22 @@ def byte_compile(self, files): install_root = self.get_finalized_command('install').root if self.compile: - byte_compile(files, optimize=0, - force=self.force, prefix=install_root, - dry_run=self.dry_run) + byte_compile( + files, + optimize=0, + force=self.force, + prefix=install_root, + dry_run=self.dry_run, + ) if self.optimize > 0: - byte_compile(files, optimize=self.optimize, - force=self.force, prefix=install_root, - verbose=self.verbose, dry_run=self.dry_run) - + byte_compile( + files, + optimize=self.optimize, + force=self.force, + prefix=install_root, + verbose=self.verbose, + dry_run=self.dry_run, + ) # -- Utility methods ----------------------------------------------- @@ -165,15 +179,18 @@ def _bytecode_filenames(self, py_filenames): if ext != PYTHON_SOURCE_EXTENSION: continue if self.compile: - bytecode_files.append(importlib.util.cache_from_source( - py_file, optimization='')) + bytecode_files.append( + importlib.util.cache_from_source(py_file, optimization='') + ) if self.optimize > 0: - bytecode_files.append(importlib.util.cache_from_source( - py_file, optimization=self.optimize)) + bytecode_files.append( + importlib.util.cache_from_source( + py_file, optimization=self.optimize + ) + ) return bytecode_files - # -- External interface -------------------------------------------- # (called by outsiders) @@ -182,19 +199,23 @@ def get_outputs(self): were actually run. Not affected by the "dry-run" flag or whether modules have actually been built yet. """ - pure_outputs = \ - self._mutate_outputs(self.distribution.has_pure_modules(), - 'build_py', 'build_lib', - self.install_dir) + pure_outputs = self._mutate_outputs( + self.distribution.has_pure_modules(), + 'build_py', + 'build_lib', + self.install_dir, + ) if self.compile: bytecode_outputs = self._bytecode_filenames(pure_outputs) else: bytecode_outputs = [] - ext_outputs = \ - self._mutate_outputs(self.distribution.has_ext_modules(), - 'build_ext', 'build_lib', - self.install_dir) + ext_outputs = self._mutate_outputs( + self.distribution.has_ext_modules(), + 'build_ext', + 'build_lib', + self.install_dir, + ) return pure_outputs + bytecode_outputs + ext_outputs diff --git a/setuptools/_distutils/command/install_scripts.py b/setuptools/_distutils/command/install_scripts.py index 31a1130ee54..f09bd644207 100644 --- a/setuptools/_distutils/command/install_scripts.py +++ b/setuptools/_distutils/command/install_scripts.py @@ -17,7 +17,7 @@ class install_scripts(Command): user_options = [ ('install-dir=', 'd', "directory to install scripts to"), - ('build-dir=','b', "build directory (where to install from)"), + ('build-dir=', 'b', "build directory (where to install from)"), ('force', 'f', "force installation (overwrite existing files)"), ('skip-build', None, "skip the build steps"), ] @@ -32,11 +32,12 @@ def initialize_options(self): def finalize_options(self): self.set_undefined_options('build', ('build_scripts', 'build_dir')) - self.set_undefined_options('install', - ('install_scripts', 'install_dir'), - ('force', 'force'), - ('skip_build', 'skip_build'), - ) + self.set_undefined_options( + 'install', + ('install_scripts', 'install_dir'), + ('force', 'force'), + ('skip_build', 'skip_build'), + ) def run(self): if not self.skip_build: diff --git a/setuptools/_distutils/command/py37compat.py b/setuptools/_distutils/command/py37compat.py index 754715a5084..aa0c0a7fcd1 100644 --- a/setuptools/_distutils/command/py37compat.py +++ b/setuptools/_distutils/command/py37compat.py @@ -7,12 +7,13 @@ def _pythonlib_compat(): library. See pypa/distutils#9. """ from distutils import sysconfig + if not sysconfig.get_config_var('Py_ENABLED_SHARED'): return yield 'python{}.{}{}'.format( sys.hexversion >> 24, - (sys.hexversion >> 16) & 0xff, + (sys.hexversion >> 16) & 0xFF, sysconfig.get_config_var('ABIFLAGS'), ) diff --git a/setuptools/_distutils/command/register.py b/setuptools/_distutils/command/register.py index 0fac94e9e54..7dc23e12991 100644 --- a/setuptools/_distutils/command/register.py +++ b/setuptools/_distutils/command/register.py @@ -14,17 +14,23 @@ from distutils.errors import * from distutils import log + class register(PyPIRCCommand): - description = ("register the distribution with the Python package index") + description = "register the distribution with the Python package index" user_options = PyPIRCCommand.user_options + [ - ('list-classifiers', None, - 'list the valid Trove classifiers'), - ('strict', None , - 'Will stop the registering if the meta-data are not fully compliant') - ] + ('list-classifiers', None, 'list the valid Trove classifiers'), + ( + 'strict', + None, + 'Will stop the registering if the meta-data are not fully compliant', + ), + ] boolean_options = PyPIRCCommand.boolean_options + [ - 'verify', 'list-classifiers', 'strict'] + 'verify', + 'list-classifiers', + 'strict', + ] sub_commands = [('check', lambda self: True)] @@ -36,8 +42,10 @@ def initialize_options(self): def finalize_options(self): PyPIRCCommand.finalize_options(self) # setting options for the `check` subcommand - check_options = {'strict': ('register', self.strict), - 'restructuredtext': ('register', 1)} + check_options = { + 'strict': ('register', self.strict), + 'restructuredtext': ('register', 1), + } self.distribution.command_options['check'] = check_options def run(self): @@ -57,8 +65,11 @@ def run(self): def check_metadata(self): """Deprecated API.""" - warn("distutils.command.register.check_metadata is deprecated, \ - use the check command instead", PendingDeprecationWarning) + warn( + "distutils.command.register.check_metadata is deprecated, \ + use the check command instead", + PendingDeprecationWarning, + ) check = self.distribution.get_command_obj('check') check.ensure_finalized() check.strict = self.strict @@ -66,8 +77,7 @@ def check_metadata(self): check.run() def _set_config(self): - ''' Reads the configuration file and set attributes. - ''' + """Reads the configuration file and set attributes.""" config = self._read_pypirc() if config != {}: self.username = config['username'] @@ -83,47 +93,45 @@ def _set_config(self): self.has_config = False def classifiers(self): - ''' Fetch the list of classifiers from the server. - ''' - url = self.repository+'?:action=list_classifiers' + """Fetch the list of classifiers from the server.""" + url = self.repository + '?:action=list_classifiers' response = urllib.request.urlopen(url) log.info(self._read_pypi_response(response)) def verify_metadata(self): - ''' Send the metadata to the package index server to be checked. - ''' + """Send the metadata to the package index server to be checked.""" # send the info to the server and report the result (code, result) = self.post_to_server(self.build_post_data('verify')) log.info('Server response (%s): %s', code, result) def send_metadata(self): - ''' Send the metadata to the package index server. + """Send the metadata to the package index server. - Well, do the following: - 1. figure who the user is, and then - 2. send the data as a Basic auth'ed POST. + Well, do the following: + 1. figure who the user is, and then + 2. send the data as a Basic auth'ed POST. - First we try to read the username/password from $HOME/.pypirc, - which is a ConfigParser-formatted file with a section - [distutils] containing username and password entries (both - in clear text). Eg: + First we try to read the username/password from $HOME/.pypirc, + which is a ConfigParser-formatted file with a section + [distutils] containing username and password entries (both + in clear text). Eg: - [distutils] - index-servers = - pypi + [distutils] + index-servers = + pypi - [pypi] - username: fred - password: sekrit + [pypi] + username: fred + password: sekrit - Otherwise, to figure who the user is, we offer the user three - choices: + Otherwise, to figure who the user is, we offer the user three + choices: - 1. use existing login, - 2. register as a new user, or - 3. set the password to a random string and email the user. + 1. use existing login, + 2. register as a new user, or + 3. set the password to a random string and email the user. - ''' + """ # see if we can short-cut and get the username/password from the # config if self.has_config: @@ -137,13 +145,16 @@ def send_metadata(self): # get the user's login info choices = '1 2 3 4'.split() while choice not in choices: - self.announce('''\ + self.announce( + '''\ We need to know who you are, so please choose either: 1. use your existing login, 2. register as a new user, 3. have the server generate a new password for you (and email it to you), or 4. quit -Your selection [default 1]: ''', log.INFO) +Your selection [default 1]: ''', + log.INFO, + ) choice = input() if not choice: choice = '1' @@ -162,10 +173,8 @@ def send_metadata(self): host = urllib.parse.urlparse(self.repository)[1] auth.add_password(self.realm, host, username, password) # send the info to the server and report the result - code, result = self.post_to_server(self.build_post_data('submit'), - auth) - self.announce('Server response (%s): %s' % (code, result), - log.INFO) + code, result = self.post_to_server(self.build_post_data('submit'), auth) + self.announce('Server response (%s): %s' % (code, result), log.INFO) # possibly save the login if code == 200: @@ -174,10 +183,17 @@ def send_metadata(self): # so the upload command can reuse it self.distribution.password = password else: - self.announce(('I can store your PyPI login so future ' - 'submissions will be faster.'), log.INFO) - self.announce('(the login will be stored in %s)' % \ - self._get_rc_file(), log.INFO) + self.announce( + ( + 'I can store your PyPI login so future ' + 'submissions will be faster.' + ), + log.INFO, + ) + self.announce( + '(the login will be stored in %s)' % self._get_rc_file(), + log.INFO, + ) choice = 'X' while choice.lower() not in 'yn': choice = input('Save your login (y/N)?') @@ -208,8 +224,7 @@ def send_metadata(self): log.info('Server response (%s): %s', code, result) else: log.info('You will receive an email shortly.') - log.info(('Follow the instructions in it to ' - 'complete registration.')) + log.info(('Follow the instructions in it to ' 'complete registration.')) elif choice == '3': data = {':action': 'password_reset'} data['email'] = '' @@ -224,7 +239,7 @@ def build_post_data(self, action): meta = self.distribution.metadata data = { ':action': action, - 'metadata_version' : '1.0', + 'metadata_version': '1.0', 'name': meta.get_name(), 'version': meta.get_version(), 'summary': meta.get_description(), @@ -247,12 +262,11 @@ def build_post_data(self, action): return data def post_to_server(self, data, auth=None): - ''' Post a query to the server, and return a string response. - ''' + """Post a query to the server, and return a string response.""" if 'name' in data: - self.announce('Registering %s to %s' % (data['name'], - self.repository), - log.INFO) + self.announce( + 'Registering %s to %s' % (data['name'], self.repository), log.INFO + ) # Build up the MIME payload for the urllib2 POST data boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' sep_boundary = '\n--' + boundary @@ -260,12 +274,12 @@ def post_to_server(self, data, auth=None): body = io.StringIO() for key, value in data.items(): # handle multiple entries for the same name - if type(value) not in (type([]), type( () )): + if type(value) not in (type([]), type(())): value = [value] for value in value: value = str(value) body.write(sep_boundary) - body.write('\nContent-Disposition: form-data; name="%s"'%key) + body.write('\nContent-Disposition: form-data; name="%s"' % key) body.write("\n\n") body.write(value) if value and value[-1] == '\r': @@ -276,8 +290,9 @@ def post_to_server(self, data, auth=None): # build the Request headers = { - 'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary, - 'Content-length': str(len(body)) + 'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8' + % boundary, + 'Content-length': str(len(body)), } req = urllib.request.Request(self.repository, body, headers) diff --git a/setuptools/_distutils/command/sdist.py b/setuptools/_distutils/command/sdist.py index b4996fcb1d2..aad3e7134c0 100644 --- a/setuptools/_distutils/command/sdist.py +++ b/setuptools/_distutils/command/sdist.py @@ -24,13 +24,12 @@ def show_formats(): """ from distutils.fancy_getopt import FancyGetopt from distutils.archive_util import ARCHIVE_FORMATS + formats = [] for format in ARCHIVE_FORMATS.keys(): - formats.append(("formats=" + format, None, - ARCHIVE_FORMATS[format][2])) + formats.append(("formats=" + format, None, ARCHIVE_FORMATS[format][2])) formats.sort() - FancyGetopt(formats).print_help( - "List of available source distribution formats:") + FancyGetopt(formats).print_help("List of available source distribution formats:") class sdist(Command): @@ -44,55 +43,77 @@ def checking_metadata(self): return self.metadata_check user_options = [ - ('template=', 't', - "name of manifest template file [default: MANIFEST.in]"), - ('manifest=', 'm', - "name of manifest file [default: MANIFEST]"), - ('use-defaults', None, - "include the default file set in the manifest " - "[default; disable with --no-defaults]"), - ('no-defaults', None, - "don't include the default file set"), - ('prune', None, - "specifically exclude files/directories that should not be " - "distributed (build tree, RCS/CVS dirs, etc.) " - "[default; disable with --no-prune]"), - ('no-prune', None, - "don't automatically exclude anything"), - ('manifest-only', 'o', - "just regenerate the manifest and then stop " - "(implies --force-manifest)"), - ('force-manifest', 'f', - "forcibly regenerate the manifest and carry on as usual. " - "Deprecated: now the manifest is always regenerated."), - ('formats=', None, - "formats for source distribution (comma-separated list)"), - ('keep-temp', 'k', - "keep the distribution tree around after creating " + - "archive file(s)"), - ('dist-dir=', 'd', - "directory to put the source distribution archive(s) in " - "[default: dist]"), - ('metadata-check', None, - "Ensure that all required elements of meta-data " - "are supplied. Warn if any missing. [default]"), - ('owner=', 'u', - "Owner name used when creating a tar file [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file [default: current group]"), - ] - - boolean_options = ['use-defaults', 'prune', - 'manifest-only', 'force-manifest', - 'keep-temp', 'metadata-check'] + ('template=', 't', "name of manifest template file [default: MANIFEST.in]"), + ('manifest=', 'm', "name of manifest file [default: MANIFEST]"), + ( + 'use-defaults', + None, + "include the default file set in the manifest " + "[default; disable with --no-defaults]", + ), + ('no-defaults', None, "don't include the default file set"), + ( + 'prune', + None, + "specifically exclude files/directories that should not be " + "distributed (build tree, RCS/CVS dirs, etc.) " + "[default; disable with --no-prune]", + ), + ('no-prune', None, "don't automatically exclude anything"), + ( + 'manifest-only', + 'o', + "just regenerate the manifest and then stop " "(implies --force-manifest)", + ), + ( + 'force-manifest', + 'f', + "forcibly regenerate the manifest and carry on as usual. " + "Deprecated: now the manifest is always regenerated.", + ), + ('formats=', None, "formats for source distribution (comma-separated list)"), + ( + 'keep-temp', + 'k', + "keep the distribution tree around after creating " + "archive file(s)", + ), + ( + 'dist-dir=', + 'd', + "directory to put the source distribution archive(s) in " "[default: dist]", + ), + ( + 'metadata-check', + None, + "Ensure that all required elements of meta-data " + "are supplied. Warn if any missing. [default]", + ), + ( + 'owner=', + 'u', + "Owner name used when creating a tar file [default: current user]", + ), + ( + 'group=', + 'g', + "Group name used when creating a tar file [default: current group]", + ), + ] + + boolean_options = [ + 'use-defaults', + 'prune', + 'manifest-only', + 'force-manifest', + 'keep-temp', + 'metadata-check', + ] help_options = [ - ('help-formats', None, - "list available distribution formats", show_formats), - ] + ('help-formats', None, "list available distribution formats", show_formats), + ] - negative_opt = {'no-defaults': 'use-defaults', - 'no-prune': 'prune' } + negative_opt = {'no-defaults': 'use-defaults', 'no-prune': 'prune'} sub_commands = [('check', checking_metadata)] @@ -131,8 +152,7 @@ def finalize_options(self): bad_format = archive_util.check_archive_formats(self.formats) if bad_format: - raise DistutilsOptionError( - "unknown archive format '%s'" % bad_format) + raise DistutilsOptionError("unknown archive format '%s'" % bad_format) if self.dist_dir is None: self.dist_dir = "dist" @@ -161,8 +181,11 @@ def run(self): def check_metadata(self): """Deprecated API.""" - warn("distutils.command.sdist.check_metadata is deprecated, \ - use the check command instead", PendingDeprecationWarning) + warn( + "distutils.command.sdist.check_metadata is deprecated, \ + use the check command instead", + PendingDeprecationWarning, + ) check = self.distribution.get_command_obj('check') check.ensure_finalized() check.run() @@ -189,9 +212,10 @@ def get_file_list(self): return if not template_exists: - self.warn(("manifest template '%s' does not exist " + - "(using default file list)") % - self.template) + self.warn( + ("manifest template '%s' does not exist " + "(using default file list)") + % self.template + ) self.filelist.findall() if self.use_defaults: @@ -259,8 +283,9 @@ def _add_defaults_standards(self): break if not got_it: - self.warn("standard file not found: should have one of " + - ', '.join(alts)) + self.warn( + "standard file not found: should have one of " + ', '.join(alts) + ) else: if self._cs_path_exists(fn): self.filelist.append(fn) @@ -328,14 +353,20 @@ def read_template(self): 'self.filelist', which updates itself accordingly. """ log.info("reading manifest template '%s'", self.template) - template = TextFile(self.template, strip_comments=1, skip_blanks=1, - join_lines=1, lstrip_ws=1, rstrip_ws=1, - collapse_join=1) + template = TextFile( + self.template, + strip_comments=1, + skip_blanks=1, + join_lines=1, + lstrip_ws=1, + rstrip_ws=1, + collapse_join=1, + ) try: while True: line = template.readline() - if line is None: # end of file + if line is None: # end of file break try: @@ -344,9 +375,10 @@ def read_template(self): # malformed lines, or a ValueError from the lower-level # convert_path function except (DistutilsTemplateError, ValueError) as msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + self.warn( + "%s, line %d: %s" + % (template.filename, template.current_line, msg) + ) finally: template.close() @@ -369,8 +401,7 @@ def prune_file_list(self): else: seps = '/' - vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', - '_darcs'] + vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', '_darcs'] vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps) self.filelist.exclude_pattern(vcs_ptrn, is_regex=1) @@ -380,14 +411,19 @@ def write_manifest(self): named by 'self.manifest'. """ if self._manifest_is_not_generated(): - log.info("not writing to manually maintained " - "manifest file '%s'" % self.manifest) + log.info( + "not writing to manually maintained " + "manifest file '%s'" % self.manifest + ) return content = self.filelist.files[:] content.insert(0, '# file GENERATED by distutils, do NOT edit') - self.execute(file_util.write_file, (self.manifest, content), - "writing manifest file '%s'" % self.manifest) + self.execute( + file_util.write_file, + (self.manifest, content), + "writing manifest file '%s'" % self.manifest, + ) def _manifest_is_not_generated(self): # check for special comment used in 3.1.3 and higher @@ -437,10 +473,10 @@ def make_release_tree(self, base_dir, files): # out-of-date, because by default we blow away 'base_dir' when # we're done making the distribution archives.) - if hasattr(os, 'link'): # can make hard links on this system + if hasattr(os, 'link'): # can make hard links on this system link = 'hard' msg = "making hard links in %s..." % base_dir - else: # nope, have to copy + else: # nope, have to copy link = None msg = "copying files to %s..." % base_dir @@ -471,14 +507,15 @@ def make_distribution(self): base_name = os.path.join(self.dist_dir, base_dir) self.make_release_tree(base_dir, self.filelist.files) - archive_files = [] # remember names of files we create + archive_files = [] # remember names of files we create # tar archive must be created last to avoid overwrite and remove if 'tar' in self.formats: self.formats.append(self.formats.pop(self.formats.index('tar'))) for fmt in self.formats: - file = self.make_archive(base_name, fmt, base_dir=base_dir, - owner=self.owner, group=self.group) + file = self.make_archive( + base_name, fmt, base_dir=base_dir, owner=self.owner, group=self.group + ) archive_files.append(file) self.distribution.dist_files.append(('sdist', '', file)) diff --git a/setuptools/_distutils/command/upload.py b/setuptools/_distutils/command/upload.py index 95e9fda186f..782e3dea965 100644 --- a/setuptools/_distutils/command/upload.py +++ b/setuptools/_distutils/command/upload.py @@ -31,10 +31,9 @@ class upload(PyPIRCCommand): description = "upload binary package to PyPI" user_options = PyPIRCCommand.user_options + [ - ('sign', 's', - 'sign files to upload using gpg'), + ('sign', 's', 'sign files to upload using gpg'), ('identity=', 'i', 'GPG identity used to sign files'), - ] + ] boolean_options = PyPIRCCommand.boolean_options + ['sign'] @@ -49,9 +48,7 @@ def initialize_options(self): def finalize_options(self): PyPIRCCommand.finalize_options(self) if self.identity and not self.sign: - raise DistutilsOptionError( - "Must use --sign for --identity to have meaning" - ) + raise DistutilsOptionError("Must use --sign for --identity to have meaning") config = self._read_pypirc() if config != {}: self.username = config['username'] @@ -66,16 +63,17 @@ def finalize_options(self): def run(self): if not self.distribution.dist_files: - msg = ("Must create and upload files in one command " - "(e.g. setup.py sdist upload)") + msg = ( + "Must create and upload files in one command " + "(e.g. setup.py sdist upload)" + ) raise DistutilsOptionError(msg) for command, pyversion, filename in self.distribution.dist_files: self.upload_file(command, pyversion, filename) def upload_file(self, command, pyversion, filename): # Makes sure the repository URL is compliant - schema, netloc, url, params, query, fragments = \ - urlparse(self.repository) + schema, netloc, url, params, query, fragments = urlparse(self.repository) if params or query or fragments: raise AssertionError("Incompatible url %s" % self.repository) @@ -87,12 +85,11 @@ def upload_file(self, command, pyversion, filename): gpg_args = ["gpg", "--detach-sign", "-a", filename] if self.identity: gpg_args[2:2] = ["--local-user", self.identity] - spawn(gpg_args, - dry_run=self.dry_run) + spawn(gpg_args, dry_run=self.dry_run) # Fill in the data - send all the meta-data in case we need to # register a new release - f = open(filename,'rb') + f = open(filename, 'rb') try: content = f.read() finally: @@ -103,16 +100,13 @@ def upload_file(self, command, pyversion, filename): # action ':action': 'file_upload', 'protocol_version': '1', - # identify release 'name': meta.get_name(), 'version': meta.get_version(), - # file content - 'content': (os.path.basename(filename),content), + 'content': (os.path.basename(filename), content), 'filetype': command, 'pyversion': pyversion, - # additional meta-data 'metadata_version': '1.0', 'summary': meta.get_description(), @@ -129,7 +123,7 @@ def upload_file(self, command, pyversion, filename): 'provides': meta.get_provides(), 'requires': meta.get_requires(), 'obsoletes': meta.get_obsoletes(), - } + } data['comment'] = '' @@ -145,8 +139,7 @@ def upload_file(self, command, pyversion, filename): if self.sign: with open(filename + ".asc", "rb") as f: - data['gpg_signature'] = (os.path.basename(filename) + ".asc", - f.read()) + data['gpg_signature'] = (os.path.basename(filename) + ".asc", f.read()) # set up the authentication user_pass = (self.username + ":" + self.password).encode('ascii') @@ -187,8 +180,7 @@ def upload_file(self, command, pyversion, filename): 'Authorization': auth, } - request = Request(self.repository, data=body, - headers=headers) + request = Request(self.repository, data=body, headers=headers) # send the data try: result = urlopen(request) @@ -202,8 +194,7 @@ def upload_file(self, command, pyversion, filename): raise if status == 200: - self.announce('Server response (%s): %s' % (status, reason), - log.INFO) + self.announce('Server response (%s): %s' % (status, reason), log.INFO) if self.show_response: text = self._read_pypi_response(result) msg = '\n'.join(('-' * 75, text, '-' * 75)) diff --git a/setuptools/_distutils/config.py b/setuptools/_distutils/config.py index 2171abd6969..34a1c3b7c9e 100644 --- a/setuptools/_distutils/config.py +++ b/setuptools/_distutils/config.py @@ -18,20 +18,19 @@ password:%s """ + class PyPIRCCommand(Command): - """Base command that knows how to handle the .pypirc file - """ + """Base command that knows how to handle the .pypirc file""" + DEFAULT_REPOSITORY = 'https://upload.pypi.org/legacy/' DEFAULT_REALM = 'pypi' repository = None realm = None user_options = [ - ('repository=', 'r', - "url of repository [default: %s]" % \ - DEFAULT_REPOSITORY), - ('show-response', None, - 'display full response text from server')] + ('repository=', 'r', "url of repository [default: %s]" % DEFAULT_REPOSITORY), + ('show-response', None, 'display full response text from server'), + ] boolean_options = ['show-response'] @@ -58,9 +57,11 @@ def _read_pypirc(self): if 'distutils' in sections: # let's get the list of servers index_servers = config.get('distutils', 'index-servers') - _servers = [server.strip() for server in - index_servers.split('\n') - if server.strip() != ''] + _servers = [ + server.strip() + for server in index_servers.split('\n') + if server.strip() != '' + ] if _servers == []: # nothing set, let's try to get the default pypi if 'pypi' in sections: @@ -74,10 +75,11 @@ def _read_pypirc(self): current['username'] = config.get(server, 'username') # optional params - for key, default in (('repository', - self.DEFAULT_REPOSITORY), - ('realm', self.DEFAULT_REALM), - ('password', None)): + for key, default in ( + ('repository', self.DEFAULT_REPOSITORY), + ('realm', self.DEFAULT_REALM), + ('password', None), + ): if config.has_option(server, key): current[key] = config.get(server, key) else: @@ -86,13 +88,17 @@ def _read_pypirc(self): # work around people having "repository" for the "pypi" # section of their config set to the HTTP (rather than # HTTPS) URL - if (server == 'pypi' and - repository in (self.DEFAULT_REPOSITORY, 'pypi')): + if server == 'pypi' and repository in ( + self.DEFAULT_REPOSITORY, + 'pypi', + ): current['repository'] = self.DEFAULT_REPOSITORY return current - if (current['server'] == repository or - current['repository'] == repository): + if ( + current['server'] == repository + or current['repository'] == repository + ): return current elif 'server-login' in sections: # old format @@ -101,17 +107,20 @@ def _read_pypirc(self): repository = config.get(server, 'repository') else: repository = self.DEFAULT_REPOSITORY - return {'username': config.get(server, 'username'), - 'password': config.get(server, 'password'), - 'repository': repository, - 'server': server, - 'realm': self.DEFAULT_REALM} + return { + 'username': config.get(server, 'username'), + 'password': config.get(server, 'password'), + 'repository': repository, + 'server': server, + 'realm': self.DEFAULT_REALM, + } return {} def _read_pypi_response(self, response): """Read and decode a PyPI HTTP response.""" import cgi + content_type = response.getheader('content-type', 'text/plain') encoding = cgi.parse_header(content_type)[1].get('charset', 'ascii') return response.read().decode(encoding) diff --git a/setuptools/_distutils/core.py b/setuptools/_distutils/core.py index d603d4a45a7..093c68434bd 100644 --- a/setuptools/_distutils/core.py +++ b/setuptools/_distutils/core.py @@ -29,7 +29,8 @@ or: %(script)s cmd --help """ -def gen_usage (script_name): + +def gen_usage(script_name): script = os.path.basename(script_name) return USAGE % vars() @@ -39,22 +40,51 @@ def gen_usage (script_name): _setup_distribution = None # Legal keyword arguments for the setup() function -setup_keywords = ('distclass', 'script_name', 'script_args', 'options', - 'name', 'version', 'author', 'author_email', - 'maintainer', 'maintainer_email', 'url', 'license', - 'description', 'long_description', 'keywords', - 'platforms', 'classifiers', 'download_url', - 'requires', 'provides', 'obsoletes', - ) +setup_keywords = ( + 'distclass', + 'script_name', + 'script_args', + 'options', + 'name', + 'version', + 'author', + 'author_email', + 'maintainer', + 'maintainer_email', + 'url', + 'license', + 'description', + 'long_description', + 'keywords', + 'platforms', + 'classifiers', + 'download_url', + 'requires', + 'provides', + 'obsoletes', +) # Legal keyword arguments for the Extension constructor -extension_keywords = ('name', 'sources', 'include_dirs', - 'define_macros', 'undef_macros', - 'library_dirs', 'libraries', 'runtime_library_dirs', - 'extra_objects', 'extra_compile_args', 'extra_link_args', - 'swig_opts', 'export_symbols', 'depends', 'language') - -def setup (**attrs): +extension_keywords = ( + 'name', + 'sources', + 'include_dirs', + 'define_macros', + 'undef_macros', + 'library_dirs', + 'libraries', + 'runtime_library_dirs', + 'extra_objects', + 'extra_compile_args', + 'extra_link_args', + 'swig_opts', + 'export_symbols', + 'depends', + 'language', +) + + +def setup(**attrs): """The gateway to the Distutils: do everything your setup script needs to do, in a highly flexible and user-driven way. Briefly: create a Distribution instance; find and parse config files; parse the command @@ -99,7 +129,7 @@ class found in 'cmdclass' is used in place of the default, which is if 'script_name' not in attrs: attrs['script_name'] = os.path.basename(sys.argv[0]) - if 'script_args' not in attrs: + if 'script_args' not in attrs: attrs['script_args'] = sys.argv[1:] # Create the Distribution instance, using the remaining arguments @@ -110,8 +140,7 @@ class found in 'cmdclass' is used in place of the default, which is if 'name' not in attrs: raise SystemExit("error in setup command: %s" % msg) else: - raise SystemExit("error in %s setup command: %s" % \ - (attrs['name'], msg)) + raise SystemExit("error in %s setup command: %s" % (attrs['name'], msg)) if _setup_stop_after == "init": return dist @@ -155,8 +184,7 @@ class found in 'cmdclass' is used in place of the default, which is else: raise SystemExit("error: %s" % (exc,)) - except (DistutilsError, - CCompilerError) as msg: + except (DistutilsError, CCompilerError) as msg: if DEBUG: raise else: @@ -164,10 +192,11 @@ class found in 'cmdclass' is used in place of the default, which is return dist + # setup () -def run_setup (script_name, script_args=None, stop_after="run"): +def run_setup(script_name, script_args=None, stop_after="run"): """Run a setup script in a somewhat controlled environment, and return the Distribution instance that drives things. This is useful if you need to find out the distribution meta-data (passed as @@ -222,13 +251,18 @@ def run_setup (script_name, script_args=None, stop_after="run"): pass if _setup_distribution is None: - raise RuntimeError(("'distutils.core.setup()' was never called -- " - "perhaps '%s' is not a Distutils setup script?") % \ - script_name) + raise RuntimeError( + ( + "'distutils.core.setup()' was never called -- " + "perhaps '%s' is not a Distutils setup script?" + ) + % script_name + ) # I wonder if the setup script's namespace -- g and l -- would be of # any interest to callers? - #print "_setup_distribution:", _setup_distribution + # print "_setup_distribution:", _setup_distribution return _setup_distribution + # run_setup () diff --git a/setuptools/_distutils/cygwinccompiler.py b/setuptools/_distutils/cygwinccompiler.py index f1c38e390cf..23a4c7d6fb3 100644 --- a/setuptools/_distutils/cygwinccompiler.py +++ b/setuptools/_distutils/cygwinccompiler.py @@ -55,18 +55,23 @@ from distutils.unixccompiler import UnixCCompiler from distutils.file_util import write_file -from distutils.errors import (DistutilsExecError, CCompilerError, - CompileError, UnknownFileError) +from distutils.errors import ( + DistutilsExecError, + CCompilerError, + CompileError, + UnknownFileError, +) from distutils.version import LooseVersion from distutils.spawn import find_executable + def get_msvcr(): """Include the appropriate MSVC runtime library if Python was built with MSVC 7.0 or later. """ msc_pos = sys.version.find('MSC v.') if msc_pos != -1: - msc_ver = sys.version[msc_pos+6:msc_pos+10] + msc_ver = sys.version[msc_pos + 6 : msc_pos + 10] if msc_ver == '1300': # MSVC 7.0 return ['msvcr70'] @@ -87,8 +92,8 @@ def get_msvcr(): class CygwinCCompiler(UnixCCompiler): - """ Handles the Cygwin port of the GNU C compiler to Windows. - """ + """Handles the Cygwin port of the GNU C compiler to Windows.""" + compiler_type = 'cygwin' obj_extension = ".o" static_lib_extension = ".a" @@ -102,25 +107,24 @@ def __init__(self, verbose=0, dry_run=0, force=0): UnixCCompiler.__init__(self, verbose, dry_run, force) status, details = check_config_h() - self.debug_print("Python's GCC status: %s (details: %s)" % - (status, details)) + self.debug_print("Python's GCC status: %s (details: %s)" % (status, details)) if status is not CONFIG_H_OK: self.warn( "Python's pyconfig.h doesn't seem to support your compiler. " "Reason: %s. " - "Compiling may fail because of undefined preprocessor macros." - % details) + "Compiling may fail because of undefined preprocessor macros." % details + ) self.cc = os.environ.get('CC', 'gcc') self.cxx = os.environ.get('CXX', 'g++') - if ('gcc' in self.cc): # Start gcc workaround - self.gcc_version, self.ld_version, self.dllwrap_version = \ - get_versions() - self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % - (self.gcc_version, - self.ld_version, - self.dllwrap_version) ) + if 'gcc' in self.cc: # Start gcc workaround + self.gcc_version, self.ld_version, self.dllwrap_version = get_versions() + self.debug_print( + self.compiler_type + + ": gcc %s, ld %s, dllwrap %s\n" + % (self.gcc_version, self.ld_version, self.dllwrap_version) + ) # ld_version >= "2.10.90" and < "2.13" should also be able to use # gcc -mdll instead of dllwrap @@ -138,24 +142,24 @@ def __init__(self, verbose=0, dry_run=0, force=0): shared_option = "-shared" else: shared_option = "-mdll -static" - else: # Assume linker is up to date + else: # Assume linker is up to date self.linker_dll = self.cc shared_option = "-shared" - self.set_executables(compiler='%s -mcygwin -O -Wall' % self.cc, - compiler_so='%s -mcygwin -mdll -O -Wall' % self.cc, - compiler_cxx='%s -mcygwin -O -Wall' % self.cxx, - linker_exe='%s -mcygwin' % self.cc, - linker_so=('%s -mcygwin %s' % - (self.linker_dll, shared_option))) + self.set_executables( + compiler='%s -mcygwin -O -Wall' % self.cc, + compiler_so='%s -mcygwin -mdll -O -Wall' % self.cc, + compiler_cxx='%s -mcygwin -O -Wall' % self.cxx, + linker_exe='%s -mcygwin' % self.cc, + linker_so=('%s -mcygwin %s' % (self.linker_dll, shared_option)), + ) # cygwin and mingw32 need different sets of libraries - if ('gcc' in self.cc and self.gcc_version == "2.91.57"): + if 'gcc' in self.cc and self.gcc_version == "2.91.57": # cygwin shouldn't need msvcrt, but without the dlls will crash # (gcc version 2.91.57) -- perhaps something about initialization - self.dll_libraries=["msvcrt"] - self.warn( - "Consider upgrading to a newer version of gcc") + self.dll_libraries = ["msvcrt"] + self.warn("Consider upgrading to a newer version of gcc") else: # Include the appropriate MSVC runtime library if Python was built # with MSVC 7.0 or later. @@ -169,17 +173,30 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): self.spawn(["windres", "-i", src, "-o", obj]) except DistutilsExecError as msg: raise CompileError(msg) - else: # for other files use the C-compiler + else: # for other files use the C-compiler try: - self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + - extra_postargs) + self.spawn( + self.compiler_so + cc_args + [src, '-o', obj] + extra_postargs + ) except DistutilsExecError as msg: raise CompileError(msg) - def link(self, target_desc, objects, output_filename, output_dir=None, - libraries=None, library_dirs=None, runtime_library_dirs=None, - export_symbols=None, debug=0, extra_preargs=None, - extra_postargs=None, build_temp=None, target_lang=None): + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): """Link the objects.""" # use separate copies, so we can modify the lists extra_preargs = copy.copy(extra_preargs or []) @@ -191,8 +208,9 @@ def link(self, target_desc, objects, output_filename, output_dir=None, # handle export symbols by creating a def-file # with executables this only works with gcc/ld as linker - if ((export_symbols is not None) and - (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): + if (export_symbols is not None) and ( + target_desc != self.EXECUTABLE or self.linker_dll == "gcc" + ): # (The linker doesn't do anything if output is up-to-date. # So it would probably better to check if we really need this, # but for this we had to insert some unchanged parts of @@ -204,20 +222,18 @@ def link(self, target_desc, objects, output_filename, output_dir=None, temp_dir = os.path.dirname(objects[0]) # name of dll to give the helper files the same base name (dll_name, dll_extension) = os.path.splitext( - os.path.basename(output_filename)) + os.path.basename(output_filename) + ) # generate the filenames for these files def_file = os.path.join(temp_dir, dll_name + ".def") lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a") # Generate .def file - contents = [ - "LIBRARY %s" % os.path.basename(output_filename), - "EXPORTS"] + contents = ["LIBRARY %s" % os.path.basename(output_filename), "EXPORTS"] for sym in export_symbols: contents.append(sym) - self.execute(write_file, (def_file, contents), - "writing %s" % def_file) + self.execute(write_file, (def_file, contents), "writing %s" % def_file) # next add options for def-file and to creating import libraries @@ -229,11 +245,11 @@ def link(self, target_desc, objects, output_filename, output_dir=None, # we use gcc/ld here and can be sure ld is >= 2.9.10 else: # doesn't work: bfd_close build\...\libfoo.a: Invalid operation - #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file]) + # extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file]) # for gcc/ld the def-file is specified as any object files objects.append(def_file) - #end: if ((export_symbols is not None) and + # end: if ((export_symbols is not None) and # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): # who wants symbols and a many times larger output file @@ -245,12 +261,22 @@ def link(self, target_desc, objects, output_filename, output_dir=None, if not debug: extra_preargs.append("-s") - UnixCCompiler.link(self, target_desc, objects, output_filename, - output_dir, libraries, library_dirs, - runtime_library_dirs, - None, # export_symbols, we do this in our def-file - debug, extra_preargs, extra_postargs, build_temp, - target_lang) + UnixCCompiler.link( + self, + target_desc, + objects, + output_filename, + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + None, # export_symbols, we do this in our def-file + debug, + extra_preargs, + extra_postargs, + build_temp, + target_lang, + ) # -- Miscellaneous methods ----------------------------------------- @@ -262,66 +288,68 @@ def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): for src_name in source_filenames: # use normcase to make sure '.rc' is really '.rc' and not '.RC' base, ext = os.path.splitext(os.path.normcase(src_name)) - if ext not in (self.src_extensions + ['.rc','.res']): - raise UnknownFileError("unknown file type '%s' (from '%s')" % \ - (ext, src_name)) + if ext not in (self.src_extensions + ['.rc', '.res']): + raise UnknownFileError( + "unknown file type '%s' (from '%s')" % (ext, src_name) + ) if strip_dir: - base = os.path.basename (base) + base = os.path.basename(base) if ext in ('.res', '.rc'): # these need to be compiled to object files - obj_names.append (os.path.join(output_dir, - base + ext + self.obj_extension)) + obj_names.append( + os.path.join(output_dir, base + ext + self.obj_extension) + ) else: - obj_names.append (os.path.join(output_dir, - base + self.obj_extension)) + obj_names.append(os.path.join(output_dir, base + self.obj_extension)) return obj_names + # the same as cygwin plus some additional parameters class Mingw32CCompiler(CygwinCCompiler): - """ Handles the Mingw32 port of the GNU C compiler to Windows. - """ + """Handles the Mingw32 port of the GNU C compiler to Windows.""" + compiler_type = 'mingw32' def __init__(self, verbose=0, dry_run=0, force=0): - CygwinCCompiler.__init__ (self, verbose, dry_run, force) + CygwinCCompiler.__init__(self, verbose, dry_run, force) # ld_version >= "2.13" support -shared so use it instead of # -mdll -static - if ('gcc' in self.cc and self.ld_version < "2.13"): + if 'gcc' in self.cc and self.ld_version < "2.13": shared_option = "-mdll -static" else: shared_option = "-shared" # A real mingw32 doesn't need to specify a different entry point, # but cygwin 2.91.57 in no-cygwin-mode needs it. - if ('gcc' in self.cc and self.gcc_version <= "2.91.57"): + if 'gcc' in self.cc and self.gcc_version <= "2.91.57": entry_point = '--entry _DllMain@12' else: entry_point = '' if is_cygwincc(self.cc): - raise CCompilerError( - 'Cygwin gcc cannot be used with --compiler=mingw32') - - self.set_executables(compiler='%s -O -Wall' % self.cc, - compiler_so='%s -mdll -O -Wall' % self.cc, - compiler_cxx='%s -O -Wall' % self.cxx, - linker_exe='%s' % self.cc, - linker_so='%s %s %s' - % (self.linker_dll, shared_option, - entry_point)) + raise CCompilerError('Cygwin gcc cannot be used with --compiler=mingw32') + + self.set_executables( + compiler='%s -O -Wall' % self.cc, + compiler_so='%s -mdll -O -Wall' % self.cc, + compiler_cxx='%s -O -Wall' % self.cxx, + linker_exe='%s' % self.cc, + linker_so='%s %s %s' % (self.linker_dll, shared_option, entry_point), + ) # Maybe we should also append -mthreads, but then the finished # dlls need another dll (mingwm10.dll see Mingw32 docs) # (-mthreads: Support thread-safe exception handling on `Mingw32') # no additional libraries needed - self.dll_libraries=[] + self.dll_libraries = [] # Include the appropriate MSVC runtime library if Python was built # with MSVC 7.0 or later. self.dll_libraries = get_msvcr() + # Because these compilers aren't configured in Python's pyconfig.h file by # default, we should at least warn the user if he is using an unmodified # version. @@ -330,6 +358,7 @@ def __init__(self, verbose=0, dry_run=0, force=0): CONFIG_H_NOTOK = "not ok" CONFIG_H_UNCERTAIN = "uncertain" + def check_config_h(): """Check if the current Python installation appears amenable to building extensions with GCC. @@ -374,11 +403,12 @@ def check_config_h(): finally: config_h.close() except OSError as exc: - return (CONFIG_H_UNCERTAIN, - "couldn't read '%s': %s" % (fn, exc.strerror)) + return (CONFIG_H_UNCERTAIN, "couldn't read '%s': %s" % (fn, exc.strerror)) + RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)') + def _find_exe_version(cmd): """Find the version of an executable by running `cmd` in the shell. @@ -400,14 +430,16 @@ def _find_exe_version(cmd): # so we need to decode our bytes return LooseVersion(result.group(1).decode()) + def get_versions(): - """ Try to find out the versions of gcc, ld and dllwrap. + """Try to find out the versions of gcc, ld and dllwrap. If not possible it returns None for it. """ commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version'] return tuple([_find_exe_version(cmd) for cmd in commands]) + def is_cygwincc(cc): '''Try to determine if the compiler that would be used is from cygwin.''' out_string = check_output([cc, '-dumpmachine']) diff --git a/setuptools/_distutils/dep_util.py b/setuptools/_distutils/dep_util.py index d74f5e4e92f..d94e111ca6c 100644 --- a/setuptools/_distutils/dep_util.py +++ b/setuptools/_distutils/dep_util.py @@ -8,28 +8,29 @@ from distutils.errors import DistutilsFileError -def newer (source, target): +def newer(source, target): """Return true if 'source' exists and is more recently modified than 'target', or if 'source' exists and 'target' doesn't. Return false if both exist and 'target' is the same age or younger than 'source'. Raise DistutilsFileError if 'source' does not exist. """ if not os.path.exists(source): - raise DistutilsFileError("file '%s' does not exist" % - os.path.abspath(source)) + raise DistutilsFileError("file '%s' does not exist" % os.path.abspath(source)) if not os.path.exists(target): return 1 from stat import ST_MTIME + mtime1 = os.stat(source)[ST_MTIME] mtime2 = os.stat(target)[ST_MTIME] return mtime1 > mtime2 + # newer () -def newer_pairwise (sources, targets): +def newer_pairwise(sources, targets): """Walk two filename lists in parallel, testing if each source is newer than its corresponding target. Return a pair of lists (sources, targets) where source is newer than target, according to the semantics @@ -48,10 +49,11 @@ def newer_pairwise (sources, targets): return (n_sources, n_targets) + # newer_pairwise () -def newer_group (sources, target, missing='error'): +def newer_group(sources, target, missing='error'): """Return true if 'target' is out-of-date with respect to any file listed in 'sources'. In other words, if 'target' exists and is newer than every file in 'sources', return false; otherwise return true. @@ -73,15 +75,16 @@ def newer_group (sources, target, missing='error'): # we can immediately return true. If we fall through to the end # of the loop, then 'target' is up-to-date and we return false. from stat import ST_MTIME + target_mtime = os.stat(target)[ST_MTIME] for source in sources: if not os.path.exists(source): - if missing == 'error': # blow up when we stat() the file + if missing == 'error': # blow up when we stat() the file pass - elif missing == 'ignore': # missing source dropped from - continue # target's dependency list - elif missing == 'newer': # missing source means target is - return 1 # out-of-date + elif missing == 'ignore': # missing source dropped from + continue # target's dependency list + elif missing == 'newer': # missing source means target is + return 1 # out-of-date source_mtime = os.stat(source)[ST_MTIME] if source_mtime > target_mtime: @@ -89,4 +92,5 @@ def newer_group (sources, target, missing='error'): else: return 0 + # newer_group () diff --git a/setuptools/_distutils/dir_util.py b/setuptools/_distutils/dir_util.py index d5cd8e3e24f..2c19b9833cb 100644 --- a/setuptools/_distutils/dir_util.py +++ b/setuptools/_distutils/dir_util.py @@ -30,7 +30,8 @@ def mkpath(name, mode=0o777, verbose=1, dry_run=0): # Detect a common bug -- name is None if not isinstance(name, str): raise DistutilsInternalError( - "mkpath: 'name' must be a string (got %r)" % (name,)) + "mkpath: 'name' must be a string (got %r)" % (name,) + ) # XXX what's the better way to handle verbosity? print as we create # each directory in the path (the current behaviour), or only announce @@ -45,17 +46,17 @@ def mkpath(name, mode=0o777, verbose=1, dry_run=0): return created_dirs (head, tail) = os.path.split(name) - tails = [tail] # stack of lone dirs to create + tails = [tail] # stack of lone dirs to create while head and tail and not os.path.isdir(head): (head, tail) = os.path.split(head) - tails.insert(0, tail) # push next higher dir onto stack + tails.insert(0, tail) # push next higher dir onto stack # now 'head' contains the deepest directory that already exists # (that is, the child of 'head' in 'name' is the highest directory # that does *not* exist) for d in tails: - #print "head = %s, d = %s: " % (head, d), + # print "head = %s, d = %s: " % (head, d), head = os.path.join(head, d) abs_head = os.path.abspath(head) @@ -71,12 +72,14 @@ def mkpath(name, mode=0o777, verbose=1, dry_run=0): except OSError as exc: if not (exc.errno == errno.EEXIST and os.path.isdir(head)): raise DistutilsFileError( - "could not create '%s': %s" % (head, exc.args[-1])) + "could not create '%s': %s" % (head, exc.args[-1]) + ) created_dirs.append(head) _path_created[abs_head] = 1 return created_dirs + def create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0): """Create all the empty directories under 'base_dir' needed to put 'files' there. @@ -96,8 +99,17 @@ def create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0): for dir in sorted(need_dir): mkpath(dir, mode, verbose=verbose, dry_run=dry_run) -def copy_tree(src, dst, preserve_mode=1, preserve_times=1, - preserve_symlinks=0, update=0, verbose=1, dry_run=0): + +def copy_tree( + src, + dst, + preserve_mode=1, + preserve_times=1, + preserve_symlinks=0, + update=0, + verbose=1, + dry_run=0, +): """Copy an entire directory tree 'src' to a new location 'dst'. Both 'src' and 'dst' must be directory names. If 'src' is not a @@ -120,8 +132,7 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1, from distutils.file_util import copy_file if not dry_run and not os.path.isdir(src): - raise DistutilsFileError( - "cannot copy tree '%s': not a directory" % src) + raise DistutilsFileError("cannot copy tree '%s': not a directory" % src) try: names = os.listdir(src) except OSError as e: @@ -129,7 +140,8 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1, names = [] else: raise DistutilsFileError( - "error listing files in '%s': %s" % (src, e.strerror)) + "error listing files in '%s': %s" % (src, e.strerror) + ) if not dry_run: mkpath(dst, verbose=verbose) @@ -154,27 +166,43 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1, elif os.path.isdir(src_name): outputs.extend( - copy_tree(src_name, dst_name, preserve_mode, - preserve_times, preserve_symlinks, update, - verbose=verbose, dry_run=dry_run)) + copy_tree( + src_name, + dst_name, + preserve_mode, + preserve_times, + preserve_symlinks, + update, + verbose=verbose, + dry_run=dry_run, + ) + ) else: - copy_file(src_name, dst_name, preserve_mode, - preserve_times, update, verbose=verbose, - dry_run=dry_run) + copy_file( + src_name, + dst_name, + preserve_mode, + preserve_times, + update, + verbose=verbose, + dry_run=dry_run, + ) outputs.append(dst_name) return outputs + def _build_cmdtuple(path, cmdtuples): """Helper for remove_tree().""" for f in os.listdir(path): - real_f = os.path.join(path,f) + real_f = os.path.join(path, f) if os.path.isdir(real_f) and not os.path.islink(real_f): _build_cmdtuple(real_f, cmdtuples) else: cmdtuples.append((os.remove, real_f)) cmdtuples.append((os.rmdir, path)) + def remove_tree(directory, verbose=1, dry_run=0): """Recursively remove an entire directory tree. @@ -199,6 +227,7 @@ def remove_tree(directory, verbose=1, dry_run=0): except OSError as exc: log.warn("error removing %s: %s", directory, exc) + def ensure_relative(path): """Take the full path 'path', and make it a relative path. diff --git a/setuptools/_distutils/dist.py b/setuptools/_distutils/dist.py index 37db4d6cd75..f184181da9c 100644 --- a/setuptools/_distutils/dist.py +++ b/setuptools/_distutils/dist.py @@ -69,8 +69,7 @@ class Distribution: ('quiet', 'q', "run quietly (turns verbosity off)"), ('dry-run', 'n', "don't actually do anything"), ('help', 'h', "show detailed help message"), - ('no-user-cfg', None, - 'ignore pydistutils.cfg in your home directory'), + ('no-user-cfg', None, 'ignore pydistutils.cfg in your home directory'), ] # 'common_usage' is a short (2-3 line) string describing the common @@ -84,49 +83,32 @@ class Distribution: # options that are not propagated to the commands display_options = [ - ('help-commands', None, - "list all available commands"), - ('name', None, - "print package name"), - ('version', 'V', - "print package version"), - ('fullname', None, - "print -"), - ('author', None, - "print the author's name"), - ('author-email', None, - "print the author's email address"), - ('maintainer', None, - "print the maintainer's name"), - ('maintainer-email', None, - "print the maintainer's email address"), - ('contact', None, - "print the maintainer's name if known, else the author's"), - ('contact-email', None, - "print the maintainer's email address if known, else the author's"), - ('url', None, - "print the URL for this package"), - ('license', None, - "print the license of the package"), - ('licence', None, - "alias for --license"), - ('description', None, - "print the package description"), - ('long-description', None, - "print the long package description"), - ('platforms', None, - "print the list of platforms"), - ('classifiers', None, - "print the list of classifiers"), - ('keywords', None, - "print the list of keywords"), - ('provides', None, - "print the list of packages/modules provided"), - ('requires', None, - "print the list of packages/modules required"), - ('obsoletes', None, - "print the list of packages/modules made obsolete") - ] + ('help-commands', None, "list all available commands"), + ('name', None, "print package name"), + ('version', 'V', "print package version"), + ('fullname', None, "print -"), + ('author', None, "print the author's name"), + ('author-email', None, "print the author's email address"), + ('maintainer', None, "print the maintainer's name"), + ('maintainer-email', None, "print the maintainer's email address"), + ('contact', None, "print the maintainer's name if known, else the author's"), + ( + 'contact-email', + None, + "print the maintainer's email address if known, else the author's", + ), + ('url', None, "print the URL for this package"), + ('license', None, "print the license of the package"), + ('licence', None, "alias for --license"), + ('description', None, "print the package description"), + ('long-description', None, "print the long package description"), + ('platforms', None, "print the list of platforms"), + ('classifiers', None, "print the list of classifiers"), + ('keywords', None, "print the list of keywords"), + ('provides', None, "print the list of packages/modules provided"), + ('requires', None, "print the list of packages/modules required"), + ('obsoletes', None, "print the list of packages/modules made obsolete"), + ] display_option_names = [translate_longopt(x[0]) for x in display_options] # negative options are options that exclude other options @@ -306,7 +288,7 @@ def get_option_dict(self, command): def dump_option_dicts(self, header=None, commands=None, indent=""): from pprint import pformat - if commands is None: # dump all command option dicts + if commands is None: # dump all command option dicts commands = sorted(self.command_options.keys()) if header is not None: @@ -320,11 +302,9 @@ def dump_option_dicts(self, header=None, commands=None, indent=""): for cmd_name in commands: opt_dict = self.command_options.get(cmd_name) if opt_dict is None: - self.announce(indent + - "no option dict for '%s' command" % cmd_name) + self.announce(indent + "no option dict for '%s' command" % cmd_name) else: - self.announce(indent + - "option dict for '%s' command:" % cmd_name) + self.announce(indent + "option dict for '%s' command:" % cmd_name) out = pformat(opt_dict) for line in out.split('\n'): self.announce(indent + " " + line) @@ -385,10 +365,20 @@ def parse_config_files(self, filenames=None): # Ignore install directory options if we have a venv if sys.prefix != sys.base_prefix: ignore_options = [ - 'install-base', 'install-platbase', 'install-lib', - 'install-platlib', 'install-purelib', 'install-headers', - 'install-scripts', 'install-data', 'prefix', 'exec-prefix', - 'home', 'user', 'root'] + 'install-base', + 'install-platbase', + 'install-lib', + 'install-platlib', + 'install-purelib', + 'install-headers', + 'install-scripts', + 'install-data', + 'prefix', + 'exec-prefix', + 'home', + 'user', + 'root', + ] else: ignore_options = [] @@ -411,7 +401,7 @@ def parse_config_files(self, filenames=None): for opt in options: if opt != '__name__' and opt not in ignore_options: - val = parser.get(section,opt) + val = parser.get(section, opt) opt = opt.replace('-', '_') opt_dict[opt] = (filename, val) @@ -428,7 +418,7 @@ def parse_config_files(self, filenames=None): try: if alias: setattr(self, alias, not strtobool(val)) - elif opt in ('verbose', 'dry_run'): # ugh! + elif opt in ('verbose', 'dry_run'): # ugh! setattr(self, opt, strtobool(val)) else: setattr(self, opt, val) @@ -482,7 +472,7 @@ def parse_command_line(self): return while args: args = self._parse_command_opts(parser, args) - if args is None: # user asked for help (and got it) + if args is None: # user asked for help (and got it) return # Handle the cases of --help as a "global" option, ie. @@ -492,9 +482,9 @@ def parse_command_line(self): # latter, we omit the display-only options and show help for # each command listed on the command line. if self.help: - self._show_help(parser, - display_options=len(self.commands) == 0, - commands=self.commands) + self._show_help( + parser, display_options=len(self.commands) == 0, commands=self.commands + ) return # Oops, no commands found -- an end-user error @@ -511,9 +501,12 @@ def _get_toplevel_options(self): level as well as options recognized for commands. """ return self.global_options + [ - ("command-packages=", None, - "list of packages that provide distutils commands"), - ] + ( + "command-packages=", + None, + "list of packages that provide distutils commands", + ), + ] def _parse_command_opts(self, parser, args): """Parse the command-line options for a single command. @@ -545,14 +538,19 @@ def _parse_command_opts(self, parser, args): # to be sure that the basic "command" interface is implemented. if not issubclass(cmd_class, Command): raise DistutilsClassError( - "command class %s must subclass Command" % cmd_class) + "command class %s must subclass Command" % cmd_class + ) # Also make sure that the command object provides a list of its # known options. - if not (hasattr(cmd_class, 'user_options') and - isinstance(cmd_class.user_options, list)): - msg = ("command class %s must provide " - "'user_options' attribute (a list of tuples)") + if not ( + hasattr(cmd_class, 'user_options') + and isinstance(cmd_class.user_options, list) + ): + msg = ( + "command class %s must provide " + "'user_options' attribute (a list of tuples)" + ) raise DistutilsClassError(msg % cmd_class) # If the command class has a list of negative alias options, @@ -564,36 +562,39 @@ def _parse_command_opts(self, parser, args): # Check for help_options in command class. They have a different # format (tuple of four) so we need to preprocess them here. - if (hasattr(cmd_class, 'help_options') and - isinstance(cmd_class.help_options, list)): + if hasattr(cmd_class, 'help_options') and isinstance( + cmd_class.help_options, list + ): help_options = fix_help_options(cmd_class.help_options) else: help_options = [] # All commands support the global options too, just by adding # in 'global_options'. - parser.set_option_table(self.global_options + - cmd_class.user_options + - help_options) + parser.set_option_table( + self.global_options + cmd_class.user_options + help_options + ) parser.set_negative_aliases(negative_opt) (args, opts) = parser.getopt(args[1:]) if hasattr(opts, 'help') and opts.help: self._show_help(parser, display_options=0, commands=[cmd_class]) return - if (hasattr(cmd_class, 'help_options') and - isinstance(cmd_class.help_options, list)): - help_option_found=0 + if hasattr(cmd_class, 'help_options') and isinstance( + cmd_class.help_options, list + ): + help_option_found = 0 for (help_option, short, desc, func) in cmd_class.help_options: if hasattr(opts, parser.get_attr_name(help_option)): - help_option_found=1 + help_option_found = 1 if callable(func): func() else: raise DistutilsClassError( "invalid help function %r for help option '%s': " "must be a callable object (function, etc.)" - % (func, help_option)) + % (func, help_option) + ) if help_option_found: return @@ -619,8 +620,7 @@ def finalize_options(self): value = [elm.strip() for elm in value.split(',')] setattr(self.metadata, attr, value) - def _show_help(self, parser, global_options=1, display_options=1, - commands=[]): + def _show_help(self, parser, global_options=1, display_options=1, commands=[]): """Show help for the setup script command-line in the form of several lists of command-line options. 'parser' should be a FancyGetopt instance; do not expect it to be returned in the @@ -649,8 +649,9 @@ def _show_help(self, parser, global_options=1, display_options=1, if display_options: parser.set_option_table(self.display_options) parser.print_help( - "Information display options (just display " + - "information, ignore any commands)") + "Information display options (just display " + + "information, ignore any commands)" + ) print('') for command in self.commands: @@ -658,10 +659,10 @@ def _show_help(self, parser, global_options=1, display_options=1, klass = command else: klass = self.get_command_class(command) - if (hasattr(klass, 'help_options') and - isinstance(klass.help_options, list)): - parser.set_option_table(klass.user_options + - fix_help_options(klass.help_options)) + if hasattr(klass, 'help_options') and isinstance(klass.help_options, list): + parser.set_option_table( + klass.user_options + fix_help_options(klass.help_options) + ) else: parser.set_option_table(klass.user_options) parser.print_help("Options for '%s' command:" % klass.__name__) @@ -697,11 +698,10 @@ def handle_display_options(self, option_order): for (opt, val) in option_order: if val and is_display_option.get(opt): opt = translate_longopt(opt) - value = getattr(self.metadata, "get_"+opt)() + value = getattr(self.metadata, "get_" + opt)() if opt in ['keywords', 'platforms']: print(','.join(value)) - elif opt in ('classifiers', 'provides', 'requires', - 'obsoletes'): + elif opt in ('classifiers', 'provides', 'requires', 'obsoletes'): print('\n'.join(value)) else: print(value) @@ -735,6 +735,7 @@ def print_commands(self): 'description'. """ import distutils.command + std_commands = distutils.command.__all__ is_std = {} for cmd in std_commands: @@ -746,18 +747,14 @@ def print_commands(self): extra_commands.append(cmd) max_length = 0 - for cmd in (std_commands + extra_commands): + for cmd in std_commands + extra_commands: if len(cmd) > max_length: max_length = len(cmd) - self.print_command_list(std_commands, - "Standard commands", - max_length) + self.print_command_list(std_commands, "Standard commands", max_length) if extra_commands: print() - self.print_command_list(extra_commands, - "Extra commands", - max_length) + self.print_command_list(extra_commands, "Extra commands", max_length) def get_command_list(self): """Get a list of (command, description) tuples. @@ -769,6 +766,7 @@ def get_command_list(self): # Currently this is only used on Mac OS, for the Mac-only GUI # Distutils interface (by Jack Jansen) import distutils.command + std_commands = distutils.command.__all__ is_std = {} for cmd in std_commands: @@ -780,7 +778,7 @@ def get_command_list(self): extra_commands.append(cmd) rv = [] - for cmd in (std_commands + extra_commands): + for cmd in std_commands + extra_commands: klass = self.cmdclass.get(cmd) if not klass: klass = self.get_command_class(cmd) @@ -836,7 +834,8 @@ def get_command_class(self, command): except AttributeError: raise DistutilsModuleError( "invalid command '%s' (no class '%s' in module '%s')" - % (command, klass_name, module_name)) + % (command, klass_name, module_name) + ) self.cmdclass[command] = klass return klass @@ -852,8 +851,10 @@ def get_command_obj(self, command, create=1): cmd_obj = self.command_obj.get(command) if not cmd_obj and create: if DEBUG: - self.announce("Distribution.get_command_obj(): " - "creating '%s' command object" % command) + self.announce( + "Distribution.get_command_obj(): " + "creating '%s' command object" % command + ) klass = self.get_command_class(command) cmd_obj = self.command_obj[command] = klass(self) @@ -887,11 +888,9 @@ def _set_command_options(self, command_obj, option_dict=None): self.announce(" setting options for '%s' command:" % command_name) for (option, (source, value)) in option_dict.items(): if DEBUG: - self.announce(" %s = %s (from %s)" % (option, value, - source)) + self.announce(" %s = %s (from %s)" % (option, value, source)) try: - bool_opts = [translate_longopt(o) - for o in command_obj.boolean_options] + bool_opts = [translate_longopt(o) for o in command_obj.boolean_options] except AttributeError: bool_opts = [] try: @@ -910,7 +909,8 @@ def _set_command_options(self, command_obj, option_dict=None): else: raise DistutilsOptionError( "error in %s: command '%s' has no such option '%s'" - % (source, command_name, option)) + % (source, command_name, option) + ) except ValueError as msg: raise DistutilsOptionError(msg) @@ -934,6 +934,7 @@ def reinitialize_command(self, command, reinit_subcommands=0): Returns the reinitialized command object. """ from distutils.cmd import Command + if not isinstance(command, Command): command_name = command command = self.get_command_obj(command_name) @@ -1010,9 +1011,11 @@ def has_data_files(self): return self.data_files and len(self.data_files) > 0 def is_pure(self): - return (self.has_pure_modules() and - not self.has_ext_modules() and - not self.has_c_libraries()) + return ( + self.has_pure_modules() + and not self.has_ext_modules() + and not self.has_c_libraries() + ) # -- Metadata query methods ---------------------------------------- @@ -1021,19 +1024,35 @@ def is_pure(self): # to self.metadata.get_XXX. The actual code is in the # DistributionMetadata class, below. + class DistributionMetadata: """Dummy class to hold the distribution meta-data: name, version, author, and so forth. """ - _METHOD_BASENAMES = ("name", "version", "author", "author_email", - "maintainer", "maintainer_email", "url", - "license", "description", "long_description", - "keywords", "platforms", "fullname", "contact", - "contact_email", "classifiers", "download_url", - # PEP 314 - "provides", "requires", "obsoletes", - ) + _METHOD_BASENAMES = ( + "name", + "version", + "author", + "author_email", + "maintainer", + "maintainer_email", + "url", + "license", + "description", + "long_description", + "keywords", + "platforms", + "fullname", + "contact", + "contact_email", + "classifiers", + "download_url", + # PEP 314 + "provides", + "requires", + "obsoletes", + ) def __init__(self, path=None): if path is not None: @@ -1111,18 +1130,22 @@ def _read_list(name): self.obsoletes = None def write_pkg_info(self, base_dir): - """Write the PKG-INFO file into the release tree. - """ - with open(os.path.join(base_dir, 'PKG-INFO'), 'w', - encoding='UTF-8') as pkg_info: + """Write the PKG-INFO file into the release tree.""" + with open( + os.path.join(base_dir, 'PKG-INFO'), 'w', encoding='UTF-8' + ) as pkg_info: self.write_pkg_file(pkg_info) def write_pkg_file(self, file): - """Write the PKG-INFO format data to a file object. - """ + """Write the PKG-INFO format data to a file object.""" version = '1.0' - if (self.provides or self.requires or self.obsoletes or - self.classifiers or self.download_url): + if ( + self.provides + or self.requires + or self.obsoletes + or self.classifiers + or self.download_url + ): version = '1.1' file.write('Metadata-Version: %s\n' % version) @@ -1189,6 +1212,7 @@ def get_url(self): def get_license(self): return self.license or "UNKNOWN" + get_licence = get_license def get_description(self): @@ -1224,6 +1248,7 @@ def get_requires(self): def set_requires(self, value): import distutils.versionpredicate + for v in value: distutils.versionpredicate.VersionPredicate(v) self.requires = list(value) @@ -1235,6 +1260,7 @@ def set_provides(self, value): value = [v.strip() for v in value] for v in value: import distutils.versionpredicate + distutils.versionpredicate.split_provision(v) self.provides = value @@ -1243,10 +1269,12 @@ def get_obsoletes(self): def set_obsoletes(self, value): import distutils.versionpredicate + for v in value: distutils.versionpredicate.VersionPredicate(v) self.obsoletes = list(value) + def fix_help_options(options): """Convert a 4-tuple 'help_options' list as found in various command classes to the 3-tuple form required by FancyGetopt. diff --git a/setuptools/_distutils/errors.py b/setuptools/_distutils/errors.py index 8b93059e19f..626254c321f 100644 --- a/setuptools/_distutils/errors.py +++ b/setuptools/_distutils/errors.py @@ -8,90 +8,120 @@ This module is safe to use in "from ... import *" mode; it only exports symbols whose names start with "Distutils" and end with "Error".""" -class DistutilsError (Exception): + +class DistutilsError(Exception): """The root of all Distutils evil.""" + pass -class DistutilsModuleError (DistutilsError): + +class DistutilsModuleError(DistutilsError): """Unable to load an expected module, or to find an expected class within some module (in particular, command modules and classes).""" + pass -class DistutilsClassError (DistutilsError): + +class DistutilsClassError(DistutilsError): """Some command class (or possibly distribution class, if anyone feels a need to subclass Distribution) is found not to be holding up its end of the bargain, ie. implementing some part of the "command "interface.""" + pass -class DistutilsGetoptError (DistutilsError): + +class DistutilsGetoptError(DistutilsError): """The option table provided to 'fancy_getopt()' is bogus.""" + pass -class DistutilsArgError (DistutilsError): + +class DistutilsArgError(DistutilsError): """Raised by fancy_getopt in response to getopt.error -- ie. an error in the command line usage.""" + pass -class DistutilsFileError (DistutilsError): + +class DistutilsFileError(DistutilsError): """Any problems in the filesystem: expected file not found, etc. Typically this is for problems that we detect before OSError could be raised.""" + pass -class DistutilsOptionError (DistutilsError): + +class DistutilsOptionError(DistutilsError): """Syntactic/semantic errors in command options, such as use of mutually conflicting options, or inconsistent options, badly-spelled values, etc. No distinction is made between option values originating in the setup script, the command line, config files, or what-have-you -- but if we *know* something originated in the setup script, we'll raise DistutilsSetupError instead.""" + pass -class DistutilsSetupError (DistutilsError): + +class DistutilsSetupError(DistutilsError): """For errors that can be definitely blamed on the setup script, such as invalid keyword arguments to 'setup()'.""" + pass -class DistutilsPlatformError (DistutilsError): + +class DistutilsPlatformError(DistutilsError): """We don't know how to do something on the current platform (but we do know how to do it on some platform) -- eg. trying to compile C files on a platform not supported by a CCompiler subclass.""" + pass -class DistutilsExecError (DistutilsError): + +class DistutilsExecError(DistutilsError): """Any problems executing an external program (such as the C compiler, when compiling C files).""" + pass -class DistutilsInternalError (DistutilsError): + +class DistutilsInternalError(DistutilsError): """Internal inconsistencies or impossibilities (obviously, this should never be seen if the code is working!).""" + pass -class DistutilsTemplateError (DistutilsError): + +class DistutilsTemplateError(DistutilsError): """Syntax error in a file list template.""" + class DistutilsByteCompileError(DistutilsError): """Byte compile error.""" + # Exception classes used by the CCompiler implementation classes -class CCompilerError (Exception): +class CCompilerError(Exception): """Some compile/link operation failed.""" -class PreprocessError (CCompilerError): + +class PreprocessError(CCompilerError): """Failure to preprocess one or more C/C++ files.""" -class CompileError (CCompilerError): + +class CompileError(CCompilerError): """Failure to compile one or more C/C++ source files.""" -class LibError (CCompilerError): + +class LibError(CCompilerError): """Failure to create a static library from one or more C/C++ object files.""" -class LinkError (CCompilerError): + +class LinkError(CCompilerError): """Failure to link one or more C/C++ object files into an executable or shared library file.""" -class UnknownFileError (CCompilerError): + +class UnknownFileError(CCompilerError): """Attempt to process an unknown file type.""" diff --git a/setuptools/_distutils/extension.py b/setuptools/_distutils/extension.py index c507da360aa..b05c5d909fc 100644 --- a/setuptools/_distutils/extension.py +++ b/setuptools/_distutils/extension.py @@ -16,6 +16,7 @@ # import that large-ish module (indirectly, through distutils.core) in # order to do anything. + class Extension: """Just a collection of attributes that describes an extension module and everything needed to build it (hopefully in a portable @@ -83,27 +84,29 @@ class Extension: # When adding arguments to this constructor, be sure to update # setup_keywords in core.py. - def __init__(self, name, sources, - include_dirs=None, - define_macros=None, - undef_macros=None, - library_dirs=None, - libraries=None, - runtime_library_dirs=None, - extra_objects=None, - extra_compile_args=None, - extra_link_args=None, - export_symbols=None, - swig_opts = None, - depends=None, - language=None, - optional=None, - **kw # To catch unknown keywords - ): + def __init__( + self, + name, + sources, + include_dirs=None, + define_macros=None, + undef_macros=None, + library_dirs=None, + libraries=None, + runtime_library_dirs=None, + extra_objects=None, + extra_compile_args=None, + extra_link_args=None, + export_symbols=None, + swig_opts=None, + depends=None, + language=None, + optional=None, + **kw # To catch unknown keywords + ): if not isinstance(name, str): raise AssertionError("'name' must be a string") - if not (isinstance(sources, list) and - all(isinstance(v, str) for v in sources)): + if not (isinstance(sources, list) and all(isinstance(v, str) for v in sources)): raise AssertionError("'sources' must be a list of strings") self.name = name @@ -135,13 +138,13 @@ def __repr__(self): self.__class__.__module__, self.__class__.__qualname__, self.name, - id(self)) + id(self), + ) def read_setup_file(filename): """Reads a Setup file and returns Extension instances.""" - from distutils.sysconfig import (parse_makefile, expand_makefile_vars, - _variable_rx) + from distutils.sysconfig import parse_makefile, expand_makefile_vars, _variable_rx from distutils.text_file import TextFile from distutils.util import split_quoted @@ -151,17 +154,22 @@ def read_setup_file(filename): # Second pass to gobble up the real content: lines of the form # ... [ ...] [ ...] [ ...] - file = TextFile(filename, - strip_comments=1, skip_blanks=1, join_lines=1, - lstrip_ws=1, rstrip_ws=1) + file = TextFile( + filename, + strip_comments=1, + skip_blanks=1, + join_lines=1, + lstrip_ws=1, + rstrip_ws=1, + ) try: extensions = [] while True: line = file.readline() - if line is None: # eof + if line is None: # eof break - if _variable_rx.match(line): # VAR=VALUE, handled in first pass + if _variable_rx.match(line): # VAR=VALUE, handled in first pass continue if line[0] == line[-1] == "*": @@ -188,7 +196,8 @@ def read_setup_file(filename): continue suffix = os.path.splitext(word)[1] - switch = word[0:2] ; value = word[2:] + switch = word[0:2] + value = word[2:] if suffix in (".c", ".cc", ".cpp", ".cxx", ".c++", ".m", ".mm"): # hmm, should we do something about C vs. C++ sources? @@ -199,14 +208,13 @@ def read_setup_file(filename): ext.include_dirs.append(value) elif switch == "-D": equals = value.find("=") - if equals == -1: # bare "-DFOO" -- no value + if equals == -1: # bare "-DFOO" -- no value ext.define_macros.append((value, None)) - else: # "-DFOO=blah" - ext.define_macros.append((value[0:equals], - value[equals+2:])) + else: # "-DFOO=blah" + ext.define_macros.append((value[0:equals], value[equals + 2 :])) elif switch == "-U": ext.undef_macros.append(value) - elif switch == "-C": # only here 'cause makesetup has it! + elif switch == "-C": # only here 'cause makesetup has it! ext.extra_compile_args.append(word) elif switch == "-l": ext.libraries.append(value) diff --git a/setuptools/_distutils/fancy_getopt.py b/setuptools/_distutils/fancy_getopt.py index 7d170dd2773..b9b21766e16 100644 --- a/setuptools/_distutils/fancy_getopt.py +++ b/setuptools/_distutils/fancy_getopt.py @@ -26,6 +26,7 @@ # (for use as attributes of some object). longopt_xlate = str.maketrans('-', '_') + class FancyGetopt: """Wrapper around the standard 'getopt()' module that provides some handy extra functionality: @@ -90,7 +91,8 @@ def set_option_table(self, option_table): def add_option(self, long_option, short_option=None, help_string=None): if long_option in self.option_index: raise DistutilsGetoptError( - "option conflict: already an option '%s'" % long_option) + "option conflict: already an option '%s'" % long_option + ) else: option = (long_option, short_option, help_string) self.option_table.append(option) @@ -111,11 +113,15 @@ def _check_alias_dict(self, aliases, what): assert isinstance(aliases, dict) for (alias, opt) in aliases.items(): if alias not in self.option_index: - raise DistutilsGetoptError(("invalid %s '%s': " - "option '%s' not defined") % (what, alias, alias)) + raise DistutilsGetoptError( + ("invalid %s '%s': " "option '%s' not defined") + % (what, alias, alias) + ) if opt not in self.option_index: - raise DistutilsGetoptError(("invalid %s '%s': " - "aliased option '%s' not defined") % (what, alias, opt)) + raise DistutilsGetoptError( + ("invalid %s '%s': " "aliased option '%s' not defined") + % (what, alias, opt) + ) def set_aliases(self, alias): """Set the aliases for this option parser.""" @@ -153,19 +159,23 @@ def _grok_option_table(self): # Type- and value-check the option names if not isinstance(long, str) or len(long) < 2: - raise DistutilsGetoptError(("invalid long option '%s': " - "must be a string of length >= 2") % long) + raise DistutilsGetoptError( + ("invalid long option '%s': " "must be a string of length >= 2") + % long + ) - if (not ((short is None) or - (isinstance(short, str) and len(short) == 1))): - raise DistutilsGetoptError("invalid short option '%s': " - "must a single character or None" % short) + if not ((short is None) or (isinstance(short, str) and len(short) == 1)): + raise DistutilsGetoptError( + "invalid short option '%s': " + "must a single character or None" % short + ) self.repeat[long] = repeat self.long_opts.append(long) - if long[-1] == '=': # option takes an argument? - if short: short = short + ':' + if long[-1] == '=': # option takes an argument? + if short: + short = short + ':' long = long[0:-1] self.takes_arg[long] = 1 else: @@ -175,11 +185,11 @@ def _grok_option_table(self): if alias_to is not None: if self.takes_arg[alias_to]: raise DistutilsGetoptError( - "invalid negative alias '%s': " - "aliased option '%s' takes a value" - % (long, alias_to)) + "invalid negative alias '%s': " + "aliased option '%s' takes a value" % (long, alias_to) + ) - self.long_opts[-1] = long # XXX redundant?! + self.long_opts[-1] = long # XXX redundant?! self.takes_arg[long] = 0 # If this is an alias option, make sure its "takes arg" flag is @@ -188,10 +198,10 @@ def _grok_option_table(self): if alias_to is not None: if self.takes_arg[long] != self.takes_arg[alias_to]: raise DistutilsGetoptError( - "invalid alias '%s': inconsistent with " - "aliased option '%s' (one of them takes a value, " - "the other doesn't" - % (long, alias_to)) + "invalid alias '%s': inconsistent with " + "aliased option '%s' (one of them takes a value, " + "the other doesn't" % (long, alias_to) + ) # Now enforce some bondage on the long option name, so we can # later translate it to an attribute name on some object. Have @@ -199,8 +209,9 @@ def _grok_option_table(self): # '='. if not longopt_re.match(long): raise DistutilsGetoptError( - "invalid long option name '%s' " - "(must be letters, numbers, hyphens only" % long) + "invalid long option name '%s' " + "(must be letters, numbers, hyphens only" % long + ) self.attr_name[long] = self.get_attr_name(long) if short: @@ -235,7 +246,7 @@ def getopt(self, args=None, object=None): raise DistutilsArgError(msg) for opt, val in opts: - if len(opt) == 2 and opt[0] == '-': # it's a short option + if len(opt) == 2 and opt[0] == '-': # it's a short option opt = self.short2long[opt[1]] else: assert len(opt) > 2 and opt[:2] == '--' @@ -245,7 +256,7 @@ def getopt(self, args=None, object=None): if alias: opt = alias - if not self.takes_arg[opt]: # boolean option? + if not self.takes_arg[opt]: # boolean option? assert val == '', "boolean option can't have value" alias = self.negative_alias.get(opt) if alias: @@ -294,11 +305,11 @@ def generate_help(self, header=None): if long[-1] == '=': l = l - 1 if short is not None: - l = l + 5 # " (-x)" where short == 'x' + l = l + 5 # " (-x)" where short == 'x' if l > max_opt: max_opt = l - opt_width = max_opt + 2 + 2 + 2 # room for indent + dashes + gutter + opt_width = max_opt + 2 + 2 + 2 # room for indent + dashes + gutter # Typical help block looks like this: # --foo controls foonabulation @@ -348,8 +359,7 @@ def generate_help(self, header=None): else: opt_names = "%s (-%s)" % (long, short) if text: - lines.append(" --%-*s %s" % - (max_opt, opt_names, text[0])) + lines.append(" --%-*s %s" % (max_opt, opt_names, text[0])) else: lines.append(" --%-*s" % opt_names) @@ -370,7 +380,8 @@ def fancy_getopt(options, negative_opt, object, args): return parser.getopt(args, object) -WS_TRANS = {ord(_wschar) : ' ' for _wschar in string.whitespace} +WS_TRANS = {ord(_wschar): ' ' for _wschar in string.whitespace} + def wrap_text(text, width): """wrap_text(text : string, width : int) -> [string] @@ -386,26 +397,26 @@ def wrap_text(text, width): text = text.expandtabs() text = text.translate(WS_TRANS) chunks = re.split(r'( +|-+)', text) - chunks = [ch for ch in chunks if ch] # ' - ' results in empty strings + chunks = [ch for ch in chunks if ch] # ' - ' results in empty strings lines = [] while chunks: - cur_line = [] # list of chunks (to-be-joined) - cur_len = 0 # length of current line + cur_line = [] # list of chunks (to-be-joined) + cur_len = 0 # length of current line while chunks: l = len(chunks[0]) - if cur_len + l <= width: # can squeeze (at least) this chunk in + if cur_len + l <= width: # can squeeze (at least) this chunk in cur_line.append(chunks[0]) del chunks[0] cur_len = cur_len + l - else: # this line is full + else: # this line is full # drop last chunk if all space if cur_line and cur_line[-1][0] == ' ': del cur_line[-1] break - if chunks: # any chunks left to process? + if chunks: # any chunks left to process? # if the current line is still empty, then we had a single # chunk that's too big too fit on a line -- so we break # down and break it up at the line width diff --git a/setuptools/_distutils/file_util.py b/setuptools/_distutils/file_util.py index b3fee35a6cc..4ff2230c000 100644 --- a/setuptools/_distutils/file_util.py +++ b/setuptools/_distutils/file_util.py @@ -8,12 +8,10 @@ from distutils import log # for generating verbose output in 'copy_file()' -_copy_action = { None: 'copying', - 'hard': 'hard linking', - 'sym': 'symbolically linking' } +_copy_action = {None: 'copying', 'hard': 'hard linking', 'sym': 'symbolically linking'} -def _copy_file_contents(src, dst, buffer_size=16*1024): +def _copy_file_contents(src, dst, buffer_size=16 * 1024): """Copy the file 'src' to 'dst'; both must be filenames. Any error opening either file, reading from 'src', or writing to 'dst', raises DistutilsFileError. Data is read/written in chunks of 'buffer_size' @@ -35,20 +33,21 @@ def _copy_file_contents(src, dst, buffer_size=16*1024): os.unlink(dst) except OSError as e: raise DistutilsFileError( - "could not delete '%s': %s" % (dst, e.strerror)) + "could not delete '%s': %s" % (dst, e.strerror) + ) try: fdst = open(dst, 'wb') except OSError as e: - raise DistutilsFileError( - "could not create '%s': %s" % (dst, e.strerror)) + raise DistutilsFileError("could not create '%s': %s" % (dst, e.strerror)) while True: try: buf = fsrc.read(buffer_size) except OSError as e: raise DistutilsFileError( - "could not read from '%s': %s" % (src, e.strerror)) + "could not read from '%s': %s" % (src, e.strerror) + ) if not buf: break @@ -57,15 +56,25 @@ def _copy_file_contents(src, dst, buffer_size=16*1024): fdst.write(buf) except OSError as e: raise DistutilsFileError( - "could not write to '%s': %s" % (dst, e.strerror)) + "could not write to '%s': %s" % (dst, e.strerror) + ) finally: if fdst: fdst.close() if fsrc: fsrc.close() -def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0, - link=None, verbose=1, dry_run=0): + +def copy_file( + src, + dst, + preserve_mode=1, + preserve_times=1, + update=0, + link=None, + verbose=1, + dry_run=0, +): """Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src' is copied there with the same name; otherwise, it must be a filename. (If the file exists, it will be ruthlessly clobbered.) If 'preserve_mode' @@ -102,7 +111,8 @@ def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0, if not os.path.isfile(src): raise DistutilsFileError( - "can't copy '%s': doesn't exist or not a regular file" % src) + "can't copy '%s': doesn't exist or not a regular file" % src + ) if os.path.isdir(dst): dir = dst @@ -163,9 +173,7 @@ def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0, # XXX I suspect this is Unix-specific -- need porting help! -def move_file (src, dst, - verbose=1, - dry_run=0): +def move_file(src, dst, verbose=1, dry_run=0): """Move a file 'src' to 'dst'. If 'dst' is a directory, the file will be moved into it with the same name; otherwise, 'src' is just renamed @@ -190,13 +198,13 @@ def move_file (src, dst, dst = os.path.join(dst, basename(src)) elif exists(dst): raise DistutilsFileError( - "can't move '%s': destination '%s' already exists" % - (src, dst)) + "can't move '%s': destination '%s' already exists" % (src, dst) + ) if not isdir(dirname(dst)): raise DistutilsFileError( - "can't move '%s': destination '%s' not a valid path" % - (src, dst)) + "can't move '%s': destination '%s' not a valid path" % (src, dst) + ) copy_it = False try: @@ -206,8 +214,7 @@ def move_file (src, dst, if num == errno.EXDEV: copy_it = True else: - raise DistutilsFileError( - "couldn't move '%s' to '%s': %s" % (src, dst, msg)) + raise DistutilsFileError("couldn't move '%s' to '%s': %s" % (src, dst, msg)) if copy_it: copy_file(src, dst, verbose=verbose) @@ -220,13 +227,13 @@ def move_file (src, dst, except OSError: pass raise DistutilsFileError( - "couldn't move '%s' to '%s' by copy/delete: " - "delete '%s' failed: %s" - % (src, dst, src, msg)) + "couldn't move '%s' to '%s' by copy/delete: " + "delete '%s' failed: %s" % (src, dst, src, msg) + ) return dst -def write_file (filename, contents): +def write_file(filename, contents): """Create a file with the specified name and write 'contents' (a sequence of strings without line terminators) to it. """ diff --git a/setuptools/_distutils/filelist.py b/setuptools/_distutils/filelist.py index 82a77384dcb..37ab341e901 100644 --- a/setuptools/_distutils/filelist.py +++ b/setuptools/_distutils/filelist.py @@ -46,6 +46,7 @@ def debug_print(self, msg): DISTUTILS_DEBUG environment variable) flag is true. """ from distutils.debug import DEBUG + if DEBUG: print(msg) @@ -80,22 +81,24 @@ def _parse_template_line(self, line): patterns = dir = dir_pattern = None - if action in ('include', 'exclude', - 'global-include', 'global-exclude'): + if action in ('include', 'exclude', 'global-include', 'global-exclude'): if len(words) < 2: raise DistutilsTemplateError( - "'%s' expects ..." % action) + "'%s' expects ..." % action + ) patterns = [convert_path(w) for w in words[1:]] elif action in ('recursive-include', 'recursive-exclude'): if len(words) < 3: raise DistutilsTemplateError( - "'%s' expects ..." % action) + "'%s' expects ..." % action + ) dir = convert_path(words[1]) patterns = [convert_path(w) for w in words[2:]] elif action in ('graft', 'prune'): if len(words) != 2: raise DistutilsTemplateError( - "'%s' expects a single " % action) + "'%s' expects a single " % action + ) dir_pattern = convert_path(words[1]) else: raise DistutilsTemplateError("unknown action '%s'" % action) @@ -117,65 +120,82 @@ def process_template_line(self, line): self.debug_print("include " + ' '.join(patterns)) for pattern in patterns: if not self.include_pattern(pattern, anchor=1): - log.warn("warning: no files found matching '%s'", - pattern) + log.warn("warning: no files found matching '%s'", pattern) elif action == 'exclude': self.debug_print("exclude " + ' '.join(patterns)) for pattern in patterns: if not self.exclude_pattern(pattern, anchor=1): - log.warn(("warning: no previously-included files " - "found matching '%s'"), pattern) + log.warn( + ( + "warning: no previously-included files " + "found matching '%s'" + ), + pattern, + ) elif action == 'global-include': self.debug_print("global-include " + ' '.join(patterns)) for pattern in patterns: if not self.include_pattern(pattern, anchor=0): - log.warn(("warning: no files found matching '%s' " - "anywhere in distribution"), pattern) + log.warn( + ( + "warning: no files found matching '%s' " + "anywhere in distribution" + ), + pattern, + ) elif action == 'global-exclude': self.debug_print("global-exclude " + ' '.join(patterns)) for pattern in patterns: if not self.exclude_pattern(pattern, anchor=0): - log.warn(("warning: no previously-included files matching " - "'%s' found anywhere in distribution"), - pattern) + log.warn( + ( + "warning: no previously-included files matching " + "'%s' found anywhere in distribution" + ), + pattern, + ) elif action == 'recursive-include': - self.debug_print("recursive-include %s %s" % - (dir, ' '.join(patterns))) + self.debug_print("recursive-include %s %s" % (dir, ' '.join(patterns))) for pattern in patterns: if not self.include_pattern(pattern, prefix=dir): msg = ( - "warning: no files found matching '%s' " - "under directory '%s'" + "warning: no files found matching '%s' " "under directory '%s'" ) log.warn(msg, pattern, dir) elif action == 'recursive-exclude': - self.debug_print("recursive-exclude %s %s" % - (dir, ' '.join(patterns))) + self.debug_print("recursive-exclude %s %s" % (dir, ' '.join(patterns))) for pattern in patterns: if not self.exclude_pattern(pattern, prefix=dir): - log.warn(("warning: no previously-included files matching " - "'%s' found under directory '%s'"), - pattern, dir) + log.warn( + ( + "warning: no previously-included files matching " + "'%s' found under directory '%s'" + ), + pattern, + dir, + ) elif action == 'graft': self.debug_print("graft " + dir_pattern) if not self.include_pattern(None, prefix=dir_pattern): - log.warn("warning: no directories found matching '%s'", - dir_pattern) + log.warn("warning: no directories found matching '%s'", dir_pattern) elif action == 'prune': self.debug_print("prune " + dir_pattern) if not self.exclude_pattern(None, prefix=dir_pattern): - log.warn(("no previously-included directories found " - "matching '%s'"), dir_pattern) + log.warn( + ("no previously-included directories found " "matching '%s'"), + dir_pattern, + ) else: raise DistutilsInternalError( - "this cannot happen: invalid action '%s'" % action) + "this cannot happen: invalid action '%s'" % action + ) # Filtering/selection methods @@ -207,8 +227,7 @@ def include_pattern(self, pattern, anchor=1, prefix=None, is_regex=0): # XXX docstring lying about what the special chars are? files_found = False pattern_re = translate_pattern(pattern, anchor, prefix, is_regex) - self.debug_print("include_pattern: applying regex r'%s'" % - pattern_re.pattern) + self.debug_print("include_pattern: applying regex r'%s'" % pattern_re.pattern) # delayed loading of allfiles list if self.allfiles is None: @@ -221,8 +240,7 @@ def include_pattern(self, pattern, anchor=1, prefix=None, is_regex=0): files_found = True return files_found - def exclude_pattern( - self, pattern, anchor=1, prefix=None, is_regex=0): + def exclude_pattern(self, pattern, anchor=1, prefix=None, is_regex=0): """Remove strings (presumably filenames) from 'files' that match 'pattern'. Other parameters are the same as for 'include_pattern()', above. @@ -231,9 +249,8 @@ def exclude_pattern( """ files_found = False pattern_re = translate_pattern(pattern, anchor, prefix, is_regex) - self.debug_print("exclude_pattern: applying regex r'%s'" % - pattern_re.pattern) - for i in range(len(self.files)-1, -1, -1): + self.debug_print("exclude_pattern: applying regex r'%s'" % pattern_re.pattern) + for i in range(len(self.files) - 1, -1, -1): if pattern_re.search(self.files[i]): self.debug_print(" removing " + self.files[i]) del self.files[i] @@ -243,15 +260,14 @@ def exclude_pattern( # Utility functions + def _find_all_simple(path): """ Find all files under 'path' """ all_unique = _UniqueDirs.filter(os.walk(path, followlinks=True)) results = ( - os.path.join(base, file) - for base, dirs, files in all_unique - for file in files + os.path.join(base, file) for base, dirs, files in all_unique for file in files ) return filter(os.path.isfile, results) @@ -262,6 +278,7 @@ class _UniqueDirs(set): avoiding infinite recursion. Ref https://bugs.python.org/issue44497. """ + def __call__(self, walk_item): """ Given an item from an os.walk result, determine @@ -341,15 +358,14 @@ def translate_pattern(pattern, anchor=1, prefix=None, is_regex=0): if prefix is not None: prefix_re = glob_to_re(prefix) assert prefix_re.startswith(start) and prefix_re.endswith(end) - prefix_re = prefix_re[len(start): len(prefix_re) - len(end)] + prefix_re = prefix_re[len(start) : len(prefix_re) - len(end)] sep = os.sep if os.sep == '\\': sep = r'\\' - pattern_re = pattern_re[len(start): len(pattern_re) - len(end)] - pattern_re = r'%s\A%s%s.*%s%s' % ( - start, prefix_re, sep, pattern_re, end) - else: # no prefix -- respect anchor flag + pattern_re = pattern_re[len(start) : len(pattern_re) - len(end)] + pattern_re = r'%s\A%s%s.*%s%s' % (start, prefix_re, sep, pattern_re, end) + else: # no prefix -- respect anchor flag if anchor: - pattern_re = r'%s\A%s' % (start, pattern_re[len(start):]) + pattern_re = r'%s\A%s' % (start, pattern_re[len(start) :]) return re.compile(pattern_re) diff --git a/setuptools/_distutils/log.py b/setuptools/_distutils/log.py index 8ef6b28ea2e..0c977462e3b 100644 --- a/setuptools/_distutils/log.py +++ b/setuptools/_distutils/log.py @@ -11,8 +11,8 @@ import sys -class Log: +class Log: def __init__(self, threshold=WARN): self.threshold = threshold @@ -54,6 +54,7 @@ def error(self, msg, *args): def fatal(self, msg, *args): self._log(FATAL, msg, args) + _global_log = Log() log = _global_log.log debug = _global_log.debug @@ -62,12 +63,14 @@ def fatal(self, msg, *args): error = _global_log.error fatal = _global_log.fatal + def set_threshold(level): # return the old threshold for use from tests old = _global_log.threshold _global_log.threshold = level return old + def set_verbosity(v): if v <= 0: set_threshold(WARN) diff --git a/setuptools/_distutils/msvc9compiler.py b/setuptools/_distutils/msvc9compiler.py index a1b3b02ff0a..6cd9a43e842 100644 --- a/setuptools/_distutils/msvc9compiler.py +++ b/setuptools/_distutils/msvc9compiler.py @@ -17,8 +17,13 @@ import sys import re -from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ - CompileError, LibError, LinkError +from distutils.errors import ( + DistutilsExecError, + DistutilsPlatformError, + CompileError, + LibError, + LinkError, +) from distutils.ccompiler import CCompiler, gen_lib_options from distutils import log from distutils.util import get_platform @@ -30,12 +35,14 @@ RegEnumValue = winreg.EnumValue RegError = winreg.error -HKEYS = (winreg.HKEY_USERS, - winreg.HKEY_CURRENT_USER, - winreg.HKEY_LOCAL_MACHINE, - winreg.HKEY_CLASSES_ROOT) +HKEYS = ( + winreg.HKEY_USERS, + winreg.HKEY_CURRENT_USER, + winreg.HKEY_LOCAL_MACHINE, + winreg.HKEY_CLASSES_ROOT, +) -NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32) +NATIVE_WIN64 = sys.platform == 'win32' and sys.maxsize > 2 ** 32 if NATIVE_WIN64: # Visual C++ is a 32-bit application, so we need to look in # the corresponding registry branch, if we're running a @@ -52,13 +59,13 @@ # 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is # the param to cross-compile on x86 targeting amd64.) PLAT_TO_VCVARS = { - 'win32' : 'x86', - 'win-amd64' : 'amd64', + 'win32': 'x86', + 'win-amd64': 'amd64', } + class Reg: - """Helper class to read values from the registry - """ + """Helper class to read values from the registry""" def get_value(cls, path, key): for base in HKEYS: @@ -66,6 +73,7 @@ def get_value(cls, path, key): if d and key in d: return d[key] raise KeyError(key) + get_value = classmethod(get_value) def read_keys(cls, base, key): @@ -84,6 +92,7 @@ def read_keys(cls, base, key): L.append(k) i += 1 return L + read_keys = classmethod(read_keys) def read_values(cls, base, key): @@ -106,6 +115,7 @@ def read_values(cls, base, key): d[cls.convert_mbcs(name)] = cls.convert_mbcs(value) i += 1 return d + read_values = classmethod(read_values) def convert_mbcs(s): @@ -116,10 +126,11 @@ def convert_mbcs(s): except UnicodeError: pass return s + convert_mbcs = staticmethod(convert_mbcs) -class MacroExpander: +class MacroExpander: def __init__(self, version): self.macros = {} self.vsbase = VS_BASE % version @@ -134,16 +145,16 @@ def load_macros(self, version): self.set_macro("FrameworkDir", NET_BASE, "installroot") try: if version >= 8.0: - self.set_macro("FrameworkSDKDir", NET_BASE, - "sdkinstallrootv2.0") + self.set_macro("FrameworkSDKDir", NET_BASE, "sdkinstallrootv2.0") else: raise KeyError("sdkinstallrootv2.0") except KeyError: raise DistutilsPlatformError( - """Python was built with Visual Studio 2008; + """Python was built with Visual Studio 2008; extensions must be built with a compiler than can generate compatible binaries. Visual Studio 2008 was not found on this system. If you have Cygwin installed, -you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") +you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""" + ) if version >= 9.0: self.set_macro("FrameworkVersion", self.vsbase, "clr version") @@ -164,6 +175,7 @@ def sub(self, s): s = s.replace(k, v) return s + def get_build_version(): """Return the version of MSVC that was used to build Python. @@ -189,6 +201,7 @@ def get_build_version(): # else we don't know what version of the compiler this is return None + def normalize_and_reduce_paths(paths): """Return a list of normalized paths with duplicates removed. @@ -203,9 +216,9 @@ def normalize_and_reduce_paths(paths): reduced_paths.append(np) return reduced_paths + def removeDuplicates(variable): - """Remove duplicate values of an environment variable. - """ + """Remove duplicate values of an environment variable.""" oldList = variable.split(os.pathsep) newList = [] for i in oldList: @@ -214,6 +227,7 @@ def removeDuplicates(variable): newVariable = os.pathsep.join(newList) return newVariable + def find_vcvarsall(version): """Find the vcvarsall.bat file @@ -222,8 +236,7 @@ def find_vcvarsall(version): """ vsbase = VS_BASE % version try: - productdir = Reg.get_value(r"%s\Setup\VC" % vsbase, - "productdir") + productdir = Reg.get_value(r"%s\Setup\VC" % vsbase, "productdir") except KeyError: log.debug("Unable to find productdir in registry") productdir = None @@ -249,9 +262,9 @@ def find_vcvarsall(version): log.debug("Unable to find vcvarsall.bat") return None + def query_vcvarsall(version, arch="x86"): - """Launch vcvarsall.bat and read the settings from its environment - """ + """Launch vcvarsall.bat and read the settings from its environment""" vcvarsall = find_vcvarsall(version) interesting = {"include", "lib", "libpath", "path"} result = {} @@ -259,9 +272,11 @@ def query_vcvarsall(version, arch="x86"): if vcvarsall is None: raise DistutilsPlatformError("Unable to find vcvarsall.bat") log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version) - popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + popen = subprocess.Popen( + '"%s" %s & set' % (vcvarsall, arch), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) try: stdout, stderr = popen.communicate() if popen.wait() != 0: @@ -289,15 +304,17 @@ def query_vcvarsall(version, arch="x86"): return result + # More globals VERSION = get_build_version() if VERSION < 8.0: raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION) # MACROS = MacroExpander(VERSION) -class MSVCCompiler(CCompiler) : + +class MSVCCompiler(CCompiler): """Concrete class that implements an interface to Microsoft Visual C++, - as defined by the CCompiler abstract class.""" + as defined by the CCompiler abstract class.""" compiler_type = 'msvc' @@ -316,8 +333,7 @@ class MSVCCompiler(CCompiler) : # Needed for the filename generation methods provided by the # base class, CCompiler. - src_extensions = (_c_extensions + _cpp_extensions + - _rc_extensions + _mc_extensions) + src_extensions = _c_extensions + _cpp_extensions + _rc_extensions + _mc_extensions res_extension = '.res' obj_extension = '.obj' static_lib_extension = '.lib' @@ -326,14 +342,14 @@ class MSVCCompiler(CCompiler) : exe_extension = '.exe' def __init__(self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) + CCompiler.__init__(self, verbose, dry_run, force) self.__version = VERSION self.__root = r"Software\Microsoft\VisualStudio" # self.__macros = MACROS self.__paths = [] # target platform (.plat_name is consistent with 'bdist') self.plat_name = None - self.__arch = None # deprecated name + self.__arch = None # deprecated name self.initialized = False def initialize(self, plat_name=None): @@ -344,10 +360,13 @@ def initialize(self, plat_name=None): # sanity check for platforms to prevent obscure errors later. ok_plats = 'win32', 'win-amd64' if plat_name not in ok_plats: - raise DistutilsPlatformError("--plat-name must be one of %s" % - (ok_plats,)) + raise DistutilsPlatformError("--plat-name must be one of %s" % (ok_plats,)) - if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): + if ( + "DISTUTILS_USE_SDK" in os.environ + and "MSSdk" in os.environ + and self.find_exe("cl.exe") + ): # Assume that the SDK set up everything alright; don't try to be # smarter self.cc = "cl.exe" @@ -365,8 +384,9 @@ def initialize(self, plat_name=None): plat_spec = PLAT_TO_VCVARS[plat_name] else: # cross compile from win32 -> some 64bit - plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \ - PLAT_TO_VCVARS[plat_name] + plat_spec = ( + PLAT_TO_VCVARS[get_platform()] + '_' + PLAT_TO_VCVARS[plat_name] + ) vc_env = query_vcvarsall(VERSION, plat_spec) @@ -375,18 +395,19 @@ def initialize(self, plat_name=None): os.environ['include'] = vc_env['include'] if len(self.__paths) == 0: - raise DistutilsPlatformError("Python was built with %s, " - "and extensions need to be built with the same " - "version of the compiler, but it isn't installed." - % self.__product) + raise DistutilsPlatformError( + "Python was built with %s, " + "and extensions need to be built with the same " + "version of the compiler, but it isn't installed." % self.__product + ) self.cc = self.find_exe("cl.exe") self.linker = self.find_exe("link.exe") self.lib = self.find_exe("lib.exe") - self.rc = self.find_exe("rc.exe") # resource compiler - self.mc = self.find_exe("mc.exe") # message compiler - #self.set_path_env_var('lib') - #self.set_path_env_var('include') + self.rc = self.find_exe("rc.exe") # resource compiler + self.mc = self.find_exe("mc.exe") # message compiler + # self.set_path_env_var('lib') + # self.set_path_env_var('include') # extend the MSVC path with the current path try: @@ -399,71 +420,83 @@ def initialize(self, plat_name=None): self.preprocess_options = None if self.__arch == "x86": - self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', - '/Z7', '/D_DEBUG'] + self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/DNDEBUG'] + self.compile_options_debug = [ + '/nologo', + '/Od', + '/MDd', + '/W3', + '/Z7', + '/D_DEBUG', + ] else: # Win64 - self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GS-' , - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', - '/Z7', '/D_DEBUG'] + self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GS-', '/DNDEBUG'] + self.compile_options_debug = [ + '/nologo', + '/Od', + '/MDd', + '/W3', + '/GS-', + '/Z7', + '/D_DEBUG', + ] self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] if self.__version >= 7: - self.ldflags_shared_debug = [ - '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG' - ] - self.ldflags_static = [ '/nologo'] + self.ldflags_shared_debug = ['/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'] + self.ldflags_static = ['/nologo'] self.initialized = True # -- Worker methods ------------------------------------------------ - def object_filenames(self, - source_filenames, - strip_dir=0, - output_dir=''): + def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): # Copied from ccompiler.py, extended to return .res as 'object'-file # for .rc input file - if output_dir is None: output_dir = '' + if output_dir is None: + output_dir = '' obj_names = [] for src_name in source_filenames: - (base, ext) = os.path.splitext (src_name) - base = os.path.splitdrive(base)[1] # Chop off the drive - base = base[os.path.isabs(base):] # If abs, chop off leading / + (base, ext) = os.path.splitext(src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base) :] # If abs, chop off leading / if ext not in self.src_extensions: # Better to raise an exception instead of silently continuing # and later complain about sources and targets having # different lengths - raise CompileError ("Don't know how to compile %s" % src_name) + raise CompileError("Don't know how to compile %s" % src_name) if strip_dir: - base = os.path.basename (base) + base = os.path.basename(base) if ext in self._rc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) + obj_names.append(os.path.join(output_dir, base + self.res_extension)) elif ext in self._mc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) + obj_names.append(os.path.join(output_dir, base + self.res_extension)) else: - obj_names.append (os.path.join (output_dir, - base + self.obj_extension)) + obj_names.append(os.path.join(output_dir, base + self.obj_extension)) return obj_names - - def compile(self, sources, - output_dir=None, macros=None, include_dirs=None, debug=0, - extra_preargs=None, extra_postargs=None, depends=None): + def compile( + self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None, + ): if not self.initialized: self.initialize() - compile_info = self._setup_compile(output_dir, macros, include_dirs, - sources, depends, extra_postargs) + compile_info = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs + ) macros, objects, extra_postargs, pp_opts, build = compile_info compile_opts = extra_preargs or [] - compile_opts.append ('/c') + compile_opts.append('/c') if debug: compile_opts.extend(self.compile_options_debug) else: @@ -489,8 +522,7 @@ def compile(self, sources, input_opt = src output_opt = "/fo" + obj try: - self.spawn([self.rc] + pp_opts + - [output_opt] + [input_opt]) + self.spawn([self.rc] + pp_opts + [output_opt] + [input_opt]) except DistutilsExecError as msg: raise CompileError(msg) continue @@ -510,50 +542,46 @@ def compile(self, sources, rc_dir = os.path.dirname(obj) try: # first compile .MC to .RC and .H file - self.spawn([self.mc] + - ['-h', h_dir, '-r', rc_dir] + [src]) - base, _ = os.path.splitext (os.path.basename (src)) - rc_file = os.path.join (rc_dir, base + '.rc') + self.spawn([self.mc] + ['-h', h_dir, '-r', rc_dir] + [src]) + base, _ = os.path.splitext(os.path.basename(src)) + rc_file = os.path.join(rc_dir, base + '.rc') # then compile .RC to .RES file - self.spawn([self.rc] + - ["/fo" + obj] + [rc_file]) + self.spawn([self.rc] + ["/fo" + obj] + [rc_file]) except DistutilsExecError as msg: raise CompileError(msg) continue else: # how to handle this file? - raise CompileError("Don't know how to compile %s to %s" - % (src, obj)) + raise CompileError("Don't know how to compile %s to %s" % (src, obj)) output_opt = "/Fo" + obj try: - self.spawn([self.cc] + compile_opts + pp_opts + - [input_opt, output_opt] + - extra_postargs) + self.spawn( + [self.cc] + + compile_opts + + pp_opts + + [input_opt, output_opt] + + extra_postargs + ) except DistutilsExecError as msg: raise CompileError(msg) return objects - - def create_static_lib(self, - objects, - output_libname, - output_dir=None, - debug=0, - target_lang=None): + def create_static_lib( + self, objects, output_libname, output_dir=None, debug=0, target_lang=None + ): if not self.initialized: self.initialize() (objects, output_dir) = self._fix_object_args(objects, output_dir) - output_filename = self.library_filename(output_libname, - output_dir=output_dir) + output_filename = self.library_filename(output_libname, output_dir=output_dir) if self._need_link(objects, output_filename): lib_args = objects + ['/OUT:' + output_filename] if debug: - pass # XXX what goes here? + pass # XXX what goes here? try: self.spawn([self.lib] + lib_args) except DistutilsExecError as msg: @@ -561,36 +589,36 @@ def create_static_lib(self, else: log.debug("skipping %s (up-to-date)", output_filename) - - def link(self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): if not self.initialized: self.initialize() (objects, output_dir) = self._fix_object_args(objects, output_dir) - fixed_args = self._fix_lib_args(libraries, library_dirs, - runtime_library_dirs) + fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) (libraries, library_dirs, runtime_library_dirs) = fixed_args if runtime_library_dirs: - self.warn ("I don't know what to do with 'runtime_library_dirs': " - + str (runtime_library_dirs)) + self.warn( + "I don't know what to do with 'runtime_library_dirs': " + + str(runtime_library_dirs) + ) - lib_opts = gen_lib_options(self, - library_dirs, runtime_library_dirs, - libraries) + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries) if output_dir is not None: output_filename = os.path.join(output_dir, output_filename) @@ -607,11 +635,12 @@ def link(self, ldflags = self.ldflags_shared export_opts = [] - for sym in (export_symbols or []): + for sym in export_symbols or []: export_opts.append("/EXPORT:" + sym) - ld_args = (ldflags + lib_opts + export_opts + - objects + ['/OUT:' + output_filename]) + ld_args = ( + ldflags + lib_opts + export_opts + objects + ['/OUT:' + output_filename] + ) # The MSVC linker generates .lib and .exp files, which cannot be # suppressed by any linker switches. The .lib files may even be @@ -621,11 +650,10 @@ def link(self, build_temp = os.path.dirname(objects[0]) if export_symbols is not None: (dll_name, dll_ext) = os.path.splitext( - os.path.basename(output_filename)) - implib_file = os.path.join( - build_temp, - self.library_filename(dll_name)) - ld_args.append ('/IMPLIB:' + implib_file) + os.path.basename(output_filename) + ) + implib_file = os.path.join(build_temp, self.library_filename(dll_name)) + ld_args.append('/IMPLIB:' + implib_file) self.manifest_setup_ldargs(output_filename, build_temp, ld_args) @@ -650,8 +678,7 @@ def link(self, mffilename, mfid = mfinfo out_arg = '-outputresource:%s;%s' % (output_filename, mfid) try: - self.spawn(['mt.exe', '-nologo', '-manifest', - mffilename, out_arg]) + self.spawn(['mt.exe', '-nologo', '-manifest', mffilename, out_arg]) except DistutilsExecError as msg: raise LinkError(msg) else: @@ -665,8 +692,8 @@ def manifest_setup_ldargs(self, output_filename, build_temp, ld_args): # Ask the linker to generate the manifest in the temp dir, so # we can check it, and possibly embed it, later. temp_manifest = os.path.join( - build_temp, - os.path.basename(output_filename) + ".manifest") + build_temp, os.path.basename(output_filename) + ".manifest" + ) ld_args.append('/MANIFESTFILE:' + temp_manifest) def manifest_get_embed_info(self, target_desc, ld_args): @@ -709,9 +736,10 @@ def _remove_visual_c_ref(self, manifest_file): finally: manifest_f.close() pattern = re.compile( - r"""|)""", - re.DOTALL) + re.DOTALL, + ) manifest_buf = re.sub(pattern, "", manifest_buf) pattern = r"\s*" manifest_buf = re.sub(pattern, "", manifest_buf) @@ -719,7 +747,9 @@ def _remove_visual_c_ref(self, manifest_file): # don't want a manifest embedded. pattern = re.compile( r"""|)""", re.DOTALL) + r""".*?(?:/>|)""", + re.DOTALL, + ) if re.search(pattern, manifest_buf) is None: return None @@ -741,12 +771,12 @@ def library_dir_option(self, dir): def runtime_library_dir_option(self, dir): raise DistutilsPlatformError( - "don't know how to set runtime library search path for MSVC++") + "don't know how to set runtime library search path for MSVC++" + ) def library_option(self, lib): return self.library_filename(lib) - def find_library_file(self, dirs, lib, debug=0): # Prefer a debugging library if found (and requested), but deal # with it if we don't have one. @@ -756,7 +786,7 @@ def find_library_file(self, dirs, lib, debug=0): try_names = [lib] for dir in dirs: for name in try_names: - libfile = os.path.join(dir, self.library_filename (name)) + libfile = os.path.join(dir, self.library_filename(name)) if os.path.exists(libfile): return libfile else: @@ -781,7 +811,7 @@ def find_exe(self, exe): # didn't find it; try existing path for p in os.environ['Path'].split(';'): - fn = os.path.join(os.path.abspath(p),exe) + fn = os.path.join(os.path.abspath(p), exe) if os.path.isfile(fn): return fn diff --git a/setuptools/_distutils/msvccompiler.py b/setuptools/_distutils/msvccompiler.py index 2d447b857d3..3c043460162 100644 --- a/setuptools/_distutils/msvccompiler.py +++ b/setuptools/_distutils/msvccompiler.py @@ -9,11 +9,14 @@ # finding DevStudio (through the registry) import sys, os -from distutils.errors import \ - DistutilsExecError, DistutilsPlatformError, \ - CompileError, LibError, LinkError -from distutils.ccompiler import \ - CCompiler, gen_lib_options +from distutils.errors import ( + DistutilsExecError, + DistutilsPlatformError, + CompileError, + LibError, + LinkError, +) +from distutils.ccompiler import CCompiler, gen_lib_options from distutils import log _can_read_reg = False @@ -32,6 +35,7 @@ try: import win32api import win32con + _can_read_reg = True hkey_mod = win32con @@ -40,17 +44,22 @@ RegEnumValue = win32api.RegEnumValue RegError = win32api.error except ImportError: - log.info("Warning: Can't read registry to find the " - "necessary compiler setting\n" - "Make sure that Python modules winreg, " - "win32api or win32con are installed.") + log.info( + "Warning: Can't read registry to find the " + "necessary compiler setting\n" + "Make sure that Python modules winreg, " + "win32api or win32con are installed." + ) pass if _can_read_reg: - HKEYS = (hkey_mod.HKEY_USERS, - hkey_mod.HKEY_CURRENT_USER, - hkey_mod.HKEY_LOCAL_MACHINE, - hkey_mod.HKEY_CLASSES_ROOT) + HKEYS = ( + hkey_mod.HKEY_USERS, + hkey_mod.HKEY_CURRENT_USER, + hkey_mod.HKEY_LOCAL_MACHINE, + hkey_mod.HKEY_CLASSES_ROOT, + ) + def read_keys(base, key): """Return list of registry keys.""" @@ -69,6 +78,7 @@ def read_keys(base, key): i += 1 return L + def read_values(base, key): """Return dict of registry keys and values. @@ -90,6 +100,7 @@ def read_values(base, key): i += 1 return d + def convert_mbcs(s): dec = getattr(s, "decode", None) if dec is not None: @@ -99,6 +110,7 @@ def convert_mbcs(s): pass return s + class MacroExpander: def __init__(self, version): self.macros = {} @@ -122,12 +134,13 @@ def load_macros(self, version): self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") else: self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") - except KeyError as exc: # + except KeyError as exc: # raise DistutilsPlatformError( - """Python was built with Visual Studio 2003; + """Python was built with Visual Studio 2003; extensions must be built with a compiler than can generate compatible binaries. Visual Studio 2003 was not found on this system. If you have Cygwin installed, -you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") +you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""" + ) p = r"Software\Microsoft\NET Framework Setup\Product" for base in HKEYS: @@ -144,6 +157,7 @@ def sub(self, s): s = s.replace(k, v) return s + def get_build_version(): """Return the version of MSVC that was used to build Python. @@ -169,6 +183,7 @@ def get_build_version(): # else we don't know what version of the compiler this is return None + def get_build_architecture(): """Return the processor architecture. @@ -180,7 +195,8 @@ def get_build_architecture(): if i == -1: return "Intel" j = sys.version.find(")", i) - return sys.version[i+len(prefix):j] + return sys.version[i + len(prefix) : j] + def normalize_and_reduce_paths(paths): """Return a list of normalized paths with duplicates removed. @@ -197,9 +213,9 @@ def normalize_and_reduce_paths(paths): return reduced_paths -class MSVCCompiler(CCompiler) : +class MSVCCompiler(CCompiler): """Concrete class that implements an interface to Microsoft Visual C++, - as defined by the CCompiler abstract class.""" + as defined by the CCompiler abstract class.""" compiler_type = 'msvc' @@ -218,8 +234,7 @@ class MSVCCompiler(CCompiler) : # Needed for the filename generation methods provided by the # base class, CCompiler. - src_extensions = (_c_extensions + _cpp_extensions + - _rc_extensions + _mc_extensions) + src_extensions = _c_extensions + _cpp_extensions + _rc_extensions + _mc_extensions res_extension = '.res' obj_extension = '.obj' static_lib_extension = '.lib' @@ -228,7 +243,7 @@ class MSVCCompiler(CCompiler) : exe_extension = '.exe' def __init__(self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) + CCompiler.__init__(self, verbose, dry_run, force) self.__version = get_build_version() self.__arch = get_build_architecture() if self.__arch == "Intel": @@ -247,7 +262,11 @@ def __init__(self, verbose=0, dry_run=0, force=0): def initialize(self): self.__paths = [] - if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): + if ( + "DISTUTILS_USE_SDK" in os.environ + and "MSSdk" in os.environ + and self.find_exe("cl.exe") + ): # Assume that the SDK set up everything alright; don't try to be # smarter self.cc = "cl.exe" @@ -259,16 +278,17 @@ def initialize(self): self.__paths = self.get_msvc_paths("path") if len(self.__paths) == 0: - raise DistutilsPlatformError("Python was built with %s, " - "and extensions need to be built with the same " - "version of the compiler, but it isn't installed." - % self.__product) + raise DistutilsPlatformError( + "Python was built with %s, " + "and extensions need to be built with the same " + "version of the compiler, but it isn't installed." % self.__product + ) self.cc = self.find_exe("cl.exe") self.linker = self.find_exe("link.exe") self.lib = self.find_exe("lib.exe") - self.rc = self.find_exe("rc.exe") # resource compiler - self.mc = self.find_exe("mc.exe") # message compiler + self.rc = self.find_exe("rc.exe") # resource compiler + self.mc = self.find_exe("mc.exe") # message compiler self.set_path_env_var('lib') self.set_path_env_var('include') @@ -283,75 +303,92 @@ def initialize(self): self.preprocess_options = None if self.__arch == "Intel": - self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GX' , - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX', - '/Z7', '/D_DEBUG'] + self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GX', '/DNDEBUG'] + self.compile_options_debug = [ + '/nologo', + '/Od', + '/MDd', + '/W3', + '/GX', + '/Z7', + '/D_DEBUG', + ] else: # Win64 - self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GS-' , - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', - '/Z7', '/D_DEBUG'] + self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GS-', '/DNDEBUG'] + self.compile_options_debug = [ + '/nologo', + '/Od', + '/MDd', + '/W3', + '/GS-', + '/Z7', + '/D_DEBUG', + ] self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] if self.__version >= 7: - self.ldflags_shared_debug = [ - '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG' - ] + self.ldflags_shared_debug = ['/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'] else: self.ldflags_shared_debug = [ - '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG' - ] - self.ldflags_static = [ '/nologo'] + '/DLL', + '/nologo', + '/INCREMENTAL:no', + '/pdb:None', + '/DEBUG', + ] + self.ldflags_static = ['/nologo'] self.initialized = True # -- Worker methods ------------------------------------------------ - def object_filenames(self, - source_filenames, - strip_dir=0, - output_dir=''): + def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): # Copied from ccompiler.py, extended to return .res as 'object'-file # for .rc input file - if output_dir is None: output_dir = '' + if output_dir is None: + output_dir = '' obj_names = [] for src_name in source_filenames: - (base, ext) = os.path.splitext (src_name) - base = os.path.splitdrive(base)[1] # Chop off the drive - base = base[os.path.isabs(base):] # If abs, chop off leading / + (base, ext) = os.path.splitext(src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base) :] # If abs, chop off leading / if ext not in self.src_extensions: # Better to raise an exception instead of silently continuing # and later complain about sources and targets having # different lengths - raise CompileError ("Don't know how to compile %s" % src_name) + raise CompileError("Don't know how to compile %s" % src_name) if strip_dir: - base = os.path.basename (base) + base = os.path.basename(base) if ext in self._rc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) + obj_names.append(os.path.join(output_dir, base + self.res_extension)) elif ext in self._mc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) + obj_names.append(os.path.join(output_dir, base + self.res_extension)) else: - obj_names.append (os.path.join (output_dir, - base + self.obj_extension)) + obj_names.append(os.path.join(output_dir, base + self.obj_extension)) return obj_names - - def compile(self, sources, - output_dir=None, macros=None, include_dirs=None, debug=0, - extra_preargs=None, extra_postargs=None, depends=None): + def compile( + self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None, + ): if not self.initialized: self.initialize() - compile_info = self._setup_compile(output_dir, macros, include_dirs, - sources, depends, extra_postargs) + compile_info = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs + ) macros, objects, extra_postargs, pp_opts, build = compile_info compile_opts = extra_preargs or [] - compile_opts.append ('/c') + compile_opts.append('/c') if debug: compile_opts.extend(self.compile_options_debug) else: @@ -377,8 +414,7 @@ def compile(self, sources, input_opt = src output_opt = "/fo" + obj try: - self.spawn([self.rc] + pp_opts + - [output_opt] + [input_opt]) + self.spawn([self.rc] + pp_opts + [output_opt] + [input_opt]) except DistutilsExecError as msg: raise CompileError(msg) continue @@ -398,50 +434,46 @@ def compile(self, sources, rc_dir = os.path.dirname(obj) try: # first compile .MC to .RC and .H file - self.spawn([self.mc] + - ['-h', h_dir, '-r', rc_dir] + [src]) - base, _ = os.path.splitext (os.path.basename (src)) - rc_file = os.path.join (rc_dir, base + '.rc') + self.spawn([self.mc] + ['-h', h_dir, '-r', rc_dir] + [src]) + base, _ = os.path.splitext(os.path.basename(src)) + rc_file = os.path.join(rc_dir, base + '.rc') # then compile .RC to .RES file - self.spawn([self.rc] + - ["/fo" + obj] + [rc_file]) + self.spawn([self.rc] + ["/fo" + obj] + [rc_file]) except DistutilsExecError as msg: raise CompileError(msg) continue else: # how to handle this file? - raise CompileError("Don't know how to compile %s to %s" - % (src, obj)) + raise CompileError("Don't know how to compile %s to %s" % (src, obj)) output_opt = "/Fo" + obj try: - self.spawn([self.cc] + compile_opts + pp_opts + - [input_opt, output_opt] + - extra_postargs) + self.spawn( + [self.cc] + + compile_opts + + pp_opts + + [input_opt, output_opt] + + extra_postargs + ) except DistutilsExecError as msg: raise CompileError(msg) return objects - - def create_static_lib(self, - objects, - output_libname, - output_dir=None, - debug=0, - target_lang=None): + def create_static_lib( + self, objects, output_libname, output_dir=None, debug=0, target_lang=None + ): if not self.initialized: self.initialize() (objects, output_dir) = self._fix_object_args(objects, output_dir) - output_filename = self.library_filename(output_libname, - output_dir=output_dir) + output_filename = self.library_filename(output_libname, output_dir=output_dir) if self._need_link(objects, output_filename): lib_args = objects + ['/OUT:' + output_filename] if debug: - pass # XXX what goes here? + pass # XXX what goes here? try: self.spawn([self.lib] + lib_args) except DistutilsExecError as msg: @@ -449,36 +481,36 @@ def create_static_lib(self, else: log.debug("skipping %s (up-to-date)", output_filename) - - def link(self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): if not self.initialized: self.initialize() (objects, output_dir) = self._fix_object_args(objects, output_dir) - fixed_args = self._fix_lib_args(libraries, library_dirs, - runtime_library_dirs) + fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) (libraries, library_dirs, runtime_library_dirs) = fixed_args if runtime_library_dirs: - self.warn ("I don't know what to do with 'runtime_library_dirs': " - + str (runtime_library_dirs)) + self.warn( + "I don't know what to do with 'runtime_library_dirs': " + + str(runtime_library_dirs) + ) - lib_opts = gen_lib_options(self, - library_dirs, runtime_library_dirs, - libraries) + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries) if output_dir is not None: output_filename = os.path.join(output_dir, output_filename) @@ -495,11 +527,12 @@ def link(self, ldflags = self.ldflags_shared export_opts = [] - for sym in (export_symbols or []): + for sym in export_symbols or []: export_opts.append("/EXPORT:" + sym) - ld_args = (ldflags + lib_opts + export_opts + - objects + ['/OUT:' + output_filename]) + ld_args = ( + ldflags + lib_opts + export_opts + objects + ['/OUT:' + output_filename] + ) # The MSVC linker generates .lib and .exp files, which cannot be # suppressed by any linker switches. The .lib files may even be @@ -508,11 +541,12 @@ def link(self, # builds, they can go into the same directory. if export_symbols is not None: (dll_name, dll_ext) = os.path.splitext( - os.path.basename(output_filename)) + os.path.basename(output_filename) + ) implib_file = os.path.join( - os.path.dirname(objects[0]), - self.library_filename(dll_name)) - ld_args.append ('/IMPLIB:' + implib_file) + os.path.dirname(objects[0]), self.library_filename(dll_name) + ) + ld_args.append('/IMPLIB:' + implib_file) if extra_preargs: ld_args[:0] = extra_preargs @@ -528,7 +562,6 @@ def link(self, else: log.debug("skipping %s (up-to-date)", output_filename) - # -- Miscellaneous methods ----------------------------------------- # These are all used by the 'gen_lib_options() function, in # ccompiler.py. @@ -538,12 +571,12 @@ def library_dir_option(self, dir): def runtime_library_dir_option(self, dir): raise DistutilsPlatformError( - "don't know how to set runtime library search path for MSVC++") + "don't know how to set runtime library search path for MSVC++" + ) def library_option(self, lib): return self.library_filename(lib) - def find_library_file(self, dirs, lib, debug=0): # Prefer a debugging library if found (and requested), but deal # with it if we don't have one. @@ -553,7 +586,7 @@ def find_library_file(self, dirs, lib, debug=0): try_names = [lib] for dir in dirs: for name in try_names: - libfile = os.path.join(dir, self.library_filename (name)) + libfile = os.path.join(dir, self.library_filename(name)) if os.path.exists(libfile): return libfile else: @@ -578,7 +611,7 @@ def find_exe(self, exe): # didn't find it; try existing path for p in os.environ['Path'].split(';'): - fn = os.path.join(os.path.abspath(p),exe) + fn = os.path.join(os.path.abspath(p), exe) if os.path.isfile(fn): return fn @@ -595,11 +628,15 @@ def get_msvc_paths(self, path, platform='x86'): path = path + " dirs" if self.__version >= 7: - key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" - % (self.__root, self.__version)) + key = r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" % ( + self.__root, + self.__version, + ) else: - key = (r"%s\6.0\Build System\Components\Platforms" - r"\Win32 (%s)\Directories" % (self.__root, platform)) + key = ( + r"%s\6.0\Build System\Components\Platforms" + r"\Win32 (%s)\Directories" % (self.__root, platform) + ) for base in HKEYS: d = read_values(base, key) @@ -613,10 +650,12 @@ def get_msvc_paths(self, path, platform='x86'): if self.__version == 6: for base in HKEYS: if read_values(base, r"%s\6.0" % self.__root) is not None: - self.warn("It seems you have Visual Studio 6 installed, " + self.warn( + "It seems you have Visual Studio 6 installed, " "but the expected registry settings are not present.\n" "You must at least run the Visual Studio GUI once " - "so that these entries are created.") + "so that these entries are created." + ) break return [] @@ -639,5 +678,6 @@ def set_path_env_var(self, name): log.debug("Importing new compiler from distutils.msvc9compiler") OldMSVCCompiler = MSVCCompiler from distutils.msvc9compiler import MSVCCompiler + # get_build_architecture not really relevant now we support cross-compile from distutils.msvc9compiler import MacroExpander diff --git a/setuptools/_distutils/py38compat.py b/setuptools/_distutils/py38compat.py index 7dbe8cef54a..e556b69ee9d 100644 --- a/setuptools/_distutils/py38compat.py +++ b/setuptools/_distutils/py38compat.py @@ -1,6 +1,7 @@ def aix_platform(osname, version, release): try: import _aix_support + return _aix_support.aix_platform() except ImportError: pass diff --git a/setuptools/_distutils/spawn.py b/setuptools/_distutils/spawn.py index 6e1c89f1f23..45f530f840c 100644 --- a/setuptools/_distutils/spawn.py +++ b/setuptools/_distutils/spawn.py @@ -48,6 +48,7 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None): if sys.platform == 'darwin': from distutils.util import MACOSX_VERSION_VAR, get_macosx_target_ver + macosx_target_ver = get_macosx_target_ver() if macosx_target_ver: env[MACOSX_VERSION_VAR] = macosx_target_ver @@ -59,14 +60,14 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None): except OSError as exc: if not DEBUG: cmd = cmd[0] - raise DistutilsExecError( - "command %r failed: %s" % (cmd, exc.args[-1])) from exc + raise DistutilsExecError("command %r failed: %s" % (cmd, exc.args[-1])) from exc if exitcode: if not DEBUG: cmd = cmd[0] raise DistutilsExecError( - "command %r failed with exit code %s" % (cmd, exitcode)) + "command %r failed with exit code %s" % (cmd, exitcode) + ) def find_executable(executable, path=None): diff --git a/setuptools/_distutils/sysconfig.py b/setuptools/_distutils/sysconfig.py index 879b6981ed4..1113376e3b0 100644 --- a/setuptools/_distutils/sysconfig.py +++ b/setuptools/_distutils/sysconfig.py @@ -47,22 +47,28 @@ def _is_python_source_dir(d): return True return False + _sys_home = getattr(sys, '_home', None) if os.name == 'nt': + def _fix_pcbuild(d): if d and os.path.normcase(d).startswith( - os.path.normcase(os.path.join(PREFIX, "PCbuild"))): + os.path.normcase(os.path.join(PREFIX, "PCbuild")) + ): return PREFIX return d + project_base = _fix_pcbuild(project_base) _sys_home = _fix_pcbuild(_sys_home) + def _python_build(): if _sys_home: return _is_python_source_dir(_sys_home) return _is_python_source_dir(project_base) + python_build = _python_build() @@ -78,6 +84,7 @@ def _python_build(): # this attribute, which is fine. pass + def get_python_version(): """Return a string containing the major and minor Python version, leaving off the patchlevel. Sample return values could be '1.5' @@ -119,13 +126,17 @@ def get_python_inc(plat_specific=0, prefix=None): if python_build: # Include both the include and PC dir to ensure we can find # pyconfig.h - return (os.path.join(prefix, "include") + os.path.pathsep + - os.path.join(prefix, "PC")) + return ( + os.path.join(prefix, "include") + + os.path.pathsep + + os.path.join(prefix, "PC") + ) return os.path.join(prefix, "include") else: raise DistutilsPlatformError( "I don't know where Python installs its C header files " - "on platform '%s'" % os.name) + "on platform '%s'" % os.name + ) def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): @@ -164,8 +175,7 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): else: # Pure Python libdir = "lib" - libpython = os.path.join(prefix, libdir, - "python" + get_python_version()) + libpython = os.path.join(prefix, libdir, "python" + get_python_version()) if standard_lib: return libpython else: @@ -178,8 +188,8 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): else: raise DistutilsPlatformError( "I don't know where Python installs its library " - "on platform '%s'" % os.name) - + "on platform '%s'" % os.name + ) def customize_compiler(compiler): @@ -202,21 +212,40 @@ def customize_compiler(compiler): # Use get_config_var() to ensure _config_vars is initialized. if not get_config_var('CUSTOMIZED_OSX_COMPILER'): import _osx_support + _osx_support.customize_compiler(_config_vars) _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' - (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ - get_config_vars('CC', 'CXX', 'CFLAGS', - 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') + ( + cc, + cxx, + cflags, + ccshared, + ldshared, + shlib_suffix, + ar, + ar_flags, + ) = get_config_vars( + 'CC', + 'CXX', + 'CFLAGS', + 'CCSHARED', + 'LDSHARED', + 'SHLIB_SUFFIX', + 'AR', + 'ARFLAGS', + ) if 'CC' in os.environ: newcc = os.environ['CC'] - if (sys.platform == 'darwin' - and 'LDSHARED' not in os.environ - and ldshared.startswith(cc)): + if ( + sys.platform == 'darwin' + and 'LDSHARED' not in os.environ + and ldshared.startswith(cc) + ): # On OS X, if CC is overridden, use that as the default # command for LDSHARED as well - ldshared = newcc + ldshared[len(cc):] + ldshared = newcc + ldshared[len(cc) :] cc = newcc if 'CXX' in os.environ: cxx = os.environ['CXX'] @@ -225,7 +254,7 @@ def customize_compiler(compiler): if 'CPP' in os.environ: cpp = os.environ['CPP'] else: - cpp = cc + " -E" # not always + cpp = cc + " -E" # not always if 'LDFLAGS' in os.environ: ldshared = ldshared + ' ' + os.environ['LDFLAGS'] if 'CFLAGS' in os.environ: @@ -250,7 +279,8 @@ def customize_compiler(compiler): compiler_cxx=cxx, linker_so=ldshared, linker_exe=cc, - archiver=archiver) + archiver=archiver, + ) compiler.shared_lib_extension = shlib_suffix @@ -298,8 +328,10 @@ def parse_config_h(fp, g=None): m = define_rx.match(line) if m: n, v = m.group(1, 2) - try: v = int(v) - except ValueError: pass + try: + v = int(v) + except ValueError: + pass g[n] = v else: m = undef_rx.match(line) @@ -314,6 +346,7 @@ def parse_config_h(fp, g=None): _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") + def parse_makefile(fn, g=None): """Parse a Makefile-style file. @@ -322,7 +355,10 @@ def parse_makefile(fn, g=None): used instead of a new dictionary. """ from distutils.text_file import TextFile - fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape") + + fp = TextFile( + fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape" + ) if g is None: g = {} @@ -331,7 +367,7 @@ def parse_makefile(fn, g=None): while True: line = fp.readline() - if line is None: # eof + if line is None: # eof break m = _variable_rx.match(line) if m: @@ -386,20 +422,20 @@ def parse_makefile(fn, g=None): else: done[n] = item = "" if found: - after = value[m.end():] - value = value[:m.start()] + item + after + after = value[m.end() :] + value = value[: m.start()] + item + after if "$" in after: notdone[name] = value else: - try: value = int(value) + try: + value = int(value) except ValueError: done[name] = value.strip() else: done[name] = value del notdone[name] - if name.startswith('PY_') \ - and name[3:] in renamed_variables: + if name.startswith('PY_') and name[3:] in renamed_variables: name = name[3:] if name not in done: @@ -447,21 +483,25 @@ def expand_makefile_vars(s, vars): _config_vars = None + def _init_posix(): """Initialize the module as appropriate for POSIX systems.""" # _sysconfigdata is generated at build time, see the sysconfig module - name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME', + name = os.environ.get( + '_PYTHON_SYSCONFIGDATA_NAME', '_sysconfigdata_{abi}_{platform}_{multiarch}'.format( - abi=sys.abiflags, - platform=sys.platform, - multiarch=getattr(sys.implementation, '_multiarch', ''), - )) + abi=sys.abiflags, + platform=sys.platform, + multiarch=getattr(sys.implementation, '_multiarch', ''), + ), + ) try: _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) except ImportError: # Python 3.5 and pypy 7.3.1 _temp = __import__( - '_sysconfigdata', globals(), locals(), ['build_time_vars'], 0) + '_sysconfigdata', globals(), locals(), ['build_time_vars'], 0 + ) build_time_vars = _temp.build_time_vars global _config_vars _config_vars = {} @@ -540,8 +580,7 @@ def get_config_vars(*args): # from a different directory. if python_build and os.name == "posix": base = project_base - if (not os.path.isabs(_config_vars['srcdir']) and - base != os.getcwd()): + if not os.path.isabs(_config_vars['srcdir']) and base != os.getcwd(): # srcdir is relative and we are not in the same directory # as the executable. Assume executable is in the build # directory and make srcdir absolute. @@ -552,6 +591,7 @@ def get_config_vars(*args): # multi-architecture, multi-os-version installers if sys.platform == 'darwin': import _osx_support + _osx_support.customize_config_vars(_config_vars) if args: @@ -562,6 +602,7 @@ def get_config_vars(*args): else: return _config_vars + def get_config_var(name): """Return the value of a single variable using the dictionary returned by 'get_config_vars()'. Equivalent to @@ -569,5 +610,6 @@ def get_config_var(name): """ if name == 'SO': import warnings + warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2) return get_config_vars().get(name) diff --git a/setuptools/_distutils/tests/py35compat.py b/setuptools/_distutils/tests/py35compat.py index 0c755261add..2252bc3cab0 100644 --- a/setuptools/_distutils/tests/py35compat.py +++ b/setuptools/_distutils/tests/py35compat.py @@ -18,6 +18,7 @@ def _missing_compiler_executable(cmd_names=[]): """ from distutils import ccompiler, sysconfig, spawn + compiler = ccompiler.new_compiler() sysconfig.customize_compiler(compiler) for name in compiler.executables: @@ -25,8 +26,7 @@ def _missing_compiler_executable(cmd_names=[]): continue cmd = getattr(compiler, name) if cmd_names: - assert cmd is not None, \ - "the '%s' executable is not configured" % name + assert cmd is not None, "the '%s' executable is not configured" % name elif not cmd: continue if spawn.find_executable(cmd[0]) is None: @@ -45,9 +45,11 @@ def _missing_compiler_executable(cmd_names=[]): # Adapted from Python 3.9 test.support module is_android = hasattr(sys, 'getandroidapilevel') unix_shell = ( - None if sys.platform == 'win32' else - '/system/bin/sh' if is_android else - '/bin/sh' + None + if sys.platform == 'win32' + else '/system/bin/sh' + if is_android + else '/bin/sh' ) diff --git a/setuptools/_distutils/tests/support.py b/setuptools/_distutils/tests/support.py index b4410fc9d9e..3085468a214 100644 --- a/setuptools/_distutils/tests/support.py +++ b/setuptools/_distutils/tests/support.py @@ -15,7 +15,6 @@ class LoggingSilencer(object): - def setUp(self): super().setUp() self.threshold = log.set_threshold(log.FATAL) @@ -35,13 +34,11 @@ def _log(self, level, msg, args): if level not in (DEBUG, INFO, WARN, ERROR, FATAL): raise ValueError('%s wrong log level' % str(level)) if not isinstance(msg, str): - raise TypeError("msg should be str, not '%.200s'" - % (type(msg).__name__)) + raise TypeError("msg should be str, not '%.200s'" % (type(msg).__name__)) self.logs.append((level, msg, args)) def get_logs(self, *levels): - return [msg % args for level, msg, args - in self.logs if level in levels] + return [msg % args for level, msg, args in self.logs if level in levels] def clear_logs(self): self.logs = [] @@ -120,7 +117,6 @@ def ensure_finalized(self): class EnvironGuard(object): - def setUp(self): super(EnvironGuard, self).setUp() self.old_environ = deepcopy(os.environ) @@ -151,8 +147,9 @@ def test_compile(self): """ filename = _get_xxmodule_path() if filename is None: - raise unittest.SkipTest('cannot find xxmodule.c (test must run in ' - 'the python build dir)') + raise unittest.SkipTest( + 'cannot find xxmodule.c (test must run in ' 'the python build dir)' + ) shutil.copy(filename, directory) diff --git a/setuptools/_distutils/tests/test_archive_util.py b/setuptools/_distutils/tests/test_archive_util.py index ce6456dc5d2..641296f855a 100644 --- a/setuptools/_distutils/tests/test_archive_util.py +++ b/setuptools/_distutils/tests/test_archive_util.py @@ -8,9 +8,13 @@ import warnings from distutils import archive_util -from distutils.archive_util import (check_archive_formats, make_tarball, - make_zipfile, make_archive, - ARCHIVE_FORMATS) +from distutils.archive_util import ( + check_archive_formats, + make_tarball, + make_zipfile, + make_archive, + ARCHIVE_FORMATS, +) from distutils.spawn import find_executable, spawn from distutils.tests import support from test.support import run_unittest, patch @@ -21,18 +25,21 @@ try: import grp import pwd + UID_GID_SUPPORT = True except ImportError: UID_GID_SUPPORT = False try: import zipfile + ZIP_SUPPORT = True except ImportError: ZIP_SUPPORT = find_executable('zip') try: import zlib + ZLIB_SUPPORT = True except ImportError: ZLIB_SUPPORT = False @@ -47,6 +54,7 @@ except ImportError: lzma = None + def can_fs_encode(filename): """ Return True if the filename can be saved in the file system. @@ -60,10 +68,9 @@ def can_fs_encode(filename): return True -class ArchiveUtilTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): - +class ArchiveUtilTestCase( + support.TempdirManager, support.LoggingSilencer, unittest.TestCase +): @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') def test_make_tarball(self, name='archive'): # creating something to tar @@ -87,27 +94,31 @@ def test_make_tarball_xz(self): tmpdir = self._create_files() self._make_tarball(tmpdir, 'archive', '.tar.xz', compress='xz') - @unittest.skipUnless(can_fs_encode('årchiv'), - 'File system cannot handle this filename') + @unittest.skipUnless( + can_fs_encode('årchiv'), 'File system cannot handle this filename' + ) def test_make_tarball_latin1(self): """ Mirror test_make_tarball, except filename contains latin characters. """ - self.test_make_tarball('årchiv') # note this isn't a real word + self.test_make_tarball('årchiv') # note this isn't a real word - @unittest.skipUnless(can_fs_encode('のアーカイブ'), - 'File system cannot handle this filename') + @unittest.skipUnless( + can_fs_encode('のアーカイブ'), 'File system cannot handle this filename' + ) def test_make_tarball_extended(self): """ Mirror test_make_tarball, except filename contains extended characters outside the latin charset. """ - self.test_make_tarball('のアーカイブ') # japanese for archive + self.test_make_tarball('のアーカイブ') # japanese for archive def _make_tarball(self, tmpdir, target_name, suffix, **kwargs): tmpdir2 = self.mkdtemp() - unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], - "source and target should be on same drive") + unittest.skipUnless( + splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], + "source and target should be on same drive", + ) base_name = os.path.join(tmpdir2, target_name) @@ -129,8 +140,14 @@ def _tarinfo(self, path): finally: tar.close() - _zip_created_files = ['dist/', 'dist/file1', 'dist/file2', - 'dist/sub/', 'dist/sub/file3', 'dist/sub2/'] + _zip_created_files = [ + 'dist/', + 'dist/file1', + 'dist/file2', + 'dist/sub/', + 'dist/sub/file3', + 'dist/sub2/', + ] _created_files = [p.rstrip('/') for p in _zip_created_files] def _create_files(self): @@ -145,11 +162,12 @@ def _create_files(self): os.mkdir(os.path.join(dist, 'sub2')) return tmpdir - @unittest.skipUnless(find_executable('tar') and find_executable('gzip') - and ZLIB_SUPPORT, - 'Need the tar, gzip and zlib command to run') + @unittest.skipUnless( + find_executable('tar') and find_executable('gzip') and ZLIB_SUPPORT, + 'Need the tar, gzip and zlib command to run', + ) def test_tarfile_vs_tar(self): - tmpdir = self._create_files() + tmpdir = self._create_files() tmpdir2 = self.mkdtemp() base_name = os.path.join(tmpdir2, 'archive') old_dir = os.getcwd() @@ -202,10 +220,11 @@ def test_tarfile_vs_tar(self): tarball = base_name + '.tar' self.assertTrue(os.path.exists(tarball)) - @unittest.skipUnless(find_executable('compress'), - 'The compress program is required') + @unittest.skipUnless( + find_executable('compress'), 'The compress program is required' + ) def test_compress_deprecated(self): - tmpdir = self._create_files() + tmpdir = self._create_files() base_name = os.path.join(self.mkdtemp(), 'archive') # using compress and testing the PendingDeprecationWarning @@ -228,15 +247,15 @@ def test_compress_deprecated(self): try: with check_warnings() as w: warnings.simplefilter("always") - make_tarball(base_name, 'dist', compress='compress', - dry_run=True) + make_tarball(base_name, 'dist', compress='compress', dry_run=True) finally: os.chdir(old_dir) self.assertFalse(os.path.exists(tarball)) self.assertEqual(len(w.warnings), 1) - @unittest.skipUnless(ZIP_SUPPORT and ZLIB_SUPPORT, - 'Need zip and zlib support to run') + @unittest.skipUnless( + ZIP_SUPPORT and ZLIB_SUPPORT, 'Need zip and zlib support to run' + ) def test_make_zipfile(self): # creating something to tar tmpdir = self._create_files() @@ -256,6 +275,7 @@ def test_make_zipfile_no_zlib(self): called = [] zipfile_class = zipfile.ZipFile + def fake_zipfile(*a, **kw): if kw.get('compression', None) == zipfile.ZIP_STORED: called.append((a, kw)) @@ -270,17 +290,18 @@ def fake_zipfile(*a, **kw): make_zipfile(base_name, 'dist') tarball = base_name + '.zip' - self.assertEqual(called, - [((tarball, "w"), {'compression': zipfile.ZIP_STORED})]) + self.assertEqual( + called, [((tarball, "w"), {'compression': zipfile.ZIP_STORED})] + ) self.assertTrue(os.path.exists(tarball)) with zipfile.ZipFile(tarball) as zf: self.assertEqual(sorted(zf.namelist()), self._zip_created_files) def test_check_archive_formats(self): - self.assertEqual(check_archive_formats(['gztar', 'xxx', 'zip']), - 'xxx') - self.assertIsNone(check_archive_formats(['gztar', 'bztar', 'xztar', - 'ztar', 'tar', 'zip'])) + self.assertEqual(check_archive_formats(['gztar', 'xxx', 'zip']), 'xxx') + self.assertIsNone( + check_archive_formats(['gztar', 'bztar', 'xztar', 'ztar', 'tar', 'zip']) + ) def test_make_archive(self): tmpdir = self.mkdtemp() @@ -289,8 +310,10 @@ def test_make_archive(self): def test_make_archive_cwd(self): current_dir = os.getcwd() + def _breaks(*args, **kw): raise RuntimeError() + ARCHIVE_FORMATS['xxx'] = (_breaks, [], 'xxx file') try: try: @@ -302,8 +325,8 @@ def _breaks(*args, **kw): del ARCHIVE_FORMATS['xxx'] def test_make_archive_tar(self): - base_dir = self._create_files() - base_name = os.path.join(self.mkdtemp() , 'archive') + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') res = make_archive(base_name, 'tar', base_dir, 'dist') self.assertTrue(os.path.exists(res)) self.assertEqual(os.path.basename(res), 'archive.tar') @@ -311,8 +334,8 @@ def test_make_archive_tar(self): @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') def test_make_archive_gztar(self): - base_dir = self._create_files() - base_name = os.path.join(self.mkdtemp() , 'archive') + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') res = make_archive(base_name, 'gztar', base_dir, 'dist') self.assertTrue(os.path.exists(res)) self.assertEqual(os.path.basename(res), 'archive.tar.gz') @@ -320,8 +343,8 @@ def test_make_archive_gztar(self): @unittest.skipUnless(bz2, 'Need bz2 support to run') def test_make_archive_bztar(self): - base_dir = self._create_files() - base_name = os.path.join(self.mkdtemp() , 'archive') + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') res = make_archive(base_name, 'bztar', base_dir, 'dist') self.assertTrue(os.path.exists(res)) self.assertEqual(os.path.basename(res), 'archive.tar.bz2') @@ -329,8 +352,8 @@ def test_make_archive_bztar(self): @unittest.skipUnless(lzma, 'Need xz support to run') def test_make_archive_xztar(self): - base_dir = self._create_files() - base_name = os.path.join(self.mkdtemp() , 'archive') + base_dir = self._create_files() + base_name = os.path.join(self.mkdtemp(), 'archive') res = make_archive(base_name, 'xztar', base_dir, 'dist') self.assertTrue(os.path.exists(res)) self.assertEqual(os.path.basename(res), 'archive.tar.xz') @@ -345,36 +368,40 @@ def test_make_archive_owner_group(self): else: group = owner = 'root' - base_dir = self._create_files() + base_dir = self._create_files() root_dir = self.mkdtemp() - base_name = os.path.join(self.mkdtemp() , 'archive') - res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, - group=group) + base_name = os.path.join(self.mkdtemp(), 'archive') + res = make_archive( + base_name, 'zip', root_dir, base_dir, owner=owner, group=group + ) self.assertTrue(os.path.exists(res)) res = make_archive(base_name, 'zip', root_dir, base_dir) self.assertTrue(os.path.exists(res)) - res = make_archive(base_name, 'tar', root_dir, base_dir, - owner=owner, group=group) + res = make_archive( + base_name, 'tar', root_dir, base_dir, owner=owner, group=group + ) self.assertTrue(os.path.exists(res)) - res = make_archive(base_name, 'tar', root_dir, base_dir, - owner='kjhkjhkjg', group='oihohoh') + res = make_archive( + base_name, 'tar', root_dir, base_dir, owner='kjhkjhkjg', group='oihohoh' + ) self.assertTrue(os.path.exists(res)) @unittest.skipUnless(ZLIB_SUPPORT, "Requires zlib") @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") def test_tarfile_root_owner(self): - tmpdir = self._create_files() + tmpdir = self._create_files() base_name = os.path.join(self.mkdtemp(), 'archive') old_dir = os.getcwd() os.chdir(tmpdir) group = grp.getgrgid(0)[0] owner = pwd.getpwuid(0)[0] try: - archive_name = make_tarball(base_name, 'dist', compress=None, - owner=owner, group=group) + archive_name = make_tarball( + base_name, 'dist', compress=None, owner=owner, group=group + ) finally: os.chdir(old_dir) @@ -390,8 +417,10 @@ def test_tarfile_root_owner(self): finally: archive.close() + def test_suite(): return unittest.makeSuite(ArchiveUtilTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_bdist.py b/setuptools/_distutils/tests/test_bdist.py index 130d8bf155a..a9a9e5a6eeb 100644 --- a/setuptools/_distutils/tests/test_bdist.py +++ b/setuptools/_distutils/tests/test_bdist.py @@ -8,9 +8,7 @@ from distutils.tests import support -class BuildTestCase(support.TempdirManager, - unittest.TestCase): - +class BuildTestCase(support.TempdirManager, unittest.TestCase): def test_formats(self): # let's create a command and make sure # we can set the format @@ -21,8 +19,17 @@ def test_formats(self): self.assertEqual(cmd.formats, ['msi']) # what formats does bdist offer? - formats = ['bztar', 'gztar', 'msi', 'rpm', 'tar', - 'wininst', 'xztar', 'zip', 'ztar'] + formats = [ + 'bztar', + 'gztar', + 'msi', + 'rpm', + 'tar', + 'wininst', + 'xztar', + 'zip', + 'ztar', + ] found = sorted(cmd.format_command) self.assertEqual(found, formats) @@ -34,24 +41,30 @@ def test_skip_build(self): cmd.ensure_finalized() dist.command_obj['bdist'] = cmd - names = ['bdist_dumb', 'bdist_wininst'] # bdist_rpm does not support --skip-build + names = [ + 'bdist_dumb', + 'bdist_wininst', + ] # bdist_rpm does not support --skip-build if os.name == 'nt': names.append('bdist_msi') for name in names: with warnings.catch_warnings(): - warnings.filterwarnings('ignore', 'bdist_wininst command is deprecated', - DeprecationWarning) + warnings.filterwarnings( + 'ignore', 'bdist_wininst command is deprecated', DeprecationWarning + ) subcmd = cmd.get_finalized_command(name) if getattr(subcmd, '_unsupported', False): # command is not supported on this build continue - self.assertTrue(subcmd.skip_build, - '%s should take --skip-build from bdist' % name) + self.assertTrue( + subcmd.skip_build, '%s should take --skip-build from bdist' % name + ) def test_suite(): return unittest.makeSuite(BuildTestCase) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_bdist_dumb.py b/setuptools/_distutils/tests/test_bdist_dumb.py index 01a233bce37..13d2b0142cc 100644 --- a/setuptools/_distutils/tests/test_bdist_dumb.py +++ b/setuptools/_distutils/tests/test_bdist_dumb.py @@ -21,16 +21,18 @@ try: import zlib + ZLIB_SUPPORT = True except ImportError: ZLIB_SUPPORT = False -class BuildDumbTestCase(support.TempdirManager, - support.LoggingSilencer, - support.EnvironGuard, - unittest.TestCase): - +class BuildDumbTestCase( + support.TempdirManager, + support.LoggingSilencer, + support.EnvironGuard, + unittest.TestCase, +): def setUp(self): super(BuildDumbTestCase, self).setUp() self.old_location = os.getcwd() @@ -54,10 +56,16 @@ def test_simple_built(self): self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py') self.write_file((pkg_dir, 'README'), '') - dist = Distribution({'name': 'foo', 'version': '0.1', - 'py_modules': ['foo'], - 'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx'}) + dist = Distribution( + { + 'name': 'foo', + 'version': '0.1', + 'py_modules': ['foo'], + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + } + ) dist.script_name = 'setup.py' os.chdir(pkg_dir) @@ -90,8 +98,10 @@ def test_simple_built(self): wanted.append('foo.%s.pyc' % sys.implementation.cache_tag) self.assertEqual(contents, sorted(wanted)) + def test_suite(): return unittest.makeSuite(BuildDumbTestCase) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_bdist_msi.py b/setuptools/_distutils/tests/test_bdist_msi.py index 937266f8c08..5edb63b433a 100644 --- a/setuptools/_distutils/tests/test_bdist_msi.py +++ b/setuptools/_distutils/tests/test_bdist_msi.py @@ -8,13 +8,13 @@ @unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') -class BDistMSITestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): - +class BDistMSITestCase( + support.TempdirManager, support.LoggingSilencer, unittest.TestCase +): def test_minimal(self): # minimal test XXX need more tests from distutils.command.bdist_msi import bdist_msi + project_dir, dist = self.create_dist() with check_warnings(("", DeprecationWarning)): cmd = bdist_msi(dist) @@ -24,5 +24,6 @@ def test_minimal(self): def test_suite(): return unittest.makeSuite(BDistMSITestCase) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_bdist_rpm.py b/setuptools/_distutils/tests/test_bdist_rpm.py index 6453a02b88f..340bf276462 100644 --- a/setuptools/_distutils/tests/test_bdist_rpm.py +++ b/setuptools/_distutils/tests/test_bdist_rpm.py @@ -19,11 +19,13 @@ """ -class BuildRpmTestCase(support.TempdirManager, - support.EnvironGuard, - support.LoggingSilencer, - unittest.TestCase): +class BuildRpmTestCase( + support.TempdirManager, + support.EnvironGuard, + support.LoggingSilencer, + unittest.TestCase, +): def setUp(self): try: sys.executable.encode("UTF-8") @@ -42,17 +44,18 @@ def tearDown(self): # XXX I am unable yet to make this test work without # spurious sdtout/stderr output under Mac OS X - @unittest.skipUnless(sys.platform.startswith('linux'), - 'spurious sdtout/stderr output under Mac OS X') + @unittest.skipUnless( + sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X' + ) @requires_zlib - @unittest.skipIf(find_executable('rpm') is None, - 'the rpm command is not found') - @unittest.skipIf(find_executable('rpmbuild') is None, - 'the rpmbuild command is not found') + @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') + @unittest.skipIf( + find_executable('rpmbuild') is None, 'the rpmbuild command is not found' + ) def test_quiet(self): # let's create a package tmp_dir = self.mkdtemp() - os.environ['HOME'] = tmp_dir # to confine dir '.rpmdb' creation + os.environ['HOME'] = tmp_dir # to confine dir '.rpmdb' creation pkg_dir = os.path.join(tmp_dir, 'foo') os.mkdir(pkg_dir) self.write_file((pkg_dir, 'setup.py'), SETUP_PY) @@ -60,10 +63,16 @@ def test_quiet(self): self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py') self.write_file((pkg_dir, 'README'), '') - dist = Distribution({'name': 'foo', 'version': '0.1', - 'py_modules': ['foo'], - 'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx'}) + dist = Distribution( + { + 'name': 'foo', + 'version': '0.1', + 'py_modules': ['foo'], + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + } + ) dist.script_name = 'setup.py' os.chdir(pkg_dir) @@ -81,22 +90,25 @@ def test_quiet(self): # bug #2945: upload ignores bdist_rpm files self.assertIn(('bdist_rpm', 'any', 'dist/foo-0.1-1.src.rpm'), dist.dist_files) - self.assertIn(('bdist_rpm', 'any', 'dist/foo-0.1-1.noarch.rpm'), dist.dist_files) + self.assertIn( + ('bdist_rpm', 'any', 'dist/foo-0.1-1.noarch.rpm'), dist.dist_files + ) # XXX I am unable yet to make this test work without # spurious sdtout/stderr output under Mac OS X - @unittest.skipUnless(sys.platform.startswith('linux'), - 'spurious sdtout/stderr output under Mac OS X') + @unittest.skipUnless( + sys.platform.startswith('linux'), 'spurious sdtout/stderr output under Mac OS X' + ) @requires_zlib # http://bugs.python.org/issue1533164 - @unittest.skipIf(find_executable('rpm') is None, - 'the rpm command is not found') - @unittest.skipIf(find_executable('rpmbuild') is None, - 'the rpmbuild command is not found') + @unittest.skipIf(find_executable('rpm') is None, 'the rpm command is not found') + @unittest.skipIf( + find_executable('rpmbuild') is None, 'the rpmbuild command is not found' + ) def test_no_optimize_flag(self): # let's create a package that breaks bdist_rpm tmp_dir = self.mkdtemp() - os.environ['HOME'] = tmp_dir # to confine dir '.rpmdb' creation + os.environ['HOME'] = tmp_dir # to confine dir '.rpmdb' creation pkg_dir = os.path.join(tmp_dir, 'foo') os.mkdir(pkg_dir) self.write_file((pkg_dir, 'setup.py'), SETUP_PY) @@ -104,10 +116,16 @@ def test_no_optimize_flag(self): self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py') self.write_file((pkg_dir, 'README'), '') - dist = Distribution({'name': 'foo', 'version': '0.1', - 'py_modules': ['foo'], - 'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx'}) + dist = Distribution( + { + 'name': 'foo', + 'version': '0.1', + 'py_modules': ['foo'], + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + } + ) dist.script_name = 'setup.py' os.chdir(pkg_dir) @@ -124,12 +142,16 @@ def test_no_optimize_flag(self): # bug #2945: upload ignores bdist_rpm files self.assertIn(('bdist_rpm', 'any', 'dist/foo-0.1-1.src.rpm'), dist.dist_files) - self.assertIn(('bdist_rpm', 'any', 'dist/foo-0.1-1.noarch.rpm'), dist.dist_files) + self.assertIn( + ('bdist_rpm', 'any', 'dist/foo-0.1-1.noarch.rpm'), dist.dist_files + ) os.remove(os.path.join(pkg_dir, 'dist', 'foo-0.1-1.noarch.rpm')) + def test_suite(): return unittest.makeSuite(BuildRpmTestCase) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_bdist_wininst.py b/setuptools/_distutils/tests/test_bdist_wininst.py index 31cf2628de5..7f26291a0fa 100644 --- a/setuptools/_distutils/tests/test_bdist_wininst.py +++ b/setuptools/_distutils/tests/test_bdist_wininst.py @@ -9,14 +9,18 @@ from distutils.command.bdist_wininst import bdist_wininst from distutils.tests import support -@unittest.skipIf(sys.platform == 'win32' and platform.machine() == 'ARM64', - 'bdist_wininst is not supported in this install') -@unittest.skipIf(getattr(bdist_wininst, '_unsupported', False), - 'bdist_wininst is not supported in this install') -class BuildWinInstTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): +@unittest.skipIf( + sys.platform == 'win32' and platform.machine() == 'ARM64', + 'bdist_wininst is not supported in this install', +) +@unittest.skipIf( + getattr(bdist_wininst, '_unsupported', False), + 'bdist_wininst is not supported in this install', +) +class BuildWinInstTestCase( + support.TempdirManager, support.LoggingSilencer, unittest.TestCase +): def test_get_exe_bytes(self): # issue5731: command was broken on non-windows platforms @@ -33,8 +37,10 @@ def test_get_exe_bytes(self): exe_file = cmd.get_exe_bytes() self.assertGreater(len(exe_file), 10) + def test_suite(): return unittest.makeSuite(BuildWinInstTestCase) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_build.py b/setuptools/_distutils/tests/test_build.py index b020a5ba356..21807ad1d90 100644 --- a/setuptools/_distutils/tests/test_build.py +++ b/setuptools/_distutils/tests/test_build.py @@ -8,10 +8,8 @@ from distutils.tests import support from sysconfig import get_platform -class BuildTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): +class BuildTestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): def test_finalize_options(self): pkg_dir, dist = self.create_dist() cmd = build(dist) @@ -42,15 +40,16 @@ def test_finalize_options(self): self.assertEqual(cmd.build_temp, wanted) # build_scripts is build/scripts-x.x - wanted = os.path.join(cmd.build_base, - 'scripts-%d.%d' % sys.version_info[:2]) + wanted = os.path.join(cmd.build_base, 'scripts-%d.%d' % sys.version_info[:2]) self.assertEqual(cmd.build_scripts, wanted) # executable is os.path.normpath(sys.executable) self.assertEqual(cmd.executable, os.path.normpath(sys.executable)) + def test_suite(): return unittest.makeSuite(BuildTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_build_clib.py b/setuptools/_distutils/tests/test_build_clib.py index 259c43522d1..104c9c221d3 100644 --- a/setuptools/_distutils/tests/test_build_clib.py +++ b/setuptools/_distutils/tests/test_build_clib.py @@ -11,10 +11,10 @@ from distutils.errors import DistutilsSetupError from distutils.tests import support -class BuildCLibTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): +class BuildCLibTestCase( + support.TempdirManager, support.LoggingSilencer, unittest.TestCase +): def test_check_library_dist(self): pkg_dir, dist = self.create_dist() cmd = build_clib(dist) @@ -23,23 +23,27 @@ def test_check_library_dist(self): self.assertRaises(DistutilsSetupError, cmd.check_library_list, 'foo') # each element of 'libraries' must a 2-tuple - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - ['foo1', 'foo2']) + self.assertRaises(DistutilsSetupError, cmd.check_library_list, ['foo1', 'foo2']) # first element of each tuple in 'libraries' # must be a string (the library name) - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - [(1, 'foo1'), ('name', 'foo2')]) + self.assertRaises( + DistutilsSetupError, cmd.check_library_list, [(1, 'foo1'), ('name', 'foo2')] + ) # library name may not contain directory separators - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - [('name', 'foo1'), - ('another/name', 'foo2')]) + self.assertRaises( + DistutilsSetupError, + cmd.check_library_list, + [('name', 'foo1'), ('another/name', 'foo2')], + ) # second element of each tuple must be a dictionary (build info) - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - [('name', {}), - ('another', 'foo2')]) + self.assertRaises( + DistutilsSetupError, + cmd.check_library_list, + [('name', {}), ('another', 'foo2')], + ) # those work libs = [('name', {}), ('name', {'ok': 'good'})] @@ -63,17 +67,21 @@ def test_get_source_files(self): cmd.libraries = [('name', {'sources': ('a', 'b')})] self.assertEqual(cmd.get_source_files(), ['a', 'b']) - cmd.libraries = [('name', {'sources': ('a', 'b')}), - ('name2', {'sources': ['c', 'd']})] + cmd.libraries = [ + ('name', {'sources': ('a', 'b')}), + ('name2', {'sources': ['c', 'd']}), + ] self.assertEqual(cmd.get_source_files(), ['a', 'b', 'c', 'd']) def test_build_libraries(self): pkg_dir, dist = self.create_dist() cmd = build_clib(dist) + class FakeCompiler: def compile(*args, **kw): pass + create_static_lib = compile cmd.compiler = FakeCompiler() @@ -129,8 +137,10 @@ def test_run(self): # let's check the result self.assertIn('libfoo.a', os.listdir(build_temp)) + def test_suite(): return unittest.makeSuite(BuildCLibTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_build_ext.py b/setuptools/_distutils/tests/test_build_ext.py index 85ecf4b720e..656b5f0f459 100644 --- a/setuptools/_distutils/tests/test_build_ext.py +++ b/setuptools/_distutils/tests/test_build_ext.py @@ -6,12 +6,19 @@ from distutils.core import Distribution from distutils.command.build_ext import build_ext from distutils import sysconfig -from distutils.tests.support import (TempdirManager, LoggingSilencer, - copy_xxmodule_c, fixup_build_ext) +from distutils.tests.support import ( + TempdirManager, + LoggingSilencer, + copy_xxmodule_c, + fixup_build_ext, +) from distutils.extension import Extension from distutils.errors import ( - CompileError, DistutilsPlatformError, DistutilsSetupError, - UnknownFileError) + CompileError, + DistutilsPlatformError, + DistutilsSetupError, + UnknownFileError, +) import unittest from test import support @@ -23,17 +30,17 @@ ALREADY_TESTED = False -class BuildExtTestCase(TempdirManager, - LoggingSilencer, - unittest.TestCase): +class BuildExtTestCase(TempdirManager, LoggingSilencer, unittest.TestCase): def setUp(self): # Create a simple test environment super(BuildExtTestCase, self).setUp() self.tmp_dir = self.mkdtemp() import site + self.old_user_base = site.USER_BASE site.USER_BASE = self.mkdtemp() from distutils.command import build_ext + build_ext.USER_BASE = site.USER_BASE # bpo-30132: On Windows, a .pdb file may be created in the current @@ -45,8 +52,10 @@ def setUp(self): def tearDown(self): import site + site.USER_BASE = self.old_user_base from distutils.command import build_ext + build_ext.USER_BASE = self.old_user_base super(BuildExtTestCase, self).tearDown() @@ -83,7 +92,8 @@ def test_build_ext(self): else: ALREADY_TESTED = type(self).__name__ - code = textwrap.dedent(""" + code = textwrap.dedent( + """ tmp_dir = {self.tmp_dir!r} import sys @@ -109,7 +119,10 @@ def test_xx(self): unittest.main() - """.format(**locals())) + """.format( + **locals() + ) + ) assert_python_ok('-c', code) def test_solaris_enable_shared(self): @@ -117,8 +130,9 @@ def test_solaris_enable_shared(self): cmd = self.build_ext(dist) old = sys.platform - sys.platform = 'sunos' # fooling finalize_options - from distutils.sysconfig import _config_vars + sys.platform = 'sunos' # fooling finalize_options + from distutils.sysconfig import _config_vars + old_var = _config_vars.get('Py_ENABLE_SHARED') _config_vars['Py_ENABLE_SHARED'] = 1 try: @@ -135,12 +149,12 @@ def test_solaris_enable_shared(self): def test_user_site(self): import site + dist = Distribution({'name': 'xx'}) cmd = self.build_ext(dist) # making sure the user option is there - options = [name for name, short, lable in - cmd.user_options] + options = [name for name, short, lable in cmd.user_options] self.assertIn('user', options) # setting a value @@ -169,8 +183,9 @@ def test_optional_extension(self): dist = Distribution({'name': 'xx', 'ext_modules': modules}) cmd = self.build_ext(dist) cmd.ensure_finalized() - self.assertRaises((UnknownFileError, CompileError), - cmd.run) # should raise an error + self.assertRaises( + (UnknownFileError, CompileError), cmd.run + ) # should raise an error modules = [Extension('foo', ['xxx'], optional=True)] dist = Distribution({'name': 'xx', 'ext_modules': modules}) @@ -256,8 +271,7 @@ def test_check_extensions_list(self): cmd.finalize_options() #'extensions' option must be a list of Extension instances - self.assertRaises(DistutilsSetupError, - cmd.check_extensions_list, 'foo') + self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, 'foo') # each element of 'ext_modules' option must be an # Extension instance or 2-tuple @@ -276,8 +290,7 @@ def test_check_extensions_list(self): self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts) # ok this one should pass - exts = [('foo.bar', {'sources': [''], 'libraries': 'foo', - 'some': 'bar'})] + exts = [('foo.bar', {'sources': [''], 'libraries': 'foo', 'some': 'bar'})] cmd.check_extensions_list(exts) ext = exts[0] self.assertIsInstance(ext, Extension) @@ -289,8 +302,17 @@ def test_check_extensions_list(self): self.assertFalse(hasattr(ext, 'some')) # 'macros' element of build info dict must be 1- or 2-tuple - exts = [('foo.bar', {'sources': [''], 'libraries': 'foo', - 'some': 'bar', 'macros': [('1', '2', '3'), 'foo']})] + exts = [ + ( + 'foo.bar', + { + 'sources': [''], + 'libraries': 'foo', + 'some': 'bar', + 'macros': [('1', '2', '3'), 'foo'], + }, + ) + ] self.assertRaises(DistutilsSetupError, cmd.check_extensions_list, exts) exts[0][1]['macros'] = [('1', '2'), ('3',)] @@ -337,8 +359,7 @@ def test_get_outputs(self): c_file = os.path.join(tmp_dir, 'foo.c') self.write_file(c_file, 'void PyInit_foo(void) {}\n') ext = Extension('foo', [c_file], optional=False) - dist = Distribution({'name': 'xx', - 'ext_modules': [ext]}) + dist = Distribution({'name': 'xx', 'ext_modules': [ext]}) cmd = self.build_ext(dist) fixup_build_ext(cmd) cmd.ensure_finalized() @@ -398,9 +419,9 @@ def test_get_outputs(self): def test_ext_fullpath(self): ext = sysconfig.get_config_var('EXT_SUFFIX') # building lxml.etree inplace - #etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c') - #etree_ext = Extension('lxml.etree', [etree_c]) - #dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]}) + # etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c') + # etree_ext = Extension('lxml.etree', [etree_c]) + # dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]}) dist = Distribution() cmd = self.build_ext(dist) cmd.inplace = 1 @@ -423,8 +444,7 @@ def test_ext_fullpath(self): build_py.package_dir = {} cmd.distribution.packages = ['twisted', 'twisted.runner.portmap'] path = cmd.get_ext_fullpath('twisted.runner.portmap') - wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner', - 'portmap' + ext) + wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner', 'portmap' + ext) self.assertEqual(wanted, path) # building twisted.runner.portmap inplace @@ -433,7 +453,6 @@ def test_ext_fullpath(self): wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext) self.assertEqual(wanted, path) - @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX') def test_deployment_target_default(self): # Issue 9516: Test that, in the absence of the environment variable, @@ -445,8 +464,9 @@ def test_deployment_target_default(self): def test_deployment_target_too_low(self): # Issue 9516: Test that an extension module is not allowed to be # compiled with a deployment target less than that of the interpreter. - self.assertRaises(DistutilsPlatformError, - self._try_compile_deployment_target, '>', '10.1') + self.assertRaises( + DistutilsPlatformError, self._try_compile_deployment_target, '>', '10.1' + ) @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for MacOSX') def test_deployment_target_higher_ok(self): @@ -475,7 +495,9 @@ def _try_compile_deployment_target(self, operator, target): deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c') with open(deptarget_c, 'w') as fp: - fp.write(textwrap.dedent('''\ + fp.write( + textwrap.dedent( + '''\ #include int dummy; @@ -485,7 +507,10 @@ def _try_compile_deployment_target(self, operator, target): #error "Unexpected target" #endif - ''' % operator)) + ''' + % operator + ) + ) # get the deployment target that the interpreter was built with target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') @@ -502,12 +527,9 @@ def _try_compile_deployment_target(self, operator, target): deptarget_ext = Extension( 'deptarget', [deptarget_c], - extra_compile_args=['-DTARGET=%s'%(target,)], + extra_compile_args=['-DTARGET=%s' % (target,)], ) - dist = Distribution({ - 'name': 'deptarget', - 'ext_modules': [deptarget_ext] - }) + dist = Distribution({'name': 'deptarget', 'ext_modules': [deptarget_ext]}) dist.package_dir = self.tmp_dir cmd = self.build_ext(dist) cmd.build_lib = self.tmp_dir @@ -529,7 +551,6 @@ def _try_compile_deployment_target(self, operator, target): class ParallelBuildExtTestCase(BuildExtTestCase): - def build_ext(self, *args, **kwargs): build_ext = super().build_ext(*args, **kwargs) build_ext.parallel = True @@ -542,5 +563,6 @@ def test_suite(): suite.addTest(unittest.makeSuite(ParallelBuildExtTestCase)) return suite + if __name__ == '__main__': support.run_unittest(__name__) diff --git a/setuptools/_distutils/tests/test_build_py.py b/setuptools/_distutils/tests/test_build_py.py index 0712e92c6ab..2e5230744aa 100644 --- a/setuptools/_distutils/tests/test_build_py.py +++ b/setuptools/_distutils/tests/test_build_py.py @@ -12,10 +12,9 @@ from test.support import run_unittest -class BuildPyTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): - +class BuildPyTestCase( + support.TempdirManager, support.LoggingSilencer, unittest.TestCase +): def test_package_data(self): sources = self.mkdtemp() f = open(os.path.join(sources, "__init__.py"), "w") @@ -31,13 +30,10 @@ def test_package_data(self): destination = self.mkdtemp() - dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": sources}}) + dist = Distribution({"packages": ["pkg"], "package_dir": {"pkg": sources}}) # script_name need not exist, it just need to be initialized dist.script_name = os.path.join(sources, "setup.py") - dist.command_obj["build"] = support.DummyCommand( - force=0, - build_lib=destination) + dist.command_obj["build"] = support.DummyCommand(force=0, build_lib=destination) dist.packages = ["pkg"] dist.package_data = {"pkg": ["README.txt"]} dist.package_dir = {"pkg": sources} @@ -62,8 +58,7 @@ def test_package_data(self): self.assertFalse(os.path.exists(pycache_dir)) else: pyc_files = os.listdir(pycache_dir) - self.assertIn("__init__.%s.pyc" % sys.implementation.cache_tag, - pyc_files) + self.assertIn("__init__.%s.pyc" % sys.implementation.cache_tag, pyc_files) def test_empty_package_dir(self): # See bugs #1668596/#1720897 @@ -75,9 +70,13 @@ def test_empty_package_dir(self): open(os.path.join(testdir, "testfile"), "w").close() os.chdir(sources) - dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": ""}, - "package_data": {"pkg": ["doc/*"]}}) + dist = Distribution( + { + "packages": ["pkg"], + "package_dir": {"pkg": ""}, + "package_data": {"pkg": ["doc/*"]}, + } + ) # script_name need not exist, it just need to be initialized dist.script_name = os.path.join(sources, "setup.py") dist.script_args = ["build"] @@ -102,8 +101,7 @@ def test_byte_compile(self): found = os.listdir(cmd.build_lib) self.assertEqual(sorted(found), ['__pycache__', 'boiledeggs.py']) found = os.listdir(os.path.join(cmd.build_lib, '__pycache__')) - self.assertEqual(found, - ['boiledeggs.%s.pyc' % sys.implementation.cache_tag]) + self.assertEqual(found, ['boiledeggs.%s.pyc' % sys.implementation.cache_tag]) @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled') def test_byte_compile_optimized(self): @@ -142,8 +140,7 @@ def test_dir_in_package_data(self): os.mkdir(os.path.join(docdir, 'otherdir')) os.chdir(sources) - dist = Distribution({"packages": ["pkg"], - "package_data": {"pkg": ["doc/*"]}}) + dist = Distribution({"packages": ["pkg"], "package_data": {"pkg": ["doc/*"]}}) # script_name need not exist, it just need to be initialized dist.script_name = os.path.join(sources, "setup.py") dist.script_args = ["build"] @@ -168,12 +165,12 @@ def test_dont_write_bytecode(self): finally: sys.dont_write_bytecode = old_dont_write_bytecode - self.assertIn('byte-compiling is disabled', - self.logs[0][1] % self.logs[0][2]) + self.assertIn('byte-compiling is disabled', self.logs[0][1] % self.logs[0][2]) def test_suite(): return unittest.makeSuite(BuildPyTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_build_scripts.py b/setuptools/_distutils/tests/test_build_scripts.py index 954fc763987..daf17f6c7ff 100644 --- a/setuptools/_distutils/tests/test_build_scripts.py +++ b/setuptools/_distutils/tests/test_build_scripts.py @@ -11,10 +11,9 @@ from test.support import run_unittest -class BuildScriptsTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): - +class BuildScriptsTestCase( + support.TempdirManager, support.LoggingSilencer, unittest.TestCase +): def test_default_settings(self): cmd = self.get_build_scripts_cmd("/foo/bar", []) self.assertFalse(cmd.force) @@ -30,9 +29,9 @@ def test_build(self): target = self.mkdtemp() expected = self.write_sample_scripts(source) - cmd = self.get_build_scripts_cmd(target, - [os.path.join(source, fn) - for fn in expected]) + cmd = self.get_build_scripts_cmd( + target, [os.path.join(source, fn) for fn in expected] + ) cmd.finalize_options() cmd.run() @@ -42,32 +41,38 @@ def test_build(self): def get_build_scripts_cmd(self, target, scripts): import sys + dist = Distribution() dist.scripts = scripts dist.command_obj["build"] = support.DummyCommand( - build_scripts=target, - force=1, - executable=sys.executable - ) + build_scripts=target, force=1, executable=sys.executable + ) return build_scripts(dist) def write_sample_scripts(self, dir): expected = [] expected.append("script1.py") - self.write_script(dir, "script1.py", - ("#! /usr/bin/env python2.3\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) + self.write_script( + dir, + "script1.py", + ( + "#! /usr/bin/env python2.3\n" + "# bogus script w/ Python sh-bang\n" + "pass\n" + ), + ) expected.append("script2.py") - self.write_script(dir, "script2.py", - ("#!/usr/bin/python\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) + self.write_script( + dir, + "script2.py", + ("#!/usr/bin/python\n" "# bogus script w/ Python sh-bang\n" "pass\n"), + ) expected.append("shell.sh") - self.write_script(dir, "shell.sh", - ("#!/bin/sh\n" - "# bogus shell script w/ sh-bang\n" - "exit 0\n")) + self.write_script( + dir, + "shell.sh", + ("#!/bin/sh\n" "# bogus shell script w/ sh-bang\n" "exit 0\n"), + ) return expected def write_script(self, dir, name, text): @@ -82,10 +87,9 @@ def test_version_int(self): target = self.mkdtemp() expected = self.write_sample_scripts(source) - - cmd = self.get_build_scripts_cmd(target, - [os.path.join(source, fn) - for fn in expected]) + cmd = self.get_build_scripts_cmd( + target, [os.path.join(source, fn) for fn in expected] + ) cmd.finalize_options() # http://bugs.python.org/issue4524 @@ -105,8 +109,10 @@ def test_version_int(self): for name in expected: self.assertIn(name, built) + def test_suite(): return unittest.makeSuite(BuildScriptsTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_check.py b/setuptools/_distutils/tests/test_check.py index e534aca1d47..55a64ce2679 100644 --- a/setuptools/_distutils/tests/test_check.py +++ b/setuptools/_distutils/tests/test_check.py @@ -17,10 +17,7 @@ HERE = os.path.dirname(__file__) -class CheckTestCase(support.LoggingSilencer, - support.TempdirManager, - unittest.TestCase): - +class CheckTestCase(support.LoggingSilencer, support.TempdirManager, unittest.TestCase): def _run(self, metadata=None, cwd=None, **options): if metadata is None: metadata = {} @@ -48,9 +45,13 @@ def test_check_metadata(self): # now let's add the required fields # and run it again, to make sure we don't get # any warning anymore - metadata = {'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx', - 'name': 'xxx', 'version': 'xxx'} + metadata = { + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', + 'version': 'xxx', + } cmd = self._run(metadata) self.assertEqual(cmd._warnings, 0) @@ -63,11 +64,15 @@ def test_check_metadata(self): self.assertEqual(cmd._warnings, 0) # now a test with non-ASCII characters - metadata = {'url': 'xxx', 'author': '\u00c9ric', - 'author_email': 'xxx', 'name': 'xxx', - 'version': 'xxx', - 'description': 'Something about esszet \u00df', - 'long_description': 'More things about esszet \u00df'} + metadata = { + 'url': 'xxx', + 'author': '\u00c9ric', + 'author_email': 'xxx', + 'name': 'xxx', + 'version': 'xxx', + 'description': 'Something about esszet \u00df', + 'long_description': 'More things about esszet \u00df', + } cmd = self._run(metadata) self.assertEqual(cmd._warnings, 0) @@ -96,12 +101,20 @@ def test_check_restructuredtext(self): self.assertEqual(cmd._warnings, 1) # let's see if we have an error with strict=1 - metadata = {'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx', - 'name': 'xxx', 'version': 'xxx', - 'long_description': broken_rest} - self.assertRaises(DistutilsSetupError, self._run, metadata, - **{'strict': 1, 'restructuredtext': 1}) + metadata = { + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', + 'version': 'xxx', + 'long_description': broken_rest, + } + self.assertRaises( + DistutilsSetupError, + self._run, + metadata, + **{'strict': 1, 'restructuredtext': 1} + ) # and non-broken rest, including a non-ASCII character to test #12114 metadata['long_description'] = 'title\n=====\n\ntest \u00df' @@ -118,22 +131,30 @@ def test_check_restructuredtext_with_syntax_highlight(self): # Don't fail if there is a `code` or `code-block` directive example_rst_docs = [] - example_rst_docs.append(textwrap.dedent("""\ + example_rst_docs.append( + textwrap.dedent( + """\ Here's some code: .. code:: python def foo(): pass - """)) - example_rst_docs.append(textwrap.dedent("""\ + """ + ) + ) + example_rst_docs.append( + textwrap.dedent( + """\ Here's some code: .. code-block:: python def foo(): pass - """)) + """ + ) + ) for rest_with_code in example_rst_docs: pkg_info, dist = self.create_dist(long_description=rest_with_code) @@ -145,19 +166,20 @@ def foo(): else: self.assertEqual(len(msgs), 1) self.assertEqual( - str(msgs[0][1]), - 'Cannot analyze code. Pygments package not found.' + str(msgs[0][1]), 'Cannot analyze code. Pygments package not found.' ) def test_check_all(self): metadata = {'url': 'xxx', 'author': 'xxx'} - self.assertRaises(DistutilsSetupError, self._run, - {}, **{'strict': 1, - 'restructuredtext': 1}) + self.assertRaises( + DistutilsSetupError, self._run, {}, **{'strict': 1, 'restructuredtext': 1} + ) + def test_suite(): return unittest.makeSuite(CheckTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_clean.py b/setuptools/_distutils/tests/test_clean.py index c605afd8601..7937dee2c85 100644 --- a/setuptools/_distutils/tests/test_clean.py +++ b/setuptools/_distutils/tests/test_clean.py @@ -6,18 +6,23 @@ from distutils.tests import support from test.support import run_unittest -class cleanTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): +class cleanTestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): def test_simple_run(self): pkg_dir, dist = self.create_dist() cmd = clean(dist) # let's add some elements clean should remove - dirs = [(d, os.path.join(pkg_dir, d)) - for d in ('build_temp', 'build_lib', 'bdist_base', - 'build_scripts', 'build_base')] + dirs = [ + (d, os.path.join(pkg_dir, d)) + for d in ( + 'build_temp', + 'build_lib', + 'bdist_base', + 'build_scripts', + 'build_base', + ) + ] for name, path in dirs: os.mkdir(path) @@ -34,16 +39,17 @@ def test_simple_run(self): # make sure the files where removed for name, path in dirs: - self.assertFalse(os.path.exists(path), - '%s was not removed' % path) + self.assertFalse(os.path.exists(path), '%s was not removed' % path) # let's run the command again (should spit warnings but succeed) cmd.all = 1 cmd.ensure_finalized() cmd.run() + def test_suite(): return unittest.makeSuite(cleanTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_cmd.py b/setuptools/_distutils/tests/test_cmd.py index cf5197c30fc..3ec49935251 100644 --- a/setuptools/_distutils/tests/test_cmd.py +++ b/setuptools/_distutils/tests/test_cmd.py @@ -8,12 +8,13 @@ from distutils.errors import DistutilsOptionError from distutils import debug + class MyCmd(Command): def initialize_options(self): pass -class CommandTestCase(unittest.TestCase): +class CommandTestCase(unittest.TestCase): def setUp(self): dist = Distribution() self.cmd = MyCmd(dist) @@ -28,11 +29,13 @@ def test_ensure_string_list(self): cmd.ensure_string_list('yes_string_list') cmd.ensure_string_list('yes_string_list2') - self.assertRaises(DistutilsOptionError, - cmd.ensure_string_list, 'not_string_list') + self.assertRaises( + DistutilsOptionError, cmd.ensure_string_list, 'not_string_list' + ) - self.assertRaises(DistutilsOptionError, - cmd.ensure_string_list, 'not_string_list2') + self.assertRaises( + DistutilsOptionError, cmd.ensure_string_list, 'not_string_list2' + ) cmd.option1 = 'ok,dok' cmd.ensure_string_list('option1') @@ -42,21 +45,21 @@ def test_ensure_string_list(self): cmd.ensure_string_list('option2') cmd.option3 = ['ok', 2] - self.assertRaises(DistutilsOptionError, cmd.ensure_string_list, - 'option3') - + self.assertRaises(DistutilsOptionError, cmd.ensure_string_list, 'option3') def test_make_file(self): cmd = self.cmd # making sure it raises when infiles is not a string or a list/tuple - self.assertRaises(TypeError, cmd.make_file, - infiles=1, outfile='', func='func', args=()) + self.assertRaises( + TypeError, cmd.make_file, infiles=1, outfile='', func='func', args=() + ) # making sure execute gets called properly def _execute(func, args, exec_msg, level): self.assertEqual(exec_msg, 'generating out from in') + cmd.force = True cmd.execute = _execute cmd.make_file(infiles='in', outfile='out', func='func', args=()) @@ -64,8 +67,10 @@ def _execute(func, args, exec_msg, level): def test_dump_options(self): msgs = [] + def _announce(msg, level): msgs.append(msg) + cmd = self.cmd cmd.announce = _announce cmd.option1 = 1 @@ -73,8 +78,7 @@ def _announce(msg, level): cmd.user_options = [('option1', '', ''), ('option2', '', '')] cmd.dump_options() - wanted = ["command options for 'MyCmd':", ' option1 = 1', - ' option2 = 1'] + wanted = ["command options for 'MyCmd':", ' option1 = 1', ' option2 = 1'] self.assertEqual(msgs, wanted) def test_ensure_string(self): @@ -119,8 +123,10 @@ def test_debug_print(self): finally: debug.DEBUG = False + def test_suite(): return unittest.makeSuite(CommandTestCase) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_config.py b/setuptools/_distutils/tests/test_config.py index 344084afb77..c341c4c92a6 100644 --- a/setuptools/_distutils/tests/test_config.py +++ b/setuptools/_distutils/tests/test_config.py @@ -50,11 +50,12 @@ """ -class BasePyPIRCCommandTestCase(support.TempdirManager, - support.LoggingSilencer, - support.EnvironGuard, - unittest.TestCase): - +class BasePyPIRCCommandTestCase( + support.TempdirManager, + support.LoggingSilencer, + support.EnvironGuard, + unittest.TestCase, +): def setUp(self): """Patches the environment.""" super(BasePyPIRCCommandTestCase, self).setUp() @@ -67,8 +68,10 @@ def setUp(self): class command(PyPIRCCommand): def __init__(self, dist): PyPIRCCommand.__init__(self, dist) + def initialize_options(self): pass + finalize_options = initialize_options self._cmd = command @@ -81,7 +84,6 @@ def tearDown(self): class PyPIRCCommandTestCase(BasePyPIRCCommandTestCase): - def test_server_registration(self): # This test makes sure PyPIRCCommand knows how to: # 1. handle several sections in .pypirc @@ -93,18 +95,26 @@ def test_server_registration(self): config = cmd._read_pypirc() config = list(sorted(config.items())) - waited = [('password', 'secret'), ('realm', 'pypi'), - ('repository', 'https://upload.pypi.org/legacy/'), - ('server', 'server1'), ('username', 'me')] + waited = [ + ('password', 'secret'), + ('realm', 'pypi'), + ('repository', 'https://upload.pypi.org/legacy/'), + ('server', 'server1'), + ('username', 'me'), + ] self.assertEqual(config, waited) # old format self.write_file(self.rc, PYPIRC_OLD) config = cmd._read_pypirc() config = list(sorted(config.items())) - waited = [('password', 'secret'), ('realm', 'pypi'), - ('repository', 'https://upload.pypi.org/legacy/'), - ('server', 'server-login'), ('username', 'tarek')] + waited = [ + ('password', 'secret'), + ('realm', 'pypi'), + ('repository', 'https://upload.pypi.org/legacy/'), + ('server', 'server-login'), + ('username', 'tarek'), + ] self.assertEqual(config, waited) def test_server_empty_registration(self): @@ -128,14 +138,19 @@ def test_config_interpolation(self): config = cmd._read_pypirc() config = list(sorted(config.items())) - waited = [('password', 'yh^%#rest-of-my-password'), ('realm', 'pypi'), - ('repository', 'https://upload.pypi.org/legacy/'), - ('server', 'server3'), ('username', 'cbiggles')] + waited = [ + ('password', 'yh^%#rest-of-my-password'), + ('realm', 'pypi'), + ('repository', 'https://upload.pypi.org/legacy/'), + ('server', 'server3'), + ('username', 'cbiggles'), + ] self.assertEqual(config, waited) def test_suite(): return unittest.makeSuite(PyPIRCCommandTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_config_cmd.py b/setuptools/_distutils/tests/test_config_cmd.py index 4cd9a6b9a0c..c5b3668ace3 100644 --- a/setuptools/_distutils/tests/test_config_cmd.py +++ b/setuptools/_distutils/tests/test_config_cmd.py @@ -10,10 +10,10 @@ from distutils.tests import support from distutils import log -class ConfigTestCase(support.LoggingSilencer, - support.TempdirManager, - unittest.TestCase): +class ConfigTestCase( + support.LoggingSilencer, support.TempdirManager, unittest.TestCase +): def _info(self, msg, *args): for line in msg.splitlines(): self._logs.append(line) @@ -37,7 +37,7 @@ def test_dump_file(self): f.close() dump_file(this_file, 'I am the header') - self.assertEqual(len(self._logs), numlines+1) + self.assertEqual(len(self._logs), numlines + 1) @unittest.skipIf(sys.platform == 'win32', "can't test on Windows") def test_search_cpp(self): @@ -49,7 +49,9 @@ def test_search_cpp(self): cmd._check_compiler() compiler = cmd.compiler if sys.platform[:3] == "aix" and "xlc" in compiler.preprocessor[0].lower(): - self.skipTest('xlc: The -E option overrides the -P, -o, and -qsyntaxonly options') + self.skipTest( + 'xlc: The -E option overrides the -P, -o, and -qsyntaxonly options' + ) # simple pattern searches match = cmd.search_cpp(pattern='xxx', body='/* xxx */') @@ -91,8 +93,10 @@ def test_clean(self): for f in (f1, f2): self.assertFalse(os.path.exists(f)) + def test_suite(): return unittest.makeSuite(ConfigTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_core.py b/setuptools/_distutils/tests/test_core.py index 666ff4a3cde..270d6ab4736 100644 --- a/setuptools/_distutils/tests/test_core.py +++ b/setuptools/_distutils/tests/test_core.py @@ -45,8 +45,8 @@ class install(_install): setup(cmdclass={'install': install}) """ -class CoreTestCase(support.EnvironGuard, unittest.TestCase): +class CoreTestCase(support.EnvironGuard, unittest.TestCase): def setUp(self): super(CoreTestCase, self).setUp() self.old_stdout = sys.stdout @@ -79,21 +79,18 @@ def write_setup(self, text, path=os_helper.TESTFN): def test_run_setup_provides_file(self): # Make sure the script can use __file__; if that's missing, the test # setup.py script will raise NameError. - distutils.core.run_setup( - self.write_setup(setup_using___file__)) + distutils.core.run_setup(self.write_setup(setup_using___file__)) def test_run_setup_preserves_sys_argv(self): # Make sure run_setup does not clobber sys.argv argv_copy = sys.argv.copy() - distutils.core.run_setup( - self.write_setup(setup_does_nothing)) + distutils.core.run_setup(self.write_setup(setup_does_nothing)) self.assertEqual(sys.argv, argv_copy) def test_run_setup_defines_subclass(self): # Make sure the script can use __file__; if that's missing, the test # setup.py script will raise NameError. - dist = distutils.core.run_setup( - self.write_setup(setup_defines_subclass)) + dist = distutils.core.run_setup(self.write_setup(setup_defines_subclass)) install = dist.get_command_obj('install') self.assertIn('cmd', install.sub_commands) @@ -107,8 +104,7 @@ def test_run_setup_uses_current_dir(self): # Create a directory and write the setup.py file there: os.mkdir(os_helper.TESTFN) setup_py = os.path.join(os_helper.TESTFN, "setup.py") - distutils.core.run_setup( - self.write_setup(setup_prints_cwd, path=setup_py)) + distutils.core.run_setup(self.write_setup(setup_prints_cwd, path=setup_py)) output = sys.stdout.getvalue() if output.endswith("\n"): @@ -133,8 +129,10 @@ def test_debug_mode(self): wanted = "options (after parsing config files):\n" self.assertEqual(stdout.readlines()[0], wanted) + def test_suite(): return unittest.makeSuite(CoreTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_cygwinccompiler.py b/setuptools/_distutils/tests/test_cygwinccompiler.py index 9dc869de4c8..4b5fe54dc6f 100644 --- a/setuptools/_distutils/tests/test_cygwinccompiler.py +++ b/setuptools/_distutils/tests/test_cygwinccompiler.py @@ -6,12 +6,17 @@ from test.support import run_unittest from distutils import cygwinccompiler -from distutils.cygwinccompiler import (check_config_h, - CONFIG_H_OK, CONFIG_H_NOTOK, - CONFIG_H_UNCERTAIN, get_versions, - get_msvcr) +from distutils.cygwinccompiler import ( + check_config_h, + CONFIG_H_OK, + CONFIG_H_NOTOK, + CONFIG_H_UNCERTAIN, + get_versions, + get_msvcr, +) from distutils.tests import support + class FakePopen(object): test_class = None @@ -25,14 +30,13 @@ def __init__(self, cmd, shell, stdout): self.stdout = os.popen(cmd, 'r') -class CygwinCCompilerTestCase(support.TempdirManager, - unittest.TestCase): - +class CygwinCCompilerTestCase(support.TempdirManager, unittest.TestCase): def setUp(self): super(CygwinCCompilerTestCase, self).setUp() self.version = sys.version self.python_h = os.path.join(self.mkdtemp(), 'python.h') from distutils import sysconfig + self.old_get_config_h_filename = sysconfig.get_config_h_filename sysconfig.get_config_h_filename = self._get_config_h_filename self.old_find_executable = cygwinccompiler.find_executable @@ -45,6 +49,7 @@ def setUp(self): def tearDown(self): sys.version = self.version from distutils import sysconfig + sysconfig.get_config_h_filename = self.old_get_config_h_filename cygwinccompiler.find_executable = self.old_find_executable cygwinccompiler.Popen = self.old_popen @@ -62,8 +67,10 @@ def test_check_config_h(self): # check_config_h looks for "GCC" in sys.version first # returns CONFIG_H_OK if found - sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) \n[GCC ' - '4.0.1 (Apple Computer, Inc. build 5370)]') + sys.version = ( + '2.6.1 (r261:67515, Dec 6 2008, 16:42:21) \n[GCC ' + '4.0.1 (Apple Computer, Inc. build 5370)]' + ) self.assertEqual(check_config_h()[0], CONFIG_H_OK) @@ -118,37 +125,46 @@ def test_get_versions(self): def test_get_msvcr(self): # none - sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) ' - '\n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]') + sys.version = ( + '2.6.1 (r261:67515, Dec 6 2008, 16:42:21) ' + '\n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]' + ) self.assertEqual(get_msvcr(), None) # MSVC 7.0 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1300 32 bits (Intel)]') + sys.version = ( + '2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' '[MSC v.1300 32 bits (Intel)]' + ) self.assertEqual(get_msvcr(), ['msvcr70']) # MSVC 7.1 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1310 32 bits (Intel)]') + sys.version = ( + '2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' '[MSC v.1310 32 bits (Intel)]' + ) self.assertEqual(get_msvcr(), ['msvcr71']) # VS2005 / MSVC 8.0 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1400 32 bits (Intel)]') + sys.version = ( + '2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' '[MSC v.1400 32 bits (Intel)]' + ) self.assertEqual(get_msvcr(), ['msvcr80']) # VS2008 / MSVC 9.0 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1500 32 bits (Intel)]') + sys.version = ( + '2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' '[MSC v.1500 32 bits (Intel)]' + ) self.assertEqual(get_msvcr(), ['msvcr90']) # unknown - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1999 32 bits (Intel)]') + sys.version = ( + '2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' '[MSC v.1999 32 bits (Intel)]' + ) self.assertRaises(ValueError, get_msvcr) + def test_suite(): return unittest.makeSuite(CygwinCCompilerTestCase) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_dep_util.py b/setuptools/_distutils/tests/test_dep_util.py index c6fae39cfb1..c89aa440ca2 100644 --- a/setuptools/_distutils/tests/test_dep_util.py +++ b/setuptools/_distutils/tests/test_dep_util.py @@ -7,8 +7,8 @@ from distutils.tests import support from test.support import run_unittest -class DepUtilTestCase(support.TempdirManager, unittest.TestCase): +class DepUtilTestCase(support.TempdirManager, unittest.TestCase): def test_newer(self): tmpdir = self.mkdtemp() @@ -36,14 +36,13 @@ def test_newer_pairwise(self): os.mkdir(targets) one = os.path.join(sources, 'one') two = os.path.join(sources, 'two') - three = os.path.abspath(__file__) # I am the old file + three = os.path.abspath(__file__) # I am the old file four = os.path.join(targets, 'four') self.write_file(one) self.write_file(two) self.write_file(four) - self.assertEqual(newer_pairwise([one, two], [three, four]), - ([one],[three])) + self.assertEqual(newer_pairwise([one, two], [three, four]), ([one], [three])) def test_newer_group(self): tmpdir = self.mkdtemp() @@ -66,15 +65,14 @@ def test_newer_group(self): os.remove(one) self.assertRaises(OSError, newer_group, [one, two, old_file], three) - self.assertFalse(newer_group([one, two, old_file], three, - missing='ignore')) + self.assertFalse(newer_group([one, two, old_file], three, missing='ignore')) - self.assertTrue(newer_group([one, two, old_file], three, - missing='newer')) + self.assertTrue(newer_group([one, two, old_file], three, missing='newer')) def test_suite(): return unittest.makeSuite(DepUtilTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_dir_util.py b/setuptools/_distutils/tests/test_dir_util.py index d436cf83191..7f06b01c09f 100644 --- a/setuptools/_distutils/tests/test_dir_util.py +++ b/setuptools/_distutils/tests/test_dir_util.py @@ -6,8 +6,13 @@ from unittest.mock import patch from distutils import dir_util, errors -from distutils.dir_util import (mkpath, remove_tree, create_tree, copy_tree, - ensure_relative) +from distutils.dir_util import ( + mkpath, + remove_tree, + create_tree, + copy_tree, + ensure_relative, +) from distutils import log from distutils.tests import support @@ -15,7 +20,6 @@ class DirUtilTestCase(support.TempdirManager, unittest.TestCase): - def _log(self, msg, *args): if len(args) > 0: self._logs.append(msg % args) @@ -44,8 +48,7 @@ def test_mkpath_remove_tree_verbosity(self): remove_tree(self.root_target, verbose=0) mkpath(self.target, verbose=1) - wanted = ['creating %s' % self.root_target, - 'creating %s' % self.target] + wanted = ['creating %s' % self.root_target, 'creating %s' % self.target] self.assertEqual(self._logs, wanted) self._logs = [] @@ -53,18 +56,18 @@ def test_mkpath_remove_tree_verbosity(self): wanted = ["removing '%s' (and everything under it)" % self.root_target] self.assertEqual(self._logs, wanted) - @unittest.skipIf(sys.platform.startswith('win'), - "This test is only appropriate for POSIX-like systems.") + @unittest.skipIf( + sys.platform.startswith('win'), + "This test is only appropriate for POSIX-like systems.", + ) def test_mkpath_with_custom_mode(self): # Get and set the current umask value for testing mode bits. umask = os.umask(0o002) os.umask(umask) mkpath(self.target, 0o700) - self.assertEqual( - stat.S_IMODE(os.stat(self.target).st_mode), 0o700 & ~umask) + self.assertEqual(stat.S_IMODE(os.stat(self.target).st_mode), 0o700 & ~umask) mkpath(self.target2, 0o555) - self.assertEqual( - stat.S_IMODE(os.stat(self.target2).st_mode), 0o555 & ~umask) + self.assertEqual(stat.S_IMODE(os.stat(self.target2).st_mode), 0o555 & ~umask) def test_create_tree_verbosity(self): @@ -118,7 +121,7 @@ def test_ensure_relative(self): if os.sep == '/': self.assertEqual(ensure_relative('/home/foo'), 'home/foo') self.assertEqual(ensure_relative('some/path'), 'some/path') - else: # \\ + else: # \\ self.assertEqual(ensure_relative('c:\\home\\foo'), 'c:home\\foo') self.assertEqual(ensure_relative('home\\foo'), 'home\\foo') @@ -126,8 +129,9 @@ def test_copy_tree_exception_in_listdir(self): """ An exception in listdir should raise a DistutilsFileError """ - with patch("os.listdir", side_effect=OSError()), \ - self.assertRaises(errors.DistutilsFileError): + with patch("os.listdir", side_effect=OSError()), self.assertRaises( + errors.DistutilsFileError + ): src = self.tempdirs[-1] dir_util.copy_tree(src, None) @@ -135,5 +139,6 @@ def test_copy_tree_exception_in_listdir(self): def test_suite(): return unittest.makeSuite(DirUtilTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_dist.py b/setuptools/_distutils/tests/test_dist.py index 45eadee87fd..15cdeeaa730 100644 --- a/setuptools/_distutils/tests/test_dist.py +++ b/setuptools/_distutils/tests/test_dist.py @@ -11,9 +11,7 @@ from distutils.dist import Distribution, fix_help_options from distutils.cmd import Command -from test.support import ( - captured_stdout, captured_stderr, run_unittest -) +from test.support import captured_stdout, captured_stderr, run_unittest from .py38compat import TESTFN from distutils.tests import support from distutils import log @@ -42,11 +40,12 @@ def find_config_files(self): return self._config_files -class DistributionTestCase(support.LoggingSilencer, - support.TempdirManager, - support.EnvironGuard, - unittest.TestCase): - +class DistributionTestCase( + support.LoggingSilencer, + support.TempdirManager, + support.EnvironGuard, + unittest.TestCase, +): def setUp(self): super(DistributionTestCase, self).setUp() self.argv = sys.argv, sys.argv[:] @@ -71,15 +70,21 @@ def test_command_packages_unspecified(self): def test_command_packages_cmdline(self): from distutils.tests.test_dist import test_dist - sys.argv.extend(["--command-packages", - "foo.bar,distutils.tests", - "test_dist", - "-Ssometext", - ]) + + sys.argv.extend( + [ + "--command-packages", + "foo.bar,distutils.tests", + "test_dist", + "-Ssometext", + ] + ) d = self.create_distribution() # let's actually try to load our test command: - self.assertEqual(d.get_command_packages(), - ["distutils.command", "foo.bar", "distutils.tests"]) + self.assertEqual( + d.get_command_packages(), + ["distutils.command", "foo.bar", "distutils.tests"], + ) cmd = d.get_command_obj("test_dist") self.assertIsInstance(cmd, test_dist) self.assertEqual(cmd.sample_option, "sometext") @@ -95,20 +100,25 @@ def test_venv_install_options(self): fakepath = '/somedir' with open(TESTFN, "w") as f: - print(("[install]\n" - "install-base = {0}\n" - "install-platbase = {0}\n" - "install-lib = {0}\n" - "install-platlib = {0}\n" - "install-purelib = {0}\n" - "install-headers = {0}\n" - "install-scripts = {0}\n" - "install-data = {0}\n" - "prefix = {0}\n" - "exec-prefix = {0}\n" - "home = {0}\n" - "user = {0}\n" - "root = {0}").format(fakepath), file=f) + print( + ( + "[install]\n" + "install-base = {0}\n" + "install-platbase = {0}\n" + "install-lib = {0}\n" + "install-platlib = {0}\n" + "install-purelib = {0}\n" + "install-headers = {0}\n" + "install-scripts = {0}\n" + "install-data = {0}\n" + "prefix = {0}\n" + "exec-prefix = {0}\n" + "home = {0}\n" + "user = {0}\n" + "root = {0}" + ).format(fakepath), + file=f, + ) # Base case: Not in a Virtual Environment with mock.patch.multiple(sys, prefix='/a', base_prefix='/a') as values: @@ -133,8 +143,8 @@ def test_venv_install_options(self): } self.assertEqual( - sorted(d.command_options.get('install').keys()), - sorted(result_dict.keys())) + sorted(d.command_options.get('install').keys()), sorted(result_dict.keys()) + ) for (key, value) in d.command_options.get('install').items(): self.assertEqual(value, result_dict[key]) @@ -157,14 +167,14 @@ def test_command_packages_configfile(self): f.close() d = self.create_distribution([TESTFN]) - self.assertEqual(d.get_command_packages(), - ["distutils.command", "foo.bar", "splat"]) + self.assertEqual( + d.get_command_packages(), ["distutils.command", "foo.bar", "splat"] + ) # ensure command line overrides config: sys.argv[1:] = ["--command-packages", "spork", "build"] d = self.create_distribution([TESTFN]) - self.assertEqual(d.get_command_packages(), - ["distutils.command", "spork"]) + self.assertEqual(d.get_command_packages(), ["distutils.command", "spork"]) # Setting --command-packages to '' should cause the default to # be used even if a config file specified something else: @@ -184,16 +194,21 @@ def _warn(msg): self.addCleanup(setattr, warnings, 'warn', warnings.warn) warnings.warn = _warn - dist = Distribution(attrs={'author': 'xxx', 'name': 'xxx', - 'version': 'xxx', 'url': 'xxxx', - 'options': {}}) + dist = Distribution( + attrs={ + 'author': 'xxx', + 'name': 'xxx', + 'version': 'xxx', + 'url': 'xxxx', + 'options': {}, + } + ) self.assertEqual(len(warns), 0) self.assertNotIn('options', dir(dist)) def test_finalize_options(self): - attrs = {'keywords': 'one,two', - 'platforms': 'one,two'} + attrs = {'keywords': 'one,two', 'platforms': 'one,two'} dist = Distribution(attrs=attrs) dist.finalize_options() @@ -202,8 +217,7 @@ def test_finalize_options(self): self.assertEqual(dist.metadata.platforms, ['one', 'two']) self.assertEqual(dist.metadata.keywords, ['one', 'two']) - attrs = {'keywords': 'foo bar', - 'platforms': 'foo bar'} + attrs = {'keywords': 'foo bar', 'platforms': 'foo bar'} dist = Distribution(attrs=attrs) dist.finalize_options() self.assertEqual(dist.metadata.platforms, ['foo bar']) @@ -214,8 +228,7 @@ def test_get_command_packages(self): self.assertEqual(dist.command_packages, None) cmds = dist.get_command_packages() self.assertEqual(cmds, ['distutils.command']) - self.assertEqual(dist.command_packages, - ['distutils.command']) + self.assertEqual(dist.command_packages, ['distutils.command']) dist.command_packages = 'one,two' cmds = dist.get_command_packages() @@ -228,7 +241,6 @@ def test_announce(self): kwargs = {'level': 'ok2'} self.assertRaises(ValueError, dist.announce, args, kwargs) - def test_find_config_files_disable(self): # Ticket #1180: Allow user to disable their home config file. temp_home = self.mkdtemp() @@ -255,11 +267,10 @@ def _expander(path): os.path.expanduser = old_expander # make sure --no-user-cfg disables the user cfg file - self.assertEqual(len(all_files)-1, len(files)) + self.assertEqual(len(all_files) - 1, len(files)) -class MetadataTestCase(support.TempdirManager, support.EnvironGuard, - unittest.TestCase): +class MetadataTestCase(support.TempdirManager, support.EnvironGuard, unittest.TestCase): def setUp(self): super(MetadataTestCase, self).setUp() self.argv = sys.argv, sys.argv[:] @@ -275,8 +286,7 @@ def format_metadata(self, dist): return sio.getvalue() def test_simple_metadata(self): - attrs = {"name": "package", - "version": "1.0"} + attrs = {"name": "package", "version": "1.0"} dist = Distribution(attrs) meta = self.format_metadata(dist) self.assertIn("Metadata-Version: 1.0", meta) @@ -285,34 +295,35 @@ def test_simple_metadata(self): self.assertNotIn("obsoletes:", meta.lower()) def test_provides(self): - attrs = {"name": "package", - "version": "1.0", - "provides": ["package", "package.sub"]} + attrs = { + "name": "package", + "version": "1.0", + "provides": ["package", "package.sub"], + } dist = Distribution(attrs) - self.assertEqual(dist.metadata.get_provides(), - ["package", "package.sub"]) - self.assertEqual(dist.get_provides(), - ["package", "package.sub"]) + self.assertEqual(dist.metadata.get_provides(), ["package", "package.sub"]) + self.assertEqual(dist.get_provides(), ["package", "package.sub"]) meta = self.format_metadata(dist) self.assertIn("Metadata-Version: 1.1", meta) self.assertNotIn("requires:", meta.lower()) self.assertNotIn("obsoletes:", meta.lower()) def test_provides_illegal(self): - self.assertRaises(ValueError, Distribution, - {"name": "package", - "version": "1.0", - "provides": ["my.pkg (splat)"]}) + self.assertRaises( + ValueError, + Distribution, + {"name": "package", "version": "1.0", "provides": ["my.pkg (splat)"]}, + ) def test_requires(self): - attrs = {"name": "package", - "version": "1.0", - "requires": ["other", "another (==1.0)"]} + attrs = { + "name": "package", + "version": "1.0", + "requires": ["other", "another (==1.0)"], + } dist = Distribution(attrs) - self.assertEqual(dist.metadata.get_requires(), - ["other", "another (==1.0)"]) - self.assertEqual(dist.get_requires(), - ["other", "another (==1.0)"]) + self.assertEqual(dist.metadata.get_requires(), ["other", "another (==1.0)"]) + self.assertEqual(dist.get_requires(), ["other", "another (==1.0)"]) meta = self.format_metadata(dist) self.assertIn("Metadata-Version: 1.1", meta) self.assertNotIn("provides:", meta.lower()) @@ -321,27 +332,26 @@ def test_requires(self): self.assertNotIn("obsoletes:", meta.lower()) def test_requires_illegal(self): - self.assertRaises(ValueError, Distribution, - {"name": "package", - "version": "1.0", - "requires": ["my.pkg (splat)"]}) + self.assertRaises( + ValueError, + Distribution, + {"name": "package", "version": "1.0", "requires": ["my.pkg (splat)"]}, + ) def test_requires_to_list(self): - attrs = {"name": "package", - "requires": iter(["other"])} + attrs = {"name": "package", "requires": iter(["other"])} dist = Distribution(attrs) self.assertIsInstance(dist.metadata.requires, list) - def test_obsoletes(self): - attrs = {"name": "package", - "version": "1.0", - "obsoletes": ["other", "another (<1.0)"]} + attrs = { + "name": "package", + "version": "1.0", + "obsoletes": ["other", "another (<1.0)"], + } dist = Distribution(attrs) - self.assertEqual(dist.metadata.get_obsoletes(), - ["other", "another (<1.0)"]) - self.assertEqual(dist.get_obsoletes(), - ["other", "another (<1.0)"]) + self.assertEqual(dist.metadata.get_obsoletes(), ["other", "another (<1.0)"]) + self.assertEqual(dist.get_obsoletes(), ["other", "another (<1.0)"]) meta = self.format_metadata(dist) self.assertIn("Metadata-Version: 1.1", meta) self.assertNotIn("provides:", meta.lower()) @@ -350,48 +360,59 @@ def test_obsoletes(self): self.assertIn("Obsoletes: another (<1.0)", meta) def test_obsoletes_illegal(self): - self.assertRaises(ValueError, Distribution, - {"name": "package", - "version": "1.0", - "obsoletes": ["my.pkg (splat)"]}) + self.assertRaises( + ValueError, + Distribution, + {"name": "package", "version": "1.0", "obsoletes": ["my.pkg (splat)"]}, + ) def test_obsoletes_to_list(self): - attrs = {"name": "package", - "obsoletes": iter(["other"])} + attrs = {"name": "package", "obsoletes": iter(["other"])} dist = Distribution(attrs) self.assertIsInstance(dist.metadata.obsoletes, list) def test_classifier(self): - attrs = {'name': 'Boa', 'version': '3.0', - 'classifiers': ['Programming Language :: Python :: 3']} + attrs = { + 'name': 'Boa', + 'version': '3.0', + 'classifiers': ['Programming Language :: Python :: 3'], + } dist = Distribution(attrs) - self.assertEqual(dist.get_classifiers(), - ['Programming Language :: Python :: 3']) + self.assertEqual( + dist.get_classifiers(), ['Programming Language :: Python :: 3'] + ) meta = self.format_metadata(dist) self.assertIn('Metadata-Version: 1.1', meta) def test_classifier_invalid_type(self): - attrs = {'name': 'Boa', 'version': '3.0', - 'classifiers': ('Programming Language :: Python :: 3',)} + attrs = { + 'name': 'Boa', + 'version': '3.0', + 'classifiers': ('Programming Language :: Python :: 3',), + } with captured_stderr() as error: d = Distribution(attrs) # should have warning about passing a non-list self.assertIn('should be a list', error.getvalue()) # should be converted to a list self.assertIsInstance(d.metadata.classifiers, list) - self.assertEqual(d.metadata.classifiers, - list(attrs['classifiers'])) + self.assertEqual(d.metadata.classifiers, list(attrs['classifiers'])) def test_keywords(self): - attrs = {'name': 'Monty', 'version': '1.0', - 'keywords': ['spam', 'eggs', 'life of brian']} + attrs = { + 'name': 'Monty', + 'version': '1.0', + 'keywords': ['spam', 'eggs', 'life of brian'], + } dist = Distribution(attrs) - self.assertEqual(dist.get_keywords(), - ['spam', 'eggs', 'life of brian']) + self.assertEqual(dist.get_keywords(), ['spam', 'eggs', 'life of brian']) def test_keywords_invalid_type(self): - attrs = {'name': 'Monty', 'version': '1.0', - 'keywords': ('spam', 'eggs', 'life of brian')} + attrs = { + 'name': 'Monty', + 'version': '1.0', + 'keywords': ('spam', 'eggs', 'life of brian'), + } with captured_stderr() as error: d = Distribution(attrs) # should have warning about passing a non-list @@ -401,15 +422,20 @@ def test_keywords_invalid_type(self): self.assertEqual(d.metadata.keywords, list(attrs['keywords'])) def test_platforms(self): - attrs = {'name': 'Monty', 'version': '1.0', - 'platforms': ['GNU/Linux', 'Some Evil Platform']} + attrs = { + 'name': 'Monty', + 'version': '1.0', + 'platforms': ['GNU/Linux', 'Some Evil Platform'], + } dist = Distribution(attrs) - self.assertEqual(dist.get_platforms(), - ['GNU/Linux', 'Some Evil Platform']) + self.assertEqual(dist.get_platforms(), ['GNU/Linux', 'Some Evil Platform']) def test_platforms_invalid_types(self): - attrs = {'name': 'Monty', 'version': '1.0', - 'platforms': ('GNU/Linux', 'Some Evil Platform')} + attrs = { + 'name': 'Monty', + 'version': '1.0', + 'platforms': ('GNU/Linux', 'Some Evil Platform'), + } with captured_stderr() as error: d = Distribution(attrs) # should have warning about passing a non-list @@ -419,21 +445,24 @@ def test_platforms_invalid_types(self): self.assertEqual(d.metadata.platforms, list(attrs['platforms'])) def test_download_url(self): - attrs = {'name': 'Boa', 'version': '3.0', - 'download_url': 'http://example.org/boa'} + attrs = { + 'name': 'Boa', + 'version': '3.0', + 'download_url': 'http://example.org/boa', + } dist = Distribution(attrs) meta = self.format_metadata(dist) self.assertIn('Metadata-Version: 1.1', meta) def test_long_description(self): - long_desc = textwrap.dedent("""\ + long_desc = textwrap.dedent( + """\ example:: We start here and continue here - and end here.""") - attrs = {"name": "package", - "version": "1.0", - "long_description": long_desc} + and end here.""" + ) + attrs = {"name": "package", "version": "1.0", "long_description": long_desc} dist = Distribution(attrs) meta = self.format_metadata(dist) @@ -470,8 +499,9 @@ def test_custom_pydistutils(self): # home drive should be found os.environ['USERPROFILE'] = temp_dir files = dist.find_config_files() - self.assertIn(user_filename, files, - '%r not found in %r' % (user_filename, files)) + self.assertIn( + user_filename, files, '%r not found in %r' % (user_filename, files) + ) finally: os.remove(user_filename) @@ -491,19 +521,19 @@ def test_show_help(self): with captured_stdout() as s: dist.parse_command_line() - output = [line for line in s.getvalue().split('\n') - if line.strip() != ''] + output = [line for line in s.getvalue().split('\n') if line.strip() != ''] self.assertTrue(output) - def test_read_metadata(self): - attrs = {"name": "package", - "version": "1.0", - "long_description": "desc", - "description": "xxx", - "download_url": "http://example.com", - "keywords": ['one', 'two'], - "requires": ['foo']} + attrs = { + "name": "package", + "version": "1.0", + "long_description": "desc", + "description": "xxx", + "download_url": "http://example.com", + "keywords": ['one', 'two'], + "requires": ['foo'], + } dist = Distribution(attrs) metadata = dist.metadata @@ -523,11 +553,13 @@ def test_read_metadata(self): self.assertEqual(metadata.obsoletes, None) self.assertEqual(metadata.requires, ['foo']) + def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(DistributionTestCase)) suite.addTest(unittest.makeSuite(MetadataTestCase)) return suite + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_extension.py b/setuptools/_distutils/tests/test_extension.py index 2eb5b422df5..34c8b5fec91 100644 --- a/setuptools/_distutils/tests/test_extension.py +++ b/setuptools/_distutils/tests/test_extension.py @@ -8,8 +8,8 @@ from .py38compat import check_warnings -class ExtensionTestCase(unittest.TestCase): +class ExtensionTestCase(unittest.TestCase): def test_read_setup_file(self): # trying to read a Setup file # (sample extracted from the PyGame project) @@ -21,14 +21,42 @@ def test_read_setup_file(self): # here are the extensions read_setup_file should have created # out of the file - wanted = ['_arraysurfarray', '_camera', '_numericsndarray', - '_numericsurfarray', 'base', 'bufferproxy', 'cdrom', - 'color', 'constants', 'display', 'draw', 'event', - 'fastevent', 'font', 'gfxdraw', 'image', 'imageext', - 'joystick', 'key', 'mask', 'mixer', 'mixer_music', - 'mouse', 'movie', 'overlay', 'pixelarray', 'pypm', - 'rect', 'rwobject', 'scrap', 'surface', 'surflock', - 'time', 'transform'] + wanted = [ + '_arraysurfarray', + '_camera', + '_numericsndarray', + '_numericsurfarray', + 'base', + 'bufferproxy', + 'cdrom', + 'color', + 'constants', + 'display', + 'draw', + 'event', + 'fastevent', + 'font', + 'gfxdraw', + 'image', + 'imageext', + 'joystick', + 'key', + 'mask', + 'mixer', + 'mixer_music', + 'mouse', + 'movie', + 'overlay', + 'pixelarray', + 'pypm', + 'rect', + 'rwobject', + 'scrap', + 'surface', + 'surflock', + 'time', + 'transform', + ] self.assertEqual(names, wanted) @@ -46,10 +74,20 @@ def test_extension_init(self): self.assertEqual(ext.sources, ['file1', 'file2']) # others arguments have defaults - for attr in ('include_dirs', 'define_macros', 'undef_macros', - 'library_dirs', 'libraries', 'runtime_library_dirs', - 'extra_objects', 'extra_compile_args', 'extra_link_args', - 'export_symbols', 'swig_opts', 'depends'): + for attr in ( + 'include_dirs', + 'define_macros', + 'undef_macros', + 'library_dirs', + 'libraries', + 'runtime_library_dirs', + 'extra_objects', + 'extra_compile_args', + 'extra_link_args', + 'export_symbols', + 'swig_opts', + 'depends', + ): self.assertEqual(getattr(ext, attr), []) self.assertEqual(ext.language, None) @@ -61,11 +99,14 @@ def test_extension_init(self): ext = Extension('name', ['file1', 'file2'], chic=True) self.assertEqual(len(w.warnings), 1) - self.assertEqual(str(w.warnings[0].message), - "Unknown Extension options: 'chic'") + self.assertEqual( + str(w.warnings[0].message), "Unknown Extension options: 'chic'" + ) + def test_suite(): return unittest.makeSuite(ExtensionTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_file_util.py b/setuptools/_distutils/tests/test_file_util.py index d2536075264..5f5b7aeee52 100644 --- a/setuptools/_distutils/tests/test_file_util.py +++ b/setuptools/_distutils/tests/test_file_util.py @@ -13,7 +13,6 @@ class FileUtilTestCase(support.TempdirManager, unittest.TestCase): - def _log(self, msg, *args): if len(args) > 0: self._logs.append(msg % args) @@ -64,17 +63,18 @@ def test_move_file_verbosity(self): def test_move_file_exception_unpacking_rename(self): # see issue 22182 - with patch("os.rename", side_effect=OSError("wrong", 1)), \ - self.assertRaises(DistutilsFileError): + with patch("os.rename", side_effect=OSError("wrong", 1)), self.assertRaises( + DistutilsFileError + ): with open(self.source, 'w') as fobj: fobj.write('spam eggs') move_file(self.source, self.target, verbose=0) def test_move_file_exception_unpacking_unlink(self): # see issue 22182 - with patch("os.rename", side_effect=OSError(errno.EXDEV, "wrong")), \ - patch("os.unlink", side_effect=OSError("wrong", 1)), \ - self.assertRaises(DistutilsFileError): + with patch("os.rename", side_effect=OSError(errno.EXDEV, "wrong")), patch( + "os.unlink", side_effect=OSError("wrong", 1) + ), self.assertRaises(DistutilsFileError): with open(self.source, 'w') as fobj: fobj.write('spam eggs') move_file(self.source, self.target, verbose=0) @@ -120,5 +120,6 @@ def test_copy_file_hard_link_failure(self): def test_suite(): return unittest.makeSuite(FileUtilTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_filelist.py b/setuptools/_distutils/tests/test_filelist.py index 9ec507b5d0b..2d4d19dfe26 100644 --- a/setuptools/_distutils/tests/test_filelist.py +++ b/setuptools/_distutils/tests/test_filelist.py @@ -36,9 +36,7 @@ def make_local_path(s): return s.replace('/', os.sep) -class FileListTestCase(support.LoggingSilencer, - unittest.TestCase): - +class FileListTestCase(support.LoggingSilencer, unittest.TestCase): def assertNoWarnings(self): self.assertEqual(self.get_logs(WARN), []) self.clear_logs() @@ -61,7 +59,8 @@ def test_glob_to_re(self): (r'foo\\*', r'(?s:foo\\\\[^%(sep)s]*)\Z'), (r'foo\\\*', r'(?s:foo\\\\\\[^%(sep)s]*)\Z'), ('foo????', r'(?s:foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s])\Z'), - (r'foo\\??', r'(?s:foo\\\\[^%(sep)s][^%(sep)s])\Z')): + (r'foo\\??', r'(?s:foo\\\\[^%(sep)s][^%(sep)s])\Z'), + ): regex = regex % {'sep': sep} self.assertEqual(glob_to_re(glob), adapt_glob(regex)) @@ -71,37 +70,42 @@ def test_process_template_line(self): l = make_local_path # simulated file list - file_list.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt', - 'buildout.cfg', - # filelist does not filter out VCS directories, - # it's sdist that does - l('.hg/last-message.txt'), - l('global/one.txt'), - l('global/two.txt'), - l('global/files.x'), - l('global/here.tmp'), - l('f/o/f.oo'), - l('dir/graft-one'), - l('dir/dir2/graft2'), - l('dir3/ok'), - l('dir3/sub/ok.txt'), - ] + file_list.allfiles = [ + 'foo.tmp', + 'ok', + 'xo', + 'four.txt', + 'buildout.cfg', + # filelist does not filter out VCS directories, + # it's sdist that does + l('.hg/last-message.txt'), + l('global/one.txt'), + l('global/two.txt'), + l('global/files.x'), + l('global/here.tmp'), + l('f/o/f.oo'), + l('dir/graft-one'), + l('dir/dir2/graft2'), + l('dir3/ok'), + l('dir3/sub/ok.txt'), + ] for line in MANIFEST_IN.split('\n'): if line.strip() == '': continue file_list.process_template_line(line) - wanted = ['ok', - 'buildout.cfg', - 'four.txt', - l('.hg/last-message.txt'), - l('global/one.txt'), - l('global/two.txt'), - l('f/o/f.oo'), - l('dir/graft-one'), - l('dir/dir2/graft2'), - ] + wanted = [ + 'ok', + 'buildout.cfg', + 'four.txt', + l('.hg/last-message.txt'), + l('global/one.txt'), + l('global/two.txt'), + l('f/o/f.oo'), + l('dir/graft-one'), + l('dir/dir2/graft2'), + ] self.assertEqual(file_list.files, wanted) @@ -135,24 +139,23 @@ def test_remove_duplicates(self): def test_translate_pattern(self): # not regex - self.assertTrue(hasattr( - translate_pattern('a', anchor=True, is_regex=False), - 'search')) + self.assertTrue( + hasattr(translate_pattern('a', anchor=True, is_regex=False), 'search') + ) # is a regex regex = re.compile('a') - self.assertEqual( - translate_pattern(regex, anchor=True, is_regex=True), - regex) + self.assertEqual(translate_pattern(regex, anchor=True, is_regex=True), regex) # plain string flagged as regex - self.assertTrue(hasattr( - translate_pattern('a', anchor=True, is_regex=True), - 'search')) + self.assertTrue( + hasattr(translate_pattern('a', anchor=True, is_regex=True), 'search') + ) # glob support - self.assertTrue(translate_pattern( - '*.py', anchor=True, is_regex=False).search('filelist.py')) + self.assertTrue( + translate_pattern('*.py', anchor=True, is_regex=False).search('filelist.py') + ) def test_exclude_pattern(self): # return False if no match @@ -192,11 +195,20 @@ def test_process_template(self): l = make_local_path # invalid lines file_list = FileList() - for action in ('include', 'exclude', 'global-include', - 'global-exclude', 'recursive-include', - 'recursive-exclude', 'graft', 'prune', 'blarg'): - self.assertRaises(DistutilsTemplateError, - file_list.process_template_line, action) + for action in ( + 'include', + 'exclude', + 'global-include', + 'global-exclude', + 'recursive-include', + 'recursive-exclude', + 'graft', + 'prune', + 'blarg', + ): + self.assertRaises( + DistutilsTemplateError, file_list.process_template_line, action + ) # include file_list = FileList() @@ -248,8 +260,7 @@ def test_process_template(self): # recursive-include file_list = FileList() - file_list.set_allfiles(['a.py', l('d/b.py'), l('d/c.txt'), - l('d/d/e.py')]) + file_list.set_allfiles(['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]) file_list.process_template_line('recursive-include d *.py') self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')]) @@ -273,8 +284,7 @@ def test_process_template(self): # graft file_list = FileList() - file_list.set_allfiles(['a.py', l('d/b.py'), l('d/d/e.py'), - l('f/f.py')]) + file_list.set_allfiles(['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]) file_list.process_template_line('graft d') self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')]) @@ -343,10 +353,12 @@ def test_symlink_loop(self): def test_suite(): - return unittest.TestSuite([ - unittest.makeSuite(FileListTestCase), - unittest.makeSuite(FindAllTestCase), - ]) + return unittest.TestSuite( + [ + unittest.makeSuite(FileListTestCase), + unittest.makeSuite(FindAllTestCase), + ] + ) if __name__ == "__main__": diff --git a/setuptools/_distutils/tests/test_install.py b/setuptools/_distutils/tests/test_install.py index eb684a09e6e..8fe2d728b70 100644 --- a/setuptools/_distutils/tests/test_install.py +++ b/setuptools/_distutils/tests/test_install.py @@ -24,11 +24,12 @@ def _make_ext_name(modname): return modname + sysconfig.get_config_var('EXT_SUFFIX') -class InstallTestCase(support.TempdirManager, - support.EnvironGuard, - support.LoggingSilencer, - unittest.TestCase): - +class InstallTestCase( + support.TempdirManager, + support.EnvironGuard, + support.LoggingSilencer, + unittest.TestCase, +): def test_home_installation_scheme(self): # This ensure two things: # - that --home generates the desired set of directory names @@ -42,7 +43,7 @@ def test_home_installation_scheme(self): dist.command_obj["build"] = support.DummyCommand( build_base=builddir, build_lib=os.path.join(builddir, "lib"), - ) + ) cmd = install(dist) cmd.home = destination @@ -62,8 +63,10 @@ def check_path(got, expected): platlibdir = os.path.join(destination, _platlibdir, "python") check_path(cmd.install_platlib, platlibdir) check_path(cmd.install_purelib, libdir) - check_path(cmd.install_headers, - os.path.join(destination, "include", "python", "foopkg")) + check_path( + cmd.install_headers, + os.path.join(destination, "include", "python", "foopkg"), + ) check_path(cmd.install_scripts, os.path.join(destination, "bin")) check_path(cmd.install_data, destination) @@ -82,6 +85,7 @@ def test_user_site(self): def _expanduser(path): return self.tmpdir + self.old_expand = os.path.expanduser os.path.expanduser = _expanduser @@ -101,8 +105,7 @@ def cleanup(): cmd = install(dist) # making sure the user option is there - options = [name for name, short, lable in - cmd.user_options] + options = [name for name, short, lable in cmd.user_options] self.assertIn('user', options) # setting a value @@ -173,8 +176,7 @@ def test_finalize_options(self): def test_record(self): install_dir = self.mkdtemp() - project_dir, dist = self.create_dist(py_modules=['hello'], - scripts=['sayhi']) + project_dir, dist = self.create_dist(py_modules=['hello'], scripts=['sayhi']) os.chdir(project_dir) self.write_file('hello.py', "def main(): print('o hai')") self.write_file('sayhi', 'from hello import main; main()') @@ -193,9 +195,12 @@ def test_record(self): f.close() found = [os.path.basename(line) for line in content.splitlines()] - expected = ['hello.py', 'hello.%s.pyc' % sys.implementation.cache_tag, - 'sayhi', - 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] + expected = [ + 'hello.py', + 'hello.%s.pyc' % sys.implementation.cache_tag, + 'sayhi', + 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2], + ] self.assertEqual(found, expected) def test_record_extensions(self): @@ -203,8 +208,9 @@ def test_record_extensions(self): if cmd is not None: self.skipTest('The %r command is not found' % cmd) install_dir = self.mkdtemp() - project_dir, dist = self.create_dist(ext_modules=[ - Extension('xx', ['xxmodule.c'])]) + project_dir, dist = self.create_dist( + ext_modules=[Extension('xx', ['xxmodule.c'])] + ) os.chdir(project_dir) support.copy_xxmodule_c(project_dir) @@ -227,8 +233,10 @@ def test_record_extensions(self): f.close() found = [os.path.basename(line) for line in content.splitlines()] - expected = [_make_ext_name('xx'), - 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] + expected = [ + _make_ext_name('xx'), + 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2], + ] self.assertEqual(found, expected) def test_debug_mode(self): @@ -246,5 +254,6 @@ def test_debug_mode(self): def test_suite(): return unittest.makeSuite(InstallTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_install_data.py b/setuptools/_distutils/tests/test_install_data.py index 32ab296a320..8f53143d9eb 100644 --- a/setuptools/_distutils/tests/test_install_data.py +++ b/setuptools/_distutils/tests/test_install_data.py @@ -6,11 +6,13 @@ from distutils.tests import support from test.support import run_unittest -class InstallDataTestCase(support.TempdirManager, - support.LoggingSilencer, - support.EnvironGuard, - unittest.TestCase): +class InstallDataTestCase( + support.TempdirManager, + support.LoggingSilencer, + support.EnvironGuard, + unittest.TestCase, +): def test_simple_run(self): pkg_dir, dist = self.create_dist() cmd = install_data(dist) @@ -57,9 +59,7 @@ def test_simple_run(self): inst4 = os.path.join(pkg_dir, 'inst4') three = os.path.join(cmd.install_dir, 'three') self.write_file(three, 'xx') - cmd.data_files = [one, (inst2, [two]), - ('inst3', [three]), - (inst4, [])] + cmd.data_files = [one, (inst2, [two]), ('inst3', [three]), (inst4, [])] cmd.ensure_finalized() cmd.run() @@ -68,8 +68,10 @@ def test_simple_run(self): self.assertTrue(os.path.exists(os.path.join(inst2, rtwo))) self.assertTrue(os.path.exists(os.path.join(inst, rone))) + def test_suite(): return unittest.makeSuite(InstallDataTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_install_headers.py b/setuptools/_distutils/tests/test_install_headers.py index 2217b321e6e..ba02d1bccd2 100644 --- a/setuptools/_distutils/tests/test_install_headers.py +++ b/setuptools/_distutils/tests/test_install_headers.py @@ -6,11 +6,13 @@ from distutils.tests import support from test.support import run_unittest -class InstallHeadersTestCase(support.TempdirManager, - support.LoggingSilencer, - support.EnvironGuard, - unittest.TestCase): +class InstallHeadersTestCase( + support.TempdirManager, + support.LoggingSilencer, + support.EnvironGuard, + unittest.TestCase, +): def test_simple_run(self): # we have two headers header_list = self.mkdtemp() @@ -32,8 +34,10 @@ def test_simple_run(self): # let's check the results self.assertEqual(len(cmd.get_outputs()), 2) + def test_suite(): return unittest.makeSuite(InstallHeadersTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_install_lib.py b/setuptools/_distutils/tests/test_install_lib.py index fda6315bbc7..65657fa89d7 100644 --- a/setuptools/_distutils/tests/test_install_lib.py +++ b/setuptools/_distutils/tests/test_install_lib.py @@ -11,11 +11,12 @@ from test.support import run_unittest -class InstallLibTestCase(support.TempdirManager, - support.LoggingSilencer, - support.EnvironGuard, - unittest.TestCase): - +class InstallLibTestCase( + support.TempdirManager, + support.LoggingSilencer, + support.EnvironGuard, + unittest.TestCase, +): def test_finalize_options(self): dist = self.create_dist()[1] cmd = install_lib(dist) @@ -45,8 +46,9 @@ def test_byte_compile(self): self.write_file(f, '# python file') cmd.byte_compile([f]) pyc_file = importlib.util.cache_from_source('foo.py', optimization='') - pyc_opt_file = importlib.util.cache_from_source('foo.py', - optimization=cmd.optimize) + pyc_opt_file = importlib.util.cache_from_source( + 'foo.py', optimization=cmd.optimize + ) self.assertTrue(os.path.exists(pyc_file)) self.assertTrue(os.path.exists(pyc_opt_file)) @@ -104,12 +106,12 @@ def test_dont_write_bytecode(self): finally: sys.dont_write_bytecode = old_dont_write_bytecode - self.assertIn('byte-compiling is disabled', - self.logs[0][1] % self.logs[0][2]) + self.assertIn('byte-compiling is disabled', self.logs[0][1] % self.logs[0][2]) def test_suite(): return unittest.makeSuite(InstallLibTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_install_scripts.py b/setuptools/_distutils/tests/test_install_scripts.py index 1f7b1038cb2..abc904cd6e6 100644 --- a/setuptools/_distutils/tests/test_install_scripts.py +++ b/setuptools/_distutils/tests/test_install_scripts.py @@ -10,19 +10,17 @@ from test.support import run_unittest -class InstallScriptsTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): - +class InstallScriptsTestCase( + support.TempdirManager, support.LoggingSilencer, unittest.TestCase +): def test_default_settings(self): dist = Distribution() - dist.command_obj["build"] = support.DummyCommand( - build_scripts="/foo/bar") + dist.command_obj["build"] = support.DummyCommand(build_scripts="/foo/bar") dist.command_obj["install"] = support.DummyCommand( install_scripts="/splat/funk", force=1, skip_build=1, - ) + ) cmd = install_scripts(dist) self.assertFalse(cmd.force) self.assertFalse(cmd.skip_build) @@ -48,15 +46,21 @@ def write_script(name, text): finally: f.close() - write_script("script1.py", ("#! /usr/bin/env python2.3\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - write_script("script2.py", ("#!/usr/bin/python\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - write_script("shell.sh", ("#!/bin/sh\n" - "# bogus shell script w/ sh-bang\n" - "exit 0\n")) + write_script( + "script1.py", + ( + "#! /usr/bin/env python2.3\n" + "# bogus script w/ Python sh-bang\n" + "pass\n" + ), + ) + write_script( + "script2.py", + ("#!/usr/bin/python\n" "# bogus script w/ Python sh-bang\n" "pass\n"), + ) + write_script( + "shell.sh", ("#!/bin/sh\n" "# bogus shell script w/ sh-bang\n" "exit 0\n") + ) target = self.mkdtemp() dist = Distribution() @@ -65,7 +69,7 @@ def write_script(name, text): install_scripts=target, force=1, skip_build=1, - ) + ) cmd = install_scripts(dist) cmd.finalize_options() cmd.run() @@ -78,5 +82,6 @@ def write_script(name, text): def test_suite(): return unittest.makeSuite(InstallScriptsTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_log.py b/setuptools/_distutils/tests/test_log.py index 75cf900617b..794976a2c33 100644 --- a/setuptools/_distutils/tests/test_log.py +++ b/setuptools/_distutils/tests/test_log.py @@ -7,40 +7,55 @@ from distutils import log + class TestLog(unittest.TestCase): def test_non_ascii(self): # Issues #8663, #34421: test that non-encodable text is escaped with # backslashreplace error handler and encodable non-ASCII text is # output as is. - for errors in ('strict', 'backslashreplace', 'surrogateescape', - 'replace', 'ignore'): + for errors in ( + 'strict', + 'backslashreplace', + 'surrogateescape', + 'replace', + 'ignore', + ): with self.subTest(errors=errors): - stdout = io.TextIOWrapper(io.BytesIO(), - encoding='cp437', errors=errors) - stderr = io.TextIOWrapper(io.BytesIO(), - encoding='cp437', errors=errors) + stdout = io.TextIOWrapper(io.BytesIO(), encoding='cp437', errors=errors) + stderr = io.TextIOWrapper(io.BytesIO(), encoding='cp437', errors=errors) old_threshold = log.set_threshold(log.DEBUG) try: - with swap_attr(sys, 'stdout', stdout), \ - swap_attr(sys, 'stderr', stderr): + with swap_attr(sys, 'stdout', stdout), swap_attr( + sys, 'stderr', stderr + ): log.debug('Dεbug\tMėssãge') log.fatal('Fαtal\tÈrrōr') finally: log.set_threshold(old_threshold) stdout.seek(0) - self.assertEqual(stdout.read().rstrip(), - 'Dεbug\tM?ss?ge' if errors == 'replace' else - 'Dεbug\tMssge' if errors == 'ignore' else - 'Dεbug\tM\\u0117ss\\xe3ge') + self.assertEqual( + stdout.read().rstrip(), + 'Dεbug\tM?ss?ge' + if errors == 'replace' + else 'Dεbug\tMssge' + if errors == 'ignore' + else 'Dεbug\tM\\u0117ss\\xe3ge', + ) stderr.seek(0) - self.assertEqual(stderr.read().rstrip(), - 'Fαtal\t?rr?r' if errors == 'replace' else - 'Fαtal\trrr' if errors == 'ignore' else - 'Fαtal\t\\xc8rr\\u014dr') + self.assertEqual( + stderr.read().rstrip(), + 'Fαtal\t?rr?r' + if errors == 'replace' + else 'Fαtal\trrr' + if errors == 'ignore' + else 'Fαtal\t\\xc8rr\\u014dr', + ) + def test_suite(): return unittest.makeSuite(TestLog) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_msvc9compiler.py b/setuptools/_distutils/tests/test_msvc9compiler.py index 77a07ef39dd..77f347acaa5 100644 --- a/setuptools/_distutils/tests/test_msvc9compiler.py +++ b/setuptools/_distutils/tests/test_msvc9compiler.py @@ -90,38 +90,42 @@ """ -if sys.platform=="win32": +if sys.platform == "win32": from distutils.msvccompiler import get_build_version - if get_build_version()>=8.0: + + if get_build_version() >= 8.0: SKIP_MESSAGE = None else: SKIP_MESSAGE = "These tests are only for MSVC8.0 or above" else: SKIP_MESSAGE = "These tests are only for win32" -@unittest.skipUnless(SKIP_MESSAGE is None, SKIP_MESSAGE) -class msvc9compilerTestCase(support.TempdirManager, - unittest.TestCase): +@unittest.skipUnless(SKIP_MESSAGE is None, SKIP_MESSAGE) +class msvc9compilerTestCase(support.TempdirManager, unittest.TestCase): def test_no_compiler(self): # makes sure query_vcvarsall raises # a DistutilsPlatformError if the compiler # is not found from distutils.msvc9compiler import query_vcvarsall + def _find_vcvarsall(version): return None from distutils import msvc9compiler + old_find_vcvarsall = msvc9compiler.find_vcvarsall msvc9compiler.find_vcvarsall = _find_vcvarsall try: - self.assertRaises(DistutilsPlatformError, query_vcvarsall, - 'wont find this version') + self.assertRaises( + DistutilsPlatformError, query_vcvarsall, 'wont find this version' + ) finally: msvc9compiler.find_vcvarsall = old_find_vcvarsall def test_reg_class(self): from distutils.msvc9compiler import Reg + self.assertRaises(KeyError, Reg.get_value, 'xxx', 'xxx') # looking for values that should exist on all @@ -131,6 +135,7 @@ def test_reg_class(self): self.assertIn(v, ('0', '1', '2')) import winreg + HKCU = winreg.HKEY_CURRENT_USER keys = Reg.read_keys(HKCU, 'xxxx') self.assertEqual(keys, None) @@ -140,6 +145,7 @@ def test_reg_class(self): def test_remove_visual_c_ref(self): from distutils.msvc9compiler import MSVCCompiler + tempdir = self.mkdtemp() manifest = os.path.join(tempdir, 'manifest') f = open(manifest, 'w') @@ -164,6 +170,7 @@ def test_remove_visual_c_ref(self): def test_remove_entire_manifest(self): from distutils.msvc9compiler import MSVCCompiler + tempdir = self.mkdtemp() manifest = os.path.join(tempdir, 'manifest') f = open(manifest, 'w') @@ -180,5 +187,6 @@ def test_remove_entire_manifest(self): def test_suite(): return unittest.makeSuite(msvc9compilerTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_msvccompiler.py b/setuptools/_distutils/tests/test_msvccompiler.py index 46a51cd0a7b..e44aa6ad8e4 100644 --- a/setuptools/_distutils/tests/test_msvccompiler.py +++ b/setuptools/_distutils/tests/test_msvccompiler.py @@ -9,15 +9,14 @@ from test.support import run_unittest -SKIP_MESSAGE = (None if sys.platform == "win32" else - "These tests are only for win32") +SKIP_MESSAGE = None if sys.platform == "win32" else "These tests are only for win32" -@unittest.skipUnless(SKIP_MESSAGE is None, SKIP_MESSAGE) -class msvccompilerTestCase(support.TempdirManager, - unittest.TestCase): +@unittest.skipUnless(SKIP_MESSAGE is None, SKIP_MESSAGE) +class msvccompilerTestCase(support.TempdirManager, unittest.TestCase): def test_no_compiler(self): import distutils._msvccompiler as _msvccompiler + # makes sure query_vcvarsall raises # a DistutilsPlatformError if the compiler # is not found @@ -27,9 +26,11 @@ def _find_vcvarsall(plat_spec): old_find_vcvarsall = _msvccompiler._find_vcvarsall _msvccompiler._find_vcvarsall = _find_vcvarsall try: - self.assertRaises(DistutilsPlatformError, - _msvccompiler._get_vc_env, - 'wont find this version') + self.assertRaises( + DistutilsPlatformError, + _msvccompiler._get_vc_env, + 'wont find this version', + ) finally: _msvccompiler._find_vcvarsall = old_find_vcvarsall @@ -95,14 +96,14 @@ def test_concurrent_safe(self): Concurrent calls to spawn should have consistent results. """ import distutils._msvccompiler as _msvccompiler + compiler = _msvccompiler.MSVCCompiler() compiler._paths = "expected" inner_cmd = 'import os; assert os.environ["PATH"] == "expected"' command = ['python', '-c', inner_cmd] threads = [ - CheckThread(target=compiler.spawn, args=[command]) - for n in range(100) + CheckThread(target=compiler.spawn, args=[command]) for n in range(100) ] for thread in threads: thread.start() @@ -117,6 +118,7 @@ def test_concurrent_safe_fallback(self): """ import distutils._msvccompiler as _msvccompiler from distutils import ccompiler + compiler = _msvccompiler.MSVCCompiler() compiler._paths = "expected" @@ -124,8 +126,7 @@ def CCompiler_spawn(self, cmd): "A spawn without an env argument." assert os.environ["PATH"] == "expected" - with unittest.mock.patch.object( - ccompiler.CCompiler, 'spawn', CCompiler_spawn): + with unittest.mock.patch.object(ccompiler.CCompiler, 'spawn', CCompiler_spawn): compiler.spawn(["n/a"]) assert os.environ.get("PATH") != "expected" @@ -134,5 +135,6 @@ def CCompiler_spawn(self, cmd): def test_suite(): return unittest.makeSuite(msvccompilerTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_register.py b/setuptools/_distutils/tests/test_register.py index 84607f996f1..29fc02b9d0f 100644 --- a/setuptools/_distutils/tests/test_register.py +++ b/setuptools/_distutils/tests/test_register.py @@ -41,8 +41,10 @@ password:password """ + class Inputs(object): """Fakes user inputs.""" + def __init__(self, *answers): self.answers = answers self.index = 0 @@ -53,8 +55,10 @@ def __call__(self, prompt=''): finally: self.index += 1 + class FakeOpener(object): """Fakes a PyPI server""" + def __init__(self): self.reqs = [] @@ -71,17 +75,18 @@ def read(self): def getheader(self, name, default=None): return { 'content-type': 'text/plain; charset=utf-8', - }.get(name.lower(), default) + }.get(name.lower(), default) class RegisterTestCase(BasePyPIRCCommandTestCase): - def setUp(self): super(RegisterTestCase, self).setUp() # patching the password prompt self._old_getpass = getpass.getpass + def _getpass(prompt): return 'password' + getpass.getpass = _getpass urllib.request._opener = None self.old_opener = urllib.request.build_opener @@ -95,9 +100,13 @@ def tearDown(self): def _get_cmd(self, metadata=None): if metadata is None: - metadata = {'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx', - 'name': 'xxx', 'version': 'xxx'} + metadata = { + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', + 'version': 'xxx', + } pkg_info, dist = self.create_dist(**metadata) return register(dist) @@ -143,6 +152,7 @@ def test_create_pypirc(self): # if we run the command again def _no_way(prompt=''): raise AssertionError(prompt) + register_module.input = _no_way cmd.show_response = 1 @@ -220,10 +230,14 @@ def test_strict(self): self.assertRaises(DistutilsSetupError, cmd.run) # metadata are OK but long_description is broken - metadata = {'url': 'xxx', 'author': 'xxx', - 'author_email': 'éxéxé', - 'name': 'xxx', 'version': 'xxx', - 'long_description': 'title\n==\n\ntext'} + metadata = { + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'éxéxé', + 'name': 'xxx', + 'version': 'xxx', + 'long_description': 'title\n==\n\ntext', + } cmd = self._get_cmd(metadata) cmd.ensure_finalized() @@ -255,11 +269,15 @@ def test_strict(self): del register_module.input # and finally a Unicode test (bug #12114) - metadata = {'url': 'xxx', 'author': '\u00c9ric', - 'author_email': 'xxx', 'name': 'xxx', - 'version': 'xxx', - 'description': 'Something about esszet \u00df', - 'long_description': 'More things about esszet \u00df'} + metadata = { + 'url': 'xxx', + 'author': '\u00c9ric', + 'author_email': 'xxx', + 'name': 'xxx', + 'version': 'xxx', + 'description': 'Something about esszet \u00df', + 'long_description': 'More things about esszet \u00df', + } cmd = self._get_cmd(metadata) cmd.ensure_finalized() @@ -275,10 +293,14 @@ def test_strict(self): @unittest.skipUnless(docutils is not None, 'needs docutils') def test_register_invalid_long_description(self): description = ':funkie:`str`' # mimic Sphinx-specific markup - metadata = {'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx', - 'name': 'xxx', 'version': 'xxx', - 'long_description': description} + metadata = { + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', + 'version': 'xxx', + 'long_description': description, + } cmd = self._get_cmd(metadata) cmd.ensure_finalized() cmd.strict = True @@ -321,5 +343,6 @@ def test_show_response(self): def test_suite(): return unittest.makeSuite(RegisterTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_sdist.py b/setuptools/_distutils/tests/test_sdist.py index b087a817879..44ff66afaa5 100644 --- a/setuptools/_distutils/tests/test_sdist.py +++ b/setuptools/_distutils/tests/test_sdist.py @@ -12,6 +12,7 @@ try: import zlib + ZLIB_SUPPORT = True except ImportError: ZLIB_SUPPORT = False @@ -19,6 +20,7 @@ try: import grp import pwd + UID_GID_SUPPORT = True except ImportError: UID_GID_SUPPORT = False @@ -54,8 +56,8 @@ somecode%(sep)sdoc.txt """ -class SDistTestCase(BasePyPIRCCommandTestCase): +class SDistTestCase(BasePyPIRCCommandTestCase): def setUp(self): # PyPIRCCommandTestCase creates a temp dir already # and put it in self.tmp_dir @@ -78,9 +80,13 @@ def tearDown(self): def get_cmd(self, metadata=None): """Returns a cmd""" if metadata is None: - metadata = {'name': 'fake', 'version': '1.0', - 'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx'} + metadata = { + 'name': 'fake', + 'version': '1.0', + 'url': 'xxx', + 'author': 'xxx', + 'author_email': 'xxx', + } dist = Distribution(metadata) dist.script_name = 'setup.py' dist.packages = ['somecode'] @@ -99,12 +105,10 @@ def test_prune_file_list(self): self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx') os.mkdir(join(self.tmp_dir, 'somecode', '.hg')) - self.write_file((self.tmp_dir, 'somecode', '.hg', - 'ok'), 'xxx') + self.write_file((self.tmp_dir, 'somecode', '.hg', 'ok'), 'xxx') os.mkdir(join(self.tmp_dir, 'somecode', '.git')) - self.write_file((self.tmp_dir, 'somecode', '.git', - 'ok'), 'xxx') + self.write_file((self.tmp_dir, 'somecode', '.git', 'ok'), 'xxx') self.write_file((self.tmp_dir, 'somecode', '.nfs0001'), 'xxx') @@ -130,15 +134,19 @@ def test_prune_file_list(self): zip_file.close() # making sure everything has been pruned correctly - expected = ['', 'PKG-INFO', 'README', 'setup.py', - 'somecode/', 'somecode/__init__.py'] + expected = [ + '', + 'PKG-INFO', + 'README', + 'setup.py', + 'somecode/', + 'somecode/__init__.py', + ] self.assertEqual(sorted(content), ['fake-1.0/' + x for x in expected]) @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') - @unittest.skipIf(find_executable('tar') is None, - "The tar command is not found") - @unittest.skipIf(find_executable('gzip') is None, - "The gzip command is not found") + @unittest.skipIf(find_executable('tar') is None, "The tar command is not found") + @unittest.skipIf(find_executable('gzip') is None, "The gzip command is not found") def test_make_distribution(self): # now building a sdist dist, cmd = self.get_cmd() @@ -178,8 +186,7 @@ def test_add_defaults(self): # filling data_files by pointing files # in package_data - dist.package_data = {'': ['*.cfg', '*.dat'], - 'somecode': ['*.txt']} + dist.package_data = {'': ['*.cfg', '*.dat'], 'somecode': ['*.txt']} self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#') @@ -199,12 +206,11 @@ def test_add_defaults(self): self.write_file((some_dir, 'file.txt'), '#') self.write_file((some_dir, 'other_file.txt'), '#') - dist.data_files = [('data', ['data/data.dt', - 'buildout.cfg', - 'inroot.txt', - 'notexisting']), - 'some/file.txt', - 'some/other_file.txt'] + dist.data_files = [ + ('data', ['data/data.dt', 'buildout.cfg', 'inroot.txt', 'notexisting']), + 'some/file.txt', + 'some/other_file.txt', + ] # adding a script script_dir = join(self.tmp_dir, 'scripts') @@ -230,12 +236,25 @@ def test_add_defaults(self): zip_file.close() # making sure everything was added - expected = ['', 'PKG-INFO', 'README', 'buildout.cfg', - 'data/', 'data/data.dt', 'inroot.txt', - 'scripts/', 'scripts/script.py', 'setup.py', - 'some/', 'some/file.txt', 'some/other_file.txt', - 'somecode/', 'somecode/__init__.py', 'somecode/doc.dat', - 'somecode/doc.txt'] + expected = [ + '', + 'PKG-INFO', + 'README', + 'buildout.cfg', + 'data/', + 'data/data.dt', + 'inroot.txt', + 'scripts/', + 'scripts/script.py', + 'setup.py', + 'some/', + 'some/file.txt', + 'some/other_file.txt', + 'somecode/', + 'somecode/__init__.py', + 'somecode/doc.dat', + 'somecode/doc.txt', + ] self.assertEqual(sorted(content), ['fake-1.0/' + x for x in expected]) # checking the MANIFEST @@ -255,8 +274,9 @@ def test_metadata_check_option(self): # with the `check` subcommand cmd.ensure_finalized() cmd.run() - warnings = [msg for msg in self.get_logs(WARN) if - msg.startswith('warning: check:')] + warnings = [ + msg for msg in self.get_logs(WARN) if msg.startswith('warning: check:') + ] self.assertEqual(len(warnings), 2) # trying with a complete set of metadata @@ -265,8 +285,9 @@ def test_metadata_check_option(self): cmd.ensure_finalized() cmd.metadata_check = 0 cmd.run() - warnings = [msg for msg in self.get_logs(WARN) if - msg.startswith('warning: check:')] + warnings = [ + msg for msg in self.get_logs(WARN) if msg.startswith('warning: check:') + ] self.assertEqual(len(warnings), 0) def test_check_metadata_deprecated(self): @@ -283,8 +304,11 @@ def test_show_formats(self): # the output should be a header line + one line per format num_formats = len(ARCHIVE_FORMATS.keys()) - output = [line for line in stdout.getvalue().split('\n') - if line.strip().startswith('--formats=')] + output = [ + line + for line in stdout.getvalue().split('\n') + if line.strip().startswith('--formats=') + ] self.assertEqual(len(output), num_formats) def test_finalize_options(self): @@ -347,8 +371,9 @@ def test_get_file_list(self): f = open(cmd.manifest) try: - manifest = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] + manifest = [ + line.strip() for line in f.read().split('\n') if line.strip() != '' + ] finally: f.close() @@ -366,8 +391,9 @@ def test_get_file_list(self): f = open(cmd.manifest) try: - manifest2 = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] + manifest2 = [ + line.strip() for line in f.read().split('\n') if line.strip() != '' + ] finally: f.close() @@ -384,22 +410,24 @@ def test_manifest_marker(self): f = open(cmd.manifest) try: - manifest = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] + manifest = [ + line.strip() for line in f.read().split('\n') if line.strip() != '' + ] finally: f.close() - self.assertEqual(manifest[0], - '# file GENERATED by distutils, do NOT edit') + self.assertEqual(manifest[0], '# file GENERATED by distutils, do NOT edit') @unittest.skipUnless(ZLIB_SUPPORT, "Need zlib support to run") def test_manifest_comments(self): # make sure comments don't cause exceptions or wrong includes - contents = dedent("""\ + contents = dedent( + """\ # bad.py #bad.py good.py - """) + """ + ) dist, cmd = self.get_cmd() cmd.ensure_finalized() self.write_file((self.tmp_dir, cmd.manifest), contents) @@ -416,15 +444,18 @@ def test_manual_manifest(self): cmd.formats = ['gztar'] cmd.ensure_finalized() self.write_file((self.tmp_dir, cmd.manifest), 'README.manual') - self.write_file((self.tmp_dir, 'README.manual'), - 'This project maintains its MANIFEST file itself.') + self.write_file( + (self.tmp_dir, 'README.manual'), + 'This project maintains its MANIFEST file itself.', + ) cmd.run() self.assertEqual(cmd.filelist.files, ['README.manual']) f = open(cmd.manifest) try: - manifest = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] + manifest = [ + line.strip() for line in f.read().split('\n') if line.strip() != '' + ] finally: f.close() @@ -436,15 +467,15 @@ def test_manual_manifest(self): filenames = [tarinfo.name for tarinfo in archive] finally: archive.close() - self.assertEqual(sorted(filenames), ['fake-1.0', 'fake-1.0/PKG-INFO', - 'fake-1.0/README.manual']) + self.assertEqual( + sorted(filenames), + ['fake-1.0', 'fake-1.0/PKG-INFO', 'fake-1.0/README.manual'], + ) @unittest.skipUnless(ZLIB_SUPPORT, "requires zlib") @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") - @unittest.skipIf(find_executable('tar') is None, - "The tar command is not found") - @unittest.skipIf(find_executable('gzip') is None, - "The gzip command is not found") + @unittest.skipIf(find_executable('tar') is None, "The tar command is not found") + @unittest.skipIf(find_executable('gzip') is None, "The gzip command is not found") def test_make_distribution_owner_group(self): # now building a sdist dist, cmd = self.get_cmd() @@ -487,8 +518,10 @@ def test_make_distribution_owner_group(self): finally: archive.close() + def test_suite(): return unittest.makeSuite(SDistTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_spawn.py b/setuptools/_distutils/tests/test_spawn.py index f620da78430..a18f83b1ed2 100644 --- a/setuptools/_distutils/tests/test_spawn.py +++ b/setuptools/_distutils/tests/test_spawn.py @@ -13,12 +13,9 @@ from distutils.errors import DistutilsExecError from distutils.tests import support -class SpawnTestCase(support.TempdirManager, - support.LoggingSilencer, - unittest.TestCase): - @unittest.skipUnless(os.name in ('nt', 'posix'), - 'Runs only under posix or nt') +class SpawnTestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): + @unittest.skipUnless(os.name in ('nt', 'posix'), 'Runs only under posix or nt') def test_spawn(self): tmpdir = self.mkdtemp() @@ -74,16 +71,15 @@ def test_find_executable(self): # test non-existent program dont_exist_program = "dontexist_" + program - rv = find_executable(dont_exist_program , path=tmp_dir) + rv = find_executable(dont_exist_program, path=tmp_dir) self.assertIsNone(rv) # PATH='': no match, except in the current directory with os_helper.EnvironmentVarGuard() as env: env['PATH'] = '' - with unittest.mock.patch('distutils.spawn.os.confstr', - return_value=tmp_dir, create=True), \ - unittest.mock.patch('distutils.spawn.os.defpath', - tmp_dir): + with unittest.mock.patch( + 'distutils.spawn.os.confstr', return_value=tmp_dir, create=True + ), unittest.mock.patch('distutils.spawn.os.defpath', tmp_dir): rv = find_executable(program) self.assertIsNone(rv) @@ -95,9 +91,9 @@ def test_find_executable(self): # PATH=':': explicitly looks in the current directory with os_helper.EnvironmentVarGuard() as env: env['PATH'] = os.pathsep - with unittest.mock.patch('distutils.spawn.os.confstr', - return_value='', create=True), \ - unittest.mock.patch('distutils.spawn.os.defpath', ''): + with unittest.mock.patch( + 'distutils.spawn.os.confstr', return_value='', create=True + ), unittest.mock.patch('distutils.spawn.os.defpath', ''): rv = find_executable(program) self.assertIsNone(rv) @@ -111,18 +107,16 @@ def test_find_executable(self): env.pop('PATH', None) # without confstr - with unittest.mock.patch('distutils.spawn.os.confstr', - side_effect=ValueError, - create=True), \ - unittest.mock.patch('distutils.spawn.os.defpath', - tmp_dir): + with unittest.mock.patch( + 'distutils.spawn.os.confstr', side_effect=ValueError, create=True + ), unittest.mock.patch('distutils.spawn.os.defpath', tmp_dir): rv = find_executable(program) self.assertEqual(rv, filename) # with confstr - with unittest.mock.patch('distutils.spawn.os.confstr', - return_value=tmp_dir, create=True), \ - unittest.mock.patch('distutils.spawn.os.defpath', ''): + with unittest.mock.patch( + 'distutils.spawn.os.confstr', return_value=tmp_dir, create=True + ), unittest.mock.patch('distutils.spawn.os.defpath', ''): rv = find_executable(program) self.assertEqual(rv, filename) @@ -135,5 +129,6 @@ def test_spawn_missing_exe(self): def test_suite(): return unittest.makeSuite(SpawnTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_sysconfig.py b/setuptools/_distutils/tests/test_sysconfig.py index c757194288c..366aa19ca61 100644 --- a/setuptools/_distutils/tests/test_sysconfig.py +++ b/setuptools/_distutils/tests/test_sysconfig.py @@ -39,10 +39,11 @@ def test_get_config_h_filename(self): def test_get_python_lib(self): # XXX doesn't work on Linux when Python was never installed before - #self.assertTrue(os.path.isdir(lib_dir), lib_dir) + # self.assertTrue(os.path.isdir(lib_dir), lib_dir) # test for pythonxx.lib? - self.assertNotEqual(sysconfig.get_python_lib(), - sysconfig.get_python_lib(prefix=TESTFN)) + self.assertNotEqual( + sysconfig.get_python_lib(), sysconfig.get_python_lib(prefix=TESTFN) + ) def test_get_config_vars(self): cvars = sysconfig.get_config_vars() @@ -64,9 +65,7 @@ def test_srcdir(self): self.assertTrue(os.path.exists(Python_h), Python_h) self.assertTrue(sysconfig._is_python_source_dir(srcdir)) elif os.name == 'posix': - self.assertEqual( - os.path.dirname(sysconfig.get_makefile_filename()), - srcdir) + self.assertEqual(os.path.dirname(sysconfig.get_makefile_filename()), srcdir) def test_srcdir_independent_of_cwd(self): # srcdir should be independent of the current working directory @@ -97,7 +96,6 @@ def set_executables(self, **kw): 'CCSHARED': '--sc-ccshared', 'LDSHARED': 'sc_ldshared', 'SHLIB_SUFFIX': 'sc_shutil_suffix', - # On macOS, disable _osx_support.customize_compiler() 'CUSTOMIZED_OSX_COMPILER': 'True', } @@ -110,8 +108,9 @@ def set_executables(self, **kw): return comp - @unittest.skipUnless(get_default_compiler() == 'unix', - 'not testing if default compiler is not unix') + @unittest.skipUnless( + get_default_compiler() == 'unix', 'not testing if default compiler is not unix' + ) def test_customize_compiler(self): # Make sure that sysconfig._config_vars is initialized sysconfig.get_config_vars() @@ -127,22 +126,21 @@ def test_customize_compiler(self): os.environ['CPPFLAGS'] = '--env-cppflags' comp = self.customize_compiler() - self.assertEqual(comp.exes['archiver'], - 'env_ar --env-arflags') - self.assertEqual(comp.exes['preprocessor'], - 'env_cpp --env-cppflags') - self.assertEqual(comp.exes['compiler'], - 'env_cc --sc-cflags --env-cflags --env-cppflags') - self.assertEqual(comp.exes['compiler_so'], - ('env_cc --sc-cflags ' - '--env-cflags ''--env-cppflags --sc-ccshared')) - self.assertEqual(comp.exes['compiler_cxx'], - 'env_cxx --env-cxx-flags') - self.assertEqual(comp.exes['linker_exe'], - 'env_cc') - self.assertEqual(comp.exes['linker_so'], - ('env_ldshared --env-ldflags --env-cflags' - ' --env-cppflags')) + self.assertEqual(comp.exes['archiver'], 'env_ar --env-arflags') + self.assertEqual(comp.exes['preprocessor'], 'env_cpp --env-cppflags') + self.assertEqual( + comp.exes['compiler'], 'env_cc --sc-cflags --env-cflags --env-cppflags' + ) + self.assertEqual( + comp.exes['compiler_so'], + ('env_cc --sc-cflags ' '--env-cflags ' '--env-cppflags --sc-ccshared'), + ) + self.assertEqual(comp.exes['compiler_cxx'], 'env_cxx --env-cxx-flags') + self.assertEqual(comp.exes['linker_exe'], 'env_cc') + self.assertEqual( + comp.exes['linker_so'], + ('env_ldshared --env-ldflags --env-cflags' ' --env-cppflags'), + ) self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix') del os.environ['AR'] @@ -156,20 +154,13 @@ def test_customize_compiler(self): del os.environ['CPPFLAGS'] comp = self.customize_compiler() - self.assertEqual(comp.exes['archiver'], - 'sc_ar --sc-arflags') - self.assertEqual(comp.exes['preprocessor'], - 'sc_cc -E') - self.assertEqual(comp.exes['compiler'], - 'sc_cc --sc-cflags') - self.assertEqual(comp.exes['compiler_so'], - 'sc_cc --sc-cflags --sc-ccshared') - self.assertEqual(comp.exes['compiler_cxx'], - 'sc_cxx') - self.assertEqual(comp.exes['linker_exe'], - 'sc_cc') - self.assertEqual(comp.exes['linker_so'], - 'sc_ldshared') + self.assertEqual(comp.exes['archiver'], 'sc_ar --sc-arflags') + self.assertEqual(comp.exes['preprocessor'], 'sc_cc -E') + self.assertEqual(comp.exes['compiler'], 'sc_cc --sc-cflags') + self.assertEqual(comp.exes['compiler_so'], 'sc_cc --sc-cflags --sc-ccshared') + self.assertEqual(comp.exes['compiler_cxx'], 'sc_cxx') + self.assertEqual(comp.exes['linker_exe'], 'sc_cc') + self.assertEqual(comp.exes['linker_so'], 'sc_ldshared') self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix') def test_parse_makefile_base(self): @@ -181,8 +172,9 @@ def test_parse_makefile_base(self): finally: fd.close() d = sysconfig.parse_makefile(self.makefile) - self.assertEqual(d, {'CONFIG_ARGS': "'--arg1=optarg1' 'ENV=LIB'", - 'OTHER': 'foo'}) + self.assertEqual( + d, {'CONFIG_ARGS': "'--arg1=optarg1' 'ENV=LIB'", 'OTHER': 'foo'} + ) def test_parse_makefile_literal_dollar(self): self.makefile = TESTFN @@ -193,19 +185,25 @@ def test_parse_makefile_literal_dollar(self): finally: fd.close() d = sysconfig.parse_makefile(self.makefile) - self.assertEqual(d, {'CONFIG_ARGS': r"'--arg1=optarg1' 'ENV=\$LIB'", - 'OTHER': 'foo'}) - + self.assertEqual( + d, {'CONFIG_ARGS': r"'--arg1=optarg1' 'ENV=\$LIB'", 'OTHER': 'foo'} + ) def test_sysconfig_module(self): import sysconfig as global_sysconfig - self.assertEqual(global_sysconfig.get_config_var('CFLAGS'), - sysconfig.get_config_var('CFLAGS')) - self.assertEqual(global_sysconfig.get_config_var('LDFLAGS'), - sysconfig.get_config_var('LDFLAGS')) - @unittest.skipIf(sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'), - 'compiler flags customized') + self.assertEqual( + global_sysconfig.get_config_var('CFLAGS'), + sysconfig.get_config_var('CFLAGS'), + ) + self.assertEqual( + global_sysconfig.get_config_var('LDFLAGS'), + sysconfig.get_config_var('LDFLAGS'), + ) + + @unittest.skipIf( + sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'), 'compiler flags customized' + ) def test_sysconfig_compiler_vars(self): # On OS X, binary installers support extension module building on # various levels of the operating system with differing Xcode @@ -222,28 +220,38 @@ def test_sysconfig_compiler_vars(self): # The longer-term solution is to only have one version of sysconfig. import sysconfig as global_sysconfig + if sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'): self.skipTest('compiler flags customized') - self.assertEqual(global_sysconfig.get_config_var('LDSHARED'), - sysconfig.get_config_var('LDSHARED')) - self.assertEqual(global_sysconfig.get_config_var('CC'), - sysconfig.get_config_var('CC')) - - @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None, - 'EXT_SUFFIX required for this test') + self.assertEqual( + global_sysconfig.get_config_var('LDSHARED'), + sysconfig.get_config_var('LDSHARED'), + ) + self.assertEqual( + global_sysconfig.get_config_var('CC'), sysconfig.get_config_var('CC') + ) + + @unittest.skipIf( + sysconfig.get_config_var('EXT_SUFFIX') is None, + 'EXT_SUFFIX required for this test', + ) def test_SO_deprecation(self): - self.assertWarns(DeprecationWarning, - sysconfig.get_config_var, 'SO') + self.assertWarns(DeprecationWarning, sysconfig.get_config_var, 'SO') - @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None, - 'EXT_SUFFIX required for this test') + @unittest.skipIf( + sysconfig.get_config_var('EXT_SUFFIX') is None, + 'EXT_SUFFIX required for this test', + ) def test_SO_value(self): with check_warnings(('', DeprecationWarning)): - self.assertEqual(sysconfig.get_config_var('SO'), - sysconfig.get_config_var('EXT_SUFFIX')) + self.assertEqual( + sysconfig.get_config_var('SO'), sysconfig.get_config_var('EXT_SUFFIX') + ) - @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None, - 'EXT_SUFFIX required for this test') + @unittest.skipIf( + sysconfig.get_config_var('EXT_SUFFIX') is None, + 'EXT_SUFFIX required for this test', + ) def test_SO_in_vars(self): vars = sysconfig.get_config_vars() self.assertIsNotNone(vars['SO']) @@ -254,17 +262,23 @@ def test_customize_compiler_before_get_config_vars(self): # instance can be called without an explicit call to # get_config_vars(). with open(TESTFN, 'w') as f: - f.writelines(textwrap.dedent('''\ + f.writelines( + textwrap.dedent( + '''\ from distutils.core import Distribution config = Distribution().get_command_obj('config') # try_compile may pass or it may fail if no compiler # is found but it should not raise an exception. rc = config.try_compile('int x;') - ''')) - p = subprocess.Popen([str(sys.executable), TESTFN], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True) + ''' + ) + ) + p = subprocess.Popen( + [str(sys.executable), TESTFN], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + ) outs, errs = p.communicate() self.assertEqual(0, p.returncode, "Subprocess failed: " + outs) diff --git a/setuptools/_distutils/tests/test_text_file.py b/setuptools/_distutils/tests/test_text_file.py index 7e76240a9a3..872337beedc 100644 --- a/setuptools/_distutils/tests/test_text_file.py +++ b/setuptools/_distutils/tests/test_text_file.py @@ -12,32 +12,35 @@ continues on next line """ -class TextFileTestCase(support.TempdirManager, unittest.TestCase): +class TextFileTestCase(support.TempdirManager, unittest.TestCase): def test_class(self): # old tests moved from text_file.__main__ # so they are really called by the buildbots # result 1: no fancy options - result1 = ['# test file\n', '\n', 'line 3 \\\n', - '# intervening comment\n', - ' continues on next line\n'] + result1 = [ + '# test file\n', + '\n', + 'line 3 \\\n', + '# intervening comment\n', + ' continues on next line\n', + ] # result 2: just strip comments - result2 = ["\n", - "line 3 \\\n", - " continues on next line\n"] + result2 = ["\n", "line 3 \\\n", " continues on next line\n"] # result 3: just strip blank lines - result3 = ["# test file\n", - "line 3 \\\n", - "# intervening comment\n", - " continues on next line\n"] + result3 = [ + "# test file\n", + "line 3 \\\n", + "# intervening comment\n", + " continues on next line\n", + ] # result 4: default, strip comments, blank lines, # and trailing whitespace - result4 = ["line 3 \\", - " continues on next line"] + result4 = ["line 3 \\", " continues on next line"] # result 5: strip comments and blanks, plus join lines (but don't # "collapse" joined lines @@ -59,22 +62,25 @@ def test_input(count, description, file, expected_result): finally: out_file.close() - in_file = TextFile(filename, strip_comments=0, skip_blanks=0, - lstrip_ws=0, rstrip_ws=0) + in_file = TextFile( + filename, strip_comments=0, skip_blanks=0, lstrip_ws=0, rstrip_ws=0 + ) try: test_input(1, "no processing", in_file, result1) finally: in_file.close() - in_file = TextFile(filename, strip_comments=1, skip_blanks=0, - lstrip_ws=0, rstrip_ws=0) + in_file = TextFile( + filename, strip_comments=1, skip_blanks=0, lstrip_ws=0, rstrip_ws=0 + ) try: test_input(2, "strip comments", in_file, result2) finally: in_file.close() - in_file = TextFile(filename, strip_comments=0, skip_blanks=1, - lstrip_ws=0, rstrip_ws=0) + in_file = TextFile( + filename, strip_comments=0, skip_blanks=1, lstrip_ws=0, rstrip_ws=0 + ) try: test_input(3, "strip blanks", in_file, result3) finally: @@ -86,22 +92,31 @@ def test_input(count, description, file, expected_result): finally: in_file.close() - in_file = TextFile(filename, strip_comments=1, skip_blanks=1, - join_lines=1, rstrip_ws=1) + in_file = TextFile( + filename, strip_comments=1, skip_blanks=1, join_lines=1, rstrip_ws=1 + ) try: test_input(5, "join lines without collapsing", in_file, result5) finally: in_file.close() - in_file = TextFile(filename, strip_comments=1, skip_blanks=1, - join_lines=1, rstrip_ws=1, collapse_join=1) + in_file = TextFile( + filename, + strip_comments=1, + skip_blanks=1, + join_lines=1, + rstrip_ws=1, + collapse_join=1, + ) try: test_input(6, "join lines with collapsing", in_file, result6) finally: in_file.close() + def test_suite(): return unittest.makeSuite(TextFileTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_unixccompiler.py b/setuptools/_distutils/tests/test_unixccompiler.py index ebd7c161e03..317d1e6b3e5 100644 --- a/setuptools/_distutils/tests/test_unixccompiler.py +++ b/setuptools/_distutils/tests/test_unixccompiler.py @@ -11,15 +11,17 @@ from distutils.unixccompiler import UnixCCompiler from distutils.util import _clear_cached_macosx_ver -class UnixCCompilerTestCase(unittest.TestCase): +class UnixCCompilerTestCase(unittest.TestCase): def setUp(self): self._backup_platform = sys.platform self._backup_get_config_var = sysconfig.get_config_var self._backup_get_config_vars = sysconfig.get_config_vars + class CompilerWrapper(UnixCCompiler): def rpath_foo(self): return self.runtime_library_dir_option('/foo') + self.cc = CompilerWrapper() def tearDown(self): @@ -44,18 +46,18 @@ def test_runtime_libdir_option(self): # Version value of None generates two tests: as None and as empty string # Expected flag value of None means an mismatch exception is expected darwin_test_cases = [ - ((None , None ), darwin_lib_flag), - ((None , '11' ), darwin_rpath_flag), - (('10' , None ), darwin_lib_flag), - (('10.3' , None ), darwin_lib_flag), - (('10.3.1', None ), darwin_lib_flag), - (('10.5' , None ), darwin_rpath_flag), - (('10.5.1', None ), darwin_rpath_flag), - (('10.3' , '10.3' ), darwin_lib_flag), - (('10.3' , '10.5' ), darwin_rpath_flag), - (('10.5' , '10.3' ), darwin_lib_flag), - (('10.5' , '11' ), darwin_rpath_flag), - (('10.4' , '10' ), None), + ((None, None), darwin_lib_flag), + ((None, '11'), darwin_rpath_flag), + (('10', None), darwin_lib_flag), + (('10.3', None), darwin_lib_flag), + (('10.3.1', None), darwin_lib_flag), + (('10.5', None), darwin_rpath_flag), + (('10.5.1', None), darwin_rpath_flag), + (('10.3', '10.3'), darwin_lib_flag), + (('10.3', '10.5'), darwin_rpath_flag), + (('10.5', '10.3'), darwin_lib_flag), + (('10.5', '11'), darwin_rpath_flag), + (('10.4', '10'), None), ] def make_darwin_gcv(syscfg_macosx_ver): @@ -63,12 +65,15 @@ def gcv(var): if var == darwin_ver_var: return syscfg_macosx_ver return "xxx" + return gcv def do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag): env = os.environ - msg = "macOS version = (sysconfig=%r, env=%r)" % \ - (syscfg_macosx_ver, env_macosx_ver) + msg = "macOS version = (sysconfig=%r, env=%r)" % ( + syscfg_macosx_ver, + env_macosx_ver, + ) # Save old_gcv = sysconfig.get_config_var @@ -86,8 +91,9 @@ def do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag): if expected_flag is not None: self.assertEqual(self.cc.rpath_foo(), expected_flag, msg=msg) else: - with self.assertRaisesRegex(DistutilsPlatformError, - darwin_ver_var + r' mismatch', msg=msg): + with self.assertRaisesRegex( + DistutilsPlatformError, darwin_ver_var + r' mismatch', msg=msg + ): self.cc.rpath_foo() # Restore @@ -113,18 +119,22 @@ def do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag): # hp-ux sys.platform = 'hp-ux' + def gcv(v): return 'xxx' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), ['+s', '-L/foo']) def gcv(v): return 'gcc' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), ['-Wl,+s', '-L/foo']) def gcv(v): return 'g++' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), ['-Wl,+s', '-L/foo']) @@ -132,52 +142,62 @@ def gcv(v): # GCC GNULD sys.platform = 'bar' + def gcv(v): if v == 'CC': return 'gcc' elif v == 'GNULD': return 'yes' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo') # GCC non-GNULD sys.platform = 'bar' + def gcv(v): if v == 'CC': return 'gcc' elif v == 'GNULD': return 'no' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-Wl,-R/foo') # GCC GNULD with fully qualified configuration prefix # see #7617 sys.platform = 'bar' + def gcv(v): if v == 'CC': return 'x86_64-pc-linux-gnu-gcc-4.4.2' elif v == 'GNULD': return 'yes' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo') # non-GCC GNULD sys.platform = 'bar' + def gcv(v): if v == 'CC': return 'cc' elif v == 'GNULD': return 'yes' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-R/foo') # non-GCC non-GNULD sys.platform = 'bar' + def gcv(v): if v == 'CC': return 'cc' elif v == 'GNULD': return 'no' + sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-R/foo') @@ -194,6 +214,7 @@ def gcvs(*args, _orig=sysconfig.get_config_vars): if args: return list(map(sysconfig.get_config_var, args)) return _orig() + sysconfig.get_config_var = gcv sysconfig.get_config_vars = gcvs with EnvironmentVarGuard() as env: @@ -216,6 +237,7 @@ def gcvs(*args, _orig=sysconfig.get_config_vars): if args: return list(map(sysconfig.get_config_var, args)) return _orig() + sysconfig.get_config_var = gcv sysconfig.get_config_vars = gcvs with EnvironmentVarGuard() as env: @@ -228,5 +250,6 @@ def gcvs(*args, _orig=sysconfig.get_config_vars): def test_suite(): return unittest.makeSuite(UnixCCompilerTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_upload.py b/setuptools/_distutils/tests/test_upload.py index bca5516d2f7..81767975912 100644 --- a/setuptools/_distutils/tests/test_upload.py +++ b/setuptools/_distutils/tests/test_upload.py @@ -43,8 +43,8 @@ username:me """ -class FakeOpen(object): +class FakeOpen(object): def __init__(self, url, msg=None, code=None): self.url = url if not isinstance(url, str): @@ -57,7 +57,7 @@ def __init__(self, url, msg=None, code=None): def getheader(self, name, default=None): return { 'content-type': 'text/plain; charset=utf-8', - }.get(name.lower(), default) + }.get(name.lower(), default) def read(self): return b'xyzzy' @@ -67,7 +67,6 @@ def getcode(self): class uploadTestCase(BasePyPIRCCommandTestCase): - def setUp(self): super(uploadTestCase, self).setUp() self.old_open = upload_mod.urlopen @@ -91,9 +90,12 @@ def test_finalize_options(self): dist = Distribution() cmd = upload(dist) cmd.finalize_options() - for attr, waited in (('username', 'me'), ('password', 'secret'), - ('realm', 'pypi'), - ('repository', 'https://upload.pypi.org/legacy/')): + for attr, waited in ( + ('username', 'me'), + ('password', 'secret'), + ('realm', 'pypi'), + ('repository', 'https://upload.pypi.org/legacy/'), + ): self.assertEqual(getattr(cmd, attr), waited) def test_saved_password(self): @@ -137,13 +139,12 @@ def test_upload(self): expected_url = 'https://upload.pypi.org/legacy/' self.assertEqual(self.last_open.req.get_full_url(), expected_url) data = self.last_open.req.data - self.assertIn(b'xxx',data) + self.assertIn(b'xxx', data) self.assertIn(b'protocol_version', data) self.assertIn(b'sha256_digest', data) self.assertIn( - b'cd2eb0837c9b4c962c22d2ff8b5441b7b45805887f051d39bf133b583baf' - b'6860', - data + b'cd2eb0837c9b4c962c22d2ff8b5441b7b45805887f051d39bf133b583baf' b'6860', + data, ) if b'md5_digest' in data: self.assertIn(b'f561aaf6ef0bf14d4208bb46a4ccb3ad', data) @@ -152,7 +153,7 @@ def test_upload(self): b'b6f289a27d4fe90da63c503bfe0a9b761a8f76bb86148565065f040be' b'6d1c3044cf7ded78ef800509bccb4b648e507d88dc6383d67642aadcc' b'ce443f1534330a', - data + data, ) # The PyPI response body was echoed @@ -173,8 +174,7 @@ def test_upload_correct_cr(self): # other fields that ended with \r used to be modified, now are # preserved. pkg_dir, dist = self.create_dist( - dist_files=dist_files, - description='long description\r' + dist_files=dist_files, description='long description\r' ) cmd = upload(dist) cmd.show_response = 1 @@ -200,13 +200,18 @@ def test_wrong_exception_order(self): pkg_dir, dist = self.create_dist(dist_files=dist_files) tests = [ (OSError('oserror'), 'oserror', OSError), - (HTTPError('url', 400, 'httperror', {}, None), - 'Upload failed (400): httperror', DistutilsError), + ( + HTTPError('url', 400, 'httperror', {}, None), + 'Upload failed (400): httperror', + DistutilsError, + ), ] for exception, expected, raised_exception in tests: with self.subTest(exception=type(exception).__name__): - with mock.patch('distutils.command.upload.urlopen', - new=mock.Mock(side_effect=exception)): + with mock.patch( + 'distutils.command.upload.urlopen', + new=mock.Mock(side_effect=exception), + ): with self.assertRaises(raised_exception): cmd = upload(dist) cmd.ensure_finalized() @@ -219,5 +224,6 @@ def test_wrong_exception_order(self): def test_suite(): return unittest.makeSuite(uploadTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_util.py b/setuptools/_distutils/tests/test_util.py index bf0d4333f9a..fbe2861451f 100644 --- a/setuptools/_distutils/tests/test_util.py +++ b/setuptools/_distutils/tests/test_util.py @@ -7,18 +7,25 @@ from unittest import mock from distutils.errors import DistutilsPlatformError, DistutilsByteCompileError -from distutils.util import (get_platform, convert_path, change_root, - check_environ, split_quoted, strtobool, - rfc822_escape, byte_compile, - grok_environment_error) -from distutils import util # used to patch _environ_checked +from distutils.util import ( + get_platform, + convert_path, + change_root, + check_environ, + split_quoted, + strtobool, + rfc822_escape, + byte_compile, + grok_environment_error, +) +from distutils import util # used to patch _environ_checked from distutils.sysconfig import get_config_vars from distutils import sysconfig from distutils.tests import support import _osx_support -class UtilTestCase(support.EnvironGuard, unittest.TestCase): +class UtilTestCase(support.EnvironGuard, unittest.TestCase): def setUp(self): super(UtilTestCase, self).setUp() # saving the environment @@ -67,35 +74,49 @@ def test_get_platform(self): # windows XP, 32bits os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Intel)]') + sys.version = ( + '2.4.4 (#71, Oct 18 2006, 08:34:43) ' '[MSC v.1310 32 bit (Intel)]' + ) sys.platform = 'win32' self.assertEqual(get_platform(), 'win32') # windows XP, amd64 os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Amd64)]') + sys.version = ( + '2.4.4 (#71, Oct 18 2006, 08:34:43) ' '[MSC v.1310 32 bit (Amd64)]' + ) sys.platform = 'win32' self.assertEqual(get_platform(), 'win-amd64') # macbook os.name = 'posix' - sys.version = ('2.5 (r25:51918, Sep 19 2006, 08:49:13) ' - '\n[GCC 4.0.1 (Apple Computer, Inc. build 5341)]') + sys.version = ( + '2.5 (r25:51918, Sep 19 2006, 08:49:13) ' + '\n[GCC 4.0.1 (Apple Computer, Inc. build 5341)]' + ) sys.platform = 'darwin' - self._set_uname(('Darwin', 'macziade', '8.11.1', - ('Darwin Kernel Version 8.11.1: ' + self._set_uname( + ( + 'Darwin', + 'macziade', + '8.11.1', + ( + 'Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' - 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) + 'root:xnu-792.25.20~1/RELEASE_I386' + ), + 'i386', + ) + ) _osx_support._remove_original_values(get_config_vars()) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' - '-fwrapv -O3 -Wall -Wstrict-prototypes') + get_config_vars()['CFLAGS'] = ( + '-fno-strict-aliasing -DNDEBUG -g ' '-fwrapv -O3 -Wall -Wstrict-prototypes' + ) cursize = sys.maxsize - sys.maxsize = (2 ** 31)-1 + sys.maxsize = (2 ** 31) - 1 try: self.assertEqual(get_platform(), 'macosx-10.3-i386') finally: @@ -104,10 +125,12 @@ def test_get_platform(self): # macbook with fat binaries (fat, universal or fat64) _osx_support._remove_original_values(get_config_vars()) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' - get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') + get_config_vars()['CFLAGS'] = ( + '-arch ppc -arch i386 -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk ' + '-fno-strict-aliasing -fno-common ' + '-dynamic -DNDEBUG -g -O3' + ) self.assertEqual(get_platform(), 'macosx-10.4-fat') @@ -115,54 +138,71 @@ def test_get_platform(self): os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.1' self.assertEqual(get_platform(), 'macosx-10.4-fat') - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') + get_config_vars()['CFLAGS'] = ( + '-arch x86_64 -arch i386 -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk ' + '-fno-strict-aliasing -fno-common ' + '-dynamic -DNDEBUG -g -O3' + ) self.assertEqual(get_platform(), 'macosx-10.4-intel') _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') + get_config_vars()['CFLAGS'] = ( + '-arch x86_64 -arch ppc -arch i386 -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk ' + '-fno-strict-aliasing -fno-common ' + '-dynamic -DNDEBUG -g -O3' + ) self.assertEqual(get_platform(), 'macosx-10.4-fat3') _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') + get_config_vars()['CFLAGS'] = ( + '-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk ' + '-fno-strict-aliasing -fno-common ' + '-dynamic -DNDEBUG -g -O3' + ) self.assertEqual(get_platform(), 'macosx-10.4-universal') _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') + get_config_vars()['CFLAGS'] = ( + '-arch x86_64 -arch ppc64 -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk ' + '-fno-strict-aliasing -fno-common ' + '-dynamic -DNDEBUG -g -O3' + ) self.assertEqual(get_platform(), 'macosx-10.4-fat64') for arch in ('ppc', 'i386', 'x86_64', 'ppc64'): _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch %s -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3'%(arch,)) - - self.assertEqual(get_platform(), 'macosx-10.4-%s'%(arch,)) + get_config_vars()['CFLAGS'] = ( + '-arch %s -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk ' + '-fno-strict-aliasing -fno-common ' + '-dynamic -DNDEBUG -g -O3' % (arch,) + ) + self.assertEqual(get_platform(), 'macosx-10.4-%s' % (arch,)) # linux debian sarge os.name = 'posix' - sys.version = ('2.3.5 (#1, Jul 4 2007, 17:28:59) ' - '\n[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)]') + sys.version = ( + '2.3.5 (#1, Jul 4 2007, 17:28:59) ' + '\n[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)]' + ) sys.platform = 'linux2' - self._set_uname(('Linux', 'aglae', '2.6.21.1dedibox-r7', - '#1 Mon Apr 30 17:25:38 CEST 2007', 'i686')) + self._set_uname( + ( + 'Linux', + 'aglae', + '2.6.21.1dedibox-r7', + '#1 Mon Apr 30 17:25:38 CEST 2007', + 'i686', + ) + ) self.assertEqual(get_platform(), 'linux-i686') @@ -171,65 +211,73 @@ def test_get_platform(self): def test_convert_path(self): # linux/mac os.sep = '/' + def _join(path): return '/'.join(path) + os.path.join = _join - self.assertEqual(convert_path('/home/to/my/stuff'), - '/home/to/my/stuff') + self.assertEqual(convert_path('/home/to/my/stuff'), '/home/to/my/stuff') # win os.sep = '\\' + def _join(*path): return '\\'.join(path) + os.path.join = _join self.assertRaises(ValueError, convert_path, '/home/to/my/stuff') self.assertRaises(ValueError, convert_path, 'home/to/my/stuff/') - self.assertEqual(convert_path('home/to/my/stuff'), - 'home\\to\\my\\stuff') - self.assertEqual(convert_path('.'), - os.curdir) + self.assertEqual(convert_path('home/to/my/stuff'), 'home\\to\\my\\stuff') + self.assertEqual(convert_path('.'), os.curdir) def test_change_root(self): # linux/mac os.name = 'posix' + def _isabs(path): return path[0] == '/' + os.path.isabs = _isabs + def _join(*path): return '/'.join(path) + os.path.join = _join - self.assertEqual(change_root('/root', '/old/its/here'), - '/root/old/its/here') - self.assertEqual(change_root('/root', 'its/here'), - '/root/its/here') + self.assertEqual(change_root('/root', '/old/its/here'), '/root/old/its/here') + self.assertEqual(change_root('/root', 'its/here'), '/root/its/here') # windows os.name = 'nt' + def _isabs(path): return path.startswith('c:\\') + os.path.isabs = _isabs + def _splitdrive(path): if path.startswith('c:'): return ('', path.replace('c:', '')) return ('', path) + os.path.splitdrive = _splitdrive + def _join(*path): return '\\'.join(path) + os.path.join = _join - self.assertEqual(change_root('c:\\root', 'c:\\old\\its\\here'), - 'c:\\root\\old\\its\\here') - self.assertEqual(change_root('c:\\root', 'its\\here'), - 'c:\\root\\its\\here') + self.assertEqual( + change_root('c:\\root', 'c:\\old\\its\\here'), 'c:\\root\\old\\its\\here' + ) + self.assertEqual(change_root('c:\\root', 'its\\here'), 'c:\\root\\its\\here') # BugsBunny os (it's a great os) os.name = 'BugsBunny' - self.assertRaises(DistutilsPlatformError, - change_root, 'c:\\root', 'its\\here') + self.assertRaises(DistutilsPlatformError, change_root, 'c:\\root', 'its\\here') # XXX platforms to be covered: mac @@ -250,8 +298,9 @@ def test_check_environ_getpwuid(self): import pwd # only set pw_dir field, other fields are not used - result = pwd.struct_passwd((None, None, None, None, None, - '/home/distutils', None)) + result = pwd.struct_passwd( + (None, None, None, None, None, '/home/distutils', None) + ) with mock.patch.object(pwd, 'getpwuid', return_value=result): check_environ() self.assertEqual(os.environ['HOME'], '/home/distutils') @@ -265,8 +314,10 @@ def test_check_environ_getpwuid(self): self.assertNotIn('HOME', os.environ) def test_split_quoted(self): - self.assertEqual(split_quoted('""one"" "two" \'three\' \\four'), - ['one', 'two', 'three', 'four']) + self.assertEqual( + split_quoted('""one"" "two" \'three\' \\four'), + ['one', 'two', 'three', 'four'], + ) def test_strtobool(self): yes = ('y', 'Y', 'yes', 'True', 't', 'true', 'True', 'On', 'on', '1') @@ -281,8 +332,9 @@ def test_strtobool(self): def test_rfc822_escape(self): header = 'I am a\npoor\nlonesome\nheader\n' res = rfc822_escape(header) - wanted = ('I am a%(8s)spoor%(8s)slonesome%(8s)s' - 'header%(8s)s') % {'8s': '\n'+8*' '} + wanted = ('I am a%(8s)spoor%(8s)slonesome%(8s)s' 'header%(8s)s') % { + '8s': '\n' + 8 * ' ' + } self.assertEqual(res, wanted) def test_dont_write_bytecode(self): @@ -305,5 +357,6 @@ def test_grok_environment_error(self): def test_suite(): return unittest.makeSuite(UtilTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_version.py b/setuptools/_distutils/tests/test_version.py index 8671cd2fc5c..d852a5bef4d 100644 --- a/setuptools/_distutils/tests/test_version.py +++ b/setuptools/_distutils/tests/test_version.py @@ -4,8 +4,8 @@ from distutils.version import StrictVersion from test.support import run_unittest -class VersionTestCase(unittest.TestCase): +class VersionTestCase(unittest.TestCase): def test_prerelease(self): version = StrictVersion('1.2.3a1') self.assertEqual(version.version, (1, 2, 3)) @@ -16,21 +16,23 @@ def test_prerelease(self): self.assertEqual(str(version), '1.2') def test_cmp_strict(self): - versions = (('1.5.1', '1.5.2b2', -1), - ('161', '3.10a', ValueError), - ('8.02', '8.02', 0), - ('3.4j', '1996.07.12', ValueError), - ('3.2.pl0', '3.1.1.6', ValueError), - ('2g6', '11g', ValueError), - ('0.9', '2.2', -1), - ('1.2.1', '1.2', 1), - ('1.1', '1.2.2', -1), - ('1.2', '1.1', 1), - ('1.2.1', '1.2.2', -1), - ('1.2.2', '1.2', 1), - ('1.2', '1.2.2', -1), - ('0.4.0', '0.4', 0), - ('1.13++', '5.5.kw', ValueError)) + versions = ( + ('1.5.1', '1.5.2b2', -1), + ('161', '3.10a', ValueError), + ('8.02', '8.02', 0), + ('3.4j', '1996.07.12', ValueError), + ('3.2.pl0', '3.1.1.6', ValueError), + ('2g6', '11g', ValueError), + ('0.9', '2.2', -1), + ('1.2.1', '1.2', 1), + ('1.1', '1.2.2', -1), + ('1.2', '1.1', 1), + ('1.2.1', '1.2.2', -1), + ('1.2.2', '1.2', 1), + ('1.2', '1.2.2', -1), + ('0.4.0', '0.4', 0), + ('1.13++', '5.5.kw', ValueError), + ) for v1, v2, wanted in versions: try: @@ -39,49 +41,55 @@ def test_cmp_strict(self): if wanted is ValueError: continue else: - raise AssertionError(("cmp(%s, %s) " - "shouldn't raise ValueError") - % (v1, v2)) - self.assertEqual(res, wanted, - 'cmp(%s, %s) should be %s, got %s' % - (v1, v2, wanted, res)) + raise AssertionError( + ("cmp(%s, %s) " "shouldn't raise ValueError") % (v1, v2) + ) + self.assertEqual( + res, wanted, 'cmp(%s, %s) should be %s, got %s' % (v1, v2, wanted, res) + ) res = StrictVersion(v1)._cmp(v2) - self.assertEqual(res, wanted, - 'cmp(%s, %s) should be %s, got %s' % - (v1, v2, wanted, res)) + self.assertEqual( + res, wanted, 'cmp(%s, %s) should be %s, got %s' % (v1, v2, wanted, res) + ) res = StrictVersion(v1)._cmp(object()) - self.assertIs(res, NotImplemented, - 'cmp(%s, %s) should be NotImplemented, got %s' % - (v1, v2, res)) - + self.assertIs( + res, + NotImplemented, + 'cmp(%s, %s) should be NotImplemented, got %s' % (v1, v2, res), + ) def test_cmp(self): - versions = (('1.5.1', '1.5.2b2', -1), - ('161', '3.10a', 1), - ('8.02', '8.02', 0), - ('3.4j', '1996.07.12', -1), - ('3.2.pl0', '3.1.1.6', 1), - ('2g6', '11g', -1), - ('0.960923', '2.2beta29', -1), - ('1.13++', '5.5.kw', -1)) - + versions = ( + ('1.5.1', '1.5.2b2', -1), + ('161', '3.10a', 1), + ('8.02', '8.02', 0), + ('3.4j', '1996.07.12', -1), + ('3.2.pl0', '3.1.1.6', 1), + ('2g6', '11g', -1), + ('0.960923', '2.2beta29', -1), + ('1.13++', '5.5.kw', -1), + ) for v1, v2, wanted in versions: res = LooseVersion(v1)._cmp(LooseVersion(v2)) - self.assertEqual(res, wanted, - 'cmp(%s, %s) should be %s, got %s' % - (v1, v2, wanted, res)) + self.assertEqual( + res, wanted, 'cmp(%s, %s) should be %s, got %s' % (v1, v2, wanted, res) + ) res = LooseVersion(v1)._cmp(v2) - self.assertEqual(res, wanted, - 'cmp(%s, %s) should be %s, got %s' % - (v1, v2, wanted, res)) + self.assertEqual( + res, wanted, 'cmp(%s, %s) should be %s, got %s' % (v1, v2, wanted, res) + ) res = LooseVersion(v1)._cmp(object()) - self.assertIs(res, NotImplemented, - 'cmp(%s, %s) should be NotImplemented, got %s' % - (v1, v2, res)) + self.assertIs( + res, + NotImplemented, + 'cmp(%s, %s) should be NotImplemented, got %s' % (v1, v2, res), + ) + def test_suite(): return unittest.makeSuite(VersionTestCase) + if __name__ == "__main__": run_unittest(test_suite()) diff --git a/setuptools/_distutils/tests/test_versionpredicate.py b/setuptools/_distutils/tests/test_versionpredicate.py index 28ae09dc205..ce3d0f46e05 100644 --- a/setuptools/_distutils/tests/test_versionpredicate.py +++ b/setuptools/_distutils/tests/test_versionpredicate.py @@ -6,8 +6,10 @@ import doctest from test.support import run_unittest + def test_suite(): return doctest.DocTestSuite(distutils.versionpredicate) + if __name__ == '__main__': run_unittest(test_suite()) diff --git a/setuptools/_distutils/text_file.py b/setuptools/_distutils/text_file.py index 93abad38f43..015d68027cb 100644 --- a/setuptools/_distutils/text_file.py +++ b/setuptools/_distutils/text_file.py @@ -9,79 +9,82 @@ class TextFile: """Provides a file-like object that takes care of all the things you - commonly want to do when processing a text file that has some - line-by-line syntax: strip comments (as long as "#" is your - comment character), skip blank lines, join adjacent lines by - escaping the newline (ie. backslash at end of line), strip - leading and/or trailing whitespace. All of these are optional - and independently controllable. - - Provides a 'warn()' method so you can generate warning messages that - report physical line number, even if the logical line in question - spans multiple physical lines. Also provides 'unreadline()' for - implementing line-at-a-time lookahead. - - Constructor is called as: - - TextFile (filename=None, file=None, **options) - - It bombs (RuntimeError) if both 'filename' and 'file' are None; - 'filename' should be a string, and 'file' a file object (or - something that provides 'readline()' and 'close()' methods). It is - recommended that you supply at least 'filename', so that TextFile - can include it in warning messages. If 'file' is not supplied, - TextFile creates its own using 'io.open()'. - - The options are all boolean, and affect the value returned by - 'readline()': - strip_comments [default: true] - strip from "#" to end-of-line, as well as any whitespace - leading up to the "#" -- unless it is escaped by a backslash - lstrip_ws [default: false] - strip leading whitespace from each line before returning it - rstrip_ws [default: true] - strip trailing whitespace (including line terminator!) from - each line before returning it - skip_blanks [default: true} - skip lines that are empty *after* stripping comments and - whitespace. (If both lstrip_ws and rstrip_ws are false, - then some lines may consist of solely whitespace: these will - *not* be skipped, even if 'skip_blanks' is true.) - join_lines [default: false] - if a backslash is the last non-newline character on a line - after stripping comments and whitespace, join the following line - to it to form one "logical line"; if N consecutive lines end - with a backslash, then N+1 physical lines will be joined to - form one logical line. - collapse_join [default: false] - strip leading whitespace from lines that are joined to their - predecessor; only matters if (join_lines and not lstrip_ws) - errors [default: 'strict'] - error handler used to decode the file content - - Note that since 'rstrip_ws' can strip the trailing newline, the - semantics of 'readline()' must differ from those of the builtin file - object's 'readline()' method! In particular, 'readline()' returns - None for end-of-file: an empty string might just be a blank line (or - an all-whitespace line), if 'rstrip_ws' is true but 'skip_blanks' is - not.""" - - default_options = { 'strip_comments': 1, - 'skip_blanks': 1, - 'lstrip_ws': 0, - 'rstrip_ws': 1, - 'join_lines': 0, - 'collapse_join': 0, - 'errors': 'strict', - } + commonly want to do when processing a text file that has some + line-by-line syntax: strip comments (as long as "#" is your + comment character), skip blank lines, join adjacent lines by + escaping the newline (ie. backslash at end of line), strip + leading and/or trailing whitespace. All of these are optional + and independently controllable. + + Provides a 'warn()' method so you can generate warning messages that + report physical line number, even if the logical line in question + spans multiple physical lines. Also provides 'unreadline()' for + implementing line-at-a-time lookahead. + + Constructor is called as: + + TextFile (filename=None, file=None, **options) + + It bombs (RuntimeError) if both 'filename' and 'file' are None; + 'filename' should be a string, and 'file' a file object (or + something that provides 'readline()' and 'close()' methods). It is + recommended that you supply at least 'filename', so that TextFile + can include it in warning messages. If 'file' is not supplied, + TextFile creates its own using 'io.open()'. + + The options are all boolean, and affect the value returned by + 'readline()': + strip_comments [default: true] + strip from "#" to end-of-line, as well as any whitespace + leading up to the "#" -- unless it is escaped by a backslash + lstrip_ws [default: false] + strip leading whitespace from each line before returning it + rstrip_ws [default: true] + strip trailing whitespace (including line terminator!) from + each line before returning it + skip_blanks [default: true} + skip lines that are empty *after* stripping comments and + whitespace. (If both lstrip_ws and rstrip_ws are false, + then some lines may consist of solely whitespace: these will + *not* be skipped, even if 'skip_blanks' is true.) + join_lines [default: false] + if a backslash is the last non-newline character on a line + after stripping comments and whitespace, join the following line + to it to form one "logical line"; if N consecutive lines end + with a backslash, then N+1 physical lines will be joined to + form one logical line. + collapse_join [default: false] + strip leading whitespace from lines that are joined to their + predecessor; only matters if (join_lines and not lstrip_ws) + errors [default: 'strict'] + error handler used to decode the file content + + Note that since 'rstrip_ws' can strip the trailing newline, the + semantics of 'readline()' must differ from those of the builtin file + object's 'readline()' method! In particular, 'readline()' returns + None for end-of-file: an empty string might just be a blank line (or + an all-whitespace line), if 'rstrip_ws' is true but 'skip_blanks' is + not.""" + + default_options = { + 'strip_comments': 1, + 'skip_blanks': 1, + 'lstrip_ws': 0, + 'rstrip_ws': 1, + 'join_lines': 0, + 'collapse_join': 0, + 'errors': 'strict', + } def __init__(self, filename=None, file=None, **options): """Construct a new TextFile object. At least one of 'filename' - (a string) and 'file' (a file-like object) must be supplied. - They keyword argument options are described above and affect - the values returned by 'readline()'.""" + (a string) and 'file' (a file-like object) must be supplied. + They keyword argument options are described above and affect + the values returned by 'readline()'.""" if filename is None and file is None: - raise RuntimeError("you must supply either or both of 'filename' and 'file'") + raise RuntimeError( + "you must supply either or both of 'filename' and 'file'" + ) # set values for all options -- either from client option hash # or fallback to default_options @@ -101,7 +104,7 @@ def __init__(self, filename=None, file=None, **options): else: self.filename = filename self.file = file - self.current_line = 0 # assuming that file is at BOF! + self.current_line = 0 # assuming that file is at BOF! # 'linebuf' is a stack of lines that will be emptied before we # actually read from the file; it's only populated by an @@ -110,14 +113,14 @@ def __init__(self, filename=None, file=None, **options): def open(self, filename): """Open a new file named 'filename'. This overrides both the - 'filename' and 'file' arguments to the constructor.""" + 'filename' and 'file' arguments to the constructor.""" self.filename = filename self.file = io.open(self.filename, 'r', errors=self.errors) self.current_line = 0 def close(self): """Close the current file and forget everything we know about it - (filename, current line number).""" + (filename, current line number).""" file = self.file self.file = None self.filename = None @@ -141,24 +144,24 @@ def error(self, msg, line=None): def warn(self, msg, line=None): """Print (to stderr) a warning message tied to the current logical - line in the current file. If the current logical line in the - file spans multiple physical lines, the warning refers to the - whole range, eg. "lines 3-5". If 'line' supplied, it overrides - the current line number; it may be a list or tuple to indicate a - range of physical lines, or an integer for a single physical - line.""" + line in the current file. If the current logical line in the + file spans multiple physical lines, the warning refers to the + whole range, eg. "lines 3-5". If 'line' supplied, it overrides + the current line number; it may be a list or tuple to indicate a + range of physical lines, or an integer for a single physical + line.""" sys.stderr.write("warning: " + self.gen_error(msg, line) + "\n") def readline(self): """Read and return a single logical line from the current file (or - from an internal buffer if lines have previously been "unread" - with 'unreadline()'). If the 'join_lines' option is true, this - may involve reading multiple physical lines concatenated into a - single string. Updates the current line number, so calling - 'warn()' after 'readline()' emits a warning about the physical - line(s) just read. Returns None on end-of-file, since the empty - string can occur if 'rstrip_ws' is true but 'strip_blanks' is - not.""" + from an internal buffer if lines have previously been "unread" + with 'unreadline()'). If the 'join_lines' option is true, this + may involve reading multiple physical lines concatenated into a + single string. Updates the current line number, so calling + 'warn()' after 'readline()' emits a warning about the physical + line(s) just read. Returns None on end-of-file, since the empty + string can occur if 'rstrip_ws' is true but 'strip_blanks' is + not.""" # If any "unread" lines waiting in 'linebuf', return the top # one. (We don't actually buffer read-ahead data -- lines only # get put in 'linebuf' if the client explicitly does an @@ -187,12 +190,12 @@ def readline(self): # lurking in there) and otherwise leave the line alone. pos = line.find("#") - if pos == -1: # no "#" -- no comments + if pos == -1: # no "#" -- no comments pass # It's definitely a comment -- either "#" is the first # character, or it's elsewhere and unescaped. - elif pos == 0 or line[pos-1] != "\\": + elif pos == 0 or line[pos - 1] != "\\": # Have to preserve the trailing newline, because it's # the job of a later step (rstrip_ws) to remove it -- # and if rstrip_ws is false, we'd better preserve it! @@ -211,15 +214,14 @@ def readline(self): # result in "hello there". if line.strip() == "": continue - else: # it's an escaped "#" + else: # it's an escaped "#" line = line.replace("\\#", "#") # did previous line end with a backslash? then accumulate if self.join_lines and buildup_line: # oops: end of file if line is None: - self.warn("continuation line immediately precedes " - "end-of-file") + self.warn("continuation line immediately precedes " "end-of-file") return buildup_line if self.collapse_join: @@ -230,11 +232,10 @@ def readline(self): if isinstance(self.current_line, list): self.current_line[1] = self.current_line[1] + 1 else: - self.current_line = [self.current_line, - self.current_line + 1] + self.current_line = [self.current_line, self.current_line + 1] # just an ordinary line, read it as usual else: - if line is None: # eof + if line is None: # eof return None # still have to be careful about incrementing the line number! @@ -271,7 +272,7 @@ def readline(self): def readlines(self): """Read and return the list of all logical lines remaining in the - current file.""" + current file.""" lines = [] while True: line = self.readline() @@ -281,6 +282,6 @@ def readlines(self): def unreadline(self, line): """Push 'line' (a string) onto an internal buffer that will be - checked by future 'readline()' calls. Handy for implementing - a parser with line-at-a-time lookahead.""" + checked by future 'readline()' calls. Handy for implementing + a parser with line-at-a-time lookahead.""" self.linebuf.append(line) diff --git a/setuptools/_distutils/unixccompiler.py b/setuptools/_distutils/unixccompiler.py index f51977a5ae4..f30c5322dc2 100644 --- a/setuptools/_distutils/unixccompiler.py +++ b/setuptools/_distutils/unixccompiler.py @@ -17,10 +17,8 @@ from distutils import sysconfig from distutils.dep_util import newer -from distutils.ccompiler import \ - CCompiler, gen_preprocess_options, gen_lib_options -from distutils.errors import \ - DistutilsExecError, CompileError, LibError, LinkError +from distutils.ccompiler import CCompiler, gen_preprocess_options, gen_lib_options +from distutils.errors import DistutilsExecError, CompileError, LibError, LinkError from distutils import log if sys.platform == 'darwin': @@ -52,15 +50,16 @@ class UnixCCompiler(CCompiler): # are pretty generic; they will probably have to be set by an outsider # (eg. using information discovered by the sysconfig about building # Python extensions). - executables = {'preprocessor' : None, - 'compiler' : ["cc"], - 'compiler_so' : ["cc"], - 'compiler_cxx' : ["cc"], - 'linker_so' : ["cc", "-shared"], - 'linker_exe' : ["cc"], - 'archiver' : ["ar", "-cr"], - 'ranlib' : None, - } + executables = { + 'preprocessor': None, + 'compiler': ["cc"], + 'compiler_so': ["cc"], + 'compiler_cxx': ["cc"], + 'linker_so': ["cc", "-shared"], + 'linker_exe': ["cc"], + 'archiver': ["ar", "-cr"], + 'ranlib': None, + } if sys.platform[:6] == "darwin": executables['ranlib'] = ["ranlib"] @@ -71,7 +70,7 @@ class UnixCCompiler(CCompiler): # reasonable common default here, but it's not necessarily used on all # Unices! - src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] + src_extensions = [".c", ".C", ".cc", ".cxx", ".cpp", ".m"] obj_extension = ".o" static_lib_extension = ".a" shared_lib_extension = ".so" @@ -82,8 +81,15 @@ class UnixCCompiler(CCompiler): if sys.platform == "cygwin": exe_extension = ".exe" - def preprocess(self, source, output_file=None, macros=None, - include_dirs=None, extra_preargs=None, extra_postargs=None): + def preprocess( + self, + source, + output_file=None, + macros=None, + include_dirs=None, + extra_preargs=None, + extra_postargs=None, + ): fixed_args = self._fix_compile_args(None, macros, include_dirs) ignore, macros, include_dirs = fixed_args pp_opts = gen_preprocess_options(macros, include_dirs) @@ -111,26 +117,24 @@ def preprocess(self, source, output_file=None, macros=None, def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): compiler_so = self.compiler_so if sys.platform == 'darwin': - compiler_so = _osx_support.compiler_fixup(compiler_so, - cc_args + extra_postargs) + compiler_so = _osx_support.compiler_fixup( + compiler_so, cc_args + extra_postargs + ) try: - self.spawn(compiler_so + cc_args + [src, '-o', obj] + - extra_postargs) + self.spawn(compiler_so + cc_args + [src, '-o', obj] + extra_postargs) except DistutilsExecError as msg: raise CompileError(msg) - def create_static_lib(self, objects, output_libname, - output_dir=None, debug=0, target_lang=None): + def create_static_lib( + self, objects, output_libname, output_dir=None, debug=0, target_lang=None + ): objects, output_dir = self._fix_object_args(objects, output_dir) - output_filename = \ - self.library_filename(output_libname, output_dir=output_dir) + output_filename = self.library_filename(output_libname, output_dir=output_dir) if self._need_link(objects, output_filename): self.mkpath(os.path.dirname(output_filename)) - self.spawn(self.archiver + - [output_filename] + - objects + self.objects) + self.spawn(self.archiver + [output_filename] + objects + self.objects) # Not many Unices required ranlib anymore -- SunOS 4.x is, I # think the only major Unix that does. Maybe we need some @@ -145,26 +149,34 @@ def create_static_lib(self, objects, output_libname, else: log.debug("skipping %s (up-to-date)", output_filename) - def link(self, target_desc, objects, - output_filename, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, - export_symbols=None, debug=0, extra_preargs=None, - extra_postargs=None, build_temp=None, target_lang=None): + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): objects, output_dir = self._fix_object_args(objects, output_dir) - fixed_args = self._fix_lib_args(libraries, library_dirs, - runtime_library_dirs) + fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) libraries, library_dirs, runtime_library_dirs = fixed_args - lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, - libraries) + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries) if not isinstance(output_dir, (str, type(None))): raise TypeError("'output_dir' must be a string or None") if output_dir is not None: output_filename = os.path.join(output_dir, output_filename) if self._need_link(objects, output_filename): - ld_args = (objects + self.objects + - lib_opts + ['-o', output_filename]) + ld_args = objects + self.objects + lib_opts + ['-o', output_filename] if debug: ld_args[:0] = ['-g'] if extra_preargs: @@ -196,7 +208,7 @@ def link(self, target_desc, objects, else: offset = 0 - linker[i+offset] = self.compiler_cxx[i] + linker[i + offset] = self.compiler_cxx[i] if sys.platform == 'darwin': linker = _osx_support.compiler_fixup(linker, ld_args) @@ -234,10 +246,11 @@ def runtime_library_dir_option(self, dir): compiler = os.path.basename(sysconfig.get_config_var("CC")) if sys.platform[:6] == "darwin": from distutils.util import get_macosx_target_ver, split_version + macosx_target_ver = get_macosx_target_ver() if macosx_target_ver and split_version(macosx_target_ver) >= [10, 5]: return "-Wl,-rpath," + dir - else: # no support for -rpath on earlier macOS versions + else: # no support for -rpath on earlier macOS versions return "-L" + dir elif sys.platform[:7] == "freebsd": return "-Wl,-rpath=" + dir @@ -298,8 +311,6 @@ def find_library_file(self, dirs, lib, debug=0): else: sysroot = m.group(1) - - for dir in dirs: shared = os.path.join(dir, shared_f) dylib = os.path.join(dir, dylib_f) @@ -307,8 +318,9 @@ def find_library_file(self, dirs, lib, debug=0): xcode_stub = os.path.join(dir, xcode_stub_f) if sys.platform == 'darwin' and ( - dir.startswith('/System/') or ( - dir.startswith('/usr/') and not dir.startswith('/usr/local/'))): + dir.startswith('/System/') + or (dir.startswith('/usr/') and not dir.startswith('/usr/local/')) + ): shared = os.path.join(sysroot, dir[1:], shared_f) dylib = os.path.join(sysroot, dir[1:], dylib_f) diff --git a/setuptools/_distutils/util.py b/setuptools/_distutils/util.py index 4232fd21a2a..5ad060ec871 100644 --- a/setuptools/_distutils/util.py +++ b/setuptools/_distutils/util.py @@ -69,67 +69,77 @@ def get_host_platform(): # At least on Linux/Intel, 'machine' is the processor -- # i386, etc. # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) + return "%s-%s" % (osname, machine) elif osname[:5] == "sunos": - if release[0] >= "5": # SunOS 5 == Solaris 2 + if release[0] >= "5": # SunOS 5 == Solaris 2 osname = "solaris" release = "%d.%s" % (int(release[0]) - 3, release[2:]) # We can't use "platform.architecture()[0]" because a # bootstrap problem. We use a dict to get an error # if some suspicious happens. - bitness = {2147483647:"32bit", 9223372036854775807:"64bit"} + bitness = {2147483647: "32bit", 9223372036854775807: "64bit"} machine += ".%s" % bitness[sys.maxsize] # fall through to standard osname-release-machine representation elif osname[:3] == "aix": from .py38compat import aix_platform + return aix_platform(osname, version, release) elif osname[:6] == "cygwin": osname = "cygwin" - rel_re = re.compile (r'[\d.]+', re.ASCII) + rel_re = re.compile(r'[\d.]+', re.ASCII) m = rel_re.match(release) if m: release = m.group() elif osname[:6] == "darwin": import _osx_support, distutils.sysconfig + osname, release, machine = _osx_support.get_platform_osx( - distutils.sysconfig.get_config_vars(), - osname, release, machine) + distutils.sysconfig.get_config_vars(), osname, release, machine + ) return "%s-%s-%s" % (osname, release, machine) + def get_platform(): if os.name == 'nt': TARGET_TO_PLAT = { - 'x86' : 'win32', - 'x64' : 'win-amd64', - 'arm' : 'win-arm32', + 'x86': 'win32', + 'x64': 'win-amd64', + 'arm': 'win-arm32', 'arm64': 'win-arm64', } - return TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) or get_host_platform() + return ( + TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) + or get_host_platform() + ) else: return get_host_platform() if sys.platform == 'darwin': - _syscfg_macosx_ver = None # cache the version pulled from sysconfig + _syscfg_macosx_ver = None # cache the version pulled from sysconfig MACOSX_VERSION_VAR = 'MACOSX_DEPLOYMENT_TARGET' + def _clear_cached_macosx_ver(): """For testing only. Do not call.""" global _syscfg_macosx_ver _syscfg_macosx_ver = None + def get_macosx_target_ver_from_syscfg(): """Get the version of macOS latched in the Python interpreter configuration. Returns the version as a string or None if can't obtain one. Cached.""" global _syscfg_macosx_ver if _syscfg_macosx_ver is None: from distutils import sysconfig + ver = sysconfig.get_config_var(MACOSX_VERSION_VAR) or '' if ver: _syscfg_macosx_ver = ver return _syscfg_macosx_ver + def get_macosx_target_ver(): """Return the version of macOS for which we are building. @@ -147,12 +157,16 @@ def get_macosx_target_ver(): # ensures extension modules are built with correct compatibility # values, specifically LDSHARED which can use # '-undefined dynamic_lookup' which only works on >= 10.3. - if syscfg_ver and split_version(syscfg_ver) >= [10, 3] and \ - split_version(env_ver) < [10, 3]: - my_msg = ('$' + MACOSX_VERSION_VAR + ' mismatch: ' - 'now "%s" but "%s" during configure; ' - 'must use 10.3 or later' - % (env_ver, syscfg_ver)) + if ( + syscfg_ver + and split_version(syscfg_ver) >= [10, 3] + and split_version(env_ver) < [10, 3] + ): + my_msg = ( + '$' + MACOSX_VERSION_VAR + ' mismatch: ' + 'now "%s" but "%s" during configure; ' + 'must use 10.3 or later' % (env_ver, syscfg_ver) + ) raise DistutilsPlatformError(my_msg) return env_ver return syscfg_ver @@ -163,7 +177,7 @@ def split_version(s): return [int(n) for n in s.split('.')] -def convert_path (pathname): +def convert_path(pathname): """Return 'pathname' as a name that will work on the native filesystem, i.e. split it on '/' and put it back together again using the current directory separator. Needed because filenames in the setup script are @@ -188,10 +202,11 @@ def convert_path (pathname): return os.curdir return os.path.join(*paths) + # convert_path () -def change_root (new_root, pathname): +def change_root(new_root, pathname): """Return 'pathname' with 'new_root' prepended. If 'pathname' is relative, this is equivalent to "os.path.join(new_root,pathname)". Otherwise, it requires making 'pathname' relative and then joining the @@ -214,7 +229,9 @@ def change_root (new_root, pathname): _environ_checked = 0 -def check_environ (): + + +def check_environ(): """Ensure that 'os.environ' has all the environment variables we guarantee that users can use in config files, command-line options, etc. Currently this includes: @@ -229,6 +246,7 @@ def check_environ (): if os.name == 'posix' and 'HOME' not in os.environ: try: import pwd + os.environ['HOME'] = pwd.getpwuid(os.getuid())[5] except (ImportError, KeyError): # bpo-10496: if the current user identifier doesn't exist in the @@ -241,7 +259,7 @@ def check_environ (): _environ_checked = 1 -def subst_vars (s, local_vars): +def subst_vars(s, local_vars): """Perform shell/Perl-style variable substitution on 'string'. Every occurrence of '$' followed by a name is considered a variable, and variable is substituted by the value found in the 'local_vars' @@ -251,7 +269,8 @@ def subst_vars (s, local_vars): variables not found in either 'local_vars' or 'os.environ'. """ check_environ() - def _subst (match, local_vars=local_vars): + + def _subst(match, local_vars=local_vars): var_name = match.group(1) if var_name in local_vars: return str(local_vars[var_name]) @@ -263,10 +282,11 @@ def _subst (match, local_vars=local_vars): except KeyError as var: raise ValueError("invalid variable '$%s'" % var) + # subst_vars () -def grok_environment_error (exc, prefix="error: "): +def grok_environment_error(exc, prefix="error: "): # Function kept for backward compatibility. # Used to try clever things with EnvironmentErrors, # but nowadays str(exception) produces good messages. @@ -275,13 +295,16 @@ def grok_environment_error (exc, prefix="error: "): # Needed by 'split_quoted()' _wordchars_re = _squote_re = _dquote_re = None + + def _init_regex(): global _wordchars_re, _squote_re, _dquote_re _wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace) _squote_re = re.compile(r"'(?:[^'\\]|\\.)*'") _dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"') -def split_quoted (s): + +def split_quoted(s): """Split a string up according to Unix shell-like rules for quotes and backslashes. In short: words are delimited by spaces, as long as those spaces are not escaped by a backslash, or inside a quoted string. @@ -295,7 +318,8 @@ def split_quoted (s): # This is a nice algorithm for splitting up a single string, since it # doesn't require character-by-character examination. It was a little # bit of a brain-bender to get it working right, though... - if _wordchars_re is None: _init_regex() + if _wordchars_re is None: + _init_regex() s = s.strip() words = [] @@ -308,20 +332,20 @@ def split_quoted (s): words.append(s[:end]) break - if s[end] in string.whitespace: # unescaped, unquoted whitespace: now - words.append(s[:end]) # we definitely have a word delimiter + if s[end] in string.whitespace: # unescaped, unquoted whitespace: now + words.append(s[:end]) # we definitely have a word delimiter s = s[end:].lstrip() pos = 0 - elif s[end] == '\\': # preserve whatever is being escaped; - # will become part of the current word - s = s[:end] + s[end+1:] - pos = end+1 + elif s[end] == '\\': # preserve whatever is being escaped; + # will become part of the current word + s = s[:end] + s[end + 1 :] + pos = end + 1 else: - if s[end] == "'": # slurp singly-quoted string + if s[end] == "'": # slurp singly-quoted string m = _squote_re.match(s, end) - elif s[end] == '"': # slurp doubly-quoted string + elif s[end] == '"': # slurp doubly-quoted string m = _dquote_re.match(s, end) else: raise RuntimeError("this can't happen (bad char '%c')" % s[end]) @@ -330,7 +354,7 @@ def split_quoted (s): raise ValueError("bad string (mismatched %s quotes?)" % s[end]) (beg, end) = m.span() - s = s[:beg] + s[beg+1:end-1] + s[end:] + s = s[:beg] + s[beg + 1 : end - 1] + s[end:] pos = m.end() - 2 if pos >= len(s): @@ -339,10 +363,11 @@ def split_quoted (s): return words + # split_quoted () -def execute (func, args, msg=None, verbose=0, dry_run=0): +def execute(func, args, msg=None, verbose=0, dry_run=0): """Perform some action that affects the outside world (eg. by writing to the filesystem). Such actions are special because they are disabled by the 'dry_run' flag. This method takes care of all @@ -353,7 +378,7 @@ def execute (func, args, msg=None, verbose=0, dry_run=0): """ if msg is None: msg = "%s%r" % (func.__name__, args) - if msg[-2:] == ',)': # correct for singleton tuple + if msg[-2:] == ',)': # correct for singleton tuple msg = msg[0:-2] + ')' log.info(msg) @@ -361,7 +386,7 @@ def execute (func, args, msg=None, verbose=0, dry_run=0): func(*args) -def strtobool (val): +def strtobool(val): """Convert a string representation of truth to true (1) or false (0). True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values @@ -377,11 +402,16 @@ def strtobool (val): raise ValueError("invalid truth value %r" % (val,)) -def byte_compile (py_files, - optimize=0, force=0, - prefix=None, base_dir=None, - verbose=1, dry_run=0, - direct=None): +def byte_compile( + py_files, + optimize=0, + force=0, + prefix=None, + base_dir=None, + verbose=1, + dry_run=0, + direct=None, +): """Byte-compile a collection of Python source files to .pyc files in a __pycache__ subdirectory. 'py_files' is a list of files to compile; any files that don't end in ".py" are silently @@ -430,16 +460,18 @@ def byte_compile (py_files, # optimize mode, or if either optimization level was requested by # the caller. if direct is None: - direct = (__debug__ and optimize == 0) + direct = __debug__ and optimize == 0 # "Indirect" byte-compilation: write a temporary script and then # run it with the appropriate flags. if not direct: try: from tempfile import mkstemp + (script_fd, script_name) = mkstemp(".py") except ImportError: from tempfile import mktemp + (script_fd, script_name) = None, mktemp(".py") log.info("writing byte-compilation script '%s'", script_name) if not dry_run: @@ -449,10 +481,12 @@ def byte_compile (py_files, script = open(script_name, "w") with script: - script.write("""\ + script.write( + """\ from distutils.util import byte_compile files = [ -""") +""" + ) # XXX would be nice to write absolute filenames, just for # safety's sake (script should be more robust in the face of @@ -464,24 +498,26 @@ def byte_compile (py_files, # problem is that it's really a directory, but I'm treating it # as a dumb string, so trailing slashes and so forth matter. - #py_files = map(os.path.abspath, py_files) - #if prefix: + # py_files = map(os.path.abspath, py_files) + # if prefix: # prefix = os.path.abspath(prefix) script.write(",\n".join(map(repr, py_files)) + "]\n") - script.write(""" + script.write( + """ byte_compile(files, optimize=%r, force=%r, prefix=%r, base_dir=%r, verbose=%r, dry_run=0, direct=1) -""" % (optimize, force, prefix, base_dir, verbose)) +""" + % (optimize, force, prefix, base_dir, verbose) + ) cmd = [sys.executable] cmd.extend(_optim_args_from_interpreter_flags()) cmd.append(script_name) spawn(cmd, dry_run=dry_run) - execute(os.remove, (script_name,), "removing %s" % script_name, - dry_run=dry_run) + execute(os.remove, (script_name,), "removing %s" % script_name, dry_run=dry_run) # "Direct" byte-compilation: use the py_compile module to compile # right here, right now. Note that the script generated in indirect @@ -501,16 +537,17 @@ def byte_compile (py_files, # dfile - purported source filename (same as 'file' by default) if optimize >= 0: opt = '' if optimize == 0 else optimize - cfile = importlib.util.cache_from_source( - file, optimization=opt) + cfile = importlib.util.cache_from_source(file, optimization=opt) else: cfile = importlib.util.cache_from_source(file) dfile = file if prefix: - if file[:len(prefix)] != prefix: - raise ValueError("invalid prefix: filename %r doesn't start with %r" - % (file, prefix)) - dfile = dfile[len(prefix):] + if file[: len(prefix)] != prefix: + raise ValueError( + "invalid prefix: filename %r doesn't start with %r" + % (file, prefix) + ) + dfile = dfile[len(prefix) :] if base_dir: dfile = os.path.join(base_dir, dfile) @@ -521,12 +558,13 @@ def byte_compile (py_files, if not dry_run: compile(file, cfile, dfile) else: - log.debug("skipping byte-compilation of %s to %s", - file, cfile_base) + log.debug("skipping byte-compilation of %s to %s", file, cfile_base) + # byte_compile () -def rfc822_escape (header): + +def rfc822_escape(header): """Return a version of the string escaped for inclusion in an RFC-822 header, by ensuring there are 8 spaces space after each newline. """ @@ -534,8 +572,10 @@ def rfc822_escape (header): sep = '\n' + 8 * ' ' return sep.join(lines) + # 2to3 support + def run_2to3(files, fixer_names=None, options=None, explicit=None): """Invoke 2to3 on a list of Python files. The files should all come from the build area, as the @@ -548,6 +588,7 @@ def run_2to3(files, fixer_names=None, options=None, explicit=None): # Make this class local, to delay import of 2to3 from lib2to3.refactor import RefactoringTool, get_fixers_from_package + class DistutilsRefactoringTool(RefactoringTool): def log_error(self, msg, *args, **kw): log.error(msg, *args) @@ -563,8 +604,10 @@ def log_debug(self, msg, *args): r = DistutilsRefactoringTool(fixer_names, options=options) r.refactor(files, write=True) -def copydir_run_2to3(src, dest, template=None, fixer_names=None, - options=None, explicit=None): + +def copydir_run_2to3( + src, dest, template=None, fixer_names=None, options=None, explicit=None +): """Recursively copy a directory, only copying new and changed files, running run_2to3 over all newly copied Python modules afterward. @@ -573,6 +616,7 @@ def copydir_run_2to3(src, dest, template=None, fixer_names=None, from distutils.dir_util import mkpath from distutils.file_util import copy_file from distutils.filelist import FileList + filelist = FileList() curdir = os.getcwd() os.chdir(src) @@ -584,23 +628,30 @@ def copydir_run_2to3(src, dest, template=None, fixer_names=None, if template: for line in template.splitlines(): line = line.strip() - if not line: continue + if not line: + continue filelist.process_template_line(line) copied = [] for filename in filelist.files: outname = os.path.join(dest, filename) mkpath(os.path.dirname(outname)) res = copy_file(os.path.join(src, filename), outname, update=1) - if res[1]: copied.append(outname) - run_2to3([fn for fn in copied if fn.lower().endswith('.py')], - fixer_names=fixer_names, options=options, explicit=explicit) + if res[1]: + copied.append(outname) + run_2to3( + [fn for fn in copied if fn.lower().endswith('.py')], + fixer_names=fixer_names, + options=options, + explicit=explicit, + ) return copied + class Mixin2to3: - '''Mixin class for commands that run 2to3. + """Mixin class for commands that run 2to3. To configure 2to3, setup scripts may either change the class variables, or inherit from individual commands - to override how 2to3 is invoked.''' + to override how 2to3 is invoked.""" # provide list of fixers to run; # defaults to all from lib2to3.fixers diff --git a/setuptools/_distutils/version.py b/setuptools/_distutils/version.py index c33bebaed26..9074c1f5975 100644 --- a/setuptools/_distutils/version.py +++ b/setuptools/_distutils/version.py @@ -28,6 +28,7 @@ import re + class Version: """Abstract base class for version numbering classes. Just provides constructor (__init__) and reproducer (__repr__), because those @@ -35,11 +36,11 @@ class Version: rich comparisons to _cmp. """ - def __init__ (self, vstring=None): + def __init__(self, vstring=None): if vstring: self.parse(vstring) - def __repr__ (self): + def __repr__(self): return "%s ('%s')" % (self.__class__.__name__, str(self)) def __eq__(self, other): @@ -90,7 +91,7 @@ def __ge__(self, other): # instance of your version class) -class StrictVersion (Version): +class StrictVersion(Version): """Version numbering for anal retentives and software idealists. Implements the standard interface for version number classes as @@ -127,17 +128,16 @@ class StrictVersion (Version): in the distutils documentation. """ - version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', - re.VERBOSE | re.ASCII) - + version_re = re.compile( + r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', re.VERBOSE | re.ASCII + ) - def parse (self, vstring): + def parse(self, vstring): match = self.version_re.match(vstring) if not match: raise ValueError("invalid version number '%s'" % vstring) - (major, minor, patch, prerelease, prerelease_num) = \ - match.group(1, 2, 4, 5, 6) + (major, minor, patch, prerelease, prerelease_num) = match.group(1, 2, 4, 5, 6) if patch: self.version = tuple(map(int, [major, minor, patch])) @@ -149,8 +149,7 @@ def parse (self, vstring): else: self.prerelease = None - - def __str__ (self): + def __str__(self): if self.version[2] == 0: vstring = '.'.join(map(str, self.version[0:2])) @@ -162,8 +161,7 @@ def __str__ (self): return vstring - - def _cmp (self, other): + def _cmp(self, other): if isinstance(other, str): other = StrictVersion(other) elif not isinstance(other, StrictVersion): @@ -183,13 +181,13 @@ def _cmp (self, other): # case 3: self doesn't have prerelease, other does: self is greater # case 4: both have prerelease: must compare them! - if (not self.prerelease and not other.prerelease): + if not self.prerelease and not other.prerelease: return 0 - elif (self.prerelease and not other.prerelease): + elif self.prerelease and not other.prerelease: return -1 - elif (not self.prerelease and other.prerelease): + elif not self.prerelease and other.prerelease: return 1 - elif (self.prerelease and other.prerelease): + elif self.prerelease and other.prerelease: if self.prerelease == other.prerelease: return 0 elif self.prerelease < other.prerelease: @@ -199,6 +197,7 @@ def _cmp (self, other): else: assert False, "never get here" + # end class StrictVersion @@ -266,7 +265,8 @@ def _cmp (self, other): # the Right Thing" (ie. the code matches the conception). But I'd rather # have a conception that matches common notions about version numbers. -class LooseVersion (Version): + +class LooseVersion(Version): """Version numbering for anarchists and software realists. Implements the standard interface for version number classes as @@ -301,18 +301,16 @@ class LooseVersion (Version): component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) - def __init__ (self, vstring=None): + def __init__(self, vstring=None): if vstring: self.parse(vstring) - - def parse (self, vstring): + def parse(self, vstring): # I've given up on thinking I can reconstruct the version string # from the parsed tuple -- so I just store the string here for # use by __str__ self.vstring = vstring - components = [x for x in self.component_re.split(vstring) - if x and x != '.'] + components = [x for x in self.component_re.split(vstring) if x and x != '.'] for i, obj in enumerate(components): try: components[i] = int(obj) @@ -321,16 +319,13 @@ def parse (self, vstring): self.version = components - - def __str__ (self): + def __str__(self): return self.vstring - - def __repr__ (self): + def __repr__(self): return "LooseVersion ('%s')" % str(self) - - def _cmp (self, other): + def _cmp(self, other): if isinstance(other, str): other = LooseVersion(other) elif not isinstance(other, LooseVersion): diff --git a/setuptools/_distutils/versionpredicate.py b/setuptools/_distutils/versionpredicate.py index 062c98f2489..e55f6692eb6 100644 --- a/setuptools/_distutils/versionpredicate.py +++ b/setuptools/_distutils/versionpredicate.py @@ -5,11 +5,10 @@ import operator -re_validPackage = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)", - re.ASCII) +re_validPackage = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)", re.ASCII) # (package) (rest) -re_paren = re.compile(r"^\s*\((.*)\)\s*$") # (list) inside of parentheses +re_paren = re.compile(r"^\s*\((.*)\)\s*$") # (list) inside of parentheses re_splitComparison = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$") # (comp) (version) @@ -25,8 +24,16 @@ def splitUp(pred): comp, verStr = res.groups() return (comp, distutils.version.StrictVersion(verStr)) -compmap = {"<": operator.lt, "<=": operator.le, "==": operator.eq, - ">": operator.gt, ">=": operator.ge, "!=": operator.ne} + +compmap = { + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + ">": operator.gt, + ">=": operator.ge, + "!=": operator.ne, +} + class VersionPredicate: """Parse and test package version predicates. @@ -94,8 +101,7 @@ class VersionPredicate: """ def __init__(self, versionPredicateStr): - """Parse a version predicate string. - """ + """Parse a version predicate string.""" # Fields: # name: package name # pred: list of (comparison string, StrictVersion) @@ -115,8 +121,7 @@ def __init__(self, versionPredicateStr): str = match.groups()[0] self.pred = [splitUp(aPred) for aPred in str.split(",")] if not self.pred: - raise ValueError("empty parenthesized list in %r" - % versionPredicateStr) + raise ValueError("empty parenthesized list in %r" % versionPredicateStr) else: self.pred = [] @@ -140,6 +145,7 @@ def satisfied_by(self, version): _provision_rx = None + def split_provision(value): """Return the name and optional version number of a provision. @@ -154,8 +160,8 @@ def split_provision(value): global _provision_rx if _provision_rx is None: _provision_rx = re.compile( - r"([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$", - re.ASCII) + r"([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$", re.ASCII + ) value = value.strip() m = _provision_rx.match(value) if not m: diff --git a/setuptools/_imp.py b/setuptools/_imp.py index 47efd792b3c..0e5f614d982 100644 --- a/setuptools/_imp.py +++ b/setuptools/_imp.py @@ -20,8 +20,8 @@ def find_spec(module, paths): finder = ( importlib.machinery.PathFinder().find_spec - if isinstance(paths, list) else - importlib.util.find_spec + if isinstance(paths, list) + else importlib.util.find_spec ) return finder(module, paths) @@ -37,13 +37,19 @@ def find_module(module, paths=None): kind = -1 file = None static = isinstance(spec.loader, type) - if spec.origin == 'frozen' or static and issubclass( - spec.loader, importlib.machinery.FrozenImporter): + if ( + spec.origin == 'frozen' + or static + and issubclass(spec.loader, importlib.machinery.FrozenImporter) + ): kind = PY_FROZEN path = None # imp compabilty suffix = mode = '' # imp compatibility - elif spec.origin == 'built-in' or static and issubclass( - spec.loader, importlib.machinery.BuiltinImporter): + elif ( + spec.origin == 'built-in' + or static + and issubclass(spec.loader, importlib.machinery.BuiltinImporter) + ): kind = C_BUILTIN path = None # imp compabilty suffix = mode = '' # imp compatibility diff --git a/setuptools/_vendor/more_itertools/more.py b/setuptools/_vendor/more_itertools/more.py index 0f7d282aa5d..31de4751f01 100644 --- a/setuptools/_vendor/more_itertools/more.py +++ b/setuptools/_vendor/more_itertools/more.py @@ -560,9 +560,7 @@ def one(iterable, too_short=None, too_long=None): try: first_value = next(it) except StopIteration as e: - raise ( - too_short or ValueError('too few items in iterable (expected 1)') - ) from e + raise (too_short or ValueError('too few items in iterable (expected 1)')) from e try: second_value = next(it) @@ -843,9 +841,7 @@ def substrings_indexes(seq, reverse=False): r = range(1, len(seq) + 1) if reverse: r = reversed(r) - return ( - (seq[i : i + L], i, i + L) for L in r for i in range(len(seq) - L + 1) - ) + return ((seq[i : i + L], i, i + L) for L in r for i in range(len(seq) - L + 1)) class bucket: @@ -1474,18 +1470,14 @@ def stagger(iterable, offsets=(-1, 0, 1), longest=False, fillvalue=None): """ children = tee(iterable, len(offsets)) - return zip_offset( - *children, offsets=offsets, longest=longest, fillvalue=fillvalue - ) + return zip_offset(*children, offsets=offsets, longest=longest, fillvalue=fillvalue) class UnequalIterablesError(ValueError): def __init__(self, details=None): msg = 'Iterables have different lengths' if details is not None: - msg += (': index 0 has length {}; index {} has length {}').format( - *details - ) + msg += (': index 0 has length {}; index {} has length {}').format(*details) super().__init__(msg) @@ -1640,13 +1632,9 @@ def sort_together(iterables, key_list=(0,), key=None, reverse=False): # if key_list contains multiple items, use itemgetter to return a # tuple of items, which we pass as *args to the key function get_key_items = itemgetter(*key_list) - key_argument = lambda zipped_items: key( - *get_key_items(zipped_items) - ) + key_argument = lambda zipped_items: key(*get_key_items(zipped_items)) - return list( - zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse)) - ) + return list(zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse))) def unzip(iterable): @@ -1953,13 +1941,11 @@ def __init__(self, *args): self._start, self._stop, self._step = args elif argc == 0: raise TypeError( - 'numeric_range expected at least ' - '1 argument, got {}'.format(argc) + 'numeric_range expected at least ' '1 argument, got {}'.format(argc) ) else: raise TypeError( - 'numeric_range expected at most ' - '3 arguments, got {}'.format(argc) + 'numeric_range expected at most ' '3 arguments, got {}'.format(argc) ) self._zero = type(self._step)(0) @@ -2063,9 +2049,7 @@ def __reduce__(self): def __repr__(self): if self._step == 1: - return "numeric_range({}, {})".format( - repr(self._start), repr(self._stop) - ) + return "numeric_range({}, {})".format(repr(self._start), repr(self._stop)) else: return "numeric_range({}, {}, {})".format( repr(self._start), repr(self._stop), repr(self._step) @@ -2073,9 +2057,7 @@ def __repr__(self): def __reversed__(self): return iter( - numeric_range( - self._get_by_index(-1), self._start - self._step, -self._step - ) + numeric_range(self._get_by_index(-1), self._start - self._step, -self._step) ) def count(self, value): @@ -2467,9 +2449,7 @@ def consecutive_groups(iterable, ordering=lambda x: x): [[1, 2], [11, 12], [21, 22]] """ - for k, g in groupby( - enumerate(iterable), key=lambda x: x[0] - ordering(x[1]) - ): + for k, g in groupby(enumerate(iterable), key=lambda x: x[0] - ordering(x[1])): yield map(itemgetter(1), g) @@ -3042,9 +3022,7 @@ def set_partitions(iterable, k=None): n = len(L) if k is not None: if k < 1: - raise ValueError( - "Can't partition in a negative or zero number of groups" - ) + raise ValueError("Can't partition in a negative or zero number of groups") elif k > n: return diff --git a/setuptools/_vendor/more_itertools/recipes.py b/setuptools/_vendor/more_itertools/recipes.py index 521abd7c2ca..7f725138db4 100644 --- a/setuptools/_vendor/more_itertools/recipes.py +++ b/setuptools/_vendor/more_itertools/recipes.py @@ -289,9 +289,7 @@ def grouper(iterable, n, fillvalue=None): """ if isinstance(iterable, int): - warnings.warn( - "grouper expects iterable as first parameter", DeprecationWarning - ) + warnings.warn("grouper expects iterable as first parameter", DeprecationWarning) n, iterable = iterable, n args = [iter(iterable)] * n return zip_longest(fillvalue=fillvalue, *args) diff --git a/setuptools/_vendor/packaging/markers.py b/setuptools/_vendor/packaging/markers.py index 03fbdfcc944..8586ce05a1d 100644 --- a/setuptools/_vendor/packaging/markers.py +++ b/setuptools/_vendor/packaging/markers.py @@ -8,7 +8,12 @@ import platform import sys -from setuptools.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd +from setuptools.extern.pyparsing import ( + ParseException, + ParseResults, + stringStart, + stringEnd, +) from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString from setuptools.extern.pyparsing import Literal as L # noqa diff --git a/setuptools/_vendor/packaging/requirements.py b/setuptools/_vendor/packaging/requirements.py index 5d50c7d7e20..3527bfa0a34 100644 --- a/setuptools/_vendor/packaging/requirements.py +++ b/setuptools/_vendor/packaging/requirements.py @@ -6,7 +6,12 @@ import string import re -from setuptools.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +from setuptools.extern.pyparsing import ( + stringStart, + stringEnd, + originalTextFor, + ParseException, +) from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine from setuptools.extern.pyparsing import Literal as L # noqa from urllib import parse as urlparse diff --git a/setuptools/_vendor/packaging/specifiers.py b/setuptools/_vendor/packaging/specifiers.py index fe09bb1dbb2..ef3bdb5011e 100644 --- a/setuptools/_vendor/packaging/specifiers.py +++ b/setuptools/_vendor/packaging/specifiers.py @@ -317,7 +317,7 @@ def _compare_greater_than(self, prospective, spec): 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) diff --git a/setuptools/_vendor/pyparsing.py b/setuptools/_vendor/pyparsing.py index 4cae7883870..90ad5be7db8 100644 --- a/setuptools/_vendor/pyparsing.py +++ b/setuptools/_vendor/pyparsing.py @@ -22,8 +22,7 @@ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__doc__ = \ -""" +__doc__ = """ pyparsing module - Classes and methods to define and execute parsing grammars ============================================================================= @@ -113,27 +112,114 @@ class names, and the use of '+', '|' and '^' operators. except ImportError: _OrderedDict = None -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) +# ~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) __all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', -'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', -'CloseMatch', 'tokenMap', 'pyparsing_common', + 'And', + 'CaselessKeyword', + 'CaselessLiteral', + 'CharsNotIn', + 'Combine', + 'Dict', + 'Each', + 'Empty', + 'FollowedBy', + 'Forward', + 'GoToColumn', + 'Group', + 'Keyword', + 'LineEnd', + 'LineStart', + 'Literal', + 'MatchFirst', + 'NoMatch', + 'NotAny', + 'OneOrMore', + 'OnlyOnce', + 'Optional', + 'Or', + 'ParseBaseException', + 'ParseElementEnhance', + 'ParseException', + 'ParseExpression', + 'ParseFatalException', + 'ParseResults', + 'ParseSyntaxException', + 'ParserElement', + 'QuotedString', + 'RecursiveGrammarException', + 'Regex', + 'SkipTo', + 'StringEnd', + 'StringStart', + 'Suppress', + 'Token', + 'TokenConverter', + 'White', + 'Word', + 'WordEnd', + 'WordStart', + 'ZeroOrMore', + 'alphanums', + 'alphas', + 'alphas8bit', + 'anyCloseTag', + 'anyOpenTag', + 'cStyleComment', + 'col', + 'commaSeparatedList', + 'commonHTMLEntity', + 'countedArray', + 'cppStyleComment', + 'dblQuotedString', + 'dblSlashComment', + 'delimitedList', + 'dictOf', + 'downcaseTokens', + 'empty', + 'hexnums', + 'htmlComment', + 'javaStyleComment', + 'line', + 'lineEnd', + 'lineStart', + 'lineno', + 'makeHTMLTags', + 'makeXMLTags', + 'matchOnlyAtCol', + 'matchPreviousExpr', + 'matchPreviousLiteral', + 'nestedExpr', + 'nullDebugAction', + 'nums', + 'oneOf', + 'opAssoc', + 'operatorPrecedence', + 'printables', + 'punc8bit', + 'pythonStyleComment', + 'quotedString', + 'removeQuotes', + 'replaceHTMLEntity', + 'replaceWith', + 'restOfLine', + 'sglQuotedString', + 'srange', + 'stringEnd', + 'stringStart', + 'traceParseAction', + 'unicodeString', + 'upcaseTokens', + 'withAttribute', + 'indentedBlock', + 'originalTextFor', + 'ungroup', + 'infixNotation', + 'locatedExpr', + 'withClass', + 'CloseMatch', + 'tokenMap', + 'pyparsing_common', ] system_version = tuple(sys.version_info)[:3] @@ -145,7 +231,19 @@ class names, and the use of '+', '|' and '^' operators. _ustr = str # build list of single arg builtins, that can be used as parse actions - singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] + singleArgBuiltins = [ + sum, + len, + sorted, + reversed, + list, + tuple, + set, + any, + all, + min, + max, + ] else: _MAX_INT = sys.maxint @@ -153,10 +251,10 @@ class names, and the use of '+', '|' and '^' operators. def _ustr(obj): """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. + str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It + then < returns the unicode object | encodes it with the default encoding | ... >. """ - if isinstance(obj,unicode): + if isinstance(obj, unicode): return obj try: @@ -174,39 +272,45 @@ def _ustr(obj): # build list of single arg builtins, tolerant of Python version, that can be used as parse actions singleArgBuiltins = [] import __builtin__ + for fname in "sum len sorted reversed list tuple set any all min max".split(): try: - singleArgBuiltins.append(getattr(__builtin__,fname)) + singleArgBuiltins.append(getattr(__builtin__, fname)) except AttributeError: continue - + _generatorType = type((y for y in range(1))) - + + def _xml_escape(data): """Escape &, <, >, ", ', etc. in a string of data.""" # ampersand must be replaced first from_symbols = '&><"\'' - to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) - for from_,to_ in zip(from_symbols, to_symbols): + to_symbols = ('&' + s + ';' for s in "amp gt lt quot apos".split()) + for from_, to_ in zip(from_symbols, to_symbols): data = data.replace(from_, to_) return data + class _Constants(object): pass -alphas = string.ascii_uppercase + string.ascii_lowercase -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) + +alphas = string.ascii_uppercase + string.ascii_lowercase +nums = "0123456789" +hexnums = nums + "ABCDEFabcdef" +alphanums = alphas + nums +_bslash = chr(92) printables = "".join(c for c in string.printable if c not in string.whitespace) + class ParseBaseException(Exception): """base exception class for all parsing runtime exceptions""" + # Performance tuning: we construct a *lot* of these, so keep this # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): + def __init__(self, pstr, loc=0, msg=None, elem=None): self.loc = loc if msg is None: self.msg = pstr @@ -220,44 +324,53 @@ def __init__( self, pstr, loc=0, msg=None, elem=None ): @classmethod def _from_exception(cls, pe): """ - internal factory method to simplify creating one type of ParseException + internal factory method to simplify creating one type of ParseException from another - avoids having __init__ signature conflicts among subclasses """ return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) - def __getattr__( self, aname ): + def __getattr__(self, aname): """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) + if aname == "lineno": + return lineno(self.loc, self.pstr) + elif aname in ("col", "column"): + return col(self.loc, self.pstr) + elif aname == "line": + return line(self.loc, self.pstr) else: raise AttributeError(aname) - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): + def __str__(self): + return "%s (at char %d), (line:%d, col:%d)" % ( + self.msg, + self.loc, + self.lineno, + self.column, + ) + + def __repr__(self): return _ustr(self) - def markInputline( self, markerString = ">!<" ): + + def markInputline(self, markerString=">!<"): """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. + the location of the exception with a special symbol. """ line_str = self.line line_column = self.column - 1 if markerString: - line_str = "".join((line_str[:line_column], - markerString, line_str[line_column:])) + line_str = "".join( + (line_str[:line_column], markerString, line_str[line_column:]) + ) return line_str.strip() + def __dir__(self): return "lineno col line".split() + dir(type(self)) + class ParseException(ParseBaseException): """ Exception thrown when parse expressions don't match class; @@ -265,61 +378,74 @@ class ParseException(ParseBaseException): - lineno - returns the line number of the exception text - col - returns the column number of the exception text - line - returns the line containing the exception text - + Example:: try: Word(nums).setName("integer").parseString("ABC") except ParseException as pe: print(pe) print("column: {}".format(pe.col)) - + prints:: Expected integer (at char 0), (line:1, col:1) column: 1 """ + pass + class ParseFatalException(ParseBaseException): """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" + is found; stops all parsing immediately""" + pass + class ParseSyntaxException(ParseFatalException): """just like L{ParseFatalException}, but thrown internally when an - L{ErrorStop} ('-' operator) indicates that parsing is to stop - immediately because an unbacktrackable syntax error has been found""" + L{ErrorStop} ('-' operator) indicates that parsing is to stop + immediately because an unbacktrackable syntax error has been found""" + pass -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc + +# ~ class ReparseException(ParseBaseException): +# ~ """Experimental class - parse actions can raise this exception to cause +# ~ pyparsing to reparse the input string: +# ~ - with a modified input string, and/or +# ~ - with a modified start location +# ~ Set the values of the ReparseException in the constructor, and raise the +# ~ exception in a parse action to cause pyparsing to use the new string/location. +# ~ Setting the values as None causes no change to be made. +# ~ """ +# ~ def __init_( self, newstring, restartLoc ): +# ~ self.newParseText = newstring +# ~ self.reparseLoc = restartLoc + class RecursiveGrammarException(Exception): """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): + + def __init__(self, parseElementList): self.parseElementTrace = parseElementList - def __str__( self ): + def __str__(self): return "RecursiveGrammarException: %s" % self.parseElementTrace + class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): + def __init__(self, p1, p2): + self.tup = (p1, p2) + + def __getitem__(self, i): return self.tup[i] + def __repr__(self): return repr(self.tup[0]) - def setOffset(self,i): - self.tup = (self.tup[0],i) + + def setOffset(self, i): + self.tup = (self.tup[0], i) + class ParseResults(object): """ @@ -330,8 +456,8 @@ class ParseResults(object): Example:: integer = Word(nums) - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + integer.setResultsName("day")) # equivalent form: # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") @@ -360,7 +486,8 @@ def test(s, fn=repr): - month: 12 - year: 1999 """ - def __new__(cls, toklist=None, name=None, asList=True, modal=True ): + + def __new__(cls, toklist=None, name=None, asList=True, modal=True): if isinstance(toklist, cls): return toklist retobj = object.__new__(cls) @@ -369,7 +496,9 @@ def __new__(cls, toklist=None, name=None, asList=True, modal=True ): # Performance tuning: we construct a *lot* of these, so keep this # constructor as small and fast as possible - def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): + def __init__( + self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance + ): if self.__doinit: self.__doinit = False self.__name = None @@ -390,89 +519,109 @@ def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance if name is not None and name: if not modal: self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency + if isinstance(name, int): + name = _ustr( + name + ) # will always return a str, but use _ustr for consistency self.__name = name - if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): - if isinstance(toklist,basestring): - toklist = [ toklist ] + if not ( + isinstance(toklist, (type(None), basestring, list)) + and toklist in (None, '', []) + ): + if isinstance(toklist, basestring): + toklist = [toklist] if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) + if isinstance(toklist, ParseResults): + self[name] = _ParseResultsWithOffset(toklist.copy(), 0) else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) + self[name] = _ParseResultsWithOffset( + ParseResults(toklist[0]), 0 + ) self[name].__name = name else: try: self[name] = toklist[0] - except (KeyError,TypeError,IndexError): + except (KeyError, TypeError, IndexError): self[name] = toklist - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): + def __getitem__(self, i): + if isinstance(i, (int, slice)): return self.__toklist[i] else: if i not in self.__accumNames: return self.__tokdict[i][-1][0] else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) + return ParseResults([v[0] for v in self.__tokdict[i]]) - def __setitem__( self, k, v, isinstance=isinstance ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] + def __setitem__(self, k, v, isinstance=isinstance): + if isinstance(v, _ParseResultsWithOffset): + self.__tokdict[k] = self.__tokdict.get(k, list()) + [v] sub = v[0] - elif isinstance(k,(int,slice)): + elif isinstance(k, (int, slice)): self.__toklist[k] = v sub = v else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] + self.__tokdict[k] = self.__tokdict.get(k, list()) + [ + _ParseResultsWithOffset(v, 0) + ] sub = v - if isinstance(sub,ParseResults): + if isinstance(sub, ParseResults): sub.__parent = wkref(self) - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) + def __delitem__(self, i): + if isinstance(i, (int, slice)): + mylen = len(self.__toklist) del self.__toklist[i] # convert int to slice if isinstance(i, int): if i < 0: i += mylen - i = slice(i, i+1) + i = slice(i, i + 1) # get removed indices removed = list(range(*i.indices(mylen))) removed.reverse() # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): + for name, occurrences in self.__tokdict.items(): for j in removed: for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) + occurrences[k] = _ParseResultsWithOffset( + value, position - (position > j) + ) else: del self.__tokdict[i] - def __contains__( self, k ): + def __contains__(self, k): return k in self.__tokdict - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return ( not not self.__toklist ) + def __len__(self): + return len(self.__toklist) + + def __bool__(self): + return not not self.__toklist + __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( self.__toklist[::-1] ) - def _iterkeys( self ): + + def __iter__(self): + return iter(self.__toklist) + + def __reversed__(self): + return iter(self.__toklist[::-1]) + + def _iterkeys(self): if hasattr(self.__tokdict, "iterkeys"): return self.__tokdict.iterkeys() else: return iter(self.__tokdict) - def _itervalues( self ): + def _itervalues(self): return (self[k] for k in self._iterkeys()) - - def _iteritems( self ): + + def _iteritems(self): return ((k, self[k]) for k in self._iterkeys()) if PY_3: - keys = _iterkeys + keys = _iterkeys """Returns an iterator of all named result keys (Python 3.x only).""" values = _itervalues @@ -491,32 +640,32 @@ def _iteritems( self ): iteritems = _iteritems """Returns an iterator of all named result key-value tuples (Python 2.x only).""" - def keys( self ): + def keys(self): """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" return list(self.iterkeys()) - def values( self ): + def values(self): """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" return list(self.itervalues()) - - def items( self ): + + def items(self): """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" return list(self.iteritems()) - def haskeys( self ): + def haskeys(self): """Since keys() returns an iterator, this method is helpful in bypassing - code that looks for the existence of any defined results names.""" + code that looks for the existence of any defined results names.""" return bool(self.__tokdict) - - def pop( self, *args, **kwargs): + + def pop(self, *args, **kwargs): """ Removes and returns item at specified index (default=C{last}). Supports both C{list} and C{dict} semantics for C{pop()}. If passed no argument or an integer argument, it will use C{list} semantics - and pop tokens from the list of parsed tokens. If passed a + and pop tokens from the list of parsed tokens. If passed a non-integer argument (most likely a string), it will use C{dict} - semantics and pop the corresponding value from any defined - results names. A second default return value argument is + semantics and pop the corresponding value from any defined + results names. A second default return value argument is supported, just as in C{dict.pop()}. Example:: @@ -544,14 +693,12 @@ def remove_LABEL(tokens): """ if not args: args = [-1] - for k,v in kwargs.items(): + for k, v in kwargs.items(): if k == 'default': args = (args[0], v) else: raise TypeError("pop() got an unexpected keyword argument '%s'" % k) - if (isinstance(args[0], int) or - len(args) == 1 or - args[0] in self): + if isinstance(args[0], int) or len(args) == 1 or args[0] in self: index = args[0] ret = self[index] del self[index] @@ -567,10 +714,10 @@ def get(self, key, defaultValue=None): C{defaultValue} is specified. Similar to C{dict.get()}. - + Example:: integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") result = date_str.parseString("1999/12/31") print(result.get("year")) # -> '1999' @@ -582,10 +729,10 @@ def get(self, key, defaultValue=None): else: return defaultValue - def insert( self, index, insStr ): + def insert(self, index, insStr): """ Inserts new element at location index in the list of parsed tokens. - + Similar to C{list.insert()}. Example:: @@ -598,17 +745,19 @@ def insert_locn(locn, tokens): """ self.__toklist.insert(index, insStr) # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): + for name, occurrences in self.__tokdict.items(): for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) + occurrences[k] = _ParseResultsWithOffset( + value, position + (position > index) + ) - def append( self, item ): + def append(self, item): """ Add single element to end of ParseResults list of elements. Example:: print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - + # use a parse action to compute the sum of the parsed integers, and add it to the end def append_sum(tokens): tokens.append(sum(map(int, tokens))) @@ -616,13 +765,13 @@ def append_sum(tokens): """ self.__toklist.append(item) - def extend( self, itemseq ): + def extend(self, itemseq): """ Add sequence of elements to end of ParseResults list of elements. Example:: patt = OneOrMore(Word(alphas)) - + # use a parse action to append the reverse of the matched strings, to make a palindrome def make_palindrome(tokens): tokens.extend(reversed([t[::-1] for t in tokens])) @@ -634,74 +783,84 @@ def make_palindrome(tokens): else: self.__toklist.extend(itemseq) - def clear( self ): + def clear(self): """ Clear all elements and results names. """ del self.__toklist[:] self.__tokdict.clear() - def __getattr__( self, name ): + def __getattr__(self, name): try: return self[name] except KeyError: return "" - + if name in self.__tokdict: if name not in self.__accumNames: return self.__tokdict[name][-1][0] else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) + return ParseResults([v[0] for v in self.__tokdict[name]]) else: return "" - def __add__( self, other ): + def __add__(self, other): ret = self.copy() ret += other return ret - def __iadd__( self, other ): + def __iadd__(self, other): if other.__tokdict: offset = len(self.__toklist) - addoffset = lambda a: offset if a<0 else a+offset + addoffset = lambda a: offset if a < 0 else a + offset otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: + otherdictitems = [ + (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) + for (k, vlist) in otheritems + for v in vlist + ] + for k, v in otherdictitems: self[k] = v - if isinstance(v[0],ParseResults): + if isinstance(v[0], ParseResults): v[0].__parent = wkref(self) - + self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) + self.__accumNames.update(other.__accumNames) return self def __radd__(self, other): - if isinstance(other,int) and other == 0: + if isinstance(other, int) and other == 0: # useful for merging many ParseResults using sum() builtin return self.copy() else: # this may raise a TypeError - so be it return other + self - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - def __str__( self ): - return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' + def __repr__(self): + return "(%s, %s)" % (repr(self.__toklist), repr(self.__tokdict)) - def _asStringList( self, sep='' ): + def __str__(self): + return ( + '[' + + ', '.join( + _ustr(i) if isinstance(i, ParseResults) else repr(i) + for i in self.__toklist + ) + + ']' + ) + + def _asStringList(self, sep=''): out = [] for item in self.__toklist: if out and sep: out.append(sep) - if isinstance( item, ParseResults ): + if isinstance(item, ParseResults): out += item._asStringList() else: - out.append( _ustr(item) ) + out.append(_ustr(item)) return out - def asList( self ): + def asList(self): """ Returns the parse results as a nested list of matching tokens, all converted to strings. @@ -710,24 +869,27 @@ def asList( self ): result = patt.parseString("sldkj lsdkj sldkj") # even though the result prints in string-like form, it is actually a pyparsing ParseResults print(type(result), result) # -> ['sldkj', 'lsdkj', 'sldkj'] - + # Use asList() to create an actual list result_list = result.asList() print(type(result_list), result_list) # -> ['sldkj', 'lsdkj', 'sldkj'] """ - return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] + return [ + res.asList() if isinstance(res, ParseResults) else res + for res in self.__toklist + ] - def asDict( self ): + def asDict(self): """ Returns the named parse results as a nested dictionary. Example:: integer = Word(nums) date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - + result = date_str.parseString('12/31/1999') print(type(result), repr(result)) # -> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) - + result_dict = result.asDict() print(type(result_dict), repr(result_dict)) # -> {'day': '1999', 'year': '12', 'month': '31'} @@ -740,7 +902,7 @@ def asDict( self ): item_fn = self.items else: item_fn = self.iteritems - + def toItem(obj): if isinstance(obj, ParseResults): if obj.haskeys(): @@ -749,28 +911,29 @@ def toItem(obj): return [toItem(v) for v in obj] else: return obj - - return dict((k,toItem(v)) for k,v in item_fn()) - def copy( self ): + return dict((k, toItem(v)) for k, v in item_fn()) + + def copy(self): """ Returns a new copy of a C{ParseResults} object. """ - ret = ParseResults( self.__toklist ) + ret = ParseResults(self.__toklist) ret.__tokdict = self.__tokdict.copy() ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) + ret.__accumNames.update(self.__accumNames) ret.__name = self.__name return ret - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): + def asXML(self, doctag=None, namedItemsOnly=False, indent="", formatted=True): """ (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. """ nl = "\n" out = [] - namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist) + namedItems = dict( + (v[1], k) for (k, vlist) in self.__tokdict.items() for v in vlist + ) nextLevelIndent = indent + " " # collapse out indents if formatting is not desired @@ -792,20 +955,28 @@ def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): else: selfTag = "ITEM" - out += [ nl, indent, "<", selfTag, ">" ] + out += [nl, indent, "<", selfTag, ">"] - for i,res in enumerate(self.__toklist): - if isinstance(res,ParseResults): + for i, res in enumerate(self.__toklist): + if isinstance(res, ParseResults): if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] + out += [ + res.asXML( + namedItems[i], + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted, + ) + ] else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] + out += [ + res.asXML( + None, + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted, + ) + ] else: # individual token, see if there is a name for it resTag = None @@ -817,34 +988,42 @@ def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): else: resTag = "ITEM" xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "" ] - - out += [ nl, indent, "" ] + out += [ + nl, + nextLevelIndent, + "<", + resTag, + ">", + xmlBodyText, + "", + ] + + out += [nl, indent, ""] return "".join(out) - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: + def __lookup(self, sub): + for k, vlist in self.__tokdict.items(): + for v, loc in vlist: if sub is v: return k return None def getName(self): r""" - Returns the results name for this token expression. Useful when several + Returns the results name for this token expression. Useful when several different expressions might match at a particular location. Example:: integer = Word(nums) ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") house_number_expr = Suppress('#') + Word(nums, alphanums) - user_data = (Group(house_number_expr)("house_number") + user_data = (Group(house_number_expr)("house_number") | Group(ssn_expr)("ssn") | Group(integer)("age")) user_info = OneOrMore(user_data) - + result = user_info.parseString("22 111-22-3333 #221B") for item in result: print(item.getName(), ':', item[0]) @@ -861,9 +1040,11 @@ def getName(self): return par.__lookup(self) else: return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - next(iter(self.__tokdict.values()))[0][1] in (0,-1)): + elif ( + len(self) == 1 + and len(self.__tokdict) == 1 + and next(iter(self.__tokdict.values()))[0][1] in (0, -1) + ): return next(iter(self.__tokdict.keys())) else: return None @@ -877,7 +1058,7 @@ def dump(self, indent='', depth=0, full=True): Example:: integer = Word(nums) date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - + result = date_str.parseString('12/31/1999') print(result.dump()) prints:: @@ -888,35 +1069,55 @@ def dump(self, indent='', depth=0, full=True): """ out = [] NL = '\n' - out.append( indent+_ustr(self.asList()) ) + out.append(indent + _ustr(self.asList())) if full: if self.haskeys(): - items = sorted((str(k), v) for k,v in self.items()) - for k,v in items: + items = sorted((str(k), v) for k, v in self.items()) + for k, v in items: if out: out.append(NL) - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): + out.append("%s%s- %s: " % (indent, (' ' * depth), k)) + if isinstance(v, ParseResults): if v: - out.append( v.dump(indent,depth+1) ) + out.append(v.dump(indent, depth + 1)) else: out.append(_ustr(v)) else: out.append(repr(v)) - elif any(isinstance(vv,ParseResults) for vv in self): + elif any(isinstance(vv, ParseResults) for vv in self): v = self - for i,vv in enumerate(v): - if isinstance(vv,ParseResults): - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) + for i, vv in enumerate(v): + if isinstance(vv, ParseResults): + out.append( + "\n%s%s[%d]:\n%s%s%s" + % ( + indent, + (' ' * (depth)), + i, + indent, + (' ' * (depth + 1)), + vv.dump(indent, depth + 1), + ) + ) else: - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) - + out.append( + "\n%s%s[%d]:\n%s%s%s" + % ( + indent, + (' ' * (depth)), + i, + indent, + (' ' * (depth + 1)), + _ustr(vv), + ) + ) + return "".join(out) def pprint(self, *args, **kwargs): """ Pretty-printer for parsed results as a list, using the C{pprint} module. - Accepts additional positional or keyword args as defined for the + Accepts additional positional or keyword args as defined for the C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) Example:: @@ -938,18 +1139,19 @@ def pprint(self, *args, **kwargs): # add support for pickle protocol def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): + return ( + self.__toklist, + ( + self.__tokdict.copy(), + self.__parent is not None and self.__parent() or None, + self.__accumNames, + self.__name, + ), + ) + + def __setstate__(self, state): self.__toklist = state[0] - (self.__tokdict, - par, - inAccumNames, - self.__name) = state[1] + (self.__tokdict, par, inAccumNames, self.__name) = state[1] self.__accumNames = {} self.__accumNames.update(inAccumNames) if par is not None: @@ -961,115 +1163,136 @@ def __getnewargs__(self): return self.__toklist, self.__name, self.__asList, self.__modal def __dir__(self): - return (dir(type(self)) + list(self.keys())) + return dir(type(self)) + list(self.keys()) + MutableMapping.register(ParseResults) -def col (loc,strg): + +def col(loc, strg): """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}} for more information - on parsing strings containing C{}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ + The first column is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}} for more information + on parsing strings containing C{}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ s = strg - return 1 if 0} for more information - on parsing strings containing C{}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ + The first line is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}} for more information + on parsing strings containing C{}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + return strg.count("\n", 0, loc) + 1 + + +def line(loc, strg): + """Returns the line of text containing loc within a string, counting newlines as line separators.""" lastCR = strg.rfind("\n", 0, loc) nextCR = strg.find("\n", loc) if nextCR >= 0: - return strg[lastCR+1:nextCR] + return strg[lastCR + 1 : nextCR] else: - return strg[lastCR+1:] + return strg[lastCR + 1 :] + -def _defaultStartDebugAction( instring, loc, expr ): - print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) +def _defaultStartDebugAction(instring, loc, expr): + print( + ( + "Match " + + _ustr(expr) + + " at loc " + + _ustr(loc) + + "(%d,%d)" % (lineno(loc, instring), col(loc, instring)) + ) + ) -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) +def _defaultSuccessDebugAction(instring, startloc, endloc, expr, toks): + print("Matched " + _ustr(expr) + " -> " + str(toks.asList())) + + +def _defaultExceptionDebugAction(instring, loc, expr, exc): + print("Exception raised:" + _ustr(exc)) + def nullDebugAction(*args): """'Do-nothing' debug action, to suppress debugging output during parsing.""" pass + # Only works on Python 3.x - nonlocal is toxic to Python 2 installs -#~ 'decorator to trim function calls to match the arity of the target' -#~ def _trim_arity(func, maxargs=3): - #~ if func in singleArgBuiltins: - #~ return lambda s,l,t: func(t) - #~ limit = 0 - #~ foundArity = False - #~ def wrapper(*args): - #~ nonlocal limit,foundArity - #~ while 1: - #~ try: - #~ ret = func(*args[limit:]) - #~ foundArity = True - #~ return ret - #~ except TypeError: - #~ if limit == maxargs or foundArity: - #~ raise - #~ limit += 1 - #~ continue - #~ return wrapper +# ~ 'decorator to trim function calls to match the arity of the target' +# ~ def _trim_arity(func, maxargs=3): +# ~ if func in singleArgBuiltins: +# ~ return lambda s,l,t: func(t) +# ~ limit = 0 +# ~ foundArity = False +# ~ def wrapper(*args): +# ~ nonlocal limit,foundArity +# ~ while 1: +# ~ try: +# ~ ret = func(*args[limit:]) +# ~ foundArity = True +# ~ return ret +# ~ except TypeError: +# ~ if limit == maxargs or foundArity: +# ~ raise +# ~ limit += 1 +# ~ continue +# ~ return wrapper # this version is Python 2.x-3.x cross-compatible 'decorator to trim function calls to match the arity of the target' + + def _trim_arity(func, maxargs=2): if func in singleArgBuiltins: - return lambda s,l,t: func(t) + return lambda s, l, t: func(t) limit = [0] foundArity = [False] - + # traceback return data structure changed in Py3.5 - normalize back to plain tuples - if system_version[:2] >= (3,5): + if system_version[:2] >= (3, 5): + def extract_stack(limit=0): # special handling for Python 3.5.0 - extra deep call stack by 1 - offset = -3 if system_version == (3,5,0) else -2 - frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset] + offset = -3 if system_version == (3, 5, 0) else -2 + frame_summary = traceback.extract_stack(limit=-offset + limit - 1)[offset] return [frame_summary[:2]] + def extract_tb(tb, limit=0): frames = traceback.extract_tb(tb, limit=limit) frame_summary = frames[-1] return [frame_summary[:2]] + else: extract_stack = traceback.extract_stack extract_tb = traceback.extract_tb - - # synthesize what would be returned by traceback.extract_stack at the call to + + # synthesize what would be returned by traceback.extract_stack at the call to # user's parse action 'func', so that we don't incur call penalty at parse time - + LINE_DIFF = 6 - # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND + # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! this_line = extract_stack(limit=2)[-1] - pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) + pa_call_line_synth = (this_line[0], this_line[1] + LINE_DIFF) def wrapper(*args): while 1: try: - ret = func(*args[limit[0]:]) + ret = func(*args[limit[0] :]) foundArity[0] = True return ret except TypeError: @@ -1092,28 +1315,29 @@ def wrapper(*args): # copy func name to wrapper for sensible debug output func_name = "" try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) + func_name = getattr(func, '__name__', getattr(func, '__class__').__name__) except Exception: func_name = str(func) wrapper.__name__ = func_name return wrapper + class ParserElement(object): """Abstract base level parser element class.""" + DEFAULT_WHITE_CHARS = " \n\t\r" verbose_stacktrace = False @staticmethod - def setDefaultWhitespaceChars( chars ): + def setDefaultWhitespaceChars(chars): r""" Overrides the default whitespace chars Example:: # default whitespace chars are space, and newline OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] - + # change to just treat newline as significant ParserElement.setDefaultWhitespaceChars(" \t") OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] @@ -1124,84 +1348,84 @@ def setDefaultWhitespaceChars( chars ): def inlineLiteralsUsing(cls): """ Set class to be used for inclusion of string literals into a parser. - + Example:: # default literal class used is Literal integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] # change to Suppress ParserElement.inlineLiteralsUsing(Suppress) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] """ ParserElement._literalStringClass = cls - def __init__( self, savelist=False ): + def __init__(self, savelist=False): self.parseAction = list() self.failAction = None - #~ self.name = "" # don't define self.name, let subclasses try/except upcall + # ~ self.name = "" # don't define self.name, let subclasses try/except upcall self.strRepr = None self.resultsName = None self.saveAsList = savelist self.skipWhitespace = True self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion + self.mayReturnEmpty = False # used when checking for left-recursion self.keepTabs = False self.ignoreExprs = list() self.debug = False self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index + self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions + self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) + self.debugActions = (None, None, None) # custom debug actions self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse + self.callPreparse = True # used to avoid redundant calls to preParse self.callDuringTry = False - def copy( self ): + def copy(self): """ Make a copy of this C{ParserElement}. Useful for defining different parse actions for the same parsing pattern, using copies of the original parse element. - + Example:: integer = Word(nums).setParseAction(lambda toks: int(toks[0])) integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - + print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) prints:: [5120, 100, 655360, 268435456] Equivalent form of C{expr.copy()} is just C{expr()}:: integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") """ - cpy = copy.copy( self ) + cpy = copy.copy(self) cpy.parseAction = self.parseAction[:] cpy.ignoreExprs = self.ignoreExprs[:] if self.copyDefaultWhiteChars: cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS return cpy - def setName( self, name ): + def setName(self, name): """ Define name for this expression, makes debugging and exception messages clearer. - + Example:: Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) """ self.name = name self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): + if hasattr(self, "exception"): self.exception.msg = self.errmsg return self - def setResultsName( self, name, listAllMatches=False ): + def setResultsName(self, name, listAllMatches=False): """ Define name for referencing matching tokens as a nested attribute of the returned parse results. @@ -1210,12 +1434,12 @@ def setResultsName( self, name, listAllMatches=False ): integer, and reference it in multiple places with different names. You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - + C{expr("name")} in place of C{expr.setResultsName("name")} - see L{I{__call__}<__call__>}. Example:: - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + integer.setResultsName("day")) # equivalent form: @@ -1224,30 +1448,33 @@ def setResultsName( self, name, listAllMatches=False ): newself = self.copy() if name.endswith("*"): name = name[:-1] - listAllMatches=True + listAllMatches = True newself.resultsName = name newself.modalResults = not listAllMatches return newself - def setBreak(self,breakFlag = True): + def setBreak(self, breakFlag=True): """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. + about to be parsed. Set C{breakFlag} to True to enable, False to + disable. """ if breakFlag: _parseMethod = self._parse + def breaker(instring, loc, doActions=True, callPreParse=True): import pdb + pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) + return _parseMethod(instring, loc, doActions, callPreParse) + breaker._originalParseMethod = _parseMethod self._parse = breaker else: - if hasattr(self._parse,"_originalParseMethod"): + if hasattr(self._parse, "_originalParseMethod"): self._parse = self._parse._originalParseMethod return self - def setParseAction( self, *fns, **kwargs ): + def setParseAction(self, *fns, **kwargs): """ Define one or more actions to perform when successfully matching parse element definition. Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, @@ -1267,7 +1494,7 @@ def setParseAction( self, *fns, **kwargs ): on parsing strings containing C{}s, and suggested methods to maintain a consistent view of the parsed string, the parse location, and line and column positions within the parsed string. - + Example:: integer = Word(nums) date_str = integer + '/' + integer + '/' + integer @@ -1285,10 +1512,10 @@ def setParseAction( self, *fns, **kwargs ): self.callDuringTry = kwargs.get("callDuringTry", False) return self - def addParseAction( self, *fns, **kwargs ): + def addParseAction(self, *fns, **kwargs): """ Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}}. - + See examples in L{I{copy}}. """ self.parseAction += list(map(_trim_arity, list(fns))) @@ -1296,14 +1523,14 @@ def addParseAction( self, *fns, **kwargs ): return self def addCondition(self, *fns, **kwargs): - """Add a boolean predicate function to expression's list of parse actions. See - L{I{setParseAction}} for function call signatures. Unlike C{setParseAction}, + """Add a boolean predicate function to expression's list of parse actions. See + L{I{setParseAction}} for function call signatures. Unlike C{setParseAction}, functions passed to C{addCondition} need to return boolean success/fail of the condition. Optional keyword arguments: - message = define a custom message to be used in the raised exception - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException - + Example:: integer = Word(nums).setParseAction(lambda toks: int(toks[0])) year_int = integer.copy() @@ -1315,42 +1542,44 @@ def addCondition(self, *fns, **kwargs): msg = kwargs.get("message", "failed user-defined condition") exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException for fn in fns: - def pa(s,l,t): - if not bool(_trim_arity(fn)(s,l,t)): - raise exc_type(s,l,msg) + + def pa(s, l, t): + if not bool(_trim_arity(fn)(s, l, t)): + raise exc_type(s, l, msg) + self.parseAction.append(pa) self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) return self - def setFailAction( self, fn ): + def setFailAction(self, fn): """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{L{ParseFatalException}} - if it is desired to stop parsing immediately.""" + Fail acton fn is a callable function that takes the arguments + C{fn(s,loc,expr,err)} where: + - s = string being parsed + - loc = location where expression match was attempted and failed + - expr = the parse expression that failed + - err = the exception thrown + The function returns no value. It may throw C{L{ParseFatalException}} + if it is desired to stop parsing immediately.""" self.failAction = fn return self - def _skipIgnorables( self, instring, loc ): + def _skipIgnorables(self, instring, loc): exprsFound = True while exprsFound: exprsFound = False for e in self.ignoreExprs: try: while 1: - loc,dummy = e._parse( instring, loc ) + loc, dummy = e._parse(instring, loc) exprsFound = True except ParseException: pass return loc - def preParse( self, instring, loc ): + def preParse(self, instring, loc): if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) + loc = self._skipIgnorables(instring, loc) if self.skipWhitespace: wt = self.whiteChars @@ -1360,90 +1589,98 @@ def preParse( self, instring, loc ): return loc - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): return loc, [] - def postParse( self, instring, loc, tokenlist ): + def postParse(self, instring, loc, tokenlist): return tokenlist - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) + # ~ @profile + def _parseNoCache(self, instring, loc, doActions=True, callPreParse=True): + debugging = self.debug # and doActions ) if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) + # ~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) + if self.debugActions[0]: + self.debugActions[0](instring, loc, self) if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) + preloc = self.preParse(instring, loc) else: preloc = loc tokensStart = preloc try: try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) + loc, tokens = self.parseImpl(instring, preloc, doActions) except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) + raise ParseException(instring, len(instring), self.errmsg, self) except ParseBaseException as err: - #~ print ("Exception raised:", err) + # ~ print ("Exception raised:", err) if self.debugActions[2]: - self.debugActions[2]( instring, tokensStart, self, err ) + self.debugActions[2](instring, tokensStart, self, err) if self.failAction: - self.failAction( instring, tokensStart, self, err ) + self.failAction(instring, tokensStart, self, err) raise else: if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) + preloc = self.preParse(instring, loc) else: preloc = loc tokensStart = preloc if self.mayIndexError or preloc >= len(instring): try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) + loc, tokens = self.parseImpl(instring, preloc, doActions) except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) + raise ParseException(instring, len(instring), self.errmsg, self) else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) + loc, tokens = self.parseImpl(instring, preloc, doActions) - tokens = self.postParse( instring, loc, tokens ) + tokens = self.postParse(instring, loc, tokens) - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) + retTokens = ParseResults( + tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults + ) if self.parseAction and (doActions or self.callDuringTry): if debugging: try: for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) + tokens = fn(instring, tokensStart, retTokens) if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) + retTokens = ParseResults( + tokens, + self.resultsName, + asList=self.saveAsList + and isinstance(tokens, (ParseResults, list)), + modal=self.modalResults, + ) except ParseBaseException as err: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - self.debugActions[2]( instring, tokensStart, self, err ) + # ~ print "Exception raised in user parse action:", err + if self.debugActions[2]: + self.debugActions[2](instring, tokensStart, self, err) raise else: for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) + tokens = fn(instring, tokensStart, retTokens) if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) + retTokens = ParseResults( + tokens, + self.resultsName, + asList=self.saveAsList + and isinstance(tokens, (ParseResults, list)), + modal=self.modalResults, + ) if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) + # ~ print ("Matched",self,"->",retTokens.asList()) + if self.debugActions[1]: + self.debugActions[1](instring, tokensStart, loc, self, retTokens) return loc, retTokens - def tryParse( self, instring, loc ): + def tryParse(self, instring, loc): try: - return self._parse( instring, loc, doActions=False )[0] + return self._parse(instring, loc, doActions=False)[0] except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - + raise ParseException(instring, loc, self.errmsg, self) + def canParseNext(self, instring, loc): try: self.tryParse(instring, loc) @@ -1465,7 +1702,7 @@ def set(self, key, value): def clear(self): cache.clear() - + def cache_len(self): return len(cache) @@ -1475,6 +1712,7 @@ def cache_len(self): self.__len__ = types.MethodType(cache_len, self) if _OrderedDict is not None: + class _FifoCache(object): def __init__(self, size): self.not_in_cache = not_in_cache = object() @@ -1504,6 +1742,7 @@ def cache_len(self): self.__len__ = types.MethodType(cache_len, self) else: + class _FifoCache(object): def __init__(self, size): self.not_in_cache = not_in_cache = object() @@ -1533,13 +1772,15 @@ def cache_len(self): self.__len__ = types.MethodType(cache_len, self) # argument cache for optimizing repeated calls when backtracking through recursive expressions - packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail + packrat_cache = ( + {} + ) # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail packrat_cache_lock = RLock() packrat_cache_stats = [0, 0] # this method gets repeatedly called during backtracking with the same arguments - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): + def _parseCache(self, instring, loc, doActions=True, callPreParse=True): HIT, MISS = 0, 1 lookup = (self, instring, loc, callPreParse, doActions) with ParserElement.packrat_cache_lock: @@ -1567,35 +1808,38 @@ def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): @staticmethod def resetCache(): ParserElement.packrat_cache.clear() - ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) + ParserElement.packrat_cache_stats[:] = [0] * len( + ParserElement.packrat_cache_stats + ) _packratEnabled = False + @staticmethod def enablePackrat(cache_size_limit=128): """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - Parameters: - - cache_size_limit - (default=C{128}) - if an integer value is provided - will limit the size of the packrat cache; if None is passed, then - the cache size will be unbounded; if 0 is passed, the cache will - be effectively disabled. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - - Example:: - import pyparsing - pyparsing.ParserElement.enablePackrat() + Repeated parse attempts at the same string location (which happens + often in many complex grammars) can immediately return a cached value, + instead of re-executing parsing/validating code. Memoizing is done of + both valid results and parsing exceptions. + + Parameters: + - cache_size_limit - (default=C{128}) - if an integer value is provided + will limit the size of the packrat cache; if None is passed, then + the cache size will be unbounded; if 0 is passed, the cache will + be effectively disabled. + + This speedup may break existing programs that use parse actions that + have side-effects. For this reason, packrat parsing is disabled when + you first import pyparsing. To activate the packrat feature, your + program must call the class method C{ParserElement.enablePackrat()}. If + your program uses C{psyco} to "compile as you go", you must call + C{enablePackrat} before calling C{psyco.full()}. If you do not do this, + Python will crash. For best results, call C{enablePackrat()} immediately + after importing pyparsing. + + Example:: + import pyparsing + pyparsing.ParserElement.enablePackrat() """ if not ParserElement._packratEnabled: ParserElement._packratEnabled = True @@ -1605,7 +1849,7 @@ def enablePackrat(cache_size_limit=128): ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) ParserElement._parse = ParserElement._parseCache - def parseString( self, instring, parseAll=False ): + def parseString(self, instring, parseAll=False): """ Execute the parse expression with the given string. This is the main interface to the client code, once the complete @@ -1627,7 +1871,7 @@ def parseString( self, instring, parseAll=False ): reference the input string using the parse action's C{s} argument - explicitly expand the tabs in your input string before calling C{parseString} - + Example:: Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text @@ -1635,17 +1879,17 @@ def parseString( self, instring, parseAll=False ): ParserElement.resetCache() if not self.streamlined: self.streamline() - #~ self.saveAsList = True + # ~ self.saveAsList = True for e in self.ignoreExprs: e.streamline() if not self.keepTabs: instring = instring.expandtabs() try: - loc, tokens = self._parse( instring, 0 ) + loc, tokens = self._parse(instring, 0) if parseAll: - loc = self.preParse( instring, loc ) + loc = self.preParse(instring, loc) se = Empty() + StringEnd() - se._parse( instring, loc ) + se._parse(instring, loc) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1655,7 +1899,7 @@ def parseString( self, instring, parseAll=False ): else: return tokens - def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): + def scanString(self, instring, maxMatches=_MAX_INT, overlap=False): """ Scan the input string for expression matches. Each match will return the matching tokens, start location, and end location. May be called with optional @@ -1672,9 +1916,9 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): for tokens,start,end in Word(alphas).scanString(source): print(' '*start + '^'*(end-start)) print(' '*start + tokens[0]) - + prints:: - + sldjf123lsdjjkf345sldkjf879lkjsfd987 ^^^^^ sldjf @@ -1701,16 +1945,16 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): try: while loc <= instrlen and matches < maxMatches: try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) + preloc = preparseFn(instring, loc) + nextLoc, tokens = parseFn(instring, preloc, callPreParse=False) except ParseException: - loc = preloc+1 + loc = preloc + 1 else: if nextLoc > loc: matches += 1 yield tokens, preloc, nextLoc if overlap: - nextloc = preparseFn( instring, loc ) + nextloc = preparseFn(instring, loc) if nextloc > loc: loc = nextLoc else: @@ -1718,7 +1962,7 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): else: loc = nextLoc else: - loc = preloc+1 + loc = preloc + 1 except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1726,7 +1970,7 @@ def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc - def transformString( self, instring ): + def transformString(self, instring): """ Extension to C{L{scanString}}, to modify matching text with modified tokens that may be returned from a parse action. To use C{transformString}, define a grammar and @@ -1734,11 +1978,11 @@ def transformString( self, instring ): Invoking C{transformString()} on a target string will then scan for matches, and replace the matched text patterns according to the logic in the parse action. C{transformString()} returns the resulting transformed string. - + Example:: wd = Word(alphas) wd.setParseAction(lambda toks: toks[0].title()) - + print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) Prints:: Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. @@ -1749,19 +1993,19 @@ def transformString( self, instring ): # keep string locs straight between transformString and scanString self.keepTabs = True try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) + for t, s, e in self.scanString(instring): + out.append(instring[lastE:s]) if t: - if isinstance(t,ParseResults): + if isinstance(t, ParseResults): out += t.asList() - elif isinstance(t,list): + elif isinstance(t, list): out += t else: out.append(t) lastE = e out.append(instring[lastE:]) out = [o for o in out if o] - return "".join(map(_ustr,_flatten(out))) + return "".join(map(_ustr, _flatten(out))) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1769,16 +2013,16 @@ def transformString( self, instring ): # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc - def searchString( self, instring, maxMatches=_MAX_INT ): + def searchString(self, instring, maxMatches=_MAX_INT): """ Another extension to C{L{scanString}}, simplifying the access to the tokens found to match the given parse expression. May be called with optional C{maxMatches} argument, to clip searching after 'n' matches are found. - + Example:: # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters cap_word = Word(alphas.upper(), alphas.lower()) - + print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) # the sum() builtin can be used to merge results into a single ParseResults object @@ -1788,7 +2032,9 @@ def searchString( self, instring, maxMatches=_MAX_INT ): ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] """ try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) + return ParseResults( + [t for t, s, e in self.scanString(instring, maxMatches)] + ) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise @@ -1802,8 +2048,8 @@ def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): May be called with optional C{maxsplit} argument, to limit the number of splits; and the optional C{includeSeparators} argument (default=C{False}), if the separating matching text should be included in the split results. - - Example:: + + Example:: punc = oneOf(list(".,;:/-!?")) print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) prints:: @@ -1811,18 +2057,18 @@ def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): """ splits = 0 last = 0 - for t,s,e in self.scanString(instring, maxMatches=maxsplit): + for t, s, e in self.scanString(instring, maxMatches=maxsplit): yield instring[last:s] if includeSeparators: yield t[0] last = e yield instring[last:] - def __add__(self, other ): + def __add__(self, other): """ Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement converts them to L{Literal}s by default. - + Example:: greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" @@ -1830,23 +2076,29 @@ def __add__(self, other ): Prints:: Hello, World! -> ['Hello', ',', 'World', '!'] """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return And( [ self, other ] ) + return And([self, other]) - def __radd__(self, other ): + def __radd__(self, other): """ Implementation of + operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other + self @@ -1854,27 +2106,33 @@ def __sub__(self, other): """ Implementation of - operator, returns C{L{And}} with error stop """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return self + And._ErrorStop() + other - def __rsub__(self, other ): + def __rsub__(self, other): """ Implementation of - operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other - self - def __mul__(self,other): + def __mul__(self, other): """ Implementation of * operator, allows use of C{expr * 3} in place of C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer @@ -1894,162 +2152,190 @@ def __mul__(self,other): occurrences. If this behavior is desired, then write C{expr*(None,n) + ~expr} """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): + if isinstance(other, int): + minElements, optElements = other, 0 + elif isinstance(other, tuple): other = (other + (None, None))[:2] if other[0] is None: other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: + if isinstance(other[0], int) and other[1] is None: if other[0] == 0: return ZeroOrMore(self) if other[0] == 1: return OneOrMore(self) else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): + return self * other[0] + ZeroOrMore(self) + elif isinstance(other[0], int) and isinstance(other[1], int): minElements, optElements = other optElements -= minElements else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) + raise TypeError( + "cannot multiply 'ParserElement' and ('%s','%s') objects", + type(other[0]), + type(other[1]), + ) else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) + raise TypeError( + "cannot multiply 'ParserElement' and '%s' objects", type(other) + ) if minElements < 0: raise ValueError("cannot multiply ParserElement by negative value") if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") + raise ValueError( + "second tuple value must be greater or equal to first tuple value" + ) if minElements == optElements == 0: raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - if (optElements): + if optElements: + def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) + if n > 1: + return Optional(self + makeOptionalList(n - 1)) else: return Optional(self) + if minElements: if minElements == 1: ret = self + makeOptionalList(optElements) else: - ret = And([self]*minElements) + makeOptionalList(optElements) + ret = And([self] * minElements) + makeOptionalList(optElements) else: ret = makeOptionalList(optElements) else: if minElements == 1: ret = self else: - ret = And([self]*minElements) + ret = And([self] * minElements) return ret def __rmul__(self, other): return self.__mul__(other) - def __or__(self, other ): + def __or__(self, other): """ Implementation of | operator - returns C{L{MatchFirst}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return MatchFirst( [ self, other ] ) + return MatchFirst([self, other]) - def __ror__(self, other ): + def __ror__(self, other): """ Implementation of | operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other | self - def __xor__(self, other ): + def __xor__(self, other): """ Implementation of ^ operator - returns C{L{Or}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return Or( [ self, other ] ) + return Or([self, other]) - def __rxor__(self, other ): + def __rxor__(self, other): """ Implementation of ^ operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other ^ self - def __and__(self, other ): + def __and__(self, other): """ Implementation of & operator - returns C{L{Each}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None - return Each( [ self, other ] ) + return Each([self, other]) - def __rand__(self, other ): + def __rand__(self, other): """ Implementation of & operator when left operand is not a C{L{ParserElement}} """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + if not isinstance(other, ParserElement): + warnings.warn( + "Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, + stacklevel=2, + ) return None return other & self - def __invert__( self ): + def __invert__(self): """ Implementation of ~ operator - returns C{L{NotAny}} """ - return NotAny( self ) + return NotAny(self) def __call__(self, name=None): """ Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}. - + If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be passed as C{True}. - + If C{name} is omitted, same as calling C{L{copy}}. Example:: # these are equivalent userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") + userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") """ if name is not None: return self.setResultsName(name) else: return self.copy() - def suppress( self ): + def suppress(self): """ Suppresses the output of this C{ParserElement}; useful to keep punctuation from cluttering up returned output. """ - return Suppress( self ) + return Suppress(self) - def leaveWhitespace( self ): + def leaveWhitespace(self): """ Disables the skipping of whitespace before matching the characters in the C{ParserElement}'s defined pattern. This is normally only used internally by @@ -2058,7 +2344,7 @@ def leaveWhitespace( self ): self.skipWhitespace = False return self - def setWhitespaceChars( self, chars ): + def setWhitespaceChars(self, chars): """ Overrides the default whitespace chars """ @@ -2067,7 +2353,7 @@ def setWhitespaceChars( self, chars ): self.copyDefaultWhiteChars = False return self - def parseWithTabs( self ): + def parseWithTabs(self): """ Overrides default behavior to expand C{}s to spaces before parsing the input string. Must be called before C{parseString} when the input grammar contains elements that @@ -2076,40 +2362,42 @@ def parseWithTabs( self ): self.keepTabs = True return self - def ignore( self, other ): + def ignore(self, other): """ Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns. - + Example:: patt = OneOrMore(Word(alphas)) patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] - + patt.ignore(cStyleComment) patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] """ if isinstance(other, basestring): other = Suppress(other) - if isinstance( other, Suppress ): + if isinstance(other, Suppress): if other not in self.ignoreExprs: self.ignoreExprs.append(other) else: - self.ignoreExprs.append( Suppress( other.copy() ) ) + self.ignoreExprs.append(Suppress(other.copy())) return self - def setDebugActions( self, startAction, successAction, exceptionAction ): + def setDebugActions(self, startAction, successAction, exceptionAction): """ Enable display of debugging messages while doing pattern matching. """ - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) + self.debugActions = ( + startAction or _defaultStartDebugAction, + successAction or _defaultSuccessDebugAction, + exceptionAction or _defaultExceptionDebugAction, + ) self.debug = True return self - def setDebug( self, flag=True ): + def setDebug(self, flag=True): """ Enable display of debugging messages while doing pattern matching. Set C{flag} to True to enable, False to disable. @@ -2118,12 +2406,12 @@ def setDebug( self, flag=True ): wd = Word(alphas).setName("alphaword") integer = Word(nums).setName("numword") term = wd | integer - + # turn on debugging for wd wd.setDebug() OneOrMore(term).parseString("abc 123 xyz 890") - + prints:: Match alphaword at loc 0(1,1) Matched alphaword -> ['abc'] @@ -2145,32 +2433,36 @@ def setDebug( self, flag=True ): name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}. """ if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) + self.setDebugActions( + _defaultStartDebugAction, + _defaultSuccessDebugAction, + _defaultExceptionDebugAction, + ) else: self.debug = False return self - def __str__( self ): + def __str__(self): return self.name - def __repr__( self ): + def __repr__(self): return _ustr(self) - def streamline( self ): + def streamline(self): self.streamlined = True self.strRepr = None return self - def checkRecursion( self, parseElementList ): + def checkRecursion(self, parseElementList): pass - def validate( self, validateTrace=[] ): + def validate(self, validateTrace=[]): """ Check defined expressions for valid structure, check for infinite recursive definitions. """ - self.checkRecursion( [] ) + self.checkRecursion([]) - def parseFile( self, file_or_filename, parseAll=False ): + def parseFile(self, file_or_filename, parseAll=False): """ Execute the parse expression on the given file or filename. If a filename is specified (instead of a file object), @@ -2190,35 +2482,35 @@ def parseFile( self, file_or_filename, parseAll=False ): # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc - def __eq__(self,other): + def __eq__(self, other): if isinstance(other, ParserElement): return self is other or vars(self) == vars(other) elif isinstance(other, basestring): return self.matches(other) else: - return super(ParserElement,self)==other + return super(ParserElement, self) == other - def __ne__(self,other): + def __ne__(self, other): return not (self == other) def __hash__(self): return hash(id(self)) - def __req__(self,other): + def __req__(self, other): return self == other - def __rne__(self,other): + def __rne__(self, other): return not (self == other) def matches(self, testString, parseAll=True): """ - Method for quick testing of a parser against a test string. Good for simple + Method for quick testing of a parser against a test string. Good for simple inline microtests of sub expressions while building up larger parser. - + Parameters: - testString - to test against this expression for a match - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - + Example:: expr = Word(nums) assert expr.matches("100") @@ -2228,17 +2520,25 @@ def matches(self, testString, parseAll=True): return True except ParseBaseException: return False - - def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): + + def runTests( + self, + tests, + parseAll=True, + comment='#', + fullDump=True, + printResults=True, + failureTests=False, + ): """ Execute the parse expression on a series of test strings, showing each test, the parsed results or where the parse failed. Quick and easy way to run a parse expression against a list of sample strings. - + Parameters: - tests - a list of separate test strings, or a multiline string of test strings - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - comment - (default=C{'#'}) - expression for indicating embedded comments in the test + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + - comment - (default=C{'#'}) - expression for indicating embedded comments in the test string; pass None to disable comment filtering - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; if False, only dump nested list @@ -2246,9 +2546,9 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing Returns: a (success, results) tuple, where success indicates that all tests succeeded - (or failed if C{failureTests} is True), and the results contain a list of lines of each + (or failed if C{failureTests} is True), and the results contain a list of lines of each test's output - + Example:: number_expr = pyparsing_common.number.copy() @@ -2291,7 +2591,7 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult [1e-12] Success - + # stray character 100Z ^ @@ -2313,7 +2613,7 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult lines, create a test like this:: expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines") - + (Note that this is a raw string literal, you must include the leading 'r'.) """ if isinstance(tests, basestring): @@ -2332,7 +2632,7 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult out = ['\n'.join(comments), t] comments = [] try: - t = t.replace(r'\n','\n') + t = t.replace(r'\n', '\n') result = self.parseString(t, parseAll=parseAll) out.append(result.dump(full=fullDump)) success = success and not failureTests @@ -2340,9 +2640,9 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" if '\n' in t: out.append(line(pe.loc, t)) - out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) + out.append(' ' * (col(pe.loc, t) - 1) + '^' + fatal) else: - out.append(' '*pe.loc + '^' + fatal) + out.append(' ' * pe.loc + '^' + fatal) out.append("FAIL: " + str(pe)) success = success and failureTests result = pe @@ -2357,24 +2657,26 @@ def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResult print('\n'.join(out)) allResults.append((t, result)) - + return success, allResults - + class Token(ParserElement): """ Abstract C{ParserElement} subclass, for defining atomic matching patterns. """ - def __init__( self ): - super(Token,self).__init__( savelist=False ) + + def __init__(self): + super(Token, self).__init__(savelist=False) class Empty(Token): """ An empty token, will always match. """ - def __init__( self ): - super(Empty,self).__init__() + + def __init__(self): + super(Empty, self).__init__() self.name = "Empty" self.mayReturnEmpty = True self.mayIndexError = False @@ -2384,40 +2686,45 @@ class NoMatch(Token): """ A token that will never match. """ - def __init__( self ): - super(NoMatch,self).__init__() + + def __init__(self): + super(NoMatch, self).__init__() self.name = "NoMatch" self.mayReturnEmpty = True self.mayIndexError = False self.errmsg = "Unmatchable token" - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): raise ParseException(instring, loc, self.errmsg, self) class Literal(Token): """ Token to exactly match a specified string. - + Example:: Literal('blah').parseString('blah') # -> ['blah'] Literal('blah').parseString('blahfooblah') # -> ['blah'] Literal('blah').parseString('bla') # -> Exception: Expected "blah" - + For case-insensitive matching, use L{CaselessLiteral}. - + For keyword matching (force word break before and after the matched string), use L{Keyword} or L{CaselessKeyword}. """ - def __init__( self, matchString ): - super(Literal,self).__init__() + + def __init__(self, matchString): + super(Literal, self).__init__() self.match = matchString self.matchLen = len(matchString) try: self.firstMatchChar = matchString[0] except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) + warnings.warn( + "null string passed to Literal; use Empty() instead", + SyntaxWarning, + stacklevel=2, + ) self.__class__ = Empty self.name = '"%s"' % _ustr(self.match) self.errmsg = "Expected " + self.name @@ -2427,15 +2734,19 @@ def __init__( self, matchString ): # Performance tuning: this routine gets called a *lot* # if this is a single character match string and the first character matches, # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match + # ~ @profile + def parseImpl(self, instring, loc, doActions=True): + if instring[loc] == self.firstMatchChar and ( + self.matchLen == 1 or instring.startswith(self.match, loc) + ): + return loc + self.matchLen, self.match raise ParseException(instring, loc, self.errmsg, self) + + _L = Literal ParserElement._literalStringClass = Literal + class Keyword(Token): """ Token to exactly match a specified string as a keyword, that is, it must be @@ -2446,17 +2757,18 @@ class Keyword(Token): - C{identChars} is a string of characters that would be valid identifier characters, defaulting to all alphanumerics + "_" and "$" - C{caseless} allows case-insensitive matching, default is C{False}. - + Example:: Keyword("start").parseString("start") # -> ['start'] Keyword("start").parseString("starting") # -> Exception For case-insensitive matching, use L{CaselessKeyword}. """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - def __init__( self, matchString, identChars=None, caseless=False ): - super(Keyword,self).__init__() + DEFAULT_KEYWORD_CHARS = alphanums + "_$" + + def __init__(self, matchString, identChars=None, caseless=False): + super(Keyword, self).__init__() if identChars is None: identChars = Keyword.DEFAULT_KEYWORD_CHARS self.match = matchString @@ -2464,8 +2776,11 @@ def __init__( self, matchString, identChars=None, caseless=False ): try: self.firstMatchChar = matchString[0] except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) + warnings.warn( + "null string passed to Keyword; use Empty() instead", + SyntaxWarning, + stacklevel=2, + ) self.name = '"%s"' % self.match self.errmsg = "Expected " + self.name self.mayReturnEmpty = False @@ -2476,31 +2791,41 @@ def __init__( self, matchString, identChars=None, caseless=False ): identChars = identChars.upper() self.identChars = set(identChars) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match + if ( + (instring[loc : loc + self.matchLen].upper() == self.caselessmatch) + and ( + loc >= len(instring) - self.matchLen + or instring[loc + self.matchLen].upper() not in self.identChars + ) + and (loc == 0 or instring[loc - 1].upper() not in self.identChars) + ): + return loc + self.matchLen, self.match else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match + if ( + instring[loc] == self.firstMatchChar + and (self.matchLen == 1 or instring.startswith(self.match, loc)) + and ( + loc >= len(instring) - self.matchLen + or instring[loc + self.matchLen] not in self.identChars + ) + and (loc == 0 or instring[loc - 1] not in self.identChars) + ): + return loc + self.matchLen, self.match raise ParseException(instring, loc, self.errmsg, self) def copy(self): - c = super(Keyword,self).copy() + c = super(Keyword, self).copy() c.identChars = Keyword.DEFAULT_KEYWORD_CHARS return c @staticmethod - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ + def setDefaultKeywordChars(chars): + """Overrides the default Keyword chars""" Keyword.DEFAULT_KEYWORD_CHARS = chars + class CaselessLiteral(Literal): """ Token to match a specified string, ignoring case of letters. @@ -2509,52 +2834,58 @@ class CaselessLiteral(Literal): Example:: OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] - + (Contrast with example for L{CaselessKeyword}.) """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) + + def __init__(self, matchString): + super(CaselessLiteral, self).__init__(matchString.upper()) # Preserve the defining literal. self.returnString = matchString self.name = "'%s'" % self.returnString self.errmsg = "Expected " + self.name - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString + def parseImpl(self, instring, loc, doActions=True): + if instring[loc : loc + self.matchLen].upper() == self.match: + return loc + self.matchLen, self.returnString raise ParseException(instring, loc, self.errmsg, self) + class CaselessKeyword(Keyword): """ Caseless version of L{Keyword}. Example:: OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] - + (Contrast with example for L{CaselessLiteral}.) """ - def __init__( self, matchString, identChars=None ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match + def __init__(self, matchString, identChars=None): + super(CaselessKeyword, self).__init__(matchString, identChars, caseless=True) + + def parseImpl(self, instring, loc, doActions=True): + if (instring[loc : loc + self.matchLen].upper() == self.caselessmatch) and ( + loc >= len(instring) - self.matchLen + or instring[loc + self.matchLen].upper() not in self.identChars + ): + return loc + self.matchLen, self.match raise ParseException(instring, loc, self.errmsg, self) + class CloseMatch(Token): """ - A variation on L{Literal} which matches "close" matches, that is, + A variation on L{Literal} which matches "close" matches, that is, strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters: - C{match_string} - string to be matched - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match - + The results from a successful parse will contain the matched text from the input string and the following named results: - C{mismatches} - a list of the positions within the match_string where mismatches were found - C{original} - the original match_string used to compare against the input string - + If C{mismatches} is an empty list, then the match was an exact match. - + Example:: patt = CloseMatch("ATCATCGAATGGA") patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) @@ -2567,16 +2898,20 @@ class CloseMatch(Token): patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2) patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) """ + def __init__(self, match_string, maxMismatches=1): - super(CloseMatch,self).__init__() + super(CloseMatch, self).__init__() self.name = match_string self.match_string = match_string self.maxMismatches = maxMismatches - self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches) + self.errmsg = "Expected %r (with up to %d mismatches)" % ( + self.match_string, + self.maxMismatches, + ) self.mayIndexError = False self.mayReturnEmpty = False - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): start = loc instrlen = len(instring) maxloc = start + len(self.match_string) @@ -2587,8 +2922,10 @@ def parseImpl( self, instring, loc, doActions=True ): mismatches = [] maxMismatches = self.maxMismatches - for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)): - src,mat = s_m + for match_stringloc, s_m in enumerate( + zip(instring[loc:maxloc], self.match_string) + ): + src, mat = s_m if src != mat: mismatches.append(match_stringloc) if len(mismatches) > maxMismatches: @@ -2612,14 +2949,14 @@ class Word(Token): maximum, and/or exact length. The default value for C{min} is 1 (a minimum value < 1 is not valid); the default values for C{max} and C{exact} are 0, meaning no maximum or exact length restriction. An optional - C{excludeChars} parameter can list characters that might be found in + C{excludeChars} parameter can list characters that might be found in the input C{bodyChars} string; useful to define a word of all printables except for one or two characters, for instance. - - L{srange} is useful for defining custom character set strings for defining + + L{srange} is useful for defining custom character set strings for defining C{Word} expressions, using range notation from regular expression character sets. - - A common mistake is to use C{Word} to match a specific literal string, as in + + A common mistake is to use C{Word} to match a specific literal string, as in C{Word("Address")}. Remember that C{Word} uses the string argument to define I{sets} of matchable characters. This expression would match "Add", "AAA", "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. @@ -2637,28 +2974,38 @@ class Word(Token): Example:: # a word composed of digits integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) - + # a word with a leading capital, and zero or more lowercase capital_word = Word(alphas.upper(), alphas.lower()) # hostnames are alphanumeric, with leading alpha, and '-' hostname = Word(alphas, alphanums+'-') - + # roman numeral (not a strict parser, accepts invalid mix of characters) roman = Word("IVXLCDM") - + # any string of non-whitespace characters, except for ',' csv_value = Word(printables, excludeChars=",") """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): - super(Word,self).__init__() + + def __init__( + self, + initChars, + bodyChars=None, + min=1, + max=0, + exact=0, + asKeyword=False, + excludeChars=None, + ): + super(Word, self).__init__() if excludeChars: initChars = ''.join(c for c in initChars if c not in excludeChars) if bodyChars: bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) self.initCharsOrig = initChars self.initChars = set(initChars) - if bodyChars : + if bodyChars: self.bodyCharsOrig = bodyChars self.bodyChars = set(bodyChars) else: @@ -2668,7 +3015,9 @@ def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword= self.maxSpecified = max > 0 if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") + raise ValueError( + "cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted" + ) self.minLen = min @@ -2686,34 +3035,38 @@ def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword= self.mayIndexError = False self.asKeyword = asKeyword - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): + if ' ' not in self.initCharsOrig + self.bodyCharsOrig and ( + min == 1 and max == 0 and exact == 0 + ): if self.bodyCharsOrig == self.initCharsOrig: self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) elif len(self.initCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) + self.reString = "%s[%s]*" % ( + re.escape(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig), + ) else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) + self.reString = "[%s][%s]*" % ( + _escapeRegexRangeChars(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig), + ) if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" + self.reString = r"\b" + self.reString + r"\b" try: - self.re = re.compile( self.reString ) + self.re = re.compile(self.reString) except Exception: self.re = None - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.re: - result = self.re.match(instring,loc) + result = self.re.match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) loc = result.end() return loc, result.group() - if not(instring[ loc ] in self.initChars): + if not (instring[loc] in self.initChars): raise ParseException(instring, loc, self.errmsg, self) start = loc @@ -2721,7 +3074,7 @@ def parseImpl( self, instring, loc, doActions=True ): instrlen = len(instring) bodychars = self.bodyChars maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) + maxloc = min(maxloc, instrlen) while loc < maxloc and instring[loc] in bodychars: loc += 1 @@ -2731,7 +3084,9 @@ def parseImpl( self, instring, loc, doActions=True ): if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: throwException = True if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc 0 and instring[start - 1] in bodychars) or ( + loc < instrlen and instring[loc] in bodychars + ): throwException = True if throwException: @@ -2739,23 +3094,25 @@ def parseImpl( self, instring, loc, doActions=True ): return loc, instring[start:loc] - def __str__( self ): + def __str__(self): try: - return super(Word,self).__str__() + return super(Word, self).__str__() except Exception: pass - if self.strRepr is None: def charsAsStr(s): - if len(s)>4: - return s[:4]+"..." + if len(s) > 4: + return s[:4] + "..." else: return s - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) + if self.initCharsOrig != self.bodyCharsOrig: + self.strRepr = "W:(%s,%s)" % ( + charsAsStr(self.initCharsOrig), + charsAsStr(self.bodyCharsOrig), + ) else: self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) @@ -2766,7 +3123,7 @@ class Regex(Token): r""" Token for matching strings that match a given regular expression. Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - If the given regex contains named groups (defined using C{(?P...)}), these will be preserved as + If the given regex contains named groups (defined using C{(?P...)}), these will be preserved as named parse results. Example:: @@ -2776,14 +3133,18 @@ class Regex(Token): roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") """ compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): + + def __init__(self, pattern, flags=0): """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() + super(Regex, self).__init__() if isinstance(pattern, basestring): if not pattern: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) + warnings.warn( + "null string passed to Regex; use Empty() instead", + SyntaxWarning, + stacklevel=2, + ) self.pattern = pattern self.flags = flags @@ -2792,26 +3153,30 @@ def __init__( self, pattern, flags=0): self.re = re.compile(self.pattern, self.flags) self.reString = self.pattern except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) + warnings.warn( + "invalid pattern (%s) passed to Regex" % pattern, + SyntaxWarning, + stacklevel=2, + ) raise elif isinstance(pattern, Regex.compiledREtype): self.re = pattern - self.pattern = \ - self.reString = str(pattern) + self.pattern = self.reString = str(pattern) self.flags = flags - + else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") + raise ValueError( + "Regex may only be constructed with a string or a compiled RE object" + ) self.name = _ustr(self) self.errmsg = "Expected " + self.name self.mayIndexError = False self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) + def parseImpl(self, instring, loc, doActions=True): + result = self.re.match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -2821,11 +3186,11 @@ def parseImpl( self, instring, loc, doActions=True ): if d: for k in d: ret[k] = d[k] - return loc,ret + return loc, ret - def __str__( self ): + def __str__(self): try: - return super(Regex,self).__str__() + return super(Regex, self).__str__() except Exception: pass @@ -2838,7 +3203,7 @@ def __str__( self ): class QuotedString(Token): r""" Token for matching strings that are delimited by quoting characters. - + Defined with the following parameters: - quoteChar - string of one or more characters defining the quote delimiting string - escChar - character to escape quotes, typically backslash (default=C{None}) @@ -2860,13 +3225,25 @@ class QuotedString(Token): [['This is the "quote"']] [['This is the quote with "embedded" quotes']] """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): - super(QuotedString,self).__init__() + + def __init__( + self, + quoteChar, + escChar=None, + escQuote=None, + multiline=False, + unquoteResults=True, + endQuoteChar=None, + convertWhitespaceEscapes=True, + ): + super(QuotedString, self).__init__() # remove white space from quote chars - wont work anyway quoteChar = quoteChar.strip() if not quoteChar: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + warnings.warn( + "quoteChar cannot be the empty string", SyntaxWarning, stacklevel=2 + ) raise SyntaxError() if endQuoteChar is None: @@ -2874,7 +3251,11 @@ def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unq else: endQuoteChar = endQuoteChar.strip() if not endQuoteChar: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + warnings.warn( + "endQuoteChar cannot be the empty string", + SyntaxWarning, + stacklevel=2, + ) raise SyntaxError() self.quoteChar = quoteChar @@ -2889,35 +3270,47 @@ def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unq if multiline: self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + self.pattern = r'%s(?:[^%s%s]' % ( + re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or ''), + ) else: self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + self.pattern = r'%s(?:[^%s\n\r%s]' % ( + re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or ''), + ) if len(self.endQuoteChar) > 1: self.pattern += ( - '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' + '|(?:' + + ')|(?:'.join( + "%s[^%s]" + % ( + re.escape(self.endQuoteChar[:i]), + _escapeRegexRangeChars(self.endQuoteChar[i]), + ) + for i in range(len(self.endQuoteChar) - 1, 0, -1) ) + + ')' + ) if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) + self.pattern += r'|(?:%s)' % re.escape(escQuote) if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - self.escCharReplacePattern = re.escape(self.escChar)+"(.)" - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) + self.pattern += r'|(?:%s.)' % re.escape(escChar) + self.escCharReplacePattern = re.escape(self.escChar) + "(.)" + self.pattern += r')*%s' % re.escape(self.endQuoteChar) try: self.re = re.compile(self.pattern, self.flags) self.reString = self.pattern except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) + warnings.warn( + "invalid pattern (%s) passed to Regex" % self.pattern, + SyntaxWarning, + stacklevel=2, + ) raise self.name = _ustr(self) @@ -2925,8 +3318,12 @@ def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unq self.mayIndexError = False self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None + def parseImpl(self, instring, loc, doActions=True): + result = ( + instring[loc] == self.firstQuoteChar + and self.re.match(instring, loc) + or None + ) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -2936,18 +3333,18 @@ def parseImpl( self, instring, loc, doActions=True ): if self.unquoteResults: # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] + ret = ret[self.quoteCharLen : -self.endQuoteCharLen] - if isinstance(ret,basestring): + if isinstance(ret, basestring): # replace escaped whitespace if '\\' in ret and self.convertWhitespaceEscapes: ws_map = { - r'\t' : '\t', - r'\n' : '\n', - r'\f' : '\f', - r'\r' : '\r', + r'\t': '\t', + r'\n': '\n', + r'\f': '\f', + r'\r': '\r', } - for wslit,wschar in ws_map.items(): + for wslit, wschar in ws_map.items(): ret = ret.replace(wslit, wschar) # replace escaped characters @@ -2960,14 +3357,17 @@ def parseImpl( self, instring, loc, doActions=True ): return loc, ret - def __str__( self ): + def __str__(self): try: - return super(QuotedString,self).__str__() + return super(QuotedString, self).__str__() except Exception: pass if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) + self.strRepr = "quoted string, starting with %s ending with %s" % ( + self.quoteChar, + self.endQuoteChar, + ) return self.strRepr @@ -2988,13 +3388,16 @@ class CharsNotIn(Token): prints:: ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() + + def __init__(self, notChars, min=1, max=0, exact=0): + super(CharsNotIn, self).__init__() self.skipWhitespace = False self.notChars = notChars if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") + raise ValueError( + "cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted" + ) self.minLen = min @@ -3009,19 +3412,18 @@ def __init__( self, notChars, min=1, max=0, exact=0 ): self.name = _ustr(self) self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) + self.mayReturnEmpty = self.minLen == 0 self.mayIndexError = False - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if instring[loc] in self.notChars: raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): + maxlen = min(start + self.maxLen, len(instring)) + while loc < maxlen and (instring[loc] not in notchars): loc += 1 if loc - start < self.minLen: @@ -3029,7 +3431,7 @@ def parseImpl( self, instring, loc, doActions=True ): return loc, instring[start:loc] - def __str__( self ): + def __str__(self): try: return super(CharsNotIn, self).__str__() except Exception: @@ -3043,6 +3445,7 @@ def __str__( self ): return self.strRepr + class White(Token): """ Special matching class for matching whitespace. Normally, whitespace is ignored @@ -3051,19 +3454,23 @@ class White(Token): matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, as defined for the C{L{Word}} class. """ + whiteStrs = { - " " : "", + " ": "", "\t": "", "\n": "", "\r": "", "\f": "", - } + } + def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() + super(White, self).__init__() self.matchWhite = ws - self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) - #~ self.leaveWhitespace() - self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) + self.setWhitespaceChars( + "".join(c for c in self.whiteChars if c not in self.matchWhite) + ) + # ~ self.leaveWhitespace() + self.name = "".join(White.whiteStrs[c] for c in self.matchWhite) self.mayReturnEmpty = True self.errmsg = "Expected " + self.name @@ -3078,13 +3485,13 @@ def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): self.maxLen = exact self.minLen = exact - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): + def parseImpl(self, instring, loc, doActions=True): + if not (instring[loc] in self.matchWhite): raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) + maxloc = min(maxloc, len(instring)) while loc < maxloc and instring[loc] in self.matchWhite: loc += 1 @@ -3095,35 +3502,41 @@ def parseImpl( self, instring, loc, doActions=True ): class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ + def __init__(self): + super(_PositionToken, self).__init__() + self.name = self.__class__.__name__ self.mayReturnEmpty = True self.mayIndexError = False + class GoToColumn(_PositionToken): """ Token to advance to a specific column of input text; useful for tabular report scraping. """ - def __init__( self, colno ): - super(GoToColumn,self).__init__() + + def __init__(self, colno): + super(GoToColumn, self).__init__() self.col = colno - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: + def preParse(self, instring, loc): + if col(loc, instring) != self.col: instrlen = len(instring) if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : + loc = self._skipIgnorables(instring, loc) + while ( + loc < instrlen + and instring[loc].isspace() + and col(loc, instring) != self.col + ): loc += 1 return loc - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) + def parseImpl(self, instring, loc, doActions=True): + thiscol = col(loc, instring) if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) + raise ParseException(instring, loc, "Text not in expected column", self) newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] + ret = instring[loc:newloc] return newloc, ret @@ -3148,68 +3561,76 @@ class LineStart(_PositionToken): ['AAA', ' and this line'] """ - def __init__( self ): - super(LineStart,self).__init__() + + def __init__(self): + super(LineStart, self).__init__() self.errmsg = "Expected start of line" - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if col(loc, instring) == 1: return loc, [] raise ParseException(instring, loc, self.errmsg, self) + class LineEnd(_PositionToken): """ Matches if current position is at the end of a line within the parse string """ - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) + + def __init__(self): + super(LineEnd, self).__init__() + self.setWhitespaceChars(ParserElement.DEFAULT_WHITE_CHARS.replace("\n", "")) self.errmsg = "Expected end of line" - def parseImpl( self, instring, loc, doActions=True ): - if loc len(instring): return loc, [] else: raise ParseException(instring, loc, self.errmsg, self) + class WordStart(_PositionToken): """ Matches if the current position is at the beginning of a Word, and @@ -3218,18 +3639,22 @@ class WordStart(_PositionToken): use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of the string being parsed, or at the beginning of a line. """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() + + def __init__(self, wordChars=printables): + super(WordStart, self).__init__() self.wordChars = set(wordChars) self.errmsg = "Not at the start of a word" - def parseImpl(self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): + if ( + instring[loc - 1] in self.wordChars + or instring[loc] not in self.wordChars + ): raise ParseException(instring, loc, self.errmsg, self) return loc, [] + class WordEnd(_PositionToken): """ Matches if the current position is at the end of a Word, and @@ -3238,17 +3663,20 @@ class WordEnd(_PositionToken): use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of the string being parsed, or at the end of a line. """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() + + def __init__(self, wordChars=printables): + super(WordEnd, self).__init__() self.wordChars = set(wordChars) self.skipWhitespace = False self.errmsg = "Not at the end of a word" - def parseImpl(self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): instrlen = len(instring) - if instrlen>0 and loc 0 and loc < instrlen: + if ( + instring[loc] in self.wordChars + or instring[loc - 1] not in self.wordChars + ): raise ParseException(instring, loc, self.errmsg, self) return loc, [] @@ -3257,14 +3685,15 @@ class ParseExpression(ParserElement): """ Abstract subclass of ParserElement, for combining and post-processing parsed tokens. """ - def __init__( self, exprs, savelist = False ): - super(ParseExpression,self).__init__(savelist) - if isinstance( exprs, _generatorType ): + + def __init__(self, exprs, savelist=False): + super(ParseExpression, self).__init__(savelist) + if isinstance(exprs, _generatorType): exprs = list(exprs) - if isinstance( exprs, basestring ): - self.exprs = [ ParserElement._literalStringClass( exprs ) ] - elif isinstance( exprs, Iterable ): + if isinstance(exprs, basestring): + self.exprs = [ParserElement._literalStringClass(exprs)] + elif isinstance(exprs, Iterable): exprs = list(exprs) # if sequence of strings provided, wrap with Literal if all(isinstance(expr, basestring) for expr in exprs): @@ -3272,52 +3701,52 @@ def __init__( self, exprs, savelist = False ): self.exprs = list(exprs) else: try: - self.exprs = list( exprs ) + self.exprs = list(exprs) except TypeError: - self.exprs = [ exprs ] + self.exprs = [exprs] self.callPreparse = False - def __getitem__( self, i ): + def __getitem__(self, i): return self.exprs[i] - def append( self, other ): - self.exprs.append( other ) + def append(self, other): + self.exprs.append(other) self.strRepr = None return self - def leaveWhitespace( self ): + def leaveWhitespace(self): """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on - all contained expressions.""" + all contained expressions.""" self.skipWhitespace = False - self.exprs = [ e.copy() for e in self.exprs ] + self.exprs = [e.copy() for e in self.exprs] for e in self.exprs: e.leaveWhitespace() return self - def ignore( self, other ): - if isinstance( other, Suppress ): + def ignore(self, other): + if isinstance(other, Suppress): if other not in self.ignoreExprs: - super( ParseExpression, self).ignore( other ) + super(ParseExpression, self).ignore(other) for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) + e.ignore(self.ignoreExprs[-1]) else: - super( ParseExpression, self).ignore( other ) + super(ParseExpression, self).ignore(other) for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) + e.ignore(self.ignoreExprs[-1]) return self - def __str__( self ): + def __str__(self): try: - return super(ParseExpression,self).__str__() + return super(ParseExpression, self).__str__() except Exception: pass if self.strRepr is None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) ) + self.strRepr = "%s:(%s)" % (self.__class__.__name__, _ustr(self.exprs)) return self.strRepr - def streamline( self ): - super(ParseExpression,self).streamline() + def streamline(self): + super(ParseExpression, self).streamline() for e in self.exprs: e.streamline() @@ -3325,46 +3754,51 @@ def streamline( self ): # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d ) # but only if there are no parse actions or resultsNames on the nested And's # (likewise for Or's and MatchFirst's) - if ( len(self.exprs) == 2 ): + if len(self.exprs) == 2: other = self.exprs[0] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): - self.exprs = other.exprs[:] + [ self.exprs[1] ] + if ( + isinstance(other, self.__class__) + and not (other.parseAction) + and other.resultsName is None + and not other.debug + ): + self.exprs = other.exprs[:] + [self.exprs[1]] self.strRepr = None self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError + self.mayIndexError |= other.mayIndexError other = self.exprs[-1] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): + if ( + isinstance(other, self.__class__) + and not (other.parseAction) + and other.resultsName is None + and not other.debug + ): self.exprs = self.exprs[:-1] + other.exprs[:] self.strRepr = None self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError + self.mayIndexError |= other.mayIndexError self.errmsg = "Expected " + _ustr(self) - + return self - def setResultsName( self, name, listAllMatches=False ): - ret = super(ParseExpression,self).setResultsName(name,listAllMatches) + def setResultsName(self, name, listAllMatches=False): + ret = super(ParseExpression, self).setResultsName(name, listAllMatches) return ret - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] + def validate(self, validateTrace=[]): + tmp = validateTrace[:] + [self] for e in self.exprs: e.validate(tmp) - self.checkRecursion( [] ) - + self.checkRecursion([]) + def copy(self): - ret = super(ParseExpression,self).copy() + ret = super(ParseExpression, self).copy() ret.exprs = [e.copy() for e in self.exprs] return ret + class And(ParseExpression): """ Requires all given C{ParseExpression}s to be found in the given order. @@ -3383,21 +3817,23 @@ class And(ParseExpression): class _ErrorStop(Empty): def __init__(self, *args, **kwargs): - super(And._ErrorStop,self).__init__(*args, **kwargs) + super(And._ErrorStop, self).__init__(*args, **kwargs) self.name = '-' self.leaveWhitespace() - def __init__( self, exprs, savelist = True ): - super(And,self).__init__(exprs, savelist) + def __init__(self, exprs, savelist=True): + super(And, self).__init__(exprs, savelist) self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - self.setWhitespaceChars( self.exprs[0].whiteChars ) + self.setWhitespaceChars(self.exprs[0].whiteChars) self.skipWhitespace = self.exprs[0].skipWhitespace self.callPreparse = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): # pass False as last arg to _parse for first element, since we already # pre-parsed the string as part of our And pre-parsing - loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False ) + loc, resultlist = self.exprs[0]._parse( + instring, loc, doActions, callPreParse=False + ) errorStop = False for e in self.exprs[1:]: if isinstance(e, And._ErrorStop): @@ -3405,34 +3841,36 @@ def parseImpl( self, instring, loc, doActions=True ): continue if errorStop: try: - loc, exprtokens = e._parse( instring, loc, doActions ) + loc, exprtokens = e._parse(instring, loc, doActions) except ParseSyntaxException: raise except ParseBaseException as pe: pe.__traceback__ = None raise ParseSyntaxException._from_exception(pe) except IndexError: - raise ParseSyntaxException(instring, len(instring), self.errmsg, self) + raise ParseSyntaxException( + instring, len(instring), self.errmsg, self + ) else: - loc, exprtokens = e._parse( instring, loc, doActions ) + loc, exprtokens = e._parse(instring, loc, doActions) if exprtokens or exprtokens.haskeys(): resultlist += exprtokens return loc, resultlist - def __iadd__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #And( [ self, other ] ) + def __iadd__(self, other): + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + return self.append(other) # And( [ self, other ] ) - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) if not e.mayReturnEmpty: break - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3449,26 +3887,27 @@ class Or(ParseExpression): Example:: # construct Or using '^' operator - + number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) print(number.searchString("123 3.1416 789")) prints:: [['123'], ['3.1416'], ['789']] """ - def __init__( self, exprs, savelist = False ): - super(Or,self).__init__(exprs, savelist) + + def __init__(self, exprs, savelist=False): + super(Or, self).__init__(exprs, savelist) if self.exprs: self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) else: self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): maxExcLoc = -1 maxException = None matches = [] for e in self.exprs: try: - loc2 = e.tryParse( instring, loc ) + loc2 = e.tryParse(instring, loc) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: @@ -3476,7 +3915,9 @@ def parseImpl( self, instring, loc, doActions=True ): maxExcLoc = err.loc except IndexError: if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) + maxException = ParseException( + instring, len(instring), e.errmsg, self + ) maxExcLoc = len(instring) else: # save match among all matches, to retry longest to shortest @@ -3484,9 +3925,9 @@ def parseImpl( self, instring, loc, doActions=True ): if matches: matches.sort(key=lambda x: -x[0]) - for _,e in matches: + for _, e in matches: try: - return e._parse( instring, loc, doActions ) + return e._parse(instring, loc, doActions) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: @@ -3497,16 +3938,17 @@ def parseImpl( self, instring, loc, doActions=True ): maxException.msg = self.errmsg raise maxException else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - + raise ParseException( + instring, loc, "no defined alternatives to match", self + ) - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #Or( [ self, other ] ) + def __ixor__(self, other): + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + return self.append(other) # Or( [ self, other ] ) - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3514,10 +3956,10 @@ def __str__( self ): return self.strRepr - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) class MatchFirst(ParseExpression): @@ -3528,7 +3970,7 @@ class MatchFirst(ParseExpression): Example:: # construct MatchFirst using '|' operator - + # watch the order of expressions to match number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] @@ -3537,19 +3979,20 @@ class MatchFirst(ParseExpression): number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) + + def __init__(self, exprs, savelist=False): + super(MatchFirst, self).__init__(exprs, savelist) if self.exprs: self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) else: self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): maxExcLoc = -1 maxException = None for e in self.exprs: try: - ret = e._parse( instring, loc, doActions ) + ret = e._parse(instring, loc, doActions) return ret except ParseException as err: if err.loc > maxExcLoc: @@ -3557,7 +4000,9 @@ def parseImpl( self, instring, loc, doActions=True ): maxExcLoc = err.loc except IndexError: if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) + maxException = ParseException( + instring, len(instring), e.errmsg, self + ) maxExcLoc = len(instring) # only got here if no expression matched, raise exception for match that made it the furthest @@ -3566,15 +4011,17 @@ def parseImpl( self, instring, loc, doActions=True ): maxException.msg = self.errmsg raise maxException else: - raise ParseException(instring, loc, "no defined alternatives to match", self) + raise ParseException( + instring, loc, "no defined alternatives to match", self + ) - def __ior__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) + def __ior__(self, other): + if isinstance(other, basestring): + other = ParserElement._literalStringClass(other) + return self.append(other) # MatchFirst( [ self, other ] ) - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3582,10 +4029,10 @@ def __str__( self ): return self.strRepr - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) class Each(ParseExpression): @@ -3603,7 +4050,7 @@ class Each(ParseExpression): color_attr = "color:" + color("color") size_attr = "size:" + integer("size") - # use Each (using operator '&') to accept attributes in any order + # use Each (using operator '&') to accept attributes in any order # (shape and posn are required, color and size are optional) shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) @@ -3642,26 +4089,41 @@ class Each(ParseExpression): - shape: TRIANGLE - size: 20 """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) + + def __init__(self, exprs, savelist=True): + super(Each, self).__init__(exprs, savelist) self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = True self.initExprGroups = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.initExprGroups: - self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] + self.opt1map = dict( + (id(e.expr), e) for e in self.exprs if isinstance(e, Optional) + ) + opt1 = [e.expr for e in self.exprs if isinstance(e, Optional)] + opt2 = [ + e + for e in self.exprs + if e.mayReturnEmpty and not isinstance(e, Optional) + ] self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] + self.multioptionals = [ + e.expr for e in self.exprs if isinstance(e, ZeroOrMore) + ] + self.multirequired = [ + e.expr for e in self.exprs if isinstance(e, OneOrMore) + ] + self.required = [ + e + for e in self.exprs + if not isinstance(e, (Optional, ZeroOrMore, OneOrMore)) + ] self.required += self.multirequired self.initExprGroups = False tmpLoc = loc tmpReqd = self.required[:] - tmpOpt = self.optionals[:] + tmpOpt = self.optionals[:] matchOrder = [] keepMatching = True @@ -3670,11 +4132,11 @@ def parseImpl( self, instring, loc, doActions=True ): failed = [] for e in tmpExprs: try: - tmpLoc = e.tryParse( instring, tmpLoc ) + tmpLoc = e.tryParse(instring, tmpLoc) except ParseException: failed.append(e) else: - matchOrder.append(self.opt1map.get(id(e),e)) + matchOrder.append(self.opt1map.get(id(e), e)) if e in tmpReqd: tmpReqd.remove(e) elif e in tmpOpt: @@ -3684,21 +4146,25 @@ def parseImpl( self, instring, loc, doActions=True ): if tmpReqd: missing = ", ".join(_ustr(e) for e in tmpReqd) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) + raise ParseException( + instring, loc, "Missing one or more required elements (%s)" % missing + ) # add any unmatched Optionals, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] + matchOrder += [ + e for e in self.exprs if isinstance(e, Optional) and e.expr in tmpOpt + ] resultlist = [] for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) + loc, results = e._parse(instring, loc, doActions) resultlist.append(results) finalResults = sum(resultlist, ParseResults([])) return loc, finalResults - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3706,19 +4172,20 @@ def __str__( self ): return self.strRepr - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] + def checkRecursion(self, parseElementList): + subRecCheckList = parseElementList[:] + [self] for e in self.exprs: - e.checkRecursion( subRecCheckList ) + e.checkRecursion(subRecCheckList) class ParseElementEnhance(ParserElement): """ Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. """ - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): + + def __init__(self, expr, savelist=False): + super(ParseElementEnhance, self).__init__(savelist) + if isinstance(expr, basestring): if issubclass(ParserElement._literalStringClass, Token): expr = ParserElement._literalStringClass(expr) else: @@ -3728,64 +4195,64 @@ def __init__( self, expr, savelist=False ): if expr is not None: self.mayIndexError = expr.mayIndexError self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) + self.setWhitespaceChars(expr.whiteChars) self.skipWhitespace = expr.skipWhitespace self.saveAsList = expr.saveAsList self.callPreparse = expr.callPreparse self.ignoreExprs.extend(expr.ignoreExprs) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) + return self.expr._parse(instring, loc, doActions, callPreParse=False) else: - raise ParseException("",loc,self.errmsg,self) + raise ParseException("", loc, self.errmsg, self) - def leaveWhitespace( self ): + def leaveWhitespace(self): self.skipWhitespace = False self.expr = self.expr.copy() if self.expr is not None: self.expr.leaveWhitespace() return self - def ignore( self, other ): - if isinstance( other, Suppress ): + def ignore(self, other): + if isinstance(other, Suppress): if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) + super(ParseElementEnhance, self).ignore(other) if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) + self.expr.ignore(self.ignoreExprs[-1]) else: - super( ParseElementEnhance, self).ignore( other ) + super(ParseElementEnhance, self).ignore(other) if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) + self.expr.ignore(self.ignoreExprs[-1]) return self - def streamline( self ): - super(ParseElementEnhance,self).streamline() + def streamline(self): + super(ParseElementEnhance, self).streamline() if self.expr is not None: self.expr.streamline() return self - def checkRecursion( self, parseElementList ): + def checkRecursion(self, parseElementList): if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] + raise RecursiveGrammarException(parseElementList + [self]) + subRecCheckList = parseElementList[:] + [self] if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) + self.expr.checkRecursion(subRecCheckList) - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] + def validate(self, validateTrace=[]): + tmp = validateTrace[:] + [self] if self.expr is not None: self.expr.validate(tmp) - self.checkRecursion( [] ) + self.checkRecursion([]) - def __str__( self ): + def __str__(self): try: - return super(ParseElementEnhance,self).__str__() + return super(ParseElementEnhance, self).__str__() except Exception: pass if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) + self.strRepr = "%s:(%s)" % (self.__class__.__name__, _ustr(self.expr)) return self.strRepr @@ -3801,17 +4268,18 @@ class FollowedBy(ParseElementEnhance): data_word = Word(alphas) label = data_word + FollowedBy(':') attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - + OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() prints:: [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] """ - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) + + def __init__(self, expr): + super(FollowedBy, self).__init__(expr) self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) + def parseImpl(self, instring, loc, doActions=True): + self.expr.tryParse(instring, loc) return loc, [] @@ -3824,22 +4292,25 @@ class NotAny(ParseElementEnhance): always returns a null token list. May be constructed using the '~' operator. Example:: - + """ - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs + + def __init__(self, expr): + super(NotAny, self).__init__(expr) + # ~ self.leaveWhitespace() + self.skipWhitespace = ( + False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs + ) self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) + self.errmsg = "Found unwanted token, " + _ustr(self.expr) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): if self.expr.canParseNext(instring, loc): raise ParseException(instring, loc, self.errmsg, self) return loc, [] - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3847,8 +4318,9 @@ def __str__( self ): return self.strRepr + class _MultipleMatch(ParseElementEnhance): - def __init__( self, expr, stopOn=None): + def __init__(self, expr, stopOn=None): super(_MultipleMatch, self).__init__(expr) self.saveAsList = True ender = stopOn @@ -3856,44 +4328,45 @@ def __init__( self, expr, stopOn=None): ender = ParserElement._literalStringClass(ender) self.not_ender = ~ender if ender is not None else None - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): self_expr_parse = self.expr._parse self_skip_ignorables = self._skipIgnorables check_ender = self.not_ender is not None if check_ender: try_not_ender = self.not_ender.tryParse - + # must be at least one (but first see if we are the stopOn sentinel; # if so, fail) if check_ender: try_not_ender(instring, loc) - loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) + loc, tokens = self_expr_parse(instring, loc, doActions, callPreParse=False) try: - hasIgnoreExprs = (not not self.ignoreExprs) + hasIgnoreExprs = not not self.ignoreExprs while 1: if check_ender: try_not_ender(instring, loc) if hasIgnoreExprs: - preloc = self_skip_ignorables( instring, loc ) + preloc = self_skip_ignorables(instring, loc) else: preloc = loc - loc, tmptokens = self_expr_parse( instring, preloc, doActions ) + loc, tmptokens = self_expr_parse(instring, preloc, doActions) if tmptokens or tmptokens.haskeys(): tokens += tmptokens - except (ParseException,IndexError): + except (ParseException, IndexError): pass return loc, tokens - + + class OneOrMore(_MultipleMatch): """ Repetition of one or more of the given expression. - + Parameters: - expr - expression that must match one or more times - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) + (only required if the sentinel would ordinarily match the repetition + expression) Example:: data_word = Word(alphas) @@ -3906,13 +4379,13 @@ class OneOrMore(_MultipleMatch): # use stopOn attribute for OneOrMore to avoid reading label string as part of the data attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] - + # could also be written as (attr_expr * (1,)).parseString(text).pprint() """ - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3920,30 +4393,32 @@ def __str__( self ): return self.strRepr + class ZeroOrMore(_MultipleMatch): """ Optional repetition of zero or more of the given expression. - + Parameters: - expr - expression that must match zero or more times - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) + (only required if the sentinel would ordinarily match the repetition + expression) Example: similar to L{OneOrMore} """ - def __init__( self, expr, stopOn=None): - super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) + + def __init__(self, expr, stopOn=None): + super(ZeroOrMore, self).__init__(expr, stopOn=stopOn) self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): + + def parseImpl(self, instring, loc, doActions=True): try: return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) - except (ParseException,IndexError): + except (ParseException, IndexError): return loc, [] - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -3951,14 +4426,20 @@ def __str__( self ): return self.strRepr + class _NullToken(object): def __bool__(self): return False + __nonzero__ = __bool__ + def __str__(self): return "" + _optionalNotMatched = _NullToken() + + class Optional(ParseElementEnhance): """ Optional matching of the given expression. @@ -3973,10 +4454,10 @@ class Optional(ParseElementEnhance): zip.runTests(''' # traditional ZIP code 12345 - + # ZIP+4 form 12101-0001 - + # invalid ZIP 98765- ''') @@ -3994,28 +4475,29 @@ class Optional(ParseElementEnhance): ^ FAIL: Expected end of text (at char 5), (line:1, col:6) """ - def __init__( self, expr, default=_optionalNotMatched ): - super(Optional,self).__init__( expr, savelist=False ) + + def __init__(self, expr, default=_optionalNotMatched): + super(Optional, self).__init__(expr, savelist=False) self.saveAsList = self.expr.saveAsList self.defaultValue = default self.mayReturnEmpty = True - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): + loc, tokens = self.expr._parse(instring, loc, doActions, callPreParse=False) + except (ParseException, IndexError): if self.defaultValue is not _optionalNotMatched: if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) + tokens = ParseResults([self.defaultValue]) tokens[self.expr.resultsName] = self.defaultValue else: - tokens = [ self.defaultValue ] + tokens = [self.defaultValue] else: tokens = [] return loc, tokens - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name if self.strRepr is None: @@ -4023,18 +4505,19 @@ def __str__( self ): return self.strRepr + class SkipTo(ParseElementEnhance): """ Token for skipping over all undefined text until the matched expression is found. Parameters: - expr - target expression marking the end of the data to be skipped - - include - (default=C{False}) if True, the target expression is also parsed + - include - (default=C{False}) if True, the target expression is also parsed (the skipped text and target expression are returned as a 2-element list). - - ignore - (default=C{None}) used to define grammars (typically quoted strings and + - ignore - (default=C{None}) used to define grammars (typically quoted strings and comments) that might contain false matches to the target expression - - failOn - (default=C{None}) define expressions that are not allowed to be - included in the skipped test; if found before the target expression is found, + - failOn - (default=C{None}) define expressions that are not allowed to be + included in the skipped test; if found before the target expression is found, the SkipTo is not a match Example:: @@ -4054,11 +4537,11 @@ class SkipTo(ParseElementEnhance): # - parse action will call token.strip() for each matched token, i.e., the description body string_data = SkipTo(SEP, ignore=quotedString) string_data.setParseAction(tokenMap(str.strip)) - ticket_expr = (integer("issue_num") + SEP - + string_data("sev") + SEP - + string_data("desc") + SEP + ticket_expr = (integer("issue_num") + SEP + + string_data("sev") + SEP + + string_data("desc") + SEP + integer("days_open")) - + for tkt in ticket_expr.searchString(report): print tkt.dump() prints:: @@ -4078,8 +4561,9 @@ class SkipTo(ParseElementEnhance): - issue_num: 79 - sev: Minor """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) + + def __init__(self, other, include=False, ignore=None, failOn=None): + super(SkipTo, self).__init__(other) self.ignoreExpr = ignore self.mayReturnEmpty = True self.mayIndexError = False @@ -4089,23 +4573,27 @@ def __init__( self, other, include=False, ignore=None, failOn=None ): self.failOn = ParserElement._literalStringClass(failOn) else: self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) + self.errmsg = "No match found for " + _ustr(self.expr) - def parseImpl( self, instring, loc, doActions=True ): + def parseImpl(self, instring, loc, doActions=True): startloc = loc instrlen = len(instring) expr = self.expr expr_parse = self.expr._parse - self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None - self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None - + self_failOn_canParseNext = ( + self.failOn.canParseNext if self.failOn is not None else None + ) + self_ignoreExpr_tryParse = ( + self.ignoreExpr.tryParse if self.ignoreExpr is not None else None + ) + tmploc = loc while tmploc <= instrlen: if self_failOn_canParseNext is not None: # break if failOn expression matches if self_failOn_canParseNext(instring, tmploc): break - + if self_ignoreExpr_tryParse is not None: # advance past ignore expressions while 1: @@ -4113,7 +4601,7 @@ def parseImpl( self, instring, loc, doActions=True ): tmploc = self_ignoreExpr_tryParse(instring, tmploc) except ParseBaseException: break - + try: expr_parse(instring, tmploc, doActions=False, callPreParse=False) except (ParseException, IndexError): @@ -4131,13 +4619,14 @@ def parseImpl( self, instring, loc, doActions=True ): loc = tmploc skiptext = instring[startloc:loc] skipresult = ParseResults(skiptext) - + if self.includeMatch: - loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) + loc, mat = expr_parse(instring, loc, doActions, callPreParse=False) skipresult += mat return loc, skipresult + class Forward(ParseElementEnhance): """ Forward declaration of an expression to be defined later - @@ -4157,45 +4646,46 @@ class Forward(ParseElementEnhance): See L{ParseResults.pprint} for an example of a recursive parser created using C{Forward}. """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - def __lshift__( self, other ): - if isinstance( other, basestring ): + def __init__(self, other=None): + super(Forward, self).__init__(other, savelist=False) + + def __lshift__(self, other): + if isinstance(other, basestring): other = ParserElement._literalStringClass(other) self.expr = other self.strRepr = None self.mayIndexError = self.expr.mayIndexError self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) + self.setWhitespaceChars(self.expr.whiteChars) self.skipWhitespace = self.expr.skipWhitespace self.saveAsList = self.expr.saveAsList self.ignoreExprs.extend(self.expr.ignoreExprs) return self - + def __ilshift__(self, other): return self << other - - def leaveWhitespace( self ): + + def leaveWhitespace(self): self.skipWhitespace = False return self - def streamline( self ): + def streamline(self): if not self.streamlined: self.streamlined = True if self.expr is not None: self.expr.streamline() return self - def validate( self, validateTrace=[] ): + def validate(self, validateTrace=[]): if self not in validateTrace: - tmp = validateTrace[:]+[self] + tmp = validateTrace[:] + [self] if self.expr is not None: self.expr.validate(tmp) self.checkRecursion([]) - def __str__( self ): - if hasattr(self,"name"): + def __str__(self): + if hasattr(self, "name"): return self.name return self.__class__.__name__ + ": ..." @@ -4213,24 +4703,28 @@ def __str__( self ): def copy(self): if self.expr is not None: - return super(Forward,self).copy() + return super(Forward, self).copy() else: ret = Forward() ret <<= self return ret + class _ForwardNoRecurse(Forward): - def __str__( self ): + def __str__(self): return "..." + class TokenConverter(ParseElementEnhance): """ Abstract subclass of C{ParseExpression}, for converting parsed results. """ - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) + + def __init__(self, expr, savelist=False): + super(TokenConverter, self).__init__(expr) # , savelist ) self.saveAsList = False + class Combine(TokenConverter): """ Converter to concatenate all matching tokens to a single string. @@ -4248,8 +4742,9 @@ class Combine(TokenConverter): # no match when there are internal spaces print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) + + def __init__(self, expr, joinString="", adjacent=True): + super(Combine, self).__init__(expr) # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself if adjacent: self.leaveWhitespace() @@ -4258,23 +4753,26 @@ def __init__( self, expr, joinString="", adjacent=True ): self.joinString = joinString self.callPreparse = True - def ignore( self, other ): + def ignore(self, other): if self.adjacent: ParserElement.ignore(self, other) else: - super( Combine, self).ignore( other ) + super(Combine, self).ignore(other) return self - def postParse( self, instring, loc, tokenlist ): + def postParse(self, instring, loc, tokenlist): retToks = tokenlist.copy() del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) + retToks += ParseResults( + ["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults + ) if self.resultsName and retToks.haskeys(): - return [ retToks ] + return [retToks] else: return retToks + class Group(TokenConverter): """ Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. @@ -4289,12 +4787,14 @@ class Group(TokenConverter): func = ident + Group(Optional(delimitedList(term))) print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] """ - def __init__( self, expr ): - super(Group,self).__init__( expr ) + + def __init__(self, expr): + super(Group, self).__init__(expr) self.saveAsList = True - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] + def postParse(self, instring, loc, tokenlist): + return [tokenlist] + class Dict(TokenConverter): """ @@ -4309,16 +4809,16 @@ class Dict(TokenConverter): text = "shape: SQUARE posn: upper left color: light blue texture: burlap" attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - + # print attributes as plain groups print(OneOrMore(attr_expr).parseString(text).dump()) - + # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names result = Dict(OneOrMore(Group(attr_expr))).parseString(text) print(result.dump()) - + # access named fields as dict entries, or output as dict - print(result['shape']) + print(result['shape']) print(result.asDict()) prints:: ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] @@ -4332,31 +4832,34 @@ class Dict(TokenConverter): {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} See more examples at L{ParseResults} of accessing fields by results name. """ - def __init__( self, expr ): - super(Dict,self).__init__( expr ) + + def __init__(self, expr): + super(Dict, self).__init__(expr) self.saveAsList = True - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): + def postParse(self, instring, loc, tokenlist): + for i, tok in enumerate(tokenlist): if len(tok) == 0: continue ikey = tok[0] - if isinstance(ikey,int): + if isinstance(ikey, int): ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) + if len(tok) == 1: + tokenlist[ikey] = _ParseResultsWithOffset("", i) + elif len(tok) == 2 and not isinstance(tok[1], ParseResults): + tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i) else: - dictvalue = tok.copy() #ParseResults(i) + dictvalue = tok.copy() # ParseResults(i) del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) + if len(dictvalue) != 1 or ( + isinstance(dictvalue, ParseResults) and dictvalue.haskeys() + ): + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i) else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i) if self.resultsName: - return [ tokenlist ] + return [tokenlist] else: return tokenlist @@ -4380,10 +4883,11 @@ class Suppress(TokenConverter): ['a', 'b', 'c', 'd'] (See also L{delimitedList}.) """ - def postParse( self, instring, loc, tokenlist ): + + def postParse(self, instring, loc, tokenlist): return [] - def suppress( self ): + def suppress(self): return self @@ -4391,22 +4895,26 @@ class OnlyOnce(object): """ Wrapper for parse actions, to ensure they are only called once. """ + def __init__(self, methodCall): self.callable = _trim_arity(methodCall) self.called = False - def __call__(self,s,l,t): + + def __call__(self, s, l, t): if not self.called: - results = self.callable(s,l,t) + results = self.callable(s, l, t) self.called = True return results - raise ParseException(s,l,"") + raise ParseException(s, l, "") + def reset(self): self.called = False + def traceParseAction(f): """ - Decorator for debugging parse actions. - + Decorator for debugging parse actions. + When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".} When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised. @@ -4425,29 +4933,34 @@ def remove_duplicate_chars(tokens): ['dfjkls'] """ f = _trim_arity(f) + def z(*paArgs): thisFunc = f.__name__ - s,l,t = paArgs[-3:] - if len(paArgs)>3: + s, l, t = paArgs[-3:] + if len(paArgs) > 3: thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) + sys.stderr.write( + ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc, line(l, s), l, t) + ) try: ret = f(*paArgs) except Exception as exc: - sys.stderr.write( "< ['aa', 'bb', 'cc'] delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] """ - dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." + dlName = _ustr(expr) + " [" + _ustr(delim) + " " + _ustr(expr) + "]..." if combine: - return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) + return Combine(expr + ZeroOrMore(delim + expr)).setName(dlName) else: - return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) + return (expr + ZeroOrMore(Suppress(delim) + expr)).setName(dlName) + -def countedArray( expr, intExpr=None ): +def countedArray(expr, intExpr=None): """ Helper to define a counted list of expressions. This helper defines a pattern of the form:: integer expr expr expr... where the leading integer tells how many expr expressions follow. The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. - + If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value. Example:: @@ -4485,27 +4999,31 @@ def countedArray( expr, intExpr=None ): countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd'] """ arrayExpr = Forward() - def countFieldParseAction(s,l,t): + + def countFieldParseAction(s, l, t): n = t[0] - arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) + arrayExpr << (n and Group(And([expr] * n)) or Group(empty)) return [] + if intExpr is None: - intExpr = Word(nums).setParseAction(lambda t:int(t[0])) + intExpr = Word(nums).setParseAction(lambda t: int(t[0])) else: intExpr = intExpr.copy() intExpr.setName("arrayLen") intExpr.addParseAction(countFieldParseAction, callDuringTry=True) - return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') + return (intExpr + arrayExpr).setName('(len) ' + _ustr(expr) + '...') + def _flatten(L): ret = [] for i in L: - if isinstance(i,list): + if isinstance(i, list): ret.extend(_flatten(i)) else: ret.append(i) return ret + def matchPreviousLiteral(expr): """ Helper to define an expression that is indirectly defined from @@ -4520,7 +5038,8 @@ def matchPreviousLiteral(expr): Do I{not} use with packrat parsing enabled. """ rep = Forward() - def copyTokenToRepeater(s,l,t): + + def copyTokenToRepeater(s, l, t): if t: if len(t) == 1: rep << t[0] @@ -4530,10 +5049,12 @@ def copyTokenToRepeater(s,l,t): rep << And(Literal(tt) for tt in tflat) else: rep << Empty() + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) rep.setName('(prev) ' + _ustr(expr)) return rep + def matchPreviousExpr(expr): """ Helper to define an expression that is indirectly defined from @@ -4551,26 +5072,32 @@ def matchPreviousExpr(expr): rep = Forward() e2 = expr.copy() rep <<= e2 - def copyTokenToRepeater(s,l,t): + + def copyTokenToRepeater(s, l, t): matchTokens = _flatten(t.asList()) - def mustMatchTheseTokens(s,l,t): + + def mustMatchTheseTokens(s, l, t): theseTokens = _flatten(t.asList()) - if theseTokens != matchTokens: - raise ParseException("",0,"") - rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) + if theseTokens != matchTokens: + raise ParseException("", 0, "") + + rep.setParseAction(mustMatchTheseTokens, callDuringTry=True) + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) rep.setName('(prev) ' + _ustr(expr)) return rep + def _escapeRegexRangeChars(s): - #~ escape these chars: ^-] + # ~ escape these chars: ^-] for c in r"\^-]": - s = s.replace(c,_bslash+c) - s = s.replace("\n",r"\n") - s = s.replace("\t",r"\t") + s = s.replace(c, _bslash + c) + s = s.replace("\n", r"\n") + s = s.replace("\t", r"\t") return _ustr(s) -def oneOf( strs, caseless=False, useRegex=True ): + +def oneOf(strs, caseless=False, useRegex=True): """ Helper to quickly define a set of alternative Literals, and makes sure to do longest-first testing when there is a conflict, regardless of the input order, @@ -4594,56 +5121,68 @@ def oneOf( strs, caseless=False, useRegex=True ): [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] """ if caseless: - isequal = ( lambda a,b: a.upper() == b.upper() ) - masks = ( lambda a,b: b.upper().startswith(a.upper()) ) + isequal = lambda a, b: a.upper() == b.upper() + masks = lambda a, b: b.upper().startswith(a.upper()) parseElementClass = CaselessLiteral else: - isequal = ( lambda a,b: a == b ) - masks = ( lambda a,b: b.startswith(a) ) + isequal = lambda a, b: a == b + masks = lambda a, b: b.startswith(a) parseElementClass = Literal symbols = [] - if isinstance(strs,basestring): + if isinstance(strs, basestring): symbols = strs.split() elif isinstance(strs, Iterable): symbols = list(strs) else: - warnings.warn("Invalid argument to oneOf, expected string or iterable", - SyntaxWarning, stacklevel=2) + warnings.warn( + "Invalid argument to oneOf, expected string or iterable", + SyntaxWarning, + stacklevel=2, + ) if not symbols: return NoMatch() i = 0 - while i < len(symbols)-1: + while i < len(symbols) - 1: cur = symbols[i] - for j,other in enumerate(symbols[i+1:]): - if ( isequal(other, cur) ): - del symbols[i+j+1] + for j, other in enumerate(symbols[i + 1 :]): + if isequal(other, cur): + del symbols[i + j + 1] break - elif ( masks(cur, other) ): - del symbols[i+j+1] - symbols.insert(i,other) + elif masks(cur, other): + del symbols[i + j + 1] + symbols.insert(i, other) cur = other break else: i += 1 if not caseless and useRegex: - #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) + # ~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) + if len(symbols) == len("".join(symbols)): + return Regex( + "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) + ).setName(' | '.join(symbols)) else: - return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) + return Regex("|".join(re.escape(sym) for sym in symbols)).setName( + ' | '.join(symbols) + ) except Exception: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - + warnings.warn( + "Exception creating Regex for oneOf, building MatchFirst", + SyntaxWarning, + stacklevel=2, + ) # last resort, just use MatchFirst - return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) + return MatchFirst(parseElementClass(sym) for sym in symbols).setName( + ' | '.join(symbols) + ) -def dictOf( key, value ): + +def dictOf(key, value): """ Helper to easily and clearly define a dictionary by specifying the respective patterns for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens @@ -4656,7 +5195,7 @@ def dictOf( key, value ): text = "shape: SQUARE posn: upper left color: light blue texture: burlap" attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) print(OneOrMore(attr_expr).parseString(text).dump()) - + attr_label = label attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) @@ -4676,18 +5215,19 @@ def dictOf( key, value ): SQUARE {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) + return Dict(ZeroOrMore(Group(key + value))) + def originalTextFor(expr, asString=True): """ Helper to return the original, untokenized text for a given expression. Useful to restore the parsed fields of an HTML start tag into the raw tag text itself, or to revert separate tokens with intervening whitespace back to the original matching - input text. By default, returns astring containing the original parsed text. - - If the optional C{asString} argument is passed as C{False}, then the return value is a - C{L{ParseResults}} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if + input text. By default, returns astring containing the original parsed text. + + If the optional C{asString} argument is passed as C{False}, then the return value is a + C{L{ParseResults}} containing any results names that were originally matched, and a + single token containing the original matched text from the input string. So if the expression passed to C{L{originalTextFor}} contains expressions with defined results names, you must set C{asString} to C{False} if you want to preserve those results name values. @@ -4702,25 +5242,29 @@ def originalTextFor(expr, asString=True): [' bold text '] ['text'] """ - locMarker = Empty().setParseAction(lambda s,loc,t: loc) + locMarker = Empty().setParseAction(lambda s, loc, t: loc) endlocMarker = locMarker.copy() endlocMarker.callPreparse = False matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] + extractText = lambda s, l, t: s[t._original_start : t._original_end] else: - def extractText(s,l,t): - t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] + + def extractText(s, l, t): + t[:] = [s[t.pop('_original_start') : t.pop('_original_end')]] + matchExpr.setParseAction(extractText) matchExpr.ignoreExprs = expr.ignoreExprs return matchExpr -def ungroup(expr): + +def ungroup(expr): """ Helper to undo pyparsing's default grouping of And expressions, even if all but one are non-empty. """ - return TokenConverter(expr).setParseAction(lambda t:t[0]) + return TokenConverter(expr).setParseAction(lambda t: t[0]) + def locatedExpr(expr): """ @@ -4742,23 +5286,41 @@ def locatedExpr(expr): [[8, 'lksdjjf', 15]] [[18, 'lkkjj', 23]] """ - locator = Empty().setParseAction(lambda s,l,t: l) - return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) + locator = Empty().setParseAction(lambda s, l, t: l) + return Group( + locator("locn_start") + + expr("value") + + locator.copy().leaveWhitespace()("locn_end") + ) # convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") +empty = Empty().setName("empty") +lineStart = LineStart().setName("lineStart") +lineEnd = LineEnd().setName("lineEnd") stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) -_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1) +stringEnd = StringEnd().setName("stringEnd") + +_escapedPunc = Word(_bslash, r"\[]-*.$+^?()~ ", exact=2).setParseAction( + lambda s, l, t: t[0][1] +) +_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction( + lambda s, l, t: unichr(int(t[0].lstrip(r'\0x'), 16)) +) +_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction( + lambda s, l, t: unichr(int(t[0][1:], 8)) +) +_singleChar = ( + _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1) +) _charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" +_reBracketExpr = ( + Literal("[") + + Optional("^").setResultsName("negate") + + Group(OneOrMore(_charRange | _singleChar)).setResultsName("body") + + "]" +) + def srange(s): r""" @@ -4772,28 +5334,36 @@ def srange(s): The values enclosed in the []'s may be: - a single character - an escaped character with a leading backslash (such as C{\-} or C{\]}) - - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) - (C{\0x##} is also supported for backwards compatibility) + - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) + (C{\0x##} is also supported for backwards compatibility) - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) - a range of any of the above, separated by a dash (C{'a-z'}, etc.) - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) """ - _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) + _expanded = ( + lambda p: p + if not isinstance(p, ParseResults) + else ''.join(unichr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) + ) try: return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) except Exception: return "" + def matchOnlyAtCol(n): """ Helper method for defining parse actions that require matching at a specific column in the input text. """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) + + def verifyCol(strg, locn, toks): + if col(locn, strg) != n: + raise ParseException(strg, locn, "matched token not at column %d" % n) + return verifyCol + def replaceWith(replStr): """ Helper method for common parse actions that simply return a literal value. Especially @@ -4803,12 +5373,13 @@ def replaceWith(replStr): num = Word(nums).setParseAction(lambda toks: int(toks[0])) na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) term = na | num - + OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] """ - return lambda s,l,t: [replStr] + return lambda s, l, t: [replStr] -def removeQuotes(s,l,t): + +def removeQuotes(s, l, t): """ Helper parse action for removing quotation marks from parsed quoted strings. @@ -4822,9 +5393,10 @@ def removeQuotes(s,l,t): """ return t[0][1:-1] + def tokenMap(func, *args): """ - Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional + Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional args are passed, they are forwarded to the given function as additional arguments after the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the parsed data to an integer using base 16. @@ -4834,7 +5406,7 @@ def tokenMap(func, *args): hex_ints.runTests(''' 00 11 22 aa FF 0a 0d 1a ''') - + upperword = Word(alphas).setParseAction(tokenMap(str.upper)) OneOrMore(upperword).runTests(''' my kingdom for a horse @@ -4854,53 +5426,80 @@ def tokenMap(func, *args): now is the winter of our discontent made glorious summer by this sun of york ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] """ - def pa(s,l,t): + + def pa(s, l, t): return [func(tokn, *args) for tokn in t] try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) + func_name = getattr(func, '__name__', getattr(func, '__class__').__name__) except Exception: func_name = str(func) pa.__name__ = func_name return pa + upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) """(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}""" downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) """(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}""" - + + def _makeTags(tagStr, xml): """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): + if isinstance(tagStr, basestring): resname = tagStr tagStr = Keyword(tagStr, caseless=not xml) else: resname = tagStr.name - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + tagAttrName = Word(alphas, alphanums + "_-:") + if xml: + tagAttrValue = dblQuotedString.copy().setParseAction(removeQuotes) + openTag = ( + Suppress("<") + + tagStr("tag") + + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue))) + + Optional("/", default=[False]) + .setResultsName("empty") + .setParseAction(lambda s, l, t: t[0] == '/') + + Suppress(">") + ) else: printablesLessRAbrack = "".join(c for c in printables if c not in ">") - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + tagAttrValue = quotedString.copy().setParseAction(removeQuotes) | Word( + printablesLessRAbrack + ) + openTag = ( + Suppress("<") + + tagStr("tag") + + Dict( + ZeroOrMore( + Group( + tagAttrName.setParseAction(downcaseTokens) + + Optional(Suppress("=") + tagAttrValue) + ) + ) + ) + + Optional("/", default=[False]) + .setResultsName("empty") + .setParseAction(lambda s, l, t: t[0] == '/') + + Suppress(">") + ) closeTag = Combine(_L("") - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % resname) + openTag = openTag.setResultsName( + "start" + "".join(resname.replace(":", " ").title().split()) + ).setName("<%s>" % resname) + closeTag = closeTag.setResultsName( + "end" + "".join(resname.replace(":", " ").title().split()) + ).setName("" % resname) openTag.tag = resname closeTag.tag = resname return openTag, closeTag + def makeHTMLTags(tagStr): """ Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches @@ -4911,14 +5510,15 @@ def makeHTMLTags(tagStr): # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple a,a_end = makeHTMLTags("A") link_expr = a + SkipTo(a_end)("link_text") + a_end - + for link in link_expr.searchString(text): # attributes in the tag (like "href" shown here) are also accessible as named results print(link.link_text, '->', link.href) prints:: pyparsing -> http://pyparsing.wikispaces.com """ - return _makeTags( tagStr, False ) + return _makeTags(tagStr, False) + def makeXMLTags(tagStr): """ @@ -4927,9 +5527,10 @@ def makeXMLTags(tagStr): Example: similar to L{makeHTMLTags} """ - return _makeTags( tagStr, True ) + return _makeTags(tagStr, True) + -def withAttribute(*args,**attrDict): +def withAttribute(*args, **attrDict): """ Helper to create a validating parse action to be used with start tags created with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag @@ -4944,7 +5545,7 @@ def withAttribute(*args,**attrDict): - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) For attribute names with a namespace prefix, you must use the second form. Attribute names are matched insensitive to upper/lower case. - + If just testing for C{class} (with or without a namespace), use C{L{withClass}}. To verify that the attribute exists, but without specifying a value, pass @@ -4958,7 +5559,7 @@ def withAttribute(*args,**attrDict):
1,3 2,3 1,1
this has no type
- + ''' div,div_end = makeHTMLTags("div") @@ -4967,7 +5568,7 @@ def withAttribute(*args,**attrDict): grid_expr = div_grid + SkipTo(div | div_end)("body") for grid_header in grid_expr.searchString(html): print(grid_header.body) - + # construct a match with any div tag having a type attribute, regardless of the value div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) div_expr = div_any_type + SkipTo(div | div_end)("body") @@ -4983,17 +5584,26 @@ def withAttribute(*args,**attrDict): attrs = args[:] else: attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: + attrs = [(k, v) for k, v in attrs] + + def pa(s, l, tokens): + for attrName, attrValue in attrs: if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) + raise ParseException(s, l, "no matching attribute " + attrName) if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) + raise ParseException( + s, + l, + "attribute '%s' has value '%s', must be '%s'" + % (attrName, tokens[attrName], attrValue), + ) + return pa + + withAttribute.ANY_VALUE = object() + def withClass(classname, namespace=''): """ Simplified version of C{L{withAttribute}} when matching on a div class - made @@ -5007,15 +5617,15 @@ def withClass(classname, namespace=''):
1,3 2,3 1,1
this <div> has no class
- + ''' div,div_end = makeHTMLTags("div") div_grid = div().setParseAction(withClass("grid")) - + grid_expr = div_grid + SkipTo(div | div_end)("body") for grid_header in grid_expr.searchString(html): print(grid_header.body) - + div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) div_expr = div_any_type + SkipTo(div | div_end)("body") for div_header in div_expr.searchString(html): @@ -5027,20 +5637,22 @@ def withClass(classname, namespace=''): 1,3 2,3 1,1 """ classattr = "%s:class" % namespace if namespace else "class" - return withAttribute(**{classattr : classname}) + return withAttribute(**{classattr: classname}) + opAssoc = _Constants() opAssoc.LEFT = object() opAssoc.RIGHT = object() -def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): + +def infixNotation(baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')')): """ Helper method for constructing grammars of expressions made up of operators working in a precedence hierarchy. Operators may be unary or binary, left- or right-associative. Parse actions can also be attached - to operator expressions. The generated parser will also recognize the use + to operator expressions. The generated parser will also recognize the use of parentheses to override operator precedences (see example below). - + Note: if you define a deep operator list, you may see performance issues when using infixNotation. See L{ParserElement.enablePackrat} for a mechanism to potentially improve your parser performance. @@ -5070,15 +5682,15 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): Example:: # simple example of four-function arithmetic with ints and variable names integer = pyparsing_common.signed_integer - varname = pyparsing_common.identifier - + varname = pyparsing_common.identifier + arith_expr = infixNotation(integer | varname, [ ('-', 1, opAssoc.RIGHT), (oneOf('* /'), 2, opAssoc.LEFT), (oneOf('+ -'), 2, opAssoc.LEFT), ]) - + arith_expr.runTests(''' 5+3*6 (5+3)*6 @@ -5095,44 +5707,64 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): [[['-', 2], '-', ['-', 11]]] """ ret = Forward() - lastExpr = baseExpr | ( lpar + ret + rpar ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] + lastExpr = baseExpr | (lpar + ret + rpar) + for i, operDef in enumerate(opList): + opExpr, arity, rightLeftAssoc, pa = (operDef + (None,))[:4] termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr if arity == 3: if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") + raise ValueError( + "if numterms=3, opExpr must be a tuple or list of two expressions" + ) opExpr1, opExpr2 = opExpr thisExpr = Forward().setName(termName) if rightLeftAssoc == opAssoc.LEFT: if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) + matchExpr = FollowedBy(lastExpr + opExpr) + Group( + lastExpr + OneOrMore(opExpr) + ) elif arity == 2: if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) + matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( + lastExpr + OneOrMore(opExpr + lastExpr) + ) else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) + matchExpr = FollowedBy(lastExpr + lastExpr) + Group( + lastExpr + OneOrMore(lastExpr) + ) elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) + matchExpr = FollowedBy( + lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr + ) + Group(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + raise ValueError( + "operator must be unary (1), binary (2), or ternary (3)" + ) elif rightLeftAssoc == opAssoc.RIGHT: if arity == 1: # try to avoid LR with this extra test if not isinstance(opExpr, Optional): opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) + matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( + opExpr + thisExpr + ) elif arity == 2: if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) + matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( + lastExpr + OneOrMore(opExpr + thisExpr) + ) else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) + matchExpr = FollowedBy(lastExpr + thisExpr) + Group( + lastExpr + OneOrMore(thisExpr) + ) elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) + matchExpr = FollowedBy( + lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr + ) + Group(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + raise ValueError( + "operator must be unary (1), binary (2), or ternary (3)" + ) else: raise ValueError("operator must indicate right or left associativity") if pa: @@ -5140,20 +5772,28 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): matchExpr.setParseAction(*pa) else: matchExpr.setParseAction(pa) - thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) + thisExpr <<= matchExpr.setName(termName) | lastExpr lastExpr = thisExpr ret <<= lastExpr return ret + operatorPrecedence = infixNotation """(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" -dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") -sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") -quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| - Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") +dblQuotedString = Combine( + Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' +).setName("string enclosed in double quotes") +sglQuotedString = Combine( + Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" +).setName("string enclosed in single quotes") +quotedString = Combine( + Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' + | Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" +).setName("quotedString using single or double quotes") unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") + def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): """ Helper method for defining nested lists enclosed in opening and closing @@ -5186,23 +5826,23 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.cop code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) - c_function = (decl_data_type("type") + c_function = (decl_data_type("type") + ident("name") - + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + code_body("body")) c_function.ignore(cStyleComment) - + source_code = ''' - int is_odd(int x) { - return (x%2); + int is_odd(int x) { + return (x%2); } - - int dec_to_hex(char hchar) { - if (hchar >= '0' && hchar <= '9') { - return (ord(hchar)-ord('0')); - } else { + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { return (10+ord(hchar)-ord('A')); - } + } } ''' for func in c_function.searchString(source_code): @@ -5215,35 +5855,55 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.cop if opener == closer: raise ValueError("opening and closing strings cannot be the same") if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: + if isinstance(opener, basestring) and isinstance(closer, basestring): + if len(opener) == 1 and len(closer) == 1: if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) + content = Combine( + OneOrMore( + ~ignoreExpr + + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS, + exact=1, + ) + ) + ).setParseAction(lambda t: t[0].strip()) else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) + content = empty.copy() + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS + ).setParseAction(lambda t: t[0].strip()) else: if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) + content = Combine( + OneOrMore( + ~ignoreExpr + + ~Literal(opener) + + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) + ) + ).setParseAction(lambda t: t[0].strip()) else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) + content = Combine( + OneOrMore( + ~Literal(opener) + + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) + ) + ).setParseAction(lambda t: t[0].strip()) else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") + raise ValueError( + "opening and closing arguments must be strings if no content expression is given" + ) ret = Forward() if ignoreExpr is not None: - ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) + ret <<= Group( + Suppress(opener) + ZeroOrMore(ignoreExpr | ret | content) + Suppress(closer) + ) else: - ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - ret.setName('nested %s%s expression' % (opener,closer)) + ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer)) + ret.setName('nested %s%s expression' % (opener, closer)) return ret + def indentedBlock(blockStatementExpr, indentStack, indent=True): """ Helper method for defining space-delimited indentation blocks, such as @@ -5320,56 +5980,75 @@ def eggs(z): 'spam', ['(', 'x', 'y', ')'], ':', - [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) + + def checkPeerIndent(s, l, t): + if l >= len(s): + return + curCol = col(l, s) if curCol != indentStack[-1]: if curCol > indentStack[-1]: - raise ParseFatalException(s,l,"illegal nesting") - raise ParseException(s,l,"not a peer entry") + raise ParseFatalException(s, l, "illegal nesting") + raise ParseException(s, l, "not a peer entry") - def checkSubIndent(s,l,t): - curCol = col(l,s) + def checkSubIndent(s, l, t): + curCol = col(l, s) if curCol > indentStack[-1]: - indentStack.append( curCol ) + indentStack.append(curCol) else: - raise ParseException(s,l,"not a subentry") - - def checkUnindent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") + raise ParseException(s, l, "not a subentry") + + def checkUnindent(s, l, t): + if l >= len(s): + return + curCol = col(l, s) + if not (indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): + raise ParseException(s, l, "not an unindent") indentStack.pop() NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') - PEER = Empty().setParseAction(checkPeerIndent).setName('') + PEER = Empty().setParseAction(checkPeerIndent).setName('') UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) + smExpr = Group( + Optional(NL) + + + # ~ FollowedBy(blockStatementExpr) + + INDENT + + (OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL))) + + UNDENT + ) else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) + smExpr = Group( + Optional(NL) + (OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL))) + ) blockStatementExpr.ignore(_bslash + LineEnd()) return smExpr.setName('indented block') + alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) -_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) -commonHTMLEntity = Regex('&(?P' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") +anyOpenTag, anyCloseTag = makeHTMLTags( + Word(alphas, alphanums + "_:").setName('any tag') +) +_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(), '><& "\'')) +commonHTMLEntity = Regex( + '&(?P' + '|'.join(_htmlEntityMap.keys()) + ");" +).setName("common HTML entity") + + def replaceHTMLEntity(t): """Helper parser action to replace common HTML entities with their special characters""" return _htmlEntityMap.get(t.entity) + # it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") +cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName( + "C style comment" +) "Comment of the form C{/* ... */}" htmlComment = Regex(r"").setName("HTML comment") @@ -5379,7 +6058,9 @@ def replaceHTMLEntity(t): dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") "Comment of the form C{// ... (to end of line)}" -cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") +cppStyleComment = Combine( + Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/' | dblSlashComment +).setName("C++ style comment") "Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" javaStyleComment = cppStyleComment @@ -5388,10 +6069,19 @@ def replaceHTMLEntity(t): pythonStyleComment = Regex(r"#.*").setName("Python style comment") "Comment of the form C{# ... (to end of line)}" -_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + - Optional( Word(" \t") + - ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") -commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") +_commasepitem = ( + Combine( + OneOrMore( + Word(printables, excludeChars=',') + + Optional(Word(" \t") + ~Literal(",") + ~LineEnd()) + ) + ) + .streamline() + .setName("commaItem") +) +commaSeparatedList = delimitedList( + Optional(quotedString.copy() | _commasepitem, default="") +).setName("commaSeparatedList") """(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" @@ -5545,48 +6235,80 @@ class pyparsing_common: integer = Word(nums).setName("integer").setParseAction(convertToInteger) """expression that parses an unsigned integer, returns an int""" - hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) + hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int, 16)) """expression that parses a hexadecimal integer, returns an int""" - signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + signed_integer = ( + Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + ) """expression that parses an integer with optional leading sign, returns an int""" - fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") + fraction = ( + signed_integer().setParseAction(convertToFloat) + + '/' + + signed_integer().setParseAction(convertToFloat) + ).setName("fraction") """fractional expression of an integer divided by an integer, returns a float""" - fraction.addParseAction(lambda t: t[0]/t[-1]) + fraction.addParseAction(lambda t: t[0] / t[-1]) - mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") + mixed_integer = ( + fraction | signed_integer + Optional(Optional('-').suppress() + fraction) + ).setName("fraction or mixed integer-fraction") """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" mixed_integer.addParseAction(sum) real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) """expression that parses a floating point number and returns a float""" - sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) + sci_real = ( + Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)') + .setName("real number with scientific notation") + .setParseAction(convertToFloat) + ) """expression that parses a floating point number with optional scientific notation and returns a float""" # streamlining this expression makes the docs nicer-looking number = (sci_real | real | signed_integer).streamline() """any numeric expression, returns the corresponding Python type""" - fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) + fnumber = ( + Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?') + .setName("fnumber") + .setParseAction(convertToFloat) + ) """any int or real number, returned as float""" - - identifier = Word(alphas+'_', alphanums+'_').setName("identifier") + + identifier = Word(alphas + '_', alphanums + '_').setName("identifier") """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" - - ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") + + ipv4_address = Regex( + r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}' + ).setName("IPv4 address") "IPv4 address (C{0.0.0.0 - 255.255.255.255})" _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") - _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") - _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") - _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) + _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part) * 7).setName( + "full IPv6 address" + ) + _short_ipv6_address = ( + Optional(_ipv6_part + (':' + _ipv6_part) * (0, 6)) + + "::" + + Optional(_ipv6_part + (':' + _ipv6_part) * (0, 6)) + ).setName("short IPv6 address") + _short_ipv6_address.addCondition( + lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8 + ) _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") - ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") + ipv6_address = Combine( + (_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName( + "IPv6 address" + ) + ).setName("IPv6 address") "IPv6 address (long, short, or mixed form)" - - mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") + + mac_address = Regex( + r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}' + ).setName("MAC address") "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" @staticmethod @@ -5604,11 +6326,13 @@ def convertToDate(fmt="%Y-%m-%d"): prints:: [datetime.date(1999, 12, 31)] """ - def cvt_fn(s,l,t): + + def cvt_fn(s, l, t): try: return datetime.strptime(t[0], fmt).date() except ValueError as ve: raise ParseException(s, l, str(ve)) + return cvt_fn @staticmethod @@ -5626,41 +6350,60 @@ def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): prints:: [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] """ - def cvt_fn(s,l,t): + + def cvt_fn(s, l, t): try: return datetime.strptime(t[0], fmt) except ValueError as ve: raise ParseException(s, l, str(ve)) + return cvt_fn - iso8601_date = Regex(r'(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?').setName("ISO8601 date") + iso8601_date = Regex( + r'(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?' + ).setName("ISO8601 date") "ISO8601 date (C{yyyy-mm-dd})" - iso8601_datetime = Regex(r'(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") + iso8601_datetime = Regex( + r'(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?' + ).setName("ISO8601 datetime") "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() + @staticmethod def stripHTMLTags(s, l, tokens): """ Parse action to remove HTML tags from web page HTML source Example:: - # strip HTML links from normal text + # strip HTML links from normal text text = 'More info at the
pyparsing wiki page' td,td_end = makeHTMLTags("TD") table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end - + print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' """ return pyparsing_common._html_stripper.transformString(tokens[0]) - _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') - + Optional( White(" \t") ) ) ).streamline().setName("commaItem") - comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") + _commasepitem = ( + Combine( + OneOrMore( + ~Literal(",") + + ~LineEnd() + + Word(printables, excludeChars=',') + + Optional(White(" \t")) + ) + ) + .streamline() + .setName("commaItem") + ) + comma_separated_list = delimitedList( + Optional(quotedString.copy() | _commasepitem, default="") + ).setName("comma separated list") """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) @@ -5672,22 +6415,28 @@ def stripHTMLTags(s, l, tokens): if __name__ == "__main__": - selectToken = CaselessLiteral("select") - fromToken = CaselessLiteral("from") + selectToken = CaselessLiteral("select") + fromToken = CaselessLiteral("from") - ident = Word(alphas, alphanums + "_$") + ident = Word(alphas, alphanums + "_$") - columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) columnNameList = Group(delimitedList(columnName)).setName("columns") - columnSpec = ('*' | columnNameList) + columnSpec = '*' | columnNameList - tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - tableNameList = Group(delimitedList(tableName)).setName("tables") - - simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") + tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + tableNameList = Group(delimitedList(tableName)).setName("tables") + + simpleSQL = ( + selectToken("command") + + columnSpec("columns") + + fromToken + + tableNameList("tables") + ) # demo runTests method, including embedded comments in test string - simpleSQL.runTests(""" + simpleSQL.runTests( + """ # '*' as column list and dotted table name select * from SYS.XYZZY @@ -5709,34 +6458,44 @@ def stripHTMLTags(s, l, tokens): # invalid column name - should fail Select ^^^ frox Sys.dual - """) + """ + ) - pyparsing_common.number.runTests(""" + pyparsing_common.number.runTests( + """ 100 -100 +100 3.14159 6.02e23 1e-12 - """) + """ + ) # any int or real number, returned as float - pyparsing_common.fnumber.runTests(""" + pyparsing_common.fnumber.runTests( + """ 100 -100 +100 3.14159 6.02e23 1e-12 - """) + """ + ) - pyparsing_common.hex_integer.runTests(""" + pyparsing_common.hex_integer.runTests( + """ 100 FF - """) + """ + ) import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(""" + pyparsing_common.uuid.runTests( + """ 12345678-1234-5678-1234-567812345678 - """) + """ + ) diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py index 0f70284822f..147e7eca993 100644 --- a/setuptools/archive_util.py +++ b/setuptools/archive_util.py @@ -11,8 +11,13 @@ from pkg_resources import ensure_directory __all__ = [ - "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", - "UnrecognizedFormat", "extraction_drivers", "unpack_directory", + "unpack_archive", + "unpack_zipfile", + "unpack_tarfile", + "default_filter", + "UnrecognizedFormat", + "extraction_drivers", + "unpack_directory", ] @@ -25,9 +30,7 @@ def default_filter(src, dst): return dst -def unpack_archive( - filename, extract_dir, progress_filter=default_filter, - drivers=None): +def unpack_archive(filename, extract_dir, progress_filter=default_filter, drivers=None): """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat`` `progress_filter` is a function taking two arguments: a source path @@ -56,13 +59,11 @@ def unpack_archive( else: return else: - raise UnrecognizedFormat( - "Not a recognized archive type: %s" % filename - ) + raise UnrecognizedFormat("Not a recognized archive type: %s" % filename) def unpack_directory(filename, extract_dir, progress_filter=default_filter): - """"Unpack" a directory, using the same interface as for archives + """ "Unpack" a directory, using the same interface as for archives Raises ``UnrecognizedFormat`` if `filename` is not a directory """ @@ -128,7 +129,8 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): def _resolve_tar_file_or_dir(tar_obj, tar_member_obj): """Resolve any links and extract link targets as normal files.""" while tar_member_obj is not None and ( - tar_member_obj.islnk() or tar_member_obj.issym()): + tar_member_obj.islnk() or tar_member_obj.issym() + ): linkpath = tar_member_obj.linkname if tar_member_obj.issym(): base = posixpath.dirname(tar_member_obj.name) @@ -136,9 +138,8 @@ def _resolve_tar_file_or_dir(tar_obj, tar_member_obj): linkpath = posixpath.normpath(linkpath) tar_member_obj = tar_obj._getmember(linkpath) - is_file_or_dir = ( - tar_member_obj is not None and - (tar_member_obj.isfile() or tar_member_obj.isdir()) + is_file_or_dir = tar_member_obj is not None and ( + tar_member_obj.isfile() or tar_member_obj.isdir() ) if is_file_or_dir: return tar_member_obj @@ -190,7 +191,9 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): ) from e for member, final_dst in _iter_open_tar( - tarobj, extract_dir, progress_filter, + tarobj, + extract_dir, + progress_filter, ): try: # XXX Ugh diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 9dfb2f24b52..28487f66887 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -39,13 +39,15 @@ from pkg_resources import parse_requirements -__all__ = ['get_requires_for_build_sdist', - 'get_requires_for_build_wheel', - 'prepare_metadata_for_build_wheel', - 'build_wheel', - 'build_sdist', - '__legacy__', - 'SetupRequirementsError'] +__all__ = [ + 'get_requires_for_build_sdist', + 'get_requires_for_build_wheel', + 'prepare_metadata_for_build_wheel', + 'build_wheel', + 'build_sdist', + '__legacy__', + 'SetupRequirementsError', +] class SetupRequirementsError(BaseException): @@ -92,21 +94,20 @@ def no_install_setup_requires(): def _get_immediate_subdirectories(a_dir): - return [name for name in os.listdir(a_dir) - if os.path.isdir(os.path.join(a_dir, name))] + return [ + name for name in os.listdir(a_dir) if os.path.isdir(os.path.join(a_dir, name)) + ] def _file_with_extension(directory, extension): - matching = ( - f for f in os.listdir(directory) - if f.endswith(extension) - ) + matching = (f for f in os.listdir(directory) if f.endswith(extension)) try: - file, = matching + (file,) = matching except ValueError: raise ValueError( 'No distribution was found. Ensure that `setup.py` ' - 'is not empty and that it calls `setup()`.') + 'is not empty and that it calls `setup()`.' + ) return file @@ -119,7 +120,6 @@ def _open_setup_script(setup_script): class _BuildMetaBackend(object): - def _fix_config(self, config_settings): config_settings = config_settings or {} config_settings.setdefault('--global-option', []) @@ -128,8 +128,7 @@ def _fix_config(self, config_settings): def _get_build_requires(self, config_settings, requirements): config_settings = self._fix_config(config_settings) - sys.argv = sys.argv[:1] + ['egg_info'] + \ - config_settings["--global-option"] + sys.argv = sys.argv[:1] + ['egg_info'] + config_settings["--global-option"] try: with Distribution.patch(): self.run_setup() @@ -151,32 +150,33 @@ def run_setup(self, setup_script='setup.py'): def get_requires_for_build_wheel(self, config_settings=None): config_settings = self._fix_config(config_settings) - return self._get_build_requires( - config_settings, requirements=['wheel']) + return self._get_build_requires(config_settings, requirements=['wheel']) def get_requires_for_build_sdist(self, config_settings=None): config_settings = self._fix_config(config_settings) return self._get_build_requires(config_settings, requirements=[]) - def prepare_metadata_for_build_wheel(self, metadata_directory, - config_settings=None): - sys.argv = sys.argv[:1] + [ - 'dist_info', '--egg-base', metadata_directory] + def prepare_metadata_for_build_wheel( + self, metadata_directory, config_settings=None + ): + sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', metadata_directory] with no_install_setup_requires(): self.run_setup() dist_info_directory = metadata_directory while True: - dist_infos = [f for f in os.listdir(dist_info_directory) - if f.endswith('.dist-info')] + dist_infos = [ + f for f in os.listdir(dist_info_directory) if f.endswith('.dist-info') + ] if ( - len(dist_infos) == 0 and - len(_get_immediate_subdirectories(dist_info_directory)) == 1 + len(dist_infos) == 0 + and len(_get_immediate_subdirectories(dist_info_directory)) == 1 ): dist_info_directory = os.path.join( - dist_info_directory, os.listdir(dist_info_directory)[0]) + dist_info_directory, os.listdir(dist_info_directory)[0] + ) continue assert len(dist_infos) == 1 @@ -186,28 +186,31 @@ def prepare_metadata_for_build_wheel(self, metadata_directory, # metadata_directory. To comply, we MUST copy the directory to the root if dist_info_directory != metadata_directory: shutil.move( - os.path.join(dist_info_directory, dist_infos[0]), - metadata_directory) + os.path.join(dist_info_directory, dist_infos[0]), metadata_directory + ) shutil.rmtree(dist_info_directory, ignore_errors=True) return dist_infos[0] - def _build_with_temp_dir(self, setup_command, result_extension, - result_directory, config_settings): + def _build_with_temp_dir( + self, setup_command, result_extension, result_directory, config_settings + ): config_settings = self._fix_config(config_settings) result_directory = os.path.abspath(result_directory) # Build in a temporary directory, then copy to the target. os.makedirs(result_directory, exist_ok=True) with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir: - sys.argv = (sys.argv[:1] + setup_command + - ['--dist-dir', tmp_dist_dir] + - config_settings["--global-option"]) + sys.argv = ( + sys.argv[:1] + + setup_command + + ['--dist-dir', tmp_dist_dir] + + config_settings["--global-option"] + ) with no_install_setup_requires(): self.run_setup() - result_basename = _file_with_extension( - tmp_dist_dir, result_extension) + result_basename = _file_with_extension(tmp_dist_dir, result_extension) result_path = os.path.join(result_directory, result_basename) if os.path.exists(result_path): # os.rename will fail overwriting on non-Unix. @@ -216,15 +219,17 @@ def _build_with_temp_dir(self, setup_command, result_extension, return result_basename - def build_wheel(self, wheel_directory, config_settings=None, - metadata_directory=None): - return self._build_with_temp_dir(['bdist_wheel'], '.whl', - wheel_directory, config_settings) + def build_wheel( + self, wheel_directory, config_settings=None, metadata_directory=None + ): + return self._build_with_temp_dir( + ['bdist_wheel'], '.whl', wheel_directory, config_settings + ) def build_sdist(self, sdist_directory, config_settings=None): - return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], - '.tar.gz', sdist_directory, - config_settings) + return self._build_with_temp_dir( + ['sdist', '--formats', 'gztar'], '.tar.gz', sdist_directory, config_settings + ) class _BuildMetaLegacyBackend(_BuildMetaBackend): @@ -238,11 +243,12 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend): packaging mechanism, and will eventually be removed. """ + def run_setup(self, setup_script='setup.py'): # In order to maintain compatibility with scripts assuming that # the setup.py script is in a directory on the PYTHONPATH, inject # '' into sys.path. (pypa/setuptools#1642) - sys_path = list(sys.path) # Save the original path + sys_path = list(sys.path) # Save the original path script_dir = os.path.dirname(os.path.abspath(setup_script)) if script_dir not in sys.path: @@ -255,8 +261,7 @@ def run_setup(self, setup_script='setup.py'): sys.argv[0] = setup_script try: - super(_BuildMetaLegacyBackend, - self).run_setup(setup_script=setup_script) + super(_BuildMetaLegacyBackend, self).run_setup(setup_script=setup_script) finally: # While PEP 517 frontends should be calling each hook in a fresh # subprocess according to the standard (and thus it should not be diff --git a/setuptools/command/alias.py b/setuptools/command/alias.py index 452a9244ea6..e7b4d5456a7 100644 --- a/setuptools/command/alias.py +++ b/setuptools/command/alias.py @@ -49,7 +49,7 @@ def run(self): return elif len(self.args) == 1: - alias, = self.args + (alias,) = self.args if self.remove: command = None elif alias in aliases: diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index e6b1609f7ba..04a83075ce4 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -41,7 +41,8 @@ def sorted_walk(dir): def write_stub(resource, pyfile): - _stub_template = textwrap.dedent(""" + _stub_template = textwrap.dedent( + """ def __bootstrap__(): global __bootstrap__, __loader__, __file__ import sys, pkg_resources, importlib.util @@ -51,7 +52,8 @@ def __bootstrap__(): mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) __bootstrap__() - """).lstrip() + """ + ).lstrip() with open(pyfile, 'w') as f: f.write(_stub_template % resource) @@ -60,24 +62,25 @@ class bdist_egg(Command): description = "create an \"egg\" distribution" user_options = [ - ('bdist-dir=', 'b', - "temporary directory for creating the distribution"), - ('plat-name=', 'p', "platform name to embed in generated filenames " - "(default: %s)" % get_build_platform()), - ('exclude-source-files', None, - "remove all .py files from the generated egg"), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), + ('bdist-dir=', 'b', "temporary directory for creating the distribution"), + ( + 'plat-name=', + 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_build_platform(), + ), + ('exclude-source-files', None, "remove all .py files from the generated egg"), + ( + 'keep-temp', + 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive", + ), + ('dist-dir=', 'd', "directory to put final built distributions in"), + ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), ] - boolean_options = [ - 'keep-temp', 'skip-build', 'exclude-source-files' - ] + boolean_options = ['keep-temp', 'skip-build', 'exclude-source-files'] def initialize_options(self): self.bdist_dir = None @@ -105,9 +108,12 @@ def finalize_options(self): # Compute filename of the output egg basename = Distribution( - None, None, ei_cmd.egg_name, ei_cmd.egg_version, + None, + None, + ei_cmd.egg_name, + ei_cmd.egg_version, get_python_version(), - self.distribution.has_ext_modules() and self.plat_name + self.distribution.has_ext_modules() and self.plat_name, ).egg_name() self.egg_output = os.path.join(self.dist_dir, basename + '.egg') @@ -127,7 +133,7 @@ def do_install_data(self): if normalized == site_packages or normalized.startswith( site_packages + os.sep ): - item = realpath[len(site_packages) + 1:], item[1] + item = realpath[len(site_packages) + 1 :], item[1] # XXX else: raise ??? self.distribution.data_files.append(item) @@ -169,8 +175,7 @@ def run(self): # noqa: C901 # is too complex (14) # FIXME to_compile = [] for (p, ext_name) in enumerate(ext_outputs): filename, ext = os.path.splitext(ext_name) - pyfile = os.path.join(self.bdist_dir, strip_module(filename) + - '.py') + pyfile = os.path.join(self.bdist_dir, strip_module(filename) + '.py') self.stubs.append(pyfile) log.info("creating stub loader for %s", ext_name) if not self.dry_run: @@ -190,8 +195,7 @@ def run(self): # noqa: C901 # is too complex (14) # FIXME if self.distribution.scripts: script_dir = os.path.join(egg_info, 'scripts') log.info("installing scripts to %s", script_dir) - self.call_command('install_scripts', install_dir=script_dir, - no_ep=1) + self.call_command('install_scripts', install_dir=script_dir, no_ep=1) self.copy_metadata_to(egg_info) native_libs = os.path.join(egg_info, "native_libs.txt") @@ -208,9 +212,7 @@ def run(self): # noqa: C901 # is too complex (14) # FIXME if not self.dry_run: os.unlink(native_libs) - write_safety_flag( - os.path.join(archive_root, 'EGG-INFO'), self.zip_safe() - ) + write_safety_flag(os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()) if os.path.exists(os.path.join(self.egg_info, 'depends.txt')): log.warn( @@ -222,14 +224,20 @@ def run(self): # noqa: C901 # is too complex (14) # FIXME self.zap_pyfiles() # Make the archive - make_zipfile(self.egg_output, archive_root, verbose=self.verbose, - dry_run=self.dry_run, mode=self.gen_header()) + make_zipfile( + self.egg_output, + archive_root, + verbose=self.verbose, + dry_run=self.dry_run, + mode=self.gen_header(), + ) if not self.keep_temp: remove_tree(self.bdist_dir, dry_run=self.dry_run) # Add to 'Distribution.dist_files' so that the "upload" command works getattr(self.distribution, 'dist_files', []).append( - ('bdist_egg', get_python_version(), self.egg_output)) + ('bdist_egg', get_python_version(), self.egg_output) + ) def zap_pyfiles(self): log.info("Removing .py files from temporary directory") @@ -246,11 +254,8 @@ def zap_pyfiles(self): pattern = r'(?P.+)\.(?P[^.]+)\.pyc' m = re.match(pattern, name) - path_new = os.path.join( - base, os.pardir, m.group('name') + '.pyc') - log.info( - "Renaming file from [%s] to [%s]" - % (path_old, path_new)) + path_new = os.path.join(base, os.pardir, m.group('name') + '.pyc') + log.info("Renaming file from [%s] to [%s]" % (path_old, path_new)) try: os.remove(path_new) except OSError: @@ -275,7 +280,7 @@ def copy_metadata_to(self, target_dir): prefix = os.path.join(norm_egg_info, '') for path in self.ei_cmd.filelist.files: if path.startswith(prefix): - target = os.path.join(target_dir, path[len(prefix):]) + target = os.path.join(target_dir, path[len(prefix) :]) ensure_directory(target) self.copy_file(path, target) @@ -291,8 +296,7 @@ def get_ext_outputs(self): if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: all_outputs.append(paths[base] + filename) for filename in dirs: - paths[os.path.join(base, filename)] = (paths[base] + - filename + '/') + paths[os.path.join(base, filename)] = paths[base] + filename + '/' if self.distribution.has_ext_modules(): build_cmd = self.get_finalized_command('build_ext') @@ -365,7 +369,7 @@ def scan_module(egg_dir, base, name, stubs): filename = os.path.join(base, name) if filename[:-1] in stubs: return True # Extension module - pkg = base[len(egg_dir) + 1:].replace(os.sep, '.') + pkg = base[len(egg_dir) + 1 :].replace(os.sep, '.') module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] if sys.version_info < (3, 7): skip = 12 # skip magic & date & file size @@ -383,9 +387,17 @@ def scan_module(egg_dir, base, name, stubs): safe = False if 'inspect' in symbols: for bad in [ - 'getsource', 'getabsfile', 'getsourcefile', 'getfile' - 'getsourcelines', 'findsource', 'getcomments', 'getframeinfo', - 'getinnerframes', 'getouterframes', 'stack', 'trace' + 'getsource', + 'getabsfile', + 'getsourcefile', + 'getfile' 'getsourcelines', + 'findsource', + 'getcomments', + 'getframeinfo', + 'getinnerframes', + 'getouterframes', + 'stack', + 'trace', ]: if bad in symbols: log.warn("%s: module MAY be using inspect.%s", module, bad) @@ -410,20 +422,19 @@ def can_scan(): # CPython, PyPy, etc. return True log.warn("Unable to analyze compiled code on this platform.") - log.warn("Please ask the author to include a 'zip_safe'" - " setting (either True or False) in the package's setup.py") + log.warn( + "Please ask the author to include a 'zip_safe'" + " setting (either True or False) in the package's setup.py" + ) # Attribute names of options for commands that might need to be convinced to # install to the egg build directory -INSTALL_DIRECTORY_ATTRS = [ - 'install_lib', 'install_dir', 'install_data', 'install_base' -] +INSTALL_DIRECTORY_ATTRS = ['install_lib', 'install_dir', 'install_data', 'install_base'] -def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, - mode='w'): +def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, mode='w'): """Create a zip file from all the files under 'base_dir'. The output zip file will be named 'base_dir' + ".zip". Uses either the "zipfile" Python module (if available) or the InfoZIP "zip" utility (if installed @@ -439,7 +450,7 @@ def visit(z, dirname, names): for name in names: path = os.path.normpath(os.path.join(dirname, name)) if os.path.isfile(path): - p = path[len(base_dir) + 1:] + p = path[len(base_dir) + 1 :] if not dry_run: z.write(path, p) log.debug("adding '%s'", p) diff --git a/setuptools/command/bdist_rpm.py b/setuptools/command/bdist_rpm.py index 0eb1b9c254b..707d4fcd7c1 100644 --- a/setuptools/command/bdist_rpm.py +++ b/setuptools/command/bdist_rpm.py @@ -21,11 +21,8 @@ def _make_spec_file(self): spec = [ line.replace( "setup.py install ", - "setup.py install --single-version-externally-managed " - ).replace( - "%setup", - "%setup -n %{name}-%{unmangled_version}" - ) + "setup.py install --single-version-externally-managed ", + ).replace("%setup", "%setup -n %{name}-%{unmangled_version}") for line in spec ] return spec diff --git a/setuptools/command/build_clib.py b/setuptools/command/build_clib.py index 67ce2444ea6..224d91cddb9 100644 --- a/setuptools/command/build_clib.py +++ b/setuptools/command/build_clib.py @@ -27,7 +27,8 @@ def build_libraries(self, libraries): raise DistutilsSetupError( "in 'libraries' option (library '%s'), " "'sources' must be present and must be " - "a list of source filenames" % lib_name) + "a list of source filenames" % lib_name + ) sources = list(sources) log.info("building '%s' library", lib_name) @@ -40,7 +41,8 @@ def build_libraries(self, libraries): raise DistutilsSetupError( "in 'libraries' option (library '%s'), " "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) + "type 'source: list'" % lib_name + ) dependencies = [] # Get the global dependencies that are specified by the '' key. @@ -50,7 +52,8 @@ def build_libraries(self, libraries): raise DistutilsSetupError( "in 'libraries' option (library '%s'), " "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) + "type 'source: list'" % lib_name + ) # Build the list to be used by newer_pairwise_group # each source will be auto-added to its dependencies. @@ -62,7 +65,8 @@ def build_libraries(self, libraries): raise DistutilsSetupError( "in 'libraries' option (library '%s'), " "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) + "type 'source: list'" % lib_name + ) src_deps.extend(extra_deps) dependencies.append(src_deps) @@ -71,10 +75,7 @@ def build_libraries(self, libraries): output_dir=self.build_temp, ) - if ( - newer_pairwise_group(dependencies, expected_objects) - != ([], []) - ): + if newer_pairwise_group(dependencies, expected_objects) != ([], []): # First, compile the source code to object files in the library # directory. (This should probably change to putting object # files in a temporary build directory.) @@ -87,15 +88,12 @@ def build_libraries(self, libraries): macros=macros, include_dirs=include_dirs, extra_postargs=cflags, - debug=self.debug + debug=self.debug, ) # Now "link" the object files together into a static library. # (On Unix at least, this isn't really linking -- it just # builds an archive. Whatever.) self.compiler.create_static_lib( - expected_objects, - lib_name, - output_dir=self.build_clib, - debug=self.debug + expected_objects, lib_name, output_dir=self.build_clib, debug=self.debug ) diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index c59eff8bbf7..28e40699dc3 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -14,6 +14,7 @@ try: # Attempt to use Cython for building extensions, if available from Cython.Distutils.build_ext import build_ext as _build_ext + # Additionally, assert that the compiler module will load # also. Ref #1229. __import__('Cython.Compiler.Main') @@ -33,8 +34,9 @@ def _customize_compiler_for_shlib(compiler): tmp = _CONFIG_VARS.copy() try: # XXX Help! I don't have any idea whether these are right... - _CONFIG_VARS['LDSHARED'] = ( - "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup") + _CONFIG_VARS[ + 'LDSHARED' + ] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup" _CONFIG_VARS['CCSHARED'] = " -dynamiclib" _CONFIG_VARS['SO'] = ".dylib" customize_compiler(compiler) @@ -54,6 +56,7 @@ def _customize_compiler_for_shlib(compiler): elif os.name != 'nt': try: import dl + use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') except ImportError: pass @@ -89,16 +92,14 @@ def copy_extensions_to_source(self): modpath = fullname.split('.') package = '.'.join(modpath[:-1]) package_dir = build_py.get_package_dir(package) - dest_filename = os.path.join(package_dir, - os.path.basename(filename)) + dest_filename = os.path.join(package_dir, os.path.basename(filename)) src_filename = os.path.join(self.build_lib, filename) # Always copy, even if source is older than destination, to ensure # that the right extensions for the current Python/platform are # used. copy_file( - src_filename, dest_filename, verbose=self.verbose, - dry_run=self.dry_run + src_filename, dest_filename, verbose=self.verbose, dry_run=self.dry_run ) if ext._needs_stub: self.write_stub(package_dir or os.curdir, ext, True) @@ -115,7 +116,7 @@ def get_ext_filename(self, fullname): ext = self.ext_map[fullname] use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix() if use_abi3: - filename = filename[:-len(so_ext)] + filename = filename[: -len(so_ext)] so_ext = get_abi3_suffix() filename = filename + so_ext if isinstance(ext, Library): @@ -136,8 +137,7 @@ def finalize_options(self): _build_ext.finalize_options(self) self.extensions = self.extensions or [] self.check_extensions_list(self.extensions) - self.shlibs = [ext for ext in self.extensions - if isinstance(ext, Library)] + self.shlibs = [ext for ext in self.extensions if isinstance(ext, Library)] if self.shlibs: self.setup_shlib_compiler() for ext in self.extensions: @@ -236,52 +236,51 @@ def __get_output_extensions(self): yield '.pyo' def write_stub(self, output_dir, ext, compile=False): - log.info("writing stub loader for %s to %s", ext._full_name, - output_dir) - stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) + - '.py') + log.info("writing stub loader for %s to %s", ext._full_name, output_dir) + stub_file = os.path.join(output_dir, *ext._full_name.split('.')) + '.py' if compile and os.path.exists(stub_file): raise DistutilsError(stub_file + " already exists! Please delete.") if not self.dry_run: f = open(stub_file, 'w') f.write( - '\n'.join([ - "def __bootstrap__():", - " global __bootstrap__, __file__, __loader__", - " import sys, os, pkg_resources, importlib.util" + - if_dl(", dl"), - " __file__ = pkg_resources.resource_filename" - "(__name__,%r)" - % os.path.basename(ext._file_name), - " del __bootstrap__", - " if '__loader__' in globals():", - " del __loader__", - if_dl(" old_flags = sys.getdlopenflags()"), - " old_dir = os.getcwd()", - " try:", - " os.chdir(os.path.dirname(__file__))", - if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), - " spec = importlib.util.spec_from_file_location(", - " __name__, __file__)", - " mod = importlib.util.module_from_spec(spec)", - " spec.loader.exec_module(mod)", - " finally:", - if_dl(" sys.setdlopenflags(old_flags)"), - " os.chdir(old_dir)", - "__bootstrap__()", - "" # terminal \n - ]) + '\n'.join( + [ + "def __bootstrap__():", + " global __bootstrap__, __file__, __loader__", + " import sys, os, pkg_resources, importlib.util" + + if_dl(", dl"), + " __file__ = pkg_resources.resource_filename" + "(__name__,%r)" % os.path.basename(ext._file_name), + " del __bootstrap__", + " if '__loader__' in globals():", + " del __loader__", + if_dl(" old_flags = sys.getdlopenflags()"), + " old_dir = os.getcwd()", + " try:", + " os.chdir(os.path.dirname(__file__))", + if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), + " spec = importlib.util.spec_from_file_location(", + " __name__, __file__)", + " mod = importlib.util.module_from_spec(spec)", + " spec.loader.exec_module(mod)", + " finally:", + if_dl(" sys.setdlopenflags(old_flags)"), + " os.chdir(old_dir)", + "__bootstrap__()", + "", # terminal \n + ] + ) ) f.close() if compile: from distutils.util import byte_compile - byte_compile([stub_file], optimize=0, - force=True, dry_run=self.dry_run) + byte_compile([stub_file], optimize=0, force=True, dry_run=self.dry_run) optimize = self.get_finalized_command('install_lib').optimize if optimize > 0: - byte_compile([stub_file], optimize=optimize, - force=True, dry_run=self.dry_run) + byte_compile( + [stub_file], optimize=optimize, force=True, dry_run=self.dry_run + ) if os.path.exists(stub_file) and not self.dry_run: os.unlink(stub_file) @@ -290,25 +289,56 @@ def write_stub(self, output_dir, ext, compile=False): # Build shared libraries # def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): + self, + objects, + output_libname, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): self.link( - self.SHARED_LIBRARY, objects, output_libname, - output_dir, libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, extra_preargs, extra_postargs, - build_temp, target_lang + self.SHARED_LIBRARY, + objects, + output_libname, + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + export_symbols, + debug, + extra_preargs, + extra_postargs, + build_temp, + target_lang, ) + + else: # Build static libraries everywhere else libtype = 'static' def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): + self, + objects, + output_libname, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): # XXX we need to either disallow these attrs on Library instances, # or warn/abort here if set, or something... # libraries=None, library_dirs=None, runtime_library_dirs=None, @@ -323,6 +353,4 @@ def link_shared_object( # a different prefix basename = basename[3:] - self.create_static_lib( - objects, basename, output_dir, debug, target_lang - ) + self.create_static_lib(objects, basename, output_dir, debug, target_lang) diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py index df6fd323db2..6df15d0beaf 100644 --- a/setuptools/command/build_py.py +++ b/setuptools/command/build_py.py @@ -36,8 +36,7 @@ class build_py(orig.build_py, Mixin2to3): def finalize_options(self): orig.build_py.finalize_options(self) self.package_data = self.distribution.package_data - self.exclude_package_data = (self.distribution.exclude_package_data or - {}) + self.exclude_package_data = self.distribution.exclude_package_data or {} if 'data_files' in self.__dict__: del self.__dict__['data_files'] self.__updated_files = [] @@ -71,8 +70,7 @@ def __getattr__(self, attr): return orig.build_py.__getattr__(self, attr) def build_module(self, module, module_file, package): - outfile, copied = orig.build_py.build_module(self, module, module_file, - package) + outfile, copied = orig.build_py.build_module(self, module, module_file, package) if copied: self.__updated_files.append(outfile) return outfile, copied @@ -123,8 +121,7 @@ def build_package_data(self): outf, copied = self.copy_file(srcfile, target) make_writable(target) srcfile = os.path.abspath(srcfile) - if (copied and - srcfile in self.distribution.convert_2to3_doctests): + if copied and srcfile in self.distribution.convert_2to3_doctests: self.__doctests_2to3.append(outf) def analyze_manifest(self): @@ -202,18 +199,11 @@ def exclude_data_files(self, package, src_dir, files): package, src_dir, ) - match_groups = ( - fnmatch.filter(files, pattern) - for pattern in patterns - ) + match_groups = (fnmatch.filter(files, pattern) for pattern in patterns) # flatten the groups of matches into an iterable of matches matches = itertools.chain.from_iterable(match_groups) bad = set(matches) - keepers = ( - fn - for fn in files - if fn not in bad - ) + keepers = (fn for fn in files if fn not in bad) # ditch dupes return list(unique_everseen(keepers)) @@ -241,12 +231,17 @@ def assert_relative(path): return path from distutils.errors import DistutilsSetupError - msg = textwrap.dedent(""" + msg = ( + textwrap.dedent( + """ Error: setup script specifies an absolute path: %s setup() arguments must *always* be /-separated paths relative to the setup.py directory, *never* absolute paths. - """).lstrip() % path + """ + ).lstrip() + % path + ) raise DistutilsSetupError(msg) diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py index faf8c988e20..11f100bfa45 100644 --- a/setuptools/command/develop.py +++ b/setuptools/command/develop.py @@ -63,7 +63,8 @@ def finalize_options(self): target = pkg_resources.normalize_path(self.egg_base) egg_path = pkg_resources.normalize_path( - os.path.join(self.install_dir, self.egg_path)) + os.path.join(self.install_dir, self.egg_path) + ) if egg_path != target: raise DistutilsOptionError( "--egg-path must be a relative path from the install" @@ -74,7 +75,7 @@ def finalize_options(self): self.dist = pkg_resources.Distribution( target, pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)), - project_name=ei.egg_name + project_name=ei.egg_name, ) self.setup_path = self._resolve_setup_path( @@ -99,8 +100,10 @@ def _resolve_setup_path(egg_base, install_dir, egg_path): if resolved != pkg_resources.normalize_path(os.curdir): raise DistutilsOptionError( "Can't get a consistent path to setup script from" - " installation directory", resolved, - pkg_resources.normalize_path(os.curdir)) + " installation directory", + resolved, + pkg_resources.normalize_path(os.curdir), + ) return path_to_setup def install_for_development(self): @@ -126,7 +129,8 @@ def install_for_development(self): self.dist.location = build_path # XXX self.dist._provider = pkg_resources.PathMetadata( - build_path, ei_cmd.egg_info) + build_path, ei_cmd.egg_info + ) else: # Without 2to3 inplace works fine: self.run_command('egg_info') @@ -156,8 +160,7 @@ def uninstall_link(self): egg_link_file = open(self.egg_link) contents = [line.rstrip() for line in egg_link_file] egg_link_file.close() - if contents not in ([self.egg_path], - [self.egg_path, self.setup_path]): + if contents not in ([self.egg_path], [self.egg_path, self.setup_path]): log.warn("Link points to %s: uninstall aborted", contents) return if not self.dry_run: diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py index c45258fa03a..bdd01069413 100644 --- a/setuptools/command/dist_info.py +++ b/setuptools/command/dist_info.py @@ -14,8 +14,12 @@ class dist_info(Command): description = 'create a .dist-info directory' user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)"), + ( + 'egg-base=', + 'e', + "directory containing .egg-info directories" + " (default: top of the source tree)", + ), ] def initialize_options(self): @@ -29,7 +33,7 @@ def run(self): egg_info.egg_base = self.egg_base egg_info.finalize_options() egg_info.run() - dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info' + dist_info_dir = egg_info.egg_info[: -len('.egg-info')] + '.dist-info' log.info("creating '{}'".format(os.path.abspath(dist_info_dir))) bdist_wheel = self.get_finalized_command('bdist_wheel') diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 45adb6a1eaf..de39c24c69c 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -14,8 +14,10 @@ from distutils.util import get_platform from distutils.util import convert_path, subst_vars from distutils.errors import ( - DistutilsArgError, DistutilsOptionError, - DistutilsError, DistutilsPlatformError, + DistutilsArgError, + DistutilsOptionError, + DistutilsError, + DistutilsPlatformError, ) from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS from distutils import log, dir_util @@ -50,15 +52,28 @@ from setuptools.command import setopt from setuptools.archive_util import unpack_archive from setuptools.package_index import ( - PackageIndex, parse_requirement_arg, URL_SCHEME, + PackageIndex, + parse_requirement_arg, + URL_SCHEME, ) from setuptools.command import bdist_egg, egg_info from setuptools.wheel import Wheel from pkg_resources import ( - yield_lines, normalize_path, resource_string, ensure_directory, - get_distribution, find_distributions, Environment, Requirement, - Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, - VersionConflict, DEVELOP_DIST, + yield_lines, + normalize_path, + resource_string, + ensure_directory, + get_distribution, + find_distributions, + Environment, + Requirement, + Distribution, + PathMetadata, + EggMetadata, + WorkingSet, + DistributionNotFound, + VersionConflict, + DEVELOP_DIST, ) import pkg_resources @@ -66,7 +81,10 @@ warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) __all__ = [ - 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', + 'samefile', + 'easy_install', + 'PthDistributions', + 'extract_wininst_cfg', 'get_exe_prefixes', ] @@ -109,6 +127,7 @@ def _one_liner(text): class easy_install(Command): """Manage a download/build/install process""" + description = "Find/get/install Python packages" command_consumes_arguments = True @@ -123,30 +142,39 @@ class easy_install(Command): ("always-copy", "a", "Copy all needed packages to install dir"), ("index-url=", "i", "base URL of Python Package Index"), ("find-links=", "f", "additional URL(s) to search for packages"), - ("build-directory=", "b", - "download/extract/build in DIR; keep the results"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), - ('record=', None, - "filename in which to record list of installed files"), + ("build-directory=", "b", "download/extract/build in DIR; keep the results"), + ( + 'optimize=', + 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]", + ), + ('record=', None, "filename in which to record list of installed files"), ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), ('site-dirs=', 'S', "list of directories where .pth files work"), ('editable', 'e', "Install specified packages in editable form"), ('no-deps', 'N', "don't install dependencies"), ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), - ('local-snapshots-ok', 'l', - "allow building eggs from local checkouts"), + ('local-snapshots-ok', 'l', "allow building eggs from local checkouts"), ('version', None, "print version information and exit"), - ('no-find-links', None, - "Don't load find-links defined in packages being installed"), - ('user', None, "install in user site-package '%s'" % site.USER_SITE) + ( + 'no-find-links', + None, + "Don't load find-links defined in packages being installed", + ), + ('user', None, "install in user site-package '%s'" % site.USER_SITE), ] boolean_options = [ - 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', + 'zip-ok', + 'multi-version', + 'exclude-scripts', + 'upgrade', + 'always-copy', 'editable', - 'no-deps', 'local-snapshots-ok', 'version', - 'user' + 'no-deps', + 'local-snapshots-ok', + 'version', + 'user', ] negative_opt = {'always-unzip': 'zip-ok'} @@ -201,7 +229,8 @@ def initialize_options(self): def delete_blockers(self, blockers): extant_blockers = ( - filename for filename in blockers + filename + for filename in blockers if os.path.exists(filename) or os.path.islink(filename) ) list(map(self._delete_path, extant_blockers)) @@ -260,7 +289,9 @@ def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME self.expand_dirs() self._expand( - 'install_dir', 'script_dir', 'build_directory', + 'install_dir', + 'script_dir', + 'build_directory', 'site_dirs', ) # If a non-default installation directory was specified, default the @@ -274,13 +305,9 @@ def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME # Let install_dir get set by install_lib command, which in turn # gets its info from the install command, and takes into account # --prefix and --home and all that other crud. - self.set_undefined_options( - 'install_lib', ('install_dir', 'install_dir') - ) + self.set_undefined_options('install_lib', ('install_dir', 'install_dir')) # Likewise, set default script_dir from 'install_scripts.install_dir' - self.set_undefined_options( - 'install_scripts', ('install_dir', 'script_dir') - ) + self.set_undefined_options('install_scripts', ('install_dir', 'script_dir')) if self.user and self.install_purelib: self.install_dir = self.install_purelib @@ -293,8 +320,7 @@ def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME self.all_site_dirs = get_site_dirs() if self.site_dirs is not None: site_dirs = [ - os.path.expanduser(s.strip()) for s in - self.site_dirs.split(',') + os.path.expanduser(s.strip()) for s in self.site_dirs.split(',') ] for d in site_dirs: if not os.path.isdir(d): @@ -319,7 +345,9 @@ def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME hosts = ['*'] if self.package_index is None: self.package_index = self.create_index( - self.index_url, search_path=self.shadow_path, hosts=hosts, + self.index_url, + search_path=self.shadow_path, + hosts=hosts, ) self.local_index = Environment(self.shadow_path + sys.path) @@ -339,9 +367,7 @@ def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME if not (0 <= self.optimize <= 2): raise ValueError except ValueError as e: - raise DistutilsOptionError( - "--optimize must be 0, 1, or 2" - ) from e + raise DistutilsOptionError("--optimize must be 0, 1, or 2") from e if self.editable and not self.build_directory: raise DistutilsArgError( @@ -349,7 +375,8 @@ def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME ) if not self.args: raise DistutilsArgError( - "No urls, filenames, or requirements specified (see --help)") + "No urls, filenames, or requirements specified (see --help)" + ) self.outputs = [] @@ -415,9 +442,9 @@ def run(self, show_deprecation=True): from distutils import file_util self.execute( - file_util.write_file, (self.record, outputs), - "writing list of installed files to '%s'" % - self.record + file_util.write_file, + (self.record, outputs), + "writing list of installed files to '%s'" % self.record, ) self.warn_deprecated_options() finally: @@ -482,7 +509,8 @@ def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME self.pth_file = None # don't create a .pth file self.install_dir = instdir - __cant_write_msg = textwrap.dedent(""" + __cant_write_msg = textwrap.dedent( + """ can't create or remove files in install directory The following error occurred while trying to add or remove files in the @@ -494,15 +522,19 @@ def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME the distutils default setting) was: %s - """).lstrip() # noqa + """ + ).lstrip() # noqa - __not_exists_id = textwrap.dedent(""" + __not_exists_id = textwrap.dedent( + """ This directory does not currently exist. Please create it and try again, or choose a different installation directory (using the -d or --install-dir option). - """).lstrip() # noqa + """ + ).lstrip() # noqa - __access_msg = textwrap.dedent(""" + __access_msg = textwrap.dedent( + """ Perhaps your account does not have write access to this directory? If the installation directory is a system-owned directory, you may need to sign in as the administrator or "root" account. If you do not have administrative @@ -516,10 +548,14 @@ def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME https://setuptools.readthedocs.io/en/latest/easy_install.html Please make the appropriate changes for your system and try again. - """).lstrip() # noqa + """ + ).lstrip() # noqa def cant_write_to_target(self): - msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,) + msg = self.__cant_write_msg % ( + sys.exc_info()[1], + self.install_dir, + ) if not os.path.exists(self.install_dir): msg += '\n' + self.__not_exists_id @@ -534,12 +570,17 @@ def check_pth_processing(self): pth_file = self.pseudo_tempname() + ".pth" ok_file = pth_file + '.ok' ok_exists = os.path.exists(ok_file) - tmpl = _one_liner(""" + tmpl = ( + _one_liner( + """ import os f = open({ok_file!r}, 'w') f.write('OK') f.close() - """) + '\n' + """ + ) + + '\n' + ) try: if ok_exists: os.unlink(ok_file) @@ -557,10 +598,7 @@ def check_pth_processing(self): if os.name == 'nt': dirname, basename = os.path.split(executable) alt = os.path.join(dirname, 'pythonw.exe') - use_alt = ( - basename.lower() == 'python.exe' and - os.path.exists(alt) - ) + use_alt = basename.lower() == 'python.exe' and os.path.exists(alt) if use_alt: # use pythonw.exe to avoid opening a console window executable = alt @@ -570,10 +608,7 @@ def check_pth_processing(self): spawn([executable, '-E', '-c', 'pass'], 0) if os.path.exists(ok_file): - log.info( - "TEST PASSED: %s appears to support .pth files", - instdir - ) + log.info("TEST PASSED: %s appears to support .pth files", instdir) return True finally: if f: @@ -595,8 +630,7 @@ def install_egg_scripts(self, dist): # __pycache__ directory, so skip it. continue self.install_script( - dist, script_name, - dist.get_metadata('scripts/' + script_name) + dist, script_name, dist.get_metadata('scripts/' + script_name) ) self.install_wrapper_scripts(dist) @@ -612,8 +646,7 @@ def not_editable(self, spec): if self.editable: raise DistutilsArgError( "Invalid argument %r: you can't use filenames or URLs " - "with --editable (except via the --find-links option)." - % (spec,) + "with --editable (except via the --find-links option)." % (spec,) ) def check_editable(self, spec): @@ -622,8 +655,8 @@ def check_editable(self, spec): if os.path.exists(os.path.join(self.build_directory, spec.key)): raise DistutilsArgError( - "%r already exists in %s; can't do a checkout there" % - (spec.key, self.build_directory) + "%r already exists in %s; can't do a checkout there" + % (spec.key, self.build_directory) ) @contextlib.contextmanager @@ -653,8 +686,12 @@ def easy_install(self, spec, deps=False): self.check_editable(spec) dist = self.package_index.fetch_distribution( - spec, tmpdir, self.upgrade, self.editable, - not self.always_copy, self.local_index + spec, + tmpdir, + self.upgrade, + self.editable, + not self.always_copy, + self.local_index, ) if dist is None: msg = "Could not find suitable distribution for %r" % spec @@ -675,9 +712,9 @@ def install_item(self, spec, download, tmpdir, deps, install_needed=False): install_needed = install_needed or os.path.dirname(download) == tmpdir install_needed = install_needed or not download.endswith('.egg') install_needed = install_needed or ( - self.always_copy_from is not None and - os.path.dirname(normalize_path(download)) == - normalize_path(self.always_copy_from) + self.always_copy_from is not None + and os.path.dirname(normalize_path(download)) + == normalize_path(self.always_copy_from) ) if spec and not install_needed: @@ -715,7 +752,11 @@ def select_scheme(self, name): # FIXME: 'easy_install.process_distribution' is too complex (12) def process_distribution( # noqa: C901 - self, requirement, dist, deps=True, *info, + self, + requirement, + dist, + deps=True, + *info, ): self.update_pth(dist) self.package_index.add(dist) @@ -725,8 +766,7 @@ def process_distribution( # noqa: C901 self.install_egg_scripts(dist) self.installed_projects[dist.key] = dist log.info(self.installation_report(requirement, dist, *info)) - if (dist.has_metadata('dependency_links.txt') and - not self.no_find_links): + if dist.has_metadata('dependency_links.txt') and not self.no_find_links: self.package_index.add_find_links( dist.get_metadata_lines('dependency_links.txt') ) @@ -767,9 +807,7 @@ def should_unzip(self, dist): def maybe_move(self, spec, dist_filename, setup_base): dst = os.path.join(self.build_directory, spec.key) if os.path.exists(dst): - msg = ( - "%r already exists in %s; build directory %s will not be kept" - ) + msg = "%r already exists in %s; build directory %s will not be kept" log.warn(msg, spec.key, self.build_directory, setup_base) return setup_base if os.path.isdir(dist_filename): @@ -846,9 +884,7 @@ def install_eggs(self, spec, dist_filename, tmpdir): '.whl': self.install_wheel, } try: - install_dist = installer_map[ - dist_filename.lower()[-4:] - ] + install_dist = installer_map[dist_filename.lower()[-4:]] except KeyError: pass else: @@ -861,8 +897,11 @@ def install_eggs(self, spec, dist_filename, tmpdir): elif os.path.isdir(dist_filename): setup_base = os.path.abspath(dist_filename) - if (setup_base.startswith(tmpdir) # something we downloaded - and self.build_directory and spec is not None): + if ( + setup_base.startswith(tmpdir) # something we downloaded + and self.build_directory + and spec is not None + ): setup_base = self.maybe_move(spec, dist_filename, setup_base) # Find the setup.py file @@ -872,13 +911,12 @@ def install_eggs(self, spec, dist_filename, tmpdir): setups = glob(os.path.join(setup_base, '*', 'setup.py')) if not setups: raise DistutilsError( - "Couldn't find a setup script in %s" % - os.path.abspath(dist_filename) + "Couldn't find a setup script in %s" + % os.path.abspath(dist_filename) ) if len(setups) > 1: raise DistutilsError( - "Multiple setup scripts in %s" % - os.path.abspath(dist_filename) + "Multiple setup scripts in %s" % os.path.abspath(dist_filename) ) setup_script = setups[0] @@ -891,8 +929,7 @@ def install_eggs(self, spec, dist_filename, tmpdir): def egg_distribution(self, egg_path): if os.path.isdir(egg_path): - metadata = PathMetadata(egg_path, os.path.join(egg_path, - 'EGG-INFO')) + metadata = PathMetadata(egg_path, os.path.join(egg_path, 'EGG-INFO')) else: metadata = EggMetadata(zipimport.zipimporter(egg_path)) return Distribution.from_filename(egg_path, metadata=metadata) @@ -936,10 +973,8 @@ def install_egg(self, egg_path, tmpdir): # noqa: C901 self.execute( f, (egg_path, destination), - (m + " %s to %s") % ( - os.path.basename(egg_path), - os.path.dirname(destination) - ), + (m + " %s to %s") + % (os.path.basename(egg_path), os.path.dirname(destination)), ) update_dist_caches( destination, @@ -963,7 +998,8 @@ def install_exe(self, dist_filename, tmpdir): dist = Distribution( None, project_name=cfg.get('metadata', 'name'), - version=cfg.get('metadata', 'version'), platform=get_platform(), + version=cfg.get('metadata', 'version'), + platform=get_platform(), ) # Convert the .exe to an unpacked egg @@ -986,13 +1022,15 @@ def install_exe(self, dist_filename, tmpdir): f.close() script_dir = os.path.join(_egg_info, 'scripts') # delete entry-point scripts to avoid duping - self.delete_blockers([ - os.path.join(script_dir, args[0]) - for args in ScriptWriter.get_args(dist) - ]) + self.delete_blockers( + [os.path.join(script_dir, args[0]) for args in ScriptWriter.get_args(dist)] + ) # Build .egg file from tmpdir bdist_egg.make_zipfile( - egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run, + egg_path, + egg_tmp, + verbose=self.verbose, + dry_run=self.dry_run, ) # install the .egg return self.install_egg(egg_path, tmpdir) @@ -1010,7 +1048,7 @@ def process(src, dst): s = src.lower() for old, new in prefixes: if s.startswith(old): - src = new + src[len(old):] + src = new + src[len(old) :] parts = src.split('/') dst = os.path.join(egg_tmp, *parts) dl = dst.lower() @@ -1040,8 +1078,8 @@ def process(src, dst): bdist_egg.write_stub(resource, pyfile) self.byte_compile(to_compile) # compile .py's bdist_egg.write_safety_flag( - os.path.join(egg_tmp, 'EGG-INFO'), - bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag + os.path.join(egg_tmp, 'EGG-INFO'), bdist_egg.analyze_egg(egg_tmp, stubs) + ) # write zip-safety flag for name in 'top_level', 'native_libs': if locals()[name]: @@ -1070,17 +1108,16 @@ def install_wheel(self, wheel_path, tmpdir): self.execute( wheel.install_as_egg, (destination,), - ("Installing %s to %s") % ( - os.path.basename(wheel_path), - os.path.dirname(destination) - ), + ("Installing %s to %s") + % (os.path.basename(wheel_path), os.path.dirname(destination)), ) finally: update_dist_caches(destination, fix_zipimporter_caches=False) self.add_output(destination) return self.egg_distribution(destination) - __mv_warning = textwrap.dedent(""" + __mv_warning = textwrap.dedent( + """ Because this distribution was installed --multi-version, before you can import modules from this package in an application, you will need to 'import pkg_resources' and then use a 'require()' call similar to one of @@ -1089,13 +1126,16 @@ def install_wheel(self, wheel_path, tmpdir): pkg_resources.require("%(name)s") # latest installed version pkg_resources.require("%(name)s==%(version)s") # this exact version pkg_resources.require("%(name)s>=%(version)s") # this version or higher - """).lstrip() # noqa + """ + ).lstrip() # noqa - __id_warning = textwrap.dedent(""" + __id_warning = textwrap.dedent( + """ Note also that the installation directory must be on sys.path at runtime for this to work. (e.g. by being the application's script directory, by being on PYTHONPATH, or by being added to sys.path by your code.) - """) # noqa + """ + ) # noqa def installation_report(self, req, dist, what="Installed"): """Helpful installation message for display to package users""" @@ -1111,7 +1151,8 @@ def installation_report(self, req, dist, what="Installed"): extras = '' # TODO: self.report_extras(req, dist) return msg % locals() - __editable_msg = textwrap.dedent(""" + __editable_msg = textwrap.dedent( + """ Extracted editable version of %(spec)s to %(dirname)s If it uses setuptools in its setup script, you can activate it in @@ -1120,7 +1161,8 @@ def installation_report(self, req, dist, what="Installed"): %(python)s setup.py develop See the setuptools documentation for the "develop" command for more info. - """).lstrip() # noqa + """ + ).lstrip() # noqa def report_editable(self, spec, setup_script): dirname = os.path.dirname(setup_script) @@ -1139,15 +1181,11 @@ def run_setup(self, setup_script, setup_base, args): args.insert(0, '-q') if self.dry_run: args.insert(0, '-n') - log.info( - "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args) - ) + log.info("Running %s %s", setup_script[len(setup_base) + 1 :], ' '.join(args)) try: run_setup(setup_script, args) except SystemExit as v: - raise DistutilsError( - "Setup script exited with %s" % (v.args[0],) - ) from v + raise DistutilsError("Setup script exited with %s" % (v.args[0],)) from v def build_and_install(self, setup_script, setup_base): args = ['bdist_egg', '--dist-dir'] @@ -1166,8 +1204,7 @@ def build_and_install(self, setup_script, setup_base): for dist in all_eggs[key]: eggs.append(self.install_egg(dist.location, setup_base)) if not eggs and not self.dry_run: - log.warn("No eggs found in %s (setup script problem?)", - dist_dir) + log.warn("No eggs found in %s (setup script problem?)", dist_dir) return eggs finally: rmtree(dist_dir) @@ -1184,7 +1221,11 @@ def _set_fetcher_options(self, base): # to the setup.cfg file. ei_opts = self.distribution.get_option_dict('easy_install').copy() fetch_directives = ( - 'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts', + 'find_links', + 'site_dirs', + 'index_url', + 'optimize', + 'allow_hosts', ) fetch_options = {} for key, val in ei_opts.items(): @@ -1274,13 +1315,16 @@ def byte_compile(self, to_compile): byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) if self.optimize: byte_compile( - to_compile, optimize=self.optimize, force=1, + to_compile, + optimize=self.optimize, + force=1, dry_run=self.dry_run, ) finally: log.set_verbosity(self.verbose) # restore original verbosity - __no_default_msg = textwrap.dedent(""" + __no_default_msg = textwrap.dedent( + """ bad install directory or PYTHONPATH You are attempting to install a package to a directory that is not @@ -1310,7 +1354,8 @@ def byte_compile(self, to_compile): Please make the appropriate changes for your system and try again. - """).strip() + """ + ).strip() def create_home_path(self): """Create directories under ~.""" @@ -1382,20 +1427,24 @@ def get_site_dirs(): if sys.platform in ('os2emx', 'riscos'): sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) elif os.sep == '/': - sitedirs.extend([ - os.path.join( - prefix, - "lib", - "python{}.{}".format(*sys.version_info), - "site-packages", - ), - os.path.join(prefix, "lib", "site-python"), - ]) + sitedirs.extend( + [ + os.path.join( + prefix, + "lib", + "python{}.{}".format(*sys.version_info), + "site-packages", + ), + os.path.join(prefix, "lib", "site-python"), + ] + ) else: - sitedirs.extend([ - prefix, - os.path.join(prefix, "lib", "site-packages"), - ]) + sitedirs.extend( + [ + prefix, + os.path.join(prefix, "lib", "site-packages"), + ] + ) if sys.platform != 'darwin': continue @@ -1586,9 +1635,7 @@ def _load(self): continue # skip non-existent paths, in case somebody deleted a package # manually, and duplicate paths as well - path = self.paths[-1] = normalize_path( - os.path.join(self.basedir, path) - ) + path = self.paths[-1] = normalize_path(os.path.join(self.basedir, path)) if not os.path.exists(path) or path in seen: self.paths.pop() # skip it self.dirty = True # we cleaned up, so we're dirty now :) @@ -1629,12 +1676,11 @@ def _wrap_lines(lines): def add(self, dist): """Add `dist` to the distribution map""" - new_path = ( - dist.location not in self.paths and ( - dist.location not in self.sitedirs or - # account for '.' being in PYTHONPATH - dist.location == os.getcwd() - ) + new_path = dist.location not in self.paths and ( + dist.location not in self.sitedirs + or + # account for '.' being in PYTHONPATH + dist.location == os.getcwd() ) if new_path: self.paths.append(dist.location) @@ -1672,18 +1718,22 @@ def _wrap_lines(cls, lines): yield line yield cls.postlude - prelude = _one_liner(""" + prelude = _one_liner( + """ import sys sys.__plen = len(sys.path) - """) - postlude = _one_liner(""" + """ + ) + postlude = _one_liner( + """ import sys new = sys.path[sys.__plen:] del sys.path[sys.__plen:] p = getattr(sys, '__egginsert', 0) sys.path[p:p] = new sys.__egginsert = p + len(new) - """) + """ + ) if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite': @@ -1807,8 +1857,10 @@ def _collect_zipimporter_cache_entries(normalized_path, cache): prefix_len = len(normalized_path) for p in cache: np = normalize_path(p) - if (np.startswith(normalized_path) and - np[prefix_len:prefix_len + 1] in (os.sep, '')): + if np.startswith(normalized_path) and np[prefix_len : prefix_len + 1] in ( + os.sep, + '', + ): result.append(p) return result @@ -1854,8 +1906,10 @@ def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): old_entry.clear() _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=clear_and_remove_cached_zip_archive_directory_data) + normalized_path, + zipimport._zip_directory_cache, + updater=clear_and_remove_cached_zip_archive_directory_data, + ) # PyPy Python implementation does not allow directly writing to the @@ -1867,8 +1921,7 @@ def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): # instead of being automatically corrected to use the new correct zip archive # directory information. if '__pypy__' in sys.builtin_module_names: - _replace_zip_directory_cache_data = \ - _remove_and_clear_zip_directory_cache_data + _replace_zip_directory_cache_data = _remove_and_clear_zip_directory_cache_data else: def _replace_zip_directory_cache_data(normalized_path): @@ -1886,8 +1939,10 @@ def replace_cached_zip_archive_directory_data(path, old_entry): return old_entry _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=replace_cached_zip_archive_directory_data) + normalized_path, + zipimport._zip_directory_cache, + updater=replace_cached_zip_archive_directory_data, + ) def is_python(text, filename=''): @@ -1916,8 +1971,7 @@ def nt_quote_arg(arg): def is_python_script(script_text, filename): - """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. - """ + """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.""" if filename.endswith('.py') or filename.endswith('.pyw'): return True # extension says it's Python if is_python(script_text, filename): @@ -2024,7 +2078,8 @@ def _strip_quotes(item): @staticmethod def _render(items): cmdline = subprocess.list2cmdline( - CommandSpec._strip_quotes(item.strip()) for item in items) + CommandSpec._strip_quotes(item.strip()) for item in items + ) return '#!' + cmdline + '\n' @@ -2042,7 +2097,8 @@ class ScriptWriter: gui apps. """ - template = textwrap.dedent(r""" + template = textwrap.dedent( + r""" # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r import re import sys @@ -2075,7 +2131,8 @@ def importlib_load_entry_point(spec, group, name): if __name__ == '__main__': sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) sys.exit(load_entry_point(%(spec)r, %(group)r, %(name)r)()) - """).lstrip() + """ + ).lstrip() command_spec_class = CommandSpec @@ -2090,8 +2147,7 @@ def get_script_args(cls, dist, executable=None, wininst=False): @classmethod def get_script_header(cls, script_text, executable=None, wininst=False): # for backward compatibility - warnings.warn( - "Use get_header", EasyInstallDeprecationWarning, stacklevel=2) + warnings.warn("Use get_header", EasyInstallDeprecationWarning, stacklevel=2) if wininst: executable = "python.exe" return cls.get_header(script_text, executable) @@ -2235,8 +2291,9 @@ def _get_script_args(cls, type_, name, header, script_text): blockers = [name + x for x in old] yield (name + ext, hdr + script_text, 't', blockers) yield ( - name + '.exe', get_win_launcher(launcher_type), - 'b' # write in binary mode + name + '.exe', + get_win_launcher(launcher_type), + 'b', # write in binary mode ) if not is_64bit(): # install a manifest for the launcher to prevent Windows diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 18b81340a7f..05530cb109b 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -23,8 +23,15 @@ from setuptools.command.setopt import edit_config from setuptools.command import bdist_egg from pkg_resources import ( - parse_requirements, safe_name, parse_version, - safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) + parse_requirements, + safe_name, + parse_version, + safe_version, + yield_lines, + EntryPoint, + iter_entry_points, + to_filename, +) import setuptools.unicode_utils as unicode_utils from setuptools.glob import glob @@ -90,7 +97,7 @@ def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME pat += re.escape(char) else: # Grab the insides of the [brackets] - inner = chunk[i + 1:inner_i] + inner = chunk[i + 1 : inner_i] char_class = '' # Class negation @@ -132,7 +139,8 @@ def _maybe_tag(self, version): in which case the version string already contains all tags. """ return ( - version if self.vtags and version.endswith(self.vtags) + version + if self.vtags and version.endswith(self.vtags) else version + self.vtags ) @@ -143,6 +151,7 @@ def tags(self): if self.tag_date: version += time.strftime("-%Y%m%d") return version + vtags = property(tags) @@ -150,8 +159,12 @@ class egg_info(InfoCommon, Command): description = "create a distribution's .egg-info directory" user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)"), + ( + 'egg-base=', + 'e', + "directory containing .egg-info directories" + " (default: top of the source tree)", + ), ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), ('tag-build=', 'b', "Specify explicit tag to add to version number"), ('no-date', 'D', "Don't include date stamp [default]"), @@ -179,6 +192,7 @@ def tag_svn_revision(self): @tag_svn_revision.setter def tag_svn_revision(self, value): pass + #################################### def save_version_info(self, filename): @@ -205,16 +219,12 @@ def finalize_options(self): try: is_version = isinstance(parsed_version, packaging.version.Version) - spec = ( - "%s==%s" if is_version else "%s===%s" - ) - list( - parse_requirements(spec % (self.egg_name, self.egg_version)) - ) + spec = "%s==%s" if is_version else "%s===%s" + list(parse_requirements(spec % (self.egg_name, self.egg_version))) except ValueError as e: raise distutils.errors.DistutilsOptionError( - "Invalid distribution name or version syntax: %s-%s" % - (self.egg_name, self.egg_version) + "Invalid distribution name or version syntax: %s-%s" + % (self.egg_name, self.egg_version) ) from e if self.egg_base is None: @@ -256,9 +266,7 @@ def write_or_delete_file(self, what, filename, data, force=False): self.write_file(what, filename, data) elif os.path.exists(filename): if data is None and not force: - log.warn( - "%s not set in setup(), but %s exists", what, filename - ) + log.warn("%s not set in setup(), but %s exists", what, filename) return else: self.delete_file(filename) @@ -316,7 +324,8 @@ def check_broken_egg_info(self): "Note: Your current .egg-info directory has a '-' in its name;" '\nthis will not work correctly with "setup.py develop".\n\n' 'Please rename %s to %s to correct this problem.\n' + '-' * 78, - bei, self.egg_info + bei, + self.egg_info, ) self.broken_egg_info = self.egg_info self.egg_info = bei # make it work for now @@ -339,31 +348,28 @@ def process_template_line(self, line): 'global-include': self.global_include, 'global-exclude': self.global_exclude, 'recursive-include': functools.partial( - self.recursive_include, dir, + self.recursive_include, + dir, ), 'recursive-exclude': functools.partial( - self.recursive_exclude, dir, + self.recursive_exclude, + dir, ), 'graft': self.graft, 'prune': self.prune, } log_map = { 'include': "warning: no files found matching '%s'", - 'exclude': ( - "warning: no previously-included files found " - "matching '%s'" - ), + 'exclude': ("warning: no previously-included files found " "matching '%s'"), 'global-include': ( - "warning: no files found matching '%s' " - "anywhere in distribution" + "warning: no files found matching '%s' " "anywhere in distribution" ), 'global-exclude': ( "warning: no previously-included files matching " "'%s' found anywhere in distribution" ), 'recursive-include': ( - "warning: no files found matching '%s' " - "under directory '%s'" + "warning: no files found matching '%s' " "under directory '%s'" ), 'recursive-exclude': ( "warning: no previously-included files matching " @@ -377,8 +383,7 @@ def process_template_line(self, line): process_action = action_map[action] except KeyError: raise DistutilsInternalError( - "this cannot happen: invalid action '{action!s}'". - format(action=action), + "this cannot happen: invalid action '{action!s}'".format(action=action), ) # OK, now we know that the action is valid and we have the @@ -388,14 +393,12 @@ def process_template_line(self, line): action_is_recursive = action.startswith('recursive-') if action in {'graft', 'prune'}: patterns = [dir_pattern] - extra_log_args = (dir, ) if action_is_recursive else () + extra_log_args = (dir,) if action_is_recursive else () log_tmpl = log_map[action] self.debug_print( ' '.join( - [action] + - ([dir] if action_is_recursive else []) + - patterns, + [action] + ([dir] if action_is_recursive else []) + patterns, ) ) for pattern in patterns: @@ -431,8 +434,7 @@ def recursive_include(self, dir, pattern): Include all files anywhere in 'dir/' that match the pattern. """ full_pattern = os.path.join(dir, '**', pattern) - found = [f for f in glob(full_pattern, recursive=True) - if not os.path.isdir(f)] + found = [f for f in glob(full_pattern, recursive=True) if not os.path.isdir(f)] self.extend(found) return bool(found) @@ -605,8 +607,9 @@ def prune_file_list(self): self.filelist.prune(build.build_base) self.filelist.prune(base_dir) sep = re.escape(os.sep) - self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, - is_regex=1) + self.filelist.exclude_pattern( + r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, is_regex=1 + ) def write_file(filename, contents): @@ -654,6 +657,7 @@ def _write_requirements(stream, reqs): def append_cr(line): return line + '\n' + lines = map(append_cr, lines) stream.writelines(lines) @@ -677,10 +681,7 @@ def write_setup_requirements(cmd, basename, filename): def write_toplevel_names(cmd, basename, filename): pkgs = dict.fromkeys( - [ - k.split('.', 1)[0] - for k in cmd.distribution.iter_distribution_names() - ] + [k.split('.', 1)[0] for k in cmd.distribution.iter_distribution_names()] ) cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n') @@ -719,8 +720,7 @@ def get_pkg_info_revision(): Get a -r### off of PKG-INFO Version in case this is an sdist of a subversion revision. """ - warnings.warn( - "get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning) + warnings.warn("get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning) if os.path.exists('PKG-INFO'): with io.open('PKG-INFO') as f: for line in f: diff --git a/setuptools/command/install.py b/setuptools/command/install.py index 72b9a3e4247..aa6732a73a1 100644 --- a/setuptools/command/install.py +++ b/setuptools/command/install.py @@ -17,11 +17,15 @@ class install(orig.install): user_options = orig.install.user_options + [ ('old-and-unmanageable', None, "Try not to use this!"), - ('single-version-externally-managed', None, - "used by system package builders to create 'flat' eggs"), + ( + 'single-version-externally-managed', + None, + "used by system package builders to create 'flat' eggs", + ), ] boolean_options = orig.install.boolean_options + [ - 'old-and-unmanageable', 'single-version-externally-managed', + 'old-and-unmanageable', + 'single-version-externally-managed', ] new_commands = [ ('install_egg_info', lambda self: True), @@ -85,20 +89,20 @@ def _called_from_setup(run_frame): warnings.warn(msg) return True res = inspect.getouterframes(run_frame)[2] - caller, = res[:1] + (caller,) = res[:1] info = inspect.getframeinfo(caller) caller_module = caller.f_globals.get('__name__', '') - return ( - caller_module == 'distutils.dist' - and info.function == 'run_commands' - ) + return caller_module == 'distutils.dist' and info.function == 'run_commands' def do_egg_install(self): easy_install = self.distribution.get_command_class('easy_install') cmd = easy_install( - self.distribution, args="x", root=self.root, record=self.record, + self.distribution, + args="x", + root=self.root, + record=self.record, ) cmd.ensure_finalized() # finalize before bdist_egg munges install cmd cmd.always_copy_from = '.' # make sure local-dir eggs get installed @@ -119,7 +123,6 @@ def do_egg_install(self): # XXX Python 3.1 doesn't see _nc if this is inside the class -install.sub_commands = ( - [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] + - install.new_commands -) +install.sub_commands = [ + cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc +] + install.new_commands diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py index edc4718b686..4c8d9bac32a 100644 --- a/setuptools/command/install_egg_info.py +++ b/setuptools/command/install_egg_info.py @@ -20,12 +20,14 @@ def initialize_options(self): self.install_dir = None def finalize_options(self): - self.set_undefined_options('install_lib', - ('install_dir', 'install_dir')) + self.set_undefined_options('install_lib', ('install_dir', 'install_dir')) ei_cmd = self.get_finalized_command("egg_info") - basename = pkg_resources.Distribution( - None, None, ei_cmd.egg_name, ei_cmd.egg_version - ).egg_name() + '.egg-info' + basename = ( + pkg_resources.Distribution( + None, None, ei_cmd.egg_name, ei_cmd.egg_version + ).egg_name() + + '.egg-info' + ) self.source = ei_cmd.egg_info self.target = os.path.join(self.install_dir, basename) self.outputs = [] @@ -38,9 +40,7 @@ def run(self): self.execute(os.unlink, (self.target,), "Removing " + self.target) if not self.dry_run: pkg_resources.ensure_directory(self.target) - self.execute( - self.copytree, (), "Copying %s to %s" % (self.source, self.target) - ) + self.execute(self.copytree, (), "Copying %s to %s" % (self.source, self.target)) self.install_namespaces() def get_outputs(self): diff --git a/setuptools/command/install_lib.py b/setuptools/command/install_lib.py index 2e9d8757a58..32ff65e783b 100644 --- a/setuptools/command/install_lib.py +++ b/setuptools/command/install_lib.py @@ -77,16 +77,20 @@ def _gen_exclusion_paths(): if not hasattr(sys, 'implementation'): return - base = os.path.join( - '__pycache__', '__init__.' + sys.implementation.cache_tag) + base = os.path.join('__pycache__', '__init__.' + sys.implementation.cache_tag) yield base + '.pyc' yield base + '.pyo' yield base + '.opt-1.pyc' yield base + '.opt-2.pyc' def copy_tree( - self, infile, outfile, - preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 + self, + infile, + outfile, + preserve_mode=1, + preserve_times=1, + preserve_symlinks=0, + level=1, ): assert preserve_mode and preserve_times and not preserve_symlinks exclude = self.get_exclusions() @@ -103,8 +107,7 @@ def copy_tree( def pf(src, dst): if dst in exclude: - log.warn("Skipping installation of %s (namespace package)", - dst) + log.warn("Skipping installation of %s (namespace package)", dst) return False log.info("copying %s -> %s", src, os.path.dirname(dst)) diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py index 9cd8eb06277..c86af4973d3 100644 --- a/setuptools/command/install_scripts.py +++ b/setuptools/command/install_scripts.py @@ -28,8 +28,10 @@ def run(self): ei_cmd = self.get_finalized_command("egg_info") dist = Distribution( - ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), - ei_cmd.egg_name, ei_cmd.egg_version, + ei_cmd.egg_base, + PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), + ei_cmd.egg_name, + ei_cmd.egg_version, ) bs_cmd = self.get_finalized_command('build_scripts') exec_param = getattr(bs_cmd, 'executable', None) diff --git a/setuptools/command/py36compat.py b/setuptools/command/py36compat.py index 343547a4d31..b13af6b0162 100644 --- a/setuptools/command/py36compat.py +++ b/setuptools/command/py36compat.py @@ -65,8 +65,9 @@ def _add_defaults_standards(self): break if not got_it: - self.warn("standard file not found: should have one of " + - ', '.join(alts)) + self.warn( + "standard file not found: should have one of " + ', '.join(alts) + ) else: if self._cs_path_exists(fn): self.filelist.append(fn) diff --git a/setuptools/command/rotate.py b/setuptools/command/rotate.py index 74795ba922b..3fbd921f1fb 100644 --- a/setuptools/command/rotate.py +++ b/setuptools/command/rotate.py @@ -37,9 +37,7 @@ def finalize_options(self): except ValueError as e: raise DistutilsOptionError("--keep must be an integer") from e if isinstance(self.match, str): - self.match = [ - convert_path(p.strip()) for p in self.match.split(',') - ] + self.match = [convert_path(p.strip()) for p in self.match.split(',')] self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) def run(self): @@ -54,7 +52,7 @@ def run(self): files.reverse() log.info("%d file(s) matching %s", len(files), pattern) - files = files[self.keep:] + files = files[self.keep :] for (t, f) in files: log.info("Deleting %s", f) if not self.dry_run: diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 4a014283c86..7bf77f906f4 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -23,14 +23,17 @@ class sdist(sdist_add_defaults, orig.sdist): """Smart sdist that finds anything supported by revision control""" user_options = [ - ('formats=', None, - "formats for source distribution (comma-separated list)"), - ('keep-temp', 'k', - "keep the distribution tree around after creating " + - "archive file(s)"), - ('dist-dir=', 'd', - "directory to put the source distribution archive(s) in " - "[default: dist]"), + ('formats=', None, "formats for source distribution (comma-separated list)"), + ( + 'keep-temp', + 'k', + "keep the distribution tree around after creating " + "archive file(s)", + ), + ( + 'dist-dir=', + 'd', + "directory to put the source distribution archive(s) in " "[default: dist]", + ), ] negative_opt = {} @@ -140,8 +143,7 @@ def check_readme(self): return else: self.warn( - "standard file not found: should have one of " + - ', '.join(self.READMES) + "standard file not found: should have one of " + ', '.join(self.READMES) ) def make_release_tree(self, base_dir, files): @@ -164,8 +166,7 @@ def _manifest_is_not_generated(self): with io.open(self.manifest, 'rb') as fp: first_line = fp.readline() - return (first_line != - '# file GENERATED by distutils, do NOT edit\n'.encode()) + return first_line != '# file GENERATED by distutils, do NOT edit\n'.encode() def read_manifest(self): """Read the manifest file (named by 'self.manifest') and use it to diff --git a/setuptools/command/setopt.py b/setuptools/command/setopt.py index e18057c81ec..0703f96694e 100644 --- a/setuptools/command/setopt.py +++ b/setuptools/command/setopt.py @@ -18,15 +18,11 @@ def config_file(kind="local"): if kind == 'local': return 'setup.cfg' if kind == 'global': - return os.path.join( - os.path.dirname(distutils.__file__), 'distutils.cfg' - ) + return os.path.join(os.path.dirname(distutils.__file__), 'distutils.cfg') if kind == 'user': dot = os.name == 'posix' and '.' or '' return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot)) - raise ValueError( - "config_file() type must be 'local', 'global', or 'user'", kind - ) + raise ValueError("config_file() type must be 'local', 'global', or 'user'", kind) def edit_config(filename, settings, dry_run=False): @@ -50,19 +46,16 @@ def edit_config(filename, settings, dry_run=False): opts.add_section(section) for option, value in options.items(): if value is None: - log.debug( - "Deleting %s.%s from %s", - section, option, filename - ) + log.debug("Deleting %s.%s from %s", section, option, filename) opts.remove_option(section, option) if not opts.options(section): - log.info("Deleting empty [%s] section from %s", - section, filename) + log.info( + "Deleting empty [%s] section from %s", section, filename + ) opts.remove_section(section) else: log.debug( - "Setting %s.%s to %r in %s", - section, option, value, filename + "Setting %s.%s to %r in %s", section, option, value, filename ) opts.set(section, option, value) @@ -76,16 +69,14 @@ class option_base(Command): """Abstract base class for commands that mess with config files""" user_options = [ - ('global-config', 'g', - "save options to the site-wide distutils.cfg file"), - ('user-config', 'u', - "save options to the current user's pydistutils.cfg file"), - ('filename=', 'f', - "configuration file to use (default=setup.cfg)"), + ('global-config', 'g', "save options to the site-wide distutils.cfg file"), + ('user-config', 'u', "save options to the current user's pydistutils.cfg file"), + ('filename=', 'f', "configuration file to use (default=setup.cfg)"), ] boolean_options = [ - 'global-config', 'user-config', + 'global-config', + 'user-config', ] def initialize_options(self): @@ -105,10 +96,9 @@ def finalize_options(self): filenames.append(config_file('local')) if len(filenames) > 1: raise DistutilsOptionError( - "Must specify only one configuration file option", - filenames + "Must specify only one configuration file option", filenames ) - self.filename, = filenames + (self.filename,) = filenames class setopt(option_base): @@ -141,8 +131,7 @@ def finalize_options(self): def run(self): edit_config( - self.filename, { - self.command: {self.option.replace('-', '_'): self.set_value} - }, - self.dry_run + self.filename, + {self.command: {self.option.replace('-', '_'): self.set_value}}, + self.dry_run, ) diff --git a/setuptools/command/test.py b/setuptools/command/test.py index de4f3d11a76..50daaea61a1 100644 --- a/setuptools/command/test.py +++ b/setuptools/command/test.py @@ -8,15 +8,22 @@ from distutils import log from unittest import TestLoader -from pkg_resources import (resource_listdir, resource_exists, normalize_path, - working_set, _namespace_packages, evaluate_marker, - add_activation_listener, require, EntryPoint) +from pkg_resources import ( + resource_listdir, + resource_exists, + normalize_path, + working_set, + _namespace_packages, + evaluate_marker, + add_activation_listener, + require, + EntryPoint, +) from setuptools import Command from setuptools.extern.more_itertools import unique_everseen class ScanningLoader(TestLoader): - def __init__(self): TestLoader.__init__(self) self._visited = set() @@ -73,8 +80,11 @@ class test(Command): user_options = [ ('test-module=', 'm', "Run 'test_suite' in specified module"), - ('test-suite=', 's', - "Run single test, case or suite (e.g. 'module.test_suite')"), + ( + 'test-suite=', + 's', + "Run single test, case or suite (e.g. 'module.test_suite')", + ), ('test-runner=', 'r', "Test runner to use"), ] @@ -203,7 +213,8 @@ def install_dists(dist): ir_d = dist.fetch_build_eggs(dist.install_requires) tr_d = dist.fetch_build_eggs(dist.tests_require or []) er_d = dist.fetch_build_eggs( - v for k, v in dist.extras_require.items() + v + for k, v in dist.extras_require.items() if k.startswith(':') and evaluate_marker(k[1:]) ) return itertools.chain(ir_d, tr_d, er_d) @@ -248,7 +259,9 @@ def run_tests(self): list(map(sys.modules.__delitem__, del_modules)) test = unittest.main( - None, None, self._argv, + None, + None, + self._argv, testLoader=self._resolve_as_ep(self.test_loader), testRunner=self._resolve_as_ep(self.test_runner), exit=False, diff --git a/setuptools/command/upload_docs.py b/setuptools/command/upload_docs.py index 845bff4421f..8e4870555c0 100644 --- a/setuptools/command/upload_docs.py +++ b/setuptools/command/upload_docs.py @@ -34,10 +34,12 @@ class upload_docs(upload): description = 'Upload documentation to sites other than PyPi such as devpi' user_options = [ - ('repository=', 'r', - "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), - ('show-response', None, - 'display full response text from server'), + ( + 'repository=', + 'r', + "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY, + ), + ('show-response', None, 'display full response text from server'), ('upload-dir=', None, 'directory to upload'), ] boolean_options = upload.boolean_options @@ -80,7 +82,7 @@ def create_zipfile(self, filename): raise DistutilsOptionError(tmpl % self.target_dir) for name in files: full = os.path.join(root, name) - relative = root[len(self.target_dir):].lstrip(os.path.sep) + relative = root[len(self.target_dir) :].lstrip(os.path.sep) dest = os.path.join(relative, name) zip_file.write(full, dest) finally: @@ -128,7 +130,10 @@ def _build_multipart(cls, data): boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' sep_boundary = b'\n--' + boundary.encode('ascii') end_boundary = sep_boundary + b'--' - end_items = end_boundary, b"\n", + end_items = ( + end_boundary, + b"\n", + ) builder = functools.partial( cls._build_part, sep_boundary=sep_boundary, @@ -161,8 +166,9 @@ def upload_file(self, filename): # build the Request # We can't use urllib2 since we need to send the Basic # auth right with the first request - schema, netloc, url, params, query, fragments = \ - urllib.parse.urlparse(self.repository) + schema, netloc, url, params, query, fragments = urllib.parse.urlparse( + self.repository + ) assert not params and not query and not fragments if schema == 'http': conn = http.client.HTTPConnection(netloc) diff --git a/setuptools/config.py b/setuptools/config.py index 44de7cf5f23..aa0185efb4f 100644 --- a/setuptools/config.py +++ b/setuptools/config.py @@ -20,6 +20,7 @@ class StaticModule: """ Attempt to load the module by the name """ + def __init__(self, name): spec = importlib.util.find_spec(name) with open(spec.origin) as strm: @@ -55,8 +56,7 @@ def patch_path(path): sys.path.remove(path) -def read_configuration( - filepath, find_others=False, ignore_option_errors=False): +def read_configuration(filepath, find_others=False, ignore_option_errors=False): """Read given configuration file and returns options from it as a dict. :param str|unicode filepath: Path to configuration file @@ -77,8 +77,7 @@ def read_configuration( filepath = os.path.abspath(filepath) if not os.path.isfile(filepath): - raise DistutilsFileError( - 'Configuration file %s does not exist.' % filepath) + raise DistutilsFileError('Configuration file %s does not exist.' % filepath) current_directory = os.getcwd() os.chdir(os.path.dirname(filepath)) @@ -93,8 +92,8 @@ def read_configuration( _Distribution.parse_config_files(dist, filenames=filenames) handlers = parse_configuration( - dist, dist.command_options, - ignore_option_errors=ignore_option_errors) + dist, dist.command_options, ignore_option_errors=ignore_option_errors + ) finally: os.chdir(current_directory) @@ -132,8 +131,7 @@ def configuration_to_dict(handlers): return config_dict -def parse_configuration( - distribution, command_options, ignore_option_errors=False): +def parse_configuration(distribution, command_options, ignore_option_errors=False): """Performs additional parsing of configuration options for a distribution. @@ -147,13 +145,15 @@ def parse_configuration( If False exceptions are propagated as expected. :rtype: list """ - options = ConfigOptionsHandler( - distribution, command_options, ignore_option_errors) + options = ConfigOptionsHandler(distribution, command_options, ignore_option_errors) options.parse() meta = ConfigMetadataHandler( - distribution.metadata, command_options, ignore_option_errors, - distribution.package_dir) + distribution.metadata, + command_options, + ignore_option_errors, + distribution.package_dir, + ) meta.parse() return meta, options @@ -195,7 +195,8 @@ def __init__(self, target_obj, options, ignore_option_errors=False): def parsers(self): """Metadata item name to parser function mapping.""" raise NotImplementedError( - '%s must provide .parsers property' % self.__class__.__name__) + '%s must provide .parsers property' % self.__class__.__name__ + ) def __setitem__(self, option_name, value): unknown = tuple() @@ -268,7 +269,8 @@ def _parse_dict(cls, value): key, sep, val = line.partition(separator) if sep != separator: raise DistutilsOptionError( - 'Unable to parse option value to dict: %s' % value) + 'Unable to parse option value to dict: %s' % value + ) result[key.strip()] = val.strip() return result @@ -294,13 +296,16 @@ def _exclude_files_parser(cls, key): :param key: :rtype: callable """ + def parser(value): exclude_directive = 'file:' if value.startswith(exclude_directive): raise ValueError( 'Only strings are accepted for the {0} field, ' - 'files are not accepted'.format(key)) + 'files are not accepted'.format(key) + ) return value + return parser @classmethod @@ -325,20 +330,18 @@ def _parse_file(cls, value): if not value.startswith(include_directive): return value - spec = value[len(include_directive):] + spec = value[len(include_directive) :] filepaths = (os.path.abspath(path.strip()) for path in spec.split(',')) return '\n'.join( cls._read_file(path) for path in filepaths - if (cls._assert_local(path) or True) - and os.path.isfile(path) + if (cls._assert_local(path) or True) and os.path.isfile(path) ) @staticmethod def _assert_local(filepath): if not filepath.startswith(os.getcwd()): - raise DistutilsOptionError( - '`file:` directive can not access %s' % filepath) + raise DistutilsOptionError('`file:` directive can not access %s' % filepath) @staticmethod def _read_file(filepath): @@ -400,6 +403,7 @@ def _get_parser_compound(cls, *parse_methods): :param parse_methods: :rtype: callable """ + def parse(value): parsed = value @@ -453,22 +457,25 @@ def parse(self): self, # Dots in section names are translated into dunderscores. ('parse_section%s' % method_postfix).replace('.', '__'), - None) + None, + ) if section_parser_method is None: raise DistutilsOptionError( - 'Unsupported distribution option section: [%s.%s]' % ( - self.section_prefix, section_name)) + 'Unsupported distribution option section: [%s.%s]' + % (self.section_prefix, section_name) + ) section_parser_method(section_options) def _deprecated_config_handler(self, func, msg, warning_class): - """ this function will wrap around parameters that are deprecated + """this function will wrap around parameters that are deprecated :param msg: deprecation message :param warning_class: class of warning exception to be raised :param func: function to be wrapped around """ + @wraps(func) def config_handler(*args, **kwargs): warnings.warn(msg, warning_class) @@ -494,10 +501,12 @@ class ConfigMetadataHandler(ConfigHandler): """ - def __init__(self, target_obj, options, ignore_option_errors=False, - package_dir=None): - super(ConfigMetadataHandler, self).__init__(target_obj, options, - ignore_option_errors) + def __init__( + self, target_obj, options, ignore_option_errors=False, package_dir=None + ): + super(ConfigMetadataHandler, self).__init__( + target_obj, options, ignore_option_errors + ) self.package_dir = package_dir @property @@ -516,7 +525,8 @@ def parsers(self): parse_list, "The requires parameter is deprecated, please use " "install_requires for runtime dependencies.", - DeprecationWarning), + DeprecationWarning, + ), 'obsoletes': parse_list, 'classifiers': self._get_parser_compound(parse_file, parse_list), 'license': exclude_files_parser('license'), @@ -524,7 +534,8 @@ def parsers(self): exclude_files_parser('license_file'), "The license_file parameter is deprecated, " "use license_files instead.", - DeprecationWarning), + DeprecationWarning, + ), 'license_files': parse_list, 'description': parse_file, 'long_description': parse_file, @@ -606,17 +617,14 @@ def parsers(self): def _parse_cmdclass(self, value): def resolve_class(qualified_class_name): idx = qualified_class_name.rfind('.') - class_name = qualified_class_name[idx+1:] + class_name = qualified_class_name[idx + 1 :] pkg_name = qualified_class_name[:idx] module = __import__(pkg_name) return getattr(module, class_name) - return { - k: resolve_class(v) - for k, v in self._parse_dict(value).items() - } + return {k: resolve_class(v) for k, v in self._parse_dict(value).items()} def _parse_packages(self, value): """Parses `packages` option value. @@ -634,7 +642,8 @@ def _parse_packages(self, value): # Read function arguments from a dedicated section. find_kwargs = self.parse_section_packages__find( - self.sections.get('packages.find', {})) + self.sections.get('packages.find', {}) + ) if findns: from setuptools import find_namespace_packages as find_packages @@ -650,13 +659,13 @@ def parse_section_packages__find(self, section_options): :param dict section_options: """ - section_data = self._parse_section_to_dict( - section_options, self._parse_list) + section_data = self._parse_section_to_dict(section_options, self._parse_list) valid_keys = ['where', 'include', 'exclude'] find_kwargs = dict( - [(k, v) for k, v in section_data.items() if k in valid_keys and v]) + [(k, v) for k, v in section_data.items() if k in valid_keys and v] + ) where = find_kwargs.get('where') if where is not None: @@ -694,8 +703,7 @@ def parse_section_exclude_package_data(self, section_options): :param dict section_options: """ - self['exclude_package_data'] = self._parse_package_data( - section_options) + self['exclude_package_data'] = self._parse_package_data(section_options) def parse_section_extras_require(self, section_options): """Parses `extras_require` configuration file section. @@ -704,7 +712,8 @@ def parse_section_extras_require(self, section_options): """ parse_list = partial(self._parse_list, separator=';') self['extras_require'] = self._parse_section_to_dict( - section_options, parse_list) + section_options, parse_list + ) def parse_section_data_files(self, section_options): """Parses `data_files` configuration file section. diff --git a/setuptools/dep_util.py b/setuptools/dep_util.py index 521eb716a5e..dc9ccf62c20 100644 --- a/setuptools/dep_util.py +++ b/setuptools/dep_util.py @@ -11,8 +11,7 @@ def newer_pairwise_group(sources_groups, targets): of 'newer_group()'. """ if len(sources_groups) != len(targets): - raise ValueError( - "'sources_group' and 'targets' must be the same length") + raise ValueError("'sources_group' and 'targets' must be the same length") # build a pair of lists (sources_groups, targets) where source is newer n_sources = [] diff --git a/setuptools/depends.py b/setuptools/depends.py index 8be6928a31f..76aab41ae23 100644 --- a/setuptools/depends.py +++ b/setuptools/depends.py @@ -8,17 +8,15 @@ from . import _imp -__all__ = [ - 'Require', 'find_module', 'get_module_constant', 'extract_constant' -] +__all__ = ['Require', 'find_module', 'get_module_constant', 'extract_constant'] class Require: """A prerequisite to building or installing a distribution""" def __init__( - self, name, requested_version, module, homepage='', - attribute=None, format=None): + self, name, requested_version, module, homepage='', attribute=None, format=None + ): if format is None and requested_version is not None: format = StrictVersion @@ -39,8 +37,12 @@ def full_name(self): def version_ok(self, version): """Is 'version' sufficiently up-to-date?""" - return self.attribute is None or self.format is None or \ - str(version) != "unknown" and version >= self.requested_version + return ( + self.attribute is None + or self.format is None + or str(version) != "unknown" + and version >= self.requested_version + ) def get_version(self, paths=None, default="unknown"): """Get version number of installed module, 'None', or 'default' @@ -86,6 +88,7 @@ def maybe_close(f): def empty(): yield return + if not f: return empty() diff --git a/setuptools/dist.py b/setuptools/dist.py index df071c16c16..5b9e383406a 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -65,9 +65,7 @@ def rfc822_unescape(content: str) -> str: lines = content.splitlines() if len(lines) == 1: return lines[0].lstrip() - return '\n'.join( - (lines[0].lstrip(), - textwrap.dedent('\n'.join(lines[1:])))) + return '\n'.join((lines[0].lstrip(), textwrap.dedent('\n'.join(lines[1:])))) def _read_field_from_msg(msg: "Message", field: str) -> Optional[str]: @@ -157,8 +155,7 @@ def single_line(val): # Based on Python 3.5 version def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME - """Write the PKG-INFO format data to a file object. - """ + """Write the PKG-INFO format data to a file object.""" version = self.get_metadata_version() def write_field(key, value): @@ -209,10 +206,7 @@ def write_field(key, value): # PEP 566 if self.long_description_content_type: - write_field( - 'Description-Content-Type', - self.long_description_content_type - ) + write_field('Description-Content-Type', self.long_description_content_type) if self.provides_extras: for extra in self.provides_extras: write_field('Provides-Extra', extra) @@ -231,8 +225,7 @@ def check_importable(dist, attr, value): assert not ep.extras except (TypeError, ValueError, AttributeError, AssertionError) as e: raise DistutilsSetupError( - "%r must be importable 'module:attrs' string (got %r)" - % (attr, value) + "%r must be importable 'module:attrs' string (got %r)" % (attr, value) ) from e @@ -257,14 +250,16 @@ def check_nsp(dist, attr, value): for nsp in ns_packages: if not dist.has_contents_for(nsp): raise DistutilsSetupError( - "Distribution contains no modules or packages for " + - "namespace package %r" % nsp + "Distribution contains no modules or packages for " + + "namespace package %r" % nsp ) parent, sep, child = nsp.rpartition('.') if parent and parent not in ns_packages: distutils.log.warn( "WARNING: %r is declared as a package namespace, but %r" - " is not: please correct this in setup.py", nsp, parent + " is not: please correct this in setup.py", + nsp, + parent, ) @@ -305,9 +300,7 @@ def check_requirements(dist, attr, value): "{attr!r} must be a string or list of strings " "containing valid project/version requirement specifiers; {error}" ) - raise DistutilsSetupError( - tmpl.format(attr=attr, error=error) - ) from error + raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error def check_specifier(dist, attr, value): @@ -316,12 +309,9 @@ def check_specifier(dist, attr, value): packaging.specifiers.SpecifierSet(value) except (packaging.specifiers.InvalidSpecifier, AttributeError) as error: tmpl = ( - "{attr!r} must be a string " - "containing valid version specifiers; {error}" + "{attr!r} must be a string " "containing valid version specifiers; {error}" ) - raise DistutilsSetupError( - tmpl.format(attr=attr, error=error) - ) from error + raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error def check_entry_points(dist, attr, value): @@ -342,12 +332,12 @@ def check_package_data(dist, attr, value): if not isinstance(value, dict): raise DistutilsSetupError( "{!r} must be a dictionary mapping package names to lists of " - "string wildcard patterns".format(attr)) + "string wildcard patterns".format(attr) + ) for k, v in value.items(): if not isinstance(k, str): raise DistutilsSetupError( - "keys of {!r} dict must be strings (got {!r})" - .format(attr, k) + "keys of {!r} dict must be strings (got {!r})".format(attr, k) ) assert_string_list(dist, 'values of {!r} dict'.format(attr), v) @@ -357,7 +347,8 @@ def check_packages(dist, attr, value): if not re.match(r'\w+(\.\w+)*', pkgname): distutils.log.warn( "WARNING: %r not a valid package name; please use only " - ".-separated package names in setup.py", pkgname + ".-separated package names in setup.py", + pkgname, ) @@ -452,15 +443,20 @@ def __init__(self, attrs=None): self.setup_requires = attrs.pop('setup_requires', []) for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): vars(self).setdefault(ep.name, None) - _Distribution.__init__(self, { - k: v for k, v in attrs.items() - if k not in self._DISTUTILS_UNSUPPORTED_METADATA - }) + _Distribution.__init__( + self, + { + k: v + for k, v in attrs.items() + if k not in self._DISTUTILS_UNSUPPORTED_METADATA + }, + ) self._set_metadata_defaults(attrs) self.metadata.version = self._normalize_version( - self._validate_version(self.metadata.version)) + self._validate_version(self.metadata.version) + ) self._finalize_requires() def _set_metadata_defaults(self, attrs): @@ -596,7 +592,8 @@ def _finalize_license_files(self): patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') self.metadata.license_files = list( - unique_everseen(self._expand_patterns(patterns))) + unique_everseen(self._expand_patterns(patterns)) + ) @staticmethod def _expand_patterns(patterns): @@ -610,8 +607,7 @@ def _expand_patterns(patterns): path for pattern in patterns for path in sorted(iglob(pattern)) - if not path.endswith('~') - and os.path.isfile(path) + if not path.endswith('~') and os.path.isfile(path) ) # FIXME: 'Distribution._parse_config_files' is too complex (14) @@ -624,12 +620,25 @@ def _parse_config_files(self, filenames=None): # noqa: C901 from configparser import ConfigParser # Ignore install directory options if we have a venv - ignore_options = [] if sys.prefix == sys.base_prefix else [ - 'install-base', 'install-platbase', 'install-lib', - 'install-platlib', 'install-purelib', 'install-headers', - 'install-scripts', 'install-data', 'prefix', 'exec-prefix', - 'home', 'user', 'root', - ] + ignore_options = ( + [] + if sys.prefix == sys.base_prefix + else [ + 'install-base', + 'install-platbase', + 'install-lib', + 'install-platlib', + 'install-purelib', + 'install-headers', + 'install-scripts', + 'install-data', + 'prefix', + 'exec-prefix', + 'home', + 'user', + 'root', + ] + ) ignore_options = frozenset(ignore_options) @@ -683,21 +692,26 @@ def _parse_config_files(self, filenames=None): # noqa: C901 def warn_dash_deprecation(self, opt, section): if section in ( - 'options.extras_require', 'options.data_files', + 'options.extras_require', + 'options.data_files', ): return opt underscore_opt = opt.replace('-', '_') commands = distutils.command.__all__ + self._setuptools_commands() - if (not section.startswith('options') and section != 'metadata' - and section not in commands): + if ( + not section.startswith('options') + and section != 'metadata' + and section not in commands + ): return underscore_opt if '-' in opt: warnings.warn( "Usage of dash-separated '%s' will not be supported in future " "versions. Please use the underscore name '%s' instead" - % (opt, underscore_opt)) + % (opt, underscore_opt) + ) return underscore_opt def _setuptools_commands(self): @@ -741,11 +755,9 @@ def _set_command_options(self, command_obj, option_dict=None): # noqa: C901 self.announce(" setting options for '%s' command:" % command_name) for (option, (source, value)) in option_dict.items(): if DEBUG: - self.announce(" %s = %s (from %s)" % (option, value, - source)) + self.announce(" %s = %s (from %s)" % (option, value, source)) try: - bool_opts = [translate_longopt(o) - for o in command_obj.boolean_options] + bool_opts = [translate_longopt(o) for o in command_obj.boolean_options] except AttributeError: bool_opts = [] try: @@ -764,7 +776,8 @@ def _set_command_options(self, command_obj, option_dict=None): # noqa: C901 else: raise DistutilsOptionError( "error in %s: command '%s' has no such option '%s'" - % (source, command_name, option)) + % (source, command_name, option) + ) except ValueError as e: raise DistutilsOptionError(e) from e @@ -775,8 +788,9 @@ def parse_config_files(self, filenames=None, ignore_option_errors=False): """ self._parse_config_files(filenames=filenames) - parse_configuration(self, self.command_options, - ignore_option_errors=ignore_option_errors) + parse_configuration( + self, self.command_options, ignore_option_errors=ignore_option_errors + ) self._finalize_requires() self._finalize_license_files() @@ -802,6 +816,7 @@ def finalize_options(self): def by_order(hook): return getattr(hook, 'order', 0) + eps = map(lambda e: e.load(), pkg_resources.iter_entry_points(group)) for ep in sorted(eps, key=by_order): ep(self) @@ -817,8 +832,7 @@ def _finalize_2to3_doctests(self): if getattr(self, 'convert_2to3_doctests', None): # XXX may convert to set here when we can rely on set being builtin self.convert_2to3_doctests = [ - os.path.abspath(p) - for p in self.convert_2to3_doctests + os.path.abspath(p) for p in self.convert_2to3_doctests ] else: self.convert_2to3_doctests = [] @@ -830,10 +844,14 @@ def get_egg_cache_dir(self): windows_support.hide_file(egg_cache_dir) readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt') with open(readme_txt_filename, 'w') as f: - f.write('This directory contains eggs that were downloaded ' - 'by setuptools to build, test, and run plug-ins.\n\n') - f.write('This directory caches those eggs to prevent ' - 'repeated downloads.\n\n') + f.write( + 'This directory contains eggs that were downloaded ' + 'by setuptools to build, test, and run plug-ins.\n\n' + ) + f.write( + 'This directory caches those eggs to prevent ' + 'repeated downloads.\n\n' + ) f.write('However, it is safe to delete this directory.\n\n') return egg_cache_dir @@ -841,6 +859,7 @@ def get_egg_cache_dir(self): def fetch_build_egg(self, req): """Fetch an egg needed for building""" from setuptools.installer import fetch_build_egg + return fetch_build_egg(self, req) def get_command_class(self, command): @@ -900,19 +919,18 @@ def exclude_package(self, package): pfx = package + '.' if self.packages: self.packages = [ - p for p in self.packages - if p != package and not p.startswith(pfx) + p for p in self.packages if p != package and not p.startswith(pfx) ] if self.py_modules: self.py_modules = [ - p for p in self.py_modules - if p != package and not p.startswith(pfx) + p for p in self.py_modules if p != package and not p.startswith(pfx) ] if self.ext_modules: self.ext_modules = [ - p for p in self.ext_modules + p + for p in self.ext_modules if p.name != package and not p.name.startswith(pfx) ] @@ -934,9 +952,7 @@ def _exclude_misc(self, name, value): try: old = getattr(self, name) except AttributeError as e: - raise DistutilsSetupError( - "%s: No such distribution setting" % name - ) from e + raise DistutilsSetupError("%s: No such distribution setting" % name) from e if old is not None and not isinstance(old, sequence): raise DistutilsSetupError( name + ": this setting cannot be changed via include/exclude" @@ -948,15 +964,11 @@ def _include_misc(self, name, value): """Handle 'include()' for list/tuple attrs without a special handler""" if not isinstance(value, sequence): - raise DistutilsSetupError( - "%s: setting must be a list (%r)" % (name, value) - ) + raise DistutilsSetupError("%s: setting must be a list (%r)" % (name, value)) try: old = getattr(self, name) except AttributeError as e: - raise DistutilsSetupError( - "%s: No such distribution setting" % name - ) from e + raise DistutilsSetupError("%s: No such distribution setting" % name) from e if old is None: setattr(self, name, value) elif not isinstance(old, sequence): @@ -1009,6 +1021,7 @@ def _parse_command_opts(self, parser, args): src, alias = aliases[command] del aliases[command] # ensure each alias can expand only once! import shlex + args[:1] = shlex.split(alias, True) command = args[0] @@ -1108,12 +1121,14 @@ def handle_display_options(self, option_order): line_buffering = sys.stdout.line_buffering sys.stdout = io.TextIOWrapper( - sys.stdout.detach(), 'utf-8', errors, newline, line_buffering) + sys.stdout.detach(), 'utf-8', errors, newline, line_buffering + ) try: return _Distribution.handle_display_options(self, option_order) finally: sys.stdout = io.TextIOWrapper( - sys.stdout.detach(), encoding, errors, newline, line_buffering) + sys.stdout.detach(), encoding, errors, newline, line_buffering + ) class DistDeprecationWarning(SetuptoolsDeprecationWarning): diff --git a/setuptools/extern/__init__.py b/setuptools/extern/__init__.py index baca1afabe9..a83df517d06 100644 --- a/setuptools/extern/__init__.py +++ b/setuptools/extern/__init__.py @@ -58,7 +58,8 @@ def find_spec(self, fullname, path=None, target=None): """Return a module spec for vendored names.""" return ( importlib.util.spec_from_loader(fullname, self) - if self._module_matches_namespace(fullname) else None + if self._module_matches_namespace(fullname) + else None ) def install(self): @@ -69,5 +70,10 @@ def install(self): sys.meta_path.append(self) -names = 'packaging', 'pyparsing', 'ordered_set', 'more_itertools', +names = ( + 'packaging', + 'pyparsing', + 'ordered_set', + 'more_itertools', +) VendorImporter(__name__, names, 'setuptools._vendor').install() diff --git a/setuptools/glob.py b/setuptools/glob.py index 87062b8187f..647b9bc6ed2 100644 --- a/setuptools/glob.py +++ b/setuptools/glob.py @@ -155,8 +155,7 @@ def _isrecursive(pattern): def escape(pathname): - """Escape all special characters. - """ + """Escape all special characters.""" # Escaping is done by wrapping any of "*?[" between square brackets. # Metacharacters do not work in the drive part and shouldn't be escaped. drive, pathname = os.path.splitdrive(pathname) diff --git a/setuptools/installer.py b/setuptools/installer.py index 57e2b587aae..13965282632 100644 --- a/setuptools/installer.py +++ b/setuptools/installer.py @@ -34,8 +34,10 @@ def fetch_build_egg(dist, req): # noqa: C901 # is too complex (16) # FIXME # take precedence. opts = dist.get_option_dict('easy_install') if 'allow_hosts' in opts: - raise DistutilsError('the `allow-hosts` option is not supported ' - 'when using pip to install requirements.') + raise DistutilsError( + 'the `allow-hosts` option is not supported ' + 'when using pip to install requirements.' + ) quiet = 'PIP_QUIET' not in os.environ and 'PIP_VERBOSE' not in os.environ if 'PIP_INDEX_URL' in os.environ: index_url = None @@ -44,8 +46,7 @@ def fetch_build_egg(dist, req): # noqa: C901 # is too complex (16) # FIXME else: index_url = None find_links = ( - _fixup_find_links(opts['find_links'][1])[:] if 'find_links' in opts - else [] + _fixup_find_links(opts['find_links'][1])[:] if 'find_links' in opts else [] ) if dist.dependency_links: find_links.extend(dist.dependency_links) @@ -56,10 +57,14 @@ def fetch_build_egg(dist, req): # noqa: C901 # is too complex (16) # FIXME return egg_dist with tempfile.TemporaryDirectory() as tmpdir: cmd = [ - sys.executable, '-m', 'pip', + sys.executable, + '-m', + 'pip', '--disable-pip-version-check', - 'wheel', '--no-deps', - '-w', tmpdir, + 'wheel', + '--no-deps', + '-w', + tmpdir, ] if quiet: cmd.append('--quiet') @@ -79,9 +84,11 @@ def fetch_build_egg(dist, req): # noqa: C901 # is too complex (16) # FIXME dist_location = os.path.join(eggs_dir, wheel.egg_name()) wheel.install_as_egg(dist_location) dist_metadata = pkg_resources.PathMetadata( - dist_location, os.path.join(dist_location, 'EGG-INFO')) + dist_location, os.path.join(dist_location, 'EGG-INFO') + ) dist = pkg_resources.Distribution.from_filename( - dist_location, metadata=dist_metadata) + dist_location, metadata=dist_metadata + ) return dist diff --git a/setuptools/lib2to3_ex.py b/setuptools/lib2to3_ex.py index c176abf6334..d003671ad04 100644 --- a/setuptools/lib2to3_ex.py +++ b/setuptools/lib2to3_ex.py @@ -38,7 +38,8 @@ def run_2to3(self, files, doctests=False): "requires Python 2 support, please migrate to " "a single-codebase solution or employ an " "independent conversion process.", - SetuptoolsDeprecationWarning) + SetuptoolsDeprecationWarning, + ) log.info("Fixing " + " ".join(files)) self.__build_fixer_names() self.__exclude_fixers() diff --git a/setuptools/monkey.py b/setuptools/monkey.py index fb36dc1a97a..99dbe98cd1f 100644 --- a/setuptools/monkey.py +++ b/setuptools/monkey.py @@ -35,9 +35,11 @@ def _get_mro(cls): def get_unpatched(item): lookup = ( - get_unpatched_class if isinstance(item, type) else - get_unpatched_function if isinstance(item, types.FunctionType) else - lambda item: None + get_unpatched_class + if isinstance(item, type) + else get_unpatched_function + if isinstance(item, types.FunctionType) + else lambda item: None ) return lookup(item) @@ -49,9 +51,7 @@ def get_unpatched_class(cls): first. """ external_bases = ( - cls - for cls in _get_mro(cls) - if not cls.__module__.startswith('setuptools') + cls for cls in _get_mro(cls) if not cls.__module__.startswith('setuptools') ) base = next(external_bases) if not base.__module__.startswith('distutils'): @@ -72,10 +72,8 @@ def patch_all(): needs_warehouse = ( sys.version_info < (2, 7, 13) - or - (3, 4) < sys.version_info < (3, 4, 6) - or - (3, 5) < sys.version_info <= (3, 5, 3) + or (3, 4) < sys.version_info < (3, 4, 6) + or (3, 5) < sys.version_info <= (3, 5, 3) ) if needs_warehouse: @@ -92,9 +90,9 @@ def patch_all(): distutils.core.Extension = setuptools.extension.Extension distutils.extension.Extension = setuptools.extension.Extension if 'distutils.command.build_ext' in sys.modules: - sys.modules['distutils.command.build_ext'].Extension = ( - setuptools.extension.Extension - ) + sys.modules[ + 'distutils.command.build_ext' + ].Extension = setuptools.extension.Extension patch_for_msvc_specialized_compiler() diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 281ea1c2af6..ed66c4381d2 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -51,7 +51,6 @@ class winreg: _msvc9_suppress_errors = ( # msvc9compiler isn't available on some platforms ImportError, - # msvc9compiler raises DistutilsPlatformError in some # environments. See #1118. distutils.errors.DistutilsPlatformError, @@ -150,7 +149,7 @@ def _msvc14_find_vc2015(): winreg.HKEY_LOCAL_MACHINE, r"Software\Microsoft\VisualStudio\SxS\VC7", 0, - winreg.KEY_READ | winreg.KEY_WOW64_32KEY + winreg.KEY_READ | winreg.KEY_WOW64_32KEY, ) except OSError: return None, None @@ -190,16 +189,26 @@ def _msvc14_find_vc2017(): return None, None try: - path = subprocess.check_output([ - join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), - "-latest", - "-prerelease", - "-requiresAny", - "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", - "-requires", "Microsoft.VisualStudio.Workload.WDExpress", - "-property", "installationPath", - "-products", "*", - ]).decode(encoding="mbcs", errors="strict").strip() + path = ( + subprocess.check_output( + [ + join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), + "-latest", + "-prerelease", + "-requiresAny", + "-requires", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-requires", + "Microsoft.VisualStudio.Workload.WDExpress", + "-property", + "installationPath", + "-products", + "*", + ] + ) + .decode(encoding="mbcs", errors="strict") + .strip() + ) except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): return None, None @@ -214,7 +223,7 @@ def _msvc14_find_vc2017(): 'x86': 'x86', 'x86_amd64': 'x64', 'x86_arm': 'arm', - 'x86_arm64': 'arm64' + 'x86_arm64': 'arm64', } @@ -229,11 +238,20 @@ def _msvc14_find_vcvarsall(plat_spec): vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86' if best_dir: - vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**", - vcruntime_plat, "Microsoft.VC14*.CRT", - "vcruntime140.dll") + vcredist = join( + best_dir, + "..", + "..", + "redist", + "MSVC", + "**", + vcruntime_plat, + "Microsoft.VC14*.CRT", + "vcruntime140.dll", + ) try: import glob + vcruntime = glob.glob(vcredist, recursive=True)[-1] except (ImportError, OSError, LookupError): vcruntime = None @@ -241,8 +259,13 @@ def _msvc14_find_vcvarsall(plat_spec): if not best_dir: best_version, best_dir = _msvc14_find_vc2015() if best_version: - vcruntime = join(best_dir, 'redist', vcruntime_plat, - "Microsoft.VC140.CRT", "vcruntime140.dll") + vcruntime = join( + best_dir, + 'redist', + vcruntime_plat, + "Microsoft.VC140.CRT", + "vcruntime140.dll", + ) if not best_dir: return None, None @@ -260,16 +283,11 @@ def _msvc14_find_vcvarsall(plat_spec): def _msvc14_get_vc_env(plat_spec): """Python 3.8 "distutils/_msvccompiler.py" backport""" if "DISTUTILS_USE_SDK" in environ: - return { - key.lower(): value - for key, value in environ.items() - } + return {key.lower(): value for key, value in environ.items()} vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec) if not vcvarsall: - raise distutils.errors.DistutilsPlatformError( - "Unable to find vcvarsall.bat" - ) + raise distutils.errors.DistutilsPlatformError("Unable to find vcvarsall.bat") try: out = subprocess.check_output( @@ -283,8 +301,7 @@ def _msvc14_get_vc_env(plat_spec): env = { key.lower(): value - for key, _, value in - (line.partition('=') for line in out.splitlines()) + for key, _, value in (line.partition('=') for line in out.splitlines()) if key and value } @@ -327,6 +344,7 @@ def msvc14_gen_lib_options(*args, **kwargs): """ if "numpy.distutils" in sys.modules: import numpy as np + if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs) @@ -362,11 +380,13 @@ def _augment_exception(exc, version, arch=''): message += msdownload % 8279 elif version >= 14.0: # For VC++ 14.X Redirect user to latest Visual C++ Build Tools - message += (' Get it with "Microsoft C++ Build Tools": ' - r'https://visualstudio.microsoft.com' - r'/visual-cpp-build-tools/') + message += ( + ' Get it with "Microsoft C++ Build Tools": ' + r'https://visualstudio.microsoft.com' + r'/visual-cpp-build-tools/' + ) - exc.args = (message, ) + exc.args = (message,) class PlatformInfo: @@ -378,6 +398,7 @@ class PlatformInfo: arch: str Target architecture. """ + current_cpu = environ.get('processor_architecture', '').lower() def __init__(self, arch): @@ -393,7 +414,7 @@ def target_cpu(self): str Target CPU """ - return self.arch[self.arch.find('_') + 1:] + return self.arch[self.arch.find('_') + 1 :] def target_is_x86(self): """ @@ -434,9 +455,11 @@ def current_dir(self, hidex86=False, x64=False): subfolder: '\target', or '' (see hidex86 parameter) """ return ( - '' if (self.current_cpu == 'x86' and hidex86) else - r'\x64' if (self.current_cpu == 'amd64' and x64) else - r'\%s' % self.current_cpu + '' + if (self.current_cpu == 'x86' and hidex86) + else r'\x64' + if (self.current_cpu == 'amd64' and x64) + else r'\%s' % self.current_cpu ) def target_dir(self, hidex86=False, x64=False): @@ -456,9 +479,11 @@ def target_dir(self, hidex86=False, x64=False): subfolder: '\current', or '' (see hidex86 parameter) """ return ( - '' if (self.target_cpu == 'x86' and hidex86) else - r'\x64' if (self.target_cpu == 'amd64' and x64) else - r'\%s' % self.target_cpu + '' + if (self.target_cpu == 'x86' and hidex86) + else r'\x64' + if (self.target_cpu == 'amd64' and x64) + else r'\%s' % self.target_cpu ) def cross_dir(self, forcex86=False): @@ -479,8 +504,9 @@ def cross_dir(self, forcex86=False): """ current = 'x86' if forcex86 else self.current_cpu return ( - '' if self.target_cpu == current else - self.target_dir().replace('\\', '\\%s_' % current) + '' + if self.target_cpu == current + else self.target_dir().replace('\\', '\\%s_' % current) ) @@ -493,10 +519,13 @@ class RegistryInfo: platform_info: PlatformInfo "PlatformInfo" instance. """ - HKEYS = (winreg.HKEY_USERS, - winreg.HKEY_CURRENT_USER, - winreg.HKEY_LOCAL_MACHINE, - winreg.HKEY_CLASSES_ROOT) + + HKEYS = ( + winreg.HKEY_USERS, + winreg.HKEY_CURRENT_USER, + winreg.HKEY_LOCAL_MACHINE, + winreg.HKEY_CLASSES_ROOT, + ) def __init__(self, platform_info): self.pi = platform_info @@ -694,8 +723,7 @@ def __init__(self, registry_info, vc_ver=None): self.known_vs_paths = self.find_programdata_vs_vers() # Except for VS15+, VC version is aligned with VS version - self.vs_ver = self.vc_ver = ( - vc_ver or self._find_latest_available_vs_ver()) + self.vs_ver = self.vc_ver = vc_ver or self._find_latest_available_vs_ver() def _find_latest_available_vs_ver(self): """ @@ -710,7 +738,8 @@ def _find_latest_available_vs_ver(self): if not (reg_vc_vers or self.known_vs_paths): raise distutils.errors.DistutilsPlatformError( - 'No Microsoft Visual C++ version found') + 'No Microsoft Visual C++ version found' + ) vc_vers = set(reg_vc_vers) vc_vers.update(self.known_vs_paths) @@ -758,8 +787,7 @@ def find_programdata_vs_vers(self): float version as key, path as value. """ vs_versions = {} - instances_dir = \ - r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances' + instances_dir = r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances' try: hashed_names = listdir(instances_dir) @@ -780,8 +808,9 @@ def find_programdata_vs_vers(self): listdir(join(vs_path, r'VC\Tools\MSVC')) # Store version and path - vs_versions[self._as_float_version( - state['installationVersion'])] = vs_path + vs_versions[ + self._as_float_version(state['installationVersion']) + ] = vs_path except (OSError, IOError, KeyError): # Skip if "state.json" file is missing or bad format @@ -817,8 +846,9 @@ def VSInstallDir(self): path """ # Default path - default = join(self.ProgramFilesx86, - 'Microsoft Visual Studio %0.1f' % self.vs_ver) + default = join( + self.ProgramFilesx86, 'Microsoft Visual Studio %0.1f' % self.vs_ver + ) # Try to get path from registry, if fail use default path return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default @@ -880,8 +910,9 @@ def _guess_vc_legacy(self): str path """ - default = join(self.ProgramFilesx86, - r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver) + default = join( + self.ProgramFilesx86, r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver + ) # Try to get "VC++ for Python" path from registry as default path reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver) @@ -950,7 +981,7 @@ def WindowsSdkDir(self): # noqa: C901 # is too complex (12) # FIXME if not sdkdir or not isdir(sdkdir): # If fail, use default new path for ver in self.WindowsSdkVersion: - intver = ver[:ver.rfind('.')] + intver = ver[: ver.rfind('.')] path = r'Microsoft SDKs\Windows Kits\%s' % intver d = join(self.ProgramFiles, path) if isdir(d): @@ -1030,8 +1061,7 @@ def UniversalCRTSdkDir(self): # Find path of the more recent Kit for ver in vers: - sdkdir = self.ri.lookup(self.ri.windows_kits_roots, - 'kitsroot%s' % ver) + sdkdir = self.ri.lookup(self.ri.windows_kits_roots, 'kitsroot%s' % ver) if sdkdir: return sdkdir or '' @@ -1058,10 +1088,11 @@ def NetFxSdkVersion(self): versions """ # Set FxSdk versions for specified VS version - return (('4.7.2', '4.7.1', '4.7', - '4.6.2', '4.6.1', '4.6', - '4.5.2', '4.5.1', '4.5') - if self.vs_ver >= 14.0 else ()) + return ( + ('4.7.2', '4.7.1', '4.7', '4.6.2', '4.6.1', '4.6', '4.5.2', '4.5.1', '4.5') + if self.vs_ver >= 14.0 + else () + ) @property def NetFxSdkDir(self): @@ -1186,8 +1217,7 @@ def _use_last_dir_name(path, prefix=''): matching_dirs = ( dir_name for dir_name in reversed(listdir(path)) - if isdir(join(path, dir_name)) and - dir_name.startswith(prefix) + if isdir(join(path, dir_name)) and dir_name.startswith(prefix) ) return next(matching_dirs, None) or '' @@ -1279,8 +1309,10 @@ def VCIncludes(self): list of str paths """ - return [join(self.si.VCInstallDir, 'Include'), - join(self.si.VCInstallDir, r'ATLMFC\Include')] + return [ + join(self.si.VCInstallDir, 'Include'), + join(self.si.VCInstallDir, r'ATLMFC\Include'), + ] @property def VCLibraries(self): @@ -1340,14 +1372,15 @@ def VCTools(self): tools += [join(si.VCInstallDir, path)] elif self.vs_ver >= 15.0: - host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else - r'bin\HostX64%s') - tools += [join( - si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] + host_dir = ( + r'bin\HostX86%s' if self.pi.current_is_x86() else r'bin\HostX64%s' + ) + tools += [join(si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] if self.pi.current_cpu != self.pi.target_cpu: - tools += [join( - si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))] + tools += [ + join(si.VCInstallDir, host_dir % self.pi.current_dir(x64=True)) + ] else: tools += [join(si.VCInstallDir, 'Bin')] @@ -1394,9 +1427,11 @@ def OSIncludes(self): sdkver = self._sdk_subdir else: sdkver = '' - return [join(include, '%sshared' % sdkver), - join(include, '%sum' % sdkver), - join(include, '%swinrt' % sdkver)] + return [ + join(include, '%sshared' % sdkver), + join(include, '%sum' % sdkver), + join(include, '%swinrt' % sdkver), + ] @property def OSLibpath(self): @@ -1421,16 +1456,18 @@ def OSLibpath(self): libpath += [ ref, join(self.si.WindowsSdkDir, 'UnionMetadata'), - join( - ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), + join(ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'), + join(ref, 'Windows.Networking.Connectivity.WwanContract', '1.0.0.0'), join( - ref, 'Windows.Networking.Connectivity.WwanContract', - '1.0.0.0'), - join( - self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs', - '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration', - 'neutral'), + self.si.WindowsSdkDir, + 'ExtensionSDKs', + 'Microsoft.VCLibs', + '%0.1f' % self.vs_ver, + 'References', + 'CommonConfiguration', + 'neutral', + ), ] return libpath @@ -1531,11 +1568,9 @@ def FxTools(self): tools = [] if include32: - tools += [join(si.FrameworkDir32, ver) - for ver in si.FrameworkVersion32] + tools += [join(si.FrameworkDir32, ver) for ver in si.FrameworkVersion32] if include64: - tools += [join(si.FrameworkDir64, ver) - for ver in si.FrameworkVersion64] + tools += [join(si.FrameworkDir64, ver) for ver in si.FrameworkVersion64] return tools @property @@ -1711,9 +1746,11 @@ def VCRuntimeRedist(self): prefixes += [join(tools_path, 'redist')] # VS14 legacy path # CRT directory - crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10), - # Sometime store in directory with VS version instead of VC - 'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10)) + crt_dirs = ( + 'Microsoft.VC%d.CRT' % (self.vc_ver * 10), + # Sometime store in directory with VS version instead of VC + 'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10), + ) # vcruntime path for prefix, crt_dir in itertools.product(prefixes, crt_dirs): @@ -1736,36 +1773,47 @@ def return_env(self, exists=True): environment """ env = dict( - include=self._build_paths('include', - [self.VCIncludes, - self.OSIncludes, - self.UCRTIncludes, - self.NetFxSDKIncludes], - exists), - lib=self._build_paths('lib', - [self.VCLibraries, - self.OSLibraries, - self.FxTools, - self.UCRTLibraries, - self.NetFxSDKLibraries], - exists), - libpath=self._build_paths('libpath', - [self.VCLibraries, - self.FxTools, - self.VCStoreRefs, - self.OSLibpath], - exists), - path=self._build_paths('path', - [self.VCTools, - self.VSTools, - self.VsTDb, - self.SdkTools, - self.SdkSetup, - self.FxTools, - self.MSBuild, - self.HTMLHelpWorkshop, - self.FSharp], - exists), + include=self._build_paths( + 'include', + [ + self.VCIncludes, + self.OSIncludes, + self.UCRTIncludes, + self.NetFxSDKIncludes, + ], + exists, + ), + lib=self._build_paths( + 'lib', + [ + self.VCLibraries, + self.OSLibraries, + self.FxTools, + self.UCRTLibraries, + self.NetFxSDKLibraries, + ], + exists, + ), + libpath=self._build_paths( + 'libpath', + [self.VCLibraries, self.FxTools, self.VCStoreRefs, self.OSLibpath], + exists, + ), + path=self._build_paths( + 'path', + [ + self.VCTools, + self.VSTools, + self.VsTDb, + self.SdkTools, + self.SdkSetup, + self.FxTools, + self.MSBuild, + self.HTMLHelpWorkshop, + self.FSharp, + ], + exists, + ), ) if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist): env['py_vcruntime_redist'] = self.VCRuntimeRedist diff --git a/setuptools/namespaces.py b/setuptools/namespaces.py index 44939e1c6d4..04a9f4919e7 100644 --- a/setuptools/namespaces.py +++ b/setuptools/namespaces.py @@ -52,18 +52,13 @@ def _get_target(self): "importlib.machinery.PathFinder.find_spec(%(pkg)r, " "[os.path.dirname(p)])))" ), - ( - "m = m or " - "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))" - ), + ("m = m or " "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))"), "mp = (m or []) and m.__dict__.setdefault('__path__',[])", "(p not in mp) and mp.append(p)", ) "lines for the namespace installer" - _nspkg_tmpl_multi = ( - 'm and setattr(sys.modules[%(parent)r], %(child)r, m)', - ) + _nspkg_tmpl_multi = ('m and setattr(sys.modules[%(parent)r], %(child)r, m)',) "additional line(s) when a parent package is indicated" def _get_root(self): diff --git a/setuptools/package_index.py b/setuptools/package_index.py index d818f44ade0..800bfcde4a2 100644 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -19,9 +19,19 @@ import setuptools from pkg_resources import ( - CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST, - Environment, find_distributions, safe_name, safe_version, - to_filename, Requirement, DEVELOP_DIST, EGG_DIST, + CHECKOUT_DIST, + Distribution, + BINARY_DIST, + normalize_path, + SOURCE_DIST, + Environment, + find_distributions, + safe_name, + safe_version, + to_filename, + Requirement, + DEVELOP_DIST, + EGG_DIST, ) from distutils import log from distutils.errors import DistutilsError @@ -40,7 +50,9 @@ EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split() __all__ = [ - 'PackageIndex', 'distros_for_url', 'parse_bdist_wininst', + 'PackageIndex', + 'distros_for_url', + 'parse_bdist_wininst', 'interpret_distro_name', ] @@ -48,7 +60,8 @@ _tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}" user_agent = _tmpl.format( - py_major='{}.{}'.format(*sys.version_info), setuptools=setuptools) + py_major='{}.{}'.format(*sys.version_info), setuptools=setuptools +) def parse_requirement_arg(spec): @@ -120,13 +133,15 @@ def distros_for_location(location, basename, metadata=None): wheel = Wheel(basename) if not wheel.is_compatible(): return [] - return [Distribution( - location=location, - project_name=wheel.project_name, - version=wheel.version, - # Increase priority over eggs. - precedence=EGG_DIST + 1, - )] + return [ + Distribution( + location=location, + project_name=wheel.project_name, + version=wheel.version, + # Increase priority over eggs. + precedence=EGG_DIST + 1, + ) + ] if basename.endswith('.exe'): win_base, py_ver, platform = parse_bdist_wininst(basename) if win_base is not None: @@ -137,7 +152,7 @@ def distros_for_location(location, basename, metadata=None): # for ext in EXTENSIONS: if basename.endswith(ext): - basename = basename[:-len(ext)] + basename = basename[: -len(ext)] return interpret_distro_name(location, basename, metadata) return [] # no extension matched @@ -150,8 +165,7 @@ def distros_for_filename(filename, metadata=None): def interpret_distro_name( - location, basename, metadata, py_version=None, precedence=SOURCE_DIST, - platform=None + location, basename, metadata, py_version=None, precedence=SOURCE_DIST, platform=None ): """Generate alternative interpretations of a source distro name @@ -178,9 +192,13 @@ def interpret_distro_name( for p in range(1, len(parts) + 1): yield Distribution( - location, metadata, '-'.join(parts[:p]), '-'.join(parts[p:]), - py_version=py_version, precedence=precedence, - platform=platform + location, + metadata, + '-'.join(parts[:p]), + '-'.join(parts[p:]), + py_version=py_version, + precedence=precedence, + platform=platform, ) @@ -282,11 +300,16 @@ class PackageIndex(Environment): """A distribution index that scans web pages for download URLs""" def __init__( - self, index_url="https://pypi.org/simple/", hosts=('*',), - ca_bundle=None, verify_ssl=True, *args, **kw + self, + index_url="https://pypi.org/simple/", + hosts=('*',), + ca_bundle=None, + verify_ssl=True, + *args, + **kw ): Environment.__init__(self, *args, **kw) - self.index_url = index_url + "/" [:not index_url.endswith('/')] + self.index_url = index_url + "/"[: not index_url.endswith('/')] self.scanned_urls = {} self.fetched_urls = {} self.package_pages = {} @@ -371,7 +394,8 @@ def url_ok(self, url, fatal=False): return True msg = ( "\nNote: Bypassing %s (disallowed host; see " - "http://bit.ly/2hrImnY for details).\n") + "http://bit.ly/2hrImnY for details).\n" + ) if fatal: raise DistutilsError(msg % url) else: @@ -409,9 +433,7 @@ def _scan(self, link): if not link.startswith(self.index_url): return NO_MATCH_SENTINEL - parts = list(map( - urllib.parse.unquote, link[len(self.index_url):].split('/') - )) + parts = list(map(urllib.parse.unquote, link[len(self.index_url) :].split('/'))) if len(parts) != 2 or '#' in parts[1]: return NO_MATCH_SENTINEL @@ -453,16 +475,15 @@ def process_index(self, url, page): def need_version_info(self, url): self.scan_all( "Page at %s links to .py file(s) without version info; an index " - "scan is required.", url + "scan is required.", + url, ) def scan_all(self, msg=None, *args): if self.index_url not in self.fetched_urls: if msg: self.warn(msg, *args) - self.info( - "Scanning index of all packages (this may take a while)" - ) + self.info("Scanning index of all packages (this may take a while)") self.scan_url(self.index_url) def find_packages(self, requirement): @@ -493,9 +514,7 @@ def check_hash(self, checker, filename, tfp): """ checker is a ContentChecker """ - checker.report( - self.debug, - "Validating %%s checksum for %s" % filename) + checker.report(self.debug, "Validating %%s checksum for %s" % filename) if not checker.is_valid(): tfp.close() os.unlink(filename) @@ -532,7 +551,8 @@ def not_found_in_index(self, requirement): else: # no distros seen for this name, might be misspelled meth, msg = ( self.warn, - "Couldn't find index page for %r (maybe misspelled?)") + "Couldn't find index page for %r (maybe misspelled?)", + ) meth(msg, requirement.unsafe_name) self.scan_all() @@ -571,8 +591,14 @@ def download(self, spec, tmpdir): return getattr(self.fetch_distribution(spec, tmpdir), 'location', None) def fetch_distribution( # noqa: C901 # is too complex (14) # FIXME - self, requirement, tmpdir, force_scan=False, source=False, - develop_ok=False, local_index=None): + self, + requirement, + tmpdir, + force_scan=False, + source=False, + develop_ok=False, + local_index=None, + ): """Obtain a distribution suitable for fulfilling `requirement` `requirement` must be a ``pkg_resources.Requirement`` instance. @@ -604,15 +630,13 @@ def find(req, env=None): if dist.precedence == DEVELOP_DIST and not develop_ok: if dist not in skipped: self.warn( - "Skipping development or system egg: %s", dist, + "Skipping development or system egg: %s", + dist, ) skipped[dist] = 1 continue - test = ( - dist in req - and (dist.precedence <= SOURCE_DIST or not source) - ) + test = dist in req and (dist.precedence <= SOURCE_DIST or not source) if test: loc = self.download(dist.location, tmpdir) dist.download_location = loc @@ -661,10 +685,15 @@ def fetch(self, requirement, tmpdir, force_scan=False, source=False): def gen_setup(self, filename, fragment, tmpdir): match = EGG_FRAGMENT.match(fragment) - dists = match and [ - d for d in - interpret_distro_name(filename, match.group(1), None) if d.version - ] or [] + dists = ( + match + and [ + d + for d in interpret_distro_name(filename, match.group(1), None) + if d.version + ] + or [] + ) if len(dists) == 1: # unambiguous ``#egg`` fragment basename = os.path.basename(filename) @@ -673,6 +702,7 @@ def gen_setup(self, filename, fragment, tmpdir): if os.path.dirname(filename) != tmpdir: dst = os.path.join(tmpdir, basename) from setuptools.command.easy_install import samefile + if not samefile(filename, dst): shutil.copy2(filename, dst) filename = dst @@ -682,8 +712,9 @@ def gen_setup(self, filename, fragment, tmpdir): "from setuptools import setup\n" "setup(name=%r, version=%r, py_modules=[%r])\n" % ( - dists[0].project_name, dists[0].version, - os.path.splitext(basename)[0] + dists[0].project_name, + dists[0].version, + os.path.splitext(basename)[0], ) ) return filename @@ -759,23 +790,22 @@ def open_url(self, url, warning=None): # noqa: C901 # is too complex (12) if warning: self.warn(warning, v.reason) else: - raise DistutilsError("Download error for %s: %s" - % (url, v.reason)) from v + raise DistutilsError( + "Download error for %s: %s" % (url, v.reason) + ) from v except http.client.BadStatusLine as v: if warning: self.warn(warning, v.line) else: raise DistutilsError( '%s returned a bad status line. The server might be ' - 'down, %s' % - (url, v.line) + 'down, %s' % (url, v.line) ) from v except (http.client.HTTPException, socket.error) as v: if warning: self.warn(warning, v) else: - raise DistutilsError("Download error for %s: %s" - % (url, v)) from v + raise DistutilsError("Download error for %s: %s" % (url, v)) from v def _download_url(self, scheme, url, tmpdir): # Determine download filename @@ -880,10 +910,13 @@ def _download_git(self, url, filename): if rev is not None: self.info("Checking out %s", rev) - os.system("git -C %s checkout --quiet %s" % ( - filename, - rev, - )) + os.system( + "git -C %s checkout --quiet %s" + % ( + filename, + rev, + ) + ) return filename @@ -896,10 +929,13 @@ def _download_hg(self, url, filename): if rev is not None: self.info("Updating to %s", rev) - os.system("hg --cwd %s up -C -r %s -q" % ( - filename, - rev, - )) + os.system( + "hg --cwd %s up -C -r %s -q" + % ( + filename, + rev, + ) + ) return filename @@ -1003,7 +1039,8 @@ def __init__(self): @property def creds_by_repository(self): sections_with_repositories = [ - section for section in self.sections() + section + for section in self.sections() if self.get(section, 'repository').strip() ] @@ -1107,8 +1144,8 @@ def local_open(url): files.append('{name}'.format(name=f)) else: tmpl = ( - "{url}" - "{files}") + "{url}" "{files}" + ) body = tmpl.format(url=url, files='\n'.join(files)) status, message = 200, "OK" else: diff --git a/setuptools/py34compat.py b/setuptools/py34compat.py index 3ad917222a4..6b54d94d527 100644 --- a/setuptools/py34compat.py +++ b/setuptools/py34compat.py @@ -9,5 +9,6 @@ try: module_from_spec = importlib.util.module_from_spec except AttributeError: + def module_from_spec(spec): return spec.loader.load_module(spec.name) diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 91b960d899c..01853c85776 100644 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py @@ -26,7 +26,10 @@ __all__ = [ - "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", + "AbstractSandbox", + "DirectorySandbox", + "SandboxViolation", + "run_setup", ] @@ -106,6 +109,7 @@ def dump(type, exc): except Exception: # get UnpickleableException inside the sandbox from setuptools.sandbox import UnpickleableException as cls + return cls.dump(cls, cls(repr(exc))) @@ -154,7 +158,8 @@ def save_modules(): sys.modules.update(saved) # remove any modules imported since del_modules = ( - mod_name for mod_name in sys.modules + mod_name + for mod_name in sys.modules if mod_name not in saved # exclude any encodings modules. See #285 and not mod_name.startswith('encodings.') @@ -265,7 +270,8 @@ class AbstractSandbox: def __init__(self): self._attrs = [ - name for name in dir(_os) + name + for name in dir(_os) if not name.startswith('_') and hasattr(self, name) ] @@ -320,9 +326,25 @@ def wrap(self, path, *args, **kw): _file = _mk_single_path_wrapper('file', _file) _open = _mk_single_path_wrapper('open', _open) for name in [ - "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", - "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", - "startfile", "mkfifo", "mknod", "pathconf", "access" + "stat", + "listdir", + "chdir", + "open", + "chmod", + "chown", + "mkdir", + "remove", + "unlink", + "rmdir", + "utime", + "lchown", + "chroot", + "lstat", + "startfile", + "mkfifo", + "mknod", + "pathconf", + "access", ]: if hasattr(_os, name): locals()[name] = _mk_single_path_wrapper(name) @@ -373,7 +395,7 @@ def _remap_pair(self, operation, src, dst, *args, **kw): """Called for path pairs like rename, link, and symlink operations""" return ( self._remap_input(operation + '-from', src, *args, **kw), - self._remap_input(operation + '-to', dst, *args, **kw) + self._remap_input(operation + '-to', dst, *args, **kw), ) @@ -386,10 +408,23 @@ def _remap_pair(self, operation, src, dst, *args, **kw): class DirectorySandbox(AbstractSandbox): """Restrict operations to a single subdirectory - pseudo-chroot""" - write_ops = dict.fromkeys([ - "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", - "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam", - ]) + write_ops = dict.fromkeys( + [ + "open", + "chmod", + "chown", + "mkdir", + "remove", + "unlink", + "rmdir", + "utime", + "lchown", + "chroot", + "mkfifo", + "mknod", + "tempnam", + ] + ) _exception_patterns = [ # Allow lib2to3 to attempt to save a pickled grammar object (#121) @@ -401,13 +436,13 @@ def __init__(self, sandbox, exceptions=_EXCEPTIONS): self._sandbox = os.path.normcase(os.path.realpath(sandbox)) self._prefix = os.path.join(self._sandbox, '') self._exceptions = [ - os.path.normcase(os.path.realpath(path)) - for path in exceptions + os.path.normcase(os.path.realpath(path)) for path in exceptions ] AbstractSandbox.__init__(self) def _violation(self, operation, *args, **kw): from setuptools.sandbox import SandboxViolation + raise SandboxViolation(operation, args, kw) if _file: @@ -440,12 +475,10 @@ def _ok(self, path): def _exempted(self, filepath): start_matches = ( - filepath.startswith(exception) - for exception in self._exceptions + filepath.startswith(exception) for exception in self._exceptions ) pattern_matches = ( - re.match(pattern, filepath) - for pattern in self._exception_patterns + re.match(pattern, filepath) for pattern in self._exception_patterns ) candidates = itertools.chain(start_matches, pattern_matches) return any(candidates) @@ -470,16 +503,19 @@ def open(self, file, flags, mode=0o777, *args, **kw): WRITE_FLAGS = functools.reduce( - operator.or_, [ - getattr(_os, a, 0) for a in - "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()] + operator.or_, + [ + getattr(_os, a, 0) + for a in "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split() + ], ) class SandboxViolation(DistutilsError): """A setup script attempted to modify the filesystem outside the sandbox""" - tmpl = textwrap.dedent(""" + tmpl = textwrap.dedent( + """ SandboxViolation: {cmd}{args!r} {kwargs} The package setup script has attempted to modify files on your system @@ -489,7 +525,8 @@ class SandboxViolation(DistutilsError): support alternate installation locations even if you run its setup script by hand. Please inform the package's author and the EasyInstall maintainers to find out if a fix or workaround is available. - """).lstrip() + """ + ).lstrip() def __str__(self): cmd, args, kwargs = self.args diff --git a/setuptools/tests/contexts.py b/setuptools/tests/contexts.py index 51ce8984e04..e5d4a171f96 100644 --- a/setuptools/tests/contexts.py +++ b/setuptools/tests/contexts.py @@ -27,11 +27,7 @@ def environment(**replacements): In a context, patch the environment with replacements. Pass None values to clear the values. """ - saved = dict( - (key, os.environ[key]) - for key in replacements - if key in os.environ - ) + saved = dict((key, os.environ[key]) for key in replacements if key in os.environ) # remove values that are null remove = (key for (key, value) in replacements.items() if value is None) diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py index c0274c337c7..1d9470be102 100644 --- a/setuptools/tests/environment.py +++ b/setuptools/tests/environment.py @@ -14,8 +14,7 @@ def _which_dirs(cmd): return result -def run_setup_py(cmd, pypath=None, path=None, - data_stream=0, env=None): +def run_setup_py(cmd, pypath=None, path=None, data_stream=0, env=None): """ Execution command for tests, separate from those used by the code directly to prevent accidental behavior issues @@ -43,7 +42,11 @@ def run_setup_py(cmd, pypath=None, path=None, try: proc = _Popen( - cmd, stdout=_PIPE, stderr=_PIPE, shell=shell, env=env, + cmd, + stdout=_PIPE, + stderr=_PIPE, + shell=shell, + env=env, ) if isinstance(data_stream, tuple): diff --git a/setuptools/tests/namespaces.py b/setuptools/tests/namespaces.py index 245cf8ea389..c70e21434a8 100644 --- a/setuptools/tests/namespaces.py +++ b/setuptools/tests/namespaces.py @@ -6,7 +6,8 @@ def build_namespace_package(tmpdir, name): src_dir.mkdir() setup_py = src_dir / 'setup.py' namespace, sep, rest = name.partition('.') - script = textwrap.dedent(""" + script = textwrap.dedent( + """ import setuptools setuptools.setup( name={name!r}, @@ -14,7 +15,8 @@ def build_namespace_package(tmpdir, name): namespace_packages=[{namespace!r}], packages=[{namespace!r}], ) - """).format(**locals()) + """ + ).format(**locals()) setup_py.write_text(script, encoding='utf-8') ns_pkg_dir = src_dir / namespace ns_pkg_dir.mkdir() diff --git a/setuptools/tests/server.py b/setuptools/tests/server.py index 6717c053588..4821e7ba84d 100644 --- a/setuptools/tests/server.py +++ b/setuptools/tests/server.py @@ -22,10 +22,11 @@ class IndexServer(http.server.HTTPServer): """ def __init__( - self, server_address=('', 0), - RequestHandlerClass=http.server.SimpleHTTPRequestHandler): - http.server.HTTPServer.__init__( - self, server_address, RequestHandlerClass) + self, + server_address=('', 0), + RequestHandlerClass=http.server.SimpleHTTPRequestHandler, + ): + http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass) self._run = True def start(self): @@ -59,11 +60,8 @@ class MockServer(http.server.HTTPServer, threading.Thread): A simple HTTP Server that records the requests made to it. """ - def __init__( - self, server_address=('', 0), - RequestHandlerClass=RequestRecorder): - http.server.HTTPServer.__init__( - self, server_address, RequestHandlerClass) + def __init__(self, server_address=('', 0), RequestHandlerClass=RequestRecorder): + http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass) threading.Thread.__init__(self) self.daemon = True self.requests = [] diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py index fb5b90b1a38..29801c415dd 100644 --- a/setuptools/tests/test_bdist_egg.py +++ b/setuptools/tests/test_bdist_egg.py @@ -29,12 +29,14 @@ def setup_context(tmpdir): class Test: def test_bdist_egg(self, setup_context, user_override): - dist = Distribution(dict( - script_name='setup.py', - script_args=['bdist_egg'], - name='foo', - py_modules=['hi'], - )) + dist = Distribution( + dict( + script_name='setup.py', + script_args=['bdist_egg'], + name='foo', + py_modules=['hi'], + ) + ) os.makedirs(os.path.join('build', 'src')) with contexts.quiet(): dist.parse_command_line() @@ -49,12 +51,14 @@ def test_bdist_egg(self, setup_context, user_override): reason="Byte code disabled", ) def test_exclude_source_files(self, setup_context, user_override): - dist = Distribution(dict( - script_name='setup.py', - script_args=['bdist_egg', '--exclude-source-files'], - name='foo', - py_modules=['hi'], - )) + dist = Distribution( + dict( + script_name='setup.py', + script_args=['bdist_egg', '--exclude-source-files'], + name='foo', + py_modules=['hi'], + ) + ) with contexts.quiet(): dist.parse_command_line() dist.run_commands() diff --git a/setuptools/tests/test_build_clib.py b/setuptools/tests/test_build_clib.py index 48bea2b43d0..fc5cf048f51 100644 --- a/setuptools/tests/test_build_clib.py +++ b/setuptools/tests/test_build_clib.py @@ -7,8 +7,7 @@ class TestBuildCLib: - @mock.patch( - 'setuptools.command.build_clib.newer_pairwise_group') + @mock.patch('setuptools.command.build_clib.newer_pairwise_group') def test_build_libraries(self, mock_newer): dist = Distribution() cmd = build_clib(dist) @@ -43,8 +42,7 @@ def test_build_libraries(self, mock_newer): libs = [('example', {'sources': ['example.c'], 'obj_deps': obj_deps})] cmd.build_libraries(libs) - assert [['example.c', 'global.h', 'example.h']] in \ - mock_newer.call_args[0] + assert [['example.c', 'global.h', 'example.h']] in mock_newer.call_args[0] assert not cmd.compiler.compile.called assert cmd.compiler.create_static_lib.call_count == 1 diff --git a/setuptools/tests/test_build_ext.py b/setuptools/tests/test_build_ext.py index 3177a2cdd6b..ba73bc22696 100644 --- a/setuptools/tests/test_build_ext.py +++ b/setuptools/tests/test_build_ext.py @@ -94,7 +94,8 @@ def test_build_ext_config_handling(tmpdir_cwd): version='0.0.0', ext_modules=[Extension('foo', ['foo.c'])], ) - """), + """ + ), 'foo.c': DALS( """ #include "Python.h" @@ -136,15 +137,18 @@ def test_build_ext_config_handling(tmpdir_cwd): return module; #endif } - """), + """ + ), 'setup.cfg': DALS( """ [build] build_base = foo_build - """), + """ + ), } path.build(files) code, output = environment.run_setup_py( - cmd=['build'], data_stream=(0, 2), + cmd=['build'], + data_stream=(0, 2), ) assert code == 0, '\nSTDOUT:\n%s\nSTDERR:\n%s' % output diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index ab75a1896c6..08ec5f0d24a 100644 --- a/setuptools/tests/test_build_meta.py +++ b/setuptools/tests/test_build_meta.py @@ -40,8 +40,7 @@ class BuildBackendCaller(BuildBackendBase): def __init__(self, *args, **kwargs): super(BuildBackendCaller, self).__init__(*args, **kwargs) - (self.backend_name, _, - self.backend_obj) = self.backend_name.partition(':') + (self.backend_name, _, self.backend_obj) = self.backend_name.partition(':') def __call__(self, name, *args, **kw): """Handles aribrary function invocations on the build backend.""" @@ -59,21 +58,26 @@ def __call__(self, name, *args, **kw): defns = [ { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ __import__('setuptools').setup( name='foo', version='0.0.0', py_modules=['hello'], setup_requires=['six'], ) - """), - 'hello.py': DALS(""" + """ + ), + 'hello.py': DALS( + """ def run(): print('hello') - """), + """ + ), }, { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ assert __name__ == '__main__' __import__('setuptools').setup( name='foo', @@ -81,14 +85,18 @@ def run(): py_modules=['hello'], setup_requires=['six'], ) - """), - 'hello.py': DALS(""" + """ + ), + 'hello.py': DALS( + """ def run(): print('hello') - """), + """ + ), }, { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ variable = True def function(): return variable @@ -99,14 +107,18 @@ def function(): py_modules=['hello'], setup_requires=['six'], ) - """), - 'hello.py': DALS(""" + """ + ), + 'hello.py': DALS( + """ def run(): print('hello') - """), + """ + ), }, { - 'setup.cfg': DALS(""" + 'setup.cfg': DALS( + """ [metadata] name = foo version = 0.0.0 @@ -114,11 +126,14 @@ def run(): [options] py_modules=hello setup_requires=six - """), - 'hello.py': DALS(""" + """ + ), + 'hello.py': DALS( + """ def run(): print('hello') - """) + """ + ), }, ] @@ -159,16 +174,20 @@ def test_build_with_existing_file_present(self, build_type, tmpdir_cwd): files = { 'setup.py': "from setuptools import setup\nsetup()", 'VERSION': "0.0.1", - 'setup.cfg': DALS(""" + 'setup.cfg': DALS( + """ [metadata] name = foo version = file: VERSION - """), - 'pyproject.toml': DALS(""" + """ + ), + 'pyproject.toml': DALS( + """ [build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta - """), + """ + ), } path.build(files) @@ -238,30 +257,32 @@ def test_build_sdist_version_change(self, build_backend): with open(setup_loc, 'rt') as file_handler: content = file_handler.read() with open(setup_loc, 'wt') as file_handler: - file_handler.write( - content.replace("version='0.0.0'", "version='0.0.1'")) + file_handler.write(content.replace("version='0.0.0'", "version='0.0.1'")) shutil.rmtree(sdist_into_directory) os.makedirs(sdist_into_directory) sdist_name = build_backend.build_sdist("out_sdist") - assert os.path.isfile( - os.path.join(os.path.abspath("out_sdist"), sdist_name)) + assert os.path.isfile(os.path.join(os.path.abspath("out_sdist"), sdist_name)) def test_build_sdist_pyproject_toml_exists(self, tmpdir_cwd): files = { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ __import__('setuptools').setup( name='foo', version='0.0.0', py_modules=['hello'] - )"""), + )""" + ), 'hello.py': '', - 'pyproject.toml': DALS(""" + 'pyproject.toml': DALS( + """ [build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta - """), + """ + ), } path.build(files) build_backend = self.get_build_backend() @@ -282,16 +303,20 @@ def test_build_sdist_setup_py_exists(self, tmpdir_cwd): def test_build_sdist_setup_py_manifest_excluded(self, tmpdir_cwd): # Ensure that MANIFEST.in can exclude setup.py files = { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ __import__('setuptools').setup( name='foo', version='0.0.0', py_modules=['hello'] - )"""), + )""" + ), 'hello.py': '', - 'MANIFEST.in': DALS(""" + 'MANIFEST.in': DALS( + """ exclude setup.py - """) + """ + ), } path.build(files) @@ -303,17 +328,21 @@ def test_build_sdist_setup_py_manifest_excluded(self, tmpdir_cwd): def test_build_sdist_builds_targz_even_if_zip_indicated(self, tmpdir_cwd): files = { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ __import__('setuptools').setup( name='foo', version='0.0.0', py_modules=['hello'] - )"""), + )""" + ), 'hello.py': '', - 'setup.cfg': DALS(""" + 'setup.cfg': DALS( + """ [sdist] formats=zip - """) + """ + ), } path.build(files) @@ -322,17 +351,21 @@ def test_build_sdist_builds_targz_even_if_zip_indicated(self, tmpdir_cwd): build_backend.build_sdist("temp") _relative_path_import_files = { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ __import__('setuptools').setup( name='foo', version=__import__('hello').__version__, py_modules=['hello'] - )"""), + )""" + ), 'hello.py': '__version__ = "0.0.0"', - 'setup.cfg': DALS(""" + 'setup.cfg': DALS( + """ [sdist] formats=zip - """) + """ + ), } def test_build_sdist_relative_path_import(self, tmpdir_cwd): @@ -341,25 +374,28 @@ def test_build_sdist_relative_path_import(self, tmpdir_cwd): with pytest.raises(ImportError, match="^No module named 'hello'$"): build_backend.build_sdist("temp") - @pytest.mark.parametrize('setup_literal, requirements', [ - ("'foo'", ['foo']), - ("['foo']", ['foo']), - (r"'foo\n'", ['foo']), - (r"'foo\n\n'", ['foo']), - ("['foo', 'bar']", ['foo', 'bar']), - (r"'# Has a comment line\nfoo'", ['foo']), - (r"'foo # Has an inline comment'", ['foo']), - (r"'foo \\\n >=3.0'", ['foo>=3.0']), - (r"'foo\nbar'", ['foo', 'bar']), - (r"'foo\nbar\n'", ['foo', 'bar']), - (r"['foo\n', 'bar\n']", ['foo', 'bar']), - ]) + @pytest.mark.parametrize( + 'setup_literal, requirements', + [ + ("'foo'", ['foo']), + ("['foo']", ['foo']), + (r"'foo\n'", ['foo']), + (r"'foo\n\n'", ['foo']), + ("['foo', 'bar']", ['foo', 'bar']), + (r"'# Has a comment line\nfoo'", ['foo']), + (r"'foo # Has an inline comment'", ['foo']), + (r"'foo \\\n >=3.0'", ['foo>=3.0']), + (r"'foo\nbar'", ['foo', 'bar']), + (r"'foo\nbar\n'", ['foo', 'bar']), + (r"['foo\n', 'bar\n']", ['foo', 'bar']), + ], + ) @pytest.mark.parametrize('use_wheel', [True, False]) - def test_setup_requires(self, setup_literal, requirements, use_wheel, - tmpdir_cwd): + def test_setup_requires(self, setup_literal, requirements, use_wheel, tmpdir_cwd): files = { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ from setuptools import setup setup( @@ -368,11 +404,14 @@ def test_setup_requires(self, setup_literal, requirements, use_wheel, py_modules=["hello"], setup_requires={setup_literal}, ) - """).format(setup_literal=setup_literal), - 'hello.py': DALS(""" + """ + ).format(setup_literal=setup_literal), + 'hello.py': DALS( + """ def run(): print('hello') - """), + """ + ), } path.build(files) @@ -394,7 +433,8 @@ def run(): def test_dont_install_setup_requires(self, tmpdir_cwd): files = { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ from setuptools import setup setup( @@ -403,11 +443,14 @@ def test_dont_install_setup_requires(self, tmpdir_cwd): py_modules=["hello"], setup_requires=["does-not-exist >99"], ) - """), - 'hello.py': DALS(""" + """ + ), + 'hello.py': DALS( + """ def run(): print('hello') - """), + """ + ), } path.build(files) @@ -422,7 +465,8 @@ def run(): build_backend.prepare_metadata_for_build_wheel(dist_dir) _sys_argv_0_passthrough = { - 'setup.py': DALS(""" + 'setup.py': DALS( + """ import os import sys @@ -434,7 +478,8 @@ def run(): sys_argv = os.path.abspath(sys.argv[0]) file_path = os.path.abspath('setup.py') assert sys_argv == file_path - """) + """ + ) } def test_sys_argv_passthrough(self, tmpdir_cwd): @@ -448,9 +493,7 @@ def test_build_with_empty_setuppy(self, build_backend, build_hook): files = {'setup.py': ''} path.build(files) - with pytest.raises( - ValueError, - match=re.escape('No distribution was found.')): + with pytest.raises(ValueError, match=re.escape('No distribution was found.')): getattr(build_backend, build_hook)("temp") diff --git a/setuptools/tests/test_build_py.py b/setuptools/tests/test_build_py.py index 78a31ac49e2..557f58f4957 100644 --- a/setuptools/tests/test_build_py.py +++ b/setuptools/tests/test_build_py.py @@ -14,13 +14,15 @@ def test_directories_in_package_data_glob(tmpdir_cwd): Regression test for #261. """ - dist = Distribution(dict( - script_name='setup.py', - script_args=['build_py'], - packages=[''], - name='foo', - package_data={'': ['path/*']}, - )) + dist = Distribution( + dict( + script_name='setup.py', + script_args=['build_py'], + packages=[''], + name='foo', + package_data={'': ['path/*']}, + ) + ) os.makedirs('path/subpath') dist.parse_command_line() dist.run_commands() @@ -35,13 +37,15 @@ def test_read_only(tmpdir_cwd): #1451 """ - dist = Distribution(dict( - script_name='setup.py', - script_args=['build_py'], - packages=['pkg'], - package_data={'pkg': ['data.dat']}, - name='pkg', - )) + dist = Distribution( + dict( + script_name='setup.py', + script_args=['build_py'], + packages=['pkg'], + package_data={'pkg': ['data.dat']}, + name='pkg', + ) + ) os.makedirs('pkg') open('pkg/__init__.py', 'w').close() open('pkg/data.dat', 'w').close() @@ -65,13 +69,15 @@ def test_executable_data(tmpdir_cwd): #2041 """ - dist = Distribution(dict( - script_name='setup.py', - script_args=['build_py'], - packages=['pkg'], - package_data={'pkg': ['run-me']}, - name='pkg', - )) + dist = Distribution( + dict( + script_name='setup.py', + script_args=['build_py'], + packages=['pkg'], + package_data={'pkg': ['run-me']}, + name='pkg', + ) + ) os.makedirs('pkg') open('pkg/__init__.py', 'w').close() open('pkg/run-me', 'w').close() @@ -80,5 +86,6 @@ def test_executable_data(tmpdir_cwd): dist.parse_command_line() dist.run_commands() - assert os.stat('build/lib/pkg/run-me').st_mode & stat.S_IEXEC, \ - "Script is not executable" + assert ( + os.stat('build/lib/pkg/run-me').st_mode & stat.S_IEXEC + ), "Script is not executable" diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py index 21f1becd499..c2180542026 100644 --- a/setuptools/tests/test_config.py +++ b/setuptools/tests/test_config.py @@ -30,14 +30,11 @@ def make_package_dir(name, base_dir, ns=False): def fake_env( - tmpdir, setup_cfg, setup_py=None, - encoding='ascii', package_path='fake_package'): + tmpdir, setup_cfg, setup_py=None, encoding='ascii', package_path='fake_package' +): if setup_py is None: - setup_py = ( - 'from setuptools import setup\n' - 'setup()\n' - ) + setup_py = 'from setuptools import setup\n' 'setup()\n' tmpdir.join('setup.py').write(setup_py) config = tmpdir.join('setup.cfg') @@ -78,7 +75,6 @@ def test_parsers_implemented(): class TestConfigurationReader: - def test_basic(self, tmpdir): _, config = fake_env( tmpdir, @@ -87,7 +83,7 @@ def test_basic(self, tmpdir): 'keywords = one, two\n' '\n' '[options]\n' - 'scripts = bin/a.py, bin/b.py\n' + 'scripts = bin/a.py, bin/b.py\n', ) config_dict = read_configuration('%s' % config) assert config_dict['metadata']['version'] == '10.1.1' @@ -101,15 +97,12 @@ def test_no_config(self, tmpdir): def test_ignore_errors(self, tmpdir): _, config = fake_env( tmpdir, - '[metadata]\n' - 'version = attr: none.VERSION\n' - 'keywords = one, two\n' + '[metadata]\n' 'version = attr: none.VERSION\n' 'keywords = one, two\n', ) with pytest.raises(ImportError): read_configuration('%s' % config) - config_dict = read_configuration( - '%s' % config, ignore_option_errors=True) + config_dict = read_configuration('%s' % config, ignore_option_errors=True) assert config_dict['metadata']['keywords'] == ['one', 'two'] assert 'version' not in config_dict['metadata'] @@ -118,7 +111,6 @@ def test_ignore_errors(self, tmpdir): class TestMetadata: - def test_basic(self, tmpdir): fake_env( @@ -133,7 +125,7 @@ def test_basic(self, tmpdir): 'provides = package, package.sub\n' 'license = otherlic\n' 'download_url = http://test.test.com/test/\n' - 'maintainer_email = test@test.com\n' + 'maintainer_email = test@test.com\n', ) tmpdir.join('README').write('readme contents\nline2') @@ -160,12 +152,14 @@ def test_basic(self, tmpdir): def test_license_cfg(self, tmpdir): fake_env( tmpdir, - DALS(""" + DALS( + """ [metadata] name=foo version=0.0.1 license=Apache 2.0 - """) + """ + ), ) with get_dist(tmpdir) as dist: @@ -179,9 +173,7 @@ def test_file_mixed(self, tmpdir): fake_env( tmpdir, - '[metadata]\n' - 'long_description = file: README.rst, CHANGES.rst\n' - '\n' + '[metadata]\n' 'long_description = file: README.rst, CHANGES.rst\n' '\n', ) tmpdir.join('README.rst').write('readme contents\nline2') @@ -189,17 +181,12 @@ def test_file_mixed(self, tmpdir): with get_dist(tmpdir) as dist: assert dist.metadata.long_description == ( - 'readme contents\nline2\n' - 'changelog contents\nand stuff' + 'readme contents\nline2\n' 'changelog contents\nand stuff' ) def test_file_sandboxed(self, tmpdir): - fake_env( - tmpdir, - '[metadata]\n' - 'long_description = file: ../../README\n' - ) + fake_env(tmpdir, '[metadata]\n' 'long_description = file: ../../README\n') with get_dist(tmpdir, parse=False) as dist: with pytest.raises(DistutilsOptionError): @@ -216,7 +203,7 @@ def test_aliases(self, tmpdir): 'platform = a, b\n' 'classifier =\n' ' Framework :: Django\n' - ' Programming Language :: Python :: 3.5\n' + ' Programming Language :: Python :: 3.5\n', ) with get_dist(tmpdir) as dist: @@ -241,7 +228,7 @@ def test_multiline(self, tmpdir): ' two\n' 'classifiers =\n' ' Framework :: Django\n' - ' Programming Language :: Python :: 3.5\n' + ' Programming Language :: Python :: 3.5\n', ) with get_dist(tmpdir) as dist: metadata = dist.metadata @@ -258,7 +245,7 @@ def test_dict(self, tmpdir): '[metadata]\n' 'project_urls =\n' ' Link One = https://example.com/one/\n' - ' Link Two = https://example.com/two/\n' + ' Link Two = https://example.com/two/\n', ) with get_dist(tmpdir) as dist: metadata = dist.metadata @@ -270,9 +257,7 @@ def test_dict(self, tmpdir): def test_version(self, tmpdir): package_dir, config = fake_env( - tmpdir, - '[metadata]\n' - 'version = attr: fake_package.VERSION\n' + tmpdir, '[metadata]\n' 'version = attr: fake_package.VERSION\n' ) sub_a = package_dir.mkdir('subpkg_a') @@ -282,37 +267,28 @@ def test_version(self, tmpdir): sub_b = package_dir.mkdir('subpkg_b') sub_b.join('__init__.py').write('') sub_b.join('mod.py').write( - 'import third_party_module\n' - 'VERSION = (2016, 11, 26)' + 'import third_party_module\n' 'VERSION = (2016, 11, 26)' ) with get_dist(tmpdir) as dist: assert dist.metadata.version == '1.2.3' - config.write( - '[metadata]\n' - 'version = attr: fake_package.get_version\n' - ) + config.write('[metadata]\n' 'version = attr: fake_package.get_version\n') with get_dist(tmpdir) as dist: assert dist.metadata.version == '3.4.5.dev' - config.write( - '[metadata]\n' - 'version = attr: fake_package.VERSION_MAJOR\n' - ) + config.write('[metadata]\n' 'version = attr: fake_package.VERSION_MAJOR\n') with get_dist(tmpdir) as dist: assert dist.metadata.version == '1' config.write( - '[metadata]\n' - 'version = attr: fake_package.subpkg_a.mod.VERSION\n' + '[metadata]\n' 'version = attr: fake_package.subpkg_a.mod.VERSION\n' ) with get_dist(tmpdir) as dist: assert dist.metadata.version == '2016.11.26' config.write( - '[metadata]\n' - 'version = attr: fake_package.subpkg_b.mod.VERSION\n' + '[metadata]\n' 'version = attr: fake_package.subpkg_b.mod.VERSION\n' ) with get_dist(tmpdir) as dist: assert dist.metadata.version == '2016.11.26' @@ -320,9 +296,7 @@ def test_version(self, tmpdir): def test_version_file(self, tmpdir): _, config = fake_env( - tmpdir, - '[metadata]\n' - 'version = file: fake_package/version.txt\n' + tmpdir, '[metadata]\n' 'version = file: fake_package/version.txt\n' ) tmpdir.join('fake_package', 'version.txt').write('1.2.3\n') @@ -343,7 +317,7 @@ def test_version_with_package_dir_simple(self, tmpdir): '[options]\n' 'package_dir =\n' ' = src\n', - package_path='src/fake_package_simple' + package_path='src/fake_package_simple', ) with get_dist(tmpdir) as dist: @@ -358,7 +332,7 @@ def test_version_with_package_dir_rename(self, tmpdir): '[options]\n' 'package_dir =\n' ' fake_package_rename = fake_dir\n', - package_path='fake_dir' + package_path='fake_dir', ) with get_dist(tmpdir) as dist: @@ -373,7 +347,7 @@ def test_version_with_package_dir_complex(self, tmpdir): '[options]\n' 'package_dir =\n' ' fake_package_complex = src/fake_dir\n', - package_path='src/fake_dir' + package_path='src/fake_dir', ) with get_dist(tmpdir) as dist: @@ -381,39 +355,28 @@ def test_version_with_package_dir_complex(self, tmpdir): def test_unknown_meta_item(self, tmpdir): - fake_env( - tmpdir, - '[metadata]\n' - 'name = fake_name\n' - 'unknown = some\n' - ) + fake_env(tmpdir, '[metadata]\n' 'name = fake_name\n' 'unknown = some\n') with get_dist(tmpdir, parse=False) as dist: dist.parse_config_files() # Skip unknown. def test_usupported_section(self, tmpdir): - fake_env( - tmpdir, - '[metadata.some]\n' - 'key = val\n' - ) + fake_env(tmpdir, '[metadata.some]\n' 'key = val\n') with get_dist(tmpdir, parse=False) as dist: with pytest.raises(DistutilsOptionError): dist.parse_config_files() def test_classifiers(self, tmpdir): - expected = set([ - 'Framework :: Django', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - ]) + expected = set( + [ + 'Framework :: Django', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + ] + ) # From file. - _, config = fake_env( - tmpdir, - '[metadata]\n' - 'classifiers = file: classifiers\n' - ) + _, config = fake_env(tmpdir, '[metadata]\n' 'classifiers = file: classifiers\n') tmpdir.join('classifiers').write( 'Framework :: Django\n' @@ -441,7 +404,7 @@ def test_deprecated_config_handlers(self, tmpdir): '[metadata]\n' 'version = 10.1.1\n' 'description = Some description\n' - 'requires = some, requirement\n' + 'requires = some, requirement\n', ) with pytest.deprecated_call(): @@ -453,41 +416,26 @@ def test_deprecated_config_handlers(self, tmpdir): assert metadata.requires == ['some', 'requirement'] def test_interpolation(self, tmpdir): - fake_env( - tmpdir, - '[metadata]\n' - 'description = %(message)s\n' - ) + fake_env(tmpdir, '[metadata]\n' 'description = %(message)s\n') with pytest.raises(configparser.InterpolationMissingOptionError): with get_dist(tmpdir): pass def test_non_ascii_1(self, tmpdir): - fake_env( - tmpdir, - '[metadata]\n' - 'description = éàïôñ\n', - encoding='utf-8' - ) + fake_env(tmpdir, '[metadata]\n' 'description = éàïôñ\n', encoding='utf-8') with get_dist(tmpdir): pass def test_non_ascii_3(self, tmpdir): - fake_env( - tmpdir, - '\n' - '# -*- coding: invalid\n' - ) + fake_env(tmpdir, '\n' '# -*- coding: invalid\n') with get_dist(tmpdir): pass def test_non_ascii_4(self, tmpdir): fake_env( tmpdir, - '# -*- coding: utf-8\n' - '[metadata]\n' - 'description = éàïôñ\n', - encoding='utf-8' + '# -*- coding: utf-8\n' '[metadata]\n' 'description = éàïôñ\n', + encoding='utf-8', ) with get_dist(tmpdir) as dist: assert dist.metadata.description == 'éàïôñ' @@ -501,7 +449,7 @@ def test_not_utf8(self, tmpdir): '# vim: set fileencoding=iso-8859-15 :\n' '[metadata]\n' 'description = éàïôñ\n', - encoding='iso-8859-15' + encoding='iso-8859-15', ) with pytest.raises(UnicodeDecodeError): with get_dist(tmpdir): @@ -514,11 +462,13 @@ def test_warn_dash_deprecation(self, tmpdir): tmpdir, '[metadata]\n' 'author-email = test@test.com\n' - 'maintainer_email = foo@foo.com\n' - ) - msg = ("Usage of dash-separated 'author-email' will not be supported " - "in future versions. " - "Please use the underscore name 'author_email' instead") + 'maintainer_email = foo@foo.com\n', + ) + msg = ( + "Usage of dash-separated 'author-email' will not be supported " + "in future versions. " + "Please use the underscore name 'author_email' instead" + ) with pytest.warns(UserWarning, match=msg): with get_dist(tmpdir) as dist: metadata = dist.metadata @@ -530,14 +480,13 @@ def test_make_option_lowercase(self, tmpdir): # remove this test and the method make_option_lowercase() in setuptools.dist # when no longer needed fake_env( - tmpdir, - '[metadata]\n' - 'Name = foo\n' - 'description = Some description\n' + tmpdir, '[metadata]\n' 'Name = foo\n' 'description = Some description\n' + ) + msg = ( + "Usage of uppercase key 'Name' in 'metadata' will be deprecated in " + "future versions. " + "Please use lowercase 'name' instead" ) - msg = ("Usage of uppercase key 'Name' in 'metadata' will be deprecated in " - "future versions. " - "Please use lowercase 'name' instead") with pytest.warns(UserWarning, match=msg): with get_dist(tmpdir) as dist: metadata = dist.metadata @@ -547,7 +496,6 @@ def test_make_option_lowercase(self, tmpdir): class TestOptions: - def test_basic(self, tmpdir): fake_env( @@ -570,7 +518,7 @@ def test_basic(self, tmpdir): 'dependency_links = http://some.com/here/1, ' 'http://some.com/there/2\n' 'python_requires = >=1.0, !=2.8\n' - 'py_modules = module1, module2\n' + 'py_modules = module1, module2\n', ) with get_dist(tmpdir) as dist: assert dist.zip_safe @@ -581,23 +529,17 @@ def test_basic(self, tmpdir): assert dist.namespace_packages == ['pack1', 'pack2'] assert dist.use_2to3_fixers == ['your.fixers', 'or.here'] assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there'] - assert dist.convert_2to3_doctests == ([ - 'src/tests/one.txt', 'src/two.txt']) + assert dist.convert_2to3_doctests == (['src/tests/one.txt', 'src/two.txt']) assert dist.scripts == ['bin/one.py', 'bin/two.py'] - assert dist.dependency_links == ([ - 'http://some.com/here/1', - 'http://some.com/there/2' - ]) - assert dist.install_requires == ([ - 'docutils>=0.3', - 'pack==1.1,==1.3', - 'hey' - ]) - assert dist.setup_requires == ([ - 'docutils>=0.3', - 'spack ==1.1, ==1.3', - 'there' - ]) + assert dist.dependency_links == ( + ['http://some.com/here/1', 'http://some.com/there/2'] + ) + assert dist.install_requires == ( + ['docutils>=0.3', 'pack==1.1,==1.3', 'hey'] + ) + assert dist.setup_requires == ( + ['docutils>=0.3', 'spack ==1.1, ==1.3', 'there'] + ) assert dist.tests_require == ['mock==0.7.2', 'pytest'] assert dist.python_requires == '>=1.0, !=2.8' assert dist.py_modules == ['module1', 'module2'] @@ -643,7 +585,7 @@ def test_multiline(self, tmpdir): ' there\n' 'dependency_links = \n' ' http://some.com/here/1\n' - ' http://some.com/there/2\n' + ' http://some.com/there/2\n', ) with get_dist(tmpdir) as dist: assert dist.package_dir == {'': 'src', 'b': 'c'} @@ -651,31 +593,21 @@ def test_multiline(self, tmpdir): assert dist.namespace_packages == ['pack1', 'pack2'] assert dist.use_2to3_fixers == ['your.fixers', 'or.here'] assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there'] - assert dist.convert_2to3_doctests == ( - ['src/tests/one.txt', 'src/two.txt']) + assert dist.convert_2to3_doctests == (['src/tests/one.txt', 'src/two.txt']) assert dist.scripts == ['bin/one.py', 'bin/two.py'] - assert dist.dependency_links == ([ - 'http://some.com/here/1', - 'http://some.com/there/2' - ]) - assert dist.install_requires == ([ - 'docutils>=0.3', - 'pack==1.1,==1.3', - 'hey' - ]) - assert dist.setup_requires == ([ - 'docutils>=0.3', - 'spack ==1.1, ==1.3', - 'there' - ]) + assert dist.dependency_links == ( + ['http://some.com/here/1', 'http://some.com/there/2'] + ) + assert dist.install_requires == ( + ['docutils>=0.3', 'pack==1.1,==1.3', 'hey'] + ) + assert dist.setup_requires == ( + ['docutils>=0.3', 'spack ==1.1, ==1.3', 'there'] + ) assert dist.tests_require == ['mock==0.7.2', 'pytest'] def test_package_dir_fail(self, tmpdir): - fake_env( - tmpdir, - '[options]\n' - 'package_dir = a b\n' - ) + fake_env(tmpdir, '[options]\n' 'package_dir = a b\n') with get_dist(tmpdir, parse=False) as dist: with pytest.raises(DistutilsOptionError): dist.parse_config_files() @@ -689,7 +621,7 @@ def test_package_data(self, tmpdir): '\n' '[options.exclude_package_data]\n' '* = fake1.txt, fake2.txt\n' - 'hello = *.dat\n' + 'hello = *.dat\n', ) with get_dist(tmpdir) as dist: @@ -703,29 +635,21 @@ def test_package_data(self, tmpdir): } def test_packages(self, tmpdir): - fake_env( - tmpdir, - '[options]\n' - 'packages = find:\n' - ) + fake_env(tmpdir, '[options]\n' 'packages = find:\n') with get_dist(tmpdir) as dist: assert dist.packages == ['fake_package'] def test_find_directive(self, tmpdir): - dir_package, config = fake_env( - tmpdir, - '[options]\n' - 'packages = find:\n' - ) + dir_package, config = fake_env(tmpdir, '[options]\n' 'packages = find:\n') dir_sub_one, _ = make_package_dir('sub_one', dir_package) dir_sub_two, _ = make_package_dir('sub_two', dir_package) with get_dist(tmpdir) as dist: - assert set(dist.packages) == set([ - 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one' - ]) + assert set(dist.packages) == set( + ['fake_package', 'fake_package.sub_two', 'fake_package.sub_one'] + ) config.write( '[options]\n' @@ -749,14 +673,11 @@ def test_find_directive(self, tmpdir): ' fake_package.sub_one\n' ) with get_dist(tmpdir) as dist: - assert set(dist.packages) == set( - ['fake_package', 'fake_package.sub_two']) + assert set(dist.packages) == set(['fake_package', 'fake_package.sub_two']) def test_find_namespace_directive(self, tmpdir): dir_package, config = fake_env( - tmpdir, - '[options]\n' - 'packages = find_namespace:\n' + tmpdir, '[options]\n' 'packages = find_namespace:\n' ) dir_sub_one, _ = make_package_dir('sub_one', dir_package) @@ -764,7 +685,9 @@ def test_find_namespace_directive(self, tmpdir): with get_dist(tmpdir) as dist: assert set(dist.packages) == { - 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one' + 'fake_package', + 'fake_package.sub_two', + 'fake_package.sub_one', } config.write( @@ -789,9 +712,7 @@ def test_find_namespace_directive(self, tmpdir): ' fake_package.sub_one\n' ) with get_dist(tmpdir) as dist: - assert set(dist.packages) == { - 'fake_package', 'fake_package.sub_two' - } + assert set(dist.packages) == {'fake_package', 'fake_package.sub_two'} def test_extras_require(self, tmpdir): fake_env( @@ -800,29 +721,21 @@ def test_extras_require(self, tmpdir): 'pdf = ReportLab>=1.2; RXP\n' 'rest = \n' ' docutils>=0.3\n' - ' pack ==1.1, ==1.3\n' + ' pack ==1.1, ==1.3\n', ) with get_dist(tmpdir) as dist: assert dist.extras_require == { 'pdf': ['ReportLab>=1.2', 'RXP'], - 'rest': ['docutils>=0.3', 'pack==1.1,==1.3'] + 'rest': ['docutils>=0.3', 'pack==1.1,==1.3'], } assert dist.metadata.provides_extras == set(['pdf', 'rest']) def test_dash_preserved_extras_require(self, tmpdir): - fake_env( - tmpdir, - '[options.extras_require]\n' - 'foo-a = foo\n' - 'foo_b = test\n' - ) + fake_env(tmpdir, '[options.extras_require]\n' 'foo-a = foo\n' 'foo_b = test\n') with get_dist(tmpdir) as dist: - assert dist.extras_require == { - 'foo-a': ['foo'], - 'foo_b': ['test'] - } + assert dist.extras_require == {'foo-a': ['foo'], 'foo_b': ['test']} def test_entry_points(self, tmpdir): _, config = fake_env( @@ -830,7 +743,7 @@ def test_entry_points(self, tmpdir): '[options.entry_points]\n' 'group1 = point1 = pack.module:func, ' '.point2 = pack.module2:func_rest [rest]\n' - 'group2 = point3 = pack.module:func2\n' + 'group2 = point3 = pack.module:func2\n', ) with get_dist(tmpdir) as dist: @@ -839,7 +752,7 @@ def test_entry_points(self, tmpdir): 'point1 = pack.module:func', '.point2 = pack.module2:func_rest [rest]', ], - 'group2': ['point3 = pack.module:func2'] + 'group2': ['point3 = pack.module:func2'], } expected = ( @@ -850,10 +763,7 @@ def test_entry_points(self, tmpdir): tmpdir.join('entry_points').write(expected) # From file. - config.write( - '[options]\n' - 'entry_points = file: entry_points\n' - ) + config.write('[options]\n' 'entry_points = file: entry_points\n') with get_dist(tmpdir) as dist: assert dist.entry_points == expected @@ -864,7 +774,7 @@ def test_case_sensitive_entry_points(self, tmpdir): '[options.entry_points]\n' 'GROUP1 = point1 = pack.module:func, ' '.point2 = pack.module2:func_rest [rest]\n' - 'group2 = point3 = pack.module:func2\n' + 'group2 = point3 = pack.module:func2\n', ) with get_dist(tmpdir) as dist: @@ -873,7 +783,7 @@ def test_case_sensitive_entry_points(self, tmpdir): 'point1 = pack.module:func', '.point2 = pack.module2:func_rest [rest]', ], - 'group2': ['point3 = pack.module:func2'] + 'group2': ['point3 = pack.module:func2'], } def test_data_files(self, tmpdir): @@ -883,7 +793,7 @@ def test_data_files(self, tmpdir): 'cfg =\n' ' a/b.conf\n' ' c/d.conf\n' - 'data = e/f.dat, g/h.dat\n' + 'data = e/f.dat, g/h.dat\n', ) with get_dist(tmpdir) as dist: @@ -896,10 +806,12 @@ def test_data_files(self, tmpdir): def test_python_requires_simple(self, tmpdir): fake_env( tmpdir, - DALS(""" + DALS( + """ [options] python_requires=>=2.7 - """), + """ + ), ) with get_dist(tmpdir) as dist: dist.parse_config_files() @@ -907,10 +819,12 @@ def test_python_requires_simple(self, tmpdir): def test_python_requires_compound(self, tmpdir): fake_env( tmpdir, - DALS(""" + DALS( + """ [options] python_requires=>=2.7,!=3.0.* - """), + """ + ), ) with get_dist(tmpdir) as dist: dist.parse_config_files() @@ -918,10 +832,12 @@ def test_python_requires_compound(self, tmpdir): def test_python_requires_invalid(self, tmpdir): fake_env( tmpdir, - DALS(""" + DALS( + """ [options] python_requires=invalid - """), + """ + ), ) with pytest.raises(Exception): with get_dist(tmpdir) as dist: @@ -939,9 +855,7 @@ class CustomCmd(Command): fake_env( tmpdir, - '[options]\n' - 'cmdclass =\n' - ' customcmd = custom_build.CustomCmd\n' + '[options]\n' 'cmdclass =\n' ' customcmd = custom_build.CustomCmd\n', ) with get_dist(tmpdir) as dist: @@ -965,24 +879,23 @@ class TestExternalSetters: def _fake_distribution_init(self, dist, attrs): saved_dist_init(dist, attrs) # see self._DISTUTUILS_UNSUPPORTED_METADATA - setattr(dist.metadata, 'long_description_content_type', - 'text/something') + setattr(dist.metadata, 'long_description_content_type', 'text/something') # Test overwrite setup() args - setattr(dist.metadata, 'project_urls', { - 'Link One': 'https://example.com/one/', - 'Link Two': 'https://example.com/two/', - }) + setattr( + dist.metadata, + 'project_urls', + { + 'Link One': 'https://example.com/one/', + 'Link Two': 'https://example.com/two/', + }, + ) return None @patch.object(_Distribution, '__init__', autospec=True) def test_external_setters(self, mock_parent_init, tmpdir): mock_parent_init.side_effect = self._fake_distribution_init - dist = Distribution(attrs={ - 'project_urls': { - 'will_be': 'ignored' - } - }) + dist = Distribution(attrs={'project_urls': {'will_be': 'ignored'}}) assert dist.metadata.long_description_content_type == 'text/something' assert dist.metadata.project_urls == { diff --git a/setuptools/tests/test_depends.py b/setuptools/tests/test_depends.py index bff1dfb1990..1714c041f7a 100644 --- a/setuptools/tests/test_depends.py +++ b/setuptools/tests/test_depends.py @@ -4,7 +4,6 @@ class TestGetModuleConstant: - def test_basic(self): """ Invoke get_module_constant on a module in diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py index df8db4e2810..e8c6b562269 100644 --- a/setuptools/tests/test_develop.py +++ b/setuptools/tests/test_develop.py @@ -64,7 +64,8 @@ class TestDevelop: @pytest.mark.skipif( in_virtualenv or in_venv, - reason="Cannot run when invoked in a virtualenv or venv") + reason="Cannot run when invoked in a virtualenv or venv", + ) @ack_2to3 def test_2to3_user_mode(self, test_env): settings = dict( @@ -106,7 +107,8 @@ def test_console_scripts(self, tmpdir): """ pytest.skip( "TODO: needs a fixture to cause 'develop' " - "to be invoked without mutating environment.") + "to be invoked without mutating environment." + ) settings = dict( name='foo', packages=['foo'], @@ -132,6 +134,7 @@ class TestResolver: of what _resolve_setup_path is intending to do. Come up with more meaningful cases that look like real-world scenarios. """ + def test_resolve_setup_path_cwd(self): assert develop._resolve_setup_path('.', '.', '.') == '.' @@ -143,7 +146,6 @@ def test_resolve_setup_path_one_dir_trailing_slash(self): class TestNamespaces: - @staticmethod def install_develop(src_dir, target): @@ -151,7 +153,8 @@ def install_develop(src_dir, target): sys.executable, 'setup.py', 'develop', - '--install-dir', str(target), + '--install-dir', + str(target), ] with src_dir.as_cwd(): with test.test.paths_on_pythonpath([str(target)]): @@ -182,14 +185,16 @@ def test_namespace_package_importable(self, tmpdir): 'pip', 'install', str(pkg_A), - '-t', str(target), + '-t', + str(target), ] subprocess.check_call(install_cmd) self.install_develop(pkg_B, target) namespaces.make_site_dir(target) try_import = [ sys.executable, - '-c', 'import myns.pkgA; import myns.pkgB', + '-c', + 'import myns.pkgA; import myns.pkgB', ] with test.test.paths_on_pythonpath([str(target)]): subprocess.check_call(try_import) @@ -197,7 +202,8 @@ def test_namespace_package_importable(self, tmpdir): # additionally ensure that pkg_resources import works pkg_resources_imp = [ sys.executable, - '-c', 'import pkg_resources', + '-c', + 'import pkg_resources', ] with test.test.paths_on_pythonpath([str(target)]): subprocess.check_call(pkg_resources_imp) @@ -206,12 +212,16 @@ def test_namespace_package_importable(self, tmpdir): def install_workaround(site_packages): site_packages.mkdir(parents=True) sc = site_packages / 'sitecustomize.py' - sc.write_text(textwrap.dedent(""" + sc.write_text( + textwrap.dedent( + """ import site import pathlib here = pathlib.Path(__file__).parent site.addsitedir(str(here)) - """).lstrip()) + """ + ).lstrip() + ) @pytest.mark.xfail( platform.python_implementation() == 'PyPy', @@ -228,8 +238,7 @@ def test_editable_prefix(self, tmp_path, sample_project): site_packages = prefix / next( pathlib.Path(path).relative_to(sys.prefix) for path in sys.path - if 'site-packages' in path - and path.startswith(sys.prefix) + if 'site-packages' in path and path.startswith(sys.prefix) ) # install the workaround @@ -238,11 +247,13 @@ def test_editable_prefix(self, tmp_path, sample_project): env = dict(os.environ, PYTHONPATH=str(site_packages)) cmd = [ sys.executable, - '-m', 'pip', + '-m', + 'pip', 'install', '--editable', str(sample_project), - '--prefix', str(prefix), + '--prefix', + str(prefix), '--no-build-isolation', ] subprocess.check_call(cmd, env=env) diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py index c4279f0bc4f..2eddc9febde 100644 --- a/setuptools/tests/test_dist.py +++ b/setuptools/tests/test_dist.py @@ -27,30 +27,34 @@ def test_dist_fetch_build_egg(tmpdir): Check multiple calls to `Distribution.fetch_build_egg` work as expected. """ index = tmpdir.mkdir('index') - index_url = urllib.parse.urljoin( - 'file://', urllib.request.pathname2url(str(index))) + index_url = urllib.parse.urljoin('file://', urllib.request.pathname2url(str(index))) def sdist_with_index(distname, version): dist_dir = index.mkdir(distname) dist_sdist = '%s-%s.tar.gz' % (distname, version) make_nspkg_sdist(str(dist_dir.join(dist_sdist)), distname, version) with dist_dir.join('index.html').open('w') as fp: - fp.write(DALS( - ''' + fp.write( + DALS( + ''' {dist_sdist}
''' - ).format(dist_sdist=dist_sdist)) + ).format(dist_sdist=dist_sdist) + ) + sdist_with_index('barbazquux', '3.2.0') sdist_with_index('barbazquux-runner', '2.11.1') with tmpdir.join('setup.cfg').open('w') as fp: - fp.write(DALS( - ''' + fp.write( + DALS( + ''' [easy_install] index_url = {index_url} ''' - ).format(index_url=index_url)) + ).format(index_url=index_url) + ) reqs = ''' barbazquux-runner barbazquux @@ -58,10 +62,7 @@ def sdist_with_index(distname, version): with tmpdir.as_cwd(): dist = Distribution() dist.parse_config_files() - resolved_dists = [ - dist.fetch_build_egg(r) - for r in reqs - ] + resolved_dists = [dist.fetch_build_egg(r) for r in reqs] assert [dist.key for dist in resolved_dists if dist] == reqs @@ -84,22 +85,34 @@ def __read_test_cases(): test_cases = [ ('Metadata version 1.0', params()), - ('Metadata Version 1.0: Short long description', params( - long_description='Short long description', - )), - ('Metadata version 1.1: Classifiers', params( - classifiers=[ - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', - 'License :: OSI Approved :: MIT License', - ], - )), - ('Metadata version 1.1: Download URL', params( - download_url='https://example.com', - )), - ('Metadata Version 1.2: Requires-Python', params( - python_requires='>=3.7', - )), + ( + 'Metadata Version 1.0: Short long description', + params( + long_description='Short long description', + ), + ), + ( + 'Metadata version 1.1: Classifiers', + params( + classifiers=[ + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'License :: OSI Approved :: MIT License', + ], + ), + ), + ( + 'Metadata version 1.1: Download URL', + params( + download_url='https://example.com', + ), + ), + ( + 'Metadata Version 1.2: Requires-Python', + params( + python_requires='>=3.7', + ), + ), pytest.param( 'Metadata Version 1.2: Project-Url', params(project_urls=dict(Foo='https://example.bar')), @@ -107,36 +120,59 @@ def __read_test_cases(): reason="Issue #1578: project_urls not read", ), ), - ('Metadata Version 2.1: Long Description Content Type', params( - long_description_content_type='text/x-rst; charset=UTF-8', - )), - ('License', params(license='MIT', )), - ('License multiline', params( - license='This is a long license \nover multiple lines', - )), + ( + 'Metadata Version 2.1: Long Description Content Type', + params( + long_description_content_type='text/x-rst; charset=UTF-8', + ), + ), + ( + 'License', + params( + license='MIT', + ), + ), + ( + 'License multiline', + params( + license='This is a long license \nover multiple lines', + ), + ), pytest.param( 'Metadata Version 2.1: Provides Extra', params(provides_extras=['foo', 'bar']), marks=pytest.mark.xfail(reason="provides_extras not read"), ), - ('Missing author', dict( - name='foo', - version='1.0.0', - author_email='snorri@sturluson.name', - )), - ('Missing author e-mail', dict( - name='foo', - version='1.0.0', - author='Snorri Sturluson', - )), - ('Missing author and e-mail', dict( - name='foo', - version='1.0.0', - )), - ('Bypass normalized version', dict( - name='foo', - version=sic('1.0.0a'), - )), + ( + 'Missing author', + dict( + name='foo', + version='1.0.0', + author_email='snorri@sturluson.name', + ), + ), + ( + 'Missing author e-mail', + dict( + name='foo', + version='1.0.0', + author='Snorri Sturluson', + ), + ), + ( + 'Missing author and e-mail', + dict( + name='foo', + version='1.0.0', + ), + ), + ( + 'Bypass normalized version', + dict( + name='foo', + version=sic('1.0.0a'), + ), + ), ] return test_cases @@ -181,9 +217,7 @@ def test_read_metadata(name, attrs): def __maintainer_test_cases(): - attrs = {"name": "package", - "version": "1.0", - "description": "xxx"} + attrs = {"name": "package", "version": "1.0", "description": "xxx"} def merge_dicts(d1, d2): d1 = d1.copy() @@ -193,40 +227,60 @@ def merge_dicts(d1, d2): test_cases = [ ('No author, no maintainer', attrs.copy()), - ('Author (no e-mail), no maintainer', merge_dicts( - attrs, - {'author': 'Author Name'})), - ('Author (e-mail), no maintainer', merge_dicts( - attrs, - {'author': 'Author Name', - 'author_email': 'author@name.com'})), - ('No author, maintainer (no e-mail)', merge_dicts( - attrs, - {'maintainer': 'Maintainer Name'})), - ('No author, maintainer (e-mail)', merge_dicts( - attrs, - {'maintainer': 'Maintainer Name', - 'maintainer_email': 'maintainer@name.com'})), - ('Author (no e-mail), Maintainer (no-email)', merge_dicts( - attrs, - {'author': 'Author Name', - 'maintainer': 'Maintainer Name'})), - ('Author (e-mail), Maintainer (e-mail)', merge_dicts( - attrs, - {'author': 'Author Name', - 'author_email': 'author@name.com', - 'maintainer': 'Maintainer Name', - 'maintainer_email': 'maintainer@name.com'})), - ('No author (e-mail), no maintainer (e-mail)', merge_dicts( - attrs, - {'author_email': 'author@name.com', - 'maintainer_email': 'maintainer@name.com'})), - ('Author unicode', merge_dicts( - attrs, - {'author': '鉄沢寛'})), - ('Maintainer unicode', merge_dicts( - attrs, - {'maintainer': 'Jan Łukasiewicz'})), + ( + 'Author (no e-mail), no maintainer', + merge_dicts(attrs, {'author': 'Author Name'}), + ), + ( + 'Author (e-mail), no maintainer', + merge_dicts( + attrs, {'author': 'Author Name', 'author_email': 'author@name.com'} + ), + ), + ( + 'No author, maintainer (no e-mail)', + merge_dicts(attrs, {'maintainer': 'Maintainer Name'}), + ), + ( + 'No author, maintainer (e-mail)', + merge_dicts( + attrs, + { + 'maintainer': 'Maintainer Name', + 'maintainer_email': 'maintainer@name.com', + }, + ), + ), + ( + 'Author (no e-mail), Maintainer (no-email)', + merge_dicts( + attrs, {'author': 'Author Name', 'maintainer': 'Maintainer Name'} + ), + ), + ( + 'Author (e-mail), Maintainer (e-mail)', + merge_dicts( + attrs, + { + 'author': 'Author Name', + 'author_email': 'author@name.com', + 'maintainer': 'Maintainer Name', + 'maintainer_email': 'maintainer@name.com', + }, + ), + ), + ( + 'No author (e-mail), no maintainer (e-mail)', + merge_dicts( + attrs, + { + 'author_email': 'author@name.com', + 'maintainer_email': 'maintainer@name.com', + }, + ), + ), + ('Author unicode', merge_dicts(attrs, {'author': '鉄沢寛'})), + ('Maintainer unicode', merge_dicts(attrs, {'maintainer': 'Jan Łukasiewicz'})), ] return test_cases @@ -277,56 +331,68 @@ def test_provides_extras_deterministic_order(): dist = Distribution(attrs) assert dist.metadata.provides_extras == ['a', 'b'] attrs['extras_require'] = collections.OrderedDict( - reversed(list(attrs['extras_require'].items()))) + reversed(list(attrs['extras_require'].items())) + ) dist = Distribution(attrs) assert dist.metadata.provides_extras == ['b', 'a'] CHECK_PACKAGE_DATA_TESTS = ( # Valid. - ({ - '': ['*.txt', '*.rst'], - 'hello': ['*.msg'], - }, None), + ( + { + '': ['*.txt', '*.rst'], + 'hello': ['*.msg'], + }, + None, + ), # Not a dictionary. - (( - ('', ['*.txt', '*.rst']), - ('hello', ['*.msg']), - ), ( - "'package_data' must be a dictionary mapping package" - " names to lists of string wildcard patterns" - )), + ( + ( + ('', ['*.txt', '*.rst']), + ('hello', ['*.msg']), + ), + ( + "'package_data' must be a dictionary mapping package" + " names to lists of string wildcard patterns" + ), + ), # Invalid key type. - ({ - 400: ['*.txt', '*.rst'], - }, ( - "keys of 'package_data' dict must be strings (got 400)" - )), + ( + { + 400: ['*.txt', '*.rst'], + }, + ("keys of 'package_data' dict must be strings (got 400)"), + ), # Invalid value type. - ({ - 'hello': str('*.msg'), - }, ( - "\"values of 'package_data' dict\" " - "must be a list of strings (got '*.msg')" - )), + ( + { + 'hello': str('*.msg'), + }, + ( + "\"values of 'package_data' dict\" " + "must be a list of strings (got '*.msg')" + ), + ), # Invalid value type (generators are single use) - ({ - 'hello': (x for x in "generator"), - }, ( - "\"values of 'package_data' dict\" must be a list of strings " - "(got =1.1); extra == 'baz' - """) + """ + ) @classmethod def build_metadata(cls, **kwargs): - lines = ( - '{key}: {value}\n'.format(**locals()) - for key, value in kwargs.items() - ) + lines = ('{key}: {value}\n'.format(**locals()) for key, value in kwargs.items()) return cls.metadata_base + ''.join(lines) @pytest.fixture @@ -49,8 +48,7 @@ def metadata(self, tmpdir): def test_distinfo(self, metadata): dists = dict( - (d.project_name, d) - for d in pkg_resources.find_distributions(metadata) + (d.project_name, d) for d in pkg_resources.find_distributions(metadata) ) assert len(dists) == 2, dists diff --git a/setuptools/tests/test_distutils_adoption.py b/setuptools/tests/test_distutils_adoption.py index 0e89921c904..95b46ae30cb 100644 --- a/setuptools/tests/test_distutils_adoption.py +++ b/setuptools/tests/test_distutils_adoption.py @@ -32,8 +32,11 @@ def popen_text(call): """ Augment the Popen call with the parameters to ensure unicode text. """ - return functools.partial(call, universal_newlines=True) \ - if sys.version_info < (3, 7) else functools.partial(call, text=True) + return ( + functools.partial(call, universal_newlines=True) + if sys.version_info < (3, 7) + else functools.partial(call, text=True) + ) def find_distutils(venv, imports='distutils', env=None, **kwargs): diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index 4b2bb2b36ef..2f7c81d764d 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -24,7 +24,9 @@ from setuptools.sandbox import run_setup import setuptools.command.easy_install as ei from setuptools.command.easy_install import ( - EasyInstallDeprecationWarning, ScriptWriter, PthDistributions, + EasyInstallDeprecationWarning, + ScriptWriter, + PthDistributions, WindowsScriptWriter, ) from setuptools.dist import Distribution @@ -58,11 +60,13 @@ def as_requirement(self): return 'spec' -SETUP_PY = DALS(""" +SETUP_PY = DALS( + """ from setuptools import setup setup(name='foo') - """) + """ +) class TestEasyInstallTest: @@ -75,8 +79,7 @@ def test_get_script_args(self): assert "'spec'" in script assert "'console_scripts'" in script assert "'name'" in script - assert re.search( - '^# EASY-INSTALL-ENTRY-SCRIPT', script, flags=re.MULTILINE) + assert re.search('^# EASY-INSTALL-ENTRY-SCRIPT', script, flags=re.MULTILINE) def test_no_find_links(self): # new option '--no-find-links', that blocks find-links added at @@ -120,6 +123,7 @@ def test_all_site_dirs(self, monkeypatch): def mock_gsp(): return [path] + monkeypatch.setattr(site, 'getsitepackages', mock_gsp, raising=False) assert path in ei.get_site_dirs() @@ -132,7 +136,8 @@ def sdist_unicode(self, tmpdir): files = [ ( 'setup.py', - DALS(""" + DALS( + """ import setuptools setuptools.setup( name="setuptools-test-unicode", @@ -140,7 +145,8 @@ def sdist_unicode(self, tmpdir): packages=["mypkg"], include_package_data=True, ) - """), + """ + ), ), ( 'mypkg/__init__.py', @@ -162,8 +168,7 @@ def sdist_unicode(self, tmpdir): return str(sdist) @fail_on_ascii - def test_unicode_filename_in_sdist( - self, sdist_unicode, tmpdir, monkeypatch): + def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): """ The install command should execute correctly even if the package has unicode filenames. @@ -184,7 +189,8 @@ def sdist_unicode_in_script(self, tmpdir): files = [ ( "setup.py", - DALS(""" + DALS( + """ import setuptools setuptools.setup( name="setuptools-test-unicode", @@ -193,7 +199,8 @@ def sdist_unicode_in_script(self, tmpdir): include_package_data=True, scripts=['mypkg/unicode_in_script'], ) - """), + """ + ), ), ("mypkg/__init__.py", ""), ( @@ -205,7 +212,8 @@ def sdist_unicode_in_script(self, tmpdir): non_python_fn() { } - """), + """ + ), ), ] sdist_name = "setuptools-test-unicode-script-1.0.zip" @@ -220,7 +228,8 @@ def sdist_unicode_in_script(self, tmpdir): @fail_on_ascii def test_unicode_content_in_sdist( - self, sdist_unicode_in_script, tmpdir, monkeypatch): + self, sdist_unicode_in_script, tmpdir, monkeypatch + ): """ The install command should execute correctly even if the package has unicode in scripts. @@ -237,21 +246,25 @@ def sdist_script(self, tmpdir): files = [ ( 'setup.py', - DALS(""" + DALS( + """ import setuptools setuptools.setup( name="setuptools-test-script", version="1.0", scripts=["mypkg_script"], ) - """), + """ + ), ), ( 'mypkg_script', - DALS(""" + DALS( + """ #/usr/bin/python print('mypkg_script') - """), + """ + ), ), ] sdist_name = 'setuptools-test-script-1.0.zip' @@ -259,8 +272,9 @@ def sdist_script(self, tmpdir): make_sdist(sdist, files) return sdist - @pytest.mark.skipif(not sys.platform.startswith('linux'), - reason="Test can only be run on Linux") + @pytest.mark.skipif( + not sys.platform.startswith('linux'), reason="Test can only be run on Linux" + ) def test_script_install(self, sdist_script, tmpdir, monkeypatch): """ Check scripts are installed. @@ -297,9 +311,9 @@ def test_dist_WindowsScriptWriter_get_writer_deprecated(self): @pytest.mark.filterwarnings('ignore:Unbuilt egg') class TestPTHFileWriter: def test_add_from_cwd_site_sets_dirty(self): - '''a pth file manager should set dirty + """a pth file manager should set dirty if a distribution is in site but also the cwd - ''' + """ pth = PthDistributions('does-not_exist', [os.getcwd()]) assert not pth.dirty pth.add(PRDistribution(os.getcwd())) @@ -309,7 +323,12 @@ def test_add_from_site_is_ignored(self): location = '/test/location/does-not-have-to-exist' # PthDistributions expects all locations to be normalized location = pkg_resources.normalize_path(location) - pth = PthDistributions('does-not_exist', [location, ]) + pth = PthDistributions( + 'does-not_exist', + [ + location, + ], + ) assert not pth.dirty pth.add(PRDistribution(location)) assert not pth.dirty @@ -404,6 +423,7 @@ def user_install_setup_context(self, *args, **kwargs): """ with self.orig_context(*args, **kwargs): import setuptools.command.easy_install as ei + ei.__file__ = site.USER_SITE yield @@ -446,7 +466,6 @@ def test_bdist_egg_available_on_distutils_pkg(self, distutils_package): class TestSetupRequires: - def test_setup_requires_honors_fetch_params(self, mock_index, monkeypatch): """ When easy_install installs a source distribution which specifies @@ -463,11 +482,14 @@ def test_setup_requires_honors_fetch_params(self, mock_index, monkeypatch): with contexts.environment(PYTHONPATH=temp_install_dir): cmd = [ sys.executable, - '-m', 'setup', + '-m', + 'setup', 'easy_install', - '--index-url', mock_index.url, + '--index-url', + mock_index.url, '--exclude-scripts', - '--install-dir', temp_install_dir, + '--install-dir', + temp_install_dir, dist_file, ] subprocess.Popen(cmd).wait() @@ -483,17 +505,25 @@ def create_sdist(): """ with contexts.tempdir() as dir: dist_path = os.path.join(dir, 'setuptools-test-fetcher-1.0.tar.gz') - make_sdist(dist_path, [ - ('setup.py', DALS(""" + make_sdist( + dist_path, + [ + ( + 'setup.py', + DALS( + """ import setuptools setuptools.setup( name="setuptools-test-fetcher", version="1.0", setup_requires = ['does-not-exist'], ) - """)), - ('setup.cfg', ''), - ]) + """ + ), + ), + ('setup.cfg', ''), + ], + ) yield dist_path use_setup_cfg = ( @@ -514,14 +544,16 @@ def test_setup_requires_overrides_version_conflict(self, use_setup_cfg): requirement is already on the path. """ - fake_dist = PRDistribution('does-not-matter', project_name='foobar', - version='0.0') + fake_dist = PRDistribution( + 'does-not-matter', project_name='foobar', version='0.0' + ) working_set.add(fake_dist) with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: test_pkg = create_setup_requires_package( - temp_dir, use_setup_cfg=use_setup_cfg) + temp_dir, use_setup_cfg=use_setup_cfg + ) test_setup_py = os.path.join(test_pkg, 'setup.py') with contexts.quiet() as (stdout, stderr): # Don't even need to install the package, just @@ -552,11 +584,13 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg): tf.extractall(foobar_1_dir) sys.path.insert(1, foobar_1_dir) - dist = PRDistribution(foobar_1_dir, project_name='foo.bar', - version='0.1') + dist = PRDistribution( + foobar_1_dir, project_name='foo.bar', version='0.1' + ) working_set.add(dist) - template = DALS("""\ + template = DALS( + """\ import foo # Even with foo imported first the # setup_requires package should override import setuptools @@ -568,11 +602,17 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg): if 'foo.bar-0.2' not in foo.__path__[0]: print('FAIL') - """) + """ + ) test_pkg = create_setup_requires_package( - temp_dir, 'foo.bar', '0.2', make_nspkg_sdist, template, - use_setup_cfg=use_setup_cfg) + temp_dir, + 'foo.bar', + '0.2', + make_nspkg_sdist, + template, + use_setup_cfg=use_setup_cfg, + ) test_setup_py = os.path.join(test_pkg, 'setup.py') @@ -584,7 +624,8 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg): except pkg_resources.VersionConflict: self.fail( 'Installing setup.py requirements ' - 'caused a VersionConflict') + 'caused a VersionConflict' + ) assert 'FAIL' not in stdout.getvalue() lines = stdout.readlines() @@ -594,27 +635,38 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg): @pytest.mark.parametrize('use_setup_cfg', use_setup_cfg) def test_setup_requires_with_attr_version(self, use_setup_cfg): def make_dependency_sdist(dist_path, distname, version): - files = [( - 'setup.py', - DALS(""" + files = [ + ( + 'setup.py', + DALS( + """ import setuptools setuptools.setup( name={name!r}, version={version!r}, py_modules=[{name!r}], ) - """.format(name=distname, version=version)), - ), ( - distname + '.py', - DALS(""" + """.format( + name=distname, version=version + ) + ), + ), + ( + distname + '.py', + DALS( + """ version = 42 - """), - )] + """ + ), + ), + ] make_sdist(dist_path, files) + with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: test_pkg = create_setup_requires_package( - temp_dir, setup_attrs=dict(version='attr: foobar.version'), + temp_dir, + setup_attrs=dict(version='attr: foobar.version'), make_package=make_dependency_sdist, use_setup_cfg=use_setup_cfg + ('version',), ) @@ -633,15 +685,21 @@ def test_setup_requires_honors_pip_env(self, mock_index, monkeypatch): with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: test_pkg = create_setup_requires_package( - temp_dir, 'python-xlib', '0.19', - setup_attrs=dict(dependency_links=[])) + temp_dir, + 'python-xlib', + '0.19', + setup_attrs=dict(dependency_links=[]), + ) test_setup_cfg = os.path.join(test_pkg, 'setup.cfg') with open(test_setup_cfg, 'w') as fp: - fp.write(DALS( - ''' + fp.write( + DALS( + ''' [easy_install] index_url = https://pypi.org/legacy/ - ''')) + ''' + ) + ) test_setup_py = os.path.join(test_pkg, 'setup.py') with pytest.raises(distutils.errors.DistutilsError): run_setup(test_setup_py, [str('--version')]) @@ -660,9 +718,10 @@ def test_setup_requires_with_pep508_url(self, mock_index, monkeypatch): test_pkg = create_setup_requires_package( temp_dir, # Ignored (overridden by setup_attrs) - 'python-xlib', '0.19', - setup_attrs=dict( - setup_requires='dependency @ %s' % dep_url)) + 'python-xlib', + '0.19', + setup_attrs=dict(setup_requires='dependency @ %s' % dep_url), + ) test_setup_py = os.path.join(test_pkg, 'setup.py') run_setup(test_setup_py, [str('--version')]) assert len(mock_index.requests) == 0 @@ -676,17 +735,23 @@ def test_setup_requires_with_allow_hosts(self, mock_index): test_setup_cfg = os.path.join(test_pkg, 'setup.cfg') os.mkdir(test_pkg) with open(test_setup_py, 'w') as fp: - fp.write(DALS( - ''' + fp.write( + DALS( + ''' from setuptools import setup setup(setup_requires='python-xlib') - ''')) - with open(test_setup_cfg, 'w') as fp: - fp.write(DALS( ''' + ) + ) + with open(test_setup_cfg, 'w') as fp: + fp.write( + DALS( + ''' [easy_install] allow_hosts = * - ''')) + ''' + ) + ) with pytest.raises(distutils.errors.DistutilsError): run_setup(test_setup_py, [str('--version')]) assert len(mock_index.requests) == 0 @@ -701,16 +766,18 @@ def test_setup_requires_with_python_requires(self, monkeypatch, tmpdir): dep_1_0_url = path_to_url(str(tmpdir / dep_1_0_sdist)) dep_1_0_python_requires = '>=2.7' make_python_requires_sdist( - str(tmpdir / dep_1_0_sdist), 'dep', '1.0', dep_1_0_python_requires) + str(tmpdir / dep_1_0_sdist), 'dep', '1.0', dep_1_0_python_requires + ) dep_2_0_sdist = 'dep-2.0.tar.gz' dep_2_0_url = path_to_url(str(tmpdir / dep_2_0_sdist)) - dep_2_0_python_requires = '!=' + '.'.join( - map(str, sys.version_info[:2])) + '.*' + dep_2_0_python_requires = '!=' + '.'.join(map(str, sys.version_info[:2])) + '.*' make_python_requires_sdist( - str(tmpdir / dep_2_0_sdist), 'dep', '2.0', dep_2_0_python_requires) + str(tmpdir / dep_2_0_sdist), 'dep', '2.0', dep_2_0_python_requires + ) index = tmpdir / 'index.html' - index.write_text(DALS( - ''' + index.write_text( + DALS( + ''' Links for dep @@ -719,41 +786,43 @@ def test_setup_requires_with_python_requires(self, monkeypatch, tmpdir): {dep_2_0_sdist}
- ''').format( # noqa + ''' + ).format( # noqa dep_1_0_url=dep_1_0_url, dep_1_0_sdist=dep_1_0_sdist, dep_1_0_python_requires=dep_1_0_python_requires, dep_2_0_url=dep_2_0_url, dep_2_0_sdist=dep_2_0_sdist, dep_2_0_python_requires=dep_2_0_python_requires, - ), 'utf-8') + ), + 'utf-8', + ) index_url = path_to_url(str(index)) with contexts.save_pkg_resources_state(): test_pkg = create_setup_requires_package( str(tmpdir), - 'python-xlib', '0.19', # Ignored (overridden by setup_attrs). - setup_attrs=dict( - setup_requires='dep', dependency_links=[index_url])) + 'python-xlib', + '0.19', # Ignored (overridden by setup_attrs). + setup_attrs=dict(setup_requires='dep', dependency_links=[index_url]), + ) test_setup_py = os.path.join(test_pkg, 'setup.py') run_setup(test_setup_py, [str('--version')]) - eggs = list(map(str, pkg_resources.find_distributions( - os.path.join(test_pkg, '.eggs')))) + eggs = list( + map(str, pkg_resources.find_distributions(os.path.join(test_pkg, '.eggs'))) + ) assert eggs == ['dep 1.0'] - @pytest.mark.parametrize( - 'with_dependency_links_in_setup_py', - (False, True)) + @pytest.mark.parametrize('with_dependency_links_in_setup_py', (False, True)) def test_setup_requires_with_find_links_in_setup_cfg( - self, monkeypatch, - with_dependency_links_in_setup_py): + self, monkeypatch, with_dependency_links_in_setup_py + ): monkeypatch.setenv(str('PIP_RETRIES'), str('0')) monkeypatch.setenv(str('PIP_TIMEOUT'), str('0')) with contexts.save_pkg_resources_state(): with contexts.tempdir() as temp_dir: make_trivial_sdist( - os.path.join(temp_dir, 'python-xlib-42.tar.gz'), - 'python-xlib', - '42') + os.path.join(temp_dir, 'python-xlib-42.tar.gz'), 'python-xlib', '42' + ) test_pkg = os.path.join(temp_dir, 'test_pkg') test_setup_py = os.path.join(test_pkg, 'setup.py') test_setup_cfg = os.path.join(test_pkg, 'setup.cfg') @@ -763,25 +832,31 @@ def test_setup_requires_with_find_links_in_setup_cfg( dependency_links = [os.path.join(temp_dir, 'links')] else: dependency_links = [] - fp.write(DALS( - ''' + fp.write( + DALS( + ''' from setuptools import installer, setup setup(setup_requires='python-xlib==42', dependency_links={dependency_links!r}) - ''').format( - dependency_links=dependency_links)) - with open(test_setup_cfg, 'w') as fp: - fp.write(DALS( ''' + ).format(dependency_links=dependency_links) + ) + with open(test_setup_cfg, 'w') as fp: + fp.write( + DALS( + ''' [easy_install] index_url = {index_url} find_links = {find_links} - ''').format(index_url=os.path.join(temp_dir, 'index'), - find_links=temp_dir)) + ''' + ).format( + index_url=os.path.join(temp_dir, 'index'), + find_links=temp_dir, + ) + ) run_setup(test_setup_py, [str('--version')]) - def test_setup_requires_with_transitive_extra_dependency( - self, monkeypatch): + def test_setup_requires_with_transitive_extra_dependency(self, monkeypatch): # Use case: installing a package with a build dependency on # an already installed `dep[extra]`, which in turn depends # on `extra_dep` (whose is not already installed). @@ -789,36 +864,42 @@ def test_setup_requires_with_transitive_extra_dependency( with contexts.tempdir() as temp_dir: # Create source distribution for `extra_dep`. make_trivial_sdist( - os.path.join(temp_dir, 'extra_dep-1.0.tar.gz'), - 'extra_dep', '1.0') + os.path.join(temp_dir, 'extra_dep-1.0.tar.gz'), 'extra_dep', '1.0' + ) # Create source tree for `dep`. dep_pkg = os.path.join(temp_dir, 'dep') os.mkdir(dep_pkg) - path.build({ - 'setup.py': - DALS(""" + path.build( + { + 'setup.py': DALS( + """ import setuptools setuptools.setup( name='dep', version='2.0', extras_require={'extra': ['extra_dep']}, ) - """), - 'setup.cfg': '', - }, prefix=dep_pkg) + """ + ), + 'setup.cfg': '', + }, + prefix=dep_pkg, + ) # "Install" dep. - run_setup( - os.path.join(dep_pkg, 'setup.py'), [str('dist_info')]) + run_setup(os.path.join(dep_pkg, 'setup.py'), [str('dist_info')]) working_set.add_entry(dep_pkg) # Create source tree for test package. test_pkg = os.path.join(temp_dir, 'test_pkg') test_setup_py = os.path.join(test_pkg, 'setup.py') os.mkdir(test_pkg) with open(test_setup_py, 'w') as fp: - fp.write(DALS( - ''' + fp.write( + DALS( + ''' from setuptools import installer, setup setup(setup_requires='dep[extra]') - ''')) + ''' + ) + ) # Check... monkeypatch.setenv(str('PIP_FIND_LINKS'), str(temp_dir)) monkeypatch.setenv(str('PIP_NO_INDEX'), str('1')) @@ -833,17 +914,25 @@ def make_trivial_sdist(dist_path, distname, version): setup.py. """ - make_sdist(dist_path, [ - ('setup.py', - DALS("""\ + make_sdist( + dist_path, + [ + ( + 'setup.py', + DALS( + """\ import setuptools setuptools.setup( name=%r, version=%r ) - """ % (distname, version))), - ('setup.cfg', ''), - ]) + """ + % (distname, version) + ), + ), + ('setup.cfg', ''), + ], + ) def make_nspkg_sdist(dist_path, distname, version): @@ -858,7 +947,8 @@ def make_nspkg_sdist(dist_path, distname, version): packages = ['.'.join(parts[:idx]) for idx in range(1, len(parts) + 1)] - setup_py = DALS("""\ + setup_py = DALS( + """\ import setuptools setuptools.setup( name=%r, @@ -866,12 +956,13 @@ def make_nspkg_sdist(dist_path, distname, version): packages=%r, namespace_packages=[%r] ) - """ % (distname, version, packages, nspackage)) + """ + % (distname, version, packages, nspackage) + ) init = "__import__('pkg_resources').declare_namespace(__name__)" - files = [('setup.py', setup_py), - (os.path.join(nspackage, '__init__.py'), init)] + files = [('setup.py', setup_py), (os.path.join(nspackage, '__init__.py'), init)] for package in packages[1:]: filename = os.path.join(*(package.split('.') + ['__init__.py'])) files.append((filename, '')) @@ -880,21 +971,27 @@ def make_nspkg_sdist(dist_path, distname, version): def make_python_requires_sdist(dist_path, distname, version, python_requires): - make_sdist(dist_path, [ - ( - 'setup.py', - DALS("""\ + make_sdist( + dist_path, + [ + ( + 'setup.py', + DALS( + """\ import setuptools setuptools.setup( name={name!r}, version={version!r}, python_requires={python_requires!r}, ) - """).format( - name=distname, version=version, - python_requires=python_requires)), - ('setup.cfg', ''), - ]) + """ + ).format( + name=distname, version=version, python_requires=python_requires + ), + ), + ('setup.cfg', ''), + ], + ) def make_sdist(dist_path, files): @@ -914,10 +1011,15 @@ def make_sdist(dist_path, files): dist.addfile(file_info, fileobj=file_bytes) -def create_setup_requires_package(path, distname='foobar', version='0.1', - make_package=make_trivial_sdist, - setup_py_template=None, setup_attrs={}, - use_setup_cfg=()): +def create_setup_requires_package( + path, + distname='foobar', + version='0.1', + make_package=make_trivial_sdist, + setup_py_template=None, + setup_attrs={}, + use_setup_cfg=(), +): """Creates a source tree under path for a trivial test package that has a single requirement in setup_requires--a tarball for that requirement is also created and added to the dependency_links argument. @@ -928,9 +1030,10 @@ def create_setup_requires_package(path, distname='foobar', version='0.1', """ test_setup_attrs = { - 'name': 'test_pkg', 'version': '0.0', + 'name': 'test_pkg', + 'version': '0.0', 'setup_requires': ['%s==%s' % (distname, version)], - 'dependency_links': [os.path.abspath(path)] + 'dependency_links': [os.path.abspath(path)], } test_setup_attrs.update(setup_attrs) @@ -968,10 +1071,12 @@ def create_setup_requires_package(path, distname='foobar', version='0.1', # setup.py if setup_py_template is None: - setup_py_template = DALS("""\ + setup_py_template = DALS( + """\ import setuptools setuptools.setup(**%r) - """) + """ + ) with open(os.path.join(test_pkg, 'setup.py'), 'w') as f: f.write(setup_py_template % test_setup_attrs) @@ -983,7 +1088,7 @@ def create_setup_requires_package(path, distname='foobar', version='0.1', @pytest.mark.skipif( sys.platform.startswith('java') and ei.is_sh(sys.executable), - reason="Test cannot run under java when executable is sh" + reason="Test cannot run under java when executable is sh", ) class TestScriptHeader: non_ascii_exe = '/Users/José/bin/python' @@ -995,22 +1100,21 @@ def test_get_script_header(self): assert actual == expected def test_get_script_header_args(self): - expected = '#!%s -x\n' % ei.nt_quote_arg( - os.path.normpath(sys.executable)) + expected = '#!%s -x\n' % ei.nt_quote_arg(os.path.normpath(sys.executable)) actual = ei.ScriptWriter.get_header('#!/usr/bin/python -x') assert actual == expected def test_get_script_header_non_ascii_exe(self): actual = ei.ScriptWriter.get_header( - '#!/usr/bin/python', - executable=self.non_ascii_exe) + '#!/usr/bin/python', executable=self.non_ascii_exe + ) expected = str('#!%s -x\n') % self.non_ascii_exe assert actual == expected def test_get_script_header_exe_with_spaces(self): actual = ei.ScriptWriter.get_header( - '#!/usr/bin/python', - executable='"' + self.exe_with_spaces + '"') + '#!/usr/bin/python', executable='"' + self.exe_with_spaces + '"' + ) expected = '#!"%s"\n' % self.exe_with_spaces assert actual == expected diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index ee07b5a1be3..e5851198696 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -11,7 +11,10 @@ from jaraco import path from setuptools.command.egg_info import ( - egg_info, manifest_maker, EggInfoDeprecationWarning, get_pkg_info_revision, + egg_info, + manifest_maker, + EggInfoDeprecationWarning, + get_pkg_info_revision, ) from setuptools.dist import Distribution @@ -26,7 +29,8 @@ class Environment(str): class TestEggInfo: - setup_script = DALS(""" + setup_script = DALS( + """ from setuptools import setup setup( @@ -35,16 +39,21 @@ class TestEggInfo: entry_points={'console_scripts': ['hi = hello.run']}, zip_safe=False, ) - """) + """ + ) def _create_project(self): - path.build({ - 'setup.py': self.setup_script, - 'hello.py': DALS(""" + path.build( + { + 'setup.py': self.setup_script, + 'hello.py': DALS( + """ def run(): print('hello') - """) - }) + """ + ), + } + ) @staticmethod def _extract_mv_version(pkg_info_lines: List[str]) -> Tuple[int, int]: @@ -58,18 +67,22 @@ def env(self): os.chmod(env_dir, stat.S_IRWXU) subs = 'home', 'lib', 'scripts', 'data', 'egg-base' env.paths = dict( - (dirname, os.path.join(env_dir, dirname)) - for dirname in subs + (dirname, os.path.join(env_dir, dirname)) for dirname in subs ) list(map(os.mkdir, env.paths.values())) - path.build({ - env.paths['home']: { - '.pydistutils.cfg': DALS(""" + path.build( + { + env.paths['home']: { + '.pydistutils.cfg': DALS( + """ [egg_info] egg-base = %(egg-base)s - """ % env.paths) + """ + % env.paths + ) + } } - }) + ) yield env def test_egg_info_save_version_info_setup_empty(self, tmpdir_cwd, env): @@ -91,7 +104,10 @@ def test_egg_info_save_version_info_setup_empty(self, tmpdir_cwd, env): assert 'tag_build =' in content assert 'tag_date = 0' in content - expected_order = 'tag_build', 'tag_date', + expected_order = ( + 'tag_build', + 'tag_date', + ) self._validate_content_order(content, expected_order) @@ -112,13 +128,17 @@ def test_egg_info_save_version_info_setup_defaults(self, tmpdir_cwd, env): the file should remain unchanged. """ setup_cfg = os.path.join(env.paths['home'], 'setup.cfg') - path.build({ - setup_cfg: DALS(""" + path.build( + { + setup_cfg: DALS( + """ [egg_info] tag_build = tag_date = 0 - """), - }) + """ + ), + } + ) dist = Distribution() ei = egg_info(dist) ei.initialize_options() @@ -131,7 +151,10 @@ def test_egg_info_save_version_info_setup_defaults(self, tmpdir_cwd, env): assert 'tag_build =' in content assert 'tag_date = 0' in content - expected_order = 'tag_build', 'tag_date', + expected_order = ( + 'tag_build', + 'tag_date', + ) self._validate_content_order(content, expected_order) @@ -152,23 +175,29 @@ def test_expected_files_produced(self, tmpdir_cwd, env): assert sorted(actual) == expected def test_license_is_a_string(self, tmpdir_cwd, env): - setup_config = DALS(""" + setup_config = DALS( + """ [metadata] name=foo version=0.0.1 license=file:MIT - """) + """ + ) - setup_script = DALS(""" + setup_script = DALS( + """ from setuptools import setup setup() - """) + """ + ) - path.build({ - 'setup.py': setup_script, - 'setup.cfg': setup_config, - }) + path.build( + { + 'setup.py': setup_script, + 'setup.cfg': setup_config, + } + ) # This command should fail with a ValueError, but because it's # currently configured to use a subprocess, the actual traceback @@ -192,7 +221,7 @@ def test_rebuilt(self, tmpdir_cwd, env): timestamp_a = os.path.getmtime('foo.egg-info') # arbitrary sleep just to handle *really* fast systems - time.sleep(.001) + time.sleep(0.001) self._run_egg_info_command(tmpdir_cwd, env) timestamp_b = os.path.getmtime('foo.egg-info') @@ -201,14 +230,18 @@ def test_rebuilt(self, tmpdir_cwd, env): def test_manifest_template_is_read(self, tmpdir_cwd, env): self._create_project() - path.build({ - 'MANIFEST.in': DALS(""" + path.build( + { + 'MANIFEST.in': DALS( + """ recursive-include docs *.rst - """), - 'docs': { - 'usage.rst': "Run 'hi'", + """ + ), + 'docs': { + 'usage.rst': "Run 'hi'", + }, } - }) + ) self._run_egg_info_command(tmpdir_cwd, env) egg_info_dir = os.path.join('.', 'foo.egg-info') sources_txt = os.path.join(egg_info_dir, 'SOURCES.txt') @@ -216,18 +249,23 @@ def test_manifest_template_is_read(self, tmpdir_cwd, env): assert 'docs/usage.rst' in f.read().split('\n') def _setup_script_with_requires(self, requires, use_setup_cfg=False): - setup_script = DALS( - ''' + setup_script = ( + DALS( + ''' from setuptools import setup setup(name='foo', zip_safe=False, %s) ''' - ) % ('' if use_setup_cfg else requires) + ) + % ('' if use_setup_cfg else requires) + ) setup_config = requires if use_setup_cfg else '' - path.build({ - 'setup.py': setup_script, - 'setup.cfg': setup_config, - }) + path.build( + { + 'setup.py': setup_script, + 'setup.cfg': setup_config, + } + ) mismatch_marker = "python_version<'{this_ver}'".format( this_ver=sys.version_info[0], @@ -239,7 +277,6 @@ def _setup_script_with_requires(self, requires, use_setup_cfg=False): invalid_marker = "<=>++" class RequiresTestHelper: - @staticmethod def parametrize(*test_list, **format_dict): idlist = [] @@ -265,14 +302,19 @@ def parametrize(*test_list, **format_dict): if requires.startswith('@xfail\n'): requires = requires[7:] marks = pytest.mark.xfail - argvalues.append(pytest.param(requires, use_cfg, - expected_requires, - install_cmd_kwargs, - marks=marks)) + argvalues.append( + pytest.param( + requires, + use_cfg, + expected_requires, + install_cmd_kwargs, + marks=marks, + ) + ) return pytest.mark.parametrize( - 'requires,use_setup_cfg,' - 'expected_requires,install_cmd_kwargs', - argvalues, ids=idlist, + 'requires,use_setup_cfg,' 'expected_requires,install_cmd_kwargs', + argvalues, + ids=idlist, ) @RequiresTestHelper.parametrize( @@ -286,7 +328,6 @@ def parametrize(*test_list, **format_dict): # requires block (when used in setup.cfg) # # expected contents of requires.txt - ''' install_requires_deterministic @@ -300,7 +341,6 @@ def parametrize(*test_list, **format_dict): wheel>=0.5 pytest ''', - ''' install_requires_ordered @@ -312,7 +352,6 @@ def parametrize(*test_list, **format_dict): pytest!=10.9999,>=3.0.2 ''', - ''' install_requires_with_marker @@ -325,7 +364,6 @@ def parametrize(*test_list, **format_dict): [:{mismatch_marker_alternate}] barbazquux ''', - ''' install_requires_with_extra {'cmd': ['egg_info']} @@ -338,7 +376,6 @@ def parametrize(*test_list, **format_dict): barbazquux[test] ''', - ''' install_requires_with_extra_and_marker @@ -351,7 +388,6 @@ def parametrize(*test_list, **format_dict): [:{mismatch_marker_alternate}] barbazquux[test] ''', - ''' setup_requires_with_markers @@ -362,7 +398,6 @@ def parametrize(*test_list, **format_dict): barbazquux; {mismatch_marker} ''', - ''' tests_require_with_markers {'cmd': ['test'], 'output': "Ran 0 tests in"} @@ -374,7 +409,6 @@ def parametrize(*test_list, **format_dict): barbazquux; {mismatch_marker} ''', - ''' extras_require_with_extra {'cmd': ['egg_info']} @@ -387,7 +421,6 @@ def parametrize(*test_list, **format_dict): [extra] barbazquux[test] ''', - ''' extras_require_with_extra_and_marker_in_req @@ -402,7 +435,6 @@ def parametrize(*test_list, **format_dict): [extra:{mismatch_marker_alternate}] barbazquux[test] ''', - # FIXME: ConfigParser does not allow : in key names! ''' extras_require_with_marker @@ -416,7 +448,6 @@ def parametrize(*test_list, **format_dict): [:{mismatch_marker}] barbazquux ''', - ''' extras_require_with_marker_in_req @@ -431,7 +462,6 @@ def parametrize(*test_list, **format_dict): [extra:{mismatch_marker_alternate}] barbazquux ''', - ''' extras_require_with_empty_section @@ -448,8 +478,14 @@ def parametrize(*test_list, **format_dict): mismatch_marker_alternate=mismatch_marker_alternate, ) def test_requires( - self, tmpdir_cwd, env, requires, use_setup_cfg, - expected_requires, install_cmd_kwargs): + self, + tmpdir_cwd, + env, + requires, + use_setup_cfg, + expected_requires, + install_cmd_kwargs, + ): self._setup_script_with_requires(requires, use_setup_cfg) self._run_egg_info_command(tmpdir_cwd, env, **install_cmd_kwargs) egg_info_dir = os.path.join('.', 'foo.egg-info') @@ -490,8 +526,7 @@ def test_extras_require_with_invalid_marker_in_req(self, tmpdir_cwd, env): assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == [] def test_provides_extra(self, tmpdir_cwd, env): - self._setup_script_with_requires( - 'extras_require={"foobar": ["barbazquux"]},') + self._setup_script_with_requires('extras_require={"foobar": ["barbazquux"]},') environ = os.environ.copy().update( HOME=env.paths['home'], ) @@ -509,7 +544,8 @@ def test_provides_extra(self, tmpdir_cwd, env): def test_doesnt_provides_extra(self, tmpdir_cwd, env): self._setup_script_with_requires( - '''install_requires=["spam ; python_version<'3.6'"]''') + '''install_requires=["spam ; python_version<'3.6'"]''' + ) environ = os.environ.copy().update( HOME=env.paths['home'], ) @@ -524,51 +560,78 @@ def test_doesnt_provides_extra(self, tmpdir_cwd, env): pkg_info_text = pkginfo_file.read() assert 'Provides-Extra:' not in pkg_info_text - @pytest.mark.parametrize("files, license_in_sources", [ - ({ - 'setup.cfg': DALS(""" + @pytest.mark.parametrize( + "files, license_in_sources", + [ + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE - """), - 'LICENSE': "Test license" - }, True), # with license - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE': "Test license", + }, + True, + ), # with license + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = INVALID_LICENSE - """), - 'LICENSE': "Test license" - }, False), # with an invalid license - ({ - 'setup.cfg': DALS(""" - """), - 'LICENSE': "Test license" - }, True), # no license_file attribute, LICENSE auto-included - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE': "Test license", + }, + False, + ), # with an invalid license + ( + { + 'setup.cfg': DALS( + """ + """ + ), + 'LICENSE': "Test license", + }, + True, + ), # no license_file attribute, LICENSE auto-included + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE - """), - 'MANIFEST.in': "exclude LICENSE", - 'LICENSE': "Test license" - }, True), # manifest is overwritten by license_file - pytest.param({ - 'setup.cfg': DALS(""" + """ + ), + 'MANIFEST.in': "exclude LICENSE", + 'LICENSE': "Test license", + }, + True, + ), # manifest is overwritten by license_file + pytest.param( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICEN[CS]E* - """), - 'LICENSE': "Test license", - }, True, - id="glob_pattern"), - ]) - def test_setup_cfg_license_file( - self, tmpdir_cwd, env, files, license_in_sources): + """ + ), + 'LICENSE': "Test license", + }, + True, + id="glob_pattern", + ), + ], + ) + def test_setup_cfg_license_file(self, tmpdir_cwd, env, files, license_in_sources): self._create_project() path.build(files) environment.run_setup_py( cmd=['egg_info'], - pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]) + pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]), ) egg_info_dir = os.path.join('.', 'foo.egg-info') @@ -582,133 +645,206 @@ def test_setup_cfg_license_file( # for invalid license test assert 'INVALID_LICENSE' not in sources_text - @pytest.mark.parametrize("files, incl_licenses, excl_licenses", [ - ({ - 'setup.cfg': DALS(""" + @pytest.mark.parametrize( + "files, incl_licenses, excl_licenses", + [ + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE-ABC LICENSE-XYZ - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - }, ['LICENSE-ABC', 'LICENSE-XYZ'], []), # with licenses - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license", + }, + ['LICENSE-ABC', 'LICENSE-XYZ'], + [], + ), # with licenses + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE-ABC, LICENSE-XYZ - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - }, ['LICENSE-ABC', 'LICENSE-XYZ'], []), # with commas - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license", + }, + ['LICENSE-ABC', 'LICENSE-XYZ'], + [], + ), # with commas + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE-ABC - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - }, ['LICENSE-ABC'], ['LICENSE-XYZ']), # with one license - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license", + }, + ['LICENSE-ABC'], + ['LICENSE-XYZ'], + ), # with one license + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - }, [], ['LICENSE-ABC', 'LICENSE-XYZ']), # empty - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license", + }, + [], + ['LICENSE-ABC', 'LICENSE-XYZ'], + ), # empty + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE-XYZ - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - }, ['LICENSE-XYZ'], ['LICENSE-ABC']), # on same line - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license", + }, + ['LICENSE-XYZ'], + ['LICENSE-ABC'], + ), # on same line + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE-ABC INVALID_LICENSE - """), - 'LICENSE-ABC': "Test license" - }, ['LICENSE-ABC'], ['INVALID_LICENSE']), # with an invalid license - ({ - 'setup.cfg': DALS(""" - """), - 'LICENSE': "Test license" - }, ['LICENSE'], []), # no license_files attribute, LICENSE auto-included - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "Test license", + }, + ['LICENSE-ABC'], + ['INVALID_LICENSE'], + ), # with an invalid license + ( + { + 'setup.cfg': DALS( + """ + """ + ), + 'LICENSE': "Test license", + }, + ['LICENSE'], + [], + ), # no license_files attribute, LICENSE auto-included + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE - """), - 'MANIFEST.in': "exclude LICENSE", - 'LICENSE': "Test license" - }, ['LICENSE'], []), # manifest is overwritten by license_files - ({ - 'setup.cfg': DALS(""" + """ + ), + 'MANIFEST.in': "exclude LICENSE", + 'LICENSE': "Test license", + }, + ['LICENSE'], + [], + ), # manifest is overwritten by license_files + ( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE-ABC LICENSE-XYZ - """), - 'MANIFEST.in': "exclude LICENSE-XYZ", - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - # manifest is overwritten by license_files - }, ['LICENSE-ABC', 'LICENSE-XYZ'], []), - pytest.param({ - 'setup.cfg': "", - 'LICENSE-ABC': "ABC license", - 'COPYING-ABC': "ABC copying", - 'NOTICE-ABC': "ABC notice", - 'AUTHORS-ABC': "ABC authors", - 'LICENCE-XYZ': "XYZ license", - 'LICENSE': "License", - 'INVALID-LICENSE': "Invalid license", - }, [ - 'LICENSE-ABC', - 'COPYING-ABC', - 'NOTICE-ABC', - 'AUTHORS-ABC', - 'LICENCE-XYZ', - 'LICENSE', - ], ['INVALID-LICENSE'], - # ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') - id="default_glob_patterns"), - pytest.param({ - 'setup.cfg': DALS(""" + """ + ), + 'MANIFEST.in': "exclude LICENSE-XYZ", + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license" + # manifest is overwritten by license_files + }, + ['LICENSE-ABC', 'LICENSE-XYZ'], + [], + ), + pytest.param( + { + 'setup.cfg': "", + 'LICENSE-ABC': "ABC license", + 'COPYING-ABC': "ABC copying", + 'NOTICE-ABC': "ABC notice", + 'AUTHORS-ABC': "ABC authors", + 'LICENCE-XYZ': "XYZ license", + 'LICENSE': "License", + 'INVALID-LICENSE': "Invalid license", + }, + [ + 'LICENSE-ABC', + 'COPYING-ABC', + 'NOTICE-ABC', + 'AUTHORS-ABC', + 'LICENCE-XYZ', + 'LICENSE', + ], + ['INVALID-LICENSE'], + # ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*') + id="default_glob_patterns", + ), + pytest.param( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE* - """), - 'LICENSE-ABC': "ABC license", - 'NOTICE-XYZ': "XYZ notice", - }, ['LICENSE-ABC'], ['NOTICE-XYZ'], - id="no_default_glob_patterns"), - pytest.param({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'NOTICE-XYZ': "XYZ notice", + }, + ['LICENSE-ABC'], + ['NOTICE-XYZ'], + id="no_default_glob_patterns", + ), + pytest.param( + { + 'setup.cfg': DALS( + """ [metadata] license_files = LICENSE-ABC LICENSE* - """), - 'LICENSE-ABC': "ABC license", - }, ['LICENSE-ABC'], [], - id="files_only_added_once", - ), - ]) + """ + ), + 'LICENSE-ABC': "ABC license", + }, + ['LICENSE-ABC'], + [], + id="files_only_added_once", + ), + ], + ) def test_setup_cfg_license_files( - self, tmpdir_cwd, env, files, incl_licenses, excl_licenses): + self, tmpdir_cwd, env, files, incl_licenses, excl_licenses + ): self._create_project() path.build(files) environment.run_setup_py( cmd=['egg_info'], - pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]) + pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]), ) egg_info_dir = os.path.join('.', 'foo.egg-info') @@ -721,120 +857,178 @@ def test_setup_cfg_license_files( for lf in excl_licenses: assert sources_lines.count(lf) == 0 - @pytest.mark.parametrize("files, incl_licenses, excl_licenses", [ - ({ - 'setup.cfg': DALS(""" + @pytest.mark.parametrize( + "files, incl_licenses, excl_licenses", + [ + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = license_files = - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - }, [], ['LICENSE-ABC', 'LICENSE-XYZ']), # both empty - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license", + }, + [], + ['LICENSE-ABC', 'LICENSE-XYZ'], + ), # both empty + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE-ABC LICENSE-XYZ - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-XYZ': "XYZ license" - # license_file is still singular - }, [], ['LICENSE-ABC', 'LICENSE-XYZ']), - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-XYZ': "XYZ license" + # license_file is still singular + }, + [], + ['LICENSE-ABC', 'LICENSE-XYZ'], + ), + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE-ABC license_files = LICENSE-XYZ LICENSE-PQR - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-PQR': "PQR license", - 'LICENSE-XYZ': "XYZ license" - }, ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], []), # combined - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-PQR': "PQR license", + 'LICENSE-XYZ': "XYZ license", + }, + ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], + [], + ), # combined + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE-ABC license_files = LICENSE-ABC LICENSE-XYZ LICENSE-PQR - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-PQR': "PQR license", - 'LICENSE-XYZ': "XYZ license" - # duplicate license - }, ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], []), - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-PQR': "PQR license", + 'LICENSE-XYZ': "XYZ license" + # duplicate license + }, + ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], + [], + ), + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE-ABC license_files = LICENSE-XYZ - """), - 'LICENSE-ABC': "ABC license", - 'LICENSE-PQR': "PQR license", - 'LICENSE-XYZ': "XYZ license" - # combined subset - }, ['LICENSE-ABC', 'LICENSE-XYZ'], ['LICENSE-PQR']), - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'LICENSE-PQR': "PQR license", + 'LICENSE-XYZ': "XYZ license" + # combined subset + }, + ['LICENSE-ABC', 'LICENSE-XYZ'], + ['LICENSE-PQR'], + ), + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE-ABC license_files = LICENSE-XYZ LICENSE-PQR - """), - 'LICENSE-PQR': "Test license" - # with invalid licenses - }, ['LICENSE-PQR'], ['LICENSE-ABC', 'LICENSE-XYZ']), - ({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-PQR': "Test license" + # with invalid licenses + }, + ['LICENSE-PQR'], + ['LICENSE-ABC', 'LICENSE-XYZ'], + ), + ( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE-ABC license_files = LICENSE-PQR LICENSE-XYZ - """), - 'MANIFEST.in': "exclude LICENSE-ABC\nexclude LICENSE-PQR", - 'LICENSE-ABC': "ABC license", - 'LICENSE-PQR': "PQR license", - 'LICENSE-XYZ': "XYZ license" - # manifest is overwritten - }, ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], []), - pytest.param({ - 'setup.cfg': DALS(""" + """ + ), + 'MANIFEST.in': "exclude LICENSE-ABC\nexclude LICENSE-PQR", + 'LICENSE-ABC': "ABC license", + 'LICENSE-PQR': "PQR license", + 'LICENSE-XYZ': "XYZ license" + # manifest is overwritten + }, + ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], + [], + ), + pytest.param( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE* - """), - 'LICENSE-ABC': "ABC license", - 'NOTICE-XYZ': "XYZ notice", - }, ['LICENSE-ABC'], ['NOTICE-XYZ'], - id="no_default_glob_patterns"), - pytest.param({ - 'setup.cfg': DALS(""" + """ + ), + 'LICENSE-ABC': "ABC license", + 'NOTICE-XYZ': "XYZ notice", + }, + ['LICENSE-ABC'], + ['NOTICE-XYZ'], + id="no_default_glob_patterns", + ), + pytest.param( + { + 'setup.cfg': DALS( + """ [metadata] license_file = LICENSE* license_files = NOTICE* - """), - 'LICENSE-ABC': "ABC license", - 'NOTICE-ABC': "ABC notice", - 'AUTHORS-ABC': "ABC authors", - }, ['LICENSE-ABC', 'NOTICE-ABC'], ['AUTHORS-ABC'], - id="combined_glob_patterrns"), - ]) + """ + ), + 'LICENSE-ABC': "ABC license", + 'NOTICE-ABC': "ABC notice", + 'AUTHORS-ABC': "ABC authors", + }, + ['LICENSE-ABC', 'NOTICE-ABC'], + ['AUTHORS-ABC'], + id="combined_glob_patterrns", + ), + ], + ) def test_setup_cfg_license_file_license_files( - self, tmpdir_cwd, env, files, incl_licenses, excl_licenses): + self, tmpdir_cwd, env, files, incl_licenses, excl_licenses + ): self._create_project() path.build(files) environment.run_setup_py( cmd=['egg_info'], - pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]) + pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]), ) egg_info_dir = os.path.join('.', 'foo.egg-info') @@ -850,28 +1044,33 @@ def test_setup_cfg_license_file_license_files( def test_license_file_attr_pkg_info(self, tmpdir_cwd, env): """All matched license files should have a corresponding License-File.""" self._create_project() - path.build({ - "setup.cfg": DALS(""" + path.build( + { + "setup.cfg": DALS( + """ [metadata] license_files = NOTICE* LICENSE* - """), - "LICENSE-ABC": "ABC license", - "LICENSE-XYZ": "XYZ license", - "NOTICE": "included", - "IGNORE": "not include", - }) + """ + ), + "LICENSE-ABC": "ABC license", + "LICENSE-XYZ": "XYZ license", + "NOTICE": "included", + "IGNORE": "not include", + } + ) environment.run_setup_py( cmd=['egg_info'], - pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]) + pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]), ) egg_info_dir = os.path.join('.', 'foo.egg-info') with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file: pkg_info_lines = pkginfo_file.read().split('\n') license_file_lines = [ - line for line in pkg_info_lines if line.startswith('License-File:')] + line for line in pkg_info_lines if line.startswith('License-File:') + ] # Only 'NOTICE', LICENSE-ABC', and 'LICENSE-XYZ' should have been matched # Also assert that order from license_files is keeped @@ -902,7 +1101,8 @@ def test_long_description_content_type(self, tmpdir_cwd, env): # https://github.com/pypa/python-packaging-user-guide/pull/258 self._setup_script_with_requires( - """long_description_content_type='text/markdown',""") + """long_description_content_type='text/markdown',""" + ) environ = os.environ.copy().update( HOME=env.paths['home'], ) @@ -938,7 +1138,7 @@ def test_long_description(self, tmpdir_cwd, env): pkg_info_lines = pkginfo_file.read().split('\n') assert 'Metadata-Version: 2.1' in pkg_info_lines assert '' == pkg_info_lines[-1] # last line should be empty - long_desc_lines = pkg_info_lines[pkg_info_lines.index(''):] + long_desc_lines = pkg_info_lines[pkg_info_lines.index('') :] assert 'This is a long description' in long_desc_lines assert 'over multiple lines' in long_desc_lines @@ -954,7 +1154,8 @@ def test_project_urls(self, tmpdir_cwd, env): """project_urls={ 'Link One': 'https://example.com/one/', 'Link Two': 'https://example.com/two/', - },""") + },""" + ) environ = os.environ.copy().update( HOME=env.paths['home'], ) @@ -975,9 +1176,7 @@ def test_project_urls(self, tmpdir_cwd, env): def test_license(self, tmpdir_cwd, env): """Test single line license.""" - self._setup_script_with_requires( - "license='MIT'," - ) + self._setup_script_with_requires("license='MIT',") code, data = environment.run_setup_py( cmd=['egg_info'], pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]), @@ -1007,8 +1206,7 @@ def test_license_escape(self, tmpdir_cwd, env): assert 'text \n over multiple' in '\n'.join(pkg_info_lines) def test_python_requires_egg_info(self, tmpdir_cwd, env): - self._setup_script_with_requires( - """python_requires='>=2.7.12',""") + self._setup_script_with_requires("""python_requires='>=2.7.12',""") environ = os.environ.copy().update( HOME=env.paths['home'], ) @@ -1027,7 +1225,7 @@ def test_python_requires_egg_info(self, tmpdir_cwd, env): def test_manifest_maker_warning_suppression(self): fixtures = [ "standard file not found: should have one of foo.py, bar.py", - "standard file 'setup.py' not found" + "standard file 'setup.py' not found", ] for msg in fixtures: @@ -1068,14 +1266,18 @@ def _run_egg_info_command(self, tmpdir_cwd, env, cmd=None, output=None): def test_egg_info_tag_only_once(self, tmpdir_cwd, env): self._create_project() - path.build({ - 'setup.cfg': DALS(""" + path.build( + { + 'setup.cfg': DALS( + """ [egg_info] tag_build = dev tag_date = 0 tag_svn_revision = 0 - """), - }) + """ + ), + } + ) self._run_egg_info_command(tmpdir_cwd, env) egg_info_dir = os.path.join('.', 'foo.egg-info') with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file: diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py index 906713f61da..f70eb8415b1 100644 --- a/setuptools/tests/test_find_packages.py +++ b/setuptools/tests/test_find_packages.py @@ -29,7 +29,8 @@ def can_symlink(): def has_symlink(): bad_symlink = ( # Windows symlink directory detection is broken on Python 3.2 - platform.system() == 'Windows' and sys.version_info[:2] == (3, 2) + platform.system() == 'Windows' + and sys.version_info[:2] == (3, 2) ) return can_symlink() and not bad_symlink @@ -152,25 +153,24 @@ def _assert_packages(self, actual, expected): def test_pep420_ns_package(self): packages = find_namespace_packages( - self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets']) + self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets'] + ) self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg']) def test_pep420_ns_package_no_includes(self): - packages = find_namespace_packages( - self.dist_dir, exclude=['pkg.subpkg.assets']) - self._assert_packages( - packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg']) + packages = find_namespace_packages(self.dist_dir, exclude=['pkg.subpkg.assets']) + self._assert_packages(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg']) def test_pep420_ns_package_no_includes_or_excludes(self): packages = find_namespace_packages(self.dist_dir) - expected = [ - 'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets'] + expected = ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets'] self._assert_packages(packages, expected) def test_regular_package_with_nested_pep420_ns_packages(self): self._touch('__init__.py', self.pkg_dir) packages = find_namespace_packages( - self.dist_dir, exclude=['docs', 'pkg.subpkg.assets']) + self.dist_dir, exclude=['docs', 'pkg.subpkg.assets'] + ) self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg']) def test_pep420_ns_package_no_non_package_dirs(self): diff --git a/setuptools/tests/test_glob.py b/setuptools/tests/test_glob.py index e99587f5688..42b3c43a210 100644 --- a/setuptools/tests/test_glob.py +++ b/setuptools/tests/test_glob.py @@ -4,10 +4,13 @@ from setuptools.glob import glob -@pytest.mark.parametrize('tree, pattern, matches', ( - ('', b'', []), - ('', '', []), - (''' +@pytest.mark.parametrize( + 'tree, pattern, matches', + ( + ('', b'', []), + ('', '', []), + ( + ''' appveyor.yml CHANGES.rst LICENSE @@ -16,8 +19,12 @@ README.rst setup.cfg setup.py - ''', '*.rst', ('CHANGES.rst', 'README.rst')), - (''' + ''', + '*.rst', + ('CHANGES.rst', 'README.rst'), + ), + ( + ''' appveyor.yml CHANGES.rst LICENSE @@ -26,8 +33,12 @@ README.rst setup.cfg setup.py - ''', b'*.rst', (b'CHANGES.rst', b'README.rst')), -)) + ''', + b'*.rst', + (b'CHANGES.rst', b'README.rst'), + ), + ), +) def test_glob(monkeypatch, tmpdir, tree, pattern, matches): monkeypatch.chdir(tmpdir) path.build({name: '' for name in tree.split()}) diff --git a/setuptools/tests/test_integration.py b/setuptools/tests/test_integration.py index b557831216f..e17ffc5d5c9 100644 --- a/setuptools/tests/test_integration.py +++ b/setuptools/tests/test_integration.py @@ -16,8 +16,7 @@ pytestmark = pytest.mark.skipif( - 'platform.python_implementation() == "PyPy" and ' - 'platform.system() == "Windows"', + 'platform.python_implementation() == "PyPy" and ' 'platform.system() == "Windows"', reason="pypa/setuptools#2496", ) @@ -40,8 +39,7 @@ def setup_module(module): @pytest.fixture def install_context(request, tmpdir, monkeypatch): - """Fixture to set up temporary installation directory. - """ + """Fixture to set up temporary installation directory.""" # Save old values so we can restore them. new_cwd = tmpdir.mkdir('cwd') user_base = tmpdir.mkdir('user_base') @@ -86,25 +84,23 @@ def _install_one(requirement, cmd, pkgname, modulename): def test_stevedore(install_context): - _install_one('stevedore', install_context, - 'stevedore', 'extension.py') + _install_one('stevedore', install_context, 'stevedore', 'extension.py') @pytest.mark.xfail def test_virtualenvwrapper(install_context): - _install_one('virtualenvwrapper', install_context, - 'virtualenvwrapper', 'hook_loader.py') + _install_one( + 'virtualenvwrapper', install_context, 'virtualenvwrapper', 'hook_loader.py' + ) def test_pbr(install_context): - _install_one('pbr', install_context, - 'pbr', 'core.py') + _install_one('pbr', install_context, 'pbr', 'core.py') @pytest.mark.xfail def test_python_novaclient(install_context): - _install_one('python-novaclient', install_context, - 'novaclient', 'base.py') + _install_one('python-novaclient', install_context, 'novaclient', 'base.py') def test_pyuri(install_context): diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py index 82bdb9c6432..da4c26c340c 100644 --- a/setuptools/tests/test_manifest.py +++ b/setuptools/tests/test_manifest.py @@ -29,11 +29,14 @@ def make_local_path(s): 'packages': ['app'], } -SETUP_PY = """\ +SETUP_PY = ( + """\ from setuptools import setup setup(**%r) -""" % SETUP_ATTRS +""" + % SETUP_ATTRS +) @contextlib.contextmanager @@ -52,30 +55,31 @@ def touch(filename): # The set of files always in the manifest, including all files in the # .egg-info directory -default_files = frozenset(map(make_local_path, [ - 'README.rst', - 'MANIFEST.in', - 'setup.py', - 'app.egg-info/PKG-INFO', - 'app.egg-info/SOURCES.txt', - 'app.egg-info/dependency_links.txt', - 'app.egg-info/top_level.txt', - 'app/__init__.py', -])) +default_files = frozenset( + map( + make_local_path, + [ + 'README.rst', + 'MANIFEST.in', + 'setup.py', + 'app.egg-info/PKG-INFO', + 'app.egg-info/SOURCES.txt', + 'app.egg-info/dependency_links.txt', + 'app.egg-info/top_level.txt', + 'app/__init__.py', + ], + ) +) translate_specs = [ ('foo', ['foo'], ['bar', 'foobar']), ('foo/bar', ['foo/bar'], ['foo/bar/baz', './foo/bar', 'foo']), - # Glob matching ('*.txt', ['foo.txt', 'bar.txt'], ['foo/foo.txt']), - ( - 'dir/*.txt', - ['dir/foo.txt', 'dir/bar.txt', 'dir/.txt'], ['notdir/foo.txt']), + ('dir/*.txt', ['dir/foo.txt', 'dir/bar.txt', 'dir/.txt'], ['notdir/foo.txt']), ('*/*.py', ['bin/start.py'], []), ('docs/page-?.txt', ['docs/page-9.txt'], ['docs/page-10.txt']), - # Globstars change what they mean depending upon where they are ( 'foo/**/bar', @@ -92,32 +96,27 @@ def touch(filename): ['x', 'abc/xyz', '@nything'], [], ), - # Character classes ( 'pre[one]post', ['preopost', 'prenpost', 'preepost'], ['prepost', 'preonepost'], ), - ( 'hello[!one]world', ['helloxworld', 'helloyworld'], ['hellooworld', 'helloworld', 'hellooneworld'], ), - ( '[]one].txt', ['o.txt', '].txt', 'e.txt'], ['one].txt'], ), - ( 'foo[!]one]bar', ['fooybar'], ['foo]bar', 'fooobar', 'fooebar'], ), - ] """ A spec of inputs for 'translate_pattern' and matches and mismatches @@ -235,8 +234,7 @@ def test_empty_files(self): def test_include(self): """Include extra rst files in the project root.""" self.make_manifest("include *.rst") - files = default_files | set([ - 'testing.rst', '.hidden.rst']) + files = default_files | set(['testing.rst', '.hidden.rst']) assert files == self.get_files() def test_exclude(self): @@ -246,7 +244,8 @@ def test_exclude(self): """ include app/* exclude app/*.txt - """) + """ + ) files = default_files | set([ml('app/c.rst')]) assert files == self.get_files() @@ -254,28 +253,44 @@ def test_include_multiple(self): """Include with multiple patterns.""" ml = make_local_path self.make_manifest("include app/*.txt app/static/*") - files = default_files | set([ - ml('app/a.txt'), ml('app/b.txt'), - ml('app/static/app.js'), ml('app/static/app.js.map'), - ml('app/static/app.css'), ml('app/static/app.css.map')]) + files = default_files | set( + [ + ml('app/a.txt'), + ml('app/b.txt'), + ml('app/static/app.js'), + ml('app/static/app.js.map'), + ml('app/static/app.css'), + ml('app/static/app.css.map'), + ] + ) assert files == self.get_files() def test_graft(self): """Include the whole app/static/ directory.""" ml = make_local_path self.make_manifest("graft app/static") - files = default_files | set([ - ml('app/static/app.js'), ml('app/static/app.js.map'), - ml('app/static/app.css'), ml('app/static/app.css.map')]) + files = default_files | set( + [ + ml('app/static/app.js'), + ml('app/static/app.js.map'), + ml('app/static/app.css'), + ml('app/static/app.css.map'), + ] + ) assert files == self.get_files() def test_graft_glob_syntax(self): """Include the whole app/static/ directory.""" ml = make_local_path self.make_manifest("graft */static") - files = default_files | set([ - ml('app/static/app.js'), ml('app/static/app.js.map'), - ml('app/static/app.css'), ml('app/static/app.css.map')]) + files = default_files | set( + [ + ml('app/static/app.js'), + ml('app/static/app.js.map'), + ml('app/static/app.css'), + ml('app/static/app.css.map'), + ] + ) assert files == self.get_files() def test_graft_global_exclude(self): @@ -285,9 +300,9 @@ def test_graft_global_exclude(self): """ graft app/static global-exclude *.map - """) - files = default_files | set([ - ml('app/static/app.js'), ml('app/static/app.css')]) + """ + ) + files = default_files | set([ml('app/static/app.js'), ml('app/static/app.css')]) assert files == self.get_files() def test_global_include(self): @@ -296,10 +311,17 @@ def test_global_include(self): self.make_manifest( """ global-include *.rst *.js *.css - """) - files = default_files | set([ - '.hidden.rst', 'testing.rst', ml('app/c.rst'), - ml('app/static/app.js'), ml('app/static/app.css')]) + """ + ) + files = default_files | set( + [ + '.hidden.rst', + 'testing.rst', + ml('app/c.rst'), + ml('app/static/app.js'), + ml('app/static/app.css'), + ] + ) assert files == self.get_files() def test_graft_prune(self): @@ -309,9 +331,9 @@ def test_graft_prune(self): """ graft app prune app/static - """) - files = default_files | set([ - ml('app/a.txt'), ml('app/b.txt'), ml('app/c.rst')]) + """ + ) + files = default_files | set([ml('app/a.txt'), ml('app/b.txt'), ml('app/c.rst')]) assert files == self.get_files() @@ -343,8 +365,8 @@ def _format(msg, args): if len(args) == 0: return msg return msg % args - return [_format(msg, args) for level, msg, args - in self.logs if level in levels] + + return [_format(msg, args) for level, msg, args in self.logs if level in levels] def clear_logs(self): self.logs = [] @@ -370,24 +392,30 @@ def test_process_template_line(self): ml = make_local_path # simulated file list - self.make_files([ - 'foo.tmp', 'ok', 'xo', 'four.txt', - 'buildout.cfg', - # filelist does not filter out VCS directories, - # it's sdist that does - ml('.hg/last-message.txt'), - ml('global/one.txt'), - ml('global/two.txt'), - ml('global/files.x'), - ml('global/here.tmp'), - ml('f/o/f.oo'), - ml('dir/graft-one'), - ml('dir/dir2/graft2'), - ml('dir3/ok'), - ml('dir3/sub/ok.txt'), - ]) - - MANIFEST_IN = DALS("""\ + self.make_files( + [ + 'foo.tmp', + 'ok', + 'xo', + 'four.txt', + 'buildout.cfg', + # filelist does not filter out VCS directories, + # it's sdist that does + ml('.hg/last-message.txt'), + ml('global/one.txt'), + ml('global/two.txt'), + ml('global/files.x'), + ml('global/here.tmp'), + ml('f/o/f.oo'), + ml('dir/graft-one'), + ml('dir/dir2/graft2'), + ml('dir3/ok'), + ml('dir3/sub/ok.txt'), + ] + ) + + MANIFEST_IN = DALS( + """\ include ok include xo exclude xo @@ -400,7 +428,8 @@ def test_process_template_line(self): recursive-exclude global *.x graft dir prune dir3 - """) + """ + ) for line in MANIFEST_IN.split('\n'): if not line: @@ -460,9 +489,17 @@ def test_include_pattern(self): def test_process_template_line_invalid(self): # invalid lines file_list = FileList() - for action in ('include', 'exclude', 'global-include', - 'global-exclude', 'recursive-include', - 'recursive-exclude', 'graft', 'prune', 'blarg'): + for action in ( + 'include', + 'exclude', + 'global-include', + 'global-exclude', + 'recursive-include', + 'recursive-exclude', + 'graft', + 'prune', + 'blarg', + ): try: file_list.process_template_line(action) except DistutilsTemplateError: diff --git a/setuptools/tests/test_msvc.py b/setuptools/tests/test_msvc.py index d1527bfa46d..0ae1a5cd674 100644 --- a/setuptools/tests/test_msvc.py +++ b/setuptools/tests/test_msvc.py @@ -35,23 +35,19 @@ def mock_reg(hkcu=None, hklm=None): def read_keys(cls, base, key): """Return list of registry keys.""" hive = hives.get(base, {}) - return [ - k.rpartition('\\')[2] - for k in hive if k.startswith(key.lower()) - ] + return [k.rpartition('\\')[2] for k in hive if k.startswith(key.lower())] @classmethod def read_values(cls, base, key): """Return dict of registry keys and values.""" hive = hives.get(base, {}) return dict( - (k.rpartition('\\')[2], hive[k]) - for k in hive if k.startswith(key.lower()) + (k.rpartition('\\')[2], hive[k]) for k in hive if k.startswith(key.lower()) ) return mock.patch.multiple( - distutils.msvc9compiler.Reg, - read_keys=read_keys, read_values=read_values) + distutils.msvc9compiler.Reg, read_keys=read_keys, read_values=read_values + ) class TestModulePatch: diff --git a/setuptools/tests/test_msvc14.py b/setuptools/tests/test_msvc14.py index 1aca12dd376..59284fd8b20 100644 --- a/setuptools/tests/test_msvc14.py +++ b/setuptools/tests/test_msvc14.py @@ -9,12 +9,13 @@ import sys -@pytest.mark.skipif(sys.platform != "win32", - reason="These tests are only for win32") +@pytest.mark.skipif(sys.platform != "win32", reason="These tests are only for win32") class TestMSVC14: """Python 3.8 "distutils/tests/test_msvccompiler.py" backport""" + def test_no_compiler(self): import setuptools.msvc as _msvccompiler + # makes sure query_vcvarsall raises # a DistutilsPlatformError if the compiler # is not found @@ -25,9 +26,11 @@ def _find_vcvarsall(plat_spec): old_find_vcvarsall = _msvccompiler._msvc14_find_vcvarsall _msvccompiler._msvc14_find_vcvarsall = _find_vcvarsall try: - pytest.raises(DistutilsPlatformError, - _msvccompiler._msvc14_get_vc_env, - 'wont find this version') + pytest.raises( + DistutilsPlatformError, + _msvccompiler._msvc14_get_vc_env, + 'wont find this version', + ) finally: _msvccompiler._msvc14_find_vcvarsall = old_find_vcvarsall @@ -55,9 +58,7 @@ def test_get_vc2017(self): # This function cannot be mocked, so pass it if we find VS 2017 # and mark it skipped if we do not. version, path = _msvccompiler._msvc14_find_vc2017() - if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in [ - 'Visual Studio 2017' - ]: + if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in ['Visual Studio 2017']: assert version if version: assert version >= 15 @@ -72,7 +73,8 @@ def test_get_vc2015(self): # and mark it skipped if we do not. version, path = _msvccompiler._msvc14_find_vc2015() if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in [ - 'Visual Studio 2015', 'Visual Studio 2017' + 'Visual Studio 2015', + 'Visual Studio 2017', ]: assert version if version: diff --git a/setuptools/tests/test_namespaces.py b/setuptools/tests/test_namespaces.py index 270f90c98b0..cc54cc9f730 100644 --- a/setuptools/tests/test_namespaces.py +++ b/setuptools/tests/test_namespaces.py @@ -8,7 +8,6 @@ class TestNamespaces: - @pytest.mark.skipif( sys.version_info < (3, 5), reason="Requires importlib.util.module_from_spec", @@ -32,7 +31,8 @@ def test_mixed_site_and_non_site(self, tmpdir): 'pip.__main__', 'install', str(pkg_A), - '-t', str(site_packages), + '-t', + str(site_packages), ] subprocess.check_call(install_cmd) namespaces.make_site_dir(site_packages) @@ -42,12 +42,14 @@ def test_mixed_site_and_non_site(self, tmpdir): 'pip.__main__', 'install', str(pkg_B), - '-t', str(path_packages), + '-t', + str(path_packages), ] subprocess.check_call(install_cmd) try_import = [ sys.executable, - '-c', 'import myns.pkgA; import myns.pkgB', + '-c', + 'import myns.pkgA; import myns.pkgB', ] with test.test.paths_on_pythonpath(map(str, targets)): subprocess.check_call(try_import) @@ -62,9 +64,11 @@ def test_pkg_resources_import(self, tmpdir): target.mkdir() install_cmd = [ sys.executable, - '-m', 'pip', + '-m', + 'pip', 'install', - '-t', str(target), + '-t', + str(target), str(pkg), ] with test.test.paths_on_pythonpath([str(target)]): @@ -72,7 +76,8 @@ def test_pkg_resources_import(self, tmpdir): namespaces.make_site_dir(target) try_import = [ sys.executable, - '-c', 'import pkg_resources', + '-c', + 'import pkg_resources', ] with test.test.paths_on_pythonpath([str(target)]): subprocess.check_call(try_import) @@ -91,7 +96,8 @@ def test_namespace_package_installed_and_cwd(self, tmpdir): 'pip.__main__', 'install', str(pkg_A), - '-t', str(target), + '-t', + str(target), ] subprocess.check_call(install_cmd) namespaces.make_site_dir(target) @@ -99,7 +105,8 @@ def test_namespace_package_installed_and_cwd(self, tmpdir): # ensure that package imports and pkg_resources imports pkg_resources_imp = [ sys.executable, - '-c', 'import pkg_resources; import myns.pkgA', + '-c', + 'import pkg_resources; import myns.pkgA', ] with test.test.paths_on_pythonpath([str(target)]): subprocess.check_call(pkg_resources_imp, cwd=str(pkg_A)) @@ -120,7 +127,8 @@ def test_packages_in_the_same_namespace_installed_and_cwd(self, tmpdir): 'pip.__main__', 'install', str(pkg_A), - '-t', str(target), + '-t', + str(target), ] subprocess.check_call(install_cmd) namespaces.make_site_dir(target) @@ -128,7 +136,8 @@ def test_packages_in_the_same_namespace_installed_and_cwd(self, tmpdir): # ensure that all packages import and pkg_resources imports pkg_resources_imp = [ sys.executable, - '-c', 'import pkg_resources; import myns.pkgA; import myns.pkgB', + '-c', + 'import pkg_resources; import myns.pkgA; import myns.pkgB', ] with test.test.paths_on_pythonpath([str(target)]): subprocess.check_call(pkg_resources_imp, cwd=str(pkg_B)) diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py index 8e9435efef0..c6c914de25d 100644 --- a/setuptools/tests/test_packageindex.py +++ b/setuptools/tests/test_packageindex.py @@ -21,7 +21,9 @@ def test_regex(self): Name (md5) - """.lstrip().format(**locals()) + """.lstrip().format( + **locals() + ) assert setuptools.package_index.PYPI_MD5.match(doc) def test_bad_url_bad_port(self): @@ -38,9 +40,7 @@ def test_bad_url_typo(self): # issue 16 # easy_install inquant.contentmirror.plone breaks because of a typo # in its home URL - index = setuptools.package_index.PackageIndex( - hosts=('www.example.com',) - ) + index = setuptools.package_index.PackageIndex(hosts=('www.example.com',)) url = ( 'url:%20https://svn.plone.org/svn' @@ -54,9 +54,7 @@ def test_bad_url_typo(self): assert isinstance(v, urllib.error.HTTPError) def test_bad_url_bad_status_line(self): - index = setuptools.package_index.PackageIndex( - hosts=('www.example.com',) - ) + index = setuptools.package_index.PackageIndex(hosts=('www.example.com',)) def _urlopen(*args): raise http.client.BadStatusLine('line') @@ -74,9 +72,7 @@ def test_bad_url_double_scheme(self): """ A bad URL with a double scheme should raise a DistutilsError. """ - index = setuptools.package_index.PackageIndex( - hosts=('www.example.com',) - ) + index = setuptools.package_index.PackageIndex(hosts=('www.example.com',)) # issue 20 url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk' @@ -93,22 +89,17 @@ def test_bad_url_double_scheme(self): raise RuntimeError("Did not raise") def test_bad_url_screwy_href(self): - index = setuptools.package_index.PackageIndex( - hosts=('www.example.com',) - ) + index = setuptools.package_index.PackageIndex(hosts=('www.example.com',)) # issue #160 if sys.version_info[0] == 2 and sys.version_info[1] == 7: # this should not fail url = 'http://example.com' - page = ('') + page = '' index.process_index(url, page) def test_url_ok(self): - index = setuptools.package_index.PackageIndex( - hosts=('www.example.com',) - ) + index = setuptools.package_index.PackageIndex(hosts=('www.example.com',)) url = 'file:///tmp/test_package_index' assert index.url_ok(url, True) @@ -169,9 +160,7 @@ def test_egg_fragment(self): 'b0', 'rc0', ] - post = [ - '.post0' - ] + post = ['.post0'] dev = [ '.dev0', ] @@ -186,10 +175,14 @@ def test_egg_fragment(self): for e in epoch for r in releases for p in sum([pre, post, dev], ['']) - for locs in local] + for locs in local + ] for v, vc in versions: - dists = list(setuptools.package_index.distros_for_url( - 'http://example.com/example.zip#egg=example-' + v)) + dists = list( + setuptools.package_index.distros_for_url( + 'http://example.com/example.zip#egg=example-' + v + ) + ) assert dists[0].version == '' assert dists[1].version == vc @@ -204,8 +197,7 @@ def test_download_git_with_rev(self, tmpdir): expected_dir = str(tmpdir / 'project@master') expected = ( - 'git clone --quiet ' - 'https://github.example/group/project {expected_dir}' + 'git clone --quiet ' 'https://github.example/group/project {expected_dir}' ).format(**locals()) first_call_args = os_system_mock.call_args_list[0][0] assert first_call_args == (expected,) @@ -226,8 +218,7 @@ def test_download_git_no_rev(self, tmpdir): expected_dir = str(tmpdir / 'project') expected = ( - 'git clone --quiet ' - 'https://github.example/group/project {expected_dir}' + 'git clone --quiet ' 'https://github.example/group/project {expected_dir}' ).format(**locals()) os_system_mock.assert_called_once_with(expected) @@ -243,8 +234,7 @@ def test_download_svn(self, tmpdir): expected_dir = str(tmpdir / 'project') expected = ( - 'svn checkout -q ' - 'svn+https://svn.example/project {expected_dir}' + 'svn checkout -q ' 'svn+https://svn.example/project {expected_dir}' ).format(**locals()) os_system_mock.assert_called_once_with(expected) @@ -252,7 +242,8 @@ def test_download_svn(self, tmpdir): class TestContentCheckers: def test_md5(self): checker = setuptools.package_index.HashChecker.from_url( - 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') + 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478' + ) checker.feed('You should probably not be using MD5'.encode('ascii')) assert checker.hash.hexdigest() == 'f12895fdffbd45007040d2e44df98478' assert checker.is_valid() @@ -260,25 +251,27 @@ def test_md5(self): def test_other_fragment(self): "Content checks should succeed silently if no hash is present" checker = setuptools.package_index.HashChecker.from_url( - 'http://foo/bar#something%20completely%20different') + 'http://foo/bar#something%20completely%20different' + ) checker.feed('anything'.encode('ascii')) assert checker.is_valid() def test_blank_md5(self): "Content checks should succeed if a hash is empty" - checker = setuptools.package_index.HashChecker.from_url( - 'http://foo/bar#md5=') + checker = setuptools.package_index.HashChecker.from_url('http://foo/bar#md5=') checker.feed('anything'.encode('ascii')) assert checker.is_valid() def test_get_hash_name_md5(self): checker = setuptools.package_index.HashChecker.from_url( - 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') + 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478' + ) assert checker.hash_name == 'md5' def test_report(self): checker = setuptools.package_index.HashChecker.from_url( - 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') + 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478' + ) rep = checker.report(lambda x: x, 'My message about %s') assert rep == 'My message about md5' @@ -287,8 +280,8 @@ def test_report(self): def temp_home(tmpdir, monkeypatch): key = ( 'USERPROFILE' - if platform.system() == 'Windows' and sys.version_info > (3, 8) else - 'HOME' + if platform.system() == 'Windows' and sys.version_info > (3, 8) + else 'HOME' ) monkeypatch.setitem(os.environ, key, str(tmpdir)) @@ -298,12 +291,16 @@ def temp_home(tmpdir, monkeypatch): class TestPyPIConfig: def test_percent_in_password(self, temp_home): pypirc = temp_home / '.pypirc' - pypirc.write(DALS(""" + pypirc.write( + DALS( + """ [pypi] repository=https://pypi.org username=jaraco password=pity% - """)) + """ + ) + ) cfg = setuptools.package_index.PyPIConfig() cred = cfg.creds_by_repository['https://pypi.org'] assert cred.username == 'jaraco' diff --git a/setuptools/tests/test_sandbox.py b/setuptools/tests/test_sandbox.py index 99398cdb93b..4cbae2b6799 100644 --- a/setuptools/tests/test_sandbox.py +++ b/setuptools/tests/test_sandbox.py @@ -26,9 +26,7 @@ def test_setup_py_with_BOM(self): """ It should be possible to execute a setup.py with a Byte Order Mark """ - target = pkg_resources.resource_filename( - __name__, - 'script-with-bom.py') + target = pkg_resources.resource_filename(__name__, 'script-with-bom.py') namespace = types.ModuleType('namespace') setuptools.sandbox._execfile(target, vars(namespace)) assert namespace.result == 'passed' @@ -76,6 +74,7 @@ def test_no_exception_passes_quietly(self): def test_unpickleable_exception(self): class CantPickleThis(Exception): "This Exception is unpickleable because it's not in globals" + def __repr__(self): return 'CantPickleThis%r' % (self.args,) @@ -103,7 +102,7 @@ class ExceptionUnderTest(Exception): setuptools.sandbox.hide_setuptools() raise ExceptionUnderTest() - msg, = caught.value.args + (msg,) = caught.value.args assert msg == 'ExceptionUnderTest()' def test_sandbox_violation_raised_hiding_setuptools(self, tmpdir): diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py index 049fdcc05a3..c3774567ea6 100644 --- a/setuptools/tests/test_sdist.py +++ b/setuptools/tests/test_sdist.py @@ -25,11 +25,14 @@ 'data_files': [("data", [os.path.join("d", "e.dat")])], } -SETUP_PY = """\ +SETUP_PY = ( + """\ from setuptools import setup setup(**%r) -""" % SETUP_ATTRS +""" + % SETUP_ATTRS +) @contextlib.contextmanager @@ -389,8 +392,7 @@ def test_sdist_with_utf8_encoded_filename(self): @classmethod def make_strings(cls, item): if isinstance(item, dict): - return { - key: cls.make_strings(value) for key, value in item.items()} + return {key: cls.make_strings(value) for key, value in item.items()} if isinstance(item, list): return list(map(cls.make_strings, item)) return str(item) diff --git a/setuptools/tests/test_setuptools.py b/setuptools/tests/test_setuptools.py index 42f8e18bef9..a7fec5d4a43 100644 --- a/setuptools/tests/test_setuptools.py +++ b/setuptools/tests/test_setuptools.py @@ -73,10 +73,13 @@ def testFindModule(self): @needs_bytecode def testModuleExtract(self): from json import __version__ + assert dep.get_module_constant('json', '__version__') == __version__ assert dep.get_module_constant('sys', 'version') == sys.version - assert dep.get_module_constant( - 'setuptools.tests.test_setuptools', '__doc__') == __doc__ + assert ( + dep.get_module_constant('setuptools.tests.test_setuptools', '__doc__') + == __doc__ + ) @needs_bytecode def testRequire(self): @@ -89,6 +92,7 @@ def testRequire(self): assert req.full_name() == 'Json-1.0.3' from json import __version__ + assert req.get_version() == __version__ assert req.version_ok('1.0.9') assert not req.version_ok('0.9.1') @@ -119,6 +123,7 @@ def test_require_present(self): assert req.homepage == 'http://example.com' from setuptools.tests import __path__ + paths = [os.path.dirname(p) for p in __path__] assert req.is_present(paths) assert req.is_current(paths) @@ -217,7 +222,7 @@ def testInvalidIncludeExclude(self): class TestCommandTests: def testTestIsCommand(self): test_cmd = makeSetup().get_command_obj('test') - assert (isinstance(test_cmd, distutils.cmd.Command)) + assert isinstance(test_cmd, distutils.cmd.Command) def testLongOptSuiteWNoDefault(self): ts1 = makeSetup(script_args=['test', '--test-suite=foo.tests.suite']) @@ -232,8 +237,7 @@ def testDefaultSuite(self): def testDefaultWModuleOnCmdLine(self): ts3 = makeSetup( - test_suite='bar.tests', - script_args=['test', '-m', 'foo.tests'] + test_suite='bar.tests', script_args=['test', '-m', 'foo.tests'] ).get_command_obj('test') ts3.ensure_finalized() assert ts3.test_module == 'foo.tests' diff --git a/setuptools/tests/test_sphinx_upload_docs.py b/setuptools/tests/test_sphinx_upload_docs.py index cc5b8293bf4..da6d396b3b9 100644 --- a/setuptools/tests/test_sphinx_upload_docs.py +++ b/setuptools/tests/test_sphinx_upload_docs.py @@ -8,17 +8,19 @@ @pytest.fixture def sphinx_doc_sample_project(tmpdir_cwd): - path.build({ - 'setup.py': 'from setuptools import setup; setup()', - 'build': { - 'docs': { - 'conf.py': 'project="test"', - 'index.rst': ".. toctree::\ + path.build( + { + 'setup.py': 'from setuptools import setup; setup()', + 'build': { + 'docs': { + 'conf.py': 'project="test"', + 'index.rst': ".. toctree::\ :maxdepth: 2\ :caption: Contents:", + }, }, - }, - }) + } + ) @pytest.mark.usefixtures('sphinx_doc_sample_project') diff --git a/setuptools/tests/test_test.py b/setuptools/tests/test_test.py index 180562e2633..e0a5f78d06e 100644 --- a/setuptools/tests/test_test.py +++ b/setuptools/tests/test_test.py @@ -11,7 +11,8 @@ from .textwrap import DALS -SETUP_PY = DALS(""" +SETUP_PY = DALS( + """ from setuptools import setup setup(name='foo', @@ -19,9 +20,11 @@ namespace_packages=['name'], test_suite='name.space.tests.test_suite', ) - """) + """ +) -NS_INIT = DALS(""" +NS_INIT = DALS( + """ # -*- coding: Latin-1 -*- # Söme Arbiträry Ünicode to test Distribute Issüé 310 try: @@ -29,9 +32,11 @@ except ImportError: from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - """) + """ +) -TEST_PY = DALS(""" +TEST_PY = DALS( + """ import unittest class TestTest(unittest.TestCase): @@ -39,7 +44,8 @@ def test_test(self): print "Foo" # Should fail under Python 3 unless 2to3 is used test_suite = unittest.makeSuite(TestTest) - """) + """ +) @pytest.fixture @@ -104,13 +110,16 @@ def test_tests_are_run_once(capfd): with open('dummy/__init__.py', 'wt'): pass with open('dummy/test_dummy.py', 'wt') as f: - f.write(DALS( - """ + f.write( + DALS( + """ import unittest class TestTest(unittest.TestCase): def test_test(self): print('Foo') - """)) + """ + ) + ) dist = Distribution(params) dist.script_name = 'setup.py' cmd = test(dist) @@ -128,7 +137,7 @@ def test_warns_deprecation(capfd): packages=['name', 'name.space', 'name.space.tests'], namespace_packages=['name'], test_suite='name.space.tests.test_suite', - use_2to3=True + use_2to3=True, ) dist = Distribution(params) dist.script_name = 'setup.py' @@ -154,7 +163,7 @@ def test_deprecation_stderr(capfd): packages=['name', 'name.space', 'name.space.tests'], namespace_packages=['name'], test_suite='name.space.tests.test_suite', - use_2to3=True + use_2to3=True, ) dist = Distribution(params) dist.script_name = 'setup.py' diff --git a/setuptools/tests/test_upload_docs.py b/setuptools/tests/test_upload_docs.py index 55978aadc70..295161dcd11 100644 --- a/setuptools/tests/test_upload_docs.py +++ b/setuptools/tests/test_upload_docs.py @@ -14,17 +14,21 @@ @pytest.fixture def sample_project(tmpdir_cwd): - path.build({ - 'setup.py': DALS(""" + path.build( + { + 'setup.py': DALS( + """ from setuptools import setup setup(name='foo') - """), - 'build': { - 'index.html': 'Hello world.', - 'empty': {}, + """ + ), + 'build': { + 'index.html': 'Hello world.', + 'empty': {}, + }, } - }) + ) @pytest.mark.usefixtures('sample_project') diff --git a/setuptools/tests/test_virtualenv.py b/setuptools/tests/test_virtualenv.py index 399dbaf0bbe..35f3be81ff5 100644 --- a/setuptools/tests/test_virtualenv.py +++ b/setuptools/tests/test_virtualenv.py @@ -31,13 +31,14 @@ def pytest_virtualenv_works(virtualenv): @yield_requires_config(pytest_virtualenv.CONFIG, ['virtualenv_executable']) @pytest.fixture(scope='function') def bare_virtualenv(): - """ Bare virtualenv (no pip/setuptools/wheel). - """ - with pytest_virtualenv.VirtualEnv(args=( - '--no-wheel', - '--no-pip', - '--no-setuptools', - )) as venv: + """Bare virtualenv (no pip/setuptools/wheel).""" + with pytest_virtualenv.VirtualEnv( + args=( + '--no-wheel', + '--no-pip', + '--no-setuptools', + ) + ) as venv: yield venv @@ -88,10 +89,7 @@ def skip_network(param): 'https://github.com/pypa/pip/archive/main.zip', ] - versions = itertools.chain( - [None], - map(skip_network, network_versions) - ) + versions = itertools.chain([None], map(skip_network, network_versions)) return list(versions) @@ -107,16 +105,26 @@ def test_pip_upgrade_from_source(pip_version, tmp_src, virtualenv): upgrade_pip = () else: upgrade_pip = ('python -m pip install -U {pip_version} --retries=1',) - virtualenv.run(' && '.join(( - 'pip uninstall -y setuptools', - 'pip install -U wheel', - ) + upgrade_pip).format(pip_version=pip_version)) + virtualenv.run( + ' && '.join( + ( + 'pip uninstall -y setuptools', + 'pip install -U wheel', + ) + + upgrade_pip + ).format(pip_version=pip_version) + ) dist_dir = virtualenv.workspace # Generate source distribution / wheel. - virtualenv.run(' && '.join(( - 'python setup.py -q sdist -d {dist}', - 'python setup.py -q bdist_wheel -d {dist}', - )).format(dist=dist_dir), cd=tmp_src) + virtualenv.run( + ' && '.join( + ( + 'python setup.py -q sdist -d {dist}', + 'python setup.py -q bdist_wheel -d {dist}', + ) + ).format(dist=dist_dir), + cd=tmp_src, + ) sdist = glob.glob(os.path.join(dist_dir, '*.zip'))[0] wheel = glob.glob(os.path.join(dist_dir, '*.whl'))[0] # Then update from wheel. @@ -136,6 +144,7 @@ def sdist(distname, version): dist_path = tmpdir.join('%s-%s.tar.gz' % (distname, version)) make_nspkg_sdist(str(dist_path), distname, version) return dist_path + dependency_links = [ pathlib.Path(str(dist_path)).as_uri() for dist_path in ( @@ -146,8 +155,9 @@ def sdist(distname, version): ) ] with tmpdir.join('setup.py').open('w') as fp: - fp.write(DALS( - ''' + fp.write( + DALS( + ''' from setuptools import setup setup( @@ -169,17 +179,24 @@ def sdist(distname, version): """, }} ) - '''.format(dependency_links=dependency_links))) + '''.format( + dependency_links=dependency_links + ) + ) + ) with tmpdir.join('test.py').open('w') as fp: - fp.write(DALS( - ''' + fp.write( + DALS( + ''' import foobar import bits import bobs import pieces open('success', 'w').close() - ''')) + ''' + ) + ) # Run test command for test package. # use 'virtualenv.python' as workaround for man-group/pytest-plugins#166 cmd = [virtualenv.python, 'setup.py', 'test', '-s', 'test'] @@ -190,7 +207,8 @@ def sdist(distname, version): def test_test_command_install_requirements(virtualenv, tmpdir, request): # Ensure pip/wheel packages are installed. virtualenv.run( - "python -c \"__import__('pkg_resources').require(['pip', 'wheel'])\"") + "python -c \"__import__('pkg_resources').require(['pip', 'wheel'])\"" + ) # uninstall setuptools so that 'setup.py develop' works virtualenv.run("python -m pip uninstall -y setuptools") # disable index URL so bits and bobs aren't requested from PyPI diff --git a/setuptools/tests/test_wheel.py b/setuptools/tests/test_wheel.py index 7345b135fd1..153581ef84e 100644 --- a/setuptools/tests/test_wheel.py +++ b/setuptools/tests/test_wheel.py @@ -28,44 +28,55 @@ WHEEL_INFO_TESTS = ( ('invalid.whl', ValueError), - ('simplewheel-2.0-1-py2.py3-none-any.whl', { - 'project_name': 'simplewheel', - 'version': '2.0', - 'build': '1', - 'py_version': 'py2.py3', - 'abi': 'none', - 'platform': 'any', - }), - ('simple.dist-0.1-py2.py3-none-any.whl', { - 'project_name': 'simple.dist', - 'version': '0.1', - 'build': None, - 'py_version': 'py2.py3', - 'abi': 'none', - 'platform': 'any', - }), - ('example_pkg_a-1-py3-none-any.whl', { - 'project_name': 'example_pkg_a', - 'version': '1', - 'build': None, - 'py_version': 'py3', - 'abi': 'none', - 'platform': 'any', - }), - ('PyQt5-5.9-5.9.1-cp35.cp36.cp37-abi3-manylinux1_x86_64.whl', { - 'project_name': 'PyQt5', - 'version': '5.9', - 'build': '5.9.1', - 'py_version': 'cp35.cp36.cp37', - 'abi': 'abi3', - 'platform': 'manylinux1_x86_64', - }), + ( + 'simplewheel-2.0-1-py2.py3-none-any.whl', + { + 'project_name': 'simplewheel', + 'version': '2.0', + 'build': '1', + 'py_version': 'py2.py3', + 'abi': 'none', + 'platform': 'any', + }, + ), + ( + 'simple.dist-0.1-py2.py3-none-any.whl', + { + 'project_name': 'simple.dist', + 'version': '0.1', + 'build': None, + 'py_version': 'py2.py3', + 'abi': 'none', + 'platform': 'any', + }, + ), + ( + 'example_pkg_a-1-py3-none-any.whl', + { + 'project_name': 'example_pkg_a', + 'version': '1', + 'build': None, + 'py_version': 'py3', + 'abi': 'none', + 'platform': 'any', + }, + ), + ( + 'PyQt5-5.9-5.9.1-cp35.cp36.cp37-abi3-manylinux1_x86_64.whl', + { + 'project_name': 'PyQt5', + 'version': '5.9', + 'build': '5.9.1', + 'py_version': 'cp35.cp36.cp37', + 'abi': 'abi3', + 'platform': 'manylinux1_x86_64', + }, + ), ) @pytest.mark.parametrize( - ('filename', 'info'), WHEEL_INFO_TESTS, - ids=[t[0] for t in WHEEL_INFO_TESTS] + ('filename', 'info'), WHEEL_INFO_TESTS, ids=[t[0] for t in WHEEL_INFO_TESTS] ) def test_wheel_info(filename, info): if inspect.isclass(info): @@ -79,21 +90,25 @@ def test_wheel_info(filename, info): @contextlib.contextmanager def build_wheel(extra_file_defs=None, **kwargs): file_defs = { - 'setup.py': (DALS( - ''' + 'setup.py': ( + DALS( + ''' # -*- coding: utf-8 -*- from setuptools import setup import setuptools setup(**%r) ''' - ) % kwargs).encode('utf-8'), + ) + % kwargs + ).encode('utf-8'), } if extra_file_defs: file_defs.update(extra_file_defs) with tempdir() as source_dir: path.build(file_defs, source_dir) - subprocess.check_call((sys.executable, 'setup.py', - '-q', 'bdist_wheel'), cwd=source_dir) + subprocess.check_call( + (sys.executable, 'setup.py', '-q', 'bdist_wheel'), cwd=source_dir + ) yield glob.glob(os.path.join(source_dir, 'dist', '*.whl'))[0] @@ -101,8 +116,7 @@ def tree_set(root): contents = set() for dirpath, dirnames, filenames in os.walk(root): for filename in filenames: - contents.add(os.path.join(os.path.relpath(dirpath, root), - filename)) + contents.add(os.path.join(os.path.relpath(dirpath, root), filename)) return contents @@ -115,8 +129,7 @@ def flatten_tree(tree): for elem in contents: if isinstance(elem, dict): - output |= {os.path.join(node, val) - for val in flatten_tree(elem)} + output |= {os.path.join(node, val) for val in flatten_tree(elem)} else: output.add(os.path.join(node, elem)) return output @@ -127,19 +140,22 @@ def format_install_tree(tree): x.format( py_version=PY_MAJOR, platform=get_platform(), - shlib_ext=get_config_var('EXT_SUFFIX') or get_config_var('SO')) - for x in tree} + shlib_ext=get_config_var('EXT_SUFFIX') or get_config_var('SO'), + ) + for x in tree + } -def _check_wheel_install(filename, install_dir, install_tree_includes, - project_name, version, requires_txt): +def _check_wheel_install( + filename, install_dir, install_tree_includes, project_name, version, requires_txt +): w = Wheel(filename) egg_path = os.path.join(install_dir, w.egg_name()) w.install_as_egg(egg_path) if install_tree_includes is not None: install_tree = format_install_tree(install_tree_includes) exp = tree_set(install_dir) - assert install_tree.issubset(exp), (install_tree - exp) + assert install_tree.issubset(exp), install_tree - exp metadata = PathMetadata(egg_path, os.path.join(egg_path, 'EGG-INFO')) dist = Distribution.from_filename(egg_path, metadata=metadata) @@ -152,7 +168,6 @@ def _check_wheel_install(filename, install_dir, install_tree_includes, class Record: - def __init__(self, id, **kwargs): self._id = id self._fields = kwargs @@ -162,37 +177,27 @@ def __repr__(self): WHEEL_INSTALL_TESTS = ( - dict( id='basic', - file_defs={ - 'foo': { - '__init__.py': '' - } - }, + file_defs={'foo': {'__init__.py': ''}}, setup_kwargs=dict( packages=['foo'], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': { - 'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'top_level.txt' - ], - 'foo': ['__init__.py'] + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': { + 'EGG-INFO': ['PKG-INFO', 'RECORD', 'WHEEL', 'top_level.txt'], + 'foo': ['__init__.py'], + } } - }), + ), ), - dict( id='utf-8', setup_kwargs=dict( description='Description accentuée', - ) + ), ), - dict( id='data', file_defs={ @@ -205,21 +210,15 @@ def __repr__(self): setup_kwargs=dict( data_files=[('data_dir', ['data.txt'])], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': { - 'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'top_level.txt' - ], - 'data_dir': [ - 'data.txt' - ] + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': { + 'EGG-INFO': ['PKG-INFO', 'RECORD', 'WHEEL', 'top_level.txt'], + 'data_dir': ['data.txt'], + } } - }), + ), ), - dict( id='extension', file_defs={ @@ -269,24 +268,27 @@ def __repr__(self): }, setup_kwargs=dict( ext_modules=[ - Record('setuptools.Extension', - name='extension', - sources=['extension.c']) + Record( + 'setuptools.Extension', name='extension', sources=['extension.c'] + ) ], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}-{platform}.egg': [ - 'extension{shlib_ext}', - {'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'top_level.txt', - ]}, - ] - }), + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}-{platform}.egg': [ + 'extension{shlib_ext}', + { + 'EGG-INFO': [ + 'PKG-INFO', + 'RECORD', + 'WHEEL', + 'top_level.txt', + ] + }, + ] + } + ), ), - dict( id='header', file_defs={ @@ -298,19 +300,22 @@ def __repr__(self): setup_kwargs=dict( headers=['header.h'], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': [ - 'header.h', - {'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'top_level.txt', - ]}, - ] - }), + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': [ + 'header.h', + { + 'EGG-INFO': [ + 'PKG-INFO', + 'RECORD', + 'WHEEL', + 'top_level.txt', + ] + }, + ] + } + ), ), - dict( id='script', file_defs={ @@ -330,50 +335,49 @@ def __repr__(self): setup_kwargs=dict( scripts=['script.py', 'script.sh'], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': { - 'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'top_level.txt', - {'scripts': [ - 'script.py', - 'script.sh' - ]} - - ] + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': { + 'EGG-INFO': [ + 'PKG-INFO', + 'RECORD', + 'WHEEL', + 'top_level.txt', + {'scripts': ['script.py', 'script.sh']}, + ] + } } - }) + ), ), - dict( id='requires1', install_requires='foobar==2.0', - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': { - 'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'requires.txt', - 'top_level.txt', - ] + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': { + 'EGG-INFO': [ + 'PKG-INFO', + 'RECORD', + 'WHEEL', + 'requires.txt', + 'top_level.txt', + ] + } } - }), + ), requires_txt=DALS( ''' foobar==2.0 ''' ), ), - dict( id='requires2', install_requires=''' bar foo<=2.0; %r in sys_platform - ''' % sys.platform, + ''' + % sys.platform, requires_txt=DALS( ''' bar @@ -381,14 +385,13 @@ def __repr__(self): ''' ), ), - dict( id='requires3', install_requires=''' bar; %r != sys_platform - ''' % sys.platform, + ''' + % sys.platform, ), - dict( id='requires4', install_requires=''' @@ -406,7 +409,6 @@ def __repr__(self): ''' ), ), - dict( id='requires5', extras_require={ @@ -418,67 +420,73 @@ def __repr__(self): ''' ), ), - dict( id='namespace_package', file_defs={ 'foo': { - 'bar': { - '__init__.py': '' - }, + 'bar': {'__init__.py': ''}, }, }, setup_kwargs=dict( namespace_packages=['foo'], packages=['foo.bar'], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': [ - 'foo-1.0-py{py_version}-nspkg.pth', - {'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'namespace_packages.txt', - 'top_level.txt', - ]}, - {'foo': [ - '__init__.py', - {'bar': ['__init__.py']}, - ]}, - ] - }), + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': [ + 'foo-1.0-py{py_version}-nspkg.pth', + { + 'EGG-INFO': [ + 'PKG-INFO', + 'RECORD', + 'WHEEL', + 'namespace_packages.txt', + 'top_level.txt', + ] + }, + { + 'foo': [ + '__init__.py', + {'bar': ['__init__.py']}, + ] + }, + ] + } + ), ), - dict( id='empty_namespace_package', file_defs={ 'foobar': { - '__init__.py': - "__import__('pkg_resources').declare_namespace(__name__)", + '__init__.py': "__import__('pkg_resources').declare_namespace(__name__)", }, }, setup_kwargs=dict( namespace_packages=['foobar'], packages=['foobar'], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': [ - 'foo-1.0-py{py_version}-nspkg.pth', - {'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'namespace_packages.txt', - 'top_level.txt', - ]}, - {'foobar': [ - '__init__.py', - ]}, - ] - }), + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': [ + 'foo-1.0-py{py_version}-nspkg.pth', + { + 'EGG-INFO': [ + 'PKG-INFO', + 'RECORD', + 'WHEEL', + 'namespace_packages.txt', + 'top_level.txt', + ] + }, + { + 'foobar': [ + '__init__.py', + ] + }, + ] + } + ), ), - dict( id='data_in_package', file_defs={ @@ -490,36 +498,40 @@ def __repr__(self): Some data... ''' ), - } + }, } }, setup_kwargs=dict( packages=['foo'], data_files=[('foo/data_dir', ['foo/data_dir/data.txt'])], ), - install_tree=flatten_tree({ - 'foo-1.0-py{py_version}.egg': { - 'EGG-INFO': [ - 'PKG-INFO', - 'RECORD', - 'WHEEL', - 'top_level.txt', - ], - 'foo': [ - '__init__.py', - {'data_dir': [ - 'data.txt', - ]} - ] + install_tree=flatten_tree( + { + 'foo-1.0-py{py_version}.egg': { + 'EGG-INFO': [ + 'PKG-INFO', + 'RECORD', + 'WHEEL', + 'top_level.txt', + ], + 'foo': [ + '__init__.py', + { + 'data_dir': [ + 'data.txt', + ] + }, + ], + } } - }), + ), ), - ) @pytest.mark.parametrize( - 'params', WHEEL_INSTALL_TESTS, + 'params', + WHEEL_INSTALL_TESTS, ids=list(params['id'] for params in WHEEL_INSTALL_TESTS), ) def test_wheel_install(params): @@ -539,24 +551,28 @@ def test_wheel_install(params): extra_file_defs=file_defs, **setup_kwargs ) as filename, tempdir() as install_dir: - _check_wheel_install(filename, install_dir, - install_tree, project_name, - version, requires_txt) + _check_wheel_install( + filename, install_dir, install_tree, project_name, version, requires_txt + ) def test_wheel_install_pep_503(): - project_name = 'Foo_Bar' # PEP 503 canonicalized name is "foo-bar" + project_name = 'Foo_Bar' # PEP 503 canonicalized name is "foo-bar" version = '1.0' with build_wheel( name=project_name, version=version, ) as filename, tempdir() as install_dir: - new_filename = filename.replace(project_name, - canonicalize_name(project_name)) + new_filename = filename.replace(project_name, canonicalize_name(project_name)) shutil.move(filename, new_filename) - _check_wheel_install(new_filename, install_dir, None, - canonicalize_name(project_name), - version, None) + _check_wheel_install( + new_filename, + install_dir, + None, + canonicalize_name(project_name), + version, + None, + ) def test_wheel_no_dist_dir(): @@ -569,15 +585,15 @@ def test_wheel_no_dist_dir(): zipfile.ZipFile(wheel_path, 'w').close() with tempdir() as install_dir: with pytest.raises(ValueError): - _check_wheel_install(wheel_path, install_dir, None, - project_name, - version, None) + _check_wheel_install( + wheel_path, install_dir, None, project_name, version, None + ) def test_wheel_is_compatible(monkeypatch): def sys_tags(): for t in parse_tag('cp36-cp36m-manylinux1_x86_64'): yield t + monkeypatch.setattr('setuptools.wheel.sys_tags', sys_tags) - assert Wheel( - 'onnxruntime-0.1.2-cp36-cp36m-manylinux1_x86_64.whl').is_compatible() + assert Wheel('onnxruntime-0.1.2-cp36-cp36m-manylinux1_x86_64.whl').is_compatible() diff --git a/setuptools/tests/test_windows_wrappers.py b/setuptools/tests/test_windows_wrappers.py index 27853aae785..73dac072b32 100644 --- a/setuptools/tests/test_windows_wrappers.py +++ b/setuptools/tests/test_windows_wrappers.py @@ -55,7 +55,8 @@ class TestCLI(WrapperTester): script_name = 'foo-script.py' wrapper_source = 'cli-32.exe' wrapper_name = 'foo.exe' - script_tmpl = textwrap.dedent(""" + script_tmpl = textwrap.dedent( + """ #!%(python_exe)s import sys input = repr(sys.stdin.read()) @@ -64,7 +65,8 @@ class TestCLI(WrapperTester): print(input) if __debug__: print('non-optimized') - """).lstrip() + """ + ).lstrip() def test_basic(self, tmpdir): """ @@ -95,16 +97,17 @@ def test_basic(self, tmpdir): 'arg 4\\', 'arg5 a\\\\b', ] - proc = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = proc.communicate('hello\nworld\n'.encode('ascii')) actual = stdout.decode('ascii').replace('\r\n', '\n') - expected = textwrap.dedent(r""" + expected = textwrap.dedent( + r""" \foo-script.py ['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b'] 'hello\nworld\n' non-optimized - """).lstrip() + """ + ).lstrip() assert actual == expected def test_with_options(self, tmpdir): @@ -119,7 +122,8 @@ def test_with_options(self, tmpdir): enter the interpreter after running the script, you could use -Oi: """ self.create_script(tmpdir) - tmpl = textwrap.dedent(""" + tmpl = textwrap.dedent( + """ #!%(python_exe)s -Oi import sys input = repr(sys.stdin.read()) @@ -129,23 +133,24 @@ def test_with_options(self, tmpdir): if __debug__: print('non-optimized') sys.ps1 = '---' - """).lstrip() + """ + ).lstrip() with (tmpdir / 'foo-script.py').open('w') as f: f.write(self.prep_script(tmpl)) cmd = [str(tmpdir / 'foo.exe')] proc = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - stderr=subprocess.STDOUT) + cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT + ) stdout, stderr = proc.communicate() actual = stdout.decode('ascii').replace('\r\n', '\n') - expected = textwrap.dedent(r""" + expected = textwrap.dedent( + r""" \foo-script.py [] '' --- - """).lstrip() + """ + ).lstrip() assert actual == expected @@ -154,17 +159,20 @@ class TestGUI(WrapperTester): Testing the GUI Version ----------------------- """ + script_name = 'bar-script.pyw' wrapper_source = 'gui-32.exe' wrapper_name = 'bar.exe' - script_tmpl = textwrap.dedent(""" + script_tmpl = textwrap.dedent( + """ #!%(python_exe)s import sys f = open(sys.argv[1], 'wb') bytes_written = f.write(repr(sys.argv[2]).encode('utf-8')) f.close() - """).strip() + """ + ).strip() def test_basic(self, tmpdir): """Test the GUI version with the simple script, bar-script.py""" @@ -176,8 +184,8 @@ def test_basic(self, tmpdir): 'Test Argument', ] proc = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, - stderr=subprocess.STDOUT) + cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT + ) stdout, stderr = proc.communicate() assert not stdout assert not stderr diff --git a/setuptools/wheel.py b/setuptools/wheel.py index 0be811af2c2..6332f53cfcc 100644 --- a/setuptools/wheel.py +++ b/setuptools/wheel.py @@ -21,10 +21,10 @@ r"""^(?P.+?)-(?P\d.*?) ((-(?P\d.*?))?-(?P.+?)-(?P.+?)-(?P.+?) )\.whl$""", - re.VERBOSE).match + re.VERBOSE, +).match -NAMESPACE_PACKAGE_INIT = \ - "__import__('pkg_resources').declare_namespace(__name__)\n" +NAMESPACE_PACKAGE_INIT = "__import__('pkg_resources').declare_namespace(__name__)\n" def unpack(src_dir, dst_dir): @@ -50,7 +50,6 @@ def unpack(src_dir, dst_dir): class Wheel: - def __init__(self, filename): match = WHEEL_NAME(os.path.basename(filename)) if match is None: @@ -69,23 +68,26 @@ def tags(self): def is_compatible(self): '''Is the wheel is compatible with the current platform?''' - supported_tags = set( - (t.interpreter, t.abi, t.platform) for t in sys_tags()) + supported_tags = set((t.interpreter, t.abi, t.platform) for t in sys_tags()) return next((True for t in self.tags() if t in supported_tags), False) def egg_name(self): - return pkg_resources.Distribution( - project_name=self.project_name, version=self.version, - platform=(None if self.platform == 'any' else get_platform()), - ).egg_name() + '.egg' + return ( + pkg_resources.Distribution( + project_name=self.project_name, + version=self.version, + platform=(None if self.platform == 'any' else get_platform()), + ).egg_name() + + '.egg' + ) def get_dist_info(self, zf): # find the correct name of the .dist-info dir in the wheel file for member in zf.namelist(): dirname = posixpath.dirname(member) - if (dirname.endswith('.dist-info') and - canonicalize_name(dirname).startswith( - canonicalize_name(self.project_name))): + if dirname.endswith('.dist-info') and canonicalize_name(dirname).startswith( + canonicalize_name(self.project_name) + ): return dirname raise ValueError("unsupported wheel format. .dist-info not found") @@ -114,19 +116,17 @@ def get_metadata(name): wheel_metadata = get_metadata('WHEEL') # Check wheel format version is supported. wheel_version = parse_version(wheel_metadata.get('Wheel-Version')) - wheel_v1 = ( - parse_version('1.0') <= wheel_version < parse_version('2.0dev0') - ) + wheel_v1 = parse_version('1.0') <= wheel_version < parse_version('2.0dev0') if not wheel_v1: - raise ValueError( - 'unsupported wheel format version: %s' % wheel_version) + raise ValueError('unsupported wheel format version: %s' % wheel_version) # Extract to target directory. os.mkdir(destination_eggdir) zf.extractall(destination_eggdir) # Convert metadata. dist_info = os.path.join(destination_eggdir, dist_info) dist = pkg_resources.Distribution.from_location( - destination_eggdir, dist_info, + destination_eggdir, + dist_info, metadata=pkg_resources.PathMetadata(destination_eggdir, dist_info), ) @@ -136,6 +136,7 @@ def get_metadata(name): def raw_req(req): req.marker = None return str(req) + install_requires = list(sorted(map(raw_req, dist.requires()))) extras_require = { extra: sorted( @@ -174,8 +175,7 @@ def _move_data_entries(destination_eggdir, dist_data): dist_data = os.path.join(destination_eggdir, dist_data) dist_data_scripts = os.path.join(dist_data, 'scripts') if os.path.exists(dist_data_scripts): - egg_info_scripts = os.path.join( - destination_eggdir, 'EGG-INFO', 'scripts') + egg_info_scripts = os.path.join(destination_eggdir, 'EGG-INFO', 'scripts') os.mkdir(egg_info_scripts) for entry in os.listdir(dist_data_scripts): # Remove bytecode, as it's not properly handled @@ -188,18 +188,20 @@ def _move_data_entries(destination_eggdir, dist_data): os.path.join(egg_info_scripts, entry), ) os.rmdir(dist_data_scripts) - for subdir in filter(os.path.exists, ( - os.path.join(dist_data, d) - for d in ('data', 'headers', 'purelib', 'platlib') - )): + for subdir in filter( + os.path.exists, + ( + os.path.join(dist_data, d) + for d in ('data', 'headers', 'purelib', 'platlib') + ), + ): unpack(subdir, destination_eggdir) if os.path.exists(dist_data): os.rmdir(dist_data) @staticmethod def _fix_namespace_packages(egg_info, destination_eggdir): - namespace_packages = os.path.join( - egg_info, 'namespace_packages.txt') + namespace_packages = os.path.join(egg_info, 'namespace_packages.txt') if os.path.exists(namespace_packages): with open(namespace_packages) as fp: namespace_packages = fp.read().split() diff --git a/tools/finalize.py b/tools/finalize.py index 516a2fb5648..5db7002ba09 100644 --- a/tools/finalize.py +++ b/tools/finalize.py @@ -18,16 +18,19 @@ def release_kind(): """ # use min here as 'major' < 'minor' < 'patch' return min( - 'major' if 'breaking' in file.name else - 'minor' if 'change' in file.name else - 'patch' + 'major' + if 'breaking' in file.name + else 'minor' + if 'change' in file.name + else 'patch' for file in pathlib.Path('changelog.d').iterdir() ) bump_version_command = [ sys.executable, - '-m', 'bumpversion', + '-m', + 'bumpversion', release_kind(), ] @@ -40,9 +43,11 @@ def get_version(): def update_changelog(): cmd = [ - sys.executable, '-m', + sys.executable, + '-m', 'towncrier', - '--version', get_version(), + '--version', + get_version(), '--yes', ] subprocess.check_call(cmd)