diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f1afdd473cf..08d62162ddc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,6 +16,11 @@ repos: - id: trailing-whitespace exclude: .patch +- repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black + - repo: https://gitlab.com/pycqa/flake8 rev: 3.8.3 hooks: diff --git a/docs/html/conf.py b/docs/html/conf.py index 2ef2647ce72..a35452f0da0 100644 --- a/docs/html/conf.py +++ b/docs/html/conf.py @@ -16,7 +16,7 @@ import re import sys -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" docs_dir = os.path.dirname(os.path.dirname(__file__)) # If extensions (or modules to document with autodoc) are in another directory, @@ -30,13 +30,13 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # extensions = ['sphinx.ext.autodoc'] -extensions = ['sphinx.ext.extlinks', 'pip_sphinxext', 'sphinx.ext.intersphinx'] +extensions = ["sphinx.ext.extlinks", "pip_sphinxext", "sphinx.ext.intersphinx"] # intersphinx intersphinx_cache_limit = 0 intersphinx_mapping = { - 'pypug': ('https://packaging.python.org/', None), - 'pypa': ('https://www.pypa.io/en/latest/', None), + "pypug": ("https://packaging.python.org/", None), + "pypa": ("https://www.pypa.io/en/latest/", None), } @@ -44,17 +44,17 @@ templates_path = [] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'pip' -copyright = '2008-2020, PyPA' +project = "pip" +copyright = "2008-2020, PyPA" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -62,7 +62,7 @@ # # The short X.Y version. -version = release = 'dev' +version = release = "dev" # Readthedocs seems to install pip as an egg (via setup.py install) which # is somehow resulting in "import pip" picking up an older copy of pip. @@ -70,14 +70,14 @@ # read the version direct from the __init__.py file. (Yes, this is # fragile, but it works...) -pip_init = os.path.join(docs_dir, '..', 'src', 'pip', '__init__.py') +pip_init = os.path.join(docs_dir, "..", "src", "pip", "__init__.py") with open(pip_init) as f: for line in f: m = re.match(r'__version__ = "(.*)"', line) if m: __version__ = m.group(1) # The short X.Y version. - version = '.'.join(__version__.split('.')[:2]) + version = ".".join(__version__.split(".")[:2]) # The full version, including alpha/beta/rc tags. release = __version__ break @@ -95,14 +95,14 @@ # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. -today_fmt = '%B %d, %Y' +today_fmt = "%B %d, %Y" # List of documents that shouldn't be included in the build. # unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. -exclude_patterns = ['build/'] +exclude_patterns = ["build/"] # The reST default role (used for this markup: `text`) to use for all documents # default_role = None @@ -119,15 +119,15 @@ # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] extlinks = { - 'issue': ('https://github.com/pypa/pip/issues/%s', '#'), - 'pull': ('https://github.com/pypa/pip/pull/%s', 'PR #'), - 'pypi': ('https://pypi.org/project/%s/', ''), + "issue": ("https://github.com/pypa/pip/issues/%s", "#"), + "pull": ("https://github.com/pypa/pip/pull/%s", "PR #"), + "pypi": ("https://pypi.org/project/%s/", ""), } # -- Options for HTML output -------------------------------------------------- @@ -140,12 +140,12 @@ # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - 'collapsiblesidebar': True, - 'externalrefs': True, - 'navigation_depth': 3, - 'issues_url': 'https://github.com/pypa/pip/issues', - 'codebgcolor': '#eeffcc', - 'codetextcolor': '#333333', + "collapsiblesidebar": True, + "externalrefs": True, + "navigation_depth": 3, + "issues_url": "https://github.com/pypa/pip/issues", + "codebgcolor": "#eeffcc", + "codetextcolor": "#333333", } # Add any paths that contain custom themes here, relative to this directory. @@ -173,7 +173,7 @@ # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -html_last_updated_fmt = '%b %d, %Y' +html_last_updated_fmt = "%b %d, %Y" # If true, the Docutils Smart Quotes transform (originally based on # SmartyPants) will be used to convert characters like quotes and dashes @@ -192,10 +192,7 @@ smartquotes_action = "qe" # Custom sidebar templates, maps document names to template names. -html_sidebars = { - '**': ['localtoc.html', 'relations.html'], - 'index': ['localtoc.html'] -} +html_sidebars = {"**": ["localtoc.html", "relations.html"], "index": ["localtoc.html"]} # Additional templates that should be rendered to pages, maps page names to # template names. @@ -222,7 +219,7 @@ # html_file_suffix = '' # Output file base name for HTML help builder. -htmlhelp_basename = 'pipdocs' +htmlhelp_basename = "pipdocs" # -- Options for LaTeX output ------------------------------------------------- @@ -237,11 +234,11 @@ # (source start file, target name, title, author, documentclass [howto/manual]) latex_documents = [ ( - 'index', - 'pip.tex', - u'pip Documentation', - u'pip developers', - 'manual', + "index", + "pip.tex", + u"pip Documentation", + u"pip developers", + "manual", ), ] @@ -266,37 +263,26 @@ # List of manual pages generated man_pages = [ - ( - 'index', - 'pip', - u'package manager for Python packages', - u'pip developers', - 1 - ) + ("index", "pip", u"package manager for Python packages", u"pip developers", 1) ] def to_document_name(path, base_dir): - """Convert a provided path to a Sphinx "document name". - """ + """Convert a provided path to a Sphinx "document name".""" relative_path = os.path.relpath(path, base_dir) root, _ = os.path.splitext(relative_path) - return root.replace(os.sep, '/') + return root.replace(os.sep, "/") # Here, we crawl the entire man/commands/ directory and list every file with # appropriate name and details -man_dir = os.path.join(docs_dir, 'man') -raw_subcommands = glob.glob(os.path.join(man_dir, 'commands/*.rst')) +man_dir = os.path.join(docs_dir, "man") +raw_subcommands = glob.glob(os.path.join(man_dir, "commands/*.rst")) if not raw_subcommands: - raise FileNotFoundError( - 'The individual subcommand manpages could not be found!' - ) + raise FileNotFoundError("The individual subcommand manpages could not be found!") for fname in raw_subcommands: fname_base = to_document_name(fname, man_dir) - outname = 'pip-' + fname_base.split('/')[1] - description = u'description of {} command'.format( - outname.replace('-', ' ') - ) + outname = "pip-" + fname_base.split("/")[1] + description = u"description of {} command".format(outname.replace("-", " ")) - man_pages.append((fname_base, outname, description, u'pip developers', 1)) + man_pages.append((fname_base, outname, description, u"pip developers", 1)) diff --git a/docs/pip_sphinxext.py b/docs/pip_sphinxext.py index 6cc7a2c82ec..84e5663c649 100644 --- a/docs/pip_sphinxext.py +++ b/docs/pip_sphinxext.py @@ -18,9 +18,7 @@ class PipCommandUsage(rst.Directive): def run(self): cmd = create_command(self.arguments[0]) - usage = dedent( - cmd.usage.replace('%prog', 'pip {}'.format(cmd.name)) - ).strip() + usage = dedent(cmd.usage.replace("%prog", "pip {}".format(cmd.name))).strip() node = nodes.literal_block(usage, usage) return [node] @@ -34,19 +32,18 @@ def run(self): desc = ViewList() cmd = create_command(self.arguments[0]) description = dedent(cmd.__doc__) - for line in description.split('\n'): + for line in description.split("\n"): desc.append(line, "") self.state.nested_parse(desc, 0, node) return [node] class PipOptions(rst.Directive): - def _format_option(self, option, cmd_name=None): bookmark_line = ( ".. _`{cmd_name}_{option._long_opts[0]}`:" - if cmd_name else - ".. _`{option._long_opts[0]}`:" + if cmd_name + else ".. _`{option._long_opts[0]}`:" ).format(**locals()) line = ".. option:: " if option._short_opts: @@ -59,7 +56,7 @@ def _format_option(self, option, cmd_name=None): metavar = option.metavar or option.dest.lower() line += " <{}>".format(metavar.lower()) # fix defaults - opt_help = option.help.replace('%default', str(option.default)) + opt_help = option.help.replace("%default", str(option.default)) # fix paths with sys.prefix opt_help = opt_help.replace(sys.prefix, "") return [bookmark_line, "", line, "", " " + opt_help, ""] @@ -82,9 +79,7 @@ def run(self): class PipGeneralOptions(PipOptions): def process_options(self): - self._format_options( - [o() for o in cmdoptions.general_group['options']] - ) + self._format_options([o() for o in cmdoptions.general_group["options"]]) class PipIndexOptions(PipOptions): @@ -93,7 +88,7 @@ class PipIndexOptions(PipOptions): def process_options(self): cmd_name = self.arguments[0] self._format_options( - [o() for o in cmdoptions.index_group['options']], + [o() for o in cmdoptions.index_group["options"]], cmd_name=cmd_name, ) @@ -110,49 +105,48 @@ def process_options(self): class PipReqFileOptionsReference(PipOptions): - def determine_opt_prefix(self, opt_name): for command in commands_dict: cmd = create_command(command) if cmd.cmd_opts.has_option(opt_name): return command - raise KeyError('Could not identify prefix of opt {}'.format(opt_name)) + raise KeyError("Could not identify prefix of opt {}".format(opt_name)) def process_options(self): for option in SUPPORTED_OPTIONS: - if getattr(option, 'deprecated', False): + if getattr(option, "deprecated", False): continue opt = option() opt_name = opt._long_opts[0] if opt._short_opts: - short_opt_name = '{}, '.format(opt._short_opts[0]) + short_opt_name = "{}, ".format(opt._short_opts[0]) else: - short_opt_name = '' + short_opt_name = "" - if option in cmdoptions.general_group['options']: - prefix = '' + if option in cmdoptions.general_group["options"]: + prefix = "" else: - prefix = '{}_'.format(self.determine_opt_prefix(opt_name)) + prefix = "{}_".format(self.determine_opt_prefix(opt_name)) self.view_list.append( - ' * :ref:`{short}{long}<{prefix}{opt_name}>`'.format( + " * :ref:`{short}{long}<{prefix}{opt_name}>`".format( short=short_opt_name, long=opt_name, prefix=prefix, - opt_name=opt_name + opt_name=opt_name, ), - "\n" + "\n", ) def setup(app): - app.add_directive('pip-command-usage', PipCommandUsage) - app.add_directive('pip-command-description', PipCommandDescription) - app.add_directive('pip-command-options', PipCommandOptions) - app.add_directive('pip-general-options', PipGeneralOptions) - app.add_directive('pip-index-options', PipIndexOptions) + app.add_directive("pip-command-usage", PipCommandUsage) + app.add_directive("pip-command-description", PipCommandDescription) + app.add_directive("pip-command-options", PipCommandOptions) + app.add_directive("pip-general-options", PipGeneralOptions) + app.add_directive("pip-index-options", PipIndexOptions) app.add_directive( - 'pip-requirements-file-options-ref-list', PipReqFileOptionsReference + "pip-requirements-file-options-ref-list", PipReqFileOptionsReference ) diff --git a/noxfile.py b/noxfile.py index 1746bb69915..7e41b20aba1 100644 --- a/noxfile.py +++ b/noxfile.py @@ -13,6 +13,7 @@ sys.path.append(".") from tools.automation import release # isort:skip # noqa + sys.path.pop() nox.options.reuse_existing_virtualenvs = True @@ -76,13 +77,14 @@ def test(session): run_with_protected_pip( session, "wheel", - "-w", LOCATIONS["common-wheels"], - "-r", REQUIREMENTS["common-wheels"], + "-w", + LOCATIONS["common-wheels"], + "-r", + REQUIREMENTS["common-wheels"], ) else: - msg = ( - "Re-using existing common-wheels at {}." - .format(LOCATIONS["common-wheels"]) + msg = "Re-using existing common-wheels at {}.".format( + LOCATIONS["common-wheels"] ) session.log(msg) @@ -91,8 +93,12 @@ def test(session): if os.path.exists(sdist_dir): shutil.rmtree(sdist_dir, ignore_errors=True) session.run( - "python", "setup.py", "sdist", - "--formats=zip", "--dist-dir", sdist_dir, + "python", + "setup.py", + "sdist", + "--formats=zip", + "--dist-dir", + sdist_dir, silent=True, ) generated_files = os.listdir(sdist_dir) @@ -127,11 +133,11 @@ def get_sphinx_build_command(kind): return [ "sphinx-build", "-W", - "-c", "docs/html", # see note above - "-d", "docs/build/doctrees/" + kind, - "-b", kind, - "docs/" + kind, - "docs/build/" + kind, + "-c=docs/html", # see note above + f"-d=docs/build/doctrees/{kind}", + f"-b={kind}", + f"docs/{kind}", + f"docs/build/{kind}", ] session.run(*get_sphinx_build_command("html")) @@ -174,7 +180,9 @@ def prepare_release(session): release.generate_authors(AUTHORS_FILE) if release.modified_files_in_git(): release.commit_file( - session, AUTHORS_FILE, message=f"Update {AUTHORS_FILE}", + session, + AUTHORS_FILE, + message=f"Update {AUTHORS_FILE}", ) else: session.log(f"# No changes to {AUTHORS_FILE}") @@ -221,7 +229,7 @@ def build_release(session): tmp_dist_paths = (build_dir / p for p in tmp_dists) session.log(f"# Copying dists from {build_dir}") - os.makedirs('dist', exist_ok=True) + os.makedirs("dist", exist_ok=True) for dist, final in zip(tmp_dist_paths, tmp_dists): session.log(f"# Copying {dist} to {final}") shutil.copy(dist, final) @@ -235,7 +243,7 @@ def build_dists(session): has_forbidden_git_untracked_files = any( # Don't report the environment this session is running in - not untracked_file.startswith('.nox/build-release/') + not untracked_file.startswith(".nox/build-release/") for untracked_file in release.get_git_untracked_files() ) if has_forbidden_git_untracked_files: @@ -280,9 +288,7 @@ def upload_release(session): f"pip-{version}.tar.gz", ] if sorted(distfile_names) != sorted(expected_distribution_files): - session.error( - f"Distribution files do not seem to be for {version} release." - ) + session.error(f"Distribution files do not seem to be for {version} release.") session.log("# Upload distributions") session.run("twine", "upload", *distribution_files) diff --git a/setup.cfg b/setup.cfg index 45fd58a3e7a..450f953e4a5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,5 @@ [isort] +profile = black skip = ./build, .nox, @@ -6,16 +7,15 @@ skip = .scratch, _vendor, data -multi_line_output = 3 known_third_party = pip._vendor known_first_party = pip tests default_section = THIRDPARTY -include_trailing_comma = true [flake8] +max-line-length = 88 exclude = ./build, .nox, @@ -28,6 +28,8 @@ ignore = G200, G202, # pycodestyle checks ignored in the default configuration E121, E123, E126, E133, E226, E241, E242, E704, W503, W504, W505, + # black adds spaces around ':' + E203, per-file-ignores = # G: The plugin logging-format treats every .log and .error as logging. noxfile.py: G diff --git a/setup.py b/setup.py index 0557690deca..f2fa49f9db5 100644 --- a/setup.py +++ b/setup.py @@ -12,28 +12,27 @@ def read(rel_path): here = os.path.abspath(os.path.dirname(__file__)) # intentionally *not* adding an encoding option to open, See: # https://github.com/pypa/virtualenv/issues/201#issuecomment-3145690 - with codecs.open(os.path.join(here, rel_path), 'r') as fp: + with codecs.open(os.path.join(here, rel_path), "r") as fp: return fp.read() def get_version(rel_path): for line in read(rel_path).splitlines(): - if line.startswith('__version__'): + if line.startswith("__version__"): # __version__ = "0.9" delim = '"' if '"' in line else "'" return line.split(delim)[1] raise RuntimeError("Unable to find version string.") -long_description = read('README.rst') +long_description = read("README.rst") setup( name="pip", version=get_version("src/pip/__init__.py"), description="The PyPA recommended tool for installing Python packages.", long_description=long_description, - - license='MIT', + license="MIT", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -50,17 +49,15 @@ def get_version(rel_path): "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ], - url='https://pip.pypa.io/', - keywords='distutils easy_install egg setuptools wheel virtualenv', + url="https://pip.pypa.io/", + keywords="distutils easy_install egg setuptools wheel virtualenv", project_urls={ "Documentation": "https://pip.pypa.io", "Source": "https://github.com/pypa/pip", "Changelog": "https://pip.pypa.io/en/stable/news/", }, - - author='The pip developers', - author_email='distutils-sig@python.org', - + author="The pip developers", + author_email="distutils-sig@python.org", package_dir={"": "src"}, packages=find_packages( where="src", @@ -77,12 +74,9 @@ def get_version(rel_path): "console_scripts": [ "pip=pip._internal.cli.main:main", "pip{}=pip._internal.cli.main:main".format(sys.version_info[0]), - "pip{}.{}=pip._internal.cli.main:main".format( - *sys.version_info[:2] - ), + "pip{}.{}=pip._internal.cli.main:main".format(*sys.version_info[:2]), ], }, - zip_safe=False, - python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*', + python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", ) diff --git a/src/pip/__main__.py b/src/pip/__main__.py index 7c2505fa5bd..65a6963dc87 100644 --- a/src/pip/__main__.py +++ b/src/pip/__main__.py @@ -7,12 +7,12 @@ # of sys.path, if present to avoid using current directory # in pip commands check, freeze, install, list and show, # when invoked as python -m pip -if sys.path[0] in ('', os.getcwd()): +if sys.path[0] in ("", os.getcwd()): sys.path.pop(0) # If we are running from a wheel, add the wheel to sys.path # This allows the usage python pip-*.whl/pip install pip-*.whl -if __package__ == '': +if __package__ == "": # __file__ is pip-*.whl/pip/__main__.py # first dirname call strips of '/__main__.py', second strips off '/pip' # Resulting path is the name of the wheel itself @@ -22,5 +22,5 @@ from pip._internal.cli.main import main as _main # isort:skip # noqa -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(_main()) diff --git a/src/pip/_internal/build_env.py b/src/pip/_internal/build_env.py index a08e63cd051..44327464c73 100644 --- a/src/pip/_internal/build_env.py +++ b/src/pip/_internal/build_env.py @@ -27,15 +27,14 @@ class _Prefix: - def __init__(self, path): # type: (str) -> None self.path = path self.setup = False self.bin_dir = get_paths( - 'nt' if os.name == 'nt' else 'posix_prefix', - vars={'base': path, 'platbase': path} - )['scripts'] + "nt" if os.name == "nt" else "posix_prefix", + vars={"base": path, "platbase": path}, + )["scripts"] # Note: prefer distutils' sysconfig to get the # library paths so PyPy is correctly supported. purelib = get_python_lib(plat_specific=False, prefix=path) @@ -47,19 +46,18 @@ def __init__(self, path): class BuildEnvironment(object): - """Creates and manages an isolated environment to install build deps - """ + """Creates and manages an isolated environment to install build deps""" def __init__(self): # type: () -> None - temp_dir = TempDirectory( - kind=tempdir_kinds.BUILD_ENV, globally_managed=True - ) + temp_dir = TempDirectory(kind=tempdir_kinds.BUILD_ENV, globally_managed=True) - self._prefixes = OrderedDict(( - (name, _Prefix(os.path.join(temp_dir.path, name))) - for name in ('normal', 'overlay') - )) + self._prefixes = OrderedDict( + ( + (name, _Prefix(os.path.join(temp_dir.path, name))) + for name in ("normal", "overlay") + ) + ) self._bin_dirs = [] # type: List[str] self._lib_dirs = [] # type: List[str] @@ -71,17 +69,19 @@ def __init__(self): # - ensure .pth files are honored # - prevent access to system site packages system_sites = { - os.path.normcase(site) for site in ( + os.path.normcase(site) + for site in ( get_python_lib(plat_specific=False), get_python_lib(plat_specific=True), ) } - self._site_dir = os.path.join(temp_dir.path, 'site') + self._site_dir = os.path.join(temp_dir.path, "site") if not os.path.exists(self._site_dir): os.mkdir(self._site_dir) - with open(os.path.join(self._site_dir, 'sitecustomize.py'), 'w') as fp: - fp.write(textwrap.dedent( - ''' + with open(os.path.join(self._site_dir, "sitecustomize.py"), "w") as fp: + fp.write( + textwrap.dedent( + """ import os, site, sys # First, drop system-sites related paths. @@ -104,34 +104,37 @@ def __init__(self): for path in {lib_dirs!r}: assert not path in sys.path site.addsitedir(path) - ''' - ).format(system_sites=system_sites, lib_dirs=self._lib_dirs)) + """ + ).format(system_sites=system_sites, lib_dirs=self._lib_dirs) + ) def __enter__(self): # type: () -> None self._save_env = { name: os.environ.get(name, None) - for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH') + for name in ("PATH", "PYTHONNOUSERSITE", "PYTHONPATH") } path = self._bin_dirs[:] - old_path = self._save_env['PATH'] + old_path = self._save_env["PATH"] if old_path: path.extend(old_path.split(os.pathsep)) pythonpath = [self._site_dir] - os.environ.update({ - 'PATH': os.pathsep.join(path), - 'PYTHONNOUSERSITE': '1', - 'PYTHONPATH': os.pathsep.join(pythonpath), - }) + os.environ.update( + { + "PATH": os.pathsep.join(path), + "PYTHONNOUSERSITE": "1", + "PYTHONPATH": os.pathsep.join(pythonpath), + } + ) def __exit__( self, exc_type, # type: Optional[Type[BaseException]] exc_val, # type: Optional[BaseException] - exc_tb # type: Optional[TracebackType] + exc_tb, # type: Optional[TracebackType] ): # type: (...) -> None for varname, old_value in self._save_env.items(): @@ -143,8 +146,8 @@ def __exit__( def check_requirements(self, reqs): # type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]] """Return 2 sets: - - conflicting requirements: set of (installed, wanted) reqs tuples - - missing requirements: set of reqs + - conflicting requirements: set of (installed, wanted) reqs tuples + - missing requirements: set of reqs """ missing = set() conflicting = set() @@ -155,8 +158,7 @@ def check_requirements(self, reqs): if ws.find(Requirement.parse(req)) is None: missing.add(req) except VersionConflict as e: - conflicting.add((str(e.args[0].as_requirement()), - str(e.args[1]))) + conflicting.add((str(e.args[0].as_requirement()), str(e.args[1]))) return conflicting, missing def install_requirements( @@ -164,7 +166,7 @@ def install_requirements( finder, # type: PackageFinder requirements, # type: Iterable[str] prefix_as_string, # type: str - message # type: str + message, # type: str ): # type: (...) -> None prefix = self._prefixes[prefix_as_string] @@ -173,42 +175,50 @@ def install_requirements( if not requirements: return args = [ - sys.executable, os.path.dirname(pip_location), 'install', - '--ignore-installed', '--no-user', '--prefix', prefix.path, - '--no-warn-script-location', + sys.executable, + os.path.dirname(pip_location), + "install", + "--ignore-installed", + "--no-user", + "--prefix", + prefix.path, + "--no-warn-script-location", ] # type: List[str] if logger.getEffectiveLevel() <= logging.DEBUG: - args.append('-v') - for format_control in ('no_binary', 'only_binary'): + args.append("-v") + for format_control in ("no_binary", "only_binary"): formats = getattr(finder.format_control, format_control) - args.extend(('--' + format_control.replace('_', '-'), - ','.join(sorted(formats or {':none:'})))) + args.extend( + ( + "--" + format_control.replace("_", "-"), + ",".join(sorted(formats or {":none:"})), + ) + ) index_urls = finder.index_urls if index_urls: - args.extend(['-i', index_urls[0]]) + args.extend(["-i", index_urls[0]]) for extra_index in index_urls[1:]: - args.extend(['--extra-index-url', extra_index]) + args.extend(["--extra-index-url", extra_index]) else: - args.append('--no-index') + args.append("--no-index") for link in finder.find_links: - args.extend(['--find-links', link]) + args.extend(["--find-links", link]) for host in finder.trusted_hosts: - args.extend(['--trusted-host', host]) + args.extend(["--trusted-host", host]) if finder.allow_all_prereleases: - args.append('--pre') + args.append("--pre") if finder.prefer_binary: - args.append('--prefer-binary') - args.append('--') + args.append("--prefer-binary") + args.append("--") args.extend(requirements) with open_spinner(message) as spinner: call_subprocess(args, spinner=spinner) class NoOpBuildEnvironment(BuildEnvironment): - """A no-op drop-in replacement for BuildEnvironment - """ + """A no-op drop-in replacement for BuildEnvironment""" def __init__(self): # type: () -> None @@ -222,7 +232,7 @@ def __exit__( self, exc_type, # type: Optional[Type[BaseException]] exc_val, # type: Optional[BaseException] - exc_tb # type: Optional[TracebackType] + exc_tb, # type: Optional[TracebackType] ): # type: (...) -> None pass @@ -236,7 +246,7 @@ def install_requirements( finder, # type: PackageFinder requirements, # type: Iterable[str] prefix_as_string, # type: str - message # type: str + message, # type: str ): # type: (...) -> None raise NotImplementedError() diff --git a/src/pip/_internal/cache.py b/src/pip/_internal/cache.py index def8dd64a18..a0b5c56411c 100644 --- a/src/pip/_internal/cache.py +++ b/src/pip/_internal/cache.py @@ -37,11 +37,11 @@ class Cache(object): """An abstract class - provides cache directories for data from links - :param cache_dir: The root of the cache. - :param format_control: An object of FormatControl class to limit - binaries being read from the cache. - :param allowed_formats: which formats of files the cache should store. - ('binary' and 'source' are the only allowed values) + :param cache_dir: The root of the cache. + :param format_control: An object of FormatControl class to limit + binaries being read from the cache. + :param allowed_formats: which formats of files the cache should store. + ('binary' and 'source' are the only allowed values) """ def __init__(self, cache_dir, format_control, allowed_formats): @@ -85,8 +85,7 @@ def _get_cache_path_parts_legacy(self, link): def _get_cache_path_parts(self, link): # type: (Link) -> List[str] - """Get parts of part that must be os.path.joined with cache_dir - """ + """Get parts of part that must be os.path.joined with cache_dir""" # We want to generate an url to use as our cache key, we don't want to # just re-use the URL because it might have other items in the fragment @@ -120,17 +119,11 @@ def _get_cache_path_parts(self, link): def _get_candidates(self, link, canonical_package_name): # type: (Link, str) -> List[Any] - can_not_cache = ( - not self.cache_dir or - not canonical_package_name or - not link - ) + can_not_cache = not self.cache_dir or not canonical_package_name or not link if can_not_cache: return [] - formats = self.format_control.get_allowed_formats( - canonical_package_name - ) + formats = self.format_control.get_allowed_formats(canonical_package_name) if not self.allowed_formats.intersection(formats): return [] @@ -152,14 +145,13 @@ def get_path_for_link_legacy(self, link): def get_path_for_link(self, link): # type: (Link) -> str - """Return a directory to store cached items in for link. - """ + """Return a directory to store cached items in for link.""" raise NotImplementedError() def get( self, - link, # type: Link - package_name, # type: Optional[str] + link, # type: Link + package_name, # type: Optional[str] supported_tags, # type: List[Tag] ): # type: (...) -> Link @@ -170,14 +162,11 @@ def get( class SimpleWheelCache(Cache): - """A cache of wheels for future installs. - """ + """A cache of wheels for future installs.""" def __init__(self, cache_dir, format_control): # type: (str, FormatControl) -> None - super(SimpleWheelCache, self).__init__( - cache_dir, format_control, {"binary"} - ) + super(SimpleWheelCache, self).__init__(cache_dir, format_control, {"binary"}) def get_path_for_link_legacy(self, link): # type: (Link) -> str @@ -208,8 +197,8 @@ def get_path_for_link(self, link): def get( self, - link, # type: Link - package_name, # type: Optional[str] + link, # type: Link + package_name, # type: Optional[str] supported_tags, # type: List[Tag] ): # type: (...) -> Link @@ -219,9 +208,7 @@ def get( return link canonical_package_name = canonicalize_name(package_name) - for wheel_name, wheel_dir in self._get_candidates( - link, canonical_package_name - ): + for wheel_name, wheel_dir in self._get_candidates(link, canonical_package_name): try: wheel = Wheel(wheel_name) except InvalidWheelFilename: @@ -230,7 +217,9 @@ def get( logger.debug( "Ignoring cached wheel %s for %s as it " "does not match the expected distribution name %s.", - wheel_name, link, package_name, + wheel_name, + link, + package_name, ) continue if not wheel.supported(supported_tags): @@ -252,8 +241,7 @@ def get( class EphemWheelCache(SimpleWheelCache): - """A SimpleWheelCache that creates it's own temporary cache directory - """ + """A SimpleWheelCache that creates it's own temporary cache directory""" def __init__(self, format_control): # type: (FormatControl) -> None @@ -262,9 +250,7 @@ def __init__(self, format_control): globally_managed=True, ) - super(EphemWheelCache, self).__init__( - self._temp_dir.path, format_control - ) + super(EphemWheelCache, self).__init__(self._temp_dir.path, format_control) class CacheEntry(object): @@ -286,9 +272,7 @@ class WheelCache(Cache): def __init__(self, cache_dir, format_control): # type: (str, FormatControl) -> None - super(WheelCache, self).__init__( - cache_dir, format_control, {'binary'} - ) + super(WheelCache, self).__init__(cache_dir, format_control, {"binary"}) self._wheel_cache = SimpleWheelCache(cache_dir, format_control) self._ephem_cache = EphemWheelCache(format_control) @@ -306,8 +290,8 @@ def get_ephem_path_for_link(self, link): def get( self, - link, # type: Link - package_name, # type: Optional[str] + link, # type: Link + package_name, # type: Optional[str] supported_tags, # type: List[Tag] ): # type: (...) -> Link @@ -318,8 +302,8 @@ def get( def get_cache_entry( self, - link, # type: Link - package_name, # type: Optional[str] + link, # type: Link + package_name, # type: Optional[str] supported_tags, # type: List[Tag] ): # type: (...) -> Optional[CacheEntry] diff --git a/src/pip/_internal/cli/autocompletion.py b/src/pip/_internal/cli/autocompletion.py index 329de602513..eb489114a1c 100644 --- a/src/pip/_internal/cli/autocompletion.py +++ b/src/pip/_internal/cli/autocompletion.py @@ -17,17 +17,16 @@ def autocomplete(): # type: () -> None - """Entry Point for completion of main and subcommand options. - """ + """Entry Point for completion of main and subcommand options.""" # Don't complete if user hasn't sourced bash_completion file. - if 'PIP_AUTO_COMPLETE' not in os.environ: + if "PIP_AUTO_COMPLETE" not in os.environ: return - cwords = os.environ['COMP_WORDS'].split()[1:] - cword = int(os.environ['COMP_CWORD']) + cwords = os.environ["COMP_WORDS"].split()[1:] + cword = int(os.environ["COMP_CWORD"]) try: current = cwords[cword - 1] except IndexError: - current = '' + current = "" parser = create_main_parser() subcommands = list(commands_dict) @@ -42,12 +41,16 @@ def autocomplete(): # subcommand options if subcommand_name is not None: # special case: 'help' subcommand has no options - if subcommand_name == 'help': + if subcommand_name == "help": sys.exit(1) # special case: list locally installed dists for show and uninstall should_list_installed = ( - subcommand_name in ['show', 'uninstall'] and - not current.startswith('-') + subcommand_name + in [ + "show", + "uninstall", + ] + and not current.startswith("-") ) if should_list_installed: installed = [] @@ -69,13 +72,15 @@ def autocomplete(): options.append((opt_str, opt.nargs)) # filter out previously specified options from available options - prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] + prev_opts = [x.split("=")[0] for x in cwords[1 : cword - 1]] options = [(x, v) for (x, v) in options if x not in prev_opts] # filter options by current input options = [(k, v) for k, v in options if k.startswith(current)] # get completion type given cwords and available subcommand options completion_type = get_path_completion_type( - cwords, cword, subcommand.parser.option_list_all, + cwords, + cword, + subcommand.parser.option_list_all, ) # get completion files and directories if ``completion_type`` is # ````, ```` or ```` @@ -86,7 +91,7 @@ def autocomplete(): opt_label = option[0] # append '=' to options which require args if option[1] and option[0][:2] == "--": - opt_label += '=' + opt_label += "=" print(opt_label) else: # show main parser options only when necessary @@ -94,19 +99,17 @@ def autocomplete(): opts = [i.option_list for i in parser.option_groups] opts.append(parser.option_list) flattened_opts = chain.from_iterable(opts) - if current.startswith('-'): + if current.startswith("-"): for opt in flattened_opts: if opt.help != optparse.SUPPRESS_HELP: subcommands += opt._long_opts + opt._short_opts else: # get completion type given cwords and all available options - completion_type = get_path_completion_type(cwords, cword, - flattened_opts) + completion_type = get_path_completion_type(cwords, cword, flattened_opts) if completion_type: - subcommands = list(auto_complete_paths(current, - completion_type)) + subcommands = list(auto_complete_paths(current, completion_type)) - print(' '.join([x for x in subcommands if x.startswith(current)])) + print(" ".join([x for x in subcommands if x.startswith(current)])) sys.exit(1) @@ -119,16 +122,16 @@ def get_path_completion_type(cwords, cword, opts): :param opts: The available options to check :return: path completion type (``file``, ``dir``, ``path`` or None) """ - if cword < 2 or not cwords[cword - 2].startswith('-'): + if cword < 2 or not cwords[cword - 2].startswith("-"): return None for opt in opts: if opt.help == optparse.SUPPRESS_HELP: continue - for o in str(opt).split('/'): - if cwords[cword - 2].split('=')[0] == o: + for o in str(opt).split("/"): + if cwords[cword - 2].split("=")[0] == o: if not opt.metavar or any( - x in ('path', 'file', 'dir') - for x in opt.metavar.split('/')): + x in ("path", "file", "dir") for x in opt.metavar.split("/") + ): return opt.metavar return None @@ -150,15 +153,16 @@ def auto_complete_paths(current, completion_type): return filename = os.path.normcase(filename) # list all files that start with ``filename`` - file_list = (x for x in os.listdir(current_path) - if os.path.normcase(x).startswith(filename)) + file_list = ( + x for x in os.listdir(current_path) if os.path.normcase(x).startswith(filename) + ) for f in file_list: opt = os.path.join(current_path, f) comp_file = os.path.normcase(os.path.join(directory, f)) # complete regular files when there is not ```` after option # complete directories when there is ````, ```` or # ````after option - if completion_type != 'dir' and os.path.isfile(opt): + if completion_type != "dir" and os.path.isfile(opt): yield comp_file elif os.path.isdir(opt): - yield os.path.join(comp_file, '') + yield os.path.join(comp_file, "") diff --git a/src/pip/_internal/cli/base_command.py b/src/pip/_internal/cli/base_command.py index 8f14aa6b7a1..bbb15a971df 100644 --- a/src/pip/_internal/cli/base_command.py +++ b/src/pip/_internal/cli/base_command.py @@ -12,10 +12,7 @@ from pip._internal.cli import cmdoptions from pip._internal.cli.command_context import CommandContextMixIn -from pip._internal.cli.parser import ( - ConfigOptionParser, - UpdatingDefaultsHelpFormatter, -) +from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter from pip._internal.cli.status_codes import ( ERROR, PREVIOUS_BUILD_DIR_ERROR, @@ -35,10 +32,7 @@ from pip._internal.utils.filesystem import check_path_owner from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging from pip._internal.utils.misc import get_prog, normalize_path -from pip._internal.utils.temp_dir import ( - global_tempdir_manager, - tempdir_registry, -) +from pip._internal.utils.temp_dir import global_tempdir_manager, tempdir_registry from pip._internal.utils.typing import MYPY_CHECK_RUNNING from pip._internal.utils.virtualenv import running_under_virtualenv @@ -46,10 +40,11 @@ from optparse import Values from typing import Any, List, Optional, Tuple - from pip._internal.utils.temp_dir import \ - TempDirectoryTypeRegistry as TempDirRegistry + from pip._internal.utils.temp_dir import ( + TempDirectoryTypeRegistry as TempDirRegistry, + ) -__all__ = ['Command'] +__all__ = ["Command"] logger = logging.getLogger(__name__) @@ -62,13 +57,13 @@ def __init__(self, name, summary, isolated=False): # type: (str, str, bool) -> None super(Command, self).__init__() parser_kw = { - 'usage': self.usage, - 'prog': '{} {}'.format(get_prog(), name), - 'formatter': UpdatingDefaultsHelpFormatter(), - 'add_help_option': False, - 'name': name, - 'description': self.__doc__, - 'isolated': isolated, + "usage": self.usage, + "prog": "{} {}".format(get_prog(), name), + "formatter": UpdatingDefaultsHelpFormatter(), + "add_help_option": False, + "name": name, + "description": self.__doc__, + "isolated": isolated, } self.name = name @@ -78,7 +73,7 @@ def __init__(self, name, summary, isolated=False): self.tempdir_registry = None # type: Optional[TempDirRegistry] # Commands should add options to this option group - optgroup_name = '{} Options'.format(self.name.capitalize()) + optgroup_name = "{} Options".format(self.name.capitalize()) self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) # Add the general options @@ -102,7 +97,7 @@ def handle_pip_version_check(self, options): """ # Make sure we do the pip version check if the index_group options # are present. - assert not hasattr(options, 'no_index') + assert not hasattr(options, "no_index") def run(self, options, args): # type: (Values, List[Any]) -> int @@ -142,10 +137,7 @@ def _main(self, args): user_log_file=options.log, ) - if ( - sys.version_info[:2] == (2, 7) and - not options.no_python_version_warning - ): + if sys.version_info[:2] == (2, 7) and not options.no_python_version_warning: message = ( "pip 21.0 will drop support for Python 2.7 in January 2021. " "More details about Python 2 support in pip can be found at " @@ -159,10 +151,7 @@ def _main(self, args): ) + message deprecated(message, replacement=None, gone_in="21.0") - if ( - sys.version_info[:2] == (3, 5) and - not options.no_python_version_warning - ): + if sys.version_info[:2] == (3, 5) and not options.no_python_version_warning: message = ( "Python 3.5 reached the end of its life on September " "13th, 2020. Please upgrade your Python as Python 3.5 " @@ -176,17 +165,15 @@ def _main(self, args): # This also affects isolated builds and it should. if options.no_input: - os.environ['PIP_NO_INPUT'] = '1' + os.environ["PIP_NO_INPUT"] = "1" if options.exists_action: - os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) + os.environ["PIP_EXISTS_ACTION"] = " ".join(options.exists_action) if options.require_venv and not self.ignore_require_venv: # If a venv is required check if it can really be found if not running_under_virtualenv(): - logger.critical( - 'Could not find an activated virtualenv (required).' - ) + logger.critical("Could not find an activated virtualenv (required).") sys.exit(VIRTUALENV_NOT_FOUND) if options.cache_dir: @@ -216,7 +203,7 @@ def _main(self, args): issue=8333, ) - if 'resolver' in options.unstable_features: + if "resolver" in options.unstable_features: logger.critical( "--unstable-feature=resolver is no longer supported, and " "has been replaced with --use-feature=2020-resolver instead." @@ -229,35 +216,40 @@ def _main(self, args): return status except PreviousBuildDirError as exc: logger.critical(str(exc)) - logger.debug('Exception information:', exc_info=True) + logger.debug("Exception information:", exc_info=True) return PREVIOUS_BUILD_DIR_ERROR - except (InstallationError, UninstallationError, BadCommand, - SubProcessError, NetworkConnectionError) as exc: + except ( + InstallationError, + UninstallationError, + BadCommand, + SubProcessError, + NetworkConnectionError, + ) as exc: logger.critical(str(exc)) - logger.debug('Exception information:', exc_info=True) + logger.debug("Exception information:", exc_info=True) return ERROR except CommandError as exc: - logger.critical('%s', exc) - logger.debug('Exception information:', exc_info=True) + logger.critical("%s", exc) + logger.debug("Exception information:", exc_info=True) return ERROR except BrokenStdoutLoggingError: # Bypass our logger and write any remaining messages to stderr # because stdout no longer works. - print('ERROR: Pipe to stdout was broken', file=sys.stderr) + print("ERROR: Pipe to stdout was broken", file=sys.stderr) if level_number <= logging.DEBUG: traceback.print_exc(file=sys.stderr) return ERROR except KeyboardInterrupt: - logger.critical('Operation cancelled by user') - logger.debug('Exception information:', exc_info=True) + logger.critical("Operation cancelled by user") + logger.debug("Exception information:", exc_info=True) return ERROR except BaseException: - logger.critical('Exception:', exc_info=True) + logger.critical("Exception:", exc_info=True) return UNKNOWN_ERROR finally: diff --git a/src/pip/_internal/cli/cmdoptions.py b/src/pip/_internal/cli/cmdoptions.py index 2f640b2cbb2..58e2fc2408c 100644 --- a/src/pip/_internal/cli/cmdoptions.py +++ b/src/pip/_internal/cli/cmdoptions.py @@ -46,8 +46,8 @@ def raise_option_error(parser, option, msg): option: an Option instance. msg: the error text. """ - msg = '{} error: {}'.format(option, msg) - msg = textwrap.fill(' '.join(msg.split())) + msg = "{} error: {}".format(option, msg) + msg = textwrap.fill(" ".join(msg.split())) parser.error(msg) @@ -58,8 +58,8 @@ def make_option_group(group, parser): group -- assumed to be dict with 'name' and 'options' keys parser -- an optparse Parser """ - option_group = OptionGroup(parser, group['name']) - for option in group['options']: + option_group = OptionGroup(parser, group["name"]) + for option in group["options"]: option_group.add_option(option()) return option_group @@ -78,13 +78,15 @@ def check_install_build_global(options, check_options=None): def getname(n): # type: (str) -> Optional[Any] return getattr(check_options, n, None) + names = ["build_options", "global_options", "install_options"] if any(map(getname, names)): control = options.format_control control.disallow_binaries() warnings.warn( - 'Disabling all use of wheels due to the use of --build-option ' - '/ --global-option / --install-option.', stacklevel=2, + "Disabling all use of wheels due to the use of --build-option " + "/ --global-option / --install-option.", + stacklevel=2, ) @@ -95,17 +97,18 @@ def check_dist_restriction(options, check_target=False): :param options: The OptionParser options. :param check_target: Whether or not to check if --target is being used. """ - dist_restriction_set = any([ - options.python_version, - options.platform, - options.abi, - options.implementation, - ]) - - binary_only = FormatControl(set(), {':all:'}) + dist_restriction_set = any( + [ + options.python_version, + options.platform, + options.abi, + options.implementation, + ] + ) + + binary_only = FormatControl(set(), {":all:"}) sdist_dependencies_allowed = ( - options.format_control != binary_only and - not options.ignore_dependencies + options.format_control != binary_only and not options.ignore_dependencies ) # Installations or downloads using dist restrictions must not combine @@ -145,10 +148,11 @@ class PipOption(Option): help_ = partial( Option, - '-h', '--help', - dest='help', - action='help', - help='Show help.', + "-h", + "--help", + dest="help", + action="help", + help="Show help.", ) # type: Callable[..., Option] isolated_mode = partial( @@ -166,111 +170,119 @@ class PipOption(Option): require_virtualenv = partial( Option, # Run only if inside a virtualenv, bail if not. - '--require-virtualenv', '--require-venv', - dest='require_venv', - action='store_true', + "--require-virtualenv", + "--require-venv", + dest="require_venv", + action="store_true", default=False, - help=SUPPRESS_HELP + help=SUPPRESS_HELP, ) # type: Callable[..., Option] verbose = partial( Option, - '-v', '--verbose', - dest='verbose', - action='count', + "-v", + "--verbose", + dest="verbose", + action="count", default=0, - help='Give more output. Option is additive, and can be used up to 3 times.' + help="Give more output. Option is additive, and can be used up to 3 times.", ) # type: Callable[..., Option] no_color = partial( Option, - '--no-color', - dest='no_color', - action='store_true', + "--no-color", + dest="no_color", + action="store_true", default=False, help="Suppress colored output.", ) # type: Callable[..., Option] version = partial( Option, - '-V', '--version', - dest='version', - action='store_true', - help='Show version and exit.', + "-V", + "--version", + dest="version", + action="store_true", + help="Show version and exit.", ) # type: Callable[..., Option] quiet = partial( Option, - '-q', '--quiet', - dest='quiet', - action='count', + "-q", + "--quiet", + dest="quiet", + action="count", default=0, help=( - 'Give less output. Option is additive, and can be used up to 3' - ' times (corresponding to WARNING, ERROR, and CRITICAL logging' - ' levels).' + "Give less output. Option is additive, and can be used up to 3" + " times (corresponding to WARNING, ERROR, and CRITICAL logging" + " levels)." ), ) # type: Callable[..., Option] progress_bar = partial( Option, - '--progress-bar', - dest='progress_bar', - type='choice', + "--progress-bar", + dest="progress_bar", + type="choice", choices=list(BAR_TYPES.keys()), - default='on', + default="on", help=( - 'Specify type of progress to be displayed [' + - '|'.join(BAR_TYPES.keys()) + '] (default: %default)' + "Specify type of progress to be displayed [" + + "|".join(BAR_TYPES.keys()) + + "] (default: %default)" ), ) # type: Callable[..., Option] log = partial( PipOption, - "--log", "--log-file", "--local-log", + "--log", + "--log-file", + "--local-log", dest="log", metavar="path", type="path", - help="Path to a verbose appending log." + help="Path to a verbose appending log.", ) # type: Callable[..., Option] no_input = partial( Option, # Don't ask for input - '--no-input', - dest='no_input', - action='store_true', + "--no-input", + dest="no_input", + action="store_true", default=False, - help="Disable prompting for input." + help="Disable prompting for input.", ) # type: Callable[..., Option] proxy = partial( Option, - '--proxy', - dest='proxy', - type='str', - default='', - help="Specify a proxy in the form [user:passwd@]proxy.server:port." + "--proxy", + dest="proxy", + type="str", + default="", + help="Specify a proxy in the form [user:passwd@]proxy.server:port.", ) # type: Callable[..., Option] retries = partial( Option, - '--retries', - dest='retries', - type='int', + "--retries", + dest="retries", + type="int", default=5, help="Maximum number of retries each connection should attempt " - "(default %default times).", + "(default %default times).", ) # type: Callable[..., Option] timeout = partial( Option, - '--timeout', '--default-timeout', - metavar='sec', - dest='timeout', - type='float', + "--timeout", + "--default-timeout", + metavar="sec", + dest="timeout", + type="float", default=15, - help='Set the socket timeout (default %default seconds).', + help="Set the socket timeout (default %default seconds).", ) # type: Callable[..., Option] @@ -278,88 +290,91 @@ def exists_action(): # type: () -> Option return Option( # Option when path already exist - '--exists-action', - dest='exists_action', - type='choice', - choices=['s', 'i', 'w', 'b', 'a'], + "--exists-action", + dest="exists_action", + type="choice", + choices=["s", "i", "w", "b", "a"], default=[], - action='append', - metavar='action', + action="append", + metavar="action", help="Default action when a path already exists: " - "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.", + "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.", ) cert = partial( PipOption, - '--cert', - dest='cert', - type='path', - metavar='path', + "--cert", + dest="cert", + type="path", + metavar="path", help="Path to alternate CA bundle.", ) # type: Callable[..., Option] client_cert = partial( PipOption, - '--client-cert', - dest='client_cert', - type='path', + "--client-cert", + dest="client_cert", + type="path", default=None, - metavar='path', + metavar="path", help="Path to SSL client certificate, a single file containing the " - "private key and the certificate in PEM format.", + "private key and the certificate in PEM format.", ) # type: Callable[..., Option] index_url = partial( Option, - '-i', '--index-url', '--pypi-url', - dest='index_url', - metavar='URL', + "-i", + "--index-url", + "--pypi-url", + dest="index_url", + metavar="URL", default=PyPI.simple_url, help="Base URL of the Python Package Index (default %default). " - "This should point to a repository compliant with PEP 503 " - "(the simple repository API) or a local directory laid out " - "in the same format.", + "This should point to a repository compliant with PEP 503 " + "(the simple repository API) or a local directory laid out " + "in the same format.", ) # type: Callable[..., Option] def extra_index_url(): # type: () -> Option return Option( - '--extra-index-url', - dest='extra_index_urls', - metavar='URL', - action='append', + "--extra-index-url", + dest="extra_index_urls", + metavar="URL", + action="append", default=[], help="Extra URLs of package indexes to use in addition to " - "--index-url. Should follow the same rules as " - "--index-url.", + "--index-url. Should follow the same rules as " + "--index-url.", ) no_index = partial( Option, - '--no-index', - dest='no_index', - action='store_true', + "--no-index", + dest="no_index", + action="store_true", default=False, - help='Ignore package index (only looking at --find-links URLs instead).', + help="Ignore package index (only looking at --find-links URLs instead).", ) # type: Callable[..., Option] def find_links(): # type: () -> Option return Option( - '-f', '--find-links', - dest='find_links', - action='append', + "-f", + "--find-links", + dest="find_links", + action="append", default=[], - metavar='url', + metavar="url", help="If a URL or path to an html file, then parse for links to " - "archives such as sdist (.tar.gz) or wheel (.whl) files. " - "If a local path or file:// URL that's a directory, " - "then look for archives in the directory listing. " - "Links to VCS project URLs are not supported.", + "archives such as sdist (.tar.gz) or wheel (.whl) files. " + "If a local path or file:// URL that's a directory, " + "then look for archives in the directory listing. " + "Links to VCS project URLs are not supported.", ) @@ -372,46 +387,51 @@ def trusted_host(): metavar="HOSTNAME", default=[], help="Mark this host or host:port pair as trusted, even though it " - "does not have valid or any HTTPS.", + "does not have valid or any HTTPS.", ) def constraints(): # type: () -> Option return Option( - '-c', '--constraint', - dest='constraints', - action='append', + "-c", + "--constraint", + dest="constraints", + action="append", default=[], - metavar='file', - help='Constrain versions using the given constraints file. ' - 'This option can be used multiple times.' + metavar="file", + help="Constrain versions using the given constraints file. " + "This option can be used multiple times.", ) def requirements(): # type: () -> Option return Option( - '-r', '--requirement', - dest='requirements', - action='append', + "-r", + "--requirement", + dest="requirements", + action="append", default=[], - metavar='file', - help='Install from the given requirements file. ' - 'This option can be used multiple times.' + metavar="file", + help="Install from the given requirements file. " + "This option can be used multiple times.", ) def editable(): # type: () -> Option return Option( - '-e', '--editable', - dest='editables', - action='append', + "-e", + "--editable", + dest="editables", + action="append", default=[], - metavar='path/url', - help=('Install a project in editable mode (i.e. setuptools ' - '"develop mode") from a local project path or a VCS url.'), + metavar="path/url", + help=( + "Install a project in editable mode (i.e. setuptools " + '"develop mode") from a local project path or a VCS url.' + ), ) @@ -423,16 +443,19 @@ def _handle_src(option, opt_str, value, parser): src = partial( PipOption, - '--src', '--source', '--source-dir', '--source-directory', - dest='src_dir', - type='path', - metavar='dir', + "--src", + "--source", + "--source-dir", + "--source-directory", + dest="src_dir", + type="path", + metavar="dir", default=get_src_prefix(), - action='callback', + action="callback", callback=_handle_src, - help='Directory to check out editable projects into. ' + help="Directory to check out editable projects into. " 'The default in a virtualenv is "/src". ' - 'The default for global installs is "/src".' + 'The default for global installs is "/src".', ) # type: Callable[..., Option] @@ -446,7 +469,9 @@ def _handle_no_binary(option, opt_str, value, parser): # type: (Option, str, str, OptionParser) -> None existing = _get_format_control(parser.values, option) FormatControl.handle_mutual_excludes( - value, existing.no_binary, existing.only_binary, + value, + existing.no_binary, + existing.only_binary, ) @@ -454,7 +479,9 @@ def _handle_only_binary(option, opt_str, value, parser): # type: (Option, str, str, OptionParser) -> None existing = _get_format_control(parser.values, option) FormatControl.handle_mutual_excludes( - value, existing.only_binary, existing.no_binary, + value, + existing.only_binary, + existing.no_binary, ) @@ -462,15 +489,18 @@ def no_binary(): # type: () -> Option format_control = FormatControl(set(), set()) return Option( - "--no-binary", dest="format_control", action="callback", - callback=_handle_no_binary, type="str", + "--no-binary", + dest="format_control", + action="callback", + callback=_handle_no_binary, + type="str", default=format_control, - help='Do not use binary packages. Can be supplied multiple times, and ' - 'each time adds to the existing value. Accepts either ":all:" to ' - 'disable all binary packages, ":none:" to empty the set (notice ' - 'the colons), or one or more package names with commas between ' - 'them (no colons). Note that some packages are tricky to compile ' - 'and may fail to install when this option is used on them.', + help="Do not use binary packages. Can be supplied multiple times, and " + 'each time adds to the existing value. Accepts either ":all:" to ' + 'disable all binary packages, ":none:" to empty the set (notice ' + "the colons), or one or more package names with commas between " + "them (no colons). Note that some packages are tricky to compile " + "and may fail to install when this option is used on them.", ) @@ -478,26 +508,31 @@ def only_binary(): # type: () -> Option format_control = FormatControl(set(), set()) return Option( - "--only-binary", dest="format_control", action="callback", - callback=_handle_only_binary, type="str", + "--only-binary", + dest="format_control", + action="callback", + callback=_handle_only_binary, + type="str", default=format_control, - help='Do not use source packages. Can be supplied multiple times, and ' - 'each time adds to the existing value. Accepts either ":all:" to ' - 'disable all source packages, ":none:" to empty the set, or one ' - 'or more package names with commas between them. Packages ' - 'without binary distributions will fail to install when this ' - 'option is used on them.', + help="Do not use source packages. Can be supplied multiple times, and " + 'each time adds to the existing value. Accepts either ":all:" to ' + 'disable all source packages, ":none:" to empty the set, or one ' + "or more package names with commas between them. Packages " + "without binary distributions will fail to install when this " + "option is used on them.", ) platform = partial( Option, - '--platform', - dest='platform', - metavar='platform', + "--platform", + dest="platform", + metavar="platform", default=None, - help=("Only use wheels compatible with . " - "Defaults to the platform of the running system."), + help=( + "Only use wheels compatible with . " + "Defaults to the platform of the running system." + ), ) # type: Callable[..., Option] @@ -514,9 +549,9 @@ def _convert_python_version(value): # The empty string is the same as not providing a value. return (None, None) - parts = value.split('.') + parts = value.split(".") if len(parts) > 3: - return ((), 'at most three version parts are allowed') + return ((), "at most three version parts are allowed") if len(parts) == 1: # Then we are in the case of "3" or "37". @@ -527,7 +562,7 @@ def _convert_python_version(value): try: version_info = tuple(int(part) for part in parts) except ValueError: - return ((), 'each version part must be an integer') + return ((), "each version part must be an integer") return (version_info, None) @@ -539,10 +574,9 @@ def _handle_python_version(option, opt_str, value, parser): """ version_info, error_msg = _convert_python_version(value) if error_msg is not None: - msg = ( - 'invalid --python-version value: {!r}: {}'.format( - value, error_msg, - ) + msg = "invalid --python-version value: {!r}: {}".format( + value, + error_msg, ) raise_option_error(parser, option=option, msg=msg) @@ -551,48 +585,55 @@ def _handle_python_version(option, opt_str, value, parser): python_version = partial( Option, - '--python-version', - dest='python_version', - metavar='python_version', - action='callback', - callback=_handle_python_version, type='str', + "--python-version", + dest="python_version", + metavar="python_version", + action="callback", + callback=_handle_python_version, + type="str", default=None, - help=dedent("""\ + help=dedent( + """\ The Python interpreter version to use for wheel and "Requires-Python" compatibility checks. Defaults to a version derived from the running interpreter. The version can be specified using up to three dot-separated integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor version can also be given as a string without dots (e.g. "37" for 3.7.0). - """), + """ + ), ) # type: Callable[..., Option] implementation = partial( Option, - '--implementation', - dest='implementation', - metavar='implementation', + "--implementation", + dest="implementation", + metavar="implementation", default=None, - help=("Only use wheels compatible with Python " - "implementation , e.g. 'pp', 'jy', 'cp', " - " or 'ip'. If not specified, then the current " - "interpreter implementation is used. Use 'py' to force " - "implementation-agnostic wheels."), + help=( + "Only use wheels compatible with Python " + "implementation , e.g. 'pp', 'jy', 'cp', " + " or 'ip'. If not specified, then the current " + "interpreter implementation is used. Use 'py' to force " + "implementation-agnostic wheels." + ), ) # type: Callable[..., Option] abi = partial( Option, - '--abi', - dest='abi', - metavar='abi', + "--abi", + dest="abi", + metavar="abi", default=None, - help=("Only use wheels compatible with Python " - "abi , e.g. 'pypy_41'. If not specified, then the " - "current interpreter abi tag is used. Generally " - "you will need to specify --implementation, " - "--platform, and --python-version when using " - "this option."), + help=( + "Only use wheels compatible with Python " + "abi , e.g. 'pypy_41'. If not specified, then the " + "current interpreter abi tag is used. Generally " + "you will need to specify --implementation, " + "--platform, and --python-version when using " + "this option." + ), ) # type: Callable[..., Option] @@ -623,7 +664,7 @@ def prefer_binary(): dest="prefer_binary", action="store_true", default=False, - help="Prefer older binary packages over newer source packages." + help="Prefer older binary packages over newer source packages.", ) @@ -633,8 +674,8 @@ def prefer_binary(): dest="cache_dir", default=USER_CACHE_DIR, metavar="dir", - type='path', - help="Store the cache data in ." + type="path", + help="Store the cache data in .", ) # type: Callable[..., Option] @@ -677,9 +718,10 @@ def _handle_no_cache_dir(option, opt, value, parser): no_deps = partial( Option, - '--no-deps', '--no-dependencies', - dest='ignore_dependencies', - action='store_true', + "--no-deps", + "--no-dependencies", + dest="ignore_dependencies", + action="store_true", default=False, help="Don't install package dependencies.", ) # type: Callable[..., Option] @@ -694,37 +736,40 @@ def _handle_build_dir(option, opt, value, parser): build_dir = partial( PipOption, - '-b', '--build', '--build-dir', '--build-directory', - dest='build_dir', - type='path', - metavar='dir', - action='callback', + "-b", + "--build", + "--build-dir", + "--build-directory", + dest="build_dir", + type="path", + metavar="dir", + action="callback", callback=_handle_build_dir, - help='(DEPRECATED) ' - 'Directory to unpack packages into and build in. Note that ' - 'an initial build still takes place in a temporary directory. ' - 'The location of temporary directories can be controlled by setting ' - 'the TMPDIR environment variable (TEMP on Windows) appropriately. ' - 'When passed, build directories are not cleaned in case of failures.' + help="(DEPRECATED) " + "Directory to unpack packages into and build in. Note that " + "an initial build still takes place in a temporary directory. " + "The location of temporary directories can be controlled by setting " + "the TMPDIR environment variable (TEMP on Windows) appropriately. " + "When passed, build directories are not cleaned in case of failures.", ) # type: Callable[..., Option] ignore_requires_python = partial( Option, - '--ignore-requires-python', - dest='ignore_requires_python', - action='store_true', - help='Ignore the Requires-Python information.' + "--ignore-requires-python", + dest="ignore_requires_python", + action="store_true", + help="Ignore the Requires-Python information.", ) # type: Callable[..., Option] no_build_isolation = partial( Option, - '--no-build-isolation', - dest='build_isolation', - action='store_false', + "--no-build-isolation", + dest="build_isolation", + action="store_false", default=True, - help='Disable isolation when building a modern source distribution. ' - 'Build dependencies specified by PEP 518 must be already installed ' - 'if this option is used.' + help="Disable isolation when building a modern source distribution. " + "Build dependencies specified by PEP 518 must be already installed " + "if this option is used.", ) # type: Callable[..., Option] @@ -754,62 +799,62 @@ def _handle_no_use_pep517(option, opt, value, parser): use_pep517 = partial( Option, - '--use-pep517', - dest='use_pep517', - action='store_true', + "--use-pep517", + dest="use_pep517", + action="store_true", default=None, - help='Use PEP 517 for building source distributions ' - '(use --no-use-pep517 to force legacy behaviour).' + help="Use PEP 517 for building source distributions " + "(use --no-use-pep517 to force legacy behaviour).", ) # type: Any no_use_pep517 = partial( Option, - '--no-use-pep517', - dest='use_pep517', - action='callback', + "--no-use-pep517", + dest="use_pep517", + action="callback", callback=_handle_no_use_pep517, default=None, - help=SUPPRESS_HELP + help=SUPPRESS_HELP, ) # type: Any install_options = partial( Option, - '--install-option', - dest='install_options', - action='append', - metavar='options', + "--install-option", + dest="install_options", + action="append", + metavar="options", help="Extra arguments to be supplied to the setup.py install " - "command (use like --install-option=\"--install-scripts=/usr/local/" - "bin\"). Use multiple --install-option options to pass multiple " - "options to setup.py install. If you are using an option with a " - "directory path, be sure to use absolute path.", + 'command (use like --install-option="--install-scripts=/usr/local/' + 'bin"). Use multiple --install-option options to pass multiple ' + "options to setup.py install. If you are using an option with a " + "directory path, be sure to use absolute path.", ) # type: Callable[..., Option] global_options = partial( Option, - '--global-option', - dest='global_options', - action='append', - metavar='options', + "--global-option", + dest="global_options", + action="append", + metavar="options", help="Extra global options to be supplied to the setup.py " - "call before the install command.", + "call before the install command.", ) # type: Callable[..., Option] no_clean = partial( Option, - '--no-clean', - action='store_true', + "--no-clean", + action="store_true", default=False, - help="Don't clean up build directories." + help="Don't clean up build directories.", ) # type: Callable[..., Option] pre = partial( Option, - '--pre', - action='store_true', + "--pre", + action="store_true", default=False, help="Include pre-release and development versions. By default, " - "pip only finds stable versions.", + "pip only finds stable versions.", ) # type: Callable[..., Option] disable_pip_version_check = partial( @@ -819,7 +864,7 @@ def _handle_no_use_pep517(option, opt, value, parser): action="store_true", default=False, help="Don't periodically check PyPI to determine whether a new version " - "of pip is available for download. Implied with --no-index.", + "of pip is available for download. Implied with --no-index.", ) # type: Callable[..., Option] @@ -830,105 +875,106 @@ def _handle_merge_hash(option, opt_str, value, parser): if not parser.values.hashes: parser.values.hashes = {} try: - algo, digest = value.split(':', 1) + algo, digest = value.split(":", 1) except ValueError: - parser.error('Arguments to {} must be a hash name ' # noqa - 'followed by a value, like --hash=sha256:' - 'abcde...'.format(opt_str)) + parser.error( + "Arguments to {} must be a hash name " # noqa + "followed by a value, like --hash=sha256:" + "abcde...".format(opt_str) + ) if algo not in STRONG_HASHES: - parser.error('Allowed hash algorithms for {} are {}.'.format( # noqa - opt_str, ', '.join(STRONG_HASHES))) + parser.error( + "Allowed hash algorithms for {} are {}.".format( # noqa + opt_str, ", ".join(STRONG_HASHES) + ) + ) parser.values.hashes.setdefault(algo, []).append(digest) hash = partial( Option, - '--hash', + "--hash", # Hash values eventually end up in InstallRequirement.hashes due to # __dict__ copying in process_line(). - dest='hashes', - action='callback', + dest="hashes", + action="callback", callback=_handle_merge_hash, - type='string', + type="string", help="Verify that the package's archive matches this " - 'hash before installing. Example: --hash=sha256:abcdef...', + "hash before installing. Example: --hash=sha256:abcdef...", ) # type: Callable[..., Option] require_hashes = partial( Option, - '--require-hashes', - dest='require_hashes', - action='store_true', + "--require-hashes", + dest="require_hashes", + action="store_true", default=False, - help='Require a hash to check each requirement against, for ' - 'repeatable installs. This option is implied when any package in a ' - 'requirements file has a --hash option.', + help="Require a hash to check each requirement against, for " + "repeatable installs. This option is implied when any package in a " + "requirements file has a --hash option.", ) # type: Callable[..., Option] list_path = partial( PipOption, - '--path', - dest='path', - type='path', - action='append', - help='Restrict to the specified installation path for listing ' - 'packages (can be used multiple times).' + "--path", + dest="path", + type="path", + action="append", + help="Restrict to the specified installation path for listing " + "packages (can be used multiple times).", ) # type: Callable[..., Option] def check_list_path_option(options): # type: (Values) -> None if options.path and (options.user or options.local): - raise CommandError( - "Cannot combine '--path' with '--user' or '--local'" - ) + raise CommandError("Cannot combine '--path' with '--user' or '--local'") no_python_version_warning = partial( Option, - '--no-python-version-warning', - dest='no_python_version_warning', - action='store_true', + "--no-python-version-warning", + dest="no_python_version_warning", + action="store_true", default=False, - help='Silence deprecation warnings for upcoming unsupported Pythons.', + help="Silence deprecation warnings for upcoming unsupported Pythons.", ) # type: Callable[..., Option] unstable_feature = partial( Option, - '--unstable-feature', - dest='unstable_features', - metavar='feature', - action='append', + "--unstable-feature", + dest="unstable_features", + metavar="feature", + action="append", default=[], - choices=['resolver'], + choices=["resolver"], help=SUPPRESS_HELP, # TODO: drop this in pip 20.3 ) # type: Callable[..., Option] use_new_feature = partial( Option, - '--use-feature', - dest='features_enabled', - metavar='feature', - action='append', + "--use-feature", + dest="features_enabled", + metavar="feature", + action="append", default=[], - choices=['2020-resolver', 'fast-deps'], - help='Enable new functionality, that may be backward incompatible.', + choices=["2020-resolver", "fast-deps"], + help="Enable new functionality, that may be backward incompatible.", ) # type: Callable[..., Option] use_deprecated_feature = partial( Option, - '--use-deprecated', - dest='deprecated_features_enabled', - metavar='feature', - action='append', + "--use-deprecated", + dest="deprecated_features_enabled", + metavar="feature", + action="append", default=[], choices=[], - help=( - 'Enable deprecated functionality, that will be removed in the future.' - ), + help=("Enable deprecated functionality, that will be removed in the future."), ) # type: Callable[..., Option] @@ -937,8 +983,8 @@ def check_list_path_option(options): ########## general_group = { - 'name': 'General Options', - 'options': [ + "name": "General Options", + "options": [ help_, isolated_mode, require_virtualenv, @@ -962,15 +1008,15 @@ def check_list_path_option(options): unstable_feature, use_new_feature, use_deprecated_feature, - ] + ], } # type: Dict[str, Any] index_group = { - 'name': 'Package Index Options', - 'options': [ + "name": "Package Index Options", + "options": [ index_url, extra_index_url, no_index, find_links, - ] + ], } # type: Dict[str, Any] diff --git a/src/pip/_internal/cli/command_context.py b/src/pip/_internal/cli/command_context.py index 669c777749d..c1696824bc1 100644 --- a/src/pip/_internal/cli/command_context.py +++ b/src/pip/_internal/cli/command_context.py @@ -7,7 +7,7 @@ if MYPY_CHECK_RUNNING: from typing import ContextManager, Iterator, TypeVar - _T = TypeVar('_T', covariant=True) + _T = TypeVar("_T", covariant=True) class CommandContextMixIn(object): diff --git a/src/pip/_internal/cli/main.py b/src/pip/_internal/cli/main.py index 172f30dd5bf..9c853fb5c5e 100644 --- a/src/pip/_internal/cli/main.py +++ b/src/pip/_internal/cli/main.py @@ -46,6 +46,7 @@ # call to main. As it is not safe to do any processing after calling # main, this should not be an issue in practice. + def main(args=None): # type: (Optional[List[str]]) -> int if args is None: @@ -66,7 +67,7 @@ def main(args=None): # Needed for locale.getpreferredencoding(False) to work # in pip._internal.utils.encoding.auto_decode try: - locale.setlocale(locale.LC_ALL, '') + locale.setlocale(locale.LC_ALL, "") except locale.Error as e: # setlocale can apparently crash if locale are uninitialized logger.debug("Ignoring error %s when setting locale", e) diff --git a/src/pip/_internal/cli/main_parser.py b/src/pip/_internal/cli/main_parser.py index 6356d831df1..ec1eec73f2e 100644 --- a/src/pip/_internal/cli/main_parser.py +++ b/src/pip/_internal/cli/main_parser.py @@ -5,10 +5,7 @@ import sys from pip._internal.cli import cmdoptions -from pip._internal.cli.parser import ( - ConfigOptionParser, - UpdatingDefaultsHelpFormatter, -) +from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter from pip._internal.commands import commands_dict, get_similar_commands from pip._internal.exceptions import CommandError from pip._internal.utils.misc import get_pip_version, get_prog @@ -23,15 +20,14 @@ def create_main_parser(): # type: () -> ConfigOptionParser - """Creates and returns the main parser for pip's CLI - """ + """Creates and returns the main parser for pip's CLI""" parser_kw = { - 'usage': '\n%prog [options]', - 'add_help_option': False, - 'formatter': UpdatingDefaultsHelpFormatter(), - 'name': 'global', - 'prog': get_prog(), + "usage": "\n%prog [options]", + "add_help_option": False, + "formatter": UpdatingDefaultsHelpFormatter(), + "name": "global", + "prog": get_prog(), } parser = ConfigOptionParser(**parser_kw) @@ -47,11 +43,11 @@ def create_main_parser(): parser.main = True # type: ignore # create command listing for description - description = [''] + [ - '{name:27} {command_info.summary}'.format(**locals()) + description = [""] + [ + "{name:27} {command_info.summary}".format(**locals()) for name, command_info in commands_dict.items() ] - parser.description = '\n'.join(description) + parser.description = "\n".join(description) return parser @@ -76,7 +72,7 @@ def parse_command(args): sys.exit() # pip || pip help -> print_help() - if not args_else or (args_else[0] == 'help' and len(args_else) == 1): + if not args_else or (args_else[0] == "help" and len(args_else) == 1): parser.print_help() sys.exit() @@ -90,7 +86,7 @@ def parse_command(args): if guess: msg.append('maybe you meant "{}"'.format(guess)) - raise CommandError(' - '.join(msg)) + raise CommandError(" - ".join(msg)) # all the args without the subcommand cmd_args = args[:] diff --git a/src/pip/_internal/cli/parser.py b/src/pip/_internal/cli/parser.py index b6b78318a7a..6b6ffc3c147 100644 --- a/src/pip/_internal/cli/parser.py +++ b/src/pip/_internal/cli/parser.py @@ -26,15 +26,15 @@ class PrettyHelpFormatter(optparse.IndentedHelpFormatter): def __init__(self, *args, **kwargs): # help position must be aligned with __init__.parseopts.description - kwargs['max_help_position'] = 30 - kwargs['indent_increment'] = 1 - kwargs['width'] = get_terminal_size()[0] - 2 + kwargs["max_help_position"] = 30 + kwargs["indent_increment"] = 1 + kwargs["width"] = get_terminal_size()[0] - 2 optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs) def format_option_strings(self, option): return self._format_option_strings(option) - def _format_option_strings(self, option, mvarfmt=' <{}>', optsep=', '): + def _format_option_strings(self, option, mvarfmt=" <{}>", optsep=", "): """ Return a comma-separated list of option strings and metavars. @@ -55,49 +55,48 @@ def _format_option_strings(self, option, mvarfmt=' <{}>', optsep=', '): metavar = option.metavar or option.dest.lower() opts.append(mvarfmt.format(metavar.lower())) - return ''.join(opts) + return "".join(opts) def format_heading(self, heading): - if heading == 'Options': - return '' - return heading + ':\n' + if heading == "Options": + return "" + return heading + ":\n" def format_usage(self, usage): """ Ensure there is only one newline between usage and the first heading if there is no description. """ - msg = '\nUsage: {}\n'.format( - self.indent_lines(textwrap.dedent(usage), " ")) + msg = "\nUsage: {}\n".format(self.indent_lines(textwrap.dedent(usage), " ")) return msg def format_description(self, description): # leave full control over description to us if description: - if hasattr(self.parser, 'main'): - label = 'Commands' + if hasattr(self.parser, "main"): + label = "Commands" else: - label = 'Description' + label = "Description" # some doc strings have initial newlines, some don't - description = description.lstrip('\n') + description = description.lstrip("\n") # some doc strings have final newlines and spaces, some don't description = description.rstrip() # dedent, then reindent description = self.indent_lines(textwrap.dedent(description), " ") - description = '{}:\n{}\n'.format(label, description) + description = "{}:\n{}\n".format(label, description) return description else: - return '' + return "" def format_epilog(self, epilog): # leave full control over epilog to us if epilog: return epilog else: - return '' + return "" def indent_lines(self, text, indent): - new_lines = [indent + line for line in text.split('\n')] + new_lines = [indent + line for line in text.split("\n")] return "\n".join(new_lines) @@ -115,7 +114,6 @@ def expand_default(self, option): class CustomOptionParser(optparse.OptionParser): - def insert_option_group(self, idx, *args, **kwargs): """Insert an OptionGroup at a given position.""" group = self.add_option_group(*args, **kwargs) @@ -140,7 +138,7 @@ class ConfigOptionParser(CustomOptionParser): configuration files and environmental variables""" def __init__(self, *args, **kwargs): - self.name = kwargs.pop('name') + self.name = kwargs.pop("name") isolated = kwargs.pop("isolated", False) self.config = Configuration(isolated) @@ -166,7 +164,7 @@ def _get_ordered_configuration_items(self): if not val: logger.debug( "Ignoring configuration key '%s' as it's value is empty.", - section_key + section_key, ) continue @@ -190,7 +188,7 @@ def _update_defaults(self, defaults): # Then set the options with those values for key, val in self._get_ordered_configuration_items(): # '--' because configuration supports only long names - option = self.get_option('--' + key) + option = self.get_option("--" + key) # Ignore options not present in this parser. E.g. non-globals put # in [global] by users that want them to apply to all applicable @@ -198,31 +196,31 @@ def _update_defaults(self, defaults): if option is None: continue - if option.action in ('store_true', 'store_false'): + if option.action in ("store_true", "store_false"): try: val = strtobool(val) except ValueError: self.error( - '{} is not a valid value for {} option, ' # noqa - 'please specify a boolean value like yes/no, ' - 'true/false or 1/0 instead.'.format(val, key) + "{} is not a valid value for {} option, " # noqa + "please specify a boolean value like yes/no, " + "true/false or 1/0 instead.".format(val, key) ) - elif option.action == 'count': + elif option.action == "count": with suppress(ValueError): val = strtobool(val) with suppress(ValueError): val = int(val) if not isinstance(val, int) or val < 0: self.error( - '{} is not a valid value for {} option, ' # noqa - 'please instead specify either a non-negative integer ' - 'or a boolean value like yes/no or false/true ' - 'which is equivalent to 1/0.'.format(val, key) + "{} is not a valid value for {} option, " # noqa + "please instead specify either a non-negative integer " + "or a boolean value like yes/no or false/true " + "which is equivalent to 1/0.".format(val, key) ) - elif option.action == 'append': + elif option.action == "append": val = val.split() val = [self.check_default(option, key, v) for v in val] - elif option.action == 'callback': + elif option.action == "callback": late_eval.add(option.dest) opt_str = option.get_opt_string() val = option.convert_value(opt_str, val) diff --git a/src/pip/_internal/cli/progress_bars.py b/src/pip/_internal/cli/progress_bars.py index 69338552f13..7177fb82670 100644 --- a/src/pip/_internal/cli/progress_bars.py +++ b/src/pip/_internal/cli/progress_bars.py @@ -79,10 +79,7 @@ def __init__(self, *args, **kwargs): Save the original SIGINT handler for later. """ # https://github.com/python/mypy/issues/5887 - super(InterruptibleMixin, self).__init__( # type: ignore - *args, - **kwargs - ) + super(InterruptibleMixin, self).__init__(*args, **kwargs) # type: ignore self.original_handler = signal(SIGINT, self.handle_sigint) @@ -117,7 +114,6 @@ def handle_sigint(self, signum, frame): # type: ignore class SilentBar(Bar): - def update(self): # type: () -> None pass @@ -132,17 +128,11 @@ class BlueEmojiBar(IncrementalBar): class DownloadProgressMixin(object): - def __init__(self, *args, **kwargs): # type: (List[Any], Dict[Any, Any]) -> None # https://github.com/python/mypy/issues/5887 - super(DownloadProgressMixin, self).__init__( # type: ignore - *args, - **kwargs - ) - self.message = (" " * ( - get_indentation() + 2 - )) + self.message # type: str + super(DownloadProgressMixin, self).__init__(*args, **kwargs) # type: ignore + self.message = (" " * (get_indentation() + 2)) + self.message # type: str @property def downloaded(self): @@ -174,7 +164,6 @@ def iter(self, it): # type: ignore class WindowsMixin(object): - def __init__(self, *args, **kwargs): # type: (List[Any], Dict[Any, Any]) -> None # The Windows terminal does not support the hide/show cursor ANSI codes @@ -204,16 +193,14 @@ def __init__(self, *args, **kwargs): self.file.flush = lambda: self.file.wrapped.flush() -class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, - DownloadProgressMixin): +class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, DownloadProgressMixin): file = sys.stdout message = "%(percent)d%%" suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s" -class DefaultDownloadProgressBar(BaseDownloadProgressBar, - _BaseBar): +class DefaultDownloadProgressBar(BaseDownloadProgressBar, _BaseBar): pass @@ -221,23 +208,21 @@ class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): pass -class DownloadBar(BaseDownloadProgressBar, - Bar): +class DownloadBar(BaseDownloadProgressBar, Bar): pass -class DownloadFillingCirclesBar(BaseDownloadProgressBar, - FillingCirclesBar): +class DownloadFillingCirclesBar(BaseDownloadProgressBar, FillingCirclesBar): pass -class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, - BlueEmojiBar): +class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, BlueEmojiBar): pass -class DownloadProgressSpinner(WindowsMixin, InterruptibleMixin, - DownloadProgressMixin, Spinner): +class DownloadProgressSpinner( + WindowsMixin, InterruptibleMixin, DownloadProgressMixin, Spinner +): file = sys.stdout suffix = "%(downloaded)s %(download_speed)s" @@ -253,13 +238,15 @@ def update(self): message = self.message % self phase = self.next_phase() suffix = self.suffix % self - line = ''.join([ - message, - " " if message else "", - phase, - " " if suffix else "", - suffix, - ]) + line = "".join( + [ + message, + " " if message else "", + phase, + " " if suffix else "", + suffix, + ] + ) self.writeln(line) @@ -269,7 +256,7 @@ def update(self): "on": (DefaultDownloadProgressBar, DownloadProgressSpinner), "ascii": (DownloadBar, DownloadProgressSpinner), "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner), - "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner) + "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner), } diff --git a/src/pip/_internal/cli/req_command.py b/src/pip/_internal/cli/req_command.py index 76abce5acdf..647c1d34f35 100644 --- a/src/pip/_internal/cli/req_command.py +++ b/src/pip/_internal/cli/req_command.py @@ -38,10 +38,7 @@ from pip._internal.req.req_install import InstallRequirement from pip._internal.req.req_tracker import RequirementTracker from pip._internal.resolution.base import BaseResolver - from pip._internal.utils.temp_dir import ( - TempDirectory, - TempDirectoryTypeRegistry, - ) + from pip._internal.utils.temp_dir import TempDirectory, TempDirectoryTypeRegistry logger = logging.getLogger(__name__) @@ -52,6 +49,7 @@ class SessionCommandMixin(CommandContextMixIn): """ A class mixin for command classes needing _build_session(). """ + def __init__(self): # type: () -> None super(SessionCommandMixin, self).__init__() @@ -88,8 +86,7 @@ def _build_session(self, options, retries=None, timeout=None): assert not options.cache_dir or os.path.isabs(options.cache_dir) session = PipSession( cache=( - os.path.join(options.cache_dir, "http") - if options.cache_dir else None + os.path.join(options.cache_dir, "http") if options.cache_dir else None ), retries=retries if retries is not None else options.retries, trusted_hosts=options.trusted_hosts, @@ -106,9 +103,7 @@ def _build_session(self, options, retries=None, timeout=None): # Handle timeouts if options.timeout or timeout: - session.timeout = ( - timeout if timeout is not None else options.timeout - ) + session.timeout = timeout if timeout is not None else options.timeout # Handle configured proxies if options.proxy: @@ -139,16 +134,14 @@ def handle_pip_version_check(self, options): This overrides the default behavior of not doing the check. """ # Make sure the index_group options are present. - assert hasattr(options, 'no_index') + assert hasattr(options, "no_index") if options.disable_pip_version_check or options.no_index: return # Otherwise, check if we're using the latest version of pip available. session = self._build_session( - options, - retries=0, - timeout=min(5, options.timeout) + options, retries=0, timeout=min(5, options.timeout) ) with session: pip_self_version_check(session, options) @@ -166,6 +159,7 @@ def with_cleanup(func): """Decorator for common logic related to managing temporary directories. """ + def configure_tempdir_registry(registry): # type: (TempDirectoryTypeRegistry) -> None for t in KEEPABLE_TEMPDIR_TYPES: @@ -190,7 +184,6 @@ def wrapper(self, options, args): class RequirementCommand(IndexGroupCommand): - def __init__(self, *args, **kw): # type: (Any, Any) -> None super(RequirementCommand, self).__init__(*args, **kw) @@ -199,13 +192,13 @@ def __init__(self, *args, **kw): @staticmethod def make_requirement_preparer( - temp_build_dir, # type: TempDirectory - options, # type: Values - req_tracker, # type: RequirementTracker - session, # type: PipSession - finder, # type: PackageFinder - use_user_site, # type: bool - download_dir=None, # type: str + temp_build_dir, # type: TempDirectory + options, # type: Values + req_tracker, # type: RequirementTracker + session, # type: PipSession + finder, # type: PackageFinder + use_user_site, # type: bool + download_dir=None, # type: str wheel_download_dir=None, # type: str ): # type: (...) -> RequirementPreparer @@ -215,15 +208,15 @@ def make_requirement_preparer( temp_build_dir_path = temp_build_dir.path assert temp_build_dir_path is not None - if '2020-resolver' in options.features_enabled: - lazy_wheel = 'fast-deps' in options.features_enabled + if "2020-resolver" in options.features_enabled: + lazy_wheel = "fast-deps" in options.features_enabled if lazy_wheel: logger.warning( - 'pip is using lazily downloaded wheels using HTTP ' - 'range requests to obtain dependency information. ' - 'This experimental feature is enabled through ' - '--use-feature=fast-deps and it is not ready for ' - 'production.' + "pip is using lazily downloaded wheels using HTTP " + "range requests to obtain dependency information. " + "This experimental feature is enabled through " + "--use-feature=fast-deps and it is not ready for " + "production." ) else: lazy_wheel = False @@ -245,17 +238,17 @@ def make_requirement_preparer( @staticmethod def make_resolver( - preparer, # type: RequirementPreparer - finder, # type: PackageFinder - options, # type: Values - wheel_cache=None, # type: Optional[WheelCache] - use_user_site=False, # type: bool - ignore_installed=True, # type: bool - ignore_requires_python=False, # type: bool - force_reinstall=False, # type: bool + preparer, # type: RequirementPreparer + finder, # type: PackageFinder + options, # type: Values + wheel_cache=None, # type: Optional[WheelCache] + use_user_site=False, # type: bool + ignore_installed=True, # type: bool + ignore_requires_python=False, # type: bool + force_reinstall=False, # type: bool upgrade_strategy="to-satisfy-only", # type: str - use_pep517=None, # type: Optional[bool] - py_version_info=None # type: Optional[Tuple[int, ...]] + use_pep517=None, # type: Optional[bool] + py_version_info=None, # type: Optional[Tuple[int, ...]] ): # type: (...) -> BaseResolver """ @@ -269,7 +262,7 @@ def make_resolver( # The long import name and duplicated invocation is needed to convince # Mypy into correctly typechecking. Otherwise it would complain the # "Resolver" class being redefined. - if '2020-resolver' in options.features_enabled: + if "2020-resolver" in options.features_enabled: import pip._internal.resolution.resolvelib.resolver return pip._internal.resolution.resolvelib.resolver.Resolver( @@ -286,6 +279,7 @@ def make_resolver( py_version_info=py_version_info, ) import pip._internal.resolution.legacy.resolver + return pip._internal.resolution.legacy.resolver.Resolver( preparer=preparer, finder=finder, @@ -302,10 +296,10 @@ def make_resolver( def get_requirements( self, - args, # type: List[str] - options, # type: Values - finder, # type: PackageFinder - session, # type: PipSession + args, # type: List[str] + options, # type: Values + finder, # type: PackageFinder + session, # type: PipSession ): # type: (...) -> List[InstallRequirement] """ @@ -314,9 +308,12 @@ def get_requirements( requirements = [] # type: List[InstallRequirement] for filename in options.constraints: for parsed_req in parse_requirements( - filename, - constraint=True, finder=finder, options=options, - session=session): + filename, + constraint=True, + finder=finder, + options=options, + session=session, + ): req_to_add = install_req_from_parsed_requirement( parsed_req, isolated=options.isolated_mode, @@ -326,7 +323,9 @@ def get_requirements( for req in args: req_to_add = install_req_from_line( - req, None, isolated=options.isolated_mode, + req, + None, + isolated=options.isolated_mode, use_pep517=options.use_pep517, user_supplied=True, ) @@ -344,8 +343,8 @@ def get_requirements( # NOTE: options.require_hashes may be set if --require-hashes is True for filename in options.requirements: for parsed_req in parse_requirements( - filename, - finder=finder, options=options, session=session): + filename, finder=finder, options=options, session=session + ): req_to_add = install_req_from_parsed_requirement( parsed_req, isolated=options.isolated_mode, @@ -359,16 +358,19 @@ def get_requirements( options.require_hashes = True if not (args or options.editables or options.requirements): - opts = {'name': self.name} + opts = {"name": self.name} if options.find_links: raise CommandError( - 'You must give at least one requirement to {name} ' + "You must give at least one requirement to {name} " '(maybe you meant "pip {name} {links}"?)'.format( - **dict(opts, links=' '.join(options.find_links)))) + **dict(opts, links=" ".join(options.find_links)) + ) + ) else: raise CommandError( - 'You must give at least one requirement to {name} ' - '(see "pip help {name}")'.format(**opts)) + "You must give at least one requirement to {name} " + '(see "pip help {name}")'.format(**opts) + ) return requirements @@ -386,9 +388,9 @@ def trace_basic_info(finder): def _build_package_finder( self, - options, # type: Values - session, # type: PipSession - target_python=None, # type: Optional[TargetPython] + options, # type: Values + session, # type: PipSession + target_python=None, # type: Optional[TargetPython] ignore_requires_python=None, # type: Optional[bool] ): # type: (...) -> PackageFinder diff --git a/src/pip/_internal/cli/spinners.py b/src/pip/_internal/cli/spinners.py index 65c3c23d742..99cbd3fddc8 100644 --- a/src/pip/_internal/cli/spinners.py +++ b/src/pip/_internal/cli/spinners.py @@ -29,9 +29,14 @@ def finish(self, final_status): class InteractiveSpinner(SpinnerInterface): - def __init__(self, message, file=None, spin_chars="-\\|/", - # Empirically, 8 updates/second looks nice - min_update_interval_seconds=0.125): + def __init__( + self, + message, + file=None, + spin_chars="-\\|/", + # Empirically, 8 updates/second looks nice + min_update_interval_seconds=0.125, + ): # type: (str, IO[str], str, float) -> None self._message = message if file is None: @@ -106,8 +111,7 @@ def finish(self, final_status): # type: (str) -> None if self._finished: return - self._update( - "finished with status '{final_status}'".format(**locals())) + self._update("finished with status '{final_status}'".format(**locals())) self._finished = True diff --git a/src/pip/_internal/commands/__init__.py b/src/pip/_internal/commands/__init__.py index 4f0c4ba3ab9..c6d9513d428 100644 --- a/src/pip/_internal/commands/__init__.py +++ b/src/pip/_internal/commands/__init__.py @@ -22,7 +22,7 @@ from pip._internal.cli.base_command import Command -CommandInfo = namedtuple('CommandInfo', 'module_path, class_name, summary') +CommandInfo = namedtuple("CommandInfo", "module_path, class_name, summary") # The ordering matters for help display. # Also, even though the module path starts with the same @@ -32,68 +32,130 @@ # in a test-related module). # Finally, we need to pass an iterable of pairs here rather than a dict # so that the ordering won't be lost when using Python 2.7. -commands_dict = OrderedDict([ - ('install', CommandInfo( - 'pip._internal.commands.install', 'InstallCommand', - 'Install packages.', - )), - ('download', CommandInfo( - 'pip._internal.commands.download', 'DownloadCommand', - 'Download packages.', - )), - ('uninstall', CommandInfo( - 'pip._internal.commands.uninstall', 'UninstallCommand', - 'Uninstall packages.', - )), - ('freeze', CommandInfo( - 'pip._internal.commands.freeze', 'FreezeCommand', - 'Output installed packages in requirements format.', - )), - ('list', CommandInfo( - 'pip._internal.commands.list', 'ListCommand', - 'List installed packages.', - )), - ('show', CommandInfo( - 'pip._internal.commands.show', 'ShowCommand', - 'Show information about installed packages.', - )), - ('check', CommandInfo( - 'pip._internal.commands.check', 'CheckCommand', - 'Verify installed packages have compatible dependencies.', - )), - ('config', CommandInfo( - 'pip._internal.commands.configuration', 'ConfigurationCommand', - 'Manage local and global configuration.', - )), - ('search', CommandInfo( - 'pip._internal.commands.search', 'SearchCommand', - 'Search PyPI for packages.', - )), - ('cache', CommandInfo( - 'pip._internal.commands.cache', 'CacheCommand', - "Inspect and manage pip's wheel cache.", - )), - ('wheel', CommandInfo( - 'pip._internal.commands.wheel', 'WheelCommand', - 'Build wheels from your requirements.', - )), - ('hash', CommandInfo( - 'pip._internal.commands.hash', 'HashCommand', - 'Compute hashes of package archives.', - )), - ('completion', CommandInfo( - 'pip._internal.commands.completion', 'CompletionCommand', - 'A helper command used for command completion.', - )), - ('debug', CommandInfo( - 'pip._internal.commands.debug', 'DebugCommand', - 'Show information useful for debugging.', - )), - ('help', CommandInfo( - 'pip._internal.commands.help', 'HelpCommand', - 'Show help for commands.', - )), -]) # type: OrderedDict[str, CommandInfo] +commands_dict = OrderedDict( + [ + ( + "install", + CommandInfo( + "pip._internal.commands.install", + "InstallCommand", + "Install packages.", + ), + ), + ( + "download", + CommandInfo( + "pip._internal.commands.download", + "DownloadCommand", + "Download packages.", + ), + ), + ( + "uninstall", + CommandInfo( + "pip._internal.commands.uninstall", + "UninstallCommand", + "Uninstall packages.", + ), + ), + ( + "freeze", + CommandInfo( + "pip._internal.commands.freeze", + "FreezeCommand", + "Output installed packages in requirements format.", + ), + ), + ( + "list", + CommandInfo( + "pip._internal.commands.list", + "ListCommand", + "List installed packages.", + ), + ), + ( + "show", + CommandInfo( + "pip._internal.commands.show", + "ShowCommand", + "Show information about installed packages.", + ), + ), + ( + "check", + CommandInfo( + "pip._internal.commands.check", + "CheckCommand", + "Verify installed packages have compatible dependencies.", + ), + ), + ( + "config", + CommandInfo( + "pip._internal.commands.configuration", + "ConfigurationCommand", + "Manage local and global configuration.", + ), + ), + ( + "search", + CommandInfo( + "pip._internal.commands.search", + "SearchCommand", + "Search PyPI for packages.", + ), + ), + ( + "cache", + CommandInfo( + "pip._internal.commands.cache", + "CacheCommand", + "Inspect and manage pip's wheel cache.", + ), + ), + ( + "wheel", + CommandInfo( + "pip._internal.commands.wheel", + "WheelCommand", + "Build wheels from your requirements.", + ), + ), + ( + "hash", + CommandInfo( + "pip._internal.commands.hash", + "HashCommand", + "Compute hashes of package archives.", + ), + ), + ( + "completion", + CommandInfo( + "pip._internal.commands.completion", + "CompletionCommand", + "A helper command used for command completion.", + ), + ), + ( + "debug", + CommandInfo( + "pip._internal.commands.debug", + "DebugCommand", + "Show information useful for debugging.", + ), + ), + ( + "help", + CommandInfo( + "pip._internal.commands.help", + "HelpCommand", + "Show help for commands.", + ), + ), + ] +) # type: OrderedDict[str, CommandInfo] def create_command(name, **kwargs): diff --git a/src/pip/_internal/commands/cache.py b/src/pip/_internal/commands/cache.py index b9d3ed410bc..cbdf9d687a4 100644 --- a/src/pip/_internal/commands/cache.py +++ b/src/pip/_internal/commands/cache.py @@ -46,12 +46,12 @@ def add_options(self): # type: () -> None self.cmd_opts.add_option( - '--format', - action='store', - dest='list_format', + "--format", + action="store", + dest="list_format", default="human", - choices=('human', 'abspath'), - help="Select the output format among: human (default) or abspath" + choices=("human", "abspath"), + help="Select the output format among: human (default) or abspath", ) self.parser.insert_option_group(0, self.cmd_opts) @@ -67,8 +67,9 @@ def run(self, options, args): } if not options.cache_dir: - logger.error("pip cache commands can not " - "function since cache is disabled.") + logger.error( + "pip cache commands can not " "function since cache is disabled." + ) return ERROR # Determine action @@ -93,44 +94,50 @@ def run(self, options, args): def get_cache_dir(self, options, args): # type: (Values, List[Any]) -> None if args: - raise CommandError('Too many arguments') + raise CommandError("Too many arguments") logger.info(options.cache_dir) def get_cache_info(self, options, args): # type: (Values, List[Any]) -> None if args: - raise CommandError('Too many arguments') + raise CommandError("Too many arguments") - num_packages = len(self._find_wheels(options, '*')) + num_packages = len(self._find_wheels(options, "*")) cache_location = self._wheels_cache_dir(options) cache_size = filesystem.format_directory_size(cache_location) - message = textwrap.dedent(""" + message = ( + textwrap.dedent( + """ Location: {location} Size: {size} Number of wheels: {package_count} - """).format( - location=cache_location, - package_count=num_packages, - size=cache_size, - ).strip() + """ + ) + .format( + location=cache_location, + package_count=num_packages, + size=cache_size, + ) + .strip() + ) logger.info(message) def list_cache_items(self, options, args): # type: (Values, List[Any]) -> None if len(args) > 1: - raise CommandError('Too many arguments') + raise CommandError("Too many arguments") if args: pattern = args[0] else: - pattern = '*' + pattern = "*" files = self._find_wheels(options, pattern) - if options.list_format == 'human': + if options.list_format == "human": self.format_for_human(files) else: self.format_for_abspath(files) @@ -138,16 +145,16 @@ def list_cache_items(self, options, args): def format_for_human(self, files): # type: (List[str]) -> None if not files: - logger.info('Nothing cached.') + logger.info("Nothing cached.") return results = [] for filename in files: wheel = os.path.basename(filename) size = filesystem.format_file_size(filename) - results.append(' - {} ({})'.format(wheel, size)) - logger.info('Cache contents:\n') - logger.info('\n'.join(sorted(results))) + results.append(" - {} ({})".format(wheel, size)) + logger.info("Cache contents:\n") + logger.info("\n".join(sorted(results))) def format_for_abspath(self, files): # type: (List[str]) -> None @@ -158,35 +165,35 @@ def format_for_abspath(self, files): for filename in files: results.append(filename) - logger.info('\n'.join(sorted(results))) + logger.info("\n".join(sorted(results))) def remove_cache_items(self, options, args): # type: (Values, List[Any]) -> None if len(args) > 1: - raise CommandError('Too many arguments') + raise CommandError("Too many arguments") if not args: - raise CommandError('Please provide a pattern') + raise CommandError("Please provide a pattern") files = self._find_wheels(options, args[0]) if not files: - raise CommandError('No matching packages') + raise CommandError("No matching packages") for filename in files: os.unlink(filename) - logger.debug('Removed %s', filename) - logger.info('Files removed: %s', len(files)) + logger.debug("Removed %s", filename) + logger.info("Files removed: %s", len(files)) def purge_cache(self, options, args): # type: (Values, List[Any]) -> None if args: - raise CommandError('Too many arguments') + raise CommandError("Too many arguments") - return self.remove_cache_items(options, ['*']) + return self.remove_cache_items(options, ["*"]) def _wheels_cache_dir(self, options): # type: (Values) -> str - return os.path.join(options.cache_dir, 'wheels') + return os.path.join(options.cache_dir, "wheels") def _find_wheels(self, options, pattern): # type: (Values, str) -> List[str] diff --git a/src/pip/_internal/commands/check.py b/src/pip/_internal/commands/check.py index e066bb63c74..decb4489066 100644 --- a/src/pip/_internal/commands/check.py +++ b/src/pip/_internal/commands/check.py @@ -33,7 +33,9 @@ def run(self, options, args): for dependency in missing[project_name]: write_output( "%s %s requires %s, which is not installed.", - project_name, version, dependency[0], + project_name, + version, + dependency[0], ) for project_name in conflicting: @@ -41,7 +43,11 @@ def run(self, options, args): for dep_name, dep_version, req in conflicting[project_name]: write_output( "%s %s has requirement %s, but you have %s %s.", - project_name, version, req, dep_name, dep_version, + project_name, + version, + req, + dep_name, + dep_version, ) if missing or conflicting or parsing_probs: diff --git a/src/pip/_internal/commands/completion.py b/src/pip/_internal/commands/completion.py index b19f1ed1a56..99155af7c92 100644 --- a/src/pip/_internal/commands/completion.py +++ b/src/pip/_internal/commands/completion.py @@ -17,7 +17,7 @@ """ COMPLETION_SCRIPTS = { - 'bash': """ + "bash": """ _pip_completion() {{ COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\ @@ -26,7 +26,7 @@ }} complete -o default -F _pip_completion {prog} """, - 'zsh': """ + "zsh": """ function _pip_completion {{ local words cword read -Ac words @@ -37,7 +37,7 @@ }} compctl -K _pip_completion {prog} """, - 'fish': """ + "fish": """ function __fish_complete_pip set -lx COMP_WORDS (commandline -o) "" set -lx COMP_CWORD ( \\ @@ -59,23 +59,29 @@ class CompletionCommand(Command): def add_options(self): # type: () -> None self.cmd_opts.add_option( - '--bash', '-b', - action='store_const', - const='bash', - dest='shell', - help='Emit completion code for bash') + "--bash", + "-b", + action="store_const", + const="bash", + dest="shell", + help="Emit completion code for bash", + ) self.cmd_opts.add_option( - '--zsh', '-z', - action='store_const', - const='zsh', - dest='shell', - help='Emit completion code for zsh') + "--zsh", + "-z", + action="store_const", + const="zsh", + dest="shell", + help="Emit completion code for zsh", + ) self.cmd_opts.add_option( - '--fish', '-f', - action='store_const', - const='fish', - dest='shell', - help='Emit completion code for fish') + "--fish", + "-f", + action="store_const", + const="fish", + dest="shell", + help="Emit completion code for fish", + ) self.parser.insert_option_group(0, self.cmd_opts) @@ -83,16 +89,15 @@ def run(self, options, args): # type: (Values, List[str]) -> int """Prints the completion code of the given shell""" shells = COMPLETION_SCRIPTS.keys() - shell_options = ['--' + shell for shell in sorted(shells)] + shell_options = ["--" + shell for shell in sorted(shells)] if options.shell in shells: script = textwrap.dedent( - COMPLETION_SCRIPTS.get(options.shell, '').format( - prog=get_prog()) + COMPLETION_SCRIPTS.get(options.shell, "").format(prog=get_prog()) ) print(BASE_COMPLETION.format(script=script, shell=options.shell)) return SUCCESS else: sys.stderr.write( - 'ERROR: You must pass {}\n' .format(' or '.join(shell_options)) + "ERROR: You must pass {}\n".format(" or ".join(shell_options)) ) return SUCCESS diff --git a/src/pip/_internal/commands/configuration.py b/src/pip/_internal/commands/configuration.py index 2a6311acd74..ddb10bb44a0 100644 --- a/src/pip/_internal/commands/configuration.py +++ b/src/pip/_internal/commands/configuration.py @@ -4,11 +4,7 @@ from pip._internal.cli.base_command import Command from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.configuration import ( - Configuration, - get_configuration_files, - kinds, -) +from pip._internal.configuration import Configuration, get_configuration_files, kinds from pip._internal.exceptions import PipError from pip._internal.utils.logging import indent_log from pip._internal.utils.misc import get_prog, write_output @@ -56,38 +52,38 @@ class ConfigurationCommand(Command): def add_options(self): # type: () -> None self.cmd_opts.add_option( - '--editor', - dest='editor', - action='store', + "--editor", + dest="editor", + action="store", default=None, help=( - 'Editor to use to edit the file. Uses VISUAL or EDITOR ' - 'environment variables if not provided.' - ) + "Editor to use to edit the file. Uses VISUAL or EDITOR " + "environment variables if not provided." + ), ) self.cmd_opts.add_option( - '--global', - dest='global_file', - action='store_true', + "--global", + dest="global_file", + action="store_true", default=False, - help='Use the system-wide configuration file only' + help="Use the system-wide configuration file only", ) self.cmd_opts.add_option( - '--user', - dest='user_file', - action='store_true', + "--user", + dest="user_file", + action="store_true", default=False, - help='Use the user configuration file only' + help="Use the user configuration file only", ) self.cmd_opts.add_option( - '--site', - dest='site_file', - action='store_true', + "--site", + dest="site_file", + action="store_true", default=False, - help='Use the current environment configuration file only' + help="Use the current environment configuration file only", ) self.parser.insert_option_group(0, self.cmd_opts) @@ -140,11 +136,15 @@ def run(self, options, args): def _determine_file(self, options, need_value): # type: (Values, bool) -> Optional[Kind] - file_options = [key for key, value in ( - (kinds.USER, options.user_file), - (kinds.GLOBAL, options.global_file), - (kinds.SITE, options.site_file), - ) if value] + file_options = [ + key + for key, value in ( + (kinds.USER, options.user_file), + (kinds.GLOBAL, options.global_file), + (kinds.SITE, options.site_file), + ) + if value + ] if not file_options: if not need_value: @@ -206,26 +206,24 @@ def list_config_values(self, options, args): for fname in files: with indent_log(): file_exists = os.path.exists(fname) - write_output("%s, exists: %r", - fname, file_exists) + write_output("%s, exists: %r", fname, file_exists) if file_exists: self.print_config_file_values(variant) def print_config_file_values(self, variant): # type: (Kind) -> None """Get key-value pairs from the file of a variant""" - for name, value in self.configuration.\ - get_values_in_config(variant).items(): + for name, value in self.configuration.get_values_in_config(variant).items(): with indent_log(): write_output("%s: %s", name, value) def print_env_var_values(self): # type: () -> None """Get key-values pairs present as environment variables""" - write_output("%s:", 'env_var') + write_output("%s:", "env_var") with indent_log(): for key, value in sorted(self.configuration.get_environ_vars()): - env_var = 'PIP_{}'.format(key.upper()) + env_var = "PIP_{}".format(key.upper()) write_output("%s=%r", env_var, value) def open_in_editor(self, options, args): @@ -240,17 +238,15 @@ def open_in_editor(self, options, args): subprocess.check_call([editor, fname]) except subprocess.CalledProcessError as e: raise PipError( - "Editor Subprocess exited with exit code {}" - .format(e.returncode) + "Editor Subprocess exited with exit code {}".format(e.returncode) ) def _get_n_args(self, args, example, n): # type: (List[str], str, int) -> Any - """Helper to make sure the command got the right number of arguments - """ + """Helper to make sure the command got the right number of arguments""" if len(args) != n: msg = ( - 'Got unexpected number of arguments, expected {}. ' + "Got unexpected number of arguments, expected {}. " '(example: "{} config {}")' ).format(n, get_prog(), example) raise PipError(msg) diff --git a/src/pip/_internal/commands/debug.py b/src/pip/_internal/commands/debug.py index 1b65c43065b..0835766b620 100644 --- a/src/pip/_internal/commands/debug.py +++ b/src/pip/_internal/commands/debug.py @@ -30,38 +30,37 @@ def show_value(name, value): # type: (str, Optional[str]) -> None - logger.info('%s: %s', name, value) + logger.info("%s: %s", name, value) def show_sys_implementation(): # type: () -> None - logger.info('sys.implementation:') - if hasattr(sys, 'implementation'): + logger.info("sys.implementation:") + if hasattr(sys, "implementation"): implementation = sys.implementation # type: ignore implementation_name = implementation.name else: - implementation_name = '' + implementation_name = "" with indent_log(): - show_value('name', implementation_name) + show_value("name", implementation_name) def create_vendor_txt_map(): # type: () -> Dict[str, str] vendor_txt_path = os.path.join( - os.path.dirname(pip_location), - '_vendor', - 'vendor.txt' + os.path.dirname(pip_location), "_vendor", "vendor.txt" ) with open(vendor_txt_path) as f: # Purge non version specifying lines. # Also, remove any space prefix or suffixes (including comments). - lines = [line.strip().split(' ', 1)[0] - for line in f.readlines() if '==' in line] + lines = [ + line.strip().split(" ", 1)[0] for line in f.readlines() if "==" in line + ] # Transform into "module" -> version dict. - return dict(line.split('==', 1) for line in lines) # type: ignore + return dict(line.split("==", 1) for line in lines) # type: ignore def get_module_from_module_name(module_name): @@ -69,22 +68,17 @@ def get_module_from_module_name(module_name): # Module name can be uppercase in vendor.txt for some reason... module_name = module_name.lower() # PATCH: setuptools is actually only pkg_resources. - if module_name == 'setuptools': - module_name = 'pkg_resources' - - __import__( - 'pip._vendor.{}'.format(module_name), - globals(), - locals(), - level=0 - ) + if module_name == "setuptools": + module_name = "pkg_resources" + + __import__("pip._vendor.{}".format(module_name), globals(), locals(), level=0) return getattr(pip._vendor, module_name) def get_vendor_version_from_module(module_name): # type: (str) -> Optional[str] module = get_module_from_module_name(module_name) - version = getattr(module, '__version__', None) + version = getattr(module, "__version__", None) if not version: # Try to find version in debundled module info @@ -96,7 +90,7 @@ def get_vendor_version_from_module(module_name): [os.path.dirname(module.__file__)] # type: ignore ) package = pkg_set.find(pkg_resources.Requirement.parse(module_name)) - version = getattr(package, 'version', None) + version = getattr(package, "version", None) return version @@ -107,21 +101,25 @@ def show_actual_vendor_versions(vendor_txt_versions): a conflict or if the actual version could not be imported. """ for module_name, expected_version in vendor_txt_versions.items(): - extra_message = '' + extra_message = "" actual_version = get_vendor_version_from_module(module_name) if not actual_version: - extra_message = ' (Unable to locate actual module version, using'\ - ' vendor.txt specified version)' + extra_message = ( + " (Unable to locate actual module version, using" + " vendor.txt specified version)" + ) actual_version = expected_version elif actual_version != expected_version: - extra_message = ' (CONFLICT: vendor.txt suggests version should'\ - ' be {})'.format(expected_version) - logger.info('%s==%s%s', module_name, actual_version, extra_message) + extra_message = ( + " (CONFLICT: vendor.txt suggests version should" + " be {})".format(expected_version) + ) + logger.info("%s==%s%s", module_name, actual_version, extra_message) def show_vendor_versions(): # type: () -> None - logger.info('vendored library versions:') + logger.info("vendored library versions:") vendor_txt_versions = create_vendor_txt_map() with indent_log(): @@ -137,11 +135,11 @@ def show_tags(options): # Display the target options that were explicitly provided. formatted_target = target_python.format_given() - suffix = '' + suffix = "" if formatted_target: - suffix = ' (target: {})'.format(formatted_target) + suffix = " (target: {})".format(formatted_target) - msg = 'Compatible tags: {}{}'.format(len(tags), suffix) + msg = "Compatible tags: {}{}".format(len(tags), suffix) logger.info(msg) if options.verbose < 1 and len(tags) > tag_limit: @@ -156,8 +154,7 @@ def show_tags(options): if tags_limited: msg = ( - '...\n' - '[First {tag_limit} tags shown. Pass --verbose to show all.]' + "...\n" "[First {tag_limit} tags shown. Pass --verbose to show all.]" ).format(tag_limit=tag_limit) logger.info(msg) @@ -166,20 +163,20 @@ def ca_bundle_info(config): # type: (Configuration) -> str levels = set() for key, _ in config.items(): - levels.add(key.split('.')[0]) + levels.add(key.split(".")[0]) if not levels: return "Not specified" - levels_that_override_global = ['install', 'wheel', 'download'] + levels_that_override_global = ["install", "wheel", "download"] global_overriding_level = [ level for level in levels if level in levels_that_override_global ] if not global_overriding_level: - return 'global' + return "global" - if 'global' in levels: - levels.remove('global') + if "global" in levels: + levels.remove("global") return ", ".join(levels) @@ -206,20 +203,21 @@ def run(self, options, args): "details, since the output and options of this command may " "change without notice." ) - show_value('pip version', get_pip_version()) - show_value('sys.version', sys.version) - show_value('sys.executable', sys.executable) - show_value('sys.getdefaultencoding', sys.getdefaultencoding()) - show_value('sys.getfilesystemencoding', sys.getfilesystemencoding()) + show_value("pip version", get_pip_version()) + show_value("sys.version", sys.version) + show_value("sys.executable", sys.executable) + show_value("sys.getdefaultencoding", sys.getdefaultencoding()) + show_value("sys.getfilesystemencoding", sys.getfilesystemencoding()) show_value( - 'locale.getpreferredencoding', locale.getpreferredencoding(), + "locale.getpreferredencoding", + locale.getpreferredencoding(), ) - show_value('sys.platform', sys.platform) + show_value("sys.platform", sys.platform) show_sys_implementation() show_value("'cert' config value", ca_bundle_info(self.parser.config)) - show_value("REQUESTS_CA_BUNDLE", os.environ.get('REQUESTS_CA_BUNDLE')) - show_value("CURL_CA_BUNDLE", os.environ.get('CURL_CA_BUNDLE')) + show_value("REQUESTS_CA_BUNDLE", os.environ.get("REQUESTS_CA_BUNDLE")) + show_value("CURL_CA_BUNDLE", os.environ.get("CURL_CA_BUNDLE")) show_value("pip._vendor.certifi.where()", where()) show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED) diff --git a/src/pip/_internal/commands/download.py b/src/pip/_internal/commands/download.py index 0861d9e67b2..0971ed3df77 100644 --- a/src/pip/_internal/commands/download.py +++ b/src/pip/_internal/commands/download.py @@ -58,9 +58,12 @@ def add_options(self): self.cmd_opts.add_option(cmdoptions.no_use_pep517()) self.cmd_opts.add_option( - '-d', '--dest', '--destination-dir', '--destination-directory', - dest='download_dir', - metavar='dir', + "-d", + "--dest", + "--destination-dir", + "--destination-directory", + dest="download_dir", + metavar="dir", default=os.curdir, help=("Download packages into ."), ) @@ -98,7 +101,7 @@ def run(self, options, args): session=session, target_python=target_python, ) - build_delete = (not (options.no_clean or options.build_dir)) + build_delete = not (options.no_clean or options.build_dir) req_tracker = self.enter_context(get_requirement_tracker()) @@ -130,9 +133,7 @@ def run(self, options, args): self.trace_basic_info(finder) - requirement_set = resolver.resolve( - reqs, check_supported_wheels=True - ) + requirement_set = resolver.resolve(reqs, check_supported_wheels=True) downloaded = [] # type: List[str] for req in requirement_set.requirements.values(): @@ -140,6 +141,6 @@ def run(self, options, args): assert req.name is not None downloaded.append(req.name) if downloaded: - write_output('Successfully downloaded %s', ' '.join(downloaded)) + write_output("Successfully downloaded %s", " ".join(downloaded)) return SUCCESS diff --git a/src/pip/_internal/commands/freeze.py b/src/pip/_internal/commands/freeze.py index 2071fbabd61..cc4dc27cfc0 100644 --- a/src/pip/_internal/commands/freeze.py +++ b/src/pip/_internal/commands/freeze.py @@ -11,7 +11,7 @@ from pip._internal.utils.compat import stdlib_pkgs from pip._internal.utils.typing import MYPY_CHECK_RUNNING -DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'} +DEV_PKGS = {"pip", "setuptools", "distribute", "wheel"} if MYPY_CHECK_RUNNING: from optparse import Values @@ -32,47 +32,55 @@ class FreezeCommand(Command): def add_options(self): # type: () -> None self.cmd_opts.add_option( - '-r', '--requirement', - dest='requirements', - action='append', + "-r", + "--requirement", + dest="requirements", + action="append", default=[], - metavar='file', + metavar="file", help="Use the order in the given requirements file and its " - "comments when generating output. This option can be " - "used multiple times.") + "comments when generating output. This option can be " + "used multiple times.", + ) self.cmd_opts.add_option( - '-f', '--find-links', - dest='find_links', - action='append', + "-f", + "--find-links", + dest="find_links", + action="append", default=[], - metavar='URL', - help='URL for finding packages, which will be added to the ' - 'output.') + metavar="URL", + help="URL for finding packages, which will be added to the " "output.", + ) self.cmd_opts.add_option( - '-l', '--local', - dest='local', - action='store_true', + "-l", + "--local", + dest="local", + action="store_true", default=False, - help='If in a virtualenv that has global access, do not output ' - 'globally-installed packages.') + help="If in a virtualenv that has global access, do not output " + "globally-installed packages.", + ) self.cmd_opts.add_option( - '--user', - dest='user', - action='store_true', + "--user", + dest="user", + action="store_true", default=False, - help='Only output packages installed in user-site.') + help="Only output packages installed in user-site.", + ) self.cmd_opts.add_option(cmdoptions.list_path()) self.cmd_opts.add_option( - '--all', - dest='freeze_all', - action='store_true', - help='Do not skip these packages in the output:' - ' {}'.format(', '.join(DEV_PKGS))) + "--all", + dest="freeze_all", + action="store_true", + help="Do not skip these packages in the output:" + " {}".format(", ".join(DEV_PKGS)), + ) self.cmd_opts.add_option( - '--exclude-editable', - dest='exclude_editable', - action='store_true', - help='Exclude editable package from output.') + "--exclude-editable", + dest="exclude_editable", + action="store_true", + help="Exclude editable package from output.", + ) self.parser.insert_option_group(0, self.cmd_opts) @@ -99,5 +107,5 @@ def run(self, options, args): ) for line in freeze(**freeze_kwargs): - sys.stdout.write(line + '\n') + sys.stdout.write(line + "\n") return SUCCESS diff --git a/src/pip/_internal/commands/hash.py b/src/pip/_internal/commands/hash.py index 37831c39522..d8f345ee991 100644 --- a/src/pip/_internal/commands/hash.py +++ b/src/pip/_internal/commands/hash.py @@ -25,19 +25,22 @@ class HashCommand(Command): installs. """ - usage = '%prog [options] ...' + usage = "%prog [options] ..." ignore_require_venv = True def add_options(self): # type: () -> None self.cmd_opts.add_option( - '-a', '--algorithm', - dest='algorithm', + "-a", + "--algorithm", + dest="algorithm", choices=STRONG_HASHES, - action='store', + action="store", default=FAVORITE_HASH, - help='The hash algorithm to use: one of {}'.format( - ', '.join(STRONG_HASHES))) + help="The hash algorithm to use: one of {}".format( + ", ".join(STRONG_HASHES) + ), + ) self.parser.insert_option_group(0, self.cmd_opts) def run(self, options, args): @@ -48,15 +51,16 @@ def run(self, options, args): algorithm = options.algorithm for path in args: - write_output('%s:\n--hash=%s:%s', - path, algorithm, _hash_of_file(path, algorithm)) + write_output( + "%s:\n--hash=%s:%s", path, algorithm, _hash_of_file(path, algorithm) + ) return SUCCESS def _hash_of_file(path, algorithm): # type: (str, str) -> str """Return the hash digest of a file.""" - with open(path, 'rb') as archive: + with open(path, "rb") as archive: hash = hashlib.new(algorithm) for chunk in read_chunks(archive): hash.update(chunk) diff --git a/src/pip/_internal/commands/help.py b/src/pip/_internal/commands/help.py index 2ab2b6d8f25..de4f6229328 100644 --- a/src/pip/_internal/commands/help.py +++ b/src/pip/_internal/commands/help.py @@ -38,7 +38,7 @@ def run(self, options, args): if guess: msg.append('maybe you meant "{}"'.format(guess)) - raise CommandError(' - '.join(msg)) + raise CommandError(" - ".join(msg)) command = create_command(cmd_name) command.parser.print_help() diff --git a/src/pip/_internal/commands/install.py b/src/pip/_internal/commands/install.py index e41660070a0..9ebbcf03541 100644 --- a/src/pip/_internal/commands/install.py +++ b/src/pip/_internal/commands/install.py @@ -90,87 +90,90 @@ def add_options(self): self.cmd_opts.add_option(cmdoptions.editable()) self.cmd_opts.add_option( - '-t', '--target', - dest='target_dir', - metavar='dir', + "-t", + "--target", + dest="target_dir", + metavar="dir", default=None, - help='Install packages into . ' - 'By default this will not replace existing files/folders in ' - '. Use --upgrade to replace existing packages in ' - 'with new versions.' + help="Install packages into . " + "By default this will not replace existing files/folders in " + ". Use --upgrade to replace existing packages in " + "with new versions.", ) cmdoptions.add_target_python_options(self.cmd_opts) self.cmd_opts.add_option( - '--user', - dest='use_user_site', - action='store_true', + "--user", + dest="use_user_site", + action="store_true", help="Install to the Python user install directory for your " - "platform. Typically ~/.local/, or %APPDATA%\\Python on " - "Windows. (See the Python documentation for site.USER_BASE " - "for full details.)") + "platform. Typically ~/.local/, or %APPDATA%\\Python on " + "Windows. (See the Python documentation for site.USER_BASE " + "for full details.)", + ) self.cmd_opts.add_option( - '--no-user', - dest='use_user_site', - action='store_false', - help=SUPPRESS_HELP) + "--no-user", dest="use_user_site", action="store_false", help=SUPPRESS_HELP + ) self.cmd_opts.add_option( - '--root', - dest='root_path', - metavar='dir', + "--root", + dest="root_path", + metavar="dir", default=None, - help="Install everything relative to this alternate root " - "directory.") + help="Install everything relative to this alternate root " "directory.", + ) self.cmd_opts.add_option( - '--prefix', - dest='prefix_path', - metavar='dir', + "--prefix", + dest="prefix_path", + metavar="dir", default=None, help="Installation prefix where lib, bin and other top-level " - "folders are placed") + "folders are placed", + ) self.cmd_opts.add_option(cmdoptions.build_dir()) self.cmd_opts.add_option(cmdoptions.src()) self.cmd_opts.add_option( - '-U', '--upgrade', - dest='upgrade', - action='store_true', - help='Upgrade all specified packages to the newest available ' - 'version. The handling of dependencies depends on the ' - 'upgrade-strategy used.' + "-U", + "--upgrade", + dest="upgrade", + action="store_true", + help="Upgrade all specified packages to the newest available " + "version. The handling of dependencies depends on the " + "upgrade-strategy used.", ) self.cmd_opts.add_option( - '--upgrade-strategy', - dest='upgrade_strategy', - default='only-if-needed', - choices=['only-if-needed', 'eager'], - help='Determines how dependency upgrading should be handled ' - '[default: %default]. ' - '"eager" - dependencies are upgraded regardless of ' - 'whether the currently installed version satisfies the ' - 'requirements of the upgraded package(s). ' - '"only-if-needed" - are upgraded only when they do not ' - 'satisfy the requirements of the upgraded package(s).' + "--upgrade-strategy", + dest="upgrade_strategy", + default="only-if-needed", + choices=["only-if-needed", "eager"], + help="Determines how dependency upgrading should be handled " + "[default: %default]. " + '"eager" - dependencies are upgraded regardless of ' + "whether the currently installed version satisfies the " + "requirements of the upgraded package(s). " + '"only-if-needed" - are upgraded only when they do not ' + "satisfy the requirements of the upgraded package(s).", ) self.cmd_opts.add_option( - '--force-reinstall', - dest='force_reinstall', - action='store_true', - help='Reinstall all packages even if they are already ' - 'up-to-date.') + "--force-reinstall", + dest="force_reinstall", + action="store_true", + help="Reinstall all packages even if they are already " "up-to-date.", + ) self.cmd_opts.add_option( - '-I', '--ignore-installed', - dest='ignore_installed', - action='store_true', - help='Ignore the installed packages, overwriting them. ' - 'This can break your system if the existing package ' - 'is of a different version or was installed ' - 'with a different package manager!' + "-I", + "--ignore-installed", + dest="ignore_installed", + action="store_true", + help="Ignore the installed packages, overwriting them. " + "This can break your system if the existing package " + "is of a different version or was installed " + "with a different package manager!", ) self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) @@ -254,11 +257,11 @@ def run(self, options, args): if options.target_dir: options.ignore_installed = True options.target_dir = os.path.abspath(options.target_dir) - if (os.path.exists(options.target_dir) and not - os.path.isdir(options.target_dir)): + if os.path.exists(options.target_dir) and not os.path.isdir( + options.target_dir + ): raise CommandError( - "Target path exists but is not a directory, will not " - "continue." + "Target path exists but is not a directory, will not " "continue." ) # Create a target directory for using with the target option @@ -277,7 +280,7 @@ def run(self, options, args): target_python=target_python, ignore_requires_python=options.ignore_requires_python, ) - build_delete = (not (options.no_clean or options.build_dir)) + build_delete = not (options.no_clean or options.build_dir) wheel_cache = WheelCache(options.cache_dir, options.format_control) req_tracker = self.enter_context(get_requirement_tracker()) @@ -292,9 +295,7 @@ def run(self, options, args): try: reqs = self.get_requirements(args, options, finder, session) - reject_location_related_install_options( - reqs, options.install_options - ) + reject_location_related_install_options(reqs, options.install_options) preparer = self.make_requirement_preparer( temp_build_dir=directory, @@ -331,19 +332,14 @@ def run(self, options, args): # If we're not replacing an already installed pip, # we're not modifying it. modifying_pip = pip_req.satisfied_by is None - protect_pip_from_modification_on_windows( - modifying_pip=modifying_pip - ) + protect_pip_from_modification_on_windows(modifying_pip=modifying_pip) - check_binary_allowed = get_check_binary_allowed( - finder.format_control - ) + check_binary_allowed = get_check_binary_allowed(finder.format_control) reqs_to_build = [ - r for r in requirement_set.requirements.values() - if should_build_for_install_command( - r, check_binary_allowed - ) + r + for r in requirement_set.requirements.values() + if should_build_for_install_command(r, check_binary_allowed) ] _, build_failures = build( @@ -356,8 +352,7 @@ def run(self, options, args): # If we're using PEP 517, we cannot do a direct install # so we fail here. pep517_build_failure_names = [ - r.name # type: ignore - for r in build_failures if r.use_pep517 + r.name for r in build_failures if r.use_pep517 # type: ignore ] # type: List[str] if pep517_build_failure_names: raise InstallationError( @@ -374,15 +369,12 @@ def run(self, options, args): if not r.use_pep517: r.legacy_install_reason = 8368 - to_install = resolver.get_installation_order( - requirement_set - ) + to_install = resolver.get_installation_order(requirement_set) # Check for conflicts in the package set we're installing. conflicts = None # type: Optional[ConflictDetails] should_warn_about_conflicts = ( - not options.ignore_dependencies and - options.warn_about_conflicts + not options.ignore_dependencies and options.warn_about_conflicts ) if should_warn_about_conflicts: conflicts = self._determine_conflicts(to_install) @@ -414,7 +406,7 @@ def run(self, options, args): ) working_set = pkg_resources.WorkingSet(lib_locations) - installed.sort(key=operator.attrgetter('name')) + installed.sort(key=operator.attrgetter("name")) items = [] for result in installed: item = result.name @@ -423,7 +415,7 @@ def run(self, options, args): result.name, working_set=working_set ) if installed_version: - item += '-' + installed_version + item += "-" + installed_version except Exception: pass items.append(item) @@ -431,19 +423,22 @@ def run(self, options, args): if conflicts is not None: self._warn_about_conflicts( conflicts, - new_resolver='2020-resolver' in options.features_enabled, + new_resolver="2020-resolver" in options.features_enabled, ) - installed_desc = ' '.join(items) + installed_desc = " ".join(items) if installed_desc: write_output( - 'Successfully installed %s', installed_desc, + "Successfully installed %s", + installed_desc, ) except EnvironmentError as error: - show_traceback = (self.verbosity >= 1) + show_traceback = self.verbosity >= 1 message = create_env_error_message( - error, show_traceback, options.use_user_site, + error, + show_traceback, + options.use_user_site, ) logger.error(message, exc_info=show_traceback) # noqa @@ -467,10 +462,10 @@ def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): # Checking both purelib and platlib directories for installed # packages to be moved to target directory - scheme = distutils_scheme('', home=target_temp_dir.path) - purelib_dir = scheme['purelib'] - platlib_dir = scheme['platlib'] - data_dir = scheme['data'] + scheme = distutils_scheme("", home=target_temp_dir.path) + purelib_dir = scheme["purelib"] + platlib_dir = scheme["platlib"] + data_dir = scheme["data"] if os.path.exists(purelib_dir): lib_dir_list.append(purelib_dir) @@ -489,18 +484,18 @@ def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): if os.path.exists(target_item_dir): if not upgrade: logger.warning( - 'Target directory %s already exists. Specify ' - '--upgrade to force replacement.', - target_item_dir + "Target directory %s already exists. Specify " + "--upgrade to force replacement.", + target_item_dir, ) continue if os.path.islink(target_item_dir): logger.warning( - 'Target directory %s already exists and is ' - 'a link. pip will not automatically replace ' - 'links, please remove if replacement is ' - 'desired.', - target_item_dir + "Target directory %s already exists and is " + "a link. pip will not automatically replace " + "links, please remove if replacement is " + "desired.", + target_item_dir, ) continue if os.path.isdir(target_item_dir): @@ -508,10 +503,7 @@ def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): else: os.remove(target_item_dir) - shutil.move( - os.path.join(lib_dir, item), - target_item_dir - ) + shutil.move(os.path.join(lib_dir, item), target_item_dir) def _determine_conflicts(self, to_install): # type: (List[InstallRequirement]) -> Optional[ConflictDetails] @@ -576,23 +568,24 @@ def _warn_about_conflicts(self, conflict_details, new_resolver): def get_lib_location_guesses( - user=False, # type: bool - home=None, # type: Optional[str] - root=None, # type: Optional[str] - isolated=False, # type: bool - prefix=None # type: Optional[str] + user=False, # type: bool + home=None, # type: Optional[str] + root=None, # type: Optional[str] + isolated=False, # type: bool + prefix=None, # type: Optional[str] ): # type:(...) -> List[str] - scheme = distutils_scheme('', user=user, home=home, root=root, - isolated=isolated, prefix=prefix) - return [scheme['purelib'], scheme['platlib']] + scheme = distutils_scheme( + "", user=user, home=home, root=root, isolated=isolated, prefix=prefix + ) + return [scheme["purelib"], scheme["platlib"]] def site_packages_writable(root, isolated): # type: (Optional[str], bool) -> bool return all( - test_writable_dir(d) for d in set( - get_lib_location_guesses(root=root, isolated=isolated)) + test_writable_dir(d) + for d in set(get_lib_location_guesses(root=root, isolated=isolated)) ) @@ -651,8 +644,10 @@ def decide_user_install( logger.debug("Non-user install because site-packages writeable") return False - logger.info("Defaulting to user installation because normal site-packages " - "is not writeable") + logger.info( + "Defaulting to user installation because normal site-packages " + "is not writeable" + ) return True @@ -661,6 +656,7 @@ def reject_location_related_install_options(requirements, options): """If any location-changing --install-option arguments were passed for requirements or on the command-line, then show a deprecation warning. """ + def format_options(option_names): # type: (Iterable[str]) -> List[str] return ["--{}".format(name.replace("_", "-")) for name in option_names] @@ -681,9 +677,7 @@ def format_options(option_names): location_options = parse_distutils_args(options) if location_options: offenders.append( - "{!r} from command line".format( - format_options(location_options.keys()) - ) + "{!r} from command line".format(format_options(location_options.keys())) ) if not offenders: @@ -692,9 +686,7 @@ def format_options(option_names): raise CommandError( "Location-changing options found in --install-option: {}." " This is unsupported, use pip-level options like --user," - " --prefix, --root, and --target instead.".format( - "; ".join(offenders) - ) + " --prefix, --root, and --target instead.".format("; ".join(offenders)) ) @@ -724,10 +716,13 @@ def create_env_error_message(error, show_traceback, using_user_site): permissions_part = "Check the permissions" if not using_user_site: - parts.extend([ - user_option_part, " or ", - permissions_part.lower(), - ]) + parts.extend( + [ + user_option_part, + " or ", + permissions_part.lower(), + ] + ) else: parts.append(permissions_part) parts.append(".\n") diff --git a/src/pip/_internal/commands/list.py b/src/pip/_internal/commands/list.py index a6dfa5fd578..1d9d13f52bf 100644 --- a/src/pip/_internal/commands/list.py +++ b/src/pip/_internal/commands/list.py @@ -47,76 +47,85 @@ class ListCommand(IndexGroupCommand): def add_options(self): # type: () -> None self.cmd_opts.add_option( - '-o', '--outdated', - action='store_true', + "-o", + "--outdated", + action="store_true", default=False, - help='List outdated packages') + help="List outdated packages", + ) self.cmd_opts.add_option( - '-u', '--uptodate', - action='store_true', + "-u", + "--uptodate", + action="store_true", default=False, - help='List uptodate packages') + help="List uptodate packages", + ) self.cmd_opts.add_option( - '-e', '--editable', - action='store_true', + "-e", + "--editable", + action="store_true", default=False, - help='List editable projects.') + help="List editable projects.", + ) self.cmd_opts.add_option( - '-l', '--local', - action='store_true', + "-l", + "--local", + action="store_true", default=False, - help=('If in a virtualenv that has global access, do not list ' - 'globally-installed packages.'), + help=( + "If in a virtualenv that has global access, do not list " + "globally-installed packages." + ), ) self.cmd_opts.add_option( - '--user', - dest='user', - action='store_true', + "--user", + dest="user", + action="store_true", default=False, - help='Only output packages installed in user-site.') + help="Only output packages installed in user-site.", + ) self.cmd_opts.add_option(cmdoptions.list_path()) self.cmd_opts.add_option( - '--pre', - action='store_true', + "--pre", + action="store_true", default=False, - help=("Include pre-release and development versions. By default, " - "pip only finds stable versions."), + help=( + "Include pre-release and development versions. By default, " + "pip only finds stable versions." + ), ) self.cmd_opts.add_option( - '--format', - action='store', - dest='list_format', + "--format", + action="store", + dest="list_format", default="columns", - choices=('columns', 'freeze', 'json'), + choices=("columns", "freeze", "json"), help="Select the output format among: columns (default), freeze, " - "or json", + "or json", ) self.cmd_opts.add_option( - '--not-required', - action='store_true', - dest='not_required', - help="List packages that are not dependencies of " - "installed packages.", + "--not-required", + action="store_true", + dest="not_required", + help="List packages that are not dependencies of " "installed packages.", ) self.cmd_opts.add_option( - '--exclude-editable', - action='store_false', - dest='include_editable', - help='Exclude editable package from output.', + "--exclude-editable", + action="store_false", + dest="include_editable", + help="Exclude editable package from output.", ) self.cmd_opts.add_option( - '--include-editable', - action='store_true', - dest='include_editable', - help='Include editable package from output.', + "--include-editable", + action="store_true", + dest="include_editable", + help="Include editable package from output.", default=True, ) - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, self.parser - ) + index_opts = cmdoptions.make_option_group(cmdoptions.index_group, self.parser) self.parser.insert_option_group(0, index_opts) self.parser.insert_option_group(0, self.cmd_opts) @@ -142,8 +151,7 @@ def _build_package_finder(self, options, session): def run(self, options, args): # type: (Values, List[str]) -> int if options.outdated and options.uptodate: - raise CommandError( - "Options --outdated and --uptodate cannot be combined.") + raise CommandError("Options --outdated and --uptodate cannot be combined.") cmdoptions.check_list_path_option(options) @@ -173,14 +181,16 @@ def run(self, options, args): def get_outdated(self, packages, options): # type: (List[Distribution], Values) -> List[Distribution] return [ - dist for dist in self.iter_packages_latest_infos(packages, options) + dist + for dist in self.iter_packages_latest_infos(packages, options) if dist.latest_version > dist.parsed_version ] def get_uptodate(self, packages, options): # type: (List[Distribution], Values) -> List[Distribution] return [ - dist for dist in self.iter_packages_latest_infos(packages, options) + dist + for dist in self.iter_packages_latest_infos(packages, options) if dist.latest_version == dist.parsed_version ] @@ -205,8 +215,11 @@ def latest_info(dist): all_candidates = finder.find_all_candidates(dist.key) if not options.pre: # Remove prereleases - all_candidates = [candidate for candidate in all_candidates - if not candidate.version.is_prerelease] + all_candidates = [ + candidate + for candidate in all_candidates + if not candidate.version.is_prerelease + ] evaluator = finder.make_candidate_evaluator( project_name=dist.project_name, @@ -217,9 +230,9 @@ def latest_info(dist): remote_version = best_candidate.version if best_candidate.link.is_wheel: - typ = 'wheel' + typ = "wheel" else: - typ = 'sdist' + typ = "sdist" # This is dirty but makes the rest of the code much cleaner dist.latest_version = remote_version dist.latest_filetype = typ @@ -235,17 +248,18 @@ def output_package_listing(self, packages, options): packages, key=lambda dist: dist.project_name.lower(), ) - if options.list_format == 'columns' and packages: + if options.list_format == "columns" and packages: data, header = format_for_columns(packages, options) self.output_package_listing_columns(data, header) - elif options.list_format == 'freeze': + elif options.list_format == "freeze": for dist in packages: if options.verbose >= 1: - write_output("%s==%s (%s)", dist.project_name, - dist.version, dist.location) + write_output( + "%s==%s (%s)", dist.project_name, dist.version, dist.location + ) else: write_output("%s==%s", dist.project_name, dist.version) - elif options.list_format == 'json': + elif options.list_format == "json": write_output(format_for_json(packages, options)) def output_package_listing_columns(self, data, header): @@ -258,7 +272,7 @@ def output_package_listing_columns(self, data, header): # Create and add a separator. if len(data) > 0: - pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) + pkg_strings.insert(1, " ".join(map(lambda x: "-" * x, sizes))) for val in pkg_strings: write_output(val) @@ -307,14 +321,14 @@ def format_for_json(packages, options): data = [] for dist in packages: info = { - 'name': dist.project_name, - 'version': six.text_type(dist.version), + "name": dist.project_name, + "version": six.text_type(dist.version), } if options.verbose >= 1: - info['location'] = dist.location - info['installer'] = get_installer(dist) + info["location"] = dist.location + info["installer"] = get_installer(dist) if options.outdated: - info['latest_version'] = six.text_type(dist.latest_version) - info['latest_filetype'] = dist.latest_filetype + info["latest_version"] = six.text_type(dist.latest_version) + info["latest_filetype"] = dist.latest_filetype data.append(info) return json.dumps(data) diff --git a/src/pip/_internal/commands/search.py b/src/pip/_internal/commands/search.py index ea4f47db5b5..2557efc8a73 100644 --- a/src/pip/_internal/commands/search.py +++ b/src/pip/_internal/commands/search.py @@ -7,6 +7,7 @@ from pip._vendor import pkg_resources from pip._vendor.packaging.version import parse as parse_version + # NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is # why we ignore the type on this import from pip._vendor.six.moves import xmlrpc_client # type: ignore @@ -27,9 +28,10 @@ from typing import Dict, List, Optional from typing_extensions import TypedDict + TransformedHit = TypedDict( - 'TransformedHit', - {'name': str, 'summary': str, 'versions': List[str]}, + "TransformedHit", + {"name": str, "summary": str, "versions": List[str]}, ) logger = logging.getLogger(__name__) @@ -45,18 +47,20 @@ class SearchCommand(Command, SessionCommandMixin): def add_options(self): # type: () -> None self.cmd_opts.add_option( - '-i', '--index', - dest='index', - metavar='URL', + "-i", + "--index", + dest="index", + metavar="URL", default=PyPI.pypi_url, - help='Base URL of Python Package Index (default %default)') + help="Base URL of Python Package Index (default %default)", + ) self.parser.insert_option_group(0, self.cmd_opts) def run(self, options, args): # type: (Values, List[str]) -> int if not args: - raise CommandError('Missing required argument (search query).') + raise CommandError("Missing required argument (search query).") query = args pypi_hits = self.search(query, options) hits = transform_hits(pypi_hits) @@ -78,7 +82,7 @@ def search(self, query, options): transport = PipXmlrpcTransport(index_url, session) pypi = xmlrpc_client.ServerProxy(index_url, transport) - hits = pypi.search({'name': query, 'summary': query}, 'or') + hits = pypi.search({"name": query, "summary": query}, "or") return hits @@ -91,22 +95,22 @@ def transform_hits(hits): """ packages = OrderedDict() # type: OrderedDict[str, TransformedHit] for hit in hits: - name = hit['name'] - summary = hit['summary'] - version = hit['version'] + name = hit["name"] + summary = hit["summary"] + version = hit["version"] if name not in packages.keys(): packages[name] = { - 'name': name, - 'summary': summary, - 'versions': [version], + "name": name, + "summary": summary, + "versions": [version], } else: - packages[name]['versions'].append(version) + packages[name]["versions"].append(version) # if this is the highest version, replace summary and score - if version == highest_version(packages[name]['versions']): - packages[name]['summary'] = summary + if version == highest_version(packages[name]["versions"]): + packages[name]["summary"] = summary return list(packages.values()) @@ -116,27 +120,31 @@ def print_results(hits, name_column_width=None, terminal_width=None): if not hits: return if name_column_width is None: - name_column_width = max([ - len(hit['name']) + len(highest_version(hit.get('versions', ['-']))) - for hit in hits - ]) + 4 + name_column_width = ( + max( + [ + len(hit["name"]) + len(highest_version(hit.get("versions", ["-"]))) + for hit in hits + ] + ) + + 4 + ) installed_packages = [p.project_name for p in pkg_resources.working_set] for hit in hits: - name = hit['name'] - summary = hit['summary'] or '' - latest = highest_version(hit.get('versions', ['-'])) + name = hit["name"] + summary = hit["summary"] or "" + latest = highest_version(hit.get("versions", ["-"])) if terminal_width is not None: target_width = terminal_width - name_column_width - 5 if target_width > 10: # wrap and indent summary to fit terminal summary_lines = textwrap.wrap(summary, target_width) - summary = ('\n' + ' ' * (name_column_width + 3)).join( - summary_lines) + summary = ("\n" + " " * (name_column_width + 3)).join(summary_lines) - line = '{name_latest:{name_column_width}} - {summary}'.format( - name_latest='{name} ({latest})'.format(**locals()), - **locals()) + line = "{name_latest:{name_column_width}} - {summary}".format( + name_latest="{name} ({latest})".format(**locals()), **locals() + ) try: write_output(line) if name in installed_packages: @@ -144,14 +152,17 @@ def print_results(hits, name_column_width=None, terminal_width=None): assert dist is not None with indent_log(): if dist.version == latest: - write_output('INSTALLED: %s (latest)', dist.version) + write_output("INSTALLED: %s (latest)", dist.version) else: - write_output('INSTALLED: %s', dist.version) + write_output("INSTALLED: %s", dist.version) if parse_version(latest).pre: - write_output('LATEST: %s (pre-release; install' - ' with "pip install --pre")', latest) + write_output( + "LATEST: %s (pre-release; install" + ' with "pip install --pre")', + latest, + ) else: - write_output('LATEST: %s', latest) + write_output("LATEST: %s", latest) except UnicodeEncodeError: pass diff --git a/src/pip/_internal/commands/show.py b/src/pip/_internal/commands/show.py index b0b3f3abdcc..e40c0f4c53a 100644 --- a/src/pip/_internal/commands/show.py +++ b/src/pip/_internal/commands/show.py @@ -33,24 +33,27 @@ class ShowCommand(Command): def add_options(self): # type: () -> None self.cmd_opts.add_option( - '-f', '--files', - dest='files', - action='store_true', + "-f", + "--files", + dest="files", + action="store_true", default=False, - help='Show the full list of installed files for each package.') + help="Show the full list of installed files for each package.", + ) self.parser.insert_option_group(0, self.cmd_opts) def run(self, options, args): # type: (Values, List[str]) -> int if not args: - logger.warning('ERROR: Please provide a package name or names.') + logger.warning("ERROR: Please provide a package name or names.") return ERROR query = args results = search_packages_info(query) if not print_results( - results, list_files=options.files, verbose=options.verbose): + results, list_files=options.files, verbose=options.verbose + ): return ERROR return SUCCESS @@ -72,56 +75,56 @@ def search_packages_info(query): [name for name, pkg in zip(query, query_names) if pkg not in installed] ) if missing: - logger.warning('Package(s) not found: %s', ', '.join(missing)) + logger.warning("Package(s) not found: %s", ", ".join(missing)) def get_requiring_packages(package_name): # type: (str) -> List[str] canonical_name = canonicalize_name(package_name) return [ - pkg.project_name for pkg in pkg_resources.working_set - if canonical_name in - [canonicalize_name(required.name) for required in - pkg.requires()] + pkg.project_name + for pkg in pkg_resources.working_set + if canonical_name + in [canonicalize_name(required.name) for required in pkg.requires()] ] for dist in [installed[pkg] for pkg in query_names if pkg in installed]: package = { - 'name': dist.project_name, - 'version': dist.version, - 'location': dist.location, - 'requires': [dep.project_name for dep in dist.requires()], - 'required_by': get_requiring_packages(dist.project_name) + "name": dist.project_name, + "version": dist.version, + "location": dist.location, + "requires": [dep.project_name for dep in dist.requires()], + "required_by": get_requiring_packages(dist.project_name), } file_list = None - metadata = '' + metadata = "" if isinstance(dist, pkg_resources.DistInfoDistribution): # RECORDs should be part of .dist-info metadatas - if dist.has_metadata('RECORD'): - lines = dist.get_metadata_lines('RECORD') - paths = [line.split(',')[0] for line in lines] + if dist.has_metadata("RECORD"): + lines = dist.get_metadata_lines("RECORD") + paths = [line.split(",")[0] for line in lines] paths = [os.path.join(dist.location, p) for p in paths] file_list = [os.path.relpath(p, dist.location) for p in paths] - if dist.has_metadata('METADATA'): - metadata = dist.get_metadata('METADATA') + if dist.has_metadata("METADATA"): + metadata = dist.get_metadata("METADATA") else: # Otherwise use pip's log for .egg-info's - if dist.has_metadata('installed-files.txt'): - paths = dist.get_metadata_lines('installed-files.txt') + if dist.has_metadata("installed-files.txt"): + paths = dist.get_metadata_lines("installed-files.txt") paths = [os.path.join(dist.egg_info, p) for p in paths] file_list = [os.path.relpath(p, dist.location) for p in paths] - if dist.has_metadata('PKG-INFO'): - metadata = dist.get_metadata('PKG-INFO') + if dist.has_metadata("PKG-INFO"): + metadata = dist.get_metadata("PKG-INFO") - if dist.has_metadata('entry_points.txt'): - entry_points = dist.get_metadata_lines('entry_points.txt') - package['entry_points'] = entry_points + if dist.has_metadata("entry_points.txt"): + entry_points = dist.get_metadata_lines("entry_points.txt") + package["entry_points"] = entry_points - if dist.has_metadata('INSTALLER'): - for line in dist.get_metadata_lines('INSTALLER'): + if dist.has_metadata("INSTALLER"): + for line in dist.get_metadata_lines("INSTALLER"): if line.strip(): - package['installer'] = line.strip() + package["installer"] = line.strip() break # @todo: Should pkg_resources.Distribution have a @@ -129,19 +132,25 @@ def get_requiring_packages(package_name): feed_parser = FeedParser() feed_parser.feed(metadata) pkg_info_dict = feed_parser.close() - for key in ('metadata-version', 'summary', - 'home-page', 'author', 'author-email', 'license'): + for key in ( + "metadata-version", + "summary", + "home-page", + "author", + "author-email", + "license", + ): package[key] = pkg_info_dict.get(key) # It looks like FeedParser cannot deal with repeated headers classifiers = [] for line in metadata.splitlines(): - if line.startswith('Classifier: '): - classifiers.append(line[len('Classifier: '):]) - package['classifiers'] = classifiers + if line.startswith("Classifier: "): + classifiers.append(line[len("Classifier: ") :]) + package["classifiers"] = classifiers if file_list: - package['files'] = sorted(file_list) + package["files"] = sorted(file_list) yield package @@ -156,30 +165,29 @@ def print_results(distributions, list_files=False, verbose=False): if i > 0: write_output("---") - write_output("Name: %s", dist.get('name', '')) - write_output("Version: %s", dist.get('version', '')) - write_output("Summary: %s", dist.get('summary', '')) - write_output("Home-page: %s", dist.get('home-page', '')) - write_output("Author: %s", dist.get('author', '')) - write_output("Author-email: %s", dist.get('author-email', '')) - write_output("License: %s", dist.get('license', '')) - write_output("Location: %s", dist.get('location', '')) - write_output("Requires: %s", ', '.join(dist.get('requires', []))) - write_output("Required-by: %s", ', '.join(dist.get('required_by', []))) + write_output("Name: %s", dist.get("name", "")) + write_output("Version: %s", dist.get("version", "")) + write_output("Summary: %s", dist.get("summary", "")) + write_output("Home-page: %s", dist.get("home-page", "")) + write_output("Author: %s", dist.get("author", "")) + write_output("Author-email: %s", dist.get("author-email", "")) + write_output("License: %s", dist.get("license", "")) + write_output("Location: %s", dist.get("location", "")) + write_output("Requires: %s", ", ".join(dist.get("requires", []))) + write_output("Required-by: %s", ", ".join(dist.get("required_by", []))) if verbose: - write_output("Metadata-Version: %s", - dist.get('metadata-version', '')) - write_output("Installer: %s", dist.get('installer', '')) + write_output("Metadata-Version: %s", dist.get("metadata-version", "")) + write_output("Installer: %s", dist.get("installer", "")) write_output("Classifiers:") - for classifier in dist.get('classifiers', []): + for classifier in dist.get("classifiers", []): write_output(" %s", classifier) write_output("Entry-points:") - for entry in dist.get('entry_points', []): + for entry in dist.get("entry_points", []): write_output(" %s", entry.strip()) if list_files: write_output("Files:") - for line in dist.get('files', []): + for line in dist.get("files", []): write_output(" %s", line.strip()) if "files" not in dist: write_output("Cannot locate installed-files.txt") diff --git a/src/pip/_internal/commands/uninstall.py b/src/pip/_internal/commands/uninstall.py index 3371fe47ff1..97f045f629b 100644 --- a/src/pip/_internal/commands/uninstall.py +++ b/src/pip/_internal/commands/uninstall.py @@ -37,19 +37,22 @@ class UninstallCommand(Command, SessionCommandMixin): def add_options(self): # type: () -> None self.cmd_opts.add_option( - '-r', '--requirement', - dest='requirements', - action='append', + "-r", + "--requirement", + dest="requirements", + action="append", default=[], - metavar='file', - help='Uninstall all the packages listed in the given requirements ' - 'file. This option can be used multiple times.', + metavar="file", + help="Uninstall all the packages listed in the given requirements " + "file. This option can be used multiple times.", ) self.cmd_opts.add_option( - '-y', '--yes', - dest='yes', - action='store_true', - help="Don't ask for confirmation of uninstall deletions.") + "-y", + "--yes", + dest="yes", + action="store_true", + help="Don't ask for confirmation of uninstall deletions.", + ) self.parser.insert_option_group(0, self.cmd_opts) @@ -60,24 +63,23 @@ def run(self, options, args): reqs_to_uninstall = {} for name in args: req = install_req_from_line( - name, isolated=options.isolated_mode, + name, + isolated=options.isolated_mode, ) if req.name: reqs_to_uninstall[canonicalize_name(req.name)] = req for filename in options.requirements: for parsed_req in parse_requirements( - filename, - options=options, - session=session): + filename, options=options, session=session + ): req = install_req_from_parsed_requirement( - parsed_req, - isolated=options.isolated_mode + parsed_req, isolated=options.isolated_mode ) if req.name: reqs_to_uninstall[canonicalize_name(req.name)] = req if not reqs_to_uninstall: raise InstallationError( - 'You must give at least one requirement to {self.name} (see ' + "You must give at least one requirement to {self.name} (see " '"pip help {self.name}")'.format(**locals()) ) @@ -87,7 +89,8 @@ def run(self, options, args): for req in reqs_to_uninstall.values(): uninstall_pathset = req.uninstall( - auto_confirm=options.yes, verbose=self.verbosity > 0, + auto_confirm=options.yes, + verbose=self.verbosity > 0, ) if uninstall_pathset: uninstall_pathset.commit() diff --git a/src/pip/_internal/commands/wheel.py b/src/pip/_internal/commands/wheel.py index 0f718566bd0..7a0e484d514 100644 --- a/src/pip/_internal/commands/wheel.py +++ b/src/pip/_internal/commands/wheel.py @@ -51,21 +51,24 @@ def add_options(self): # type: () -> None self.cmd_opts.add_option( - '-w', '--wheel-dir', - dest='wheel_dir', - metavar='dir', + "-w", + "--wheel-dir", + dest="wheel_dir", + metavar="dir", default=os.curdir, - help=("Build wheels into , where the default is the " - "current working directory."), + help=( + "Build wheels into , where the default is the " + "current working directory." + ), ) self.cmd_opts.add_option(cmdoptions.no_binary()) self.cmd_opts.add_option(cmdoptions.only_binary()) self.cmd_opts.add_option(cmdoptions.prefer_binary()) self.cmd_opts.add_option( - '--build-option', - dest='build_options', - metavar='options', - action='append', + "--build-option", + dest="build_options", + metavar="options", + action="append", help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", ) self.cmd_opts.add_option(cmdoptions.no_build_isolation()) @@ -81,19 +84,22 @@ def add_options(self): self.cmd_opts.add_option(cmdoptions.progress_bar()) self.cmd_opts.add_option( - '--global-option', - dest='global_options', - action='append', - metavar='options', + "--global-option", + dest="global_options", + action="append", + metavar="options", help="Extra global options to be supplied to the setup.py " - "call before the 'bdist_wheel' command.") + "call before the 'bdist_wheel' command.", + ) self.cmd_opts.add_option( - '--pre', - action='store_true', + "--pre", + action="store_true", default=False, - help=("Include pre-release and development versions. By default, " - "pip only finds stable versions."), + help=( + "Include pre-release and development versions. By default, " + "pip only finds stable versions." + ), ) self.cmd_opts.add_option(cmdoptions.require_hashes()) @@ -114,7 +120,7 @@ def run(self, options, args): session = self.get_default_session(options) finder = self._build_package_finder(options, session) - build_delete = (not (options.no_clean or options.build_dir)) + build_delete = not (options.no_clean or options.build_dir) wheel_cache = WheelCache(options.cache_dir, options.format_control) options.wheel_dir = normalize_path(options.wheel_dir) @@ -152,12 +158,11 @@ def run(self, options, args): self.trace_basic_info(finder) - requirement_set = resolver.resolve( - reqs, check_supported_wheels=True - ) + requirement_set = resolver.resolve(reqs, check_supported_wheels=True) reqs_to_build = [ - r for r in requirement_set.requirements.values() + r + for r in requirement_set.requirements.values() if should_build_for_wheel_command(r) ] @@ -177,12 +182,11 @@ def run(self, options, args): except OSError as e: logger.warning( "Building wheel for %s failed: %s", - req.name, e, + req.name, + e, ) build_failures.append(req) if len(build_failures) != 0: - raise CommandError( - "Failed to build one or more wheels" - ) + raise CommandError("Failed to build one or more wheels") return SUCCESS diff --git a/src/pip/_internal/configuration.py b/src/pip/_internal/configuration.py index 23614fd2bbe..6c2a57d86c6 100644 --- a/src/pip/_internal/configuration.py +++ b/src/pip/_internal/configuration.py @@ -33,15 +33,15 @@ RawConfigParser = configparser.RawConfigParser # Shorthand Kind = NewType("Kind", str) -CONFIG_BASENAME = 'pip.ini' if WINDOWS else 'pip.conf' +CONFIG_BASENAME = "pip.ini" if WINDOWS else "pip.conf" ENV_NAMES_IGNORED = "version", "help" # The kinds of configurations there are. kinds = enum( - USER="user", # User Specific - GLOBAL="global", # System Wide - SITE="site", # [Virtual] Environment Specific - ENV="env", # from PIP_CONFIG_FILE + USER="user", # User Specific + GLOBAL="global", # System Wide + SITE="site", # [Virtual] Environment Specific + ENV="env", # from PIP_CONFIG_FILE ENV_VAR="env-var", # from Environment Variables ) OVERRIDE_ORDER = kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR @@ -53,10 +53,9 @@ # NOTE: Maybe use the optionx attribute to normalize keynames. def _normalize_name(name): # type: (str) -> str - """Make a name consistent regardless of source (environment or file) - """ - name = name.lower().replace('_', '-') - if name.startswith('--'): + """Make a name consistent regardless of source (environment or file)""" + name = name.lower().replace("_", "-") + if name.startswith("--"): name = name[2:] # only prefer long opts return name @@ -75,19 +74,16 @@ def _disassemble_key(name): def get_configuration_files(): # type: () -> Dict[Kind, List[str]] global_config_files = [ - os.path.join(path, CONFIG_BASENAME) - for path in appdirs.site_config_dirs('pip') + os.path.join(path, CONFIG_BASENAME) for path in appdirs.site_config_dirs("pip") ] site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME) legacy_config_file = os.path.join( - expanduser('~'), - 'pip' if WINDOWS else '.pip', + expanduser("~"), + "pip" if WINDOWS else ".pip", CONFIG_BASENAME, ) - new_config_file = os.path.join( - appdirs.user_config_dir("pip"), CONFIG_BASENAME - ) + new_config_file = os.path.join(appdirs.user_config_dir("pip"), CONFIG_BASENAME) return { kinds.GLOBAL: global_config_files, kinds.SITE: [site_config_file], @@ -133,18 +129,15 @@ def __init__(self, isolated, load_only=None): def load(self): # type: () -> None - """Loads configuration from configuration files and environment - """ + """Loads configuration from configuration files and environment""" self._load_config_files() if not self.isolated: self._load_environment_vars() def get_file_to_edit(self): # type: () -> Optional[str] - """Returns the file with highest priority in configuration - """ - assert self.load_only is not None, \ - "Need to be specified a file to be editing" + """Returns the file with highest priority in configuration""" + assert self.load_only is not None, "Need to be specified a file to be editing" try: return self._get_parser_to_modify()[0] @@ -160,8 +153,7 @@ def items(self): def get_value(self, key): # type: (str) -> Any - """Get a value from the configuration. - """ + """Get a value from the configuration.""" try: return self._dictionary[key] except KeyError: @@ -169,8 +161,7 @@ def get_value(self, key): def set_value(self, key, value): # type: (str, Any) -> None - """Modify a value in the configuration. - """ + """Modify a value in the configuration.""" self._ensure_have_load_only() assert self.load_only @@ -200,8 +191,9 @@ def unset_value(self, key): if parser is not None: section, name = _disassemble_key(key) - if not (parser.has_section(section) - and parser.remove_option(section, name)): + if not ( + parser.has_section(section) and parser.remove_option(section, name) + ): # The option was not removed. raise ConfigurationError( "Fatal Internal error [id=1]. Please report as a bug." @@ -216,8 +208,7 @@ def unset_value(self, key): def save(self): # type: () -> None - """Save the current in-memory state. - """ + """Save the current in-memory state.""" self._ensure_have_load_only() for fname, parser in self._modified_parsers: @@ -242,8 +233,7 @@ def _ensure_have_load_only(self): @property def _dictionary(self): # type: () -> Dict[str, Any] - """A dictionary representing the loaded configuration. - """ + """A dictionary representing the loaded configuration.""" # NOTE: Dictionaries are not populated if not loaded. So, conditionals # are not needed here. retval = {} @@ -255,8 +245,7 @@ def _dictionary(self): def _load_config_files(self): # type: () -> None - """Loads configuration from configuration files - """ + """Loads configuration from configuration files""" config_files = dict(self.iter_config_files()) if config_files[kinds.ENV][0:1] == [os.devnull]: logger.debug( @@ -270,9 +259,7 @@ def _load_config_files(self): # If there's specific variant set in `load_only`, load only # that variant, not the others. if self.load_only is not None and variant != self.load_only: - logger.debug( - "Skipping file '%s' (variant: %s)", fname, variant - ) + logger.debug("Skipping file '%s' (variant: %s)", fname, variant) continue parser = self._load_file(variant, fname) @@ -316,8 +303,7 @@ def _construct_parser(self, fname): def _load_environment_vars(self): # type: () -> None - """Loads configuration from environment variables - """ + """Loads configuration from environment variables""" self._config[kinds.ENV_VAR].update( self._normalized_keys(":env:", self.get_environ_vars()) ) @@ -354,7 +340,7 @@ def iter_config_files(self): # SMELL: Move the conditions out of this function # environment variables have the lowest priority - config_file = os.environ.get('PIP_CONFIG_FILE', None) + config_file = os.environ.get("PIP_CONFIG_FILE", None) if config_file is not None: yield kinds.ENV, [config_file] else: diff --git a/src/pip/_internal/distributions/__init__.py b/src/pip/_internal/distributions/__init__.py index d5c1afc5bc1..a2fece38bfe 100644 --- a/src/pip/_internal/distributions/__init__.py +++ b/src/pip/_internal/distributions/__init__.py @@ -9,8 +9,7 @@ def make_distribution_for_install_requirement(install_req): # type: (InstallRequirement) -> AbstractDistribution - """Returns a Distribution for the given InstallRequirement - """ + """Returns a Distribution for the given InstallRequirement""" # Editable requirements will always be source distributions. They use the # legacy logic until we create a modern standard for them. if install_req.editable: diff --git a/src/pip/_internal/distributions/sdist.py b/src/pip/_internal/distributions/sdist.py index 06b9df09cbe..426816269d3 100644 --- a/src/pip/_internal/distributions/sdist.py +++ b/src/pip/_internal/distributions/sdist.py @@ -51,10 +51,10 @@ def _raise_conflicts(conflicting_with, conflicting_reqs): error_message = format_string.format( requirement=self.req, conflicting_with=conflicting_with, - description=', '.join( - '{} is incompatible with {}'.format(installed, wanted) + description=", ".join( + "{} is incompatible with {}".format(installed, wanted) for installed, wanted in sorted(conflicting) - ) + ), ) raise InstallationError(error_message) @@ -65,15 +65,13 @@ def _raise_conflicts(conflicting_with, conflicting_reqs): self.req.build_env = BuildEnvironment() self.req.build_env.install_requirements( - finder, pyproject_requires, 'overlay', - "Installing build dependencies" + finder, pyproject_requires, "overlay", "Installing build dependencies" ) conflicting, missing = self.req.build_env.check_requirements( self.req.requirements_to_check ) if conflicting: - _raise_conflicts("PEP 517/518 supported requirements", - conflicting) + _raise_conflicts("PEP 517/518 supported requirements", conflicting) if missing: logger.warning( "Missing build requirements in pyproject.toml for %s.", @@ -82,15 +80,13 @@ def _raise_conflicts(conflicting_with, conflicting_reqs): logger.warning( "The project does not specify a build backend, and " "pip cannot fall back to setuptools without %s.", - " and ".join(map(repr, sorted(missing))) + " and ".join(map(repr, sorted(missing))), ) # Install any extra build dependencies that the backend requests. # This must be done in a second pass, as the pyproject.toml # dependencies must be installed before we can call the backend. with self.req.build_env: - runner = runner_with_spinner_message( - "Getting requirements to build wheel" - ) + runner = runner_with_spinner_message("Getting requirements to build wheel") backend = self.req.pep517_backend assert backend is not None with backend.subprocess_runner(runner): @@ -100,6 +96,5 @@ def _raise_conflicts(conflicting_with, conflicting_reqs): if conflicting: _raise_conflicts("the backend dependencies", conflicting) self.req.build_env.install_requirements( - finder, missing, 'normal', - "Installing backend dependencies" + finder, missing, "normal", "Installing backend dependencies" ) diff --git a/src/pip/_internal/exceptions.py b/src/pip/_internal/exceptions.py index 62bde1eeda4..067bc4b8cb9 100644 --- a/src/pip/_internal/exceptions.py +++ b/src/pip/_internal/exceptions.py @@ -63,10 +63,9 @@ def __str__(self): # type: () -> str # Use `dist` in the error message because its stringification # includes more information, like the version and location. - return ( - 'None {} metadata found for distribution: {}'.format( - self.metadata_name, self.dist, - ) + return "None {} metadata found for distribution: {}".format( + self.metadata_name, + self.dist, ) @@ -112,11 +111,13 @@ def __init__(self, error_msg, response=None, request=None): self.response = response self.request = request self.error_msg = error_msg - if (self.response is not None and not self.request and - hasattr(response, 'request')): + if ( + self.response is not None + and not self.request + and hasattr(response, "request") + ): self.request = self.response.request - super(NetworkConnectionError, self).__init__( - error_msg, response, request) + super(NetworkConnectionError, self).__init__(error_msg, response, request) def __str__(self): # type: () -> str @@ -138,6 +139,7 @@ class MetadataInconsistent(InstallationError): that do not match the information previously obtained from sdist filename or user-supplied ``#egg=`` value. """ + def __init__(self, ireq, field, built): # type: (InstallRequirement, str, Any) -> None self.ireq = ireq @@ -147,7 +149,9 @@ def __init__(self, ireq, field, built): def __str__(self): # type: () -> str return "Requested {} has different {} in metadata: {!r}".format( - self.ireq, self.field, self.built, + self.ireq, + self.field, + self.built, ) @@ -170,8 +174,8 @@ def __str__(self): lines.append(cls.head) lines.extend(e.body() for e in errors_of_cls) if lines: - return '\n'.join(lines) - return '' + return "\n".join(lines) + return "" def __nonzero__(self): # type: () -> bool @@ -198,8 +202,9 @@ class HashError(InstallationError): typically available earlier. """ + req = None # type: Optional[InstallRequirement] - head = '' + head = "" order = None # type: Optional[int] def body(self): @@ -213,11 +218,11 @@ def body(self): its link already populated by the resolver's _populate_link(). """ - return ' {}'.format(self._requirement_name()) + return " {}".format(self._requirement_name()) def __str__(self): # type: () -> str - return '{}\n{}'.format(self.head, self.body()) + return "{}\n{}".format(self.head, self.body()) def _requirement_name(self): # type: () -> str @@ -227,7 +232,7 @@ def _requirement_name(self): line numbers """ - return str(self.req) if self.req else 'unknown package' + return str(self.req) if self.req else "unknown package" class VcsHashUnsupported(HashError): @@ -235,8 +240,10 @@ class VcsHashUnsupported(HashError): we don't have a method for hashing those.""" order = 0 - head = ("Can't verify hashes for these requirements because we don't " - "have a way to hash version control repositories:") + head = ( + "Can't verify hashes for these requirements because we don't " + "have a way to hash version control repositories:" + ) class DirectoryUrlHashUnsupported(HashError): @@ -244,21 +251,25 @@ class DirectoryUrlHashUnsupported(HashError): we don't have a method for hashing those.""" order = 1 - head = ("Can't verify hashes for these file:// requirements because they " - "point to directories:") + head = ( + "Can't verify hashes for these file:// requirements because they " + "point to directories:" + ) class HashMissing(HashError): """A hash was needed for a requirement but is absent.""" order = 2 - head = ('Hashes are required in --require-hashes mode, but they are ' - 'missing from some requirements. Here is a list of those ' - 'requirements along with the hashes their downloaded archives ' - 'actually had. Add lines like these to your requirements files to ' - 'prevent tampering. (If you did not enable --require-hashes ' - 'manually, note that it turns on automatically when any package ' - 'has a hash.)') + head = ( + "Hashes are required in --require-hashes mode, but they are " + "missing from some requirements. Here is a list of those " + "requirements along with the hashes their downloaded archives " + "actually had. Add lines like these to your requirements files to " + "prevent tampering. (If you did not enable --require-hashes " + "manually, note that it turns on automatically when any package " + "has a hash.)" + ) def __init__(self, gotten_hash): # type: (str) -> None @@ -278,13 +289,16 @@ def body(self): # In the case of URL-based requirements, display the original URL # seen in the requirements file rather than the package name, # so the output can be directly copied into the requirements file. - package = (self.req.original_link if self.req.original_link - # In case someone feeds something downright stupid - # to InstallRequirement's constructor. - else getattr(self.req, 'req', None)) - return ' {} --hash={}:{}'.format(package or 'unknown package', - FAVORITE_HASH, - self.gotten_hash) + package = ( + self.req.original_link + if self.req.original_link + # In case someone feeds something downright stupid + # to InstallRequirement's constructor. + else getattr(self.req, "req", None) + ) + return " {} --hash={}:{}".format( + package or "unknown package", FAVORITE_HASH, self.gotten_hash + ) class HashUnpinned(HashError): @@ -292,8 +306,10 @@ class HashUnpinned(HashError): version.""" order = 3 - head = ('In --require-hashes mode, all requirements must have their ' - 'versions pinned with ==. These do not:') + head = ( + "In --require-hashes mode, all requirements must have their " + "versions pinned with ==. These do not:" + ) class HashMismatch(HashError): @@ -305,11 +321,14 @@ class HashMismatch(HashError): improve its error message. """ + order = 4 - head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' - 'FILE. If you have updated the package versions, please update ' - 'the hashes. Otherwise, examine the package contents carefully; ' - 'someone may have tampered with them.') + head = ( + "THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS " + "FILE. If you have updated the package versions, please update " + "the hashes. Otherwise, examine the package contents carefully; " + "someone may have tampered with them." + ) def __init__(self, allowed, gots): # type: (Dict[str, List[str]], Dict[str, _Hash]) -> None @@ -324,8 +343,7 @@ def __init__(self, allowed, gots): def body(self): # type: () -> str - return ' {}:\n{}'.format(self._requirement_name(), - self._hash_comparison()) + return " {}:\n{}".format(self._requirement_name(), self._hash_comparison()) def _hash_comparison(self): # type: () -> str @@ -339,20 +357,23 @@ def _hash_comparison(self): Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef """ + def hash_then_or(hash_name): # type: (str) -> chain[str] # For now, all the decent hashes have 6-char names, so we can get # away with hard-coding space literals. - return chain([hash_name], repeat(' or')) + return chain([hash_name], repeat(" or")) lines = [] # type: List[str] for hash_name, expecteds in iteritems(self.allowed): prefix = hash_then_or(hash_name) - lines.extend((' Expected {} {}'.format(next(prefix), e)) - for e in expecteds) - lines.append(' Got {}\n'.format( - self.gots[hash_name].hexdigest())) - return '\n'.join(lines) + lines.extend( + (" Expected {} {}".format(next(prefix), e)) for e in expecteds + ) + lines.append( + " Got {}\n".format(self.gots[hash_name].hexdigest()) + ) + return "\n".join(lines) class UnsupportedPythonVersion(InstallationError): @@ -361,8 +382,7 @@ class UnsupportedPythonVersion(InstallationError): class ConfigurationFileCouldNotBeLoaded(ConfigurationError): - """When there are errors while loading a configuration file - """ + """When there are errors while loading a configuration file""" def __init__(self, reason="could not be loaded", fname=None, error=None): # type: (str, Optional[str], Optional[configparser.Error]) -> None diff --git a/src/pip/_internal/index/collector.py b/src/pip/_internal/index/collector.py index e6230c76734..cb84985cd30 100644 --- a/src/pip/_internal/index/collector.py +++ b/src/pip/_internal/index/collector.py @@ -51,7 +51,7 @@ ResponseHeaders = MutableMapping[str, str] # Used in the @lru_cache polyfill. - F = TypeVar('F') + F = TypeVar("F") class LruCache(Protocol): def __call__(self, maxsize=None): @@ -69,6 +69,7 @@ def noop_lru_cache(maxsize=None): def _wrapper(f): # type: (F) -> F return f + return _wrapper @@ -82,15 +83,14 @@ def _match_vcs_scheme(url): Returns the matched VCS scheme, or None if there's no match. """ for scheme in vcs.schemes: - if url.lower().startswith(scheme) and url[len(scheme)] in '+:': + if url.lower().startswith(scheme) and url[len(scheme)] in "+:": return scheme return None def _is_url_like_archive(url): # type: (str) -> bool - """Return whether the URL looks like an archive. - """ + """Return whether the URL looks like an archive.""" filename = Link(url).filename for bad_ext in ARCHIVE_EXTENSIONS: if filename.endswith(bad_ext): @@ -129,7 +129,7 @@ def _ensure_html_response(url, session): `_NotHTML` if the content type is not text/html. """ scheme, netloc, path, query, fragment = urllib_parse.urlsplit(url) - if scheme not in {'http', 'https'}: + if scheme not in {"http", "https"}: raise _NotHTTP() resp = session.head(url, allow_redirects=True) @@ -155,7 +155,7 @@ def _get_html_response(url, session): if _is_url_like_archive(url): _ensure_html_response(url, session=session) - logger.debug('Getting page %s', redact_auth_from_url(url)) + logger.debug("Getting page %s", redact_auth_from_url(url)) resp = session.get( url, @@ -191,12 +191,11 @@ def _get_html_response(url, session): def _get_encoding_from_headers(headers): # type: (ResponseHeaders) -> Optional[str] - """Determine if we have any encoding information in our headers. - """ + """Determine if we have any encoding information in our headers.""" if headers and "Content-Type" in headers: content_type, params = cgi.parse_header(headers["Content-Type"]) if "charset" in params: - return params['charset'] + return params["charset"] return None @@ -244,7 +243,7 @@ def _clean_file_url_path(part): # percent-encoded: / -_reserved_chars_re = re.compile('(@|%2F)', re.IGNORECASE) +_reserved_chars_re = re.compile("(@|%2F)", re.IGNORECASE) def _clean_url_path(path, is_local_path): @@ -262,12 +261,12 @@ def _clean_url_path(path, is_local_path): parts = _reserved_chars_re.split(path) cleaned_parts = [] - for to_clean, reserved in pairwise(itertools.chain(parts, [''])): + for to_clean, reserved in pairwise(itertools.chain(parts, [""])): cleaned_parts.append(clean_func(to_clean)) # Normalize %xx escapes (e.g. %2f -> %2F) cleaned_parts.append(reserved.upper()) - return ''.join(cleaned_parts) + return "".join(cleaned_parts) def _clean_link(url): @@ -287,7 +286,7 @@ def _clean_link(url): def _create_link_from_element( - anchor, # type: HTMLElement + anchor, # type: HTMLElement page_url, # type: str base_url, # type: str ): @@ -300,10 +299,10 @@ def _create_link_from_element( return None url = _clean_link(urllib_parse.urljoin(base_url, href)) - pyrequire = anchor.get('data-requires-python') + pyrequire = anchor.get("data-requires-python") pyrequire = unescape(pyrequire) if pyrequire else None - yanked_reason = anchor.get('data-yanked') + yanked_reason = anchor.get("data-yanked") if yanked_reason: # This is a unicode string in Python 2 (and 3). yanked_reason = unescape(yanked_reason) @@ -326,8 +325,7 @@ def __init__(self, page): def __eq__(self, other): # type: (object) -> bool - return (isinstance(other, type(self)) and - self.page.url == other.page.url) + return isinstance(other, type(self)) and self.page.url == other.page.url def __hash__(self): # type: () -> int @@ -335,7 +333,7 @@ def __hash__(self): def with_cached_html_pages( - fn, # type: Callable[[HTMLPage], Iterable[Link]] + fn, # type: Callable[[HTMLPage], Iterable[Link]] ): # type: (...) -> Callable[[HTMLPage], List[Link]] """ @@ -389,9 +387,9 @@ class HTMLPage(object): def __init__( self, - content, # type: bytes - encoding, # type: Optional[str] - url, # type: str + content, # type: bytes + encoding, # type: Optional[str] + url, # type: str cache_link_parsing=True, # type: bool ): # type: (...) -> None @@ -415,7 +413,7 @@ def __str__(self): def _handle_get_page_fail( link, # type: Link reason, # type: Union[str, Exception] - meth=None # type: Optional[Callable[..., None]] + meth=None, # type: Optional[Callable[..., None]] ): # type: (...) -> None if meth is None: @@ -430,7 +428,8 @@ def _make_html_page(response, cache_link_parsing=True): response.content, encoding=encoding, url=response.url, - cache_link_parsing=cache_link_parsing) + cache_link_parsing=cache_link_parsing, + ) def _get_html_page(link, session=None): @@ -440,37 +439,44 @@ def _get_html_page(link, session=None): "_get_html_page() missing 1 required keyword argument: 'session'" ) - url = link.url.split('#', 1)[0] + url = link.url.split("#", 1)[0] # Check for VCS schemes that do not support lookup as web pages. vcs_scheme = _match_vcs_scheme(url) if vcs_scheme: - logger.warning('Cannot look at %s URL %s because it does not support ' - 'lookup as web pages.', vcs_scheme, link) + logger.warning( + "Cannot look at %s URL %s because it does not support " + "lookup as web pages.", + vcs_scheme, + link, + ) return None # Tack index.html onto file:// URLs that point to directories scheme, _, path, _, _, _ = urllib_parse.urlparse(url) - if (scheme == 'file' and os.path.isdir(urllib_request.url2pathname(path))): + if scheme == "file" and os.path.isdir(urllib_request.url2pathname(path)): # add trailing slash if not present so urljoin doesn't trim # final segment - if not url.endswith('/'): - url += '/' - url = urllib_parse.urljoin(url, 'index.html') - logger.debug(' file: URL is directory, getting %s', url) + if not url.endswith("/"): + url += "/" + url = urllib_parse.urljoin(url, "index.html") + logger.debug(" file: URL is directory, getting %s", url) try: resp = _get_html_response(url, session=session) except _NotHTTP: logger.warning( - 'Skipping page %s because it looks like an archive, and cannot ' - 'be checked by a HTTP HEAD request.', link, + "Skipping page %s because it looks like an archive, and cannot " + "be checked by a HTTP HEAD request.", + link, ) except _NotHTML as exc: logger.warning( - 'Skipping page %s because the %s request got Content-Type: %s.' - 'The only supported Content-Type is text/html', - link, exc.request_desc, exc.content_type, + "Skipping page %s because the %s request got Content-Type: %s." + "The only supported Content-Type is text/html", + link, + exc.request_desc, + exc.content_type, ) except NetworkConnectionError as exc: _handle_get_page_fail(link, exc) @@ -485,8 +491,7 @@ def _get_html_page(link, session=None): except requests.Timeout: _handle_get_page_fail(link, "timed out") else: - return _make_html_page(resp, - cache_link_parsing=link.cache_link_parsing) + return _make_html_page(resp, cache_link_parsing=link.cache_link_parsing) return None @@ -513,7 +518,7 @@ def group_locations(locations, expand_dir=False): def sort_path(path): # type: (str) -> None url = path_to_url(path) - if mimetypes.guess_type(url, strict=False)[0] == 'text/html': + if mimetypes.guess_type(url, strict=False)[0] == "text/html": urls.append(url) else: files.append(url) @@ -521,7 +526,7 @@ def sort_path(path): for url in locations: is_local_path = os.path.exists(url) - is_file_url = url.startswith('file:') + is_file_url = url.startswith("file:") if is_local_path or is_file_url: if is_local_path: @@ -537,14 +542,15 @@ def sort_path(path): urls.append(url) else: logger.warning( - "Path '%s' is ignored: it is a directory.", path, + "Path '%s' is ignored: it is a directory.", + path, ) elif os.path.isfile(path): sort_path(path) else: logger.warning( - "Url '%s' is ignored: it is neither a file " - "nor a directory.", url, + "Url '%s' is ignored: it is neither a file " "nor a directory.", + url, ) elif is_url(url): # Only add url with clear scheme @@ -552,7 +558,8 @@ def sort_path(path): else: logger.warning( "Url '%s' is ignored. It is either a non-existing " - "path or lacks a specific scheme.", url, + "path or lacks a specific scheme.", + url, ) return files, urls @@ -577,8 +584,8 @@ class CollectedLinks(object): def __init__( self, - files, # type: List[Link] - find_links, # type: List[Link] + files, # type: List[Link] + find_links, # type: List[Link] project_urls, # type: List[Link] ): # type: (...) -> None @@ -604,7 +611,7 @@ class LinkCollector(object): def __init__( self, - session, # type: PipSession + session, # type: PipSession search_scope, # type: SearchScope ): # type: (...) -> None @@ -622,8 +629,8 @@ def create(cls, session, options, suppress_no_index=False): index_urls = [options.index_url] + options.extra_index_urls if options.no_index and not suppress_no_index: logger.debug( - 'Ignoring indexes: %s', - ','.join(redact_auth_from_url(url) for url in index_urls), + "Ignoring indexes: %s", + ",".join(redact_auth_from_url(url) for url in index_urls), ) index_urls = [] @@ -631,10 +638,12 @@ def create(cls, session, options, suppress_no_index=False): find_links = options.find_links or [] search_scope = SearchScope.create( - find_links=find_links, index_urls=index_urls, + find_links=find_links, + index_urls=index_urls, ) link_collector = LinkCollector( - session=session, search_scope=search_scope, + session=session, + search_scope=search_scope, ) return link_collector @@ -660,21 +669,21 @@ def collect_links(self, project_name): index_locations = search_scope.get_index_urls_locations(project_name) index_file_loc, index_url_loc = group_locations(index_locations) fl_file_loc, fl_url_loc = group_locations( - self.find_links, expand_dir=True, + self.find_links, + expand_dir=True, ) - file_links = [ - Link(url) for url in itertools.chain(index_file_loc, fl_file_loc) - ] + file_links = [Link(url) for url in itertools.chain(index_file_loc, fl_file_loc)] # We trust every directly linked archive in find_links - find_link_links = [Link(url, '-f') for url in self.find_links] + find_link_links = [Link(url, "-f") for url in self.find_links] # We trust every url that the user has given us whether it was given # via --index-url or --find-links. # We want to filter out anything that does not have a secure origin. url_locations = [ - link for link in itertools.chain( + link + for link in itertools.chain( # Mark PyPI indices as "cache_link_parsing == False" -- this # will avoid caching the result of parsing the page for links. (Link(url, cache_link_parsing=False) for url in index_url_loc), @@ -685,13 +694,14 @@ def collect_links(self, project_name): url_locations = _remove_duplicate_links(url_locations) lines = [ - '{} location(s) to search for versions of {}:'.format( - len(url_locations), project_name, + "{} location(s) to search for versions of {}:".format( + len(url_locations), + project_name, ), ] for link in url_locations: - lines.append('* {}'.format(link)) - logger.debug('\n'.join(lines)) + lines.append("* {}".format(link)) + logger.debug("\n".join(lines)) return CollectedLinks( files=file_links, diff --git a/src/pip/_internal/index/package_finder.py b/src/pip/_internal/index/package_finder.py index 19a9c2c1370..713286ac193 100644 --- a/src/pip/_internal/index/package_finder.py +++ b/src/pip/_internal/index/package_finder.py @@ -34,16 +34,7 @@ from pip._internal.utils.urls import url_to_path if MYPY_CHECK_RUNNING: - from typing import ( - FrozenSet, - Iterable, - List, - Optional, - Set, - Text, - Tuple, - Union, - ) + from typing import FrozenSet, Iterable, List, Optional, Set, Text, Tuple, Union from pip._vendor.packaging.tags import Tag from pip._vendor.packaging.version import _BaseVersion @@ -54,12 +45,10 @@ from pip._internal.utils.hashes import Hashes BuildTag = Union[Tuple[()], Tuple[int, str]] - CandidateSortingKey = ( - Tuple[int, int, int, _BaseVersion, BuildTag, Optional[int]] - ) + CandidateSortingKey = Tuple[int, int, int, _BaseVersion, BuildTag, Optional[int]] -__all__ = ['FormatControl', 'BestCandidateResult', 'PackageFinder'] +__all__ = ["FormatControl", "BestCandidateResult", "PackageFinder"] logger = logging.getLogger(__name__) @@ -82,27 +71,32 @@ def _check_link_requires_python( """ try: is_compatible = check_requires_python( - link.requires_python, version_info=version_info, + link.requires_python, + version_info=version_info, ) except specifiers.InvalidSpecifier: logger.debug( "Ignoring invalid Requires-Python (%r) for link: %s", - link.requires_python, link, + link.requires_python, + link, ) else: if not is_compatible: - version = '.'.join(map(str, version_info)) + version = ".".join(map(str, version_info)) if not ignore_requires_python: logger.debug( - 'Link requires a different Python (%s not in: %r): %s', - version, link.requires_python, link, + "Link requires a different Python (%s not in: %r): %s", + version, + link.requires_python, + link, ) return False logger.debug( - 'Ignoring failed Requires-Python check (%s not in: %r) ' - 'for link: %s', - version, link.requires_python, link, + "Ignoring failed Requires-Python check (%s not in: %r) " "for link: %s", + version, + link.requires_python, + link, ) return True @@ -114,7 +108,7 @@ class LinkEvaluator(object): Responsible for evaluating links for a particular project. """ - _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') + _py_version_re = re.compile(r"-py([123]\.?[0-9]?)$") # Don't include an allow_yanked default value to make sure each call # site considers whether yanked releases are allowed. This also causes @@ -122,11 +116,11 @@ class LinkEvaluator(object): # people when reading the code. def __init__( self, - project_name, # type: str + project_name, # type: str canonical_name, # type: str - formats, # type: FrozenSet[str] - target_python, # type: TargetPython - allow_yanked, # type: bool + formats, # type: FrozenSet[str] + target_python, # type: TargetPython + allow_yanked, # type: bool ignore_requires_python=None, # type: Optional[bool] ): # type: (...) -> None @@ -170,11 +164,11 @@ def evaluate_link(self, link): """ version = None if link.is_yanked and not self._allow_yanked: - reason = link.yanked_reason or '' + reason = link.yanked_reason or "" # Mark this as a unicode string to prevent "UnicodeEncodeError: # 'ascii' codec can't encode character" in Python 2 when # the reason contains non-ascii characters. - return (False, u'yanked for reason: {}'.format(reason)) + return (False, u"yanked for reason: {}".format(reason)) if link.egg_fragment: egg_info = link.egg_fragment @@ -182,23 +176,21 @@ def evaluate_link(self, link): else: egg_info, ext = link.splitext() if not ext: - return (False, 'not a file') + return (False, "not a file") if ext not in SUPPORTED_EXTENSIONS: - return (False, 'unsupported archive format: {}'.format(ext)) + return (False, "unsupported archive format: {}".format(ext)) if "binary" not in self._formats and ext == WHEEL_EXTENSION: - reason = 'No binaries permitted for {}'.format( - self.project_name) + reason = "No binaries permitted for {}".format(self.project_name) return (False, reason) - if "macosx10" in link.path and ext == '.zip': - return (False, 'macosx10 one') + if "macosx10" in link.path and ext == ".zip": + return (False, "macosx10 one") if ext == WHEEL_EXTENSION: try: wheel = Wheel(link.filename) except InvalidWheelFilename: - return (False, 'invalid wheel filename') + return (False, "invalid wheel filename") if canonicalize_name(wheel.name) != self._canonical_name: - reason = 'wrong project name (not {})'.format( - self.project_name) + reason = "wrong project name (not {})".format(self.project_name) return (False, reason) supported_tags = self._target_python.get_tags() @@ -206,10 +198,8 @@ def evaluate_link(self, link): # Include the wheel's tags in the reason string to # simplify troubleshooting compatibility issues. file_tags = wheel.get_formatted_file_tags() - reason = ( - "none of the wheel's tags match: {}".format( - ', '.join(file_tags) - ) + reason = "none of the wheel's tags match: {}".format( + ", ".join(file_tags) ) return (False, reason) @@ -217,26 +207,28 @@ def evaluate_link(self, link): # This should be up by the self.ok_binary check, but see issue 2700. if "source" not in self._formats and ext != WHEEL_EXTENSION: - reason = 'No sources permitted for {}'.format(self.project_name) + reason = "No sources permitted for {}".format(self.project_name) return (False, reason) if not version: version = _extract_version_from_fragment( - egg_info, self._canonical_name, + egg_info, + self._canonical_name, ) if not version: - reason = 'Missing project version for {}'.format(self.project_name) + reason = "Missing project version for {}".format(self.project_name) return (False, reason) match = self._py_version_re.search(version) if match: - version = version[:match.start()] + version = version[: match.start()] py_version = match.group(1) if py_version != self._target_python.py_version: - return (False, 'Python version is incorrect') + return (False, "Python version is incorrect") supports_python = _check_link_requires_python( - link, version_info=self._target_python.py_version_info, + link, + version_info=self._target_python.py_version_info, ignore_requires_python=self._ignore_requires_python, ) if not supports_python: @@ -244,14 +236,14 @@ def evaluate_link(self, link): # _log_skipped_link(). return (False, None) - logger.debug('Found link %s, version: %s', link, version) + logger.debug("Found link %s, version: %s", link, version) return (True, version) def filter_unallowed_hashes( - candidates, # type: List[InstallationCandidate] - hashes, # type: Hashes + candidates, # type: List[InstallationCandidate] + hashes, # type: Hashes project_name, # type: str ): # type: (...) -> List[InstallationCandidate] @@ -272,8 +264,8 @@ def filter_unallowed_hashes( """ if not hashes: logger.debug( - 'Given no hashes to check %s links for project %r: ' - 'discarding no candidates', + "Given no hashes to check %s links for project %r: " + "discarding no candidates", len(candidates), project_name, ) @@ -303,22 +295,22 @@ def filter_unallowed_hashes( filtered = list(candidates) if len(filtered) == len(candidates): - discard_message = 'discarding no candidates' + discard_message = "discarding no candidates" else: - discard_message = 'discarding {} non-matches:\n {}'.format( + discard_message = "discarding {} non-matches:\n {}".format( len(non_matches), - '\n '.join(str(candidate.link) for candidate in non_matches) + "\n ".join(str(candidate.link) for candidate in non_matches), ) logger.debug( - 'Checked %s links for project %r against %s hashes ' - '(%s matches, %s no digest): %s', + "Checked %s links for project %r against %s hashes " + "(%s matches, %s no digest): %s", len(candidates), project_name, hashes.digest_count, match_count, len(matches_or_no_digest) - match_count, - discard_message + discard_message, ) return filtered @@ -353,9 +345,9 @@ class BestCandidateResult(object): def __init__( self, - candidates, # type: List[InstallationCandidate] + candidates, # type: List[InstallationCandidate] applicable_candidates, # type: List[InstallationCandidate] - best_candidate, # type: Optional[InstallationCandidate] + best_candidate, # type: Optional[InstallationCandidate] ): # type: (...) -> None """ @@ -378,14 +370,12 @@ def __init__( def iter_all(self): # type: () -> Iterable[InstallationCandidate] - """Iterate through all candidates. - """ + """Iterate through all candidates.""" return iter(self._candidates) def iter_applicable(self): # type: () -> Iterable[InstallationCandidate] - """Iterate through the applicable candidates. - """ + """Iterate through the applicable candidates.""" return iter(self._applicable_candidates) @@ -399,12 +389,12 @@ class CandidateEvaluator(object): @classmethod def create( cls, - project_name, # type: str - target_python=None, # type: Optional[TargetPython] + project_name, # type: str + target_python=None, # type: Optional[TargetPython] prefer_binary=False, # type: bool allow_all_prereleases=False, # type: bool - specifier=None, # type: Optional[specifiers.BaseSpecifier] - hashes=None, # type: Optional[Hashes] + specifier=None, # type: Optional[specifiers.BaseSpecifier] + hashes=None, # type: Optional[Hashes] ): # type: (...) -> CandidateEvaluator """Create a CandidateEvaluator object. @@ -435,12 +425,12 @@ def create( def __init__( self, - project_name, # type: str - supported_tags, # type: List[Tag] - specifier, # type: specifiers.BaseSpecifier + project_name, # type: str + supported_tags, # type: List[Tag] + specifier, # type: specifiers.BaseSpecifier prefer_binary=False, # type: bool allow_all_prereleases=False, # type: bool - hashes=None, # type: Optional[Hashes] + hashes=None, # type: Optional[Hashes] ): # type: (...) -> None """ @@ -466,7 +456,8 @@ def get_applicable_candidates( allow_prereleases = self._allow_all_prereleases or None specifier = self._specifier versions = { - str(v) for v in specifier.filter( + str(v) + for v in specifier.filter( # We turn the version object into a str here because otherwise # when we're debundled but setuptools isn't, Python will see # packaging.version.Version and @@ -480,9 +471,7 @@ def get_applicable_candidates( } # Again, converting version to str to deal with debundling. - applicable_candidates = [ - c for c in candidates if str(c.version) in versions - ] + applicable_candidates = [c for c in candidates if str(c.version) in versions] filtered_applicable_candidates = filter_unallowed_hashes( candidates=applicable_candidates, @@ -540,7 +529,7 @@ def _sort_key(self, candidate): binary_preference = 1 pri = -(wheel.support_index_min(valid_tags)) if wheel.build_tag is not None: - match = re.match(r'^(\d+)(.*)$', wheel.build_tag) + match = re.match(r"^(\d+)(.*)$", wheel.build_tag) build_tag_groups = match.groups() build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) else: # sdist @@ -548,13 +537,17 @@ def _sort_key(self, candidate): has_allowed_hash = int(link.is_hash_allowed(self._hashes)) yank_value = -1 * int(link.is_yanked) # -1 for yanked. return ( - has_allowed_hash, yank_value, binary_preference, candidate.version, - build_tag, pri, + has_allowed_hash, + yank_value, + binary_preference, + candidate.version, + build_tag, + pri, ) def sort_best_candidate( self, - candidates, # type: List[InstallationCandidate] + candidates, # type: List[InstallationCandidate] ): # type: (...) -> Optional[InstallationCandidate] """ @@ -568,7 +561,7 @@ def sort_best_candidate( def compute_best_candidate( self, - candidates, # type: List[InstallationCandidate] + candidates, # type: List[InstallationCandidate] ): # type: (...) -> BestCandidateResult """ @@ -594,11 +587,11 @@ class PackageFinder(object): def __init__( self, - link_collector, # type: LinkCollector - target_python, # type: TargetPython - allow_yanked, # type: bool + link_collector, # type: LinkCollector + target_python, # type: TargetPython + allow_yanked, # type: bool format_control=None, # type: Optional[FormatControl] - candidate_prefs=None, # type: CandidatePreferences + candidate_prefs=None, # type: CandidatePreferences ignore_requires_python=None, # type: Optional[bool] ): # type: (...) -> None @@ -635,8 +628,8 @@ def __init__( @classmethod def create( cls, - link_collector, # type: LinkCollector - selection_prefs, # type: SelectionPreferences + link_collector, # type: LinkCollector + selection_prefs, # type: SelectionPreferences target_python=None, # type: Optional[TargetPython] ): # type: (...) -> PackageFinder @@ -753,7 +746,7 @@ def _log_skipped_link(self, link, reason): # the reason contains non-ascii characters. # Also, put the link at the end so the reason is more visible # and because the link string is usually very long. - logger.debug(u'Skipping link: %s: %s', reason, link) + logger.debug(u"Skipping link: %s: %s", reason, link) self._logged_links.add(link) def get_install_candidate(self, link_evaluator, link): @@ -792,7 +785,8 @@ def evaluate_links(self, link_evaluator, links): def process_project_url(self, project_url, link_evaluator): # type: (Link, LinkEvaluator) -> List[InstallationCandidate] logger.debug( - 'Fetching project page and analyzing links: %s', project_url, + "Fetching project page and analyzing links: %s", + project_url, ) html_page = self._link_collector.fetch_page(project_url) if html_page is None: @@ -830,7 +824,8 @@ def find_all_candidates(self, project_name): page_versions = [] for project_url in collected_links.project_urls: package_links = self.process_project_url( - project_url, link_evaluator=link_evaluator, + project_url, + link_evaluator=link_evaluator, ) page_versions.extend(package_links) @@ -841,11 +836,10 @@ def find_all_candidates(self, project_name): if file_versions: file_versions.sort(reverse=True) logger.debug( - 'Local files found: %s', - ', '.join([ - url_to_path(candidate.link.url) - for candidate in file_versions - ]) + "Local files found: %s", + ", ".join( + [url_to_path(candidate.link.url) for candidate in file_versions] + ), ) # This is an intentional priority ordering @@ -853,13 +847,12 @@ def find_all_candidates(self, project_name): def make_candidate_evaluator( self, - project_name, # type: str + project_name, # type: str specifier=None, # type: Optional[specifiers.BaseSpecifier] - hashes=None, # type: Optional[Hashes] + hashes=None, # type: Optional[Hashes] ): # type: (...) -> CandidateEvaluator - """Create a CandidateEvaluator object to use. - """ + """Create a CandidateEvaluator object to use.""" candidate_prefs = self._candidate_prefs return CandidateEvaluator.create( project_name=project_name, @@ -872,9 +865,9 @@ def make_candidate_evaluator( def find_best_candidate( self, - project_name, # type: str - specifier=None, # type: Optional[specifiers.BaseSpecifier] - hashes=None, # type: Optional[Hashes] + project_name, # type: str + specifier=None, # type: Optional[specifiers.BaseSpecifier] + hashes=None, # type: Optional[Hashes] ): # type: (...) -> BestCandidateResult """Find matches for the given project and specifier. @@ -903,11 +896,13 @@ def find_requirement(self, req, upgrade): """ hashes = req.hashes(trust_internet=False) best_candidate_result = self.find_best_candidate( - req.name, specifier=req.specifier, hashes=hashes, + req.name, + specifier=req.specifier, + hashes=hashes, ) best_candidate = best_candidate_result.best_candidate - installed_version = None # type: Optional[_BaseVersion] + installed_version = None # type: Optional[_BaseVersion] if req.satisfied_by is not None: installed_version = parse_version(req.satisfied_by.version) @@ -917,41 +912,45 @@ def _format_versions(cand_iter): # handle different vendoring sources from pip and pkg_resources. # If we stop using the pkg_resources provided specifier and start # using our own, we can drop the cast to str(). - return ", ".join(sorted( - {str(c.version) for c in cand_iter}, - key=parse_version, - )) or "none" + return ( + ", ".join( + sorted( + {str(c.version) for c in cand_iter}, + key=parse_version, + ) + ) + or "none" + ) if installed_version is None and best_candidate is None: logger.critical( - 'Could not find a version that satisfies the requirement %s ' - '(from versions: %s)', + "Could not find a version that satisfies the requirement %s " + "(from versions: %s)", req, _format_versions(best_candidate_result.iter_all()), ) raise DistributionNotFound( - 'No matching distribution found for {}'.format( - req) + "No matching distribution found for {}".format(req) ) best_installed = False if installed_version and ( - best_candidate is None or - best_candidate.version <= installed_version): + best_candidate is None or best_candidate.version <= installed_version + ): best_installed = True if not upgrade and installed_version is not None: if best_installed: logger.debug( - 'Existing installed version (%s) is most up-to-date and ' - 'satisfies requirement', + "Existing installed version (%s) is most up-to-date and " + "satisfies requirement", installed_version, ) else: logger.debug( - 'Existing installed version (%s) satisfies requirement ' - '(most up-to-date version is %s)', + "Existing installed version (%s) satisfies requirement " + "(most up-to-date version is %s)", installed_version, best_candidate.version, ) @@ -960,15 +959,14 @@ def _format_versions(cand_iter): if best_installed: # We have an existing version, and its the best version logger.debug( - 'Installed version (%s) is most up-to-date (past versions: ' - '%s)', + "Installed version (%s) is most up-to-date (past versions: " "%s)", installed_version, _format_versions(best_candidate_result.iter_applicable()), ) raise BestVersionAlreadyInstalled logger.debug( - 'Using version %s (newest of versions: %s)', + "Using version %s (newest of versions: %s)", best_candidate.version, _format_versions(best_candidate_result.iter_applicable()), ) diff --git a/src/pip/_internal/locations.py b/src/pip/_internal/locations.py index 35a4512b4b1..24fbf925c5e 100644 --- a/src/pip/_internal/locations.py +++ b/src/pip/_internal/locations.py @@ -36,22 +36,20 @@ def get_major_minor_version(): Return the major-minor version of the current Python as a string, e.g. "3.7" or "3.10". """ - return '{}.{}'.format(*sys.version_info) + return "{}.{}".format(*sys.version_info) def get_src_prefix(): # type: () -> str if running_under_virtualenv(): - src_prefix = os.path.join(sys.prefix, 'src') + src_prefix = os.path.join(sys.prefix, "src") else: # FIXME: keep src in cwd for now (it is not a temporary folder) try: - src_prefix = os.path.join(os.getcwd(), 'src') + src_prefix = os.path.join(os.getcwd(), "src") except OSError: # In case the current working directory has been renamed or deleted - sys.exit( - "The folder you are executing pip from can no longer be found." - ) + sys.exit("The folder you are executing pip from can no longer be found.") # under macOS + virtualenv sys.prefix is not properly resolved # it is something like /path/to/python/bin/.. @@ -75,20 +73,20 @@ def get_src_prefix(): user_site = site.USER_SITE if WINDOWS: - bin_py = os.path.join(sys.prefix, 'Scripts') - bin_user = os.path.join(user_site, 'Scripts') + bin_py = os.path.join(sys.prefix, "Scripts") + bin_user = os.path.join(user_site, "Scripts") # buildout uses 'bin' on Windows too? if not os.path.exists(bin_py): - bin_py = os.path.join(sys.prefix, 'bin') - bin_user = os.path.join(user_site, 'bin') + bin_py = os.path.join(sys.prefix, "bin") + bin_user = os.path.join(user_site, "bin") else: - bin_py = os.path.join(sys.prefix, 'bin') - bin_user = os.path.join(user_site, 'bin') + bin_py = os.path.join(sys.prefix, "bin") + bin_user = os.path.join(user_site, "bin") # Forcing to use /usr/local/bin for standard macOS framework installs # Also log to ~/Library/Logs/ for use with the Console.app log viewer - if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': - bin_py = '/usr/local/bin' + if sys.platform[:6] == "darwin" and sys.prefix[:16] == "/System/Library/": + bin_py = "/usr/local/bin" def distutils_scheme( @@ -100,14 +98,14 @@ def distutils_scheme( """ from distutils.dist import Distribution - dist_args = {'name': dist_name} # type: Dict[str, Union[str, List[str]]] + dist_args = {"name": dist_name} # type: Dict[str, Union[str, List[str]]] if isolated: dist_args["script_args"] = ["--no-user-cfg"] d = Distribution(dist_args) d.parse_config_files() obj = None # type: Optional[DistutilsCommand] - obj = d.get_command_obj('install', create=True) + obj = d.get_command_obj("install", create=True) assert obj is not None i = cast(distutils_install_command, obj) # NOTE: setting user or home has the side-effect of creating the home dir @@ -125,28 +123,27 @@ def distutils_scheme( scheme = {} for key in SCHEME_KEYS: - scheme[key] = getattr(i, 'install_' + key) + scheme[key] = getattr(i, "install_" + key) # install_lib specified in setup.cfg should install *everything* # into there (i.e. it takes precedence over both purelib and # platlib). Note, i.install_lib is *always* set after # finalize_options(); we only want to override here if the user # has explicitly requested it hence going back to the config - if 'install_lib' in d.get_option_dict('install'): + if "install_lib" in d.get_option_dict("install"): scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) if running_under_virtualenv(): - scheme['headers'] = os.path.join( + scheme["headers"] = os.path.join( i.prefix, - 'include', - 'site', - 'python{}'.format(get_major_minor_version()), + "include", + "site", + "python{}".format(get_major_minor_version()), dist_name, ) if root is not None: - path_no_drive = os.path.splitdrive( - os.path.abspath(scheme["headers"]))[1] + path_no_drive = os.path.splitdrive(os.path.abspath(scheme["headers"]))[1] scheme["headers"] = os.path.join( root, path_no_drive[1:], @@ -181,9 +178,7 @@ def get_scheme( :param prefix: indicates to use the "prefix" scheme and provides the base directory for the same """ - scheme = distutils_scheme( - dist_name, user, home, root, isolated, prefix - ) + scheme = distutils_scheme(dist_name, user, home, root, isolated, prefix) return Scheme( platlib=scheme["platlib"], purelib=scheme["purelib"], diff --git a/src/pip/_internal/models/candidate.py b/src/pip/_internal/models/candidate.py index 0d89a8c07da..c62071bd835 100644 --- a/src/pip/_internal/models/candidate.py +++ b/src/pip/_internal/models/candidate.py @@ -10,8 +10,7 @@ class InstallationCandidate(KeyBasedCompareMixin): - """Represents a potential "candidate" for installation. - """ + """Represents a potential "candidate" for installation.""" __slots__ = ["name", "version", "link"] @@ -23,17 +22,21 @@ def __init__(self, name, version, link): super(InstallationCandidate, self).__init__( key=(self.name, self.version, self.link), - defining_class=InstallationCandidate + defining_class=InstallationCandidate, ) def __repr__(self): # type: () -> str return "".format( - self.name, self.version, self.link, + self.name, + self.version, + self.link, ) def __str__(self): # type: () -> str - return '{!r} candidate (version {} at {})'.format( - self.name, self.version, self.link, + return "{!r} candidate (version {} at {})".format( + self.name, + self.version, + self.link, ) diff --git a/src/pip/_internal/models/direct_url.py b/src/pip/_internal/models/direct_url.py index 99aa68d121b..f4f86db4f89 100644 --- a/src/pip/_internal/models/direct_url.py +++ b/src/pip/_internal/models/direct_url.py @@ -151,9 +151,7 @@ def _from_dict(cls, d): # type: (Optional[Dict[str, Any]]) -> Optional[DirInfo] if d is None: return None - return cls( - editable=_get_required(d, bool, "editable", default=False) - ) + return cls(editable=_get_required(d, bool, "editable", default=False)) def _to_dict(self): # type: () -> Dict[str, Any] @@ -165,7 +163,6 @@ def _to_dict(self): class DirectUrl(object): - def __init__( self, url, # type: str @@ -182,9 +179,9 @@ def _remove_auth_from_netloc(self, netloc): return netloc user_pass, netloc_no_user_pass = netloc.split("@", 1) if ( - isinstance(self.info, VcsInfo) and - self.info.vcs == "git" and - user_pass == "git" + isinstance(self.info, VcsInfo) + and self.info.vcs == "git" + and user_pass == "git" ): return netloc if ENV_VAR_RE.match(user_pass): diff --git a/src/pip/_internal/models/format_control.py b/src/pip/_internal/models/format_control.py index adcf61e2854..b30729fe587 100644 --- a/src/pip/_internal/models/format_control.py +++ b/src/pip/_internal/models/format_control.py @@ -8,8 +8,7 @@ class FormatControl(object): - """Helper for managing formats from which a package can be installed. - """ + """Helper for managing formats from which a package can be installed.""" __slots__ = ["no_binary", "only_binary"] @@ -31,10 +30,7 @@ def __eq__(self, other): if self.__slots__ != other.__slots__: return False - return all( - getattr(self, k) == getattr(other, k) - for k in self.__slots__ - ) + return all(getattr(self, k) == getattr(other, k) for k in self.__slots__) def __ne__(self, other): # type: (object) -> bool @@ -43,29 +39,27 @@ def __ne__(self, other): def __repr__(self): # type: () -> str return "{}({}, {})".format( - self.__class__.__name__, - self.no_binary, - self.only_binary + self.__class__.__name__, self.no_binary, self.only_binary ) @staticmethod def handle_mutual_excludes(value, target, other): # type: (str, Set[str], Set[str]) -> None - if value.startswith('-'): + if value.startswith("-"): raise CommandError( "--no-binary / --only-binary option requires 1 argument." ) - new = value.split(',') - while ':all:' in new: + new = value.split(",") + while ":all:" in new: other.clear() target.clear() - target.add(':all:') - del new[:new.index(':all:') + 1] + target.add(":all:") + del new[: new.index(":all:") + 1] # Without a none, we want to discard everything as :all: covers it - if ':none:' not in new: + if ":none:" not in new: return for name in new: - if name == ':none:': + if name == ":none:": target.clear() continue name = canonicalize_name(name) @@ -76,17 +70,19 @@ def get_allowed_formats(self, canonical_name): # type: (str) -> FrozenSet[str] result = {"binary", "source"} if canonical_name in self.only_binary: - result.discard('source') + result.discard("source") elif canonical_name in self.no_binary: - result.discard('binary') - elif ':all:' in self.only_binary: - result.discard('source') - elif ':all:' in self.no_binary: - result.discard('binary') + result.discard("binary") + elif ":all:" in self.only_binary: + result.discard("source") + elif ":all:" in self.no_binary: + result.discard("binary") return frozenset(result) def disallow_binaries(self): # type: () -> None self.handle_mutual_excludes( - ':all:', self.no_binary, self.only_binary, + ":all:", + self.no_binary, + self.only_binary, ) diff --git a/src/pip/_internal/models/index.py b/src/pip/_internal/models/index.py index 5b4a1fe2274..1c2052e0bd9 100644 --- a/src/pip/_internal/models/index.py +++ b/src/pip/_internal/models/index.py @@ -2,19 +2,17 @@ class PackageIndex(object): - """Represents a Package Index and provides easier access to endpoints - """ + """Represents a Package Index and provides easier access to endpoints""" - __slots__ = ['url', 'netloc', 'simple_url', 'pypi_url', - 'file_storage_domain'] + __slots__ = ["url", "netloc", "simple_url", "pypi_url", "file_storage_domain"] def __init__(self, url, file_storage_domain): # type: (str, str) -> None super(PackageIndex, self).__init__() self.url = url self.netloc = urllib_parse.urlsplit(url).netloc - self.simple_url = self._url_for_path('simple') - self.pypi_url = self._url_for_path('pypi') + self.simple_url = self._url_for_path("simple") + self.pypi_url = self._url_for_path("pypi") # This is part of a temporary hack used to block installs of PyPI # packages which depend on external urls only necessary until PyPI can @@ -26,9 +24,7 @@ def _url_for_path(self, path): return urllib_parse.urljoin(self.url, path) -PyPI = PackageIndex( - 'https://pypi.org/', file_storage_domain='files.pythonhosted.org' -) +PyPI = PackageIndex("https://pypi.org/", file_storage_domain="files.pythonhosted.org") TestPyPI = PackageIndex( - 'https://test.pypi.org/', file_storage_domain='test-files.pythonhosted.org' + "https://test.pypi.org/", file_storage_domain="test-files.pythonhosted.org" ) diff --git a/src/pip/_internal/models/link.py b/src/pip/_internal/models/link.py index 29ef402beef..56652fc6b89 100644 --- a/src/pip/_internal/models/link.py +++ b/src/pip/_internal/models/link.py @@ -22,8 +22,7 @@ class Link(KeyBasedCompareMixin): - """Represents a parsed link from a Package Index's simple URL - """ + """Represents a parsed link from a Package Index's simple URL""" __slots__ = [ "_parsed_url", @@ -36,10 +35,10 @@ class Link(KeyBasedCompareMixin): def __init__( self, - url, # type: str - comes_from=None, # type: Optional[Union[str, HTMLPage]] + url, # type: str + comes_from=None, # type: Optional[Union[str, HTMLPage]] requires_python=None, # type: Optional[str] - yanked_reason=None, # type: Optional[Text] + yanked_reason=None, # type: Optional[Text] cache_link_parsing=True, # type: bool ): # type: (...) -> None @@ -65,7 +64,7 @@ def __init__( """ # url can be a UNC windows share - if url.startswith('\\\\'): + if url.startswith("\\\\"): url = path_to_url(url) self._parsed_url = urllib_parse.urlsplit(url) @@ -84,18 +83,19 @@ def __init__( def __str__(self): # type: () -> str if self.requires_python: - rp = ' (requires-python:{})'.format(self.requires_python) + rp = " (requires-python:{})".format(self.requires_python) else: - rp = '' + rp = "" if self.comes_from: - return '{} (from {}){}'.format( - redact_auth_from_url(self._url), self.comes_from, rp) + return "{} (from {}){}".format( + redact_auth_from_url(self._url), self.comes_from, rp + ) else: return redact_auth_from_url(str(self._url)) def __repr__(self): # type: () -> str - return ''.format(self) + return "".format(self) @property def url(self): @@ -105,7 +105,7 @@ def url(self): @property def filename(self): # type: () -> str - path = self.path.rstrip('/') + path = self.path.rstrip("/") name = posixpath.basename(path) if not name: # Make sure we don't leak auth information if the netloc @@ -114,8 +114,7 @@ def filename(self): return netloc name = urllib_parse.unquote(name) - assert name, ( - 'URL {self._url!r} produced no filename'.format(**locals())) + assert name, "URL {self._url!r} produced no filename".format(**locals()) return name @property @@ -143,7 +142,7 @@ def path(self): def splitext(self): # type: () -> Tuple[str, str] - return splitext(posixpath.basename(self.path.rstrip('/'))) + return splitext(posixpath.basename(self.path.rstrip("/"))) @property def ext(self): @@ -156,7 +155,7 @@ def url_without_fragment(self): scheme, netloc, path, query, fragment = self._parsed_url return urllib_parse.urlunsplit((scheme, netloc, path, query, None)) - _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') + _egg_fragment_re = re.compile(r"[#&]egg=([^&]*)") @property def egg_fragment(self): @@ -166,7 +165,7 @@ def egg_fragment(self): return None return match.group(1) - _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') + _subdirectory_fragment_re = re.compile(r"[#&]subdirectory=([^&]*)") @property def subdirectory_fragment(self): @@ -176,9 +175,7 @@ def subdirectory_fragment(self): return None return match.group(1) - _hash_re = re.compile( - r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)' - ) + _hash_re = re.compile(r"(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)") @property def hash(self): @@ -199,12 +196,12 @@ def hash_name(self): @property def show_url(self): # type: () -> str - return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0]) + return posixpath.basename(self._url.split("#", 1)[0].split("?", 1)[0]) @property def is_file(self): # type: () -> bool - return self.scheme == 'file' + return self.scheme == "file" def is_existing_dir(self): # type: () -> bool diff --git a/src/pip/_internal/models/scheme.py b/src/pip/_internal/models/scheme.py index 5040551eb0e..98ec415e1c9 100644 --- a/src/pip/_internal/models/scheme.py +++ b/src/pip/_internal/models/scheme.py @@ -6,7 +6,7 @@ """ -SCHEME_KEYS = ['platlib', 'purelib', 'headers', 'scripts', 'data'] +SCHEME_KEYS = ["platlib", "purelib", "headers", "scripts", "data"] class Scheme(object): diff --git a/src/pip/_internal/models/search_scope.py b/src/pip/_internal/models/search_scope.py index d732504e6f5..0670976889f 100644 --- a/src/pip/_internal/models/search_scope.py +++ b/src/pip/_internal/models/search_scope.py @@ -43,7 +43,7 @@ def create( # blindly normalize anything starting with a ~... built_find_links = [] # type: List[str] for link in find_links: - if link.startswith('~'): + if link.startswith("~"): new_link = normalize_path(link) if os.path.exists(new_link): link = new_link @@ -54,11 +54,11 @@ def create( if not has_tls(): for link in itertools.chain(index_urls, built_find_links): parsed = urllib_parse.urlparse(link) - if parsed.scheme == 'https': + if parsed.scheme == "https": logger.warning( - 'pip is configured with locations that require ' - 'TLS/SSL, however the ssl module in Python is not ' - 'available.' + "pip is configured with locations that require " + "TLS/SSL, however the ssl module in Python is not " + "available." ) break @@ -95,20 +95,23 @@ def get_formatted_locations(self): # exceptions for malformed URLs if not purl.scheme and not purl.netloc: logger.warning( - 'The index url "%s" seems invalid, ' - 'please provide a scheme.', redacted_index_url) + 'The index url "%s" seems invalid, ' "please provide a scheme.", + redacted_index_url, + ) redacted_index_urls.append(redacted_index_url) - lines.append('Looking in indexes: {}'.format( - ', '.join(redacted_index_urls))) + lines.append( + "Looking in indexes: {}".format(", ".join(redacted_index_urls)) + ) if self.find_links: lines.append( - 'Looking in links: {}'.format(', '.join( - redact_auth_from_url(url) for url in self.find_links)) + "Looking in links: {}".format( + ", ".join(redact_auth_from_url(url) for url in self.find_links) + ) ) - return '\n'.join(lines) + return "\n".join(lines) def get_index_urls_locations(self, project_name): # type: (str) -> List[str] @@ -121,15 +124,15 @@ def get_index_urls_locations(self, project_name): def mkurl_pypi_url(url): # type: (str) -> str loc = posixpath.join( - url, - urllib_parse.quote(canonicalize_name(project_name))) + url, urllib_parse.quote(canonicalize_name(project_name)) + ) # For maximum compatibility with easy_install, ensure the path # ends in a trailing slash. Although this isn't in the spec # (and PyPI can handle it without the slash) some other index # implementations might break if they relied on easy_install's # behavior. - if not loc.endswith('/'): - loc = loc + '/' + if not loc.endswith("/"): + loc = loc + "/" return loc return [mkurl_pypi_url(url) for url in self.index_urls] diff --git a/src/pip/_internal/models/selection_prefs.py b/src/pip/_internal/models/selection_prefs.py index 83110dd8f90..427e3345d42 100644 --- a/src/pip/_internal/models/selection_prefs.py +++ b/src/pip/_internal/models/selection_prefs.py @@ -12,8 +12,13 @@ class SelectionPreferences(object): and installing files. """ - __slots__ = ['allow_yanked', 'allow_all_prereleases', 'format_control', - 'prefer_binary', 'ignore_requires_python'] + __slots__ = [ + "allow_yanked", + "allow_all_prereleases", + "format_control", + "prefer_binary", + "ignore_requires_python", + ] # Don't include an allow_yanked default value to make sure each call # site considers whether yanked releases are allowed. This also causes @@ -23,8 +28,8 @@ def __init__( self, allow_yanked, # type: bool allow_all_prereleases=False, # type: bool - format_control=None, # type: Optional[FormatControl] - prefer_binary=False, # type: bool + format_control=None, # type: Optional[FormatControl] + prefer_binary=False, # type: bool ignore_requires_python=None, # type: Optional[bool] ): # type: (...) -> None diff --git a/src/pip/_internal/models/target_python.py b/src/pip/_internal/models/target_python.py index 6d1ca79645f..0ac6ab6dd19 100644 --- a/src/pip/_internal/models/target_python.py +++ b/src/pip/_internal/models/target_python.py @@ -1,9 +1,6 @@ import sys -from pip._internal.utils.compatibility_tags import ( - get_supported, - version_info_to_nodot, -) +from pip._internal.utils.compatibility_tags import get_supported, version_info_to_nodot from pip._internal.utils.misc import normalize_version_info from pip._internal.utils.typing import MYPY_CHECK_RUNNING @@ -60,7 +57,7 @@ def __init__( else: py_version_info = normalize_version_info(py_version_info) - py_version = '.'.join(map(str, py_version_info[:2])) + py_version = ".".join(map(str, py_version_info[:2])) self.abi = abi self.implementation = implementation @@ -78,18 +75,19 @@ def format_given(self): """ display_version = None if self._given_py_version_info is not None: - display_version = '.'.join( + display_version = ".".join( str(part) for part in self._given_py_version_info ) key_values = [ - ('platform', self.platform), - ('version_info', display_version), - ('abi', self.abi), - ('implementation', self.implementation), + ("platform", self.platform), + ("version_info", display_version), + ("abi", self.abi), + ("implementation", self.implementation), ] - return ' '.join( - '{}={!r}'.format(key, value) for key, value in key_values + return " ".join( + "{}={!r}".format(key, value) + for key, value in key_values if value is not None ) diff --git a/src/pip/_internal/models/wheel.py b/src/pip/_internal/models/wheel.py index 4d4068f3b73..3a332c04601 100644 --- a/src/pip/_internal/models/wheel.py +++ b/src/pip/_internal/models/wheel.py @@ -19,7 +19,7 @@ class Wheel(object): r"""^(?P(?P.+?)-(?P.*?)) ((-(?P\d[^-]*?))?-(?P.+?)-(?P.+?)-(?P.+?) \.whl|\.dist-info)$""", - re.VERBOSE + re.VERBOSE, ) def __init__(self, filename): @@ -33,19 +33,18 @@ def __init__(self, filename): "{} is not a valid wheel filename.".format(filename) ) self.filename = filename - self.name = wheel_info.group('name').replace('_', '-') + self.name = wheel_info.group("name").replace("_", "-") # we'll assume "_" means "-" due to wheel naming scheme # (https://github.com/pypa/pip/issues/1150) - self.version = wheel_info.group('ver').replace('_', '-') - self.build_tag = wheel_info.group('build') - self.pyversions = wheel_info.group('pyver').split('.') - self.abis = wheel_info.group('abi').split('.') - self.plats = wheel_info.group('plat').split('.') + self.version = wheel_info.group("ver").replace("_", "-") + self.build_tag = wheel_info.group("build") + self.pyversions = wheel_info.group("pyver").split(".") + self.abis = wheel_info.group("abi").split(".") + self.plats = wheel_info.group("plat").split(".") # All the tag combinations from this file self.file_tags = { - Tag(x, y, z) for x in self.pyversions - for y in self.abis for z in self.plats + Tag(x, y, z) for x in self.pyversions for y in self.abis for z in self.plats } def get_formatted_file_tags(self): diff --git a/src/pip/_internal/network/auth.py b/src/pip/_internal/network/auth.py index 357811a16f1..1a34fbac1d5 100644 --- a/src/pip/_internal/network/auth.py +++ b/src/pip/_internal/network/auth.py @@ -36,7 +36,8 @@ keyring = None except Exception as exc: logger.warning( - "Keyring is skipped due to an exception: %s", str(exc), + "Keyring is skipped due to an exception: %s", + str(exc), ) keyring = None @@ -68,14 +69,14 @@ def get_keyring_auth(url, username): except Exception as exc: logger.warning( - "Keyring is skipped due to an exception: %s", str(exc), + "Keyring is skipped due to an exception: %s", + str(exc), ) keyring = None return None class MultiDomainBasicAuth(AuthBase): - def __init__(self, prompting=True, index_urls=None): # type: (bool, Optional[List[str]]) -> None self.prompting = prompting @@ -111,8 +112,7 @@ def _get_index_url(self, url): return u return None - def _get_new_credentials(self, original_url, allow_netrc=True, - allow_keyring=True): + def _get_new_credentials(self, original_url, allow_netrc=True, allow_keyring=True): # type: (str, bool, bool) -> AuthInfo """Find and return credentials for the specified URL.""" # Split the credentials and netloc from the url. @@ -152,9 +152,8 @@ def _get_new_credentials(self, original_url, allow_netrc=True, # If we don't have a password and keyring is available, use it. if allow_keyring: # The index url is more specific than the netloc, so try it first - kr_auth = ( - get_keyring_auth(index_url, username) or - get_keyring_auth(netloc, username) + kr_auth = get_keyring_auth(index_url, username) or get_keyring_auth( + netloc, username ) if kr_auth: logger.debug("Found credentials in keyring for %s", netloc) @@ -196,7 +195,8 @@ def _get_url_and_credentials(self, original_url): assert ( # Credentials were found - (username is not None and password is not None) or + (username is not None and password is not None) + or # Credentials were not found (username is None and password is None) ), "Could not load credentials from url: {}".format(original_url) @@ -290,7 +290,8 @@ def warn_on_401(self, resp, **kwargs): """Response callback to warn about incorrect credentials.""" if resp.status_code == 401: logger.warning( - '401 Error, Credentials not correct for %s', resp.request.url, + "401 Error, Credentials not correct for %s", + resp.request.url, ) def save_credentials(self, resp, **kwargs): @@ -304,7 +305,7 @@ def save_credentials(self, resp, **kwargs): self._credentials_to_save = None if creds and resp.status_code < 400: try: - logger.info('Saving credentials to keyring') + logger.info("Saving credentials to keyring") keyring.set_password(*creds) except Exception: - logger.exception('Failed to save credentials') + logger.exception("Failed to save credentials") diff --git a/src/pip/_internal/network/cache.py b/src/pip/_internal/network/cache.py index d2a1b7313f7..7344986786c 100644 --- a/src/pip/_internal/network/cache.py +++ b/src/pip/_internal/network/cache.py @@ -58,7 +58,7 @@ def get(self, key): # type: (str) -> Optional[bytes] path = self._get_cache_path(key) with suppressed_cache_errors(): - with open(path, 'rb') as f: + with open(path, "rb") as f: return f.read() def set(self, key, value): diff --git a/src/pip/_internal/network/download.py b/src/pip/_internal/network/download.py index 56feaabac10..365b3eb27f4 100644 --- a/src/pip/_internal/network/download.py +++ b/src/pip/_internal/network/download.py @@ -11,16 +11,8 @@ from pip._internal.exceptions import NetworkConnectionError from pip._internal.models.index import PyPI from pip._internal.network.cache import is_from_cache -from pip._internal.network.utils import ( - HEADERS, - raise_for_status, - response_chunks, -) -from pip._internal.utils.misc import ( - format_size, - redact_auth_from_url, - splitext, -) +from pip._internal.network.utils import HEADERS, raise_for_status, response_chunks +from pip._internal.utils.misc import format_size, redact_auth_from_url, splitext from pip._internal.utils.typing import MYPY_CHECK_RUNNING if MYPY_CHECK_RUNNING: @@ -37,7 +29,7 @@ def _get_http_response_size(resp): # type: (Response) -> Optional[int] try: - return int(resp.headers['content-length']) + return int(resp.headers["content-length"]) except (ValueError, KeyError, TypeError): return None @@ -45,7 +37,7 @@ def _get_http_response_size(resp): def _prepare_download( resp, # type: Response link, # type: Link - progress_bar # type: str + progress_bar, # type: str ): # type: (...) -> Iterable[bytes] total_length = _get_http_response_size(resp) @@ -58,7 +50,7 @@ def _prepare_download( logged_url = redact_auth_from_url(url) if total_length: - logged_url = '{} ({})'.format(logged_url, format_size(total_length)) + logged_url = "{} ({})".format(logged_url, format_size(total_length)) if is_from_cache(resp): logger.info("Using cached %s", logged_url) @@ -81,9 +73,7 @@ def _prepare_download( if not show_progress: return chunks - return DownloadProgressProvider( - progress_bar, max=total_length - )(chunks) + return DownloadProgressProvider(progress_bar, max=total_length)(chunks) def sanitize_content_filename(filename): @@ -101,7 +91,7 @@ def parse_content_disposition(content_disposition, default_filename): return the default filename if the result is empty. """ _type, params = cgi.parse_header(content_disposition) - filename = params.get('filename') + filename = params.get("filename") if filename: # We need to sanitize the filename to prevent directory traversal # in case the filename contains ".." path parts. @@ -116,14 +106,12 @@ def _get_http_response_filename(resp, link): """ filename = link.filename # fallback # Have a look at the Content-Disposition header for a better guess - content_disposition = resp.headers.get('content-disposition') + content_disposition = resp.headers.get("content-disposition") if content_disposition: filename = parse_content_disposition(content_disposition, filename) ext = splitext(filename)[1] # type: Optional[str] if not ext: - ext = mimetypes.guess_extension( - resp.headers.get('content-type', '') - ) + ext = mimetypes.guess_extension(resp.headers.get("content-type", "")) if ext: filename += ext if not ext and link.url != resp.url: @@ -135,7 +123,7 @@ def _get_http_response_filename(resp, link): def _http_get_download(session, link): # type: (PipSession, Link) -> Response - target_url = link.url.split('#', 1)[0] + target_url = link.url.split("#", 1)[0] resp = session.get(target_url, headers=HEADERS, stream=True) raise_for_status(resp) return resp @@ -167,15 +155,14 @@ def __call__(self, link, location): filepath = os.path.join(location, filename) chunks = _prepare_download(resp, link, self._progress_bar) - with open(filepath, 'wb') as content_file: + with open(filepath, "wb") as content_file: for chunk in chunks: content_file.write(chunk) - content_type = resp.headers.get('Content-Type', '') + content_type = resp.headers.get("Content-Type", "") return filepath, content_type class BatchDownloader(object): - def __init__( self, session, # type: PipSession @@ -195,7 +182,8 @@ def __call__(self, links, location): assert e.response is not None logger.critical( "HTTP error %s while getting %s", - e.response.status_code, link, + e.response.status_code, + link, ) raise @@ -203,8 +191,8 @@ def __call__(self, links, location): filepath = os.path.join(location, filename) chunks = _prepare_download(resp, link, self._progress_bar) - with open(filepath, 'wb') as content_file: + with open(filepath, "wb") as content_file: for chunk in chunks: content_file.write(chunk) - content_type = resp.headers.get('Content-Type', '') + content_type = resp.headers.get("Content-Type", "") yield link.url, (filepath, content_type) diff --git a/src/pip/_internal/network/lazy_wheel.py b/src/pip/_internal/network/lazy_wheel.py index a0f9e151dd7..b09c37cbed0 100644 --- a/src/pip/_internal/network/lazy_wheel.py +++ b/src/pip/_internal/network/lazy_wheel.py @@ -1,6 +1,6 @@ """Lazy ZIP over HTTP""" -__all__ = ['HTTPRangeRequestUnsupported', 'dist_from_wheel_url'] +__all__ = ["HTTPRangeRequestUnsupported", "dist_from_wheel_url"] from bisect import bisect_left, bisect_right from contextlib import contextmanager @@ -10,11 +10,7 @@ from pip._vendor.requests.models import CONTENT_CHUNK_SIZE from pip._vendor.six.moves import range -from pip._internal.network.utils import ( - HEADERS, - raise_for_status, - response_chunks, -) +from pip._internal.network.utils import HEADERS, raise_for_status, response_chunks from pip._internal.utils.typing import MYPY_CHECK_RUNNING from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel @@ -64,20 +60,20 @@ def __init__(self, url, session, chunk_size=CONTENT_CHUNK_SIZE): raise_for_status(head) assert head.status_code == 200 self._session, self._url, self._chunk_size = session, url, chunk_size - self._length = int(head.headers['Content-Length']) + self._length = int(head.headers["Content-Length"]) self._file = NamedTemporaryFile() self.truncate(self._length) self._left = [] # type: List[int] self._right = [] # type: List[int] - if 'bytes' not in head.headers.get('Accept-Ranges', 'none'): - raise HTTPRangeRequestUnsupported('range request is not supported') + if "bytes" not in head.headers.get("Accept-Ranges", "none"): + raise HTTPRangeRequestUnsupported("range request is not supported") self._check_zip() @property def mode(self): # type: () -> str """Opening mode, which is always rb.""" - return 'rb' + return "rb" @property def name(self): @@ -111,9 +107,9 @@ def read(self, size=-1): """ download_size = max(size, self._chunk_size) start, length = self.tell(), self._length - stop = length if size < 0 else min(start+download_size, length) - start = max(0, stop-download_size) - self._download(start, stop-1) + stop = length if size < 0 else min(start + download_size, length) + start = max(0, stop - download_size) + self._download(start, stop - 1) return self._file.read(size) def readable(self): @@ -195,9 +191,9 @@ def _stream_response(self, start, end, base_headers=HEADERS): # type: (int, int, Dict[str, str]) -> Response """Return HTTP response to a range request from start to end.""" headers = base_headers.copy() - headers['Range'] = 'bytes={}-{}'.format(start, end) + headers["Range"] = "bytes={}-{}".format(start, end) # TODO: Get range requests to be correctly cached - headers['Cache-Control'] = 'no-cache' + headers["Cache-Control"] = "no-cache" return self._session.get(self._url, headers=headers, stream=True) def _merge(self, start, end, left, right): @@ -211,11 +207,11 @@ def _merge(self, start, end, left, right): right (int): Index after last overlapping downloaded data """ lslice, rslice = self._left[left:right], self._right[left:right] - i = start = min([start]+lslice[:1]) - end = max([end]+rslice[-1:]) + i = start = min([start] + lslice[:1]) + end = max([end] + rslice[-1:]) for j, k in zip(lslice, rslice): if j > i: - yield i, j-1 + yield i, j - 1 i = k + 1 if i <= end: yield i, end diff --git a/src/pip/_internal/network/session.py b/src/pip/_internal/network/session.py index 176f0fb682c..2e988078720 100644 --- a/src/pip/_internal/network/session.py +++ b/src/pip/_internal/network/session.py @@ -25,6 +25,7 @@ from pip import __version__ from pip._internal.network.auth import MultiDomainBasicAuth from pip._internal.network.cache import SafeFileCache + # Import ssl from compat so the initial import occurs in only one place. from pip._internal.utils.compat import has_tls, ipaddress from pip._internal.utils.glibc import libc_ver @@ -73,13 +74,13 @@ # For more background, see: https://github.com/pypa/pip/issues/5499 CI_ENVIRONMENT_VARIABLES = ( # Azure Pipelines - 'BUILD_BUILDID', + "BUILD_BUILDID", # Jenkins - 'BUILD_ID', + "BUILD_ID", # AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI - 'CI', + "CI", # Explicit environment variable. - 'PIP_IS_CI', + "PIP_IS_CI", ) @@ -106,33 +107,38 @@ def user_agent(): }, } - if data["implementation"]["name"] == 'CPython': + if data["implementation"]["name"] == "CPython": data["implementation"]["version"] = platform.python_version() - elif data["implementation"]["name"] == 'PyPy': - if sys.pypy_version_info.releaselevel == 'final': + elif data["implementation"]["name"] == "PyPy": + if sys.pypy_version_info.releaselevel == "final": pypy_version_info = sys.pypy_version_info[:3] else: pypy_version_info = sys.pypy_version_info data["implementation"]["version"] = ".".join( [str(x) for x in pypy_version_info] ) - elif data["implementation"]["name"] == 'Jython': + elif data["implementation"]["name"] == "Jython": # Complete Guess data["implementation"]["version"] = platform.python_version() - elif data["implementation"]["name"] == 'IronPython': + elif data["implementation"]["name"] == "IronPython": # Complete Guess data["implementation"]["version"] = platform.python_version() if sys.platform.startswith("linux"): from pip._vendor import distro - distro_infos = dict(filter( - lambda x: x[1], - zip(["name", "version", "id"], distro.linux_distribution()), - )) - libc = dict(filter( - lambda x: x[1], - zip(["lib", "version"], libc_ver()), - )) + + distro_infos = dict( + filter( + lambda x: x[1], + zip(["name", "version", "id"], distro.linux_distribution()), + ) + ) + libc = dict( + filter( + lambda x: x[1], + zip(["lib", "version"], libc_ver()), + ) + ) if libc: distro_infos["libc"] = libc if distro_infos: @@ -152,6 +158,7 @@ def user_agent(): if has_tls(): import _ssl as ssl + data["openssl_version"] = ssl.OPENSSL_VERSION setuptools_version = get_installed_version("setuptools") @@ -175,9 +182,9 @@ def user_agent(): class LocalFSAdapter(BaseAdapter): - - def send(self, request, stream=None, timeout=None, verify=None, cert=None, - proxies=None): + def send( + self, request, stream=None, timeout=None, verify=None, cert=None, proxies=None + ): pathname = url_to_path(request.url) resp = Response() @@ -192,11 +199,13 @@ def send(self, request, stream=None, timeout=None, verify=None, cert=None, else: modified = email.utils.formatdate(stats.st_mtime, usegmt=True) content_type = mimetypes.guess_type(pathname)[0] or "text/plain" - resp.headers = CaseInsensitiveDict({ - "Content-Type": content_type, - "Content-Length": stats.st_size, - "Last-Modified": modified, - }) + resp.headers = CaseInsensitiveDict( + { + "Content-Type": content_type, + "Content-Length": stats.st_size, + "Last-Modified": modified, + } + ) resp.raw = open(pathname, "rb") resp.close = resp.raw.close @@ -208,7 +217,6 @@ def close(self): class InsecureHTTPAdapter(HTTPAdapter): - def cert_verify(self, conn, url, verify, cert): super(InsecureHTTPAdapter, self).cert_verify( conn=conn, url=url, verify=False, cert=cert @@ -216,7 +224,6 @@ def cert_verify(self, conn, url, verify, cert): class InsecureCacheControlAdapter(CacheControlAdapter): - def cert_verify(self, conn, url, verify, cert): super(InsecureCacheControlAdapter, self).cert_verify( conn=conn, url=url, verify=False, cert=cert @@ -255,7 +262,6 @@ def __init__(self, *args, **kwargs): # Set the total number of retries that a particular request can # have. total=retries, - # A 503 error from PyPI typically means that the Fastly -> Origin # connection got interrupted in some way. A 503 error in general # is typically considered a transient error so we'll go ahead and @@ -263,7 +269,6 @@ def __init__(self, *args, **kwargs): # A 500 may indicate transient error in Amazon S3 # A 520 or 527 - may indicate transient error in CloudFlare status_forcelist=[500, 503, 520, 527], - # Add a small amount of back off between failed requests in # order to prevent hammering the service. backoff_factor=0.25, @@ -320,46 +325,42 @@ def add_trusted_host(self, host, source=None, suppress_logging=False): string came from. """ if not suppress_logging: - msg = 'adding trusted host: {!r}'.format(host) + msg = "adding trusted host: {!r}".format(host) if source is not None: - msg += ' (from {})'.format(source) + msg += " (from {})".format(source) logger.info(msg) host_port = parse_netloc(host) if host_port not in self.pip_trusted_origins: self.pip_trusted_origins.append(host_port) - self.mount( - build_url_from_netloc(host) + '/', - self._trusted_host_adapter - ) + self.mount(build_url_from_netloc(host) + "/", self._trusted_host_adapter) if not host_port[1]: # Mount wildcard ports for the same host. - self.mount( - build_url_from_netloc(host) + ':', - self._trusted_host_adapter - ) + self.mount(build_url_from_netloc(host) + ":", self._trusted_host_adapter) def iter_secure_origins(self): # type: () -> Iterator[SecureOrigin] for secure_origin in SECURE_ORIGINS: yield secure_origin for host, port in self.pip_trusted_origins: - yield ('*', host, '*' if port is None else port) + yield ("*", host, "*" if port is None else port) def is_secure_origin(self, location): # type: (Link) -> bool # Determine if this url used a secure transport mechanism parsed = urllib_parse.urlparse(str(location)) origin_protocol, origin_host, origin_port = ( - parsed.scheme, parsed.hostname, parsed.port, + parsed.scheme, + parsed.hostname, + parsed.port, ) # The protocol to use to see if the protocol matches. # Don't count the repository type as part of the protocol: in # cases such as "git+ssh", only use "ssh". (I.e., Only verify against # the last scheme.) - origin_protocol = origin_protocol.rsplit('+', 1)[-1] + origin_protocol = origin_protocol.rsplit("+", 1)[-1] # Determine if our origin is a secure origin by looking through our # hardcoded list of secure origins, as well as any additional ones @@ -371,20 +372,16 @@ def is_secure_origin(self, location): try: addr = ipaddress.ip_address( - None - if origin_host is None - else six.ensure_text(origin_host) - ) - network = ipaddress.ip_network( - six.ensure_text(secure_host) + None if origin_host is None else six.ensure_text(origin_host) ) + network = ipaddress.ip_network(six.ensure_text(secure_host)) except ValueError: # We don't have both a valid address or a valid network, so # we'll check this origin against hostnames. if ( - origin_host and - origin_host.lower() != secure_host.lower() and - secure_host != "*" + origin_host + and origin_host.lower() != secure_host.lower() + and secure_host != "*" ): continue else: @@ -395,9 +392,9 @@ def is_secure_origin(self, location): # Check to see if the port matches. if ( - origin_port != secure_port and - secure_port != "*" and - secure_port is not None + origin_port != secure_port + and secure_port != "*" + and secure_port is not None ): continue diff --git a/src/pip/_internal/network/utils.py b/src/pip/_internal/network/utils.py index 907b3fed49a..f3fbbd47aa4 100644 --- a/src/pip/_internal/network/utils.py +++ b/src/pip/_internal/network/utils.py @@ -25,31 +25,37 @@ # you're not asking for a compressed file and will then decompress it # before sending because if that's the case I don't think it'll ever be # possible to make this work. -HEADERS = {'Accept-Encoding': 'identity'} # type: Dict[str, str] +HEADERS = {"Accept-Encoding": "identity"} # type: Dict[str, str] def raise_for_status(resp): # type: (Response) -> None - http_error_msg = u'' + http_error_msg = u"" if isinstance(resp.reason, bytes): # We attempt to decode utf-8 first because some servers # choose to localize their reason strings. If the string # isn't utf-8, we fall back to iso-8859-1 for all other # encodings. try: - reason = resp.reason.decode('utf-8') + reason = resp.reason.decode("utf-8") except UnicodeDecodeError: - reason = resp.reason.decode('iso-8859-1') + reason = resp.reason.decode("iso-8859-1") else: reason = resp.reason if 400 <= resp.status_code < 500: - http_error_msg = u'%s Client Error: %s for url: %s' % ( - resp.status_code, reason, resp.url) + http_error_msg = u"%s Client Error: %s for url: %s" % ( + resp.status_code, + reason, + resp.url, + ) elif 500 <= resp.status_code < 600: - http_error_msg = u'%s Server Error: %s for url: %s' % ( - resp.status_code, reason, resp.url) + http_error_msg = u"%s Server Error: %s for url: %s" % ( + resp.status_code, + reason, + resp.url, + ) if http_error_msg: raise NetworkConnectionError(http_error_msg, response=resp) @@ -57,8 +63,7 @@ def raise_for_status(resp): def response_chunks(response, chunk_size=CONTENT_CHUNK_SIZE): # type: (Response, int) -> Iterator[bytes] - """Given a requests Response, provide the data chunks. - """ + """Given a requests Response, provide the data chunks.""" try: # Special case for urllib3. for chunk in response.raw.stream( diff --git a/src/pip/_internal/network/xmlrpc.py b/src/pip/_internal/network/xmlrpc.py index 504018f28fe..1c60e671a13 100644 --- a/src/pip/_internal/network/xmlrpc.py +++ b/src/pip/_internal/network/xmlrpc.py @@ -38,9 +38,10 @@ def request(self, host, handler, request_body, verbose=False): parts = (self._scheme, host, handler, None, None, None) url = urllib_parse.urlunparse(parts) try: - headers = {'Content-Type': 'text/xml'} - response = self._session.post(url, data=request_body, - headers=headers, stream=True) + headers = {"Content-Type": "text/xml"} + response = self._session.post( + url, data=request_body, headers=headers, stream=True + ) raise_for_status(response) self.verbose = verbose return self.parse_response(response.raw) @@ -48,6 +49,7 @@ def request(self, host, handler, request_body, verbose=False): assert exc.response logger.critical( "HTTP error %s while getting %s", - exc.response.status_code, url, + exc.response.status_code, + url, ) raise diff --git a/src/pip/_internal/operations/build/metadata.py b/src/pip/_internal/operations/build/metadata.py index 5709962b09e..0c1ae5e7f54 100644 --- a/src/pip/_internal/operations/build/metadata.py +++ b/src/pip/_internal/operations/build/metadata.py @@ -19,9 +19,7 @@ def generate_metadata(build_env, backend): Returns the generated metadata directory. """ - metadata_tmpdir = TempDirectory( - kind="modern-metadata", globally_managed=True - ) + metadata_tmpdir = TempDirectory(kind="modern-metadata", globally_managed=True) metadata_dir = metadata_tmpdir.path @@ -31,8 +29,6 @@ def generate_metadata(build_env, backend): # consider the possibility that this hook doesn't exist. runner = runner_with_spinner_message("Preparing wheel metadata") with backend.subprocess_runner(runner): - distinfo_dir = backend.prepare_metadata_for_build_wheel( - metadata_dir - ) + distinfo_dir = backend.prepare_metadata_for_build_wheel(metadata_dir) return os.path.join(metadata_dir, distinfo_dir) diff --git a/src/pip/_internal/operations/build/metadata_legacy.py b/src/pip/_internal/operations/build/metadata_legacy.py index 14762aef3c0..b004ec4a9ed 100644 --- a/src/pip/_internal/operations/build/metadata_legacy.py +++ b/src/pip/_internal/operations/build/metadata_legacy.py @@ -18,22 +18,15 @@ def _find_egg_info(directory): # type: (str) -> str - """Find an .egg-info subdirectory in `directory`. - """ - filenames = [ - f for f in os.listdir(directory) if f.endswith(".egg-info") - ] + """Find an .egg-info subdirectory in `directory`.""" + filenames = [f for f in os.listdir(directory) if f.endswith(".egg-info")] if not filenames: - raise InstallationError( - "No .egg-info directory found in {}".format(directory) - ) + raise InstallationError("No .egg-info directory found in {}".format(directory)) if len(filenames) > 1: raise InstallationError( - "More than one .egg-info directory found in {}".format( - directory - ) + "More than one .egg-info directory found in {}".format(directory) ) return os.path.join(directory, filenames[0]) @@ -52,13 +45,12 @@ def generate_metadata( Returns the generated metadata directory. """ logger.debug( - 'Running setup.py (path:%s) egg_info for package %s', - setup_py_path, details, + "Running setup.py (path:%s) egg_info for package %s", + setup_py_path, + details, ) - egg_info_dir = TempDirectory( - kind="pip-egg-info", globally_managed=True - ).path + egg_info_dir = TempDirectory(kind="pip-egg-info", globally_managed=True).path args = make_setuptools_egg_info_args( setup_py_path, @@ -70,7 +62,7 @@ def generate_metadata( call_subprocess( args, cwd=source_dir, - command_desc='python setup.py egg_info', + command_desc="python setup.py egg_info", ) # Return the .egg-info directory. diff --git a/src/pip/_internal/operations/build/wheel.py b/src/pip/_internal/operations/build/wheel.py index d16ee0966e1..8dc5babc76b 100644 --- a/src/pip/_internal/operations/build/wheel.py +++ b/src/pip/_internal/operations/build/wheel.py @@ -27,14 +27,16 @@ def build_wheel_pep517( assert metadata_directory is not None if build_options: # PEP 517 does not support --build-options - logger.error('Cannot build wheel for %s using PEP 517 when ' - '--build-option is present', name) + logger.error( + "Cannot build wheel for %s using PEP 517 when " "--build-option is present", + name, + ) return None try: - logger.debug('Destination directory: %s', tempd) + logger.debug("Destination directory: %s", tempd) runner = runner_with_spinner_message( - 'Building wheel for {} (PEP 517)'.format(name) + "Building wheel for {} (PEP 517)".format(name) ) with backend.subprocess_runner(runner): wheel_name = backend.build_wheel( @@ -42,6 +44,6 @@ def build_wheel_pep517( metadata_directory=metadata_directory, ) except Exception: - logger.error('Failed building wheel for %s', name) + logger.error("Failed building wheel for %s", name) return None return os.path.join(tempd, wheel_name) diff --git a/src/pip/_internal/operations/build/wheel_legacy.py b/src/pip/_internal/operations/build/wheel_legacy.py index 37dc876acbd..9ab4ef44256 100644 --- a/src/pip/_internal/operations/build/wheel_legacy.py +++ b/src/pip/_internal/operations/build/wheel_legacy.py @@ -2,9 +2,7 @@ import os.path from pip._internal.cli.spinners import open_spinner -from pip._internal.utils.setuptools_build import ( - make_setuptools_bdist_wheel_args, -) +from pip._internal.utils.setuptools_build import make_setuptools_bdist_wheel_args from pip._internal.utils.subprocess import ( LOG_DIVIDER, call_subprocess, @@ -25,16 +23,16 @@ def format_command_result( # type: (...) -> str """Format command information for logging.""" command_desc = format_command_args(command_args) - text = 'Command arguments: {}\n'.format(command_desc) + text = "Command arguments: {}\n".format(command_desc) if not command_output: - text += 'Command output: None' + text += "Command output: None" elif logger.getEffectiveLevel() > logging.DEBUG: - text += 'Command output: [use --verbose to show]' + text += "Command output: [use --verbose to show]" else: - if not command_output.endswith('\n'): - command_output += '\n' - text += 'Command output:\n{}{}'.format(command_output, LOG_DIVIDER) + if not command_output.endswith("\n"): + command_output += "\n" + text += "Command output:\n{}{}".format(command_output, LOG_DIVIDER) return text @@ -51,17 +49,15 @@ def get_legacy_build_wheel_path( # Sort for determinism. names = sorted(names) if not names: - msg = ( - 'Legacy build of wheel for {!r} created no files.\n' - ).format(name) + msg = ("Legacy build of wheel for {!r} created no files.\n").format(name) msg += format_command_result(command_args, command_output) logger.warning(msg) return None if len(names) > 1: msg = ( - 'Legacy build of wheel for {!r} created more than one file.\n' - 'Filenames (choosing first): {}\n' + "Legacy build of wheel for {!r} created more than one file.\n" + "Filenames (choosing first): {}\n" ).format(name, names) msg += format_command_result(command_args, command_output) logger.warning(msg) @@ -89,9 +85,9 @@ def build_wheel_legacy( destination_dir=tempd, ) - spin_message = 'Building wheel for {} (setup.py)'.format(name) + spin_message = "Building wheel for {} (setup.py)".format(name) with open_spinner(spin_message) as spinner: - logger.debug('Destination directory: %s', tempd) + logger.debug("Destination directory: %s", tempd) try: output = call_subprocess( @@ -101,7 +97,7 @@ def build_wheel_legacy( ) except Exception: spinner.finish("error") - logger.error('Failed building wheel for %s', name) + logger.error("Failed building wheel for %s", name) return None names = os.listdir(tempd) diff --git a/src/pip/_internal/operations/check.py b/src/pip/_internal/operations/check.py index 52e8116e199..5e4eb674c92 100644 --- a/src/pip/_internal/operations/check.py +++ b/src/pip/_internal/operations/check.py @@ -7,9 +7,7 @@ from pip._vendor.packaging.utils import canonicalize_name from pip._vendor.pkg_resources import RequirementParseError -from pip._internal.distributions import ( - make_distribution_for_install_requirement, -) +from pip._internal.distributions import make_distribution_for_install_requirement from pip._internal.utils.misc import get_installed_distributions from pip._internal.utils.typing import MYPY_CHECK_RUNNING @@ -21,7 +19,7 @@ from pip._internal.req.req_install import InstallRequirement # Shorthands - PackageSet = Dict[str, 'PackageDetails'] + PackageSet = Dict[str, "PackageDetails"] Missing = Tuple[str, Any] Conflicting = Tuple[str, str, Any] @@ -30,13 +28,12 @@ CheckResult = Tuple[MissingDict, ConflictingDict] ConflictDetails = Tuple[PackageSet, CheckResult] -PackageDetails = namedtuple('PackageDetails', ['version', 'requires']) +PackageDetails = namedtuple("PackageDetails", ["version", "requires"]) def create_package_set_from_installed(**kwargs): # type: (**Any) -> Tuple[PackageSet, bool] - """Converts a list of distributions into a PackageSet. - """ + """Converts a list of distributions into a PackageSet.""" # Default to using all packages installed on the system if kwargs == {}: kwargs = {"local_only": False, "skip": ()} @@ -115,14 +112,13 @@ def check_install_conflicts(to_install): package_set, check_package_set( package_set, should_ignore=lambda name: name not in whitelist - ) + ), ) def _simulate_installation_of(to_install, package_set): # type: (List[InstallRequirement], PackageSet) -> Set[str] - """Computes the version of packages after installing to_install. - """ + """Computes the version of packages after installing to_install.""" # Keep track of packages that were installed installed = set() diff --git a/src/pip/_internal/operations/freeze.py b/src/pip/_internal/operations/freeze.py index b98b8cd79b5..b9088367dc1 100644 --- a/src/pip/_internal/operations/freeze.py +++ b/src/pip/_internal/operations/freeze.py @@ -18,10 +18,7 @@ direct_url_as_pep440_direct_reference, dist_get_direct_url, ) -from pip._internal.utils.misc import ( - dist_is_editable, - get_installed_distributions, -) +from pip._internal.utils.misc import dist_is_editable, get_installed_distributions from pip._internal.utils.typing import MYPY_CHECK_RUNNING if MYPY_CHECK_RUNNING: @@ -56,20 +53,17 @@ def freeze( isolated=False, # type: bool wheel_cache=None, # type: Optional[WheelCache] exclude_editable=False, # type: bool - skip=() # type: Container[str] + skip=(), # type: Container[str] ): # type: (...) -> Iterator[str] find_links = find_links or [] for link in find_links: - yield '-f {}'.format(link) + yield "-f {}".format(link) installations = {} # type: Dict[str, FrozenRequirement] for dist in get_installed_distributions( - local_only=local_only, - skip=(), - user_only=user_only, - paths=paths + local_only=local_only, skip=(), user_only=user_only, paths=paths ): try: req = FrozenRequirement.from_dist(dist) @@ -79,8 +73,7 @@ def freeze( # location. We also include the exception message to aid # troubleshooting. logger.warning( - 'Could not generate requirement for distribution %r: %s', - dist, exc + "Could not generate requirement for distribution %r: %s", dist, exc ) continue if exclude_editable and req.editable: @@ -99,35 +92,43 @@ def freeze( for req_file_path in requirement: with open(req_file_path) as req_file: for line in req_file: - if (not line.strip() or - line.strip().startswith('#') or - line.startswith(( - '-r', '--requirement', - '-f', '--find-links', - '-i', '--index-url', - '--pre', - '--trusted-host', - '--process-dependency-links', - '--extra-index-url', - '--use-feature'))): + if ( + not line.strip() + or line.strip().startswith("#") + or line.startswith( + ( + "-r", + "--requirement", + "-f", + "--find-links", + "-i", + "--index-url", + "--pre", + "--trusted-host", + "--process-dependency-links", + "--extra-index-url", + "--use-feature", + ) + ) + ): line = line.rstrip() if line not in emitted_options: emitted_options.add(line) yield line continue - if line.startswith('-e') or line.startswith('--editable'): - if line.startswith('-e'): + if line.startswith("-e") or line.startswith("--editable"): + if line.startswith("-e"): line = line[2:].strip() else: - line = line[len('--editable'):].strip().lstrip('=') + line = line[len("--editable") :].strip().lstrip("=") line_req = install_req_from_editable( line, isolated=isolated, ) else: line_req = install_req_from_line( - COMMENT_RE.sub('', line).strip(), + COMMENT_RE.sub("", line).strip(), isolated=isolated, ) @@ -135,15 +136,15 @@ def freeze( logger.info( "Skipping line in requirement file [%s] because " "it's not clear what it would install: %s", - req_file_path, line.strip(), + req_file_path, + line.strip(), ) logger.info( " (add #egg=PackageName to the URL to avoid" " this warning)" ) else: - line_req_canonical_name = canonicalize_name( - line_req.name) + line_req_canonical_name = canonicalize_name(line_req.name) if line_req_canonical_name not in installations: # either it's not installed, or it is installed # but has been processed already @@ -152,14 +153,13 @@ def freeze( "Requirement file [%s] contains %s, but " "package %r is not installed", req_file_path, - COMMENT_RE.sub('', line).strip(), - line_req.name + COMMENT_RE.sub("", line).strip(), + line_req.name, ) else: req_files[line_req.name].append(req_file_path) else: - yield str(installations[ - line_req_canonical_name]).rstrip() + yield str(installations[line_req_canonical_name]).rstrip() del installations[line_req_canonical_name] req_files[line_req.name].append(req_file_path) @@ -167,15 +167,14 @@ def freeze( # single requirements file or in different requirements files). for name, files in six.iteritems(req_files): if len(files) > 1: - logger.warning("Requirement %s included multiple times [%s]", - name, ', '.join(sorted(set(files)))) + logger.warning( + "Requirement %s included multiple times [%s]", + name, + ", ".join(sorted(set(files))), + ) - yield( - '## The following requirements were added by ' - 'pip freeze:' - ) - for installation in sorted( - installations.values(), key=lambda x: x.name.lower()): + yield ("## The following requirements were added by " "pip freeze:") + for installation in sorted(installations.values(), key=lambda x: x.name.lower()): if installation.canonical_name not in skip: yield str(installation).rstrip() @@ -192,17 +191,17 @@ def get_requirement_info(dist): location = os.path.normcase(os.path.abspath(dist.location)) from pip._internal.vcs import RemoteNotFoundError, vcs + vcs_backend = vcs.get_backend_for_dir(location) if vcs_backend is None: req = dist.as_requirement() logger.debug( - 'No VCS found for editable requirement "%s" in: %r', req, + 'No VCS found for editable requirement "%s" in: %r', + req, location, ) - comments = [ - '# Editable install with no version control ({})'.format(req) - ] + comments = ["# Editable install with no version control ({})".format(req)] return (location, True, comments) try: @@ -210,16 +209,17 @@ def get_requirement_info(dist): except RemoteNotFoundError: req = dist.as_requirement() comments = [ - '# Editable {} install with no remote ({})'.format( - type(vcs_backend).__name__, req, + "# Editable {} install with no remote ({})".format( + type(vcs_backend).__name__, + req, ) ] return (location, True, comments) except BadCommand: logger.warning( - 'cannot determine version of editable source in %s ' - '(%s command not found in path)', + "cannot determine version of editable source in %s " + "(%s command not found in path)", location, vcs_backend.name, ) @@ -228,16 +228,15 @@ def get_requirement_info(dist): except InstallationError as exc: logger.warning( "Error when trying to get requirement for VCS system %s, " - "falling back to uneditable format", exc + "falling back to uneditable format", + exc, ) else: if req is not None: return (req, True, []) - logger.warning( - 'Could not determine repository location of %s', location - ) - comments = ['## !! Could not determine repository location'] + logger.warning("Could not determine repository location of %s", location) + comments = ["## !! Could not determine repository location"] return (None, False, comments) @@ -276,5 +275,5 @@ def __str__(self): # type: () -> str req = self.req if self.editable: - req = '-e {}'.format(req) - return '\n'.join(list(self.comments) + [str(req)]) + '\n' + req = "-e {}".format(req) + return "\n".join(list(self.comments) + [str(req)]) + "\n" diff --git a/src/pip/_internal/operations/install/editable_legacy.py b/src/pip/_internal/operations/install/editable_legacy.py index a668a61dc60..0990382d4ce 100644 --- a/src/pip/_internal/operations/install/editable_legacy.py +++ b/src/pip/_internal/operations/install/editable_legacy.py @@ -32,7 +32,7 @@ def install_editable( """Install a package in editable mode. Most arguments are pass-through to setuptools. """ - logger.info('Running setup.py develop for %s', name) + logger.info("Running setup.py develop for %s", name) args = make_setuptools_develop_args( setup_py_path, diff --git a/src/pip/_internal/operations/install/legacy.py b/src/pip/_internal/operations/install/legacy.py index 87227d5fed6..0dc16615ac4 100644 --- a/src/pip/_internal/operations/install/legacy.py +++ b/src/pip/_internal/operations/install/legacy.py @@ -52,7 +52,7 @@ def install( with TempDirectory(kind="record") as temp_dir: try: - record_filename = os.path.join(temp_dir.path, 'install-record.txt') + record_filename = os.path.join(temp_dir.path, "install-record.txt") install_args = make_setuptools_install_args( setup_py_path, global_options=global_options, @@ -77,7 +77,7 @@ def install( ) if not os.path.exists(record_filename): - logger.debug('Record file %s not found', record_filename) + logger.debug("Record file %s not found", record_filename) # Signal to the caller that we didn't install the new package return False @@ -102,7 +102,7 @@ def prepend_root(path): for line in record_lines: directory = os.path.dirname(line) - if directory.endswith('.egg-info'): + if directory.endswith(".egg-info"): egg_info_dir = prepend_root(directory) break else: @@ -118,13 +118,11 @@ def prepend_root(path): filename = line.strip() if os.path.isdir(filename): filename += os.path.sep - new_lines.append( - os.path.relpath(prepend_root(filename), egg_info_dir) - ) + new_lines.append(os.path.relpath(prepend_root(filename), egg_info_dir)) new_lines.sort() ensure_dir(egg_info_dir) - inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') - with open(inst_files_path, 'w') as f: - f.write('\n'.join(new_lines) + '\n') + inst_files_path = os.path.join(egg_info_dir, "installed-files.txt") + with open(inst_files_path, "w") as f: + f.write("\n".join(new_lines) + "\n") return True diff --git a/src/pip/_internal/operations/install/wheel.py b/src/pip/_internal/operations/install/wheel.py index af6b39052d9..c9f5967f70f 100644 --- a/src/pip/_internal/operations/install/wheel.py +++ b/src/pip/_internal/operations/install/wheel.py @@ -21,14 +21,7 @@ from pip._vendor import pkg_resources from pip._vendor.distlib.scripts import ScriptMaker from pip._vendor.distlib.util import get_export_entry -from pip._vendor.six import ( - PY2, - ensure_str, - ensure_text, - itervalues, - reraise, - text_type, -) +from pip._vendor.six import PY2, ensure_str, ensure_text, itervalues, reraise, text_type from pip._vendor.six.moves import filterfalse, map from pip._internal.exceptions import InstallationError @@ -36,12 +29,7 @@ from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl from pip._internal.models.scheme import SCHEME_KEYS from pip._internal.utils.filesystem import adjacent_tmp_file, replace -from pip._internal.utils.misc import ( - captured_stdout, - ensure_dir, - hash_file, - partition, -) +from pip._internal.utils.misc import captured_stdout, ensure_dir, hash_file, partition from pip._internal.utils.typing import MYPY_CHECK_RUNNING from pip._internal.utils.unpacking import ( current_umask, @@ -49,10 +37,7 @@ set_extracted_file_to_default_mode_plus_executable, zip_item_is_executable, ) -from pip._internal.utils.wheel import ( - parse_wheel, - pkg_resources_distribution_for_wheel, -) +from pip._internal.utils.wheel import parse_wheel, pkg_resources_distribution_for_wheel # Use the custom cast function at runtime to make cast work, # and import typing.cast when performing pre-commit and type @@ -85,7 +70,7 @@ from pip._internal.models.scheme import Scheme from pip._internal.utils.filesystem import NamedTemporaryFileResult - RecordPath = NewType('RecordPath', text_type) + RecordPath = NewType("RecordPath", text_type) InstalledCSVRow = Tuple[RecordPath, str, Union[int, str]] class File(Protocol): @@ -105,9 +90,7 @@ def rehash(path, blocksize=1 << 20): # type: (text_type, int) -> Tuple[str, str] """Return (encoded_digest, length) for path using hashlib.sha256()""" h, length = hash_file(path, blocksize) - digest = 'sha256=' + urlsafe_b64encode( - h.digest() - ).decode('latin1').rstrip('=') + digest = "sha256=" + urlsafe_b64encode(h.digest()).decode("latin1").rstrip("=") # unicode/str python2 issues return (digest, str(length)) # type: ignore @@ -118,9 +101,9 @@ def csv_io_kwargs(mode): in the given mode. """ if PY2: - return {'mode': '{}b'.format(mode)} + return {"mode": "{}b".format(mode)} else: - return {'mode': mode, 'newline': '', 'encoding': 'utf-8'} + return {"mode": mode, "newline": "", "encoding": "utf-8"} def fix_script(path): @@ -131,14 +114,14 @@ def fix_script(path): # XXX RECORD hashes will need to be updated assert os.path.isfile(path) - with open(path, 'rb') as script: + with open(path, "rb") as script: firstline = script.readline() - if not firstline.startswith(b'#!python'): + if not firstline.startswith(b"#!python"): return False exename = sys.executable.encode(sys.getfilesystemencoding()) - firstline = b'#!' + exename + os.linesep.encode("ascii") + firstline = b"#!" + exename + os.linesep.encode("ascii") rest = script.read() - with open(path, 'wb') as script: + with open(path, "wb") as script: script.write(firstline) script.write(rest) return True @@ -153,8 +136,8 @@ def get_entrypoints(distribution): # type: (Distribution) -> Tuple[Dict[str, str], Dict[str, str]] # get the entry points and then the script names try: - console = distribution.get_entry_map('console_scripts') - gui = distribution.get_entry_map('gui_scripts') + console = distribution.get_entry_map("console_scripts") + gui = distribution.get_entry_map("gui_scripts") except KeyError: # Our dict-based Distribution raises KeyError if entry_points.txt # doesn't exist. @@ -192,14 +175,15 @@ def message_about_scripts_not_on_PATH(scripts): # We don't want to warn for directories that are on PATH. not_warn_dirs = [ - os.path.normcase(i).rstrip(os.sep) for i in - os.environ.get("PATH", "").split(os.pathsep) + os.path.normcase(i).rstrip(os.sep) + for i in os.environ.get("PATH", "").split(os.pathsep) ] # If an executable sits with sys.executable, we don't warn for it. # This covers the case of venv invocations without activating the venv. not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable))) warn_for = { - parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items() + parent_dir: scripts + for parent_dir, scripts in grouped_by_dir.items() if os.path.normcase(parent_dir) not in not_warn_dirs } # type: Dict[str, Set[str]] if not warn_for: @@ -217,8 +201,9 @@ def message_about_scripts_not_on_PATH(scripts): ) msg_lines.append( - "The {} installed in '{}' which is not on PATH." - .format(start_text, parent_dir) + "The {} installed in '{}' which is not on PATH.".format( + start_text, parent_dir + ) ) last_line_fmt = ( @@ -266,7 +251,7 @@ def _normalized_outrows(outrows): # For additional background, see-- # https://github.com/pypa/pip/issues/5868 return sorted( - (ensure_str(record_path, encoding='utf-8'), hash_, str(size)) + (ensure_str(record_path, encoding="utf-8"), hash_, str(size)) for record_path, hash_, size in outrows ) @@ -281,17 +266,19 @@ def _fs_to_record_path(path, relative_to=None): if relative_to is not None: # On Windows, do not handle relative paths if they belong to different # logical disks - if os.path.splitdrive(path)[0].lower() == \ - os.path.splitdrive(relative_to)[0].lower(): + if ( + os.path.splitdrive(path)[0].lower() + == os.path.splitdrive(relative_to)[0].lower() + ): path = os.path.relpath(path, relative_to) - path = path.replace(os.path.sep, '/') - return cast('RecordPath', path) + path = path.replace(os.path.sep, "/") + return cast("RecordPath", path) def _parse_record_path(record_column): # type: (str) -> RecordPath - p = ensure_text(record_column, encoding='utf-8') - return cast('RecordPath', p) + p = ensure_text(record_column, encoding="utf-8") + return cast("RecordPath", p) def get_csv_rows_for_installed( @@ -309,21 +296,21 @@ def get_csv_rows_for_installed( installed_rows = [] # type: List[InstalledCSVRow] for row in old_csv_rows: if len(row) > 3: - logger.warning('RECORD line has more than three elements: %s', row) + logger.warning("RECORD line has more than three elements: %s", row) old_record_path = _parse_record_path(row[0]) new_record_path = installed.pop(old_record_path, old_record_path) if new_record_path in changed: digest, length = rehash(_record_to_fs_path(new_record_path)) else: - digest = row[1] if len(row) > 1 else '' - length = row[2] if len(row) > 2 else '' + digest = row[1] if len(row) > 1 else "" + length = row[2] if len(row) > 2 else "" installed_rows.append((new_record_path, digest, length)) for f in generated: path = _fs_to_record_path(f, lib_dir) digest, length = rehash(f) installed_rows.append((path, digest, length)) for installed_record_path in itervalues(installed): - installed_rows.append((installed_record_path, '', '')) + installed_rows.append((installed_record_path, "", "")) return installed_rows @@ -371,44 +358,42 @@ def get_console_script_specs(console): # DEFAULT # - The default behavior is to install pip, pipX, pipX.Y, easy_install # and easy_install-X.Y. - pip_script = console.pop('pip', None) + pip_script = console.pop("pip", None) if pip_script: if "ENSUREPIP_OPTIONS" not in os.environ: - scripts_to_generate.append('pip = ' + pip_script) + scripts_to_generate.append("pip = " + pip_script) if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": scripts_to_generate.append( - 'pip{} = {}'.format(sys.version_info[0], pip_script) + "pip{} = {}".format(sys.version_info[0], pip_script) ) scripts_to_generate.append( - 'pip{} = {}'.format(get_major_minor_version(), pip_script) + "pip{} = {}".format(get_major_minor_version(), pip_script) ) # Delete any other versioned pip entry points - pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)] + pip_ep = [k for k in console if re.match(r"pip(\d(\.\d)?)?$", k)] for k in pip_ep: del console[k] - easy_install_script = console.pop('easy_install', None) + easy_install_script = console.pop("easy_install", None) if easy_install_script: if "ENSUREPIP_OPTIONS" not in os.environ: - scripts_to_generate.append( - 'easy_install = ' + easy_install_script - ) + scripts_to_generate.append("easy_install = " + easy_install_script) scripts_to_generate.append( - 'easy_install-{} = {}'.format( + "easy_install-{} = {}".format( get_major_minor_version(), easy_install_script ) ) # Delete any other versioned easy_install entry points easy_install_ep = [ - k for k in console if re.match(r'easy_install(-\d\.\d)?$', k) + k for k in console if re.match(r"easy_install(-\d\.\d)?$", k) ] for k in easy_install_ep: del console[k] # Generate the console entry points specified in the wheel - scripts_to_generate.extend(starmap('{} = {}'.format, console.items())) + scripts_to_generate.extend(starmap("{} = {}".format, console.items())) return scripts_to_generate @@ -611,9 +596,7 @@ def make_data_scheme_file(record_path): "Unknown scheme key used in {}: {} (for file {!r}). .data" " directory contents should be in subdirectories named" " with a valid scheme key ({})" - ).format( - wheel_path, scheme_key, record_path, valid_scheme_keys - ) + ).format(wheel_path, scheme_key, record_path, valid_scheme_keys) raise InstallationError(message) dest_path = os.path.join(scheme_path, dest_subpath) @@ -628,9 +611,7 @@ def is_data_scheme_path(path): paths = all_paths() file_paths = filterfalse(is_dir_path, paths) - root_scheme_paths, data_scheme_paths = partition( - is_data_scheme_path, file_paths - ) + root_scheme_paths, data_scheme_paths = partition(is_data_scheme_path, file_paths) make_root_scheme_file = root_scheme_file_maker( wheel_zip, @@ -641,11 +622,7 @@ def is_data_scheme_path(path): def is_script_scheme_path(path): # type: (RecordPath) -> bool parts = path.split("/", 2) - return ( - len(parts) > 2 and - parts[0].endswith(".data") and - parts[1] == "scripts" - ) + return len(parts) > 2 and parts[0].endswith(".data") and parts[1] == "scripts" other_scheme_paths, script_scheme_paths = partition( is_script_scheme_path, data_scheme_paths @@ -656,9 +633,7 @@ def is_script_scheme_path(path): files = chain(files, other_scheme_files) # Get the defined entry points - distribution = pkg_resources_distribution_for_wheel( - wheel_zip, name, wheel_path - ) + distribution = pkg_resources_distribution_for_wheel(wheel_zip, name, wheel_path) console, gui = get_entrypoints(distribution) def is_entrypoint_wrapper(file): @@ -667,21 +642,19 @@ def is_entrypoint_wrapper(file): # entry point EP by setuptools path = file.dest_path name = os.path.basename(path) - if name.lower().endswith('.exe'): + if name.lower().endswith(".exe"): matchname = name[:-4] - elif name.lower().endswith('-script.py'): + elif name.lower().endswith("-script.py"): matchname = name[:-10] elif name.lower().endswith(".pya"): matchname = name[:-4] else: matchname = name # Ignore setuptools-generated scripts - return (matchname in console or matchname in gui) + return matchname in console or matchname in gui script_scheme_files = map(make_data_scheme_file, script_scheme_paths) - script_scheme_files = filterfalse( - is_entrypoint_wrapper, script_scheme_files - ) + script_scheme_files = filterfalse(is_entrypoint_wrapper, script_scheme_files) script_scheme_files = map(ScriptFile, script_scheme_files) files = chain(files, script_scheme_files) @@ -699,19 +672,18 @@ def pyc_source_file_paths(): full_installed_path = os.path.join(lib_dir, installed_path) if not os.path.isfile(full_installed_path): continue - if not full_installed_path.endswith('.py'): + if not full_installed_path.endswith(".py"): continue yield full_installed_path def pyc_output_path(path): # type: (text_type) -> text_type - """Return the path the pyc file would have been written to. - """ + """Return the path the pyc file would have been written to.""" if PY2: if sys.flags.optimize: - return path + 'o' + return path + "o" else: - return path + 'c' + return path + "c" else: return importlib.util.cache_from_source(path) @@ -719,16 +691,12 @@ def pyc_output_path(path): if pycompile: with captured_stdout() as stdout: with warnings.catch_warnings(): - warnings.filterwarnings('ignore') + warnings.filterwarnings("ignore") for path in pyc_source_file_paths(): # Python 2's `compileall.compile_file` requires a str in # error cases, so we must convert to the native type. - path_arg = ensure_str( - path, encoding=sys.getfilesystemencoding() - ) - success = compileall.compile_file( - path_arg, force=True, quiet=True - ) + path_arg = ensure_str(path, encoding=sys.getfilesystemencoding()) + success = compileall.compile_file(path_arg, force=True, quiet=True) if success: pyc_path = pyc_output_path(path) assert os.path.exists(pyc_path) @@ -747,7 +715,7 @@ def pyc_output_path(path): # Ensure we don't generate any variants for scripts because this is almost # never what somebody wants. # See https://bitbucket.org/pypa/distlib/issue/35/ - maker.variants = {''} + maker.variants = {""} # This is required because otherwise distlib creates scripts that are not # executable. @@ -757,14 +725,12 @@ def pyc_output_path(path): # Generate the console and GUI entry points specified in the wheel scripts_to_generate = get_console_script_specs(console) - gui_scripts_to_generate = list(starmap('{} = {}'.format, gui.items())) + gui_scripts_to_generate = list(starmap("{} = {}".format, gui.items())) generated_console_scripts = maker.make_multiple(scripts_to_generate) generated.extend(generated_console_scripts) - generated.extend( - maker.make_multiple(gui_scripts_to_generate, {'gui': True}) - ) + generated.extend(maker.make_multiple(gui_scripts_to_generate, {"gui": True})) if warn_script_location: msg = message_about_scripts_not_on_PATH(generated_console_scripts) @@ -784,9 +750,9 @@ def _generate_file(path, **kwargs): dest_info_dir = os.path.join(lib_dir, info_dir) # Record pip as the installer - installer_path = os.path.join(dest_info_dir, 'INSTALLER') + installer_path = os.path.join(dest_info_dir, "INSTALLER") with _generate_file(installer_path) as installer_file: - installer_file.write(b'pip\n') + installer_file.write(b"pip\n") generated.append(installer_path) # Record the PEP 610 direct URL reference @@ -798,12 +764,12 @@ def _generate_file(path, **kwargs): # Record the REQUESTED file if requested: - requested_path = os.path.join(dest_info_dir, 'REQUESTED') + requested_path = os.path.join(dest_info_dir, "REQUESTED") with open(requested_path, "w"): pass generated.append(requested_path) - record_text = distribution.get_metadata('RECORD') + record_text = distribution.get_metadata("RECORD") record_rows = list(csv.reader(record_text.splitlines())) rows = get_csv_rows_for_installed( @@ -811,16 +777,17 @@ def _generate_file(path, **kwargs): installed=installed, changed=changed, generated=generated, - lib_dir=lib_dir) + lib_dir=lib_dir, + ) # Record details of all files installed - record_path = os.path.join(dest_info_dir, 'RECORD') + record_path = os.path.join(dest_info_dir, "RECORD") - with _generate_file(record_path, **csv_io_kwargs('w')) as record_file: + with _generate_file(record_path, **csv_io_kwargs("w")) as record_file: # The type mypy infers for record_file is different for Python 3 # (typing.IO[Any]) and Python 2 (typing.BinaryIO). We explicitly # cast to typing.IO[str] as a workaround. - writer = csv.writer(cast('IO[str]', record_file)) + writer = csv.writer(cast("IO[str]", record_file)) writer.writerows(_normalized_outrows(rows)) @@ -831,9 +798,7 @@ def req_error_context(req_description): yield except InstallationError as e: message = "For req: {}. {}".format(req_description, e.args[0]) - reraise( - InstallationError, InstallationError(message), sys.exc_info()[2] - ) + reraise(InstallationError, InstallationError(message), sys.exc_info()[2]) def install_wheel( diff --git a/src/pip/_internal/operations/prepare.py b/src/pip/_internal/operations/prepare.py index acff7ffa1f7..7b5fb11fd01 100644 --- a/src/pip/_internal/operations/prepare.py +++ b/src/pip/_internal/operations/prepare.py @@ -12,9 +12,7 @@ from pip._vendor.packaging.utils import canonicalize_name from pip._vendor.six import PY2 -from pip._internal.distributions import ( - make_distribution_for_install_requirement, -) +from pip._internal.distributions import make_distribution_for_install_requirement from pip._internal.distributions.installed import InstalledDistribution from pip._internal.exceptions import ( DirectoryUrlHashUnsupported, @@ -34,12 +32,7 @@ from pip._internal.utils.filesystem import copy2_fixed from pip._internal.utils.hashes import MissingHashes from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ( - display_path, - hide_url, - path_to_display, - rmtree, -) +from pip._internal.utils.misc import display_path, hide_url, path_to_display, rmtree from pip._internal.utils.temp_dir import TempDirectory from pip._internal.utils.typing import MYPY_CHECK_RUNNING from pip._internal.utils.unpacking import unpack_file @@ -60,21 +53,21 @@ if PY2: CopytreeKwargs = TypedDict( - 'CopytreeKwargs', + "CopytreeKwargs", { - 'ignore': Callable[[str, List[str]], List[str]], - 'symlinks': bool, + "ignore": Callable[[str, List[str]], List[str]], + "symlinks": bool, }, total=False, ) else: CopytreeKwargs = TypedDict( - 'CopytreeKwargs', + "CopytreeKwargs", { - 'copy_function': Callable[[str, str], None], - 'ignore': Callable[[str, List[str]], List[str]], - 'ignore_dangling_symlinks': bool, - 'symlinks': bool, + "copy_function": Callable[[str, str], None], + "ignore": Callable[[str, List[str]], List[str]], + "ignore_dangling_symlinks": bool, + "symlinks": bool, }, total=False, ) @@ -104,7 +97,6 @@ def unpack_vcs_link(link, location): class File(object): - def __init__(self, path, content_type): # type: (str, Optional[str]) -> None self.path = path @@ -125,9 +117,7 @@ def get_http_url( # If a download dir is specified, is the file already downloaded there? already_downloaded_path = None if download_dir: - already_downloaded_path = _check_download_dir( - link, download_dir, hashes - ) + already_downloaded_path = _check_download_dir(link, download_dir, hashes) if already_downloaded_path: from_path = already_downloaded_path @@ -176,7 +166,7 @@ def ignore(d, names): # exclude the following directories if they appear in the top # level dir (and only it). # See discussion at https://github.com/pypa/pip/pull/6770 - skipped += ['.tox', '.nox'] + skipped += [".tox", ".nox"] if os.path.abspath(d) == target_dirname: # Prevent an infinite recursion if the target is in source. # This can happen when TMPDIR is set to ${PWD}/... @@ -189,7 +179,7 @@ def ignore(d, names): if not PY2: # Python 2 does not support copy_function, so we only ignore # errors on special file copy in Python 3. - kwargs['copy_function'] = _copy2_ignoring_special_files + kwargs["copy_function"] = _copy2_ignoring_special_files shutil.copytree(source, target, **kwargs) @@ -197,17 +187,14 @@ def ignore(d, names): def get_file_url( link, # type: Link download_dir=None, # type: Optional[str] - hashes=None # type: Optional[Hashes] + hashes=None, # type: Optional[Hashes] ): # type: (...) -> File - """Get file and optionally check its hash. - """ + """Get file and optionally check its hash.""" # If a download dir is specified, is the file already there and valid? already_downloaded_path = None if download_dir: - already_downloaded_path = _check_download_dir( - link, download_dir, hashes - ) + already_downloaded_path = _check_download_dir(link, download_dir, hashes) if already_downloaded_path: from_path = already_downloaded_path @@ -274,8 +261,8 @@ def unpack_url( def _check_download_dir(link, download_dir, hashes): # type: (Link, str, Optional[Hashes]) -> Optional[str] - """ Check download_dir for previously downloaded file with correct hash - If a correct file is found return its path else None + """Check download_dir for previously downloaded file with correct hash + If a correct file is found return its path else None """ download_path = os.path.join(download_dir, link.filename) @@ -283,15 +270,14 @@ def _check_download_dir(link, download_dir, hashes): return None # If already downloaded, does its hash match? - logger.info('File was already downloaded %s', download_path) + logger.info("File was already downloaded %s", download_path) if hashes: try: hashes.check_against_path(download_path) except HashMismatch: logger.warning( - 'Previously-downloaded file %s has bad hash. ' - 'Re-downloading.', - download_path + "Previously-downloaded file %s has bad hash. " "Re-downloading.", + download_path, ) os.unlink(download_path) return None @@ -299,8 +285,7 @@ def _check_download_dir(link, download_dir, hashes): class RequirementPreparer(object): - """Prepares a Requirement - """ + """Prepares a Requirement""" def __init__( self, @@ -369,10 +354,10 @@ def _download_should_save(self): if os.path.exists(self.download_dir): return True - logger.critical('Could not find download directory') + logger.critical("Could not find download directory") raise InstallationError( - "Could not find or access download directory '{}'" - .format(self.download_dir)) + "Could not find or access download directory '{}'".format(self.download_dir) + ) def _log_preparing_link(self, req): # type: (InstallRequirement) -> None @@ -420,7 +405,7 @@ def _ensure_link_req_src_dir(self, req, download_dir, parallel_builds): # installation. # FIXME: this won't upgrade when there's an existing # package unpacked in `req.source_dir` - if os.path.exists(os.path.join(req.source_dir, 'setup.py')): + if os.path.exists(os.path.join(req.source_dir, "setup.py")): raise PreviousBuildDirError( "pip can't proceed with requirements '{}' due to a" "pre-existing build directory ({}). This is likely " @@ -468,12 +453,11 @@ def _fetch_metadata_using_lazy_wheel(self, link): if not self.use_lazy_wheel: return None if self.require_hashes: - logger.debug('Lazy wheel is not used as hash checking is required') + logger.debug("Lazy wheel is not used as hash checking is required") return None if link.is_file or not link.is_wheel: logger.debug( - 'Lazy wheel is not used as ' - '%r does not points to a remote wheel', + "Lazy wheel is not used as " "%r does not points to a remote wheel", link, ) return None @@ -481,14 +465,15 @@ def _fetch_metadata_using_lazy_wheel(self, link): wheel = Wheel(link.filename) name = canonicalize_name(wheel.name) logger.info( - 'Obtaining dependency information from %s %s', - name, wheel.version, + "Obtaining dependency information from %s %s", + name, + wheel.version, ) - url = link.url.split('#', 1)[0] + url = link.url.split("#", 1)[0] try: return dist_from_wheel_url(name, url, self._session) except HTTPRangeRequestUnsupported: - logger.debug('%s does not support range requests', url) + logger.debug("%s does not support range requests", url) return None def prepare_linked_requirement(self, req, parallel_builds=False): @@ -536,13 +521,16 @@ def _prepare_linked_requirement(self, req, parallel_builds): if link.url not in self._downloaded: try: local_file = unpack_url( - link, req.source_dir, self._download, - download_dir, hashes, + link, + req.source_dir, + self._download, + download_dir, + hashes, ) except NetworkConnectionError as exc: raise InstallationError( - 'Could not install requirement {} because of HTTP ' - 'error {} for URL {}'.format(req, exc, link) + "Could not install requirement {} because of HTTP " + "error {} for URL {}".format(req, exc, link) ) else: file_path, content_type = self._downloaded[link.url] @@ -556,18 +544,21 @@ def _prepare_linked_requirement(self, req, parallel_builds): req.local_file_path = local_file.path dist = _get_prepared_distribution( - req, self.req_tracker, self.finder, self.build_isolation, + req, + self.req_tracker, + self.finder, + self.build_isolation, ) if download_dir: if link.is_existing_dir(): - logger.info('Link is a directory, ignoring download_dir') + logger.info("Link is a directory, ignoring download_dir") elif local_file: download_location = os.path.join(download_dir, link.filename) if not os.path.exists(download_location): shutil.copy(local_file.path, download_location) download_path = display_path(download_location) - logger.info('Saved %s', download_path) + logger.info("Saved %s", download_path) if self._download_should_save: # Make a .zip of the source_dir we already created. @@ -580,24 +571,26 @@ def prepare_editable_requirement( req, # type: InstallRequirement ): # type: (...) -> Distribution - """Prepare an editable requirement - """ + """Prepare an editable requirement""" assert req.editable, "cannot prepare a non-editable req as editable" - logger.info('Obtaining %s', req) + logger.info("Obtaining %s", req) with indent_log(): if self.require_hashes: raise InstallationError( - 'The editable requirement {} cannot be installed when ' - 'requiring hashes, because there is no single file to ' - 'hash.'.format(req) + "The editable requirement {} cannot be installed when " + "requiring hashes, because there is no single file to " + "hash.".format(req) ) req.ensure_has_source_dir(self.src_dir) req.update_editable(not self._download_should_save) dist = _get_prepared_distribution( - req, self.req_tracker, self.finder, self.build_isolation, + req, + self.req_tracker, + self.finder, + self.build_isolation, ) if self._download_should_save: @@ -609,26 +602,24 @@ def prepare_editable_requirement( def prepare_installed_requirement( self, req, # type: InstallRequirement - skip_reason # type: str + skip_reason, # type: str ): # type: (...) -> Distribution - """Prepare an already-installed requirement - """ + """Prepare an already-installed requirement""" assert req.satisfied_by, "req should have been satisfied but isn't" assert skip_reason is not None, ( "did not get skip reason skipped but req.satisfied_by " "is set to {}".format(req.satisfied_by) ) logger.info( - 'Requirement %s: %s (%s)', - skip_reason, req, req.satisfied_by.version + "Requirement %s: %s (%s)", skip_reason, req, req.satisfied_by.version ) with indent_log(): if self.require_hashes: logger.debug( - 'Since it is already installed, we are trusting this ' - 'package without checking its hash. To ensure a ' - 'completely repeatable environment, install into an ' - 'empty virtualenv.' + "Since it is already installed, we are trusting this " + "package without checking its hash. To ensure a " + "completely repeatable environment, install into an " + "empty virtualenv." ) return InstalledDistribution(req).get_pkg_resources_distribution() diff --git a/src/pip/_internal/pyproject.py b/src/pip/_internal/pyproject.py index 4144a9ed60b..06dd4e86546 100644 --- a/src/pip/_internal/pyproject.py +++ b/src/pip/_internal/pyproject.py @@ -17,15 +17,14 @@ def _is_list_of_str(obj): # type: (Any) -> bool - return ( - isinstance(obj, list) and - all(isinstance(item, six.string_types) for item in obj) + return isinstance(obj, list) and all( + isinstance(item, six.string_types) for item in obj ) def make_pyproject_path(unpacked_source_directory): # type: (str) -> str - path = os.path.join(unpacked_source_directory, 'pyproject.toml') + path = os.path.join(unpacked_source_directory, "pyproject.toml") # Python2 __file__ should not be unicode if six.PY2 and isinstance(path, six.text_type): @@ -34,16 +33,16 @@ def make_pyproject_path(unpacked_source_directory): return path -BuildSystemDetails = namedtuple('BuildSystemDetails', [ - 'requires', 'backend', 'check', 'backend_path' -]) +BuildSystemDetails = namedtuple( + "BuildSystemDetails", ["requires", "backend", "check", "backend_path"] +) def load_pyproject_toml( use_pep517, # type: Optional[bool] pyproject_toml, # type: str setup_py, # type: str - req_name # type: str + req_name, # type: str ): # type: (...) -> Optional[BuildSystemDetails] """Load the pyproject.toml file. @@ -95,9 +94,7 @@ def load_pyproject_toml( raise InstallationError( "Disabling PEP 517 processing is invalid: " "project specifies a build backend of {} " - "in pyproject.toml".format( - build_system["build-backend"] - ) + "in pyproject.toml".format(build_system["build-backend"]) ) use_pep517 = True @@ -145,19 +142,24 @@ def load_pyproject_toml( # Specifying the build-system table but not the requires key is invalid if "requires" not in build_system: raise InstallationError( - error_template.format(package=req_name, reason=( - "it has a 'build-system' table but not " - "'build-system.requires' which is mandatory in the table" - )) + error_template.format( + package=req_name, + reason=( + "it has a 'build-system' table but not " + "'build-system.requires' which is mandatory in the table" + ), + ) ) # Error out if requires is not a list of strings requires = build_system["requires"] if not _is_list_of_str(requires): - raise InstallationError(error_template.format( - package=req_name, - reason="'build-system.requires' is not a list of strings.", - )) + raise InstallationError( + error_template.format( + package=req_name, + reason="'build-system.requires' is not a list of strings.", + ) + ) # Each requirement must be valid as per PEP 508 for requirement in requires: diff --git a/src/pip/_internal/req/__init__.py b/src/pip/_internal/req/__init__.py index 8568d3f8b6e..17127f7785a 100644 --- a/src/pip/_internal/req/__init__.py +++ b/src/pip/_internal/req/__init__.py @@ -14,8 +14,10 @@ from typing import Iterator, List, Optional, Sequence, Tuple __all__ = [ - "RequirementSet", "InstallRequirement", - "parse_requirements", "install_given_reqs", + "RequirementSet", + "InstallRequirement", + "parse_requirements", + "install_given_reqs", ] logger = logging.getLogger(__name__) @@ -61,8 +63,8 @@ def install_given_reqs( if to_install: logger.info( - 'Installing collected packages: %s', - ', '.join(to_install.keys()), + "Installing collected packages: %s", + ", ".join(to_install.keys()), ) installed = [] @@ -70,11 +72,9 @@ def install_given_reqs( with indent_log(): for req_name, requirement in to_install.items(): if requirement.should_reinstall: - logger.info('Attempting uninstall: %s', req_name) + logger.info("Attempting uninstall: %s", req_name) with indent_log(): - uninstalled_pathset = requirement.uninstall( - auto_confirm=True - ) + uninstalled_pathset = requirement.uninstall(auto_confirm=True) else: uninstalled_pathset = None diff --git a/src/pip/_internal/req/constructors.py b/src/pip/_internal/req/constructors.py index 97420af6c25..e1a54a4194e 100644 --- a/src/pip/_internal/req/constructors.py +++ b/src/pip/_internal/req/constructors.py @@ -36,10 +36,7 @@ from pip._internal.req.req_file import ParsedRequirement -__all__ = [ - "install_req_from_editable", "install_req_from_line", - "parse_editable" -] +__all__ = ["install_req_from_editable", "install_req_from_line", "parse_editable"] logger = logging.getLogger(__name__) operators = Specifier._operators.keys() @@ -56,7 +53,7 @@ def is_archive_file(name): def _strip_extras(path): # type: (str) -> Tuple[str, Optional[str]] - m = re.match(r'^(.+)(\[[^\]]+\])$', path) + m = re.match(r"^(.+)(\[[^\]]+\])$", path) extras = None if m: path_no_extras = m.group(1) @@ -92,23 +89,23 @@ def parse_editable(editable_req): url_no_extras, extras = _strip_extras(url) if os.path.isdir(url_no_extras): - if not os.path.exists(os.path.join(url_no_extras, 'setup.py')): + if not os.path.exists(os.path.join(url_no_extras, "setup.py")): msg = ( 'File "setup.py" not found. Directory cannot be installed ' - 'in editable mode: {}'.format(os.path.abspath(url_no_extras)) + "in editable mode: {}".format(os.path.abspath(url_no_extras)) ) pyproject_path = make_pyproject_path(url_no_extras) if os.path.isfile(pyproject_path): msg += ( '\n(A "pyproject.toml" file was found, but editable ' - 'mode currently requires a setup.py based build.)' + "mode currently requires a setup.py based build.)" ) raise InstallationError(msg) # Treating it as code that has already been checked out url_no_extras = path_to_url(url_no_extras) - if url_no_extras.lower().startswith('file:'): + if url_no_extras.lower().startswith("file:"): package_name = Link(url_no_extras).egg_fragment if extras: return ( @@ -120,24 +117,24 @@ def parse_editable(editable_req): return package_name, url_no_extras, set() for version_control in vcs: - if url.lower().startswith('{}:'.format(version_control)): - url = '{}+{}'.format(version_control, url) + if url.lower().startswith("{}:".format(version_control)): + url = "{}+{}".format(version_control, url) break - if '+' not in url: + if "+" not in url: raise InstallationError( - '{} is not a valid editable requirement. ' - 'It should either be a path to a local project or a VCS URL ' - '(beginning with svn+, git+, hg+, or bzr+).'.format(editable_req) + "{} is not a valid editable requirement. " + "It should either be a path to a local project or a VCS URL " + "(beginning with svn+, git+, hg+, or bzr+).".format(editable_req) ) - vc_type = url.split('+', 1)[0].lower() + vc_type = url.split("+", 1)[0].lower() if not vcs.get_backend(vc_type): - backends = ", ".join([bends.name + '+URL' for bends in vcs.backends]) - error_message = "For --editable={}, " \ - "only {} are currently supported".format( - editable_req, backends) + backends = ", ".join([bends.name + "+URL" for bends in vcs.backends]) + error_message = "For --editable={}, " "only {} are currently supported".format( + editable_req, backends + ) raise InstallationError(error_message) package_name = Link(url).egg_fragment @@ -161,7 +158,7 @@ def deduce_helpful_msg(req): msg = " The path does exist. " # Try to parse and check if it is a requirements file. try: - with open(req, 'r') as fp: + with open(req, "r") as fp: # parse first line only next(parse_requirements(fp.read())) msg += ( @@ -172,9 +169,7 @@ def deduce_helpful_msg(req): " the packages specified within it." ).format(req) except RequirementParseError: - logger.debug( - "Cannot parse '%s' as requirements file", req, exc_info=True - ) + logger.debug("Cannot parse '%s' as requirements file", req, exc_info=True) else: msg += " File '{}' does not exist.".format(req) return msg @@ -182,11 +177,11 @@ def deduce_helpful_msg(req): class RequirementParts(object): def __init__( - self, - requirement, # type: Optional[Requirement] - link, # type: Optional[Link] - markers, # type: Optional[Marker] - extras, # type: Set[str] + self, + requirement, # type: Optional[Requirement] + link, # type: Optional[Link] + markers, # type: Optional[Marker] + extras, # type: Set[str] ): self.requirement = requirement self.link = link @@ -284,15 +279,13 @@ def _get_url_from_path(path, name): return None if os.path.isfile(path): return path_to_url(path) - urlreq_parts = name.split('@', 1) + urlreq_parts = name.split("@", 1) if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]): # If the path contains '@' and the part before it does not look # like a path, try to treat it as a PEP 440 URL req instead. return None logger.warning( - 'Requirement %r looks like a filename, but the ' - 'file does not exist', - name + "Requirement %r looks like a filename, but the " "file does not exist", name ) return path_to_url(path) @@ -300,9 +293,9 @@ def _get_url_from_path(path, name): def parse_req_from_line(name, line_source): # type: (str, Optional[str]) -> RequirementParts if is_url(name): - marker_sep = '; ' + marker_sep = "; " else: - marker_sep = ';' + marker_sep = ";" if marker_sep in name: name, markers_as_string = name.split(marker_sep, 1) markers_as_string = markers_as_string.strip() @@ -329,9 +322,8 @@ def parse_req_from_line(name, line_source): # it's a local file, dir, or url if link: # Handle relative file URLs - if link.scheme == 'file' and re.search(r'\.\./', link.url): - link = Link( - path_to_url(os.path.normpath(os.path.abspath(link.path)))) + if link.scheme == "file" and re.search(r"\.\./", link.url): + link = Link(path_to_url(os.path.normpath(os.path.abspath(link.path)))) # wheel file if link.is_wheel: wheel = Wheel(link.filename) # can raise InvalidWheelFilename @@ -351,7 +343,7 @@ def with_source(text): # type: (str) -> str if not line_source: return text - return '{} (from {})'.format(text, line_source) + return "{} (from {})".format(text, line_source) if req_as_string is not None: try: @@ -360,16 +352,15 @@ def with_source(text): if os.path.sep in req_as_string: add_msg = "It looks like a path." add_msg += deduce_helpful_msg(req_as_string) - elif ('=' in req_as_string and - not any(op in req_as_string for op in operators)): + elif "=" in req_as_string and not any( + op in req_as_string for op in operators + ): add_msg = "= is not a valid operator. Did you mean == ?" else: - add_msg = '' - msg = with_source( - 'Invalid requirement: {!r}'.format(req_as_string) - ) + add_msg = "" + msg = with_source("Invalid requirement: {!r}".format(req_as_string)) if add_msg: - msg += '\nHint: {}'.format(add_msg) + msg += "\nHint: {}".format(add_msg) raise InstallationError(msg) else: # Deprecate extras after specifiers: "name>=1.0[extras]" @@ -378,7 +369,7 @@ def with_source(text): # RequirementParts for spec in req.specifier: spec_str = str(spec) - if spec_str.endswith(']'): + if spec_str.endswith("]"): msg = "Extras after version '{}'.".format(spec_str) replace = "moving the extras before version specifiers" deprecated(msg, replacement=replace, gone_in="21.0") @@ -408,8 +399,12 @@ def install_req_from_line( parts = parse_req_from_line(name, line_source) return InstallRequirement( - parts.requirement, comes_from, link=parts.link, markers=parts.markers, - use_pep517=use_pep517, isolated=isolated, + parts.requirement, + comes_from, + link=parts.link, + markers=parts.markers, + use_pep517=use_pep517, + isolated=isolated, install_options=options.get("install_options", []) if options else [], global_options=options.get("global_options", []) if options else [], hash_options=options.get("hashes", {}) if options else {}, @@ -436,8 +431,12 @@ def install_req_from_req_string( PyPI.file_storage_domain, TestPyPI.file_storage_domain, ] - if (req.url and comes_from and comes_from.link and - comes_from.link.netloc in domains_not_allowed): + if ( + req.url + and comes_from + and comes_from.link + and comes_from.link.netloc in domains_not_allowed + ): # Explicitly disallow pypi packages that depend on external urls raise InstallationError( "Packages installed from PyPI cannot depend on packages " diff --git a/src/pip/_internal/req/req_file.py b/src/pip/_internal/req/req_file.py index b070dc640da..512d94b9eb7 100644 --- a/src/pip/_internal/req/req_file.py +++ b/src/pip/_internal/req/req_file.py @@ -13,10 +13,7 @@ from pip._vendor.six.moves.urllib import parse as urllib_parse from pip._internal.cli import cmdoptions -from pip._internal.exceptions import ( - InstallationError, - RequirementsFileParseError, -) +from pip._internal.exceptions import InstallationError, RequirementsFileParseError from pip._internal.models.search_scope import SearchScope from pip._internal.network.utils import raise_for_status from pip._internal.utils.encoding import auto_decode @@ -45,16 +42,16 @@ LineParser = Callable[[Text], Tuple[str, Values]] -__all__ = ['parse_requirements'] +__all__ = ["parse_requirements"] -SCHEME_RE = re.compile(r'^(http|https|file):', re.I) -COMMENT_RE = re.compile(r'(^|\s+)#.*$') +SCHEME_RE = re.compile(r"^(http|https|file):", re.I) +COMMENT_RE = re.compile(r"(^|\s+)#.*$") # Matches environment variable-style values in '${MY_VARIABLE_1}' with the # variable name consisting of only uppercase letters, digits or the '_' # (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, # 2013 Edition. -ENV_VAR_RE = re.compile(r'(?P\$\{(?P[A-Z0-9_]+)\})') +ENV_VAR_RE = re.compile(r"(?P\$\{(?P[A-Z0-9_]+)\})") SUPPORTED_OPTIONS = [ cmdoptions.index_url, @@ -157,10 +154,7 @@ def parse_requirements( for parsed_line in parser.parse(filename, constraint): parsed_req = handle_line( - parsed_line, - options=options, - finder=finder, - session=session + parsed_line, options=options, finder=finder, session=session ) if parsed_req is not None: yield parsed_req @@ -186,8 +180,10 @@ def handle_requirement_line( # type: (...) -> ParsedRequirement # preserve for the nested code path - line_comes_from = '{} {} (line {})'.format( - '-c' if line.constraint else '-r', line.filename, line.lineno, + line_comes_from = "{} {} (line {})".format( + "-c" if line.constraint else "-r", + line.filename, + line.lineno, ) assert line.is_requirement @@ -212,7 +208,7 @@ def handle_requirement_line( if dest in line.opts.__dict__ and line.opts.__dict__[dest]: req_options[dest] = line.opts.__dict__[dest] - line_source = 'line {} of {}'.format(line.lineno, line.filename) + line_source = "line {} of {}".format(line.lineno, line.filename) return ParsedRequirement( requirement=line.requirement, is_editable=line.is_editable, @@ -239,8 +235,7 @@ def handle_option_line( options.require_hashes = opts.require_hashes if opts.features_enabled: options.features_enabled.extend( - f for f in opts.features_enabled - if f not in options.features_enabled + f for f in opts.features_enabled if f not in options.features_enabled ) # set finder options @@ -282,7 +277,7 @@ def handle_option_line( if session: for host in opts.trusted_hosts or []: - source = 'line {} of {}'.format(lineno, filename) + source = "line {} of {}".format(lineno, filename) session.add_trusted_host(host, source=source) @@ -345,17 +340,15 @@ def __init__( def parse(self, filename, constraint): # type: (str, bool) -> Iterator[ParsedLine] - """Parse a given file, yielding parsed lines. - """ + """Parse a given file, yielding parsed lines.""" for line in self._parse_and_recurse(filename, constraint): yield line def _parse_and_recurse(self, filename, constraint): # type: (str, bool) -> Iterator[ParsedLine] for line in self._parse_file(filename, constraint): - if ( - not line.is_requirement and - (line.opts.requirements or line.opts.constraints) + if not line.is_requirement and ( + line.opts.requirements or line.opts.constraints ): # parse a nested requirements file if line.opts.requirements: @@ -373,11 +366,13 @@ def _parse_and_recurse(self, filename, constraint): elif not SCHEME_RE.search(req_path): # do a join so relative paths work req_path = os.path.join( - os.path.dirname(filename), req_path, + os.path.dirname(filename), + req_path, ) for inner_line in self._parse_and_recurse( - req_path, nested_constraint, + req_path, + nested_constraint, ): yield inner_line else: @@ -396,7 +391,7 @@ def _parse_file(self, filename, constraint): args_str, opts = self._line_parser(line) except OptionParsingError as e: # add offending line - msg = 'Invalid requirement: {}\n{}'.format(line, e.msg) + msg = "Invalid requirement: {}\n{}".format(line, e.msg) raise RequirementsFileParseError(msg) yield ParsedLine( @@ -425,11 +420,10 @@ def parse_line(line): # Prior to 2.7.3, shlex cannot deal with unicode entries if sys.version_info < (2, 7, 3): # https://github.com/python/mypy/issues/1174 - options_str = options_str.encode('utf8') # type: ignore + options_str = options_str.encode("utf8") # type: ignore # https://github.com/python/mypy/issues/1174 - opts, _ = parser.parse_args( - shlex.split(options_str), defaults) # type: ignore + opts, _ = parser.parse_args(shlex.split(options_str), defaults) # type: ignore return args_str, opts @@ -442,16 +436,16 @@ def break_args_options(line): (and then optparse) the options, not the args. args can contain markers which are corrupted by shlex. """ - tokens = line.split(' ') + tokens = line.split(" ") args = [] options = tokens[:] for token in tokens: - if token.startswith('-') or token.startswith('--'): + if token.startswith("-") or token.startswith("--"): break else: args.append(token) options.pop(0) - return ' '.join(args), ' '.join(options) # type: ignore + return " ".join(args), " ".join(options) # type: ignore class OptionParsingError(Exception): @@ -477,6 +471,7 @@ def build_parser(): def parser_exit(self, msg): # type: (Any, str) -> NoReturn raise OptionParsingError(msg) + # NOTE: mypy disallows assigning to a method # https://github.com/python/mypy/issues/2427 parser.exit = parser_exit # type: ignore @@ -492,26 +487,26 @@ def join_lines(lines_enum): primary_line_number = None new_line = [] # type: List[Text] for line_number, line in lines_enum: - if not line.endswith('\\') or COMMENT_RE.match(line): + if not line.endswith("\\") or COMMENT_RE.match(line): if COMMENT_RE.match(line): # this ensures comments are always matched later - line = ' ' + line + line = " " + line if new_line: new_line.append(line) assert primary_line_number is not None - yield primary_line_number, ''.join(new_line) + yield primary_line_number, "".join(new_line) new_line = [] else: yield line_number, line else: if not new_line: primary_line_number = line_number - new_line.append(line.strip('\\')) + new_line.append(line.strip("\\")) # last line contains \ if new_line: assert primary_line_number is not None - yield primary_line_number, ''.join(new_line) + yield primary_line_number, "".join(new_line) # TODO: handle space after '\'. @@ -522,7 +517,7 @@ def ignore_comments(lines_enum): Strips comments and filter empty lines. """ for line_number, line in lines_enum: - line = COMMENT_RE.sub('', line) + line = COMMENT_RE.sub("", line) line = line.strip() if line: yield line_number, line @@ -568,25 +563,23 @@ def get_file_content(url, session, comes_from=None): """ scheme = get_url_scheme(url) - if scheme in ['http', 'https']: + if scheme in ["http", "https"]: # FIXME: catch some errors resp = session.get(url) raise_for_status(resp) return resp.url, resp.text - elif scheme == 'file': - if comes_from and comes_from.startswith('http'): + elif scheme == "file": + if comes_from and comes_from.startswith("http"): raise InstallationError( - 'Requirements file {} references URL {}, ' - 'which is local'.format(comes_from, url) + "Requirements file {} references URL {}, " + "which is local".format(comes_from, url) ) url = url_to_path(url) try: - with open(url, 'rb') as f: + with open(url, "rb") as f: content = auto_decode(f.read()) except IOError as exc: - raise InstallationError( - 'Could not open requirements file: {}'.format(exc) - ) + raise InstallationError("Could not open requirements file: {}".format(exc)) return url, content diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index 9a6763074a3..593381b2d36 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -22,10 +22,12 @@ from pip._internal.locations import get_scheme from pip._internal.models.link import Link from pip._internal.operations.build.metadata import generate_metadata -from pip._internal.operations.build.metadata_legacy import \ - generate_metadata as generate_metadata_legacy -from pip._internal.operations.install.editable_legacy import \ - install_editable as install_editable_legacy +from pip._internal.operations.build.metadata_legacy import ( + generate_metadata as generate_metadata_legacy, +) +from pip._internal.operations.install.editable_legacy import ( + install_editable as install_editable_legacy, +) from pip._internal.operations.install.legacy import LegacyInstallFailure from pip._internal.operations.install.legacy import install as install_legacy from pip._internal.operations.install.wheel import install_wheel @@ -132,9 +134,7 @@ def __init__( if self.editable: assert link if link.is_file: - self.source_dir = os.path.normpath( - os.path.abspath(link.file_path) - ) + self.source_dir = os.path.normpath(os.path.abspath(link.file_path)) if link is None and req and req.url: # PEP 508 URL requirement @@ -150,9 +150,7 @@ def __init__( if extras: self.extras = extras elif req: - self.extras = { - pkg_resources.safe_extra(extra) for extra in req.extras - } + self.extras = {pkg_resources.safe_extra(extra) for extra in req.extras} else: self.extras = set() if markers is None and req: @@ -213,38 +211,36 @@ def __str__(self): if self.req: s = str(self.req) if self.link: - s += ' from {}'.format(redact_auth_from_url(self.link.url)) + s += " from {}".format(redact_auth_from_url(self.link.url)) elif self.link: s = redact_auth_from_url(self.link.url) else: - s = '' + s = "" if self.satisfied_by is not None: - s += ' in {}'.format(display_path(self.satisfied_by.location)) + s += " in {}".format(display_path(self.satisfied_by.location)) if self.comes_from: if isinstance(self.comes_from, six.string_types): comes_from = self.comes_from # type: Optional[str] else: comes_from = self.comes_from.from_path() if comes_from: - s += ' (from {})'.format(comes_from) + s += " (from {})".format(comes_from) return s def __repr__(self): # type: () -> str - return '<{} object: {} editable={!r}>'.format( - self.__class__.__name__, str(self), self.editable) + return "<{} object: {} editable={!r}>".format( + self.__class__.__name__, str(self), self.editable + ) def format_debug(self): # type: () -> str - """An un-tested helper for getting state, for debugging. - """ + """An un-tested helper for getting state, for debugging.""" attributes = vars(self) names = sorted(attributes) - state = ( - "{}={!r}".format(attr, attributes[attr]) for attr in sorted(names) - ) - return '<{name} object: {{{state}}}>'.format( + state = ("{}={!r}".format(attr, attributes[attr]) for attr in sorted(names)) + return "<{name} object: {{{state}}}>".format( name=self.__class__.__name__, state=", ".join(state), ) @@ -270,8 +266,7 @@ def is_pinned(self): For example, some-package==1.2 is pinned; some-package>1.2 is not. """ specifiers = self.specifier - return (len(specifiers) == 1 and - next(iter(specifiers)).operator in {'==', '==='}) + return len(specifiers) == 1 and next(iter(specifiers)).operator in {"==", "==="} @property def installed_version(self): @@ -283,11 +278,11 @@ def match_markers(self, extras_requested=None): if not extras_requested: # Provide an extra to safely evaluate the markers # without matching any extra - extras_requested = ('',) + extras_requested = ("",) if self.markers is not None: return any( - self.markers.evaluate({'extra': extra}) - for extra in extras_requested) + self.markers.evaluate({"extra": extra}) for extra in extras_requested + ) else: return True @@ -326,8 +321,7 @@ def hashes(self, trust_internet=True): def from_path(self): # type: () -> Optional[str] - """Format a nice indicator to show where this "comes from" - """ + """Format a nice indicator to show where this "comes from" """ if self.req is None: return None s = str(self.req) @@ -337,7 +331,7 @@ def from_path(self): else: comes_from = self.comes_from.from_path() if comes_from: - s += '->' + comes_from + s += "->" + comes_from return s def ensure_build_location(self, build_dir, autodelete, parallel_builds): @@ -365,7 +359,7 @@ def ensure_build_location(self, build_dir, autodelete, parallel_builds): # FIXME: Is there a better place to create the build_dir? (hg and bzr # need this) if not os.path.exists(build_dir): - logger.debug('Creating directory %s', build_dir) + logger.debug("Creating directory %s", build_dir) os.makedirs(build_dir) actual_build_dir = os.path.join(build_dir, dir_name) # `None` indicates that we respect the globally-configured deletion @@ -380,8 +374,7 @@ def ensure_build_location(self, build_dir, autodelete, parallel_builds): def _set_requirement(self): # type: () -> None - """Set requirement after generating metadata. - """ + """Set requirement after generating metadata.""" assert self.req is None assert self.metadata is not None assert self.source_dir is not None @@ -393,11 +386,13 @@ def _set_requirement(self): op = "===" self.req = Requirement( - "".join([ - self.metadata["Name"], - op, - self.metadata["Version"], - ]) + "".join( + [ + self.metadata["Name"], + op, + self.metadata["Version"], + ] + ) ) def warn_on_mismatching_name(self): @@ -409,10 +404,12 @@ def warn_on_mismatching_name(self): # If we're here, there's a mismatch. Log a warning about it. logger.warning( - 'Generating metadata for package %s ' - 'produced metadata for project name %s. Fix your ' - '#egg=%s fragments.', - self.name, metadata_name, self.name + "Generating metadata for package %s " + "produced metadata for project name %s. Fix your " + "#egg=%s fragments.", + self.name, + metadata_name, + self.name, ) self.req = Requirement(metadata_name) @@ -434,12 +431,14 @@ def check_if_exists(self, use_user_site): if use_user_site: if dist_in_usersite(existing_dist): self.should_reinstall = True - elif (running_under_virtualenv() and - dist_in_site_packages(existing_dist)): + elif running_under_virtualenv() and dist_in_site_packages( + existing_dist + ): raise InstallationError( "Will not install to the user site because it will " "lack sys.path precedence to {} in {}".format( - existing_dist.project_name, existing_dist.location) + existing_dist.project_name, existing_dist.location + ) ) else: self.should_reinstall = True @@ -465,14 +464,14 @@ def is_wheel(self): def unpacked_source_directory(self): # type: () -> str return os.path.join( - self.source_dir, - self.link and self.link.subdirectory_fragment or '') + self.source_dir, self.link and self.link.subdirectory_fragment or "" + ) @property def setup_py_path(self): # type: () -> str assert self.source_dir, "No source dir for {}".format(self) - setup_py = os.path.join(self.unpacked_source_directory, 'setup.py') + setup_py = os.path.join(self.unpacked_source_directory, "setup.py") # Python2 __file__ should not be unicode if six.PY2 and isinstance(setup_py, six.text_type): @@ -496,10 +495,7 @@ def load_pyproject_toml(self): follow the PEP 517 or legacy (setup.py) code path. """ pyproject_toml_data = load_pyproject_toml( - self.use_pep517, - self.pyproject_toml_path, - self.setup_py_path, - str(self) + self.use_pep517, self.pyproject_toml_path, self.setup_py_path, str(self) ) if pyproject_toml_data is None: @@ -511,13 +507,14 @@ def load_pyproject_toml(self): self.requirements_to_check = check self.pyproject_requires = requires self.pep517_backend = Pep517HookCaller( - self.unpacked_source_directory, backend, backend_path=backend_path, + self.unpacked_source_directory, + backend, + backend_path=backend_path, ) def _generate_metadata(self): # type: () -> str - """Invokes metadata generator functions, with the required arguments. - """ + """Invokes metadata generator functions, with the required arguments.""" if not self.use_pep517: assert self.unpacked_source_directory @@ -526,7 +523,7 @@ def _generate_metadata(self): setup_py_path=self.setup_py_path, source_dir=self.unpacked_source_directory, isolated=self.isolated, - details=self.name or "from {}".format(self.link) + details=self.name or "from {}".format(self.link), ) assert self.pep517_backend is not None @@ -559,7 +556,7 @@ def prepare_metadata(self): @property def metadata(self): # type: () -> Any - if not hasattr(self, '_metadata'): + if not hasattr(self, "_metadata"): self._metadata = get_metadata(self.get_dist()) return self._metadata @@ -571,16 +568,16 @@ def get_dist(self): def assert_source_matches_version(self): # type: () -> None assert self.source_dir - version = self.metadata['version'] + version = self.metadata["version"] if self.req.specifier and version not in self.req.specifier: logger.warning( - 'Requested %s, but installing version %s', + "Requested %s, but installing version %s", self, version, ) else: logger.debug( - 'Source in %s has version %s, which satisfies requirement %s', + "Source in %s has version %s, which satisfies requirement %s", display_path(self.source_dir), version, self, @@ -615,27 +612,23 @@ def update_editable(self, obtain=True): # type: (bool) -> None if not self.link: logger.debug( - "Cannot update repository at %s; repository location is " - "unknown", + "Cannot update repository at %s; repository location is " "unknown", self.source_dir, ) return assert self.editable assert self.source_dir - if self.link.scheme == 'file': + if self.link.scheme == "file": # Static paths don't get updated return - assert '+' in self.link.url, \ - "bad url: {self.link.url!r}".format(**locals()) - vc_type, url = self.link.url.split('+', 1) + assert "+" in self.link.url, "bad url: {self.link.url!r}".format(**locals()) + vc_type, url = self.link.url.split("+", 1) vcs_backend = vcs.get_backend(vc_type) if vcs_backend: if not self.link.is_vcs: reason = ( "This form of VCS requirement is being deprecated: {}." - ).format( - self.link.url - ) + ).format(self.link.url) replacement = None if self.link.url.startswith("git+git@"): replacement = ( @@ -650,9 +643,9 @@ def update_editable(self, obtain=True): else: vcs_backend.export(self.source_dir, url=hidden_url) else: - assert 0, ( - 'Unexpected version control type (in {}): {}'.format( - self.link, vc_type)) + assert 0, "Unexpected version control type (in {}): {}".format( + self.link, vc_type + ) # Top-level Actions def uninstall(self, auto_confirm=False, verbose=False): @@ -674,7 +667,7 @@ def uninstall(self, auto_confirm=False, verbose=False): if not dist: logger.warning("Skipping %s as it is not installed.", self.name) return None - logger.info('Found existing installation: %s', dist) + logger.info("Found existing installation: %s", dist) uninstalled_pathset = UninstallPathSet.from_dist(dist) uninstalled_pathset.remove(auto_confirm, verbose) @@ -685,17 +678,16 @@ def _get_archive_name(self, path, parentdir, rootdir): def _clean_zip_name(name, prefix): # type: (str, str) -> str - assert name.startswith(prefix + os.path.sep), ( - "name {name!r} doesn't start with prefix {prefix!r}" - .format(**locals()) - ) - name = name[len(prefix) + 1:] - name = name.replace(os.path.sep, '/') + assert name.startswith( + prefix + os.path.sep + ), "name {name!r} doesn't start with prefix {prefix!r}".format(**locals()) + name = name[len(prefix) + 1 :] + name = name.replace(os.path.sep, "/") return name path = os.path.join(parentdir, path) name = _clean_zip_name(path, rootdir) - return self.name + '/' + name + return self.name + "/" + name def archive(self, build_dir): # type: (str) -> None @@ -706,57 +698,62 @@ def archive(self, build_dir): assert self.source_dir create_archive = True - archive_name = '{}-{}.zip'.format(self.name, self.metadata["version"]) + archive_name = "{}-{}.zip".format(self.name, self.metadata["version"]) archive_path = os.path.join(build_dir, archive_name) if os.path.exists(archive_path): response = ask_path_exists( - 'The file {} exists. (i)gnore, (w)ipe, ' - '(b)ackup, (a)bort '.format( - display_path(archive_path)), - ('i', 'w', 'b', 'a')) - if response == 'i': + "The file {} exists. (i)gnore, (w)ipe, " + "(b)ackup, (a)bort ".format(display_path(archive_path)), + ("i", "w", "b", "a"), + ) + if response == "i": create_archive = False - elif response == 'w': - logger.warning('Deleting %s', display_path(archive_path)) + elif response == "w": + logger.warning("Deleting %s", display_path(archive_path)) os.remove(archive_path) - elif response == 'b': + elif response == "b": dest_file = backup_dir(archive_path) logger.warning( - 'Backing up %s to %s', + "Backing up %s to %s", display_path(archive_path), display_path(dest_file), ) shutil.move(archive_path, dest_file) - elif response == 'a': + elif response == "a": sys.exit(-1) if not create_archive: return zip_output = zipfile.ZipFile( - archive_path, 'w', zipfile.ZIP_DEFLATED, allowZip64=True, + archive_path, + "w", + zipfile.ZIP_DEFLATED, + allowZip64=True, ) with zip_output: - dir = os.path.normcase( - os.path.abspath(self.unpacked_source_directory) - ) + dir = os.path.normcase(os.path.abspath(self.unpacked_source_directory)) for dirpath, dirnames, filenames in os.walk(dir): for dirname in dirnames: dir_arcname = self._get_archive_name( - dirname, parentdir=dirpath, rootdir=dir, + dirname, + parentdir=dirpath, + rootdir=dir, ) - zipdir = zipfile.ZipInfo(dir_arcname + '/') + zipdir = zipfile.ZipInfo(dir_arcname + "/") zipdir.external_attr = 0x1ED << 16 # 0o755 - zip_output.writestr(zipdir, '') + zip_output.writestr(zipdir, "") for filename in filenames: file_arcname = self._get_archive_name( - filename, parentdir=dirpath, rootdir=dir, + filename, + parentdir=dirpath, + rootdir=dir, ) filename = os.path.join(dirpath, filename) zip_output.write(filename, file_arcname) - logger.info('Saved %s', display_path(archive_path)) + logger.info("Saved %s", display_path(archive_path)) def install( self, @@ -767,7 +764,7 @@ def install( prefix=None, # type: Optional[str] warn_script_location=True, # type: bool use_user_site=False, # type: bool - pycompile=True # type: bool + pycompile=True, # type: bool ): # type: (...) -> None scheme = get_scheme( @@ -858,8 +855,9 @@ def install( deprecated( reason=( "{} was installed using the legacy 'setup.py install' " - "method, because a wheel could not be built for it.". - format(self.name) + "method, because a wheel could not be built for it.".format( + self.name + ) ), replacement="to fix the wheel build issue reported above", gone_in="21.0", @@ -888,12 +886,10 @@ def check_invalid_constraint_type(req): "undocumented. The new implementation of the resolver no " "longer supports these forms." ), - replacement=( - "replacing the constraint with a requirement." - ), + replacement=("replacing the constraint with a requirement."), # No plan yet for when the new resolver becomes default gone_in=None, - issue=8210 + issue=8210, ) return problem diff --git a/src/pip/_internal/req/req_set.py b/src/pip/_internal/req/req_set.py index c9ea3be5ddd..9becf32bb5a 100644 --- a/src/pip/_internal/req/req_set.py +++ b/src/pip/_internal/req/req_set.py @@ -20,13 +20,13 @@ class RequirementSet(object): - def __init__(self, check_supported_wheels=True): # type: (bool) -> None - """Create a RequirementSet. - """ + """Create a RequirementSet.""" - self.requirements = OrderedDict() # type: Dict[str, InstallRequirement] # noqa: E501 + self.requirements = ( + OrderedDict() + ) # type: Dict[str, InstallRequirement] # noqa: E501 self.check_supported_wheels = check_supported_wheels self.unnamed_requirements = [] # type: List[InstallRequirement] @@ -37,7 +37,7 @@ def __str__(self): (req for req in self.requirements.values() if not req.comes_from), key=lambda req: canonicalize_name(req.name), ) - return ' '.join(str(req.req) for req in requirements) + return " ".join(str(req.req) for req in requirements) def __repr__(self): # type: () -> str @@ -46,11 +46,11 @@ def __repr__(self): key=lambda req: canonicalize_name(req.name), ) - format_string = '<{classname} object; {count} requirement(s): {reqs}>' + format_string = "<{classname} object; {count} requirement(s): {reqs}>" return format_string.format( classname=self.__class__.__name__, count=len(requirements), - reqs=', '.join(str(req.req) for req in requirements), + reqs=", ".join(str(req.req) for req in requirements), ) def add_unnamed_requirement(self, install_req): @@ -69,7 +69,7 @@ def add_requirement( self, install_req, # type: InstallRequirement parent_req_name=None, # type: Optional[str] - extras_requested=None # type: Optional[Iterable[str]] + extras_requested=None, # type: Optional[Iterable[str]] ): # type: (...) -> Tuple[List[InstallRequirement], Optional[InstallRequirement]] # noqa: E501 """Add install_req as a requirement to install. @@ -90,7 +90,8 @@ def add_requirement( if not install_req.match_markers(extras_requested): logger.info( "Ignoring %s: markers '%s' don't match your environment", - install_req.name, install_req.markers, + install_req.name, + install_req.markers, ) return [], None @@ -101,16 +102,17 @@ def add_requirement( if install_req.link and install_req.link.is_wheel: wheel = Wheel(install_req.link.filename) tags = compatibility_tags.get_supported() - if (self.check_supported_wheels and not wheel.supported(tags)): + if self.check_supported_wheels and not wheel.supported(tags): raise InstallationError( "{} is not a supported wheel on this platform.".format( - wheel.filename) + wheel.filename + ) ) # This next bit is really a sanity check. - assert not install_req.user_supplied or parent_req_name is None, ( - "a user supplied req shouldn't have a parent" - ) + assert ( + not install_req.user_supplied or parent_req_name is None + ), "a user supplied req shouldn't have a parent" # Unnamed requirements are scanned again and the requirement won't be # added as a dependency until after scanning. @@ -120,21 +122,23 @@ def add_requirement( try: existing_req = self.get_requirement( - install_req.name) # type: Optional[InstallRequirement] + install_req.name + ) # type: Optional[InstallRequirement] except KeyError: existing_req = None has_conflicting_requirement = ( - parent_req_name is None and - existing_req and - not existing_req.constraint and - existing_req.extras == install_req.extras and - existing_req.req.specifier != install_req.req.specifier + parent_req_name is None + and existing_req + and not existing_req.constraint + and existing_req.extras == install_req.extras + and existing_req.req.specifier != install_req.req.specifier ) if has_conflicting_requirement: raise InstallationError( - "Double requirement given: {} (already in {}, name={!r})" - .format(install_req, existing_req, install_req.name) + "Double requirement given: {} (already in {}, name={!r})".format( + install_req, existing_req, install_req.name + ) ) # When no existing requirement exists, add the requirement as a @@ -149,12 +153,8 @@ def add_requirement( if install_req.constraint or not existing_req.constraint: return [], existing_req - does_not_satisfy_constraint = ( - install_req.link and - not ( - existing_req.link and - install_req.link.path == existing_req.link.path - ) + does_not_satisfy_constraint = install_req.link and not ( + existing_req.link and install_req.link.path == existing_req.link.path ) if does_not_satisfy_constraint: raise InstallationError( @@ -169,12 +169,13 @@ def add_requirement( # mark the existing object as such. if install_req.user_supplied: existing_req.user_supplied = True - existing_req.extras = tuple(sorted( - set(existing_req.extras) | set(install_req.extras) - )) + existing_req.extras = tuple( + sorted(set(existing_req.extras) | set(install_req.extras)) + ) logger.debug( "Setting %s extras to: %s", - existing_req, existing_req.extras, + existing_req, + existing_req.extras, ) # Return the existing requirement for addition to the parent and # scanning again. @@ -185,8 +186,8 @@ def has_requirement(self, name): project_name = canonicalize_name(name) return ( - project_name in self.requirements and - not self.requirements[project_name].constraint + project_name in self.requirements + and not self.requirements[project_name].constraint ) def get_requirement(self, name): diff --git a/src/pip/_internal/req/req_tracker.py b/src/pip/_internal/req/req_tracker.py index 7379c307b31..b3e9a145b42 100644 --- a/src/pip/_internal/req/req_tracker.py +++ b/src/pip/_internal/req/req_tracker.py @@ -51,12 +51,10 @@ def update_env_context_manager(**changes): @contextlib.contextmanager def get_requirement_tracker(): # type: () -> Iterator[RequirementTracker] - root = os.environ.get('PIP_REQ_TRACKER') + root = os.environ.get("PIP_REQ_TRACKER") with contextlib2.ExitStack() as ctx: if root is None: - root = ctx.enter_context( - TempDirectory(kind='req-tracker') - ).path + root = ctx.enter_context(TempDirectory(kind="req-tracker")).path ctx.enter_context(update_env_context_manager(PIP_REQ_TRACKER=root)) logger.debug("Initialized build tracking at %s", root) @@ -65,7 +63,6 @@ def get_requirement_tracker(): class RequirementTracker(object): - def __init__(self, root): # type: (str) -> None self._root = root @@ -81,7 +78,7 @@ def __exit__( self, exc_type, # type: Optional[Type[BaseException]] exc_val, # type: Optional[BaseException] - exc_tb # type: Optional[TracebackType] + exc_tb, # type: Optional[TracebackType] ): # type: (...) -> None self.cleanup() @@ -93,8 +90,7 @@ def _entry_path(self, link): def add(self, req): # type: (InstallRequirement) -> None - """Add an InstallRequirement to build tracking. - """ + """Add an InstallRequirement to build tracking.""" assert req.link # Get the file to write information about this requirement. @@ -110,31 +106,29 @@ def add(self, req): if e.errno != errno.ENOENT: raise else: - message = '{} is already being built: {}'.format( - req.link, contents) + message = "{} is already being built: {}".format(req.link, contents) raise LookupError(message) # If we're here, req should really not be building already. assert req not in self._entries # Start tracking this requirement. - with open(entry_path, 'w') as fp: + with open(entry_path, "w") as fp: fp.write(str(req)) self._entries.add(req) - logger.debug('Added %s to build tracker %r', req, self._root) + logger.debug("Added %s to build tracker %r", req, self._root) def remove(self, req): # type: (InstallRequirement) -> None - """Remove an InstallRequirement from build tracking. - """ + """Remove an InstallRequirement from build tracking.""" assert req.link # Delete the created file and the corresponding entries. os.unlink(self._entry_path(req.link)) self._entries.remove(req) - logger.debug('Removed %s from build tracker %r', req, self._root) + logger.debug("Removed %s from build tracker %r", req, self._root) def cleanup(self): # type: () -> None diff --git a/src/pip/_internal/req/req_uninstall.py b/src/pip/_internal/req/req_uninstall.py index 2e7dfcc7369..58461c4cde4 100644 --- a/src/pip/_internal/req/req_uninstall.py +++ b/src/pip/_internal/req/req_uninstall.py @@ -58,12 +58,12 @@ def _script_names(dist, script_name, is_gui): exe_name = os.path.join(bin_dir, script_name) paths_to_remove = [exe_name] if WINDOWS: - paths_to_remove.append(exe_name + '.exe') - paths_to_remove.append(exe_name + '.exe.manifest') + paths_to_remove.append(exe_name + ".exe") + paths_to_remove.append(exe_name + ".exe.manifest") if is_gui: - paths_to_remove.append(exe_name + '-script.pyw') + paths_to_remove.append(exe_name + "-script.pyw") else: - paths_to_remove.append(exe_name + '-script.py') + paths_to_remove.append(exe_name + "-script.py") return paths_to_remove @@ -77,6 +77,7 @@ def unique(*args, **kw): if item not in seen: seen.add(item) yield item + return unique @@ -91,16 +92,16 @@ def uninstallation_paths(dist): UninstallPathSet.add() takes care of the __pycache__ .py[co]. """ - r = csv.reader(FakeFile(dist.get_metadata_lines('RECORD'))) + r = csv.reader(FakeFile(dist.get_metadata_lines("RECORD"))) for row in r: path = os.path.join(dist.location, row[0]) yield path - if path.endswith('.py'): + if path.endswith(".py"): dn, fn = os.path.split(path) base = fn[:-3] - path = os.path.join(dn, base + '.pyc') + path = os.path.join(dn, base + ".pyc") yield path - path = os.path.join(dn, base + '.pyo') + path = os.path.join(dn, base + ".pyo") yield path @@ -115,8 +116,8 @@ def compact(paths): short_paths = set() # type: Set[str] for path in sorted(paths, key=len): should_skip = any( - path.startswith(shortpath.rstrip("*")) and - path[len(shortpath.rstrip("*").rstrip(sep))] == sep + path.startswith(shortpath.rstrip("*")) + and path[len(shortpath.rstrip("*").rstrip(sep))] == sep for shortpath in short_paths ) if not should_skip: @@ -133,8 +134,7 @@ def compress_for_rename(paths): """ case_map = dict((os.path.normcase(p), p) for p in paths) remaining = set(case_map) - unchecked = sorted(set(os.path.split(p)[0] - for p in case_map.values()), key=len) + unchecked = sorted(set(os.path.split(p)[0] for p in case_map.values()), key=len) wildcards = set() # type: Set[str] def norm_join(*a): @@ -142,18 +142,15 @@ def norm_join(*a): return os.path.normcase(os.path.join(*a)) for root in unchecked: - if any(os.path.normcase(root).startswith(w) - for w in wildcards): + if any(os.path.normcase(root).startswith(w) for w in wildcards): # This directory has already been handled. continue all_files = set() # type: Set[str] all_subdirs = set() # type: Set[str] for dirname, subdirs, files in os.walk(root): - all_subdirs.update(norm_join(root, dirname, d) - for d in subdirs) - all_files.update(norm_join(root, dirname, f) - for f in files) + all_subdirs.update(norm_join(root, dirname, d) for d in subdirs) + all_files.update(norm_join(root, dirname, f) for f in files) # If all the files we found are in our remaining set of files to # remove, then remove them from the latter set and add a wildcard # for the directory. @@ -203,14 +200,14 @@ def compress_for_output_listing(paths): continue file_ = os.path.join(dirpath, fname) - if (os.path.isfile(file_) and - os.path.normcase(file_) not in _normcased_files): + if ( + os.path.isfile(file_) + and os.path.normcase(file_) not in _normcased_files + ): # We are skipping this file. Add it to the set. will_skip.add(file_) - will_remove = files | { - os.path.join(folder, "*") for folder in folders - } + will_remove = files | {os.path.join(folder, "*") for folder in folders} return will_remove, will_skip @@ -218,6 +215,7 @@ def compress_for_output_listing(paths): class StashedUninstallPathSet(object): """A set of file rename operations to stash files while tentatively uninstalling them.""" + def __init__(self): # type: () -> None # Mapping from source file root to [Adjacent]TempDirectory @@ -262,7 +260,7 @@ def _get_file_stash(self, path): else: # Did not find any suitable root head = os.path.dirname(path) - save_dir = TempDirectory(kind='uninstall') + save_dir = TempDirectory(kind="uninstall") self._save_dirs[head] = save_dir relpath = os.path.relpath(path, head) @@ -282,7 +280,7 @@ def stash(self, path): new_path = self._get_file_stash(path) self._moves.append((path, new_path)) - if (path_is_dir and os.path.isdir(new_path)): + if path_is_dir and os.path.isdir(new_path): # If we're moving a directory, we need to # remove the destination first or else it will be # moved to inside the existing directory. @@ -308,7 +306,7 @@ def rollback(self): for new_path, path in self._moves: try: - logger.debug('Replacing %s from %s', new_path, path) + logger.debug("Replacing %s from %s", new_path, path) if os.path.isfile(new_path) or os.path.islink(new_path): os.unlink(new_path) elif os.path.isdir(new_path): @@ -329,6 +327,7 @@ def can_rollback(self): class UninstallPathSet(object): """A set of file paths to be removed in the uninstallation of a requirement.""" + def __init__(self, dist): # type: (Distribution) -> None self.paths = set() # type: Set[str] @@ -363,7 +362,7 @@ def add(self, path): # __pycache__ files can show up after 'installed-files.txt' is created, # due to imports - if os.path.splitext(path)[1] == '.py' and uses_pycache: + if os.path.splitext(path)[1] == ".py" and uses_pycache: self.add(cache_from_source(path)) def add_pth(self, pth_file, entry): @@ -388,10 +387,8 @@ def remove(self, auto_confirm=False, verbose=False): ) return - dist_name_version = ( - self.dist.project_name + "-" + self.dist.version - ) - logger.info('Uninstalling %s:', dist_name_version) + dist_name_version = self.dist.project_name + "-" + self.dist.version + logger.info("Uninstalling %s:", dist_name_version) with indent_log(): if auto_confirm or self._allowed_to_proceed(verbose): @@ -401,17 +398,16 @@ def remove(self, auto_confirm=False, verbose=False): for path in sorted(compact(for_rename)): moved.stash(path) - logger.debug('Removing file or directory %s', path) + logger.debug("Removing file or directory %s", path) for pth in self.pth.values(): pth.remove() - logger.info('Successfully uninstalled %s', dist_name_version) + logger.info("Successfully uninstalled %s", dist_name_version) def _allowed_to_proceed(self, verbose): # type: (bool) -> bool - """Display which files would be deleted and prompt for confirmation - """ + """Display which files would be deleted and prompt for confirmation""" def _display(msg, paths): # type: (str, Iterable[str]) -> None @@ -431,13 +427,13 @@ def _display(msg, paths): will_remove = set(self.paths) will_skip = set() - _display('Would remove:', will_remove) - _display('Would not remove (might be manually added):', will_skip) - _display('Would not remove (outside of prefix):', self._refuse) + _display("Would remove:", will_remove) + _display("Would not remove (might be manually added):", will_skip) + _display("Would not remove (outside of prefix):", self._refuse) if verbose: - _display('Will actually move:', compress_for_rename(self.paths)) + _display("Will actually move:", compress_for_rename(self.paths)) - return ask('Proceed (y/n)? ', ('y', 'n')) == 'y' + return ask("Proceed (y/n)? ", ("y", "n")) == "y" def rollback(self): # type: () -> None @@ -448,7 +444,7 @@ def rollback(self): self.dist.project_name, ) return - logger.info('Rolling back uninstall of %s', self.dist.project_name) + logger.info("Rolling back uninstall of %s", self.dist.project_name) self._moved_paths.rollback() for pth in self.pth.values(): pth.rollback() @@ -471,9 +467,11 @@ def from_dist(cls, dist): ) return cls(dist) - if dist_path in {p for p in {sysconfig.get_path("stdlib"), - sysconfig.get_path("platstdlib")} - if p}: + if dist_path in { + p + for p in {sysconfig.get_path("stdlib"), sysconfig.get_path("platstdlib")} + if p + }: logger.info( "Not uninstalling %s at %s, as it is in the standard library.", dist.key, @@ -483,43 +481,47 @@ def from_dist(cls, dist): paths_to_remove = cls(dist) develop_egg_link = egg_link_path(dist) - develop_egg_link_egg_info = '{}.egg-info'.format( - pkg_resources.to_filename(dist.project_name)) + develop_egg_link_egg_info = "{}.egg-info".format( + pkg_resources.to_filename(dist.project_name) + ) egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) # Special case for distutils installed package - distutils_egg_info = getattr(dist._provider, 'path', None) + distutils_egg_info = getattr(dist._provider, "path", None) # Uninstall cases order do matter as in the case of 2 installs of the # same package, pip needs to uninstall the currently detected version - if (egg_info_exists and dist.egg_info.endswith('.egg-info') and - not dist.egg_info.endswith(develop_egg_link_egg_info)): + if ( + egg_info_exists + and dist.egg_info.endswith(".egg-info") + and not dist.egg_info.endswith(develop_egg_link_egg_info) + ): # if dist.egg_info.endswith(develop_egg_link_egg_info), we # are in fact in the develop_egg_link case paths_to_remove.add(dist.egg_info) - if dist.has_metadata('installed-files.txt'): + if dist.has_metadata("installed-files.txt"): for installed_file in dist.get_metadata( - 'installed-files.txt').splitlines(): - path = os.path.normpath( - os.path.join(dist.egg_info, installed_file) - ) + "installed-files.txt" + ).splitlines(): + path = os.path.normpath(os.path.join(dist.egg_info, installed_file)) paths_to_remove.add(path) # FIXME: need a test for this elif block # occurs with --single-version-externally-managed/--record outside # of pip - elif dist.has_metadata('top_level.txt'): - if dist.has_metadata('namespace_packages.txt'): - namespaces = dist.get_metadata('namespace_packages.txt') + elif dist.has_metadata("top_level.txt"): + if dist.has_metadata("namespace_packages.txt"): + namespaces = dist.get_metadata("namespace_packages.txt") else: namespaces = [] for top_level_pkg in [ - p for p - in dist.get_metadata('top_level.txt').splitlines() - if p and p not in namespaces]: + p + for p in dist.get_metadata("top_level.txt").splitlines() + if p and p not in namespaces + ]: path = os.path.join(dist.location, top_level_pkg) paths_to_remove.add(path) - paths_to_remove.add(path + '.py') - paths_to_remove.add(path + '.pyc') - paths_to_remove.add(path + '.pyo') + paths_to_remove.add(path + ".py") + paths_to_remove.add(path + ".pyc") + paths_to_remove.add(path + ".pyo") elif distutils_egg_info: raise UninstallationError( @@ -530,58 +532,61 @@ def from_dist(cls, dist): ) ) - elif dist.location.endswith('.egg'): + elif dist.location.endswith(".egg"): # package installed by easy_install # We cannot match on dist.egg_name because it can slightly vary # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg paths_to_remove.add(dist.location) easy_install_egg = os.path.split(dist.location)[1] - easy_install_pth = os.path.join(os.path.dirname(dist.location), - 'easy-install.pth') - paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) + easy_install_pth = os.path.join( + os.path.dirname(dist.location), "easy-install.pth" + ) + paths_to_remove.add_pth(easy_install_pth, "./" + easy_install_egg) - elif egg_info_exists and dist.egg_info.endswith('.dist-info'): + elif egg_info_exists and dist.egg_info.endswith(".dist-info"): for path in uninstallation_paths(dist): paths_to_remove.add(path) elif develop_egg_link: # develop egg - with open(develop_egg_link, 'r') as fh: + with open(develop_egg_link, "r") as fh: link_pointer = os.path.normcase(fh.readline().strip()) - assert (link_pointer == dist.location), ( - 'Egg-link {} does not match installed location of {} ' - '(at {})'.format( - link_pointer, dist.project_name, dist.location) + assert ( + link_pointer == dist.location + ), "Egg-link {} does not match installed location of {} " "(at {})".format( + link_pointer, dist.project_name, dist.location ) paths_to_remove.add(develop_egg_link) - easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), - 'easy-install.pth') + easy_install_pth = os.path.join( + os.path.dirname(develop_egg_link), "easy-install.pth" + ) paths_to_remove.add_pth(easy_install_pth, dist.location) else: logger.debug( - 'Not sure how to uninstall: %s - Check: %s', - dist, dist.location, + "Not sure how to uninstall: %s - Check: %s", + dist, + dist.location, ) # find distutils scripts= scripts - if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): - for script in dist.metadata_listdir('scripts'): + if dist.has_metadata("scripts") and dist.metadata_isdir("scripts"): + for script in dist.metadata_listdir("scripts"): if dist_in_usersite(dist): bin_dir = bin_user else: bin_dir = bin_py paths_to_remove.add(os.path.join(bin_dir, script)) if WINDOWS: - paths_to_remove.add(os.path.join(bin_dir, script) + '.bat') + paths_to_remove.add(os.path.join(bin_dir, script) + ".bat") # find console_scripts _scripts_to_remove = [] - console_scripts = dist.get_entry_map(group='console_scripts') + console_scripts = dist.get_entry_map(group="console_scripts") for name in console_scripts.keys(): _scripts_to_remove.extend(_script_names(dist, name, False)) # find gui_scripts - gui_scripts = dist.get_entry_map(group='gui_scripts') + gui_scripts = dist.get_entry_map(group="gui_scripts") for name in gui_scripts.keys(): _scripts_to_remove.extend(_script_names(dist, name, True)) @@ -611,47 +616,43 @@ def add(self, entry): # have more than "\\sever\share". Valid examples: "\\server\share\" or # "\\server\share\folder". Python 2.7.8+ support UNC in splitdrive. if WINDOWS and not os.path.splitdrive(entry)[0]: - entry = entry.replace('\\', '/') + entry = entry.replace("\\", "/") self.entries.add(entry) def remove(self): # type: () -> None - logger.debug('Removing pth entries from %s:', self.file) + logger.debug("Removing pth entries from %s:", self.file) # If the file doesn't exist, log a warning and return if not os.path.isfile(self.file): - logger.warning( - "Cannot remove entries from nonexistent file %s", self.file - ) + logger.warning("Cannot remove entries from nonexistent file %s", self.file) return - with open(self.file, 'rb') as fh: + with open(self.file, "rb") as fh: # windows uses '\r\n' with py3k, but uses '\n' with py2.x lines = fh.readlines() self._saved_lines = lines - if any(b'\r\n' in line for line in lines): - endline = '\r\n' + if any(b"\r\n" in line for line in lines): + endline = "\r\n" else: - endline = '\n' + endline = "\n" # handle missing trailing newline if lines and not lines[-1].endswith(endline.encode("utf-8")): lines[-1] = lines[-1] + endline.encode("utf-8") for entry in self.entries: try: - logger.debug('Removing entry: %s', entry) + logger.debug("Removing entry: %s", entry) lines.remove((entry + endline).encode("utf-8")) except ValueError: pass - with open(self.file, 'wb') as fh: + with open(self.file, "wb") as fh: fh.writelines(lines) def rollback(self): # type: () -> bool if self._saved_lines is None: - logger.error( - 'Cannot roll back changes to %s, none were made', self.file - ) + logger.error("Cannot roll back changes to %s, none were made", self.file) return False - logger.debug('Rolling %s back to previous state', self.file) - with open(self.file, 'wb') as fh: + logger.debug("Rolling %s back to previous state", self.file) + with open(self.file, "wb") as fh: fh.writelines(self._saved_lines) return True diff --git a/src/pip/_internal/resolution/base.py b/src/pip/_internal/resolution/base.py index 6d50555e531..451212a4889 100644 --- a/src/pip/_internal/resolution/base.py +++ b/src/pip/_internal/resolution/base.py @@ -6,9 +6,7 @@ from pip._internal.req.req_install import InstallRequirement from pip._internal.req.req_set import RequirementSet - InstallRequirementProvider = Callable[ - [str, InstallRequirement], InstallRequirement - ] + InstallRequirementProvider = Callable[[str, InstallRequirement], InstallRequirement] class BaseResolver(object): diff --git a/src/pip/_internal/resolution/legacy/resolver.py b/src/pip/_internal/resolution/legacy/resolver.py index 6ef00bba19d..114e9d0a404 100644 --- a/src/pip/_internal/resolution/legacy/resolver.py +++ b/src/pip/_internal/resolution/legacy/resolver.py @@ -34,10 +34,7 @@ from pip._internal.utils.compatibility_tags import get_supported from pip._internal.utils.logging import indent_log from pip._internal.utils.misc import dist_in_usersite, normalize_version_info -from pip._internal.utils.packaging import ( - check_requires_python, - get_requires_python, -) +from pip._internal.utils.packaging import check_requires_python, get_requires_python from pip._internal.utils.typing import MYPY_CHECK_RUNNING if MYPY_CHECK_RUNNING: @@ -78,31 +75,37 @@ def _check_dist_requires_python( requires_python = get_requires_python(dist) try: is_compatible = check_requires_python( - requires_python, version_info=version_info, + requires_python, + version_info=version_info, ) except specifiers.InvalidSpecifier as exc: logger.warning( "Package %r has an invalid Requires-Python: %s", - dist.project_name, exc, + dist.project_name, + exc, ) return if is_compatible: return - version = '.'.join(map(str, version_info)) + version = ".".join(map(str, version_info)) if ignore_requires_python: logger.debug( - 'Ignoring failed Requires-Python check for package %r: ' - '%s not in %r', - dist.project_name, version, requires_python, + "Ignoring failed Requires-Python check for package %r: " "%s not in %r", + dist.project_name, + version, + requires_python, ) return raise UnsupportedPythonVersion( - 'Package {!r} requires a different Python: {} not in {!r}'.format( - dist.project_name, version, requires_python, - )) + "Package {!r} requires a different Python: {} not in {!r}".format( + dist.project_name, + version, + requires_python, + ) + ) class Resolver(BaseResolver): @@ -149,8 +152,9 @@ def __init__( self.use_user_site = use_user_site self._make_install_req = make_install_req - self._discovered_dependencies = \ - defaultdict(list) # type: DiscoveredDependencies + self._discovered_dependencies = defaultdict( + list + ) # type: DiscoveredDependencies def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet @@ -164,9 +168,7 @@ def resolve(self, root_reqs, check_supported_wheels): possible to move the preparation to become a step separated from dependency resolution. """ - requirement_set = RequirementSet( - check_supported_wheels=check_supported_wheels - ) + requirement_set = RequirementSet(check_supported_wheels=check_supported_wheels) for req in root_reqs: if req.constraint: check_invalid_constraint_type(req) @@ -243,8 +245,8 @@ def _check_skip_installed(self, req_to_install): if not self._is_upgrade_allowed(req_to_install): if self.upgrade_strategy == "only-if-needed": - return 'already satisfied, skipping upgrade' - return 'already satisfied' + return "already satisfied, skipping upgrade" + return "already satisfied" # Check for the possibility of an upgrade. For link-based # requirements we have to pull the tree down and inspect to assess @@ -254,7 +256,7 @@ def _check_skip_installed(self, req_to_install): self.finder.find_requirement(req_to_install, upgrade=True) except BestVersionAlreadyInstalled: # Then the best version is installed. - return 'already up-to-date' + return "already up-to-date" except DistributionNotFound: # No distribution found, so we squash the error. It will # be raised later when we re-try later to do the install. @@ -274,14 +276,14 @@ def _find_requirement_link(self, req): # Log a warning per PEP 592 if necessary before returning. link = best_candidate.link if link.is_yanked: - reason = link.yanked_reason or '' + reason = link.yanked_reason or "" msg = ( # Mark this as a unicode string to prevent # "UnicodeEncodeError: 'ascii' codec can't encode character" # in Python 2 when the reason contains non-ascii characters. - u'The candidate selected for download or install is a ' - 'yanked version: {candidate}\n' - 'Reason for being yanked: {reason}' + u"The candidate selected for download or install is a " + "yanked version: {candidate}\n" + "Reason for being yanked: {reason}" ).format(candidate=best_candidate, reason=reason) logger.warning(msg) @@ -312,7 +314,7 @@ def _populate_link(self, req): supported_tags=get_supported(), ) if cache_entry is not None: - logger.debug('Using cached wheel link: %s', cache_entry.link) + logger.debug("Using cached wheel link: %s", cache_entry.link) if req.link is req.original_link and cache_entry.persistent: req.original_link_is_in_wheel_cache = True req.link = cache_entry.link @@ -331,9 +333,7 @@ def _get_dist_for(self, req): skip_reason = self._check_skip_installed(req) if req.satisfied_by: - return self.preparer.prepare_installed_requirement( - req, skip_reason - ) + return self.preparer.prepare_installed_requirement(req, skip_reason) # We eagerly populate the link, since that's our "legacy" behavior. self._populate_link(req) @@ -352,17 +352,17 @@ def _get_dist_for(self, req): if req.satisfied_by: should_modify = ( - self.upgrade_strategy != "to-satisfy-only" or - self.force_reinstall or - self.ignore_installed or - req.link.scheme == 'file' + self.upgrade_strategy != "to-satisfy-only" + or self.force_reinstall + or self.ignore_installed + or req.link.scheme == "file" ) if should_modify: self._set_req_to_reinstall(req) else: logger.info( - 'Requirement already satisfied (use --upgrade to upgrade):' - ' %s', req, + "Requirement already satisfied (use --upgrade to upgrade):" " %s", + req, ) return dist @@ -389,7 +389,8 @@ def _resolve_one( # This will raise UnsupportedPythonVersion if the given Python # version isn't compatible with the distribution's Requires-Python. _check_dist_requires_python( - dist, version_info=self._py_version_info, + dist, + version_info=self._py_version_info, ignore_requires_python=self.ignore_requires_python, ) @@ -407,9 +408,7 @@ def add_req(subreq, extras_requested): extras_requested=extras_requested, ) if parent_req_name and add_to_parent: - self._discovered_dependencies[parent_req_name].append( - add_to_parent - ) + self._discovered_dependencies[parent_req_name].append(add_to_parent) more_reqs.extend(to_scan_again) with indent_log(): @@ -421,23 +420,21 @@ def add_req(subreq, extras_requested): # provided by the user. assert req_to_install.user_supplied requirement_set.add_requirement( - req_to_install, parent_req_name=None, + req_to_install, + parent_req_name=None, ) if not self.ignore_dependencies: if req_to_install.extras: logger.debug( "Installing extra requirements: %r", - ','.join(req_to_install.extras), + ",".join(req_to_install.extras), ) missing_requested = sorted( set(req_to_install.extras) - set(dist.extras) ) for missing in missing_requested: - logger.warning( - "%s does not provide the extra '%s'", - dist, missing - ) + logger.warning("%s does not provide the extra '%s'", dist, missing) available_requested = sorted( set(dist.extras) & set(req_to_install.extras) diff --git a/src/pip/_internal/resolution/resolvelib/candidates.py b/src/pip/_internal/resolution/resolvelib/candidates.py index ff2b336d9e0..3e6519e9fcf 100644 --- a/src/pip/_internal/resolution/resolvelib/candidates.py +++ b/src/pip/_internal/resolution/resolvelib/candidates.py @@ -56,7 +56,7 @@ def make_install_req_from_link(link, template): options=dict( install_options=template.install_options, global_options=template.global_options, - hashes=template.hash_options + hashes=template.hash_options, ), ) ireq.original_link = template.original_link @@ -77,7 +77,7 @@ def make_install_req_from_editable(link, template): options=dict( install_options=template.install_options, global_options=template.global_options, - hashes=template.hash_options + hashes=template.hash_options, ), ) @@ -101,7 +101,7 @@ def make_install_req_from_dist(dist, template): options=dict( install_options=template.install_options, global_options=template.global_options, - hashes=template.hash_options + hashes=template.hash_options, ), ) ireq.satisfied_by = dist @@ -123,15 +123,16 @@ class exposes appropriate information to the resolver. ``link`` would point to the wheel cache, while this points to the found remote link (e.g. from pypi.org). """ + is_installed = False def __init__( self, - link, # type: Link - source_link, # type: Link - ireq, # type: InstallRequirement - factory, # type: Factory - name=None, # type: Optional[str] + link, # type: Link + source_link, # type: Link + ireq, # type: InstallRequirement + factory, # type: Factory + name=None, # type: Optional[str] version=None, # type: Optional[_BaseVersion] ): # type: (...) -> None @@ -190,7 +191,7 @@ def format_for_error(self): return "{} {} (from {})".format( self.name, self.version, - self._link.file_path if self._link.is_file else self._link + self._link.file_path if self._link.is_file else self._link, ) def _prepare_distribution(self): @@ -261,10 +262,10 @@ class LinkCandidate(_InstallRequirementBackedCandidate): def __init__( self, - link, # type: Link - template, # type: InstallRequirement - factory, # type: Factory - name=None, # type: Optional[str] + link, # type: Link + template, # type: InstallRequirement + factory, # type: Factory + name=None, # type: Optional[str] version=None, # type: Optional[_BaseVersion] ): # type: (...) -> None @@ -278,20 +279,18 @@ def __init__( if ireq.link.is_wheel and not ireq.link.is_file: wheel = Wheel(ireq.link.filename) wheel_name = canonicalize_name(wheel.name) - assert name == wheel_name, ( - "{!r} != {!r} for wheel".format(name, wheel_name) - ) + assert name == wheel_name, "{!r} != {!r} for wheel".format(name, wheel_name) # Version may not be present for PEP 508 direct URLs if version is not None: - assert str(version) == wheel.version, ( - "{!r} != {!r} for wheel {}".format( - version, wheel.version, name - ) - ) - - if (cache_entry is not None and - cache_entry.persistent and - template.link is template.original_link): + assert ( + str(version) == wheel.version + ), "{!r} != {!r} for wheel {}".format(version, wheel.version, name) + + if ( + cache_entry is not None + and cache_entry.persistent + and template.link is template.original_link + ): ireq.original_link_is_in_wheel_cache = True super(LinkCandidate, self).__init__( @@ -306,7 +305,8 @@ def __init__( def _prepare_distribution(self): # type: () -> Distribution return self._factory.preparer.prepare_linked_requirement( - self._ireq, parallel_builds=True, + self._ireq, + parallel_builds=True, ) @@ -315,10 +315,10 @@ class EditableCandidate(_InstallRequirementBackedCandidate): def __init__( self, - link, # type: Link - template, # type: InstallRequirement - factory, # type: Factory - name=None, # type: Optional[str] + link, # type: Link + template, # type: InstallRequirement + factory, # type: Factory + name=None, # type: Optional[str] version=None, # type: Optional[_BaseVersion] ): # type: (...) -> None @@ -435,6 +435,7 @@ class ExtrasCandidate(Candidate): version 2.0. Having those candidates depend on foo=1.0 and foo=2.0 respectively forces the resolver to recognise that this is a conflict. """ + def __init__( self, base, # type: BaseCandidate @@ -481,8 +482,7 @@ def version(self): def format_for_error(self): # type: () -> str return "{} [{}]".format( - self.base.format_for_error(), - ", ".join(sorted(self.extras)) + self.base.format_for_error(), ", ".join(sorted(self.extras)) ) @property @@ -519,12 +519,14 @@ def iter_dependencies(self, with_requires): "%s %s does not provide the extra '%s'", self.base.name, self.version, - extra + extra, ) for r in self.base.dist.requires(valid_extras): requirement = factory.make_requirement_from_spec( - str(r), self.base._ireq, valid_extras, + str(r), + self.base._ireq, + valid_extras, ) if requirement: yield requirement diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py index 96e2d53314d..f55f4e14b41 100644 --- a/src/pip/_internal/resolution/resolvelib/factory.py +++ b/src/pip/_internal/resolution/resolvelib/factory.py @@ -136,13 +136,21 @@ def _make_candidate_from_link( if template.editable: if link not in self._editable_candidate_cache: self._editable_candidate_cache[link] = EditableCandidate( - link, template, factory=self, name=name, version=version, + link, + template, + factory=self, + name=name, + version=version, ) base = self._editable_candidate_cache[link] # type: BaseCandidate else: if link not in self._link_candidate_cache: self._link_candidate_cache[link] = LinkCandidate( - link, template, factory=self, name=name, version=version, + link, + template, + factory=self, + name=name, + version=version, ) base = self._link_candidate_cache[link] if extras: @@ -246,7 +254,8 @@ def find_candidates(self, requirements, constraint): ) return ( - c for c in explicit_candidates + c + for c in explicit_candidates if all(req.is_satisfied_by(c) for req in requirements) ) @@ -255,7 +264,8 @@ def make_requirement_from_install_req(self, ireq, requested_extras): if not ireq.match_markers(requested_extras): logger.info( "Ignoring %s: markers '%s' don't match your environment", - ireq.name, ireq.markers, + ireq.name, + ireq.markers, ) return None if not ireq.link: @@ -339,7 +349,8 @@ def get_dist_to_uninstall(self, candidate): raise InstallationError( "Will not install to the user site because it will " "lack sys.path precedence to {} in {}".format( - dist.project_name, dist.location, + dist.project_name, + dist.location, ) ) return None @@ -385,13 +396,13 @@ def get_installation_error(self, e): if parent is None: req_disp = str(req) else: - req_disp = '{} (from {})'.format(req, parent.name) + req_disp = "{} (from {})".format(req, parent.name) logger.critical( "Could not find a version that satisfies the requirement %s", req_disp, ) return DistributionNotFound( - 'No matching distribution found for {}'.format(req) + "No matching distribution found for {}".format(req) ) # OK, we now have a list of requirements that can't all be @@ -428,26 +439,28 @@ def describe_trigger(parent): else: info = "the requested packages" - msg = "Cannot install {} because these package versions " \ + msg = ( + "Cannot install {} because these package versions " "have conflicting dependencies.".format(info) + ) logger.critical(msg) msg = "\nThe conflict is caused by:" for req, parent in e.causes: msg = msg + "\n " if parent: - msg = msg + "{} {} depends on ".format( - parent.name, - parent.version - ) + msg = msg + "{} {} depends on ".format(parent.name, parent.version) else: msg = msg + "The user requested " msg = msg + req.format_for_error() - msg = msg + "\n\n" + \ - "To fix this you could try to:\n" + \ - "1. loosen the range of package versions you've specified\n" + \ - "2. remove package versions to allow pip attempt to solve " + \ - "the dependency conflict\n" + msg = ( + msg + + "\n\n" + + "To fix this you could try to:\n" + + "1. loosen the range of package versions you've specified\n" + + "2. remove package versions to allow pip attempt to solve " + + "the dependency conflict\n" + ) logger.info(msg) diff --git a/src/pip/_internal/resolution/resolvelib/provider.py b/src/pip/_internal/resolution/resolvelib/provider.py index 99f99bfc212..e31481702f4 100644 --- a/src/pip/_internal/resolution/resolvelib/provider.py +++ b/src/pip/_internal/resolution/resolvelib/provider.py @@ -5,16 +5,7 @@ from .base import Constraint if MYPY_CHECK_RUNNING: - from typing import ( - Any, - Dict, - Iterable, - Optional, - Sequence, - Set, - Tuple, - Union, - ) + from typing import Any, Dict, Iterable, Optional, Sequence, Set, Tuple, Union from .base import Candidate, Requirement from .factory import Factory @@ -93,7 +84,7 @@ def _eligible_for_upgrade(name): if self._upgrade_strategy == "eager": return True elif self._upgrade_strategy == "only-if-needed": - return (name in self.user_requested) + return name in self.user_requested return False def sort_key(c): @@ -124,7 +115,7 @@ def get_preference( self, resolution, # type: Optional[Candidate] candidates, # type: Sequence[Candidate] - information # type: Sequence[Tuple[Requirement, Candidate]] + information, # type: Sequence[Tuple[Requirement, Candidate]] ): # type: (...) -> Any # Use the "usual" value for now @@ -135,7 +126,8 @@ def find_matches(self, requirements): if not requirements: return [] constraint = self._constraints.get( - requirements[0].name, Constraint.empty(), + requirements[0].name, + Constraint.empty(), ) candidates = self._factory.find_candidates(requirements, constraint) return reversed(self._sort_matches(candidates)) @@ -147,8 +139,4 @@ def is_satisfied_by(self, requirement, candidate): def get_dependencies(self, candidate): # type: (Candidate) -> Sequence[Requirement] with_requires = not self._ignore_dependencies - return [ - r - for r in candidate.iter_dependencies(with_requires) - if r is not None - ] + return [r for r in candidate.iter_dependencies(with_requires) if r is not None] diff --git a/src/pip/_internal/resolution/resolvelib/requirements.py b/src/pip/_internal/resolution/resolvelib/requirements.py index bc1061f4303..17d9a766ab1 100644 --- a/src/pip/_internal/resolution/resolvelib/requirements.py +++ b/src/pip/_internal/resolution/resolvelib/requirements.py @@ -88,9 +88,11 @@ def get_candidate_lookup(self): def is_satisfied_by(self, candidate): # type: (Candidate) -> bool - assert candidate.name == self.name, \ - "Internal issue: Candidate is not for this requirement " \ - " {} vs {}".format(candidate.name, self.name) + assert ( + candidate.name == self.name + ), "Internal issue: Candidate is not for this requirement " " {} vs {}".format( + candidate.name, self.name + ) # We can safely always allow prereleases here since PackageFinder # already implements the prerelease logic, and would have filtered out # prerelease candidates if the user does not expect them. @@ -99,8 +101,8 @@ def is_satisfied_by(self, candidate): class RequiresPythonRequirement(Requirement): - """A requirement representing Requires-Python metadata. - """ + """A requirement representing Requires-Python metadata.""" + def __init__(self, specifier, match): # type: (SpecifierSet, Candidate) -> None self.specifier = specifier diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py index cb7d1ae8a59..81512189334 100644 --- a/src/pip/_internal/resolution/resolvelib/resolver.py +++ b/src/pip/_internal/resolution/resolvelib/resolver.py @@ -91,7 +91,8 @@ def resolve(self, root_reqs, check_supported_wheels): if req.user_supplied and req.name: user_requested.add(canonicalize_name(req.name)) r = self.factory.make_requirement_from_install_req( - req, requested_extras=(), + req, + requested_extras=(), ) if r is not None: requirements.append(r) @@ -109,7 +110,8 @@ def resolve(self, root_reqs, check_supported_wheels): try: try_to_avoid_resolution_too_deep = 2000000 self._result = resolver.resolve( - requirements, max_rounds=try_to_avoid_resolution_too_deep, + requirements, + max_rounds=try_to_avoid_resolution_too_deep, ) except ResolutionImpossible as e: @@ -147,14 +149,14 @@ def resolve(self, root_reqs, check_supported_wheels): # The reason can contain non-ASCII characters, Unicode # is required for Python 2. msg = ( - u'The candidate selected for download or install is a ' - u'yanked version: {name!r} candidate (version {version} ' - u'at {link})\nReason for being yanked: {reason}' + u"The candidate selected for download or install is a " + u"yanked version: {name!r} candidate (version {version} " + u"at {link})\nReason for being yanked: {reason}" ).format( name=candidate.name, version=candidate.version, link=link, - reason=link.yanked_reason or u'', + reason=link.yanked_reason or u"", ) logger.warning(msg) @@ -237,7 +239,7 @@ def visit(node): def _req_set_item_sorter( - item, # type: Tuple[str, InstallRequirement] + item, # type: Tuple[str, InstallRequirement] weights, # type: Dict[Optional[str], int] ): # type: (...) -> Tuple[int, str] diff --git a/src/pip/_internal/self_outdated_check.py b/src/pip/_internal/self_outdated_check.py index fbd9dfd48b7..2f7a57f74df 100644 --- a/src/pip/_internal/self_outdated_check.py +++ b/src/pip/_internal/self_outdated_check.py @@ -13,16 +13,8 @@ from pip._internal.index.collector import LinkCollector from pip._internal.index.package_finder import PackageFinder from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.utils.filesystem import ( - adjacent_tmp_file, - check_path_owner, - replace, -) -from pip._internal.utils.misc import ( - ensure_dir, - get_distribution, - get_installed_version, -) +from pip._internal.utils.filesystem import adjacent_tmp_file, check_path_owner, replace +from pip._internal.utils.misc import ensure_dir, get_distribution, get_installed_version from pip._internal.utils.packaging import get_installer from pip._internal.utils.typing import MYPY_CHECK_RUNNING @@ -141,8 +133,7 @@ def pip_self_version_check(session, options): # Determine if we need to refresh the state if "last_check" in state.state and "pypi_version" in state.state: last_check = datetime.datetime.strptime( - state.state["last_check"], - SELFCHECK_DATE_FMT + state.state["last_check"], SELFCHECK_DATE_FMT ) if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: pypi_version = state.state["pypi_version"] @@ -178,9 +169,9 @@ def pip_self_version_check(session, options): remote_version = packaging_version.parse(pypi_version) local_version_is_older = ( - pip_version < remote_version and - pip_version.base_version != remote_version.base_version and - was_installed_by_pip('pip') + pip_version < remote_version + and pip_version.base_version != remote_version.base_version + and was_installed_by_pip("pip") ) # Determine if our pypi_version is older @@ -196,7 +187,9 @@ def pip_self_version_check(session, options): "You are using pip version %s; however, version %s is " "available.\nYou should consider upgrading via the " "'%s install --upgrade pip' command.", - pip_version, pypi_version, pip_cmd + pip_version, + pypi_version, + pip_cmd, ) except Exception: logger.debug( diff --git a/src/pip/_internal/utils/appdirs.py b/src/pip/_internal/utils/appdirs.py index 3989ed31c3a..494d1681e62 100644 --- a/src/pip/_internal/utils/appdirs.py +++ b/src/pip/_internal/utils/appdirs.py @@ -27,7 +27,7 @@ def user_config_dir(appname, roaming=True): # type: (str, bool) -> str path = _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming) if _appdirs.system == "darwin" and not os.path.isdir(path): - path = os.path.expanduser('~/.config/') + path = os.path.expanduser("~/.config/") if appname: path = os.path.join(path, appname) return path @@ -40,5 +40,5 @@ def site_config_dirs(appname): dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True) if _appdirs.system not in ["win32", "darwin"]: # always look in /etc directly as well - return dirval.split(os.pathsep) + ['/etc'] + return dirval.split(os.pathsep) + ["/etc"] return [dirval] diff --git a/src/pip/_internal/utils/compat.py b/src/pip/_internal/utils/compat.py index cc63536783c..b25367710ee 100644 --- a/src/pip/_internal/utils/compat.py +++ b/src/pip/_internal/utils/compat.py @@ -27,13 +27,20 @@ from pip._vendor import ipaddress # type: ignore except ImportError: import ipaddr as ipaddress # type: ignore + ipaddress.ip_address = ipaddress.IPAddress # type: ignore ipaddress.ip_network = ipaddress.IPNetwork # type: ignore __all__ = [ - "ipaddress", "uses_pycache", "console_to_str", - "get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile", "get_terminal_size", + "ipaddress", + "uses_pycache", + "console_to_str", + "get_path_uid", + "stdlib_pkgs", + "WINDOWS", + "samefile", + "get_terminal_size", ] @@ -65,6 +72,7 @@ def backslashreplace_decode_fn(err): # Python 2 gave us characters - convert to numeric bytes raw_bytes = (ord(b) for b in raw_bytes) return u"".join(map(u"\\x{:x}".format, raw_bytes)), err.end + codecs.register_error( "backslashreplace_decode", backslashreplace_decode_fn, @@ -78,11 +86,13 @@ def has_tls(): # type: () -> bool try: import _ssl # noqa: F401 # ignore unused + return True except ImportError: pass from pip._vendor.urllib3.util import IS_PYOPENSSL + return IS_PYOPENSSL @@ -122,8 +132,8 @@ def str_to_display(data, desc=None): decoded_data = data.decode(encoding) except UnicodeDecodeError: logger.warning( - '%s does not appear to be encoded as %s', - desc or 'Bytes object', + "%s does not appear to be encoded as %s", + desc or "Bytes object", encoding, ) decoded_data = data.decode(encoding, errors=backslashreplace_decode) @@ -140,14 +150,10 @@ def str_to_display(data, desc=None): # or doesn't have an encoding attribute. Neither of these cases # should occur in normal pip use, but there's no harm in checking # in case people use pip in (unsupported) unusual situations. - output_encoding = getattr(getattr(sys, "__stderr__", None), - "encoding", None) + output_encoding = getattr(getattr(sys, "__stderr__", None), "encoding", None) if output_encoding: - output_encoded = decoded_data.encode( - output_encoding, - errors="backslashreplace" - ) + output_encoded = decoded_data.encode(output_encoding, errors="backslashreplace") decoded_data = output_encoded.decode(output_encoding) return decoded_data @@ -155,9 +161,8 @@ def str_to_display(data, desc=None): def console_to_str(data): # type: (bytes) -> Text - """Return a string, safe for output, of subprocess output. - """ - return str_to_display(data, desc='Subprocess output') + """Return a string, safe for output, of subprocess output.""" + return str_to_display(data, desc="Subprocess output") def get_path_uid(path): @@ -173,7 +178,7 @@ def get_path_uid(path): :raises OSError: When path is a symlink or can't be read. """ - if hasattr(os, 'O_NOFOLLOW'): + if hasattr(os, "O_NOFOLLOW"): fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) file_uid = os.fstat(fd).st_uid os.close(fd) @@ -185,8 +190,7 @@ def get_path_uid(path): else: # raise OSError for parity with os.O_NOFOLLOW above raise OSError( - "{} is a symlink; Will not return uid for symlinks".format( - path) + "{} is a symlink; Will not return uid for symlinks".format(path) ) return file_uid @@ -199,7 +203,7 @@ def expanduser(path): Includes a workaround for https://bugs.python.org/issue14768 """ expanded = os.path.expanduser(path) - if path.startswith('~/') and expanded.startswith('//'): + if path.startswith("~/") and expanded.startswith("//"): expanded = expanded[1:] return expanded @@ -213,14 +217,13 @@ def expanduser(path): # windows detection, covers cpython and ironpython -WINDOWS = (sys.platform.startswith("win") or - (sys.platform == 'cli' and os.name == 'nt')) +WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt") def samefile(file1, file2): # type: (str, str) -> bool """Provide an alternative for os.path.samefile on Windows/Python2""" - if hasattr(os.path, 'samefile'): + if hasattr(os.path, "samefile"): return os.path.samefile(file1, file2) else: path1 = os.path.normcase(os.path.abspath(file1)) @@ -228,7 +231,8 @@ def samefile(file1, file2): return path1 == path2 -if hasattr(shutil, 'get_terminal_size'): +if hasattr(shutil, "get_terminal_size"): + def get_terminal_size(): # type: () -> Tuple[int, int] """ @@ -236,27 +240,32 @@ def get_terminal_size(): in characters of the terminal window. """ return tuple(shutil.get_terminal_size()) # type: ignore + + else: + def get_terminal_size(): # type: () -> Tuple[int, int] """ Returns a tuple (x, y) representing the width(x) and the height(y) in characters of the terminal window. """ + def ioctl_GWINSZ(fd): try: import fcntl import struct import termios + cr = struct.unpack_from( - 'hh', - fcntl.ioctl(fd, termios.TIOCGWINSZ, '12345678') + "hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "12345678") ) except Exception: return None if cr == (0, 0): return None return cr + cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) if not cr: if sys.platform != "win32": @@ -267,5 +276,5 @@ def ioctl_GWINSZ(fd): except Exception: pass if not cr: - cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) + cr = (os.environ.get("LINES", 25), os.environ.get("COLUMNS", 80)) return int(cr[1]), int(cr[0]) diff --git a/src/pip/_internal/utils/compatibility_tags.py b/src/pip/_internal/utils/compatibility_tags.py index 4f21874ec6b..e0aa055abc3 100644 --- a/src/pip/_internal/utils/compatibility_tags.py +++ b/src/pip/_internal/utils/compatibility_tags.py @@ -22,13 +22,13 @@ from pip._vendor.packaging.tags import PythonVersion -_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') +_osx_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)") def version_info_to_nodot(version_info): # type: (Tuple[int, ...]) -> str # Only use up to the first two numbers. - return ''.join(map(str, version_info[:2])) + return "".join(map(str, version_info[:2])) def _mac_platforms(arch): @@ -43,7 +43,7 @@ def _mac_platforms(arch): # actual prefix provided by the user in case they provided # something like "macosxcustom_". It may be good to remove # this as undocumented or deprecate it in the future. - '{}_{}'.format(name, arch[len('macosx_'):]) + "{}_{}".format(name, arch[len("macosx_") :]) for arch in mac_platforms(mac_version, actual_arch) ] else: @@ -55,31 +55,31 @@ def _mac_platforms(arch): def _custom_manylinux_platforms(arch): # type: (str) -> List[str] arches = [arch] - arch_prefix, arch_sep, arch_suffix = arch.partition('_') - if arch_prefix == 'manylinux2014': + arch_prefix, arch_sep, arch_suffix = arch.partition("_") + if arch_prefix == "manylinux2014": # manylinux1/manylinux2010 wheels run on most manylinux2014 systems # with the exception of wheels depending on ncurses. PEP 599 states # manylinux1/manylinux2010 wheels should be considered # manylinux2014 wheels: # https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels - if arch_suffix in {'i686', 'x86_64'}: - arches.append('manylinux2010' + arch_sep + arch_suffix) - arches.append('manylinux1' + arch_sep + arch_suffix) - elif arch_prefix == 'manylinux2010': + if arch_suffix in {"i686", "x86_64"}: + arches.append("manylinux2010" + arch_sep + arch_suffix) + arches.append("manylinux1" + arch_sep + arch_suffix) + elif arch_prefix == "manylinux2010": # manylinux1 wheels run on most manylinux2010 systems with the # exception of wheels depending on ncurses. PEP 571 states # manylinux1 wheels should be considered manylinux2010 wheels: # https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels - arches.append('manylinux1' + arch_sep + arch_suffix) + arches.append("manylinux1" + arch_sep + arch_suffix) return arches def _get_custom_platforms(arch): # type: (str) -> List[str] - arch_prefix, arch_sep, arch_suffix = arch.partition('_') - if arch.startswith('macosx'): + arch_prefix, arch_sep, arch_suffix = arch.partition("_") + if arch.startswith("macosx"): arches = _mac_platforms(arch) - elif arch_prefix in ['manylinux2014', 'manylinux2010']: + elif arch_prefix in ["manylinux2014", "manylinux2010"]: arches = _custom_manylinux_platforms(arch) else: arches = [arch] @@ -107,7 +107,7 @@ def get_supported( version=None, # type: Optional[str] platform=None, # type: Optional[str] impl=None, # type: Optional[str] - abi=None # type: Optional[str] + abi=None, # type: Optional[str] ): # type: (...) -> List[Tag] """Return a list of supported tags for each version specified in diff --git a/src/pip/_internal/utils/deprecation.py b/src/pip/_internal/utils/deprecation.py index 2f20cfd49d3..c8a988a95b3 100644 --- a/src/pip/_internal/utils/deprecation.py +++ b/src/pip/_internal/utils/deprecation.py @@ -34,7 +34,12 @@ def _showwarning(message, category, filename, lineno, file=None, line=None): if file is not None: if _original_showwarning is not None: _original_showwarning( - message, category, filename, lineno, file, line, + message, + category, + filename, + lineno, + file, + line, ) elif issubclass(category, PipDeprecationWarning): # We use a specially named logger which will handle all of the @@ -43,7 +48,12 @@ def _showwarning(message, category, filename, lineno, file=None, line=None): logger.warning(message) else: _original_showwarning( - message, category, filename, lineno, file, line, + message, + category, + filename, + lineno, + file, + line, ) @@ -88,10 +98,13 @@ def deprecated(reason, replacement, gone_in, issue=None): (reason, DEPRECATION_MSG_PREFIX + "{}"), (gone_in, "pip {} will remove support for this functionality."), (replacement, "A possible replacement is {}."), - (issue, ( - "You can find discussion regarding this at " - "https://github.com/pypa/pip/issues/{}." - )), + ( + issue, + ( + "You can find discussion regarding this at " + "https://github.com/pypa/pip/issues/{}." + ), + ), ] message = " ".join( template.format(val) for val, template in sentences if val is not None diff --git a/src/pip/_internal/utils/direct_url_helpers.py b/src/pip/_internal/utils/direct_url_helpers.py index a355a6c5ee4..1ef7c8fa47e 100644 --- a/src/pip/_internal/utils/direct_url_helpers.py +++ b/src/pip/_internal/utils/direct_url_helpers.py @@ -60,8 +60,8 @@ def direct_url_from_link(link, source_dir=None, link_is_in_wheel_cache=False): if link.is_vcs: vcs_backend = vcs.get_backend_for_scheme(link.scheme) assert vcs_backend - url, requested_revision, _ = ( - vcs_backend.get_url_rev_and_auth(link.url_without_fragment) + url, requested_revision, _ = vcs_backend.get_url_rev_and_auth( + link.url_without_fragment ) # For VCS links, we need to find out and add commit_id. if link_is_in_wheel_cache: @@ -116,11 +116,7 @@ def dist_get_direct_url(dist): return None try: return DirectUrl.from_json(dist.get_metadata(DIRECT_URL_METADATA_NAME)) - except ( - DirectUrlValidationError, - JSONDecodeError, - UnicodeDecodeError - ) as e: + except (DirectUrlValidationError, JSONDecodeError, UnicodeDecodeError) as e: logger.warning( "Error parsing %s for %s: %s", DIRECT_URL_METADATA_NAME, diff --git a/src/pip/_internal/utils/encoding.py b/src/pip/_internal/utils/encoding.py index 42a57535af8..834c49b2407 100644 --- a/src/pip/_internal/utils/encoding.py +++ b/src/pip/_internal/utils/encoding.py @@ -9,16 +9,16 @@ from typing import List, Text, Tuple BOMS = [ - (codecs.BOM_UTF8, 'utf-8'), - (codecs.BOM_UTF16, 'utf-16'), - (codecs.BOM_UTF16_BE, 'utf-16-be'), - (codecs.BOM_UTF16_LE, 'utf-16-le'), - (codecs.BOM_UTF32, 'utf-32'), - (codecs.BOM_UTF32_BE, 'utf-32-be'), - (codecs.BOM_UTF32_LE, 'utf-32-le'), + (codecs.BOM_UTF8, "utf-8"), + (codecs.BOM_UTF16, "utf-16"), + (codecs.BOM_UTF16_BE, "utf-16-be"), + (codecs.BOM_UTF16_LE, "utf-16-le"), + (codecs.BOM_UTF32, "utf-32"), + (codecs.BOM_UTF32_BE, "utf-32-be"), + (codecs.BOM_UTF32_LE, "utf-32-le"), ] # type: List[Tuple[bytes, Text]] -ENCODING_RE = re.compile(br'coding[:=]\s*([-\w.]+)') +ENCODING_RE = re.compile(br"coding[:=]\s*([-\w.]+)") def auto_decode(data): @@ -28,13 +28,13 @@ def auto_decode(data): Fallback to locale.getpreferredencoding(False) like open() on Python3""" for bom, encoding in BOMS: if data.startswith(bom): - return data[len(bom):].decode(encoding) + return data[len(bom) :].decode(encoding) # Lets check the first two lines as in PEP263 - for line in data.split(b'\n')[:2]: - if line[0:1] == b'#' and ENCODING_RE.search(line): + for line in data.split(b"\n")[:2]: + if line[0:1] == b"#" and ENCODING_RE.search(line): result = ENCODING_RE.search(line) assert result is not None - encoding = result.groups()[0].decode('ascii') + encoding = result.groups()[0].decode("ascii") return data.decode(encoding) return data.decode( locale.getpreferredencoding(False) or sys.getdefaultencoding(), diff --git a/src/pip/_internal/utils/filesystem.py b/src/pip/_internal/utils/filesystem.py index 303243fd22f..a679c191a51 100644 --- a/src/pip/_internal/utils/filesystem.py +++ b/src/pip/_internal/utils/filesystem.py @@ -76,7 +76,8 @@ def copy2_fixed(src, dest): else: if is_socket_file: raise shutil.SpecialFileError( - "`{f}` is a socket".format(**locals())) + "`{f}` is a socket".format(**locals()) + ) raise @@ -101,10 +102,10 @@ def adjacent_tmp_file(path, **kwargs): delete=False, dir=os.path.dirname(path), prefix=os.path.basename(path), - suffix='.tmp', + suffix=".tmp", **kwargs ) as f: - result = cast('NamedTemporaryFileResult', f) + result = cast("NamedTemporaryFileResult", f) try: yield result finally: @@ -115,6 +116,7 @@ def adjacent_tmp_file(path, **kwargs): _replace_retry = retry(stop_max_delay=1000, wait_fixed=250) if PY2: + @_replace_retry def replace(src, dest): # type: (str, str) -> None @@ -124,6 +126,7 @@ def replace(src, dest): os.remove(dest) os.rename(src, dest) + else: replace = _replace_retry(os.replace) @@ -143,7 +146,7 @@ def test_writable_dir(path): break # Should never get here, but infinite loops are bad path = parent - if os.name == 'posix': + if os.name == "posix": return os.access(path, os.W_OK) return _test_writable_dir_win(path) @@ -153,10 +156,10 @@ def _test_writable_dir_win(path): # type: (str) -> bool # os.access doesn't work on Windows: http://bugs.python.org/issue2528 # and we can't use tempfile: http://bugs.python.org/issue22107 - basename = 'accesstest_deleteme_fishfingers_custard_' - alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789' + basename = "accesstest_deleteme_fishfingers_custard_" + alphabet = "abcdefghijklmnopqrstuvwxyz0123456789" for _ in range(10): - name = basename + ''.join(random.choice(alphabet) for _ in range(6)) + name = basename + "".join(random.choice(alphabet) for _ in range(6)) file = os.path.join(path, name) try: fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL) @@ -180,9 +183,7 @@ def _test_writable_dir_win(path): return True # This should never be reached - raise EnvironmentError( - 'Unexpected condition testing for writable directory' - ) + raise EnvironmentError("Unexpected condition testing for writable directory") def find_files(path, pattern): diff --git a/src/pip/_internal/utils/filetypes.py b/src/pip/_internal/utils/filetypes.py index daa0ca771b7..a0f9cf3b4fe 100644 --- a/src/pip/_internal/utils/filetypes.py +++ b/src/pip/_internal/utils/filetypes.py @@ -5,12 +5,15 @@ if MYPY_CHECK_RUNNING: from typing import Tuple -WHEEL_EXTENSION = '.whl' -BZ2_EXTENSIONS = ('.tar.bz2', '.tbz') # type: Tuple[str, ...] -XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', - '.tar.lz', '.tar.lzma') # type: Tuple[str, ...] -ZIP_EXTENSIONS = ('.zip', WHEEL_EXTENSION) # type: Tuple[str, ...] -TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar') # type: Tuple[str, ...] -ARCHIVE_EXTENSIONS = ( - ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS -) +WHEEL_EXTENSION = ".whl" +BZ2_EXTENSIONS = (".tar.bz2", ".tbz") # type: Tuple[str, ...] +XZ_EXTENSIONS = ( + ".tar.xz", + ".txz", + ".tlz", + ".tar.lz", + ".tar.lzma", +) # type: Tuple[str, ...] +ZIP_EXTENSIONS = (".zip", WHEEL_EXTENSION) # type: Tuple[str, ...] +TAR_EXTENSIONS = (".tar.gz", ".tgz", ".tar") # type: Tuple[str, ...] +ARCHIVE_EXTENSIONS = ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS diff --git a/src/pip/_internal/utils/hashes.py b/src/pip/_internal/utils/hashes.py index 4d4e26b59f3..1eccaa417a1 100644 --- a/src/pip/_internal/utils/hashes.py +++ b/src/pip/_internal/utils/hashes.py @@ -4,11 +4,7 @@ from pip._vendor.six import iteritems, iterkeys, itervalues -from pip._internal.exceptions import ( - HashMismatch, - HashMissing, - InstallationError, -) +from pip._internal.exceptions import HashMismatch, HashMissing, InstallationError from pip._internal.utils.misc import read_chunks from pip._internal.utils.typing import MYPY_CHECK_RUNNING @@ -16,6 +12,7 @@ from typing import BinaryIO, Dict, Iterator, List, NoReturn from pip._vendor.six import PY3 + if PY3: from hashlib import _Hash else: @@ -24,12 +21,12 @@ # The recommended hash algo of the moment. Change this whenever the state of # the art changes; it won't hurt backward compatibility. -FAVORITE_HASH = 'sha256' +FAVORITE_HASH = "sha256" # Names of hashlib algorithms allowed by the --hash option and ``pip hash`` # Currently, those are the ones at least as collision-resistant as sha256. -STRONG_HASHES = ['sha256', 'sha384', 'sha512'] +STRONG_HASHES = ["sha256", "sha384", "sha512"] class Hashes(object): @@ -37,6 +34,7 @@ class Hashes(object): known-good values """ + def __init__(self, hashes=None): # type: (Dict[str, List[str]]) -> None """ @@ -72,7 +70,7 @@ def digest_count(self): def is_hash_allowed( self, - hash_name, # type: str + hash_name, # type: str hex_digest, # type: str ): # type: (...) -> bool @@ -92,9 +90,7 @@ def check_against_chunks(self, chunks): try: gots[hash_name] = hashlib.new(hash_name) except (ValueError, TypeError): - raise InstallationError( - 'Unknown hash name: {}'.format(hash_name) - ) + raise InstallationError("Unknown hash name: {}".format(hash_name)) for chunk in chunks: for hash in itervalues(gots): @@ -120,7 +116,7 @@ def check_against_file(self, file): def check_against_path(self, path): # type: (str) -> None - with open(path, 'rb') as file: + with open(path, "rb") as file: return self.check_against_file(file) def __nonzero__(self): @@ -140,6 +136,7 @@ class MissingHashes(Hashes): exception showing it to the user. """ + def __init__(self): # type: () -> None """Don't offer the ``hashes`` kwarg.""" diff --git a/src/pip/_internal/utils/inject_securetransport.py b/src/pip/_internal/utils/inject_securetransport.py index 5b93b1d6730..b6863d93405 100644 --- a/src/pip/_internal/utils/inject_securetransport.py +++ b/src/pip/_internal/utils/inject_securetransport.py @@ -22,7 +22,7 @@ def inject_securetransport(): return # Checks for OpenSSL 1.0.1 - if ssl.OPENSSL_VERSION_NUMBER >= 0x1000100f: + if ssl.OPENSSL_VERSION_NUMBER >= 0x1000100F: return try: diff --git a/src/pip/_internal/utils/logging.py b/src/pip/_internal/utils/logging.py index 9a017cf7e33..639a388e71d 100644 --- a/src/pip/_internal/utils/logging.py +++ b/src/pip/_internal/utils/logging.py @@ -52,13 +52,14 @@ _log_state = threading.local() -subprocess_logger = getLogger('pip.subprocessor') +subprocess_logger = getLogger("pip.subprocessor") class BrokenStdoutLoggingError(Exception): """ Raised if BrokenPipeError occurs for the stdout stream while logging. """ + pass @@ -69,21 +70,27 @@ class BrokenStdoutLoggingError(Exception): # https://bugs.python.org/issue19612 # https://bugs.python.org/issue30418 if PY2: + def _is_broken_pipe_error(exc_class, exc): """See the docstring for non-Windows Python 3 below.""" - return (exc_class is IOError and - exc.errno in (errno.EINVAL, errno.EPIPE)) + return exc_class is IOError and exc.errno in (errno.EINVAL, errno.EPIPE) + else: # In Windows, a broken pipe IOError became OSError in Python 3. def _is_broken_pipe_error(exc_class, exc): """See the docstring for non-Windows Python 3 below.""" - return ((exc_class is BrokenPipeError) or # noqa: F821 - (exc_class is OSError and - exc.errno in (errno.EINVAL, errno.EPIPE))) + return (exc_class is BrokenPipeError) or ( # noqa: F821 + exc_class is OSError and exc.errno in (errno.EINVAL, errno.EPIPE) + ) + + elif PY2: + def _is_broken_pipe_error(exc_class, exc): """See the docstring for non-Windows Python 3 below.""" - return (exc_class is IOError and exc.errno == errno.EPIPE) + return exc_class is IOError and exc.errno == errno.EPIPE + + else: # Then we are in the non-Windows Python 3 case. def _is_broken_pipe_error(exc_class, exc): @@ -94,7 +101,7 @@ def _is_broken_pipe_error(exc_class, exc): exc_class: an exception class. exc: an exception instance. """ - return (exc_class is BrokenPipeError) # noqa: F821 + return exc_class is BrokenPipeError # noqa: F821 @contextlib.contextmanager @@ -113,11 +120,10 @@ def indent_log(num=2): def get_indentation(): - return getattr(_log_state, 'indentation', 0) + return getattr(_log_state, "indentation", 0) class IndentingFormatter(logging.Formatter): - def __init__(self, *args, **kwargs): """ A logging.Formatter that obeys the indent_log() context manager. @@ -134,15 +140,15 @@ def get_message_start(self, formatted, levelno): prefix to add to each line). """ if levelno < logging.WARNING: - return '' + return "" if formatted.startswith(DEPRECATION_MSG_PREFIX): # Then the message already has a prefix. We don't want it to # look like "WARNING: DEPRECATION: ...." - return '' + return "" if levelno < logging.ERROR: - return 'WARNING: ' + return "WARNING: " - return 'ERROR: ' + return "ERROR: " def format(self, record): """ @@ -153,22 +159,20 @@ def format(self, record): message_start = self.get_message_start(formatted, record.levelno) formatted = message_start + formatted - prefix = '' + prefix = "" if self.add_timestamp: # TODO: Use Formatter.default_time_format after dropping PY2. t = self.formatTime(record, "%Y-%m-%dT%H:%M:%S") - prefix = '{t},{record.msecs:03.0f} '.format(**locals()) + prefix = "{t},{record.msecs:03.0f} ".format(**locals()) prefix += " " * get_indentation() - formatted = "".join([ - prefix + line - for line in formatted.splitlines(True) - ]) + formatted = "".join([prefix + line for line in formatted.splitlines(True)]) return formatted def _color_wrap(*colors): def wrapped(inp): return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) + return wrapped @@ -207,7 +211,8 @@ def should_color(self): return False real_stream = ( - self.stream if not isinstance(self.stream, colorama.AnsiToWin32) + self.stream + if not isinstance(self.stream, colorama.AnsiToWin32) else self.stream.wrapped ) @@ -240,22 +245,19 @@ def handleError(self, record): # stdout stream in logging's Handler.emit(), then raise our special # exception so we can handle it in main() instead of logging the # broken pipe error and continuing. - if (exc_class and self._using_stdout() and - _is_broken_pipe_error(exc_class, exc)): + if exc_class and self._using_stdout() and _is_broken_pipe_error(exc_class, exc): raise BrokenStdoutLoggingError() return super(ColorizedStreamHandler, self).handleError(record) class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): - def _open(self): ensure_dir(os.path.dirname(self.baseFilename)) return logging.handlers.RotatingFileHandler._open(self) class MaxLevelFilter(Filter): - def __init__(self, level): self.level = level @@ -322,78 +324,76 @@ def setup_logging(verbosity, no_color, user_log_file): ["user_log"] if include_user_log else [] ) - logging.config.dictConfig({ - "version": 1, - "disable_existing_loggers": False, - "filters": { - "exclude_warnings": { - "()": "pip._internal.utils.logging.MaxLevelFilter", - "level": logging.WARNING, - }, - "restrict_to_subprocess": { - "()": "logging.Filter", - "name": subprocess_logger.name, - }, - "exclude_subprocess": { - "()": "pip._internal.utils.logging.ExcludeLoggerFilter", - "name": subprocess_logger.name, + logging.config.dictConfig( + { + "version": 1, + "disable_existing_loggers": False, + "filters": { + "exclude_warnings": { + "()": "pip._internal.utils.logging.MaxLevelFilter", + "level": logging.WARNING, + }, + "restrict_to_subprocess": { + "()": "logging.Filter", + "name": subprocess_logger.name, + }, + "exclude_subprocess": { + "()": "pip._internal.utils.logging.ExcludeLoggerFilter", + "name": subprocess_logger.name, + }, }, - }, - "formatters": { - "indent": { - "()": IndentingFormatter, - "format": "%(message)s", + "formatters": { + "indent": { + "()": IndentingFormatter, + "format": "%(message)s", + }, + "indent_with_timestamp": { + "()": IndentingFormatter, + "format": "%(message)s", + "add_timestamp": True, + }, }, - "indent_with_timestamp": { - "()": IndentingFormatter, - "format": "%(message)s", - "add_timestamp": True, + "handlers": { + "console": { + "level": level, + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stdout"], + "filters": ["exclude_subprocess", "exclude_warnings"], + "formatter": "indent", + }, + "console_errors": { + "level": "WARNING", + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stderr"], + "filters": ["exclude_subprocess"], + "formatter": "indent", + }, + # A handler responsible for logging to the console messages + # from the "subprocessor" logger. + "console_subprocess": { + "level": level, + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stderr"], + "filters": ["restrict_to_subprocess"], + "formatter": "indent", + }, + "user_log": { + "level": "DEBUG", + "class": handler_classes["file"], + "filename": additional_log_file, + "delay": True, + "formatter": "indent_with_timestamp", + }, }, - }, - "handlers": { - "console": { - "level": level, - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stdout"], - "filters": ["exclude_subprocess", "exclude_warnings"], - "formatter": "indent", + "root": { + "level": root_level, + "handlers": handlers, }, - "console_errors": { - "level": "WARNING", - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stderr"], - "filters": ["exclude_subprocess"], - "formatter": "indent", - }, - # A handler responsible for logging to the console messages - # from the "subprocessor" logger. - "console_subprocess": { - "level": level, - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stderr"], - "filters": ["restrict_to_subprocess"], - "formatter": "indent", - }, - "user_log": { - "level": "DEBUG", - "class": handler_classes["file"], - "filename": additional_log_file, - "delay": True, - "formatter": "indent_with_timestamp", - }, - }, - "root": { - "level": root_level, - "handlers": handlers, - }, - "loggers": { - "pip._vendor": { - "level": vendored_log_level - } - }, - }) + "loggers": {"pip._vendor": {"level": vendored_log_level}}, + } + ) return level_number diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py index 289db0e39fd..c7e5cc3751d 100644 --- a/src/pip/_internal/utils/misc.py +++ b/src/pip/_internal/utils/misc.py @@ -20,6 +20,7 @@ from pip._vendor import pkg_resources from pip._vendor.packaging.utils import canonicalize_name + # NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is # why we ignore the type on this import. from pip._vendor.retrying import retry # type: ignore @@ -30,17 +31,8 @@ from pip import __version__ from pip._internal.exceptions import CommandError -from pip._internal.locations import ( - get_major_minor_version, - site_packages, - user_site, -) -from pip._internal.utils.compat import ( - WINDOWS, - expanduser, - stdlib_pkgs, - str_to_display, -) +from pip._internal.locations import get_major_minor_version, site_packages, user_site +from pip._internal.utils.compat import WINDOWS, expanduser, stdlib_pkgs, str_to_display from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast from pip._internal.utils.virtualenv import ( running_under_virtualenv, @@ -74,13 +66,22 @@ T = TypeVar("T") -__all__ = ['rmtree', 'display_path', 'backup_dir', - 'ask', 'splitext', - 'format_size', 'is_installable_dir', - 'normalize_path', - 'renames', 'get_prog', - 'captured_stdout', 'ensure_dir', - 'get_installed_version', 'remove_auth_from_url'] +__all__ = [ + "rmtree", + "display_path", + "backup_dir", + "ask", + "splitext", + "format_size", + "is_installable_dir", + "normalize_path", + "renames", + "get_prog", + "captured_stdout", + "ensure_dir", + "get_installed_version", + "remove_auth_from_url", +] logger = logging.getLogger(__name__) @@ -91,10 +92,10 @@ def get_pip_version(): pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..") pip_pkg_dir = os.path.abspath(pip_pkg_dir) - return ( - 'pip {} from {} (python {})'.format( - __version__, pip_pkg_dir, get_major_minor_version(), - ) + return "pip {} from {} (python {})".format( + __version__, + pip_pkg_dir, + get_major_minor_version(), ) @@ -115,7 +116,7 @@ def normalize_version_info(py_version_info): elif len(py_version_info) > 3: py_version_info = py_version_info[:3] - return cast('VersionInfo', py_version_info) + return cast("VersionInfo", py_version_info) def ensure_dir(path): @@ -133,21 +134,20 @@ def get_prog(): # type: () -> str try: prog = os.path.basename(sys.argv[0]) - if prog in ('__main__.py', '-c'): + if prog in ("__main__.py", "-c"): return "{} -m pip".format(sys.executable) else: return prog except (AttributeError, TypeError, IndexError): pass - return 'pip' + return "pip" # Retry every half second for up to 3 seconds @retry(stop_max_delay=3000, wait_fixed=500) def rmtree(dir, ignore_errors=False): # type: (Text, bool) -> None - shutil.rmtree(dir, ignore_errors=ignore_errors, - onerror=rmtree_errorhandler) + shutil.rmtree(dir, ignore_errors=ignore_errors, onerror=rmtree_errorhandler) def rmtree_errorhandler(func, path, exc_info): @@ -185,7 +185,7 @@ def path_to_display(path): return path # Otherwise, path is a bytes object (str in Python 2). try: - display_path = path.decode(sys.getfilesystemencoding(), 'strict') + display_path = path.decode(sys.getfilesystemencoding(), "strict") except UnicodeDecodeError: # Include the full bytes to make troubleshooting easier, even though # it may not be very human readable. @@ -195,7 +195,7 @@ def path_to_display(path): # Also, we add the prefix "b" to the repr() return value both # to make the Python 2 output look like the Python 3 output, and # to signal to the user that this is a bytes representation. - display_path = str_to_display('b{!r}'.format(path)) + display_path = str_to_display("b{!r}".format(path)) else: # Silence the "F821 undefined name 'ascii'" flake8 error since # in Python 3 ascii() is a built-in. @@ -210,14 +210,14 @@ def display_path(path): if possible.""" path = os.path.normcase(os.path.abspath(path)) if sys.version_info[0] == 2: - path = path.decode(sys.getfilesystemencoding(), 'replace') - path = path.encode(sys.getdefaultencoding(), 'replace') + path = path.decode(sys.getfilesystemencoding(), "replace") + path = path.encode(sys.getdefaultencoding(), "replace") if path.startswith(os.getcwd() + os.path.sep): - path = '.' + path[len(os.getcwd()):] + path = "." + path[len(os.getcwd()) :] return path -def backup_dir(dir, ext='.bak'): +def backup_dir(dir, ext=".bak"): # type: (str, str) -> str """Figure out the name of a directory to back up the given dir to (adding .bak, .bak2, etc)""" @@ -231,7 +231,7 @@ def backup_dir(dir, ext='.bak'): def ask_path_exists(message, options): # type: (str, Iterable[str]) -> str - for action in os.environ.get('PIP_EXISTS_ACTION', '').split(): + for action in os.environ.get("PIP_EXISTS_ACTION", "").split(): if action in options: return action return ask(message, options) @@ -240,10 +240,9 @@ def ask_path_exists(message, options): def _check_no_input(message): # type: (str) -> None """Raise an error if no input is allowed.""" - if os.environ.get('PIP_NO_INPUT'): + if os.environ.get("PIP_NO_INPUT"): raise Exception( - 'No input was expected ($PIP_NO_INPUT set); question: {}'.format( - message) + "No input was expected ($PIP_NO_INPUT set); question: {}".format(message) ) @@ -256,8 +255,8 @@ def ask(message, options): response = response.strip().lower() if response not in options: print( - 'Your response ({!r}) was not one of the expected responses: ' - '{}'.format(response, ', '.join(options)) + "Your response ({!r}) was not one of the expected responses: " + "{}".format(response, ", ".join(options)) ) else: return response @@ -280,13 +279,13 @@ def ask_password(message): def format_size(bytes): # type: (float) -> str if bytes > 1000 * 1000: - return '{:.1f} MB'.format(bytes / 1000.0 / 1000) + return "{:.1f} MB".format(bytes / 1000.0 / 1000) elif bytes > 10 * 1000: - return '{} kB'.format(int(bytes / 1000)) + return "{} kB".format(int(bytes / 1000)) elif bytes > 1000: - return '{:.1f} kB'.format(bytes / 1000.0) + return "{:.1f} kB".format(bytes / 1000.0) else: - return '{} bytes'.format(int(bytes)) + return "{} bytes".format(int(bytes)) def tabulate(rows): @@ -299,21 +298,20 @@ def tabulate(rows): (['foobar 2000', '3735928559'], [10, 4]) """ rows = [tuple(map(str, row)) for row in rows] - sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue='')] + sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue="")] table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows] return table, sizes def is_installable_dir(path): # type: (str) -> bool - """Is path is a directory containing setup.py or pyproject.toml? - """ + """Is path is a directory containing setup.py or pyproject.toml?""" if not os.path.isdir(path): return False - setup_py = os.path.join(path, 'setup.py') + setup_py = os.path.join(path, "setup.py") if os.path.isfile(setup_py): return True - pyproject_toml = os.path.join(path, 'pyproject.toml') + pyproject_toml = os.path.join(path, "pyproject.toml") if os.path.isfile(pyproject_toml): return True return False @@ -346,7 +344,7 @@ def splitext(path): # type: (str) -> Tuple[str, str] """Like os.path.splitext, but take off .tar too""" base, ext = posixpath.splitext(path) - if base.lower().endswith('.tar'): + if base.lower().endswith(".tar"): ext = base[-4:] + ext base = base[:-4] return base, ext @@ -420,19 +418,19 @@ def dist_is_editable(dist): Return True if given Distribution is an editable install. """ for path_item in sys.path: - egg_link = os.path.join(path_item, dist.project_name + '.egg-link') + egg_link = os.path.join(path_item, dist.project_name + ".egg-link") if os.path.isfile(egg_link): return True return False def get_installed_distributions( - local_only=True, # type: bool - skip=stdlib_pkgs, # type: Container[str] - include_editables=True, # type: bool - editables_only=False, # type: bool - user_only=False, # type: bool - paths=None # type: Optional[List[str]] + local_only=True, # type: bool + skip=stdlib_pkgs, # type: Container[str] + include_editables=True, # type: bool + editables_only=False, # type: bool + user_only=False, # type: bool + paths=None, # type: Optional[List[str]] ): # type: (...) -> List[Distribution] """ @@ -462,36 +460,46 @@ def get_installed_distributions( if local_only: local_test = dist_is_local else: + def local_test(d): return True if include_editables: + def editable_test(d): return True + else: + def editable_test(d): return not dist_is_editable(d) if editables_only: + def editables_only_test(d): return dist_is_editable(d) + else: + def editables_only_test(d): return True if user_only: user_test = dist_in_usersite else: + def user_test(d): return True - return [d for d in working_set - if local_test(d) and - d.key not in skip and - editable_test(d) and - editables_only_test(d) and - user_test(d) - ] + return [ + d + for d in working_set + if local_test(d) + and d.key not in skip + and editable_test(d) + and editables_only_test(d) + and user_test(d) + ] def _search_distribution(req_name): @@ -575,7 +583,7 @@ def egg_link_path(dist): sites.append(site_packages) for site in sites: - egglink = os.path.join(site, dist.project_name) + '.egg-link' + egglink = os.path.join(site, dist.project_name) + ".egg-link" if os.path.isfile(egglink): return egglink return None @@ -605,6 +613,7 @@ def write_output(msg, *args): class FakeFile(object): """Wrap a list of lines in an object with readline() to make ConfigParser happy.""" + def __init__(self, lines): self._gen = iter(lines) @@ -612,14 +621,13 @@ def readline(self): try: return next(self._gen) except StopIteration: - return '' + return "" def __iter__(self): return self._gen class StreamWrapper(StringIO): - @classmethod def from_stream(cls, orig_stream): cls.orig_stream = orig_stream @@ -655,14 +663,14 @@ def captured_stdout(): Taken from Lib/support/__init__.py in the CPython repo. """ - return captured_output('stdout') + return captured_output("stdout") def captured_stderr(): """ See captured_stdout(). """ - return captured_output('stderr') + return captured_output("stderr") def get_installed_version(dist_name, working_set=None): @@ -692,8 +700,8 @@ def consume(iterator): def enum(*sequential, **named): enums = dict(zip(sequential, range(len(sequential))), **named) reverse = {value: key for key, value in enums.items()} - enums['reverse_mapping'] = reverse - return type('Enum', (), enums) + enums["reverse_mapping"] = reverse + return type("Enum", (), enums) def build_netloc(host, port): @@ -703,21 +711,21 @@ def build_netloc(host, port): """ if port is None: return host - if ':' in host: + if ":" in host: # Only wrap host with square brackets when it is IPv6 - host = '[{}]'.format(host) - return '{}:{}'.format(host, port) + host = "[{}]".format(host) + return "{}:{}".format(host, port) -def build_url_from_netloc(netloc, scheme='https'): +def build_url_from_netloc(netloc, scheme="https"): # type: (str, str) -> str """ Build a full URL from a netloc. """ - if netloc.count(':') >= 2 and '@' not in netloc and '[' not in netloc: + if netloc.count(":") >= 2 and "@" not in netloc and "[" not in netloc: # It must be a bare IPv6 address, so wrap it with brackets. - netloc = '[{}]'.format(netloc) - return '{}://{}'.format(scheme, netloc) + netloc = "[{}]".format(netloc) + return "{}://{}".format(scheme, netloc) def parse_netloc(netloc): @@ -736,24 +744,22 @@ def split_auth_from_netloc(netloc): Returns: (netloc, (username, password)). """ - if '@' not in netloc: + if "@" not in netloc: return netloc, (None, None) # Split from the right because that's how urllib.parse.urlsplit() # behaves if more than one @ is present (which can be checked using # the password attribute of urlsplit()'s return value). - auth, netloc = netloc.rsplit('@', 1) - if ':' in auth: + auth, netloc = netloc.rsplit("@", 1) + if ":" in auth: # Split from the left because that's how urllib.parse.urlsplit() # behaves if more than one : is present (which again can be checked # using the password attribute of the return value) - user_pass = auth.split(':', 1) + user_pass = auth.split(":", 1) else: user_pass = auth, None - user_pass = tuple( - None if x is None else urllib_unquote(x) for x in user_pass - ) + user_pass = tuple(None if x is None else urllib_unquote(x) for x in user_pass) return netloc, user_pass @@ -771,14 +777,14 @@ def redact_netloc(netloc): if user is None: return netloc if password is None: - user = '****' - password = '' + user = "****" + password = "" else: user = urllib_parse.quote(user) - password = ':****' - return '{user}{password}@{netloc}'.format(user=user, - password=password, - netloc=netloc) + password = ":****" + return "{user}{password}@{netloc}".format( + user=user, password=password, netloc=netloc + ) def _transform_url(url, transform_netloc): @@ -794,9 +800,7 @@ def _transform_url(url, transform_netloc): purl = urllib_parse.urlsplit(url) netloc_tuple = transform_netloc(purl.netloc) # stripped url - url_pieces = ( - purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment - ) + url_pieces = (purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment) surl = urllib_parse.urlunsplit(url_pieces) return surl, netloc_tuple @@ -837,7 +841,7 @@ def redact_auth_from_url(url): class HiddenText(object): def __init__( self, - secret, # type: str + secret, # type: str redacted, # type: str ): # type: (...) -> None @@ -846,7 +850,7 @@ def __init__( def __repr__(self): # type: (...) -> str - return ''.format(str(self)) + return "".format(str(self)) def __str__(self): # type: (...) -> str @@ -860,7 +864,7 @@ def __eq__(self, other): # The string being used for redaction doesn't also have to match, # just the raw, original string. - return (self.secret == other.secret) + return self.secret == other.secret # We need to provide an explicit __ne__ implementation for Python 2. # TODO: remove this when we drop PY2 support. @@ -871,7 +875,7 @@ def __ne__(self, other): def hide_value(value): # type: (str) -> HiddenText - return HiddenText(value, redacted='****') + return HiddenText(value, redacted="****") def hide_url(url): @@ -890,41 +894,36 @@ def protect_pip_from_modification_on_windows(modifying_pip): pip_names = [ "pip.exe", "pip{}.exe".format(sys.version_info[0]), - "pip{}.{}.exe".format(*sys.version_info[:2]) + "pip{}.{}.exe".format(*sys.version_info[:2]), ] # See https://github.com/pypa/pip/issues/1299 for more discussion should_show_use_python_msg = ( - modifying_pip and - WINDOWS and - os.path.basename(sys.argv[0]) in pip_names + modifying_pip and WINDOWS and os.path.basename(sys.argv[0]) in pip_names ) if should_show_use_python_msg: - new_command = [ - sys.executable, "-m", "pip" - ] + sys.argv[1:] + new_command = [sys.executable, "-m", "pip"] + sys.argv[1:] raise CommandError( - 'To modify pip, please run the following command:\n{}' - .format(" ".join(new_command)) + "To modify pip, please run the following command:\n{}".format( + " ".join(new_command) + ) ) def is_console_interactive(): # type: () -> bool - """Is this console interactive? - """ + """Is this console interactive?""" return sys.stdin is not None and sys.stdin.isatty() def hash_file(path, blocksize=1 << 20): # type: (Text, int) -> Tuple[Any, int] - """Return (hash, length) for path using hashlib.sha256() - """ + """Return (hash, length) for path using hashlib.sha256()""" h = hashlib.sha256() length = 0 - with open(path, 'rb') as f: + with open(path, "rb") as f: for block in read_chunks(f, size=blocksize): length += len(block) h.update(block) diff --git a/src/pip/_internal/utils/models.py b/src/pip/_internal/utils/models.py index d1c2f226796..36ea1f48c49 100644 --- a/src/pip/_internal/utils/models.py +++ b/src/pip/_internal/utils/models.py @@ -7,10 +7,9 @@ class KeyBasedCompareMixin(object): - """Provides comparison capabilities that is based on a key - """ + """Provides comparison capabilities that is based on a key""" - __slots__ = ['_compare_key', '_defining_class'] + __slots__ = ["_compare_key", "_defining_class"] def __init__(self, key, defining_class): self._compare_key = key diff --git a/src/pip/_internal/utils/packaging.py b/src/pip/_internal/utils/packaging.py index 27fd204234f..6c2f531609a 100644 --- a/src/pip/_internal/utils/packaging.py +++ b/src/pip/_internal/utils/packaging.py @@ -38,7 +38,7 @@ def check_requires_python(requires_python, version_info): return True requires_python_specifier = specifiers.SpecifierSet(requires_python) - python_version = version.parse('.'.join(map(str, version_info))) + python_version = version.parse(".".join(map(str, version_info))) return python_version in requires_python_specifier @@ -48,16 +48,17 @@ def get_metadata(dist): :raises NoneMetadataError: if the distribution reports `has_metadata()` True but `get_metadata()` returns None. """ - metadata_name = 'METADATA' - if (isinstance(dist, pkg_resources.DistInfoDistribution) and - dist.has_metadata(metadata_name)): + metadata_name = "METADATA" + if isinstance(dist, pkg_resources.DistInfoDistribution) and dist.has_metadata( + metadata_name + ): metadata = dist.get_metadata(metadata_name) - elif dist.has_metadata('PKG-INFO'): - metadata_name = 'PKG-INFO' + elif dist.has_metadata("PKG-INFO"): + metadata_name = "PKG-INFO" metadata = dist.get_metadata(metadata_name) else: logger.warning("No metadata found in %s", display_path(dist.location)) - metadata = '' + metadata = "" if metadata is None: raise NoneMetadataError(dist, metadata_name) @@ -76,7 +77,7 @@ def get_requires_python(dist): if not present. """ pkg_info_dict = get_metadata(dist) - requires_python = pkg_info_dict.get('Requires-Python') + requires_python = pkg_info_dict.get("Requires-Python") if requires_python is not None: # Convert to a str to satisfy the type checker, since requires_python @@ -88,8 +89,8 @@ def get_requires_python(dist): def get_installer(dist): # type: (Distribution) -> str - if dist.has_metadata('INSTALLER'): - for line in dist.get_metadata_lines('INSTALLER'): + if dist.has_metadata("INSTALLER"): + for line in dist.get_metadata_lines("INSTALLER"): if line.strip(): return line.strip() - return '' + return "" diff --git a/src/pip/_internal/utils/parallel.py b/src/pip/_internal/utils/parallel.py index d4113bdc285..6c7c9fee0cf 100644 --- a/src/pip/_internal/utils/parallel.py +++ b/src/pip/_internal/utils/parallel.py @@ -16,7 +16,7 @@ than using the default value of 1. """ -__all__ = ['map_multiprocess', 'map_multithread'] +__all__ = ["map_multiprocess", "map_multithread"] from contextlib import contextmanager from multiprocessing import Pool as ProcessPool @@ -33,8 +33,8 @@ from typing import Callable, Iterable, Iterator, TypeVar, Union Pool = Union[pool.Pool, pool.ThreadPool] - S = TypeVar('S') - T = TypeVar('T') + S = TypeVar("S") + T = TypeVar("T") # On platforms without sem_open, multiprocessing[.dummy] Pool # cannot be created. diff --git a/src/pip/_internal/utils/pkg_resources.py b/src/pip/_internal/utils/pkg_resources.py index 0bc129acc6a..84fee79b0a4 100644 --- a/src/pip/_internal/utils/pkg_resources.py +++ b/src/pip/_internal/utils/pkg_resources.py @@ -8,8 +8,8 @@ class DictMetadata(object): - """IMetadataProvider that reads metadata files from a dictionary. - """ + """IMetadataProvider that reads metadata files from a dictionary.""" + def __init__(self, metadata): # type: (Dict[str, bytes]) -> None self._metadata = metadata diff --git a/src/pip/_internal/utils/setuptools_build.py b/src/pip/_internal/utils/setuptools_build.py index 2a664b00703..a5ddf57e9f6 100644 --- a/src/pip/_internal/utils/setuptools_build.py +++ b/src/pip/_internal/utils/setuptools_build.py @@ -24,7 +24,7 @@ def make_setuptools_shim_args( setup_py_path, # type: str global_options=None, # type: Sequence[str] no_user_config=False, # type: bool - unbuffered_output=False # type: bool + unbuffered_output=False, # type: bool ): # type: (...) -> List[str] """ @@ -59,9 +59,7 @@ def make_setuptools_bdist_wheel_args( # relies on site.py to find parts of the standard library outside the # virtualenv. args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - unbuffered_output=True + setup_py_path, global_options=global_options, unbuffered_output=True ) args += ["bdist_wheel", "-d", destination_dir] args += build_options @@ -74,9 +72,7 @@ def make_setuptools_clean_args( ): # type: (...) -> List[str] args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - unbuffered_output=True + setup_py_path, global_options=global_options, unbuffered_output=True ) args += ["clean", "--all"] return args @@ -121,9 +117,7 @@ def make_setuptools_egg_info_args( no_user_config, # type: bool ): # type: (...) -> List[str] - args = make_setuptools_shim_args( - setup_py_path, no_user_config=no_user_config - ) + args = make_setuptools_shim_args(setup_py_path, no_user_config=no_user_config) args += ["egg_info"] @@ -144,7 +138,7 @@ def make_setuptools_install_args( home, # type: Optional[str] use_user_site, # type: bool no_user_config, # type: bool - pycompile # type: bool + pycompile, # type: bool ): # type: (...) -> List[str] assert not (use_user_site and prefix) @@ -154,7 +148,7 @@ def make_setuptools_install_args( setup_py_path, global_options=global_options, no_user_config=no_user_config, - unbuffered_output=True + unbuffered_output=True, ) args += ["install", "--record", record_filename] args += ["--single-version-externally-managed"] diff --git a/src/pip/_internal/utils/subprocess.py b/src/pip/_internal/utils/subprocess.py index 1dfe02fa0be..29b319fcdee 100644 --- a/src/pip/_internal/utils/subprocess.py +++ b/src/pip/_internal/utils/subprocess.py @@ -14,21 +14,12 @@ from pip._internal.utils.typing import MYPY_CHECK_RUNNING if MYPY_CHECK_RUNNING: - from typing import ( - Any, - Callable, - Iterable, - List, - Mapping, - Optional, - Text, - Union, - ) + from typing import Any, Callable, Iterable, List, Mapping, Optional, Text, Union CommandArgs = List[Union[str, HiddenText]] -LOG_DIVIDER = '----------------------------------------' +LOG_DIVIDER = "----------------------------------------" def make_command(*args): @@ -59,9 +50,9 @@ def format_command_args(args): # this can trigger a UnicodeDecodeError in Python 2 if the argument # has type unicode and includes a non-ascii character. (The type # checker doesn't ensure the annotations are correct in all cases.) - return ' '.join( - shlex_quote(str(arg)) if isinstance(arg, HiddenText) - else shlex_quote(arg) for arg in args + return " ".join( + shlex_quote(str(arg)) if isinstance(arg, HiddenText) else shlex_quote(arg) + for arg in args ) @@ -70,15 +61,13 @@ def reveal_command_args(args): """ Return the arguments in their raw, unredacted form. """ - return [ - arg.secret if isinstance(arg, HiddenText) else arg for arg in args - ] + return [arg.secret if isinstance(arg, HiddenText) else arg for arg in args] def make_subprocess_output_error( - cmd_args, # type: Union[List[str], CommandArgs] - cwd, # type: Optional[str] - lines, # type: List[Text] + cmd_args, # type: Union[List[str], CommandArgs] + cwd, # type: Optional[str] + lines, # type: List[Text] exit_status, # type: int ): # type: (...) -> Text @@ -93,19 +82,19 @@ def make_subprocess_output_error( # them as arguments in the unicode format string below. This avoids # "UnicodeDecodeError: 'ascii' codec can't decode byte ..." in Python 2 # if either contains a non-ascii character. - command_display = str_to_display(command, desc='command bytes') + command_display = str_to_display(command, desc="command bytes") cwd_display = path_to_display(cwd) # We know the joined output value ends in a newline. - output = ''.join(lines) + output = "".join(lines) msg = ( # Use a unicode string to avoid "UnicodeEncodeError: 'ascii' # codec can't encode character ..." in Python 2 when a format # argument (e.g. `output`) has a non-ascii character. - u'Command errored out with exit status {exit_status}:\n' - ' command: {command_display}\n' - ' cwd: {cwd_display}\n' - 'Complete output ({line_count} lines):\n{output}{divider}' + u"Command errored out with exit status {exit_status}:\n" + " command: {command_display}\n" + " cwd: {cwd_display}\n" + "Complete output ({line_count} lines):\n{output}{divider}" ).format( exit_status=exit_status, command_display=command_display, @@ -121,13 +110,13 @@ def call_subprocess( cmd, # type: Union[List[str], CommandArgs] show_stdout=False, # type: bool cwd=None, # type: Optional[str] - on_returncode='raise', # type: str + on_returncode="raise", # type: str extra_ok_returncodes=None, # type: Optional[Iterable[int]] command_desc=None, # type: Optional[str] extra_environ=None, # type: Optional[Mapping[str, Any]] unset_environ=None, # type: Optional[Iterable[str]] spinner=None, # type: Optional[SpinnerInterface] - log_failed_cmd=True # type: Optional[bool] + log_failed_cmd=True, # type: Optional[bool] ): # type: (...) -> Text """ @@ -189,8 +178,11 @@ def call_subprocess( proc = subprocess.Popen( # Convert HiddenText objects to the underlying str. reveal_command_args(cmd), - stderr=subprocess.STDOUT, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, cwd=cwd, env=env, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + cwd=cwd, + env=env, ) assert proc.stdin assert proc.stdout @@ -198,7 +190,9 @@ def call_subprocess( except Exception as exc: if log_failed_cmd: subprocess_logger.critical( - "Error %s while executing command %s", exc, command_desc, + "Error %s while executing command %s", + exc, + command_desc, ) raise all_output = [] @@ -208,7 +202,7 @@ def call_subprocess( if not line: break line = line.rstrip() - all_output.append(line + '\n') + all_output.append(line + "\n") # Show the line immediately. log_subprocess(line) @@ -221,9 +215,7 @@ def call_subprocess( finally: if proc.stdout: proc.stdout.close() - proc_had_error = ( - proc.returncode and proc.returncode not in extra_ok_returncodes - ) + proc_had_error = proc.returncode and proc.returncode not in extra_ok_returncodes if use_spinner: assert spinner if proc_had_error: @@ -231,7 +223,7 @@ def call_subprocess( else: spinner.finish("done") if proc_had_error: - if on_returncode == 'raise': + if on_returncode == "raise": if not showing_subprocess and log_failed_cmd: # Then the subprocess streams haven't been logged to the # console yet. @@ -243,23 +235,22 @@ def call_subprocess( ) subprocess_logger.error(msg) exc_msg = ( - 'Command errored out with exit status {}: {} ' - 'Check the logs for full command output.' + "Command errored out with exit status {}: {} " + "Check the logs for full command output." ).format(proc.returncode, command_desc) raise InstallationError(exc_msg) - elif on_returncode == 'warn': + elif on_returncode == "warn": subprocess_logger.warning( 'Command "%s" had error code %s in %s', command_desc, proc.returncode, cwd, ) - elif on_returncode == 'ignore': + elif on_returncode == "ignore": pass else: - raise ValueError('Invalid value: on_returncode={!r}'.format( - on_returncode)) - return ''.join(all_output) + raise ValueError("Invalid value: on_returncode={!r}".format(on_returncode)) + return "".join(all_output) def runner_with_spinner_message(message): @@ -273,7 +264,7 @@ def runner_with_spinner_message(message): def runner( cmd, # type: List[str] cwd=None, # type: Optional[str] - extra_environ=None # type: Optional[Mapping[str, Any]] + extra_environ=None, # type: Optional[Mapping[str, Any]] ): # type: (...) -> None with open_spinner(message) as spinner: diff --git a/src/pip/_internal/utils/temp_dir.py b/src/pip/_internal/utils/temp_dir.py index 03aa8286670..0b3d9f7ed69 100644 --- a/src/pip/_internal/utils/temp_dir.py +++ b/src/pip/_internal/utils/temp_dir.py @@ -16,7 +16,7 @@ if MYPY_CHECK_RUNNING: from typing import Any, Dict, Iterator, Optional, TypeVar, Union - _T = TypeVar('_T', bound='TempDirectory') + _T = TypeVar("_T", bound="TempDirectory") logger = logging.getLogger(__name__) @@ -47,8 +47,7 @@ def global_tempdir_manager(): class TempDirectoryTypeRegistry(object): - """Manages temp directory behavior - """ + """Manages temp directory behavior""" def __init__(self): # type: () -> None @@ -117,7 +116,7 @@ class TempDirectory(object): def __init__( self, - path=None, # type: Optional[str] + path=None, # type: Optional[str] delete=_default, # type: Union[bool, None, _Default] kind="temp", # type: str globally_managed=False, # type: bool @@ -149,8 +148,8 @@ def __init__( @property def path(self): # type: () -> str - assert not self._deleted, ( - "Attempted to access deleted path: {}".format(self._path) + assert not self._deleted, "Attempted to access deleted path: {}".format( + self._path ) return self._path @@ -176,22 +175,18 @@ def __exit__(self, exc, value, tb): def _create(self, kind): # type: (str) -> str - """Create a temporary directory and store its path in self.path - """ + """Create a temporary directory and store its path in self.path""" # We realpath here because some systems have their default tmpdir # symlinked to another directory. This tends to confuse build # scripts, so we canonicalize the path by traversing potential # symlinks here. - path = os.path.realpath( - tempfile.mkdtemp(prefix="pip-{}-".format(kind)) - ) + path = os.path.realpath(tempfile.mkdtemp(prefix="pip-{}-".format(kind))) logger.debug("Created temporary directory: %s", path) return path def cleanup(self): # type: () -> None - """Remove the temporary directory created and reset state - """ + """Remove the temporary directory created and reset state""" self._deleted = True if os.path.exists(self._path): # Make sure to pass unicode on Python 2 to make the contents also @@ -213,6 +208,7 @@ class AdjacentTempDirectory(TempDirectory): (when used as a contextmanager) """ + # The characters that may be used to name the temp directory # We always prepend a ~ and then rotate through these until # a usable name is found. @@ -222,7 +218,7 @@ class AdjacentTempDirectory(TempDirectory): def __init__(self, original, delete=None): # type: (str, Optional[bool]) -> None - self.original = original.rstrip('/\\') + self.original = original.rstrip("/\\") super(AdjacentTempDirectory, self).__init__(delete=delete) @classmethod @@ -237,16 +233,18 @@ def _generate_names(cls, name): """ for i in range(1, len(name)): for candidate in itertools.combinations_with_replacement( - cls.LEADING_CHARS, i - 1): - new_name = '~' + ''.join(candidate) + name[i:] + cls.LEADING_CHARS, i - 1 + ): + new_name = "~" + "".join(candidate) + name[i:] if new_name != name: yield new_name # If we make it this far, we will have to make a longer name for i in range(len(cls.LEADING_CHARS)): for candidate in itertools.combinations_with_replacement( - cls.LEADING_CHARS, i): - new_name = '~' + ''.join(candidate) + name + cls.LEADING_CHARS, i + ): + new_name = "~" + "".join(candidate) + name if new_name != name: yield new_name @@ -266,9 +264,7 @@ def _create(self, kind): break else: # Final fallback on the default behavior. - path = os.path.realpath( - tempfile.mkdtemp(prefix="pip-{}-".format(kind)) - ) + path = os.path.realpath(tempfile.mkdtemp(prefix="pip-{}-".format(kind))) logger.debug("Created temporary directory: %s", path) return path diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py index 620f31ebb74..56a7c1d99c4 100644 --- a/src/pip/_internal/utils/unpacking.py +++ b/src/pip/_internal/utils/unpacking.py @@ -32,16 +32,18 @@ try: import bz2 # noqa + SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS except ImportError: - logger.debug('bz2 module is not available') + logger.debug("bz2 module is not available") try: # Only for Python 3.3+ import lzma # noqa + SUPPORTED_EXTENSIONS += XZ_EXTENSIONS except ImportError: - logger.debug('lzma module is not available') + logger.debug("lzma module is not available") def current_umask(): @@ -54,18 +56,15 @@ def current_umask(): def split_leading_dir(path): # type: (Union[str, Text]) -> List[Union[str, Text]] - path = path.lstrip('/').lstrip('\\') - if ( - '/' in path and ( - ('\\' in path and path.find('/') < path.find('\\')) or - '\\' not in path - ) + path = path.lstrip("/").lstrip("\\") + if "/" in path and ( + ("\\" in path and path.find("/") < path.find("\\")) or "\\" not in path ): - return path.split('/', 1) - elif '\\' in path: - return path.split('\\', 1) + return path.split("/", 1) + elif "\\" in path: + return path.split("\\", 1) else: - return [path, ''] + return [path, ""] def has_leading_dir(paths): @@ -124,7 +123,7 @@ def unzip_file(filename, location, flatten=True): no-ops per the python docs. """ ensure_dir(location) - zipfp = open(filename, 'rb') + zipfp = open(filename, "rb") try: zip = zipfile.ZipFile(zipfp, allowZip64=True) leading = has_leading_dir(zip.namelist()) and flatten @@ -137,11 +136,11 @@ def unzip_file(filename, location, flatten=True): dir = os.path.dirname(fn) if not is_within_directory(location, fn): message = ( - 'The zip file ({}) has a file ({}) trying to install ' - 'outside target directory ({})' + "The zip file ({}) has a file ({}) trying to install " + "outside target directory ({})" ) raise InstallationError(message.format(filename, fn, location)) - if fn.endswith('/') or fn.endswith('\\'): + if fn.endswith("/") or fn.endswith("\\"): # A directory ensure_dir(fn) else: @@ -150,7 +149,7 @@ def unzip_file(filename, location, flatten=True): # chunk of memory for the file's content fp = zip.open(name) try: - with open(fn, 'wb') as destfp: + with open(fn, "wb") as destfp: shutil.copyfileobj(fp, destfp) finally: fp.close() @@ -171,24 +170,23 @@ def untar_file(filename, location): no-ops per the python docs. """ ensure_dir(location) - if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): - mode = 'r:gz' + if filename.lower().endswith(".gz") or filename.lower().endswith(".tgz"): + mode = "r:gz" elif filename.lower().endswith(BZ2_EXTENSIONS): - mode = 'r:bz2' + mode = "r:bz2" elif filename.lower().endswith(XZ_EXTENSIONS): - mode = 'r:xz' - elif filename.lower().endswith('.tar'): - mode = 'r' + mode = "r:xz" + elif filename.lower().endswith(".tar"): + mode = "r" else: logger.warning( - 'Cannot determine compression type for file %s', filename, + "Cannot determine compression type for file %s", + filename, ) - mode = 'r:*' + mode = "r:*" tar = tarfile.open(filename, mode) try: - leading = has_leading_dir([ - member.name for member in tar.getmembers() - ]) + leading = has_leading_dir([member.name for member in tar.getmembers()]) for member in tar.getmembers(): fn = member.name if leading: @@ -197,12 +195,10 @@ def untar_file(filename, location): path = os.path.join(location, fn) if not is_within_directory(location, path): message = ( - 'The tar file ({}) has a file ({}) trying to install ' - 'outside target directory ({})' - ) - raise InstallationError( - message.format(filename, path, location) + "The tar file ({}) has a file ({}) trying to install " + "outside target directory ({})" ) + raise InstallationError(message.format(filename, path, location)) if member.isdir(): ensure_dir(path) elif member.issym(): @@ -213,8 +209,10 @@ def untar_file(filename, location): # Some corrupt tar files seem to produce this # (specifically bad symlinks) logger.warning( - 'In the tar file %s the member %s is invalid: %s', - filename, member.name, exc, + "In the tar file %s the member %s is invalid: %s", + filename, + member.name, + exc, ) continue else: @@ -224,13 +222,15 @@ def untar_file(filename, location): # Some corrupt tar files seem to produce this # (specifically bad symlinks) logger.warning( - 'In the tar file %s the member %s is invalid: %s', - filename, member.name, exc, + "In the tar file %s the member %s is invalid: %s", + filename, + member.name, + exc, ) continue ensure_dir(os.path.dirname(path)) assert fp is not None - with open(path, 'wb') as destfp: + with open(path, "wb") as destfp: shutil.copyfileobj(fp, destfp) fp.close() # Update the timestamp (useful for cython compiled files) @@ -244,38 +244,34 @@ def untar_file(filename, location): def unpack_file( - filename, # type: str - location, # type: str - content_type=None, # type: Optional[str] + filename, # type: str + location, # type: str + content_type=None, # type: Optional[str] ): # type: (...) -> None filename = os.path.realpath(filename) if ( - content_type == 'application/zip' or - filename.lower().endswith(ZIP_EXTENSIONS) or - zipfile.is_zipfile(filename) + content_type == "application/zip" + or filename.lower().endswith(ZIP_EXTENSIONS) + or zipfile.is_zipfile(filename) ): - unzip_file( - filename, - location, - flatten=not filename.endswith('.whl') - ) + unzip_file(filename, location, flatten=not filename.endswith(".whl")) elif ( - content_type == 'application/x-gzip' or - tarfile.is_tarfile(filename) or - filename.lower().endswith( - TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS - ) + content_type == "application/x-gzip" + or tarfile.is_tarfile(filename) + or filename.lower().endswith(TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS) ): untar_file(filename, location) else: # FIXME: handle? # FIXME: magic signatures? logger.critical( - 'Cannot unpack file %s (downloaded from %s, content-type: %s); ' - 'cannot detect archive format', - filename, location, content_type, + "Cannot unpack file %s (downloaded from %s, content-type: %s); " + "cannot detect archive format", + filename, + location, + content_type, ) raise InstallationError( - 'Cannot determine archive format of {}'.format(location) + "Cannot determine archive format of {}".format(location) ) diff --git a/src/pip/_internal/utils/urls.py b/src/pip/_internal/utils/urls.py index f37bc8f90b2..ff896fa951e 100644 --- a/src/pip/_internal/utils/urls.py +++ b/src/pip/_internal/utils/urls.py @@ -12,9 +12,9 @@ def get_url_scheme(url): # type: (Union[str, Text]) -> Optional[Text] - if ':' not in url: + if ":" not in url: return None - return url.split(':', 1)[0].lower() + return url.split(":", 1)[0].lower() def path_to_url(path): @@ -24,7 +24,7 @@ def path_to_url(path): quoted path parts. """ path = os.path.normpath(os.path.abspath(path)) - url = urllib_parse.urljoin('file:', urllib_request.pathname2url(path)) + url = urllib_parse.urljoin("file:", urllib_request.pathname2url(path)) return url @@ -33,22 +33,23 @@ def url_to_path(url): """ Convert a file: URL to a path. """ - assert url.startswith('file:'), ( - "You can only turn file: urls into filenames (not {url!r})" - .format(**locals())) + assert url.startswith( + "file:" + ), "You can only turn file: urls into filenames (not {url!r})".format(**locals()) _, netloc, path, _, _ = urllib_parse.urlsplit(url) - if not netloc or netloc == 'localhost': + if not netloc or netloc == "localhost": # According to RFC 8089, same as empty authority. - netloc = '' - elif sys.platform == 'win32': + netloc = "" + elif sys.platform == "win32": # If we have a UNC path, prepend UNC share notation. - netloc = '\\\\' + netloc + netloc = "\\\\" + netloc else: raise ValueError( - 'non-local file URIs are not supported on this platform: {url!r}' - .format(**locals()) + "non-local file URIs are not supported on this platform: {url!r}".format( + **locals() + ) ) path = urllib_request.url2pathname(netloc + path) diff --git a/src/pip/_internal/utils/virtualenv.py b/src/pip/_internal/utils/virtualenv.py index 4a7812873b3..a978f4962d7 100644 --- a/src/pip/_internal/utils/virtualenv.py +++ b/src/pip/_internal/utils/virtualenv.py @@ -34,13 +34,12 @@ def _running_under_regular_virtualenv(): This handles virtual environments created with pypa's virtualenv. """ # pypa/virtualenv case - return hasattr(sys, 'real_prefix') + return hasattr(sys, "real_prefix") def running_under_virtualenv(): # type: () -> bool - """Return True if we're running inside a virtualenv, False otherwise. - """ + """Return True if we're running inside a virtualenv, False otherwise.""" return _running_under_venv() or _running_under_regular_virtualenv() @@ -50,11 +49,11 @@ def _get_pyvenv_cfg_lines(): Returns None, if it could not read/access the file. """ - pyvenv_cfg_file = os.path.join(sys.prefix, 'pyvenv.cfg') + pyvenv_cfg_file = os.path.join(sys.prefix, "pyvenv.cfg") try: # Although PEP 405 does not specify, the built-in venv module always # writes with UTF-8. (pypa/pip#8717) - with io.open(pyvenv_cfg_file, encoding='utf-8') as f: + with io.open(pyvenv_cfg_file, encoding="utf-8") as f: return f.read().splitlines() # avoids trailing newlines except IOError: return None @@ -85,7 +84,7 @@ def _no_global_under_venv(): for line in cfg_lines: match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line) - if match is not None and match.group('value') == 'false': + if match is not None and match.group("value") == "false": return True return False @@ -99,15 +98,15 @@ def _no_global_under_regular_virtualenv(): """ site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) no_global_site_packages_file = os.path.join( - site_mod_dir, 'no-global-site-packages.txt', + site_mod_dir, + "no-global-site-packages.txt", ) return os.path.exists(no_global_site_packages_file) def virtualenv_no_global(): # type: () -> bool - """Returns a boolean, whether running in venv with no system site-packages. - """ + """Returns a boolean, whether running in venv with no system site-packages.""" # PEP 405 compliance needs to be checked first since virtualenv >=20 would # return True for both checks, but is only able to use the PEP 405 config. if _running_under_venv(): diff --git a/src/pip/_internal/utils/wheel.py b/src/pip/_internal/utils/wheel.py index 9ce371c76eb..04c51c8f5ae 100644 --- a/src/pip/_internal/utils/wheel.py +++ b/src/pip/_internal/utils/wheel.py @@ -37,6 +37,7 @@ class WheelMetadata(DictMetadata): """Metadata provider that maps metadata decoding exceptions to our internal exception type. """ + def __init__(self, metadata, wheel_name): # type: (Dict[str, bytes], str) -> None super(WheelMetadata, self).__init__(metadata) @@ -49,9 +50,7 @@ def get_metadata(self, name): except UnicodeDecodeError as e: # Augment the default error with the origin of the file. raise UnsupportedWheel( - "Error decoding metadata for {}: {}".format( - self._wheel_name, e - ) + "Error decoding metadata for {}: {}".format(self._wheel_name, e) ) @@ -81,15 +80,11 @@ def pkg_resources_distribution_for_wheel(wheel_zip, name, location): wheel_zip, full_path ) except UnsupportedWheel as e: - raise UnsupportedWheel( - "{} has an invalid wheel, {}".format(name, str(e)) - ) + raise UnsupportedWheel("{} has an invalid wheel, {}".format(name, str(e))) metadata = WheelMetadata(metadata_text, location) - return DistInfoDistribution( - location=location, metadata=metadata, project_name=name - ) + return DistInfoDistribution(location=location, metadata=metadata, project_name=name) def parse_wheel(wheel_zip, name): @@ -104,9 +99,7 @@ def parse_wheel(wheel_zip, name): metadata = wheel_metadata(wheel_zip, info_dir) version = wheel_version(metadata) except UnsupportedWheel as e: - raise UnsupportedWheel( - "{} has an invalid wheel, {}".format(name, str(e)) - ) + raise UnsupportedWheel("{} has an invalid wheel, {}".format(name, str(e))) check_compatibility(version, name) @@ -123,16 +116,14 @@ def wheel_dist_info_dir(source, name): # Zip file path separators must be / subdirs = set(p.split("/", 1)[0] for p in source.namelist()) - info_dirs = [s for s in subdirs if s.endswith('.dist-info')] + info_dirs = [s for s in subdirs if s.endswith(".dist-info")] if not info_dirs: raise UnsupportedWheel(".dist-info directory not found") if len(info_dirs) > 1: raise UnsupportedWheel( - "multiple .dist-info directories found: {}".format( - ", ".join(info_dirs) - ) + "multiple .dist-info directories found: {}".format(", ".join(info_dirs)) ) info_dir = info_dirs[0] @@ -158,9 +149,7 @@ def read_wheel_metadata_file(source, path): # BadZipFile for general corruption, KeyError for missing entry, # and RuntimeError for password-protected files except (BadZipFile, KeyError, RuntimeError) as e: - raise UnsupportedWheel( - "could not read {!r} file: {!r}".format(path, e) - ) + raise UnsupportedWheel("could not read {!r} file: {!r}".format(path, e)) def wheel_metadata(source, dist_info_dir): @@ -195,7 +184,7 @@ def wheel_version(wheel_data): version = version_text.strip() try: - return tuple(map(int, version.split('.'))) + return tuple(map(int, version.split("."))) except ValueError: raise UnsupportedWheel("invalid Wheel-Version: {!r}".format(version)) @@ -216,10 +205,10 @@ def check_compatibility(version, name): if version[0] > VERSION_COMPATIBLE[0]: raise UnsupportedWheel( "{}'s Wheel-Version ({}) is not compatible with this version " - "of pip".format(name, '.'.join(map(str, version))) + "of pip".format(name, ".".join(map(str, version))) ) elif version > VERSION_COMPATIBLE: logger.warning( - 'Installing from a newer Wheel-Version (%s)', - '.'.join(map(str, version)), + "Installing from a newer Wheel-Version (%s)", + ".".join(map(str, version)), ) diff --git a/src/pip/_internal/vcs/bazaar.py b/src/pip/_internal/vcs/bazaar.py index 3180713f7db..d9247157f23 100644 --- a/src/pip/_internal/vcs/bazaar.py +++ b/src/pip/_internal/vcs/bazaar.py @@ -25,24 +25,29 @@ class Bazaar(VersionControl): - name = 'bzr' - dirname = '.bzr' - repo_name = 'branch' + name = "bzr" + dirname = ".bzr" + repo_name = "branch" schemes = ( - 'bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', - 'bzr+lp', + "bzr", + "bzr+http", + "bzr+https", + "bzr+ssh", + "bzr+sftp", + "bzr+ftp", + "bzr+lp", ) def __init__(self, *args, **kwargs): super(Bazaar, self).__init__(*args, **kwargs) # This is only needed for python <2.7.5 # Register lp but do not expose as a scheme to support bzr+lp. - if getattr(urllib_parse, 'uses_fragment', None): - urllib_parse.uses_fragment.extend(['lp']) + if getattr(urllib_parse, "uses_fragment", None): + urllib_parse.uses_fragment.extend(["lp"]) @staticmethod def get_base_rev_args(rev): - return ['-r', rev] + return ["-r", rev] def export(self, location, url): # type: (str, HiddenText) -> None @@ -54,31 +59,27 @@ def export(self, location, url): rmtree(location) url, rev_options = self.get_url_rev_options(url) - self.run_command( - make_command('export', location, url, rev_options.to_args()) - ) + self.run_command(make_command("export", location, url, rev_options.to_args())) def fetch_new(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None rev_display = rev_options.to_display() logger.info( - 'Checking out %s%s to %s', + "Checking out %s%s to %s", url, rev_display, display_path(dest), ) - cmd_args = ( - make_command('branch', '-q', rev_options.to_args(), url, dest) - ) + cmd_args = make_command("branch", "-q", rev_options.to_args(), url, dest) self.run_command(cmd_args) def switch(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None - self.run_command(make_command('switch', url), cwd=dest) + self.run_command(make_command("switch", url), cwd=dest) def update(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None - cmd_args = make_command('pull', '-q', rev_options.to_args()) + cmd_args = make_command("pull", "-q", rev_options.to_args()) self.run_command(cmd_args, cwd=dest) @classmethod @@ -86,17 +87,16 @@ def get_url_rev_and_auth(cls, url): # type: (str) -> Tuple[str, Optional[str], AuthInfo] # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it url, rev, user_pass = super(Bazaar, cls).get_url_rev_and_auth(url) - if url.startswith('ssh://'): - url = 'bzr+' + url + if url.startswith("ssh://"): + url = "bzr+" + url return url, rev, user_pass @classmethod def get_remote_url(cls, location): - urls = cls.run_command(['info'], cwd=location) + urls = cls.run_command(["info"], cwd=location) for line in urls.splitlines(): line = line.strip() - for x in ('checkout of branch: ', - 'parent branch: '): + for x in ("checkout of branch: ", "parent branch: "): if line.startswith(x): repo = line.split(x)[1] if cls._is_local_repository(repo): @@ -107,7 +107,8 @@ def get_remote_url(cls, location): @classmethod def get_revision(cls, location): revision = cls.run_command( - ['revno'], cwd=location, + ["revno"], + cwd=location, ) return revision.splitlines()[-1] diff --git a/src/pip/_internal/vcs/git.py b/src/pip/_internal/vcs/git.py index 1831aede58a..ca880471c62 100644 --- a/src/pip/_internal/vcs/git.py +++ b/src/pip/_internal/vcs/git.py @@ -37,7 +37,7 @@ logger = logging.getLogger(__name__) -HASH_REGEX = re.compile('^[a-fA-F0-9]{40}$') +HASH_REGEX = re.compile("^[a-fA-F0-9]{40}$") def looks_like_hash(sha): @@ -45,16 +45,21 @@ def looks_like_hash(sha): class Git(VersionControl): - name = 'git' - dirname = '.git' - repo_name = 'clone' + name = "git" + dirname = ".git" + repo_name = "clone" schemes = ( - 'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', + "git", + "git+http", + "git+https", + "git+ssh", + "git+git", + "git+file", ) # Prevent the user's environment variables from interfering with pip: # https://github.com/pypa/pip/issues/1130 - unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') - default_arg_rev = 'HEAD' + unset_environ = ("GIT_DIR", "GIT_WORK_TREE") + default_arg_rev = "HEAD" @staticmethod def get_base_rev_args(rev): @@ -72,22 +77,20 @@ def is_immutable_rev_checkout(self, url, dest): # return False in the rare case rev is both a commit hash # and a tag or a branch; we don't want to cache in that case # because that branch/tag could point to something else in the future - is_tag_or_branch = bool( - self.get_revision_sha(dest, rev_options.rev)[0] - ) + is_tag_or_branch = bool(self.get_revision_sha(dest, rev_options.rev)[0]) return not is_tag_or_branch def get_git_version(self): - VERSION_PFX = 'git version ' - version = self.run_command(['version']) + VERSION_PFX = "git version " + version = self.run_command(["version"]) if version.startswith(VERSION_PFX): - version = version[len(VERSION_PFX):].split()[0] + version = version[len(VERSION_PFX) :].split()[0] else: - version = '' + version = "" # get first 3 positions of the git version because # on windows it is x.y.z.windows.t, and this parses as # LegacyVersion which always smaller than a Version. - version = '.'.join(version.split('.')[:3]) + version = ".".join(version.split(".")[:3]) return parse_version(version) @classmethod @@ -100,28 +103,29 @@ def get_current_branch(cls, location): # HEAD rather than a symbolic ref. In addition, the -q causes the # command to exit with status code 1 instead of 128 in this case # and to suppress the message to stderr. - args = ['symbolic-ref', '-q', 'HEAD'] + args = ["symbolic-ref", "-q", "HEAD"] output = cls.run_command( - args, extra_ok_returncodes=(1, ), cwd=location, + args, + extra_ok_returncodes=(1,), + cwd=location, ) ref = output.strip() - if ref.startswith('refs/heads/'): - return ref[len('refs/heads/'):] + if ref.startswith("refs/heads/"): + return ref[len("refs/heads/") :] return None def export(self, location, url): # type: (str, HiddenText) -> None """Export the Git repository at the url to the destination location""" - if not location.endswith('/'): - location = location + '/' + if not location.endswith("/"): + location = location + "/" with TempDirectory(kind="export") as temp_dir: self.unpack(temp_dir.path, url=url) self.run_command( - ['checkout-index', '-a', '-f', '--prefix', location], - cwd=temp_dir.path + ["checkout-index", "-a", "-f", "--prefix", location], cwd=temp_dir.path ) @classmethod @@ -136,9 +140,9 @@ def get_revision_sha(cls, dest, rev): """ # Pass rev to pre-filter the list. - output = '' + output = "" try: - output = cls.run_command(['show-ref', rev], cwd=dest) + output = cls.run_command(["show-ref", rev], cwd=dest) except SubProcessError: pass @@ -149,12 +153,12 @@ def get_revision_sha(cls, dest, rev): except ValueError: # Include the offending line to simplify troubleshooting if # this error ever occurs. - raise ValueError('unexpected show-ref line: {!r}'.format(line)) + raise ValueError("unexpected show-ref line: {!r}".format(line)) refs[ref] = sha - branch_ref = 'refs/remotes/origin/{}'.format(rev) - tag_ref = 'refs/tags/{}'.format(rev) + branch_ref = "refs/remotes/origin/{}".format(rev) + tag_ref = "refs/tags/{}".format(rev) sha = refs.get(branch_ref) if sha is not None: @@ -223,11 +227,11 @@ def resolve_revision(cls, dest, url, rev_options): # fetch the requested revision cls.run_command( - make_command('fetch', '-q', url, rev_options.to_args()), + make_command("fetch", "-q", url, rev_options.to_args()), cwd=dest, ) # Change the revision to the SHA of the ref we fetched - sha = cls.get_revision(dest, rev='FETCH_HEAD') + sha = cls.get_revision(dest, rev="FETCH_HEAD") rev_options = rev_options.make_new(sha) return rev_options @@ -250,27 +254,33 @@ def is_commit_id_equal(cls, dest, name): def fetch_new(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None rev_display = rev_options.to_display() - logger.info('Cloning %s%s to %s', url, rev_display, display_path(dest)) - self.run_command(make_command('clone', '-q', url, dest)) + logger.info("Cloning %s%s to %s", url, rev_display, display_path(dest)) + self.run_command(make_command("clone", "-q", url, dest)) if rev_options.rev: # Then a specific revision was requested. rev_options = self.resolve_revision(dest, url, rev_options) - branch_name = getattr(rev_options, 'branch_name', None) + branch_name = getattr(rev_options, "branch_name", None) if branch_name is None: # Only do a checkout if the current commit id doesn't match # the requested revision. if not self.is_commit_id_equal(dest, rev_options.rev): cmd_args = make_command( - 'checkout', '-q', rev_options.to_args(), + "checkout", + "-q", + rev_options.to_args(), ) self.run_command(cmd_args, cwd=dest) elif self.get_current_branch(dest) != branch_name: # Then a specific branch was requested, and that branch # is not yet checked out. - track_branch = 'origin/{}'.format(branch_name) + track_branch = "origin/{}".format(branch_name) cmd_args = [ - 'checkout', '-b', branch_name, '--track', track_branch, + "checkout", + "-b", + branch_name, + "--track", + track_branch, ] self.run_command(cmd_args, cwd=dest) @@ -280,10 +290,10 @@ def fetch_new(self, dest, url, rev_options): def switch(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None self.run_command( - make_command('config', 'remote.origin.url', url), + make_command("config", "remote.origin.url", url), cwd=dest, ) - cmd_args = make_command('checkout', '-q', rev_options.to_args()) + cmd_args = make_command("checkout", "-q", rev_options.to_args()) self.run_command(cmd_args, cwd=dest) self.update_submodules(dest) @@ -291,14 +301,14 @@ def switch(self, dest, url, rev_options): def update(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None # First fetch changes from the default remote - if self.get_git_version() >= parse_version('1.9.0'): + if self.get_git_version() >= parse_version("1.9.0"): # fetch tags in addition to everything else - self.run_command(['fetch', '-q', '--tags'], cwd=dest) + self.run_command(["fetch", "-q", "--tags"], cwd=dest) else: - self.run_command(['fetch', '-q'], cwd=dest) + self.run_command(["fetch", "-q"], cwd=dest) # Then reset to wanted revision (maybe even origin/master) rev_options = self.resolve_revision(dest, url, rev_options) - cmd_args = make_command('reset', '--hard', '-q', rev_options.to_args()) + cmd_args = make_command("reset", "--hard", "-q", rev_options.to_args()) self.run_command(cmd_args, cwd=dest) #: update submodules self.update_submodules(dest) @@ -314,8 +324,9 @@ def get_remote_url(cls, location): # We need to pass 1 for extra_ok_returncodes since the command # exits with return code 1 if there are no matching lines. stdout = cls.run_command( - ['config', '--get-regexp', r'remote\..*\.url'], - extra_ok_returncodes=(1, ), cwd=location, + ["config", "--get-regexp", r"remote\..*\.url"], + extra_ok_returncodes=(1,), + cwd=location, ) remotes = stdout.splitlines() try: @@ -324,10 +335,10 @@ def get_remote_url(cls, location): raise RemoteNotFoundError for remote in remotes: - if remote.startswith('remote.origin.url '): + if remote.startswith("remote.origin.url "): found_remote = remote break - url = found_remote.split(' ')[1] + url = found_remote.split(" ")[1] return url.strip() @classmethod @@ -336,9 +347,7 @@ def has_commit(cls, location, rev): Check if rev is a commit that is available in the local repository. """ try: - cls.run_command( - ['rev-parse', '-q', '--verify', "sha^" + rev], cwd=location - ) + cls.run_command(["rev-parse", "-q", "--verify", "sha^" + rev], cwd=location) except SubProcessError: return False else: @@ -347,9 +356,10 @@ def has_commit(cls, location, rev): @classmethod def get_revision(cls, location, rev=None): if rev is None: - rev = 'HEAD' + rev = "HEAD" current_rev = cls.run_command( - ['rev-parse', rev], cwd=location, + ["rev-parse", rev], + cwd=location, ) return current_rev.strip() @@ -360,12 +370,10 @@ def get_subdirectory(cls, location): Return None if setup.py is in the repo root. """ # find the repo root - git_dir = cls.run_command( - ['rev-parse', '--git-dir'], - cwd=location).strip() + git_dir = cls.run_command(["rev-parse", "--git-dir"], cwd=location).strip() if not os.path.isabs(git_dir): git_dir = os.path.join(location, git_dir) - repo_root = os.path.abspath(os.path.join(git_dir, '..')) + repo_root = os.path.abspath(os.path.join(git_dir, "..")) return find_path_to_setup_from_repo_root(location, repo_root) @classmethod @@ -380,23 +388,21 @@ def get_url_rev_and_auth(cls, url): # Works around an apparent Git bug # (see https://article.gmane.org/gmane.comp.version-control.git/146500) scheme, netloc, path, query, fragment = urlsplit(url) - if scheme.endswith('file'): - initial_slashes = path[:-len(path.lstrip('/'))] - newpath = ( - initial_slashes + - urllib_request.url2pathname(path) - .replace('\\', '/').lstrip('/') - ) - after_plus = scheme.find('+') + 1 + if scheme.endswith("file"): + initial_slashes = path[: -len(path.lstrip("/"))] + newpath = initial_slashes + urllib_request.url2pathname(path).replace( + "\\", "/" + ).lstrip("/") + after_plus = scheme.find("+") + 1 url = scheme[:after_plus] + urlunsplit( (scheme[after_plus:], netloc, newpath, query, fragment), ) - if '://' not in url: - assert 'file:' not in url - url = url.replace('git+', 'git+ssh://') + if "://" not in url: + assert "file:" not in url + url = url.replace("git+", "git+ssh://") url, rev, user_pass = super(Git, cls).get_url_rev_and_auth(url) - url = url.replace('ssh://', '') + url = url.replace("ssh://", "") else: url, rev, user_pass = super(Git, cls).get_url_rev_and_auth(url) @@ -404,10 +410,10 @@ def get_url_rev_and_auth(cls, url): @classmethod def update_submodules(cls, location): - if not os.path.exists(os.path.join(location, '.gitmodules')): + if not os.path.exists(os.path.join(location, ".gitmodules")): return cls.run_command( - ['submodule', 'update', '--init', '--recursive', '-q'], + ["submodule", "update", "--init", "--recursive", "-q"], cwd=location, ) @@ -418,17 +424,20 @@ def get_repository_root(cls, location): return loc try: r = cls.run_command( - ['rev-parse', '--show-toplevel'], + ["rev-parse", "--show-toplevel"], cwd=location, log_failed_cmd=False, ) except BadCommand: - logger.debug("could not determine if %s is under git control " - "because git is not available", location) + logger.debug( + "could not determine if %s is under git control " + "because git is not available", + location, + ) return None except SubProcessError: return None - return os.path.normpath(r.rstrip('\r\n')) + return os.path.normpath(r.rstrip("\r\n")) vcs.register(Git) diff --git a/src/pip/_internal/vcs/mercurial.py b/src/pip/_internal/vcs/mercurial.py index 69763feaea4..55bdb31187c 100644 --- a/src/pip/_internal/vcs/mercurial.py +++ b/src/pip/_internal/vcs/mercurial.py @@ -29,11 +29,16 @@ class Mercurial(VersionControl): - name = 'hg' - dirname = '.hg' - repo_name = 'clone' + name = "hg" + dirname = ".hg" + repo_name = "clone" schemes = ( - 'hg', 'hg+file', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http', + "hg", + "hg+file", + "hg+http", + "hg+https", + "hg+ssh", + "hg+static-http", ) @staticmethod @@ -46,53 +51,51 @@ def export(self, location, url): with TempDirectory(kind="export") as temp_dir: self.unpack(temp_dir.path, url=url) - self.run_command( - ['archive', location], cwd=temp_dir.path - ) + self.run_command(["archive", location], cwd=temp_dir.path) def fetch_new(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None rev_display = rev_options.to_display() logger.info( - 'Cloning hg %s%s to %s', + "Cloning hg %s%s to %s", url, rev_display, display_path(dest), ) - self.run_command(make_command('clone', '--noupdate', '-q', url, dest)) + self.run_command(make_command("clone", "--noupdate", "-q", url, dest)) self.run_command( - make_command('update', '-q', rev_options.to_args()), + make_command("update", "-q", rev_options.to_args()), cwd=dest, ) def switch(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None - repo_config = os.path.join(dest, self.dirname, 'hgrc') + repo_config = os.path.join(dest, self.dirname, "hgrc") config = configparser.RawConfigParser() try: config.read(repo_config) - config.set('paths', 'default', url.secret) - with open(repo_config, 'w') as config_file: + config.set("paths", "default", url.secret) + with open(repo_config, "w") as config_file: config.write(config_file) except (OSError, configparser.NoSectionError) as exc: logger.warning( - 'Could not switch Mercurial repository to %s: %s', url, exc, + "Could not switch Mercurial repository to %s: %s", + url, + exc, ) else: - cmd_args = make_command('update', '-q', rev_options.to_args()) + cmd_args = make_command("update", "-q", rev_options.to_args()) self.run_command(cmd_args, cwd=dest) def update(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None - self.run_command(['pull', '-q'], cwd=dest) - cmd_args = make_command('update', '-q', rev_options.to_args()) + self.run_command(["pull", "-q"], cwd=dest) + cmd_args = make_command("update", "-q", rev_options.to_args()) self.run_command(cmd_args, cwd=dest) @classmethod def get_remote_url(cls, location): - url = cls.run_command( - ['showconfig', 'paths.default'], - cwd=location).strip() + url = cls.run_command(["showconfig", "paths.default"], cwd=location).strip() if cls._is_local_repository(url): url = path_to_url(url) return url.strip() @@ -103,7 +106,8 @@ def get_revision(cls, location): Return the repository-local changeset revision number, as an integer. """ current_revision = cls.run_command( - ['parents', '--template={rev}'], cwd=location).strip() + ["parents", "--template={rev}"], cwd=location + ).strip() return current_revision @classmethod @@ -113,8 +117,8 @@ def get_requirement_revision(cls, location): hexadecimal string """ current_rev_hash = cls.run_command( - ['parents', '--template={node}'], - cwd=location).strip() + ["parents", "--template={node}"], cwd=location + ).strip() return current_rev_hash @classmethod @@ -129,8 +133,7 @@ def get_subdirectory(cls, location): Return None if setup.py is in the repo root. """ # find the repo root - repo_root = cls.run_command( - ['root'], cwd=location).strip() + repo_root = cls.run_command(["root"], cwd=location).strip() if not os.path.isabs(repo_root): repo_root = os.path.abspath(os.path.join(location, repo_root)) return find_path_to_setup_from_repo_root(location, repo_root) @@ -142,17 +145,20 @@ def get_repository_root(cls, location): return loc try: r = cls.run_command( - ['root'], + ["root"], cwd=location, log_failed_cmd=False, ) except BadCommand: - logger.debug("could not determine if %s is under hg control " - "because hg is not available", location) + logger.debug( + "could not determine if %s is under hg control " + "because hg is not available", + location, + ) return None except SubProcessError: return None - return os.path.normpath(r.rstrip('\r\n')) + return os.path.normpath(r.rstrip("\r\n")) vcs.register(Mercurial) diff --git a/src/pip/_internal/vcs/subversion.py b/src/pip/_internal/vcs/subversion.py index eae09c19610..f09b0aafd56 100644 --- a/src/pip/_internal/vcs/subversion.py +++ b/src/pip/_internal/vcs/subversion.py @@ -21,7 +21,7 @@ _svn_xml_url_re = re.compile('url="([^"]+)"') _svn_rev_re = re.compile(r'committed-rev="(\d+)"') _svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') -_svn_info_xml_url_re = re.compile(r'(.*)') +_svn_info_xml_url_re = re.compile(r"(.*)") if MYPY_CHECK_RUNNING: @@ -36,10 +36,10 @@ class Subversion(VersionControl): - name = 'svn' - dirname = '.svn' - repo_name = 'checkout' - schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') + name = "svn" + dirname = ".svn" + repo_name = "checkout" + schemes = ("svn", "svn+ssh", "svn+http", "svn+https", "svn+svn") @classmethod def should_add_vcs_url_prefix(cls, remote_url): @@ -47,7 +47,7 @@ def should_add_vcs_url_prefix(cls, remote_url): @staticmethod def get_base_rev_args(rev): - return ['-r', rev] + return ["-r", rev] @classmethod def get_revision(cls, location): @@ -60,9 +60,9 @@ def get_revision(cls, location): for base, dirs, _ in os.walk(location): if cls.dirname not in dirs: dirs[:] = [] - continue # no sense walking uncontrolled subdirs + continue # no sense walking uncontrolled subdirs dirs.remove(cls.dirname) - entries_fn = os.path.join(base, cls.dirname, 'entries') + entries_fn = os.path.join(base, cls.dirname, "entries") if not os.path.exists(entries_fn): # FIXME: should we warn? continue @@ -70,10 +70,10 @@ def get_revision(cls, location): dirurl, localrev = cls._get_svn_url_rev(base) if base == location: - base = dirurl + '/' # save the root url + base = dirurl + "/" # save the root url elif not dirurl or not dirurl.startswith(base): dirs[:] = [] - continue # not part of the same svn tree, skip it + continue # not part of the same svn tree, skip it revision = max(revision, localrev) return revision @@ -83,7 +83,7 @@ def get_netloc_and_auth(cls, netloc, scheme): This override allows the auth information to be passed to svn via the --username and --password options instead of via the URL. """ - if scheme == 'ssh': + if scheme == "ssh": # The --username and --password options can't be used for # svn+ssh URLs, so keep the auth information in the URL. return super(Subversion, cls).get_netloc_and_auth(netloc, scheme) @@ -95,8 +95,8 @@ def get_url_rev_and_auth(cls, url): # type: (str) -> Tuple[str, Optional[str], AuthInfo] # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it url, rev, user_pass = super(Subversion, cls).get_url_rev_and_auth(url) - if url.startswith('ssh://'): - url = 'svn+' + url + if url.startswith("ssh://"): + url = "svn+" + url return url, rev, user_pass @staticmethod @@ -104,9 +104,9 @@ def make_rev_args(username, password): # type: (Optional[str], Optional[HiddenText]) -> CommandArgs extra_args = [] # type: CommandArgs if username: - extra_args += ['--username', username] + extra_args += ["--username", username] if password: - extra_args += ['--password', password] + extra_args += ["--password", password] return extra_args @@ -116,7 +116,7 @@ def get_remote_url(cls, location): # setup.py we have to look up in the location until we find a real # setup.py orig_location = location - while not os.path.exists(os.path.join(location, 'setup.py')): + while not os.path.exists(os.path.join(location, "setup.py")): last_location = location location = os.path.dirname(location) if location == last_location: @@ -135,26 +135,23 @@ def get_remote_url(cls, location): def _get_svn_url_rev(cls, location): from pip._internal.exceptions import SubProcessError - entries_path = os.path.join(location, cls.dirname, 'entries') + entries_path = os.path.join(location, cls.dirname, "entries") if os.path.exists(entries_path): with open(entries_path) as f: data = f.read() else: # subversion >= 1.7 does not have the 'entries' file - data = '' + data = "" - if (data.startswith('8') or - data.startswith('9') or - data.startswith('10')): - data = list(map(str.splitlines, data.split('\n\x0c\n'))) + if data.startswith("8") or data.startswith("9") or data.startswith("10"): + data = list(map(str.splitlines, data.split("\n\x0c\n"))) del data[0][0] # get rid of the '8' url = data[0][3] revs = [int(d[9]) for d in data if len(d) > 9 and d[9]] + [0] - elif data.startswith('= 1.8 runs in non-interactive mode if @@ -281,7 +276,7 @@ def get_remote_call_options(self): # SVN 1.7, pip should continue to support SVN 1.7. Therefore, pip # can't safely add the option if the SVN version is < 1.8 (or unknown). if svn_version >= (1, 8): - return ['--force-interactive'] + return ["--force-interactive"] return [] @@ -290,15 +285,18 @@ def export(self, location, url): """Export the svn repository at the url to the destination location""" url, rev_options = self.get_url_rev_options(url) - logger.info('Exporting svn repository %s to %s', url, location) + logger.info("Exporting svn repository %s to %s", url, location) with indent_log(): if os.path.exists(location): # Subversion doesn't like to check out over an existing # directory --force fixes this, but was only added in svn 1.5 rmtree(location) cmd_args = make_command( - 'export', self.get_remote_call_options(), - rev_options.to_args(), url, location, + "export", + self.get_remote_call_options(), + rev_options.to_args(), + url, + location, ) self.run_command(cmd_args) @@ -306,29 +304,38 @@ def fetch_new(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None rev_display = rev_options.to_display() logger.info( - 'Checking out %s%s to %s', + "Checking out %s%s to %s", url, rev_display, display_path(dest), ) cmd_args = make_command( - 'checkout', '-q', self.get_remote_call_options(), - rev_options.to_args(), url, dest, + "checkout", + "-q", + self.get_remote_call_options(), + rev_options.to_args(), + url, + dest, ) self.run_command(cmd_args) def switch(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None cmd_args = make_command( - 'switch', self.get_remote_call_options(), rev_options.to_args(), - url, dest, + "switch", + self.get_remote_call_options(), + rev_options.to_args(), + url, + dest, ) self.run_command(cmd_args) def update(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None cmd_args = make_command( - 'update', self.get_remote_call_options(), rev_options.to_args(), + "update", + self.get_remote_call_options(), + rev_options.to_args(), dest, ) self.run_command(cmd_args) diff --git a/src/pip/_internal/vcs/versioncontrol.py b/src/pip/_internal/vcs/versioncontrol.py index e4f61a99c12..108bafd71b3 100644 --- a/src/pip/_internal/vcs/versioncontrol.py +++ b/src/pip/_internal/vcs/versioncontrol.py @@ -12,11 +12,7 @@ from pip._vendor import pkg_resources from pip._vendor.six.moves.urllib import parse as urllib_parse -from pip._internal.exceptions import ( - BadCommand, - InstallationError, - SubProcessError, -) +from pip._internal.exceptions import BadCommand, InstallationError, SubProcessError from pip._internal.utils.compat import console_to_str, samefile from pip._internal.utils.logging import subprocess_logger from pip._internal.utils.misc import ( @@ -57,7 +53,7 @@ AuthInfo = Tuple[Optional[str], Optional[str]] -__all__ = ['vcs'] +__all__ = ["vcs"] logger = logging.getLogger(__name__) @@ -71,7 +67,7 @@ def is_url(name): scheme = get_url_scheme(name) if scheme is None: return False - return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes + return scheme in ["http", "https", "file", "ftp"] + vcs.all_schemes def make_vcs_requirement_url(repo_url, rev, project_name, subdir=None): @@ -84,9 +80,9 @@ def make_vcs_requirement_url(repo_url, rev, project_name, subdir=None): project_name: the (unescaped) project name. """ egg_project_name = pkg_resources.to_filename(project_name) - req = '{}@{}#egg={}'.format(repo_url, rev, egg_project_name) + req = "{}@{}#egg={}".format(repo_url, rev, egg_project_name) if subdir: - req += '&subdirectory={}'.format(subdir) + req += "&subdirectory={}".format(subdir) return req @@ -96,7 +92,7 @@ def call_subprocess( cwd=None, # type: Optional[str] extra_environ=None, # type: Optional[Mapping[str, Any]] extra_ok_returncodes=None, # type: Optional[Iterable[int]] - log_failed_cmd=True # type: Optional[bool] + log_failed_cmd=True, # type: Optional[bool] ): # type: (...) -> Text """ @@ -126,14 +122,16 @@ def call_subprocess( reveal_command_args(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, - cwd=cwd + cwd=cwd, ) if proc.stdin: proc.stdin.close() except Exception as exc: if log_failed_cmd: subprocess_logger.critical( - "Error %s while executing command %s", exc, command_desc, + "Error %s while executing command %s", + exc, + command_desc, ) raise all_output = [] @@ -145,7 +143,7 @@ def call_subprocess( if not line: break line = line.rstrip() - all_output.append(line + '\n') + all_output.append(line + "\n") # Show the line immediately. log_subprocess(line) @@ -155,9 +153,7 @@ def call_subprocess( if proc.stdout: proc.stdout.close() - proc_had_error = ( - proc.returncode and proc.returncode not in extra_ok_returncodes - ) + proc_had_error = proc.returncode and proc.returncode not in extra_ok_returncodes if proc_had_error: if not showing_subprocess and log_failed_cmd: # Then the subprocess streams haven't been logged to the @@ -170,11 +166,11 @@ def call_subprocess( ) subprocess_logger.error(msg) exc_msg = ( - 'Command errored out with exit status {}: {} ' - 'Check the logs for full command output.' + "Command errored out with exit status {}: {} " + "Check the logs for full command output." ).format(proc.returncode, command_desc) raise SubProcessError(exc_msg) - return ''.join(all_output) + return "".join(all_output) def find_path_to_setup_from_repo_root(location, repo_root): @@ -186,7 +182,7 @@ def find_path_to_setup_from_repo_root(location, repo_root): """ # find setup.py orig_location = location - while not os.path.exists(os.path.join(location, 'setup.py')): + while not os.path.exists(os.path.join(location, "setup.py")): last_location = location location = os.path.dirname(location) if location == last_location: @@ -241,7 +237,7 @@ def __init__( def __repr__(self): # type: () -> str - return ''.format(self.vc_class.name, self.rev) + return "".format(self.vc_class.name, self.rev) @property def arg_rev(self): @@ -267,9 +263,9 @@ def to_args(self): def to_display(self): # type: () -> str if not self.rev: - return '' + return "" - return ' (to revision {})'.format(self.rev) + return " (to revision {})".format(self.rev) def make_new(self, rev): # type: (str) -> RevOptions @@ -284,7 +280,7 @@ def make_new(self, rev): class VcsSupport(object): _registry = {} # type: Dict[str, VersionControl] - schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] + schemes = ["ssh", "git", "hg", "bzr", "sftp", "svn"] def __init__(self): # type: () -> None @@ -292,7 +288,7 @@ def __init__(self): # systems urllib_parse.uses_netloc.extend(self.schemes) # Python >= 2.7.4, 3.3 doesn't have uses_fragment - if getattr(urllib_parse, 'uses_fragment', None): + if getattr(urllib_parse, "uses_fragment", None): urllib_parse.uses_fragment.extend(self.schemes) super(VcsSupport, self).__init__() @@ -320,12 +316,12 @@ def all_schemes(self): def register(self, cls): # type: (Type[VersionControl]) -> None - if not hasattr(cls, 'name'): - logger.warning('Cannot register VCS %s', cls.__name__) + if not hasattr(cls, "name"): + logger.warning("Cannot register VCS %s", cls.__name__) return if cls.name not in self._registry: self._registry[cls.name] = cls() - logger.debug('Registered VCS backend: %s', cls.name) + logger.debug("Registered VCS backend: %s", cls.name) def unregister(self, name): # type: (str) -> None @@ -343,8 +339,7 @@ def get_backend_for_dir(self, location): repo_path = vcs_backend.get_repository_root(location) if not repo_path: continue - logger.debug('Determine that %s uses VCS: %s', - location, vcs_backend.name) + logger.debug("Determine that %s uses VCS: %s", location, vcs_backend.name) vcs_backends[repo_path] = vcs_backend if not vcs_backends: @@ -380,9 +375,9 @@ def get_backend(self, name): class VersionControl(object): - name = '' - dirname = '' - repo_name = '' + name = "" + dirname = "" + repo_name = "" # List of supported schemes for this Version Control schemes = () # type: Tuple[str, ...] # Iterable of environment variable names to pass to call_subprocess(). @@ -396,7 +391,7 @@ def should_add_vcs_url_prefix(cls, remote_url): Return whether the vcs prefix (e.g. "git+") should be added to a repository's remote url when used in a requirement. """ - return not remote_url.lower().startswith('{}:'.format(cls.name)) + return not remote_url.lower().startswith("{}:".format(cls.name)) @classmethod def get_subdirectory(cls, location): @@ -434,12 +429,11 @@ def get_src_requirement(cls, repo_dir, project_name): return None if cls.should_add_vcs_url_prefix(repo_url): - repo_url = '{}+{}'.format(cls.name, repo_url) + repo_url = "{}+{}".format(cls.name, repo_url) revision = cls.get_requirement_revision(repo_dir) subdir = cls.get_subdirectory(repo_dir) - req = make_vcs_requirement_url(repo_url, revision, project_name, - subdir=subdir) + req = make_vcs_requirement_url(repo_url, revision, project_name, subdir=subdir) return req @@ -484,8 +478,8 @@ def make_rev_options(cls, rev=None, extra_args=None): def _is_local_repository(cls, repo): # type: (str) -> bool """ - posix absolute paths start with os.path.sep, - win32 ones start with drive (like c:\\folder) + posix absolute paths start with os.path.sep, + win32 ones start with drive (like c:\\folder) """ drive, tail = os.path.splitdrive(repo) return repo.startswith(os.path.sep) or bool(drive) @@ -530,25 +524,25 @@ def get_url_rev_and_auth(cls, url): Returns: (url, rev, (username, password)). """ scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) - if '+' not in scheme: + if "+" not in scheme: raise ValueError( "Sorry, {!r} is a malformed VCS url. " "The format is +://, " "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp".format(url) ) # Remove the vcs prefix. - scheme = scheme.split('+', 1)[1] + scheme = scheme.split("+", 1)[1] netloc, user_pass = cls.get_netloc_and_auth(netloc, scheme) rev = None - if '@' in path: - path, rev = path.rsplit('@', 1) + if "@" in path: + path, rev = path.rsplit("@", 1) if not rev: raise InstallationError( "The URL {!r} has an empty revision (after @) " "which is not supported. Include a revision after @ " "or remove @ from the URL.".format(url) ) - url = urllib_parse.urlunsplit((scheme, netloc, path, query, '')) + url = urllib_parse.urlunsplit((scheme, netloc, path, query, "")) return url, rev, user_pass @staticmethod @@ -582,7 +576,7 @@ def normalize_url(url): Normalize a URL for comparison by unquoting it and removing any trailing slash. """ - return urllib_parse.unquote(url).rstrip('/') + return urllib_parse.unquote(url).rstrip("/") @classmethod def compare_urls(cls, url1, url2): @@ -590,7 +584,7 @@ def compare_urls(cls, url1, url2): """ Compare two repo URLs for identity, ignoring incidental differences. """ - return (cls.normalize_url(url1) == cls.normalize_url(url2)) + return cls.normalize_url(url1) == cls.normalize_url(url2) def fetch_new(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None @@ -656,73 +650,72 @@ def obtain(self, dest, url): existing_url = self.get_remote_url(dest) if self.compare_urls(existing_url, url.secret): logger.debug( - '%s in %s exists, and has correct URL (%s)', + "%s in %s exists, and has correct URL (%s)", self.repo_name.title(), display_path(dest), url, ) if not self.is_commit_id_equal(dest, rev_options.rev): logger.info( - 'Updating %s %s%s', + "Updating %s %s%s", display_path(dest), self.repo_name, rev_display, ) self.update(dest, url, rev_options) else: - logger.info('Skipping because already up-to-date.') + logger.info("Skipping because already up-to-date.") return logger.warning( - '%s %s in %s exists with URL %s', + "%s %s in %s exists with URL %s", self.name, self.repo_name, display_path(dest), existing_url, ) - prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', - ('s', 'i', 'w', 'b')) + prompt = ("(s)witch, (i)gnore, (w)ipe, (b)ackup ", ("s", "i", "w", "b")) else: logger.warning( - 'Directory %s already exists, and is not a %s %s.', + "Directory %s already exists, and is not a %s %s.", dest, self.name, self.repo_name, ) # https://github.com/python/mypy/issues/1174 - prompt = ('(i)gnore, (w)ipe, (b)ackup ', # type: ignore - ('i', 'w', 'b')) + prompt = ("(i)gnore, (w)ipe, (b)ackup ", ("i", "w", "b")) # type: ignore logger.warning( - 'The plan is to install the %s repository %s', + "The plan is to install the %s repository %s", self.name, url, ) - response = ask_path_exists('What to do? {}'.format( - prompt[0]), prompt[1]) + response = ask_path_exists("What to do? {}".format(prompt[0]), prompt[1]) - if response == 'a': + if response == "a": sys.exit(-1) - if response == 'w': - logger.warning('Deleting %s', display_path(dest)) + if response == "w": + logger.warning("Deleting %s", display_path(dest)) rmtree(dest) self.fetch_new(dest, url, rev_options) return - if response == 'b': + if response == "b": dest_dir = backup_dir(dest) logger.warning( - 'Backing up %s to %s', display_path(dest), dest_dir, + "Backing up %s to %s", + display_path(dest), + dest_dir, ) shutil.move(dest, dest_dir) self.fetch_new(dest, url, rev_options) return # Do nothing if the response is "i". - if response == 's': + if response == "s": logger.info( - 'Switching %s %s to %s%s', + "Switching %s %s to %s%s", self.repo_name, display_path(dest), url, @@ -768,7 +761,7 @@ def run_command( cwd=None, # type: Optional[str] extra_environ=None, # type: Optional[Mapping[str, Any]] extra_ok_returncodes=None, # type: Optional[Iterable[int]] - log_failed_cmd=True # type: bool + log_failed_cmd=True, # type: bool ): # type: (...) -> Text """ @@ -778,18 +771,22 @@ def run_command( """ cmd = make_command(cls.name, *cmd) try: - return call_subprocess(cmd, cwd, - extra_environ=extra_environ, - extra_ok_returncodes=extra_ok_returncodes, - log_failed_cmd=log_failed_cmd) + return call_subprocess( + cmd, + cwd, + extra_environ=extra_environ, + extra_ok_returncodes=extra_ok_returncodes, + log_failed_cmd=log_failed_cmd, + ) except OSError as e: # errno.ENOENT = no such file or directory # In other words, the VCS executable isn't available if e.errno == errno.ENOENT: raise BadCommand( - 'Cannot find command {cls.name!r} - do you have ' - '{cls.name!r} installed and in your ' - 'PATH?'.format(**locals())) + "Cannot find command {cls.name!r} - do you have " + "{cls.name!r} installed and in your " + "PATH?".format(**locals()) + ) else: raise # re-raise exception if a different error occurred @@ -799,8 +796,7 @@ def is_repository_directory(cls, path): """ Return whether a directory path is a repository directory. """ - logger.debug('Checking in %s for %s (%s)...', - path, cls.dirname, cls.name) + logger.debug("Checking in %s for %s (%s)...", path, cls.dirname, cls.name) return os.path.exists(os.path.join(path, cls.dirname)) @classmethod diff --git a/src/pip/_internal/wheel_builder.py b/src/pip/_internal/wheel_builder.py index 27fce66c264..f7d25070645 100644 --- a/src/pip/_internal/wheel_builder.py +++ b/src/pip/_internal/wheel_builder.py @@ -29,7 +29,7 @@ logger = logging.getLogger(__name__) -_egg_info_re = re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.IGNORECASE) +_egg_info_re = re.compile(r"([a-z0-9_.]+)-([a-z0-9_.!+-]+)", re.IGNORECASE) def _contains_egg_info(s): @@ -54,7 +54,8 @@ def _should_build( if req.is_wheel: if need_wheel: logger.info( - 'Skipping %s, due to already being wheel.', req.name, + "Skipping %s, due to already being wheel.", + req.name, ) return False @@ -70,8 +71,8 @@ def _should_build( if not check_binary_allowed(req): logger.info( - "Skipping wheel build for %s, due to binaries " - "being disabled for it.", req.name, + "Skipping wheel build for %s, due to binaries " "being disabled for it.", + req.name, ) return False @@ -79,7 +80,8 @@ def _should_build( # we don't build legacy requirements if wheel is not installed logger.info( "Using legacy 'setup.py install' for %s, " - "since package 'wheel' is not installed.", req.name, + "since package 'wheel' is not installed.", + req.name, ) return False @@ -90,9 +92,7 @@ def should_build_for_wheel_command( req, # type: InstallRequirement ): # type: (...) -> bool - return _should_build( - req, need_wheel=True, check_binary_allowed=_always_true - ) + return _should_build(req, need_wheel=True, check_binary_allowed=_always_true) def should_build_for_install_command( @@ -176,15 +176,14 @@ def _build_one( except OSError as e: logger.warning( "Building wheel for %s failed: %s", - req.name, e, + req.name, + e, ) return None # Install build deps into temporary directory (PEP 518) with req.build_env: - return _build_one_inside_env( - req, output_dir, build_options, global_options - ) + return _build_one_inside_env(req, output_dir, build_options, global_options) def _build_one_inside_env( @@ -221,16 +220,20 @@ def _build_one_inside_env( try: wheel_hash, length = hash_file(wheel_path) shutil.move(wheel_path, dest_path) - logger.info('Created wheel for %s: ' - 'filename=%s size=%d sha256=%s', - req.name, wheel_name, length, - wheel_hash.hexdigest()) - logger.info('Stored in directory: %s', output_dir) + logger.info( + "Created wheel for %s: " "filename=%s size=%d sha256=%s", + req.name, + wheel_name, + length, + wheel_hash.hexdigest(), + ) + logger.info("Stored in directory: %s", output_dir) return dest_path except Exception as e: logger.warning( "Building wheel for %s failed: %s", - req.name, e, + req.name, + e, ) # Ignore return, we can't do anything else useful. if not req.use_pep517: @@ -245,12 +248,12 @@ def _clean_one_legacy(req, global_options): global_options=global_options, ) - logger.info('Running setup.py clean for %s', req.name) + logger.info("Running setup.py clean for %s", req.name) try: call_subprocess(clean_args, cwd=req.source_dir) return True except Exception: - logger.error('Failed cleaning build dir for %s', req.name) + logger.error("Failed cleaning build dir for %s", req.name) return False @@ -271,17 +274,15 @@ def build( # Build the wheels. logger.info( - 'Building wheels for collected packages: %s', - ', '.join(req.name for req in requirements), # type: ignore + "Building wheels for collected packages: %s", + ", ".join(req.name for req in requirements), # type: ignore ) with indent_log(): build_successes, build_failures = [], [] for req in requirements: cache_dir = _get_cache_dir(req, wheel_cache) - wheel_file = _build_one( - req, cache_dir, build_options, global_options - ) + wheel_file = _build_one(req, cache_dir, build_options, global_options) if wheel_file: # Update the link for this. req.link = Link(path_to_url(wheel_file)) @@ -294,13 +295,13 @@ def build( # notify success/failure if build_successes: logger.info( - 'Successfully built %s', - ' '.join([req.name for req in build_successes]), # type: ignore + "Successfully built %s", + " ".join([req.name for req in build_successes]), # type: ignore ) if build_failures: logger.info( - 'Failed to build %s', - ' '.join([req.name for req in build_failures]), # type: ignore + "Failed to build %s", + " ".join([req.name for req in build_failures]), # type: ignore ) # Return a list of requirements that failed to build return build_successes, build_failures diff --git a/tests/conftest.py b/tests/conftest.py index ffd9f42158b..13b333541e8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,29 +60,32 @@ def pytest_addoption(parser): def pytest_collection_modifyitems(config, items): for item in items: - if not hasattr(item, 'module'): # e.g.: DoctestTextfile + if not hasattr(item, "module"): # e.g.: DoctestTextfile continue # Mark network tests as flaky - if (item.get_closest_marker('network') is not None and - "CI" in os.environ): + if item.get_closest_marker("network") is not None and "CI" in os.environ: item.add_marker(pytest.mark.flaky(reruns=3)) - if (item.get_closest_marker('fails_on_new_resolver') and - config.getoption("--new-resolver") and - not config.getoption("--new-resolver-runtests")): - item.add_marker(pytest.mark.skip( - 'This test does not work with the new resolver')) + if ( + item.get_closest_marker("fails_on_new_resolver") + and config.getoption("--new-resolver") + and not config.getoption("--new-resolver-runtests") + ): + item.add_marker( + pytest.mark.skip("This test does not work with the new resolver") + ) if six.PY3: - if (item.get_closest_marker('incompatible_with_test_venv') and - config.getoption("--use-venv")): - item.add_marker(pytest.mark.skip( - 'Incompatible with test venv')) - if (item.get_closest_marker('incompatible_with_venv') and - sys.prefix != sys.base_prefix): - item.add_marker(pytest.mark.skip( - 'Incompatible with venv')) + if item.get_closest_marker( + "incompatible_with_test_venv" + ) and config.getoption("--use-venv"): + item.add_marker(pytest.mark.skip("Incompatible with test venv")) + if ( + item.get_closest_marker("incompatible_with_venv") + and sys.prefix != sys.base_prefix + ): + item.add_marker(pytest.mark.skip("Incompatible with venv")) module_path = os.path.relpath( item.module.__file__, @@ -90,22 +93,21 @@ def pytest_collection_modifyitems(config, items): ) module_root_dir = module_path.split(os.pathsep)[0] - if (module_root_dir.startswith("functional") or - module_root_dir.startswith("integration") or - module_root_dir.startswith("lib")): + if ( + module_root_dir.startswith("functional") + or module_root_dir.startswith("integration") + or module_root_dir.startswith("lib") + ): item.add_marker(pytest.mark.integration) elif module_root_dir.startswith("unit"): item.add_marker(pytest.mark.unit) else: - raise RuntimeError( - "Unknown test type (filename = {})".format(module_path) - ) + raise RuntimeError("Unknown test type (filename = {})".format(module_path)) @pytest.fixture(scope="session", autouse=True) def use_new_resolver(request): - """Set environment variable to make pip default to the new resolver. - """ + """Set environment variable to make pip default to the new resolver.""" new_resolver = request.config.getoption("--new-resolver") features = set(os.environ.get("PIP_USE_FEATURE", "").split()) if new_resolver: @@ -116,9 +118,9 @@ def use_new_resolver(request): yield new_resolver -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def tmpdir_factory(request, tmpdir_factory): - """ Modified `tmpdir_factory` session fixture + """Modified `tmpdir_factory` session fixture that will automatically cleanup after itself. """ yield tmpdir_factory @@ -176,17 +178,17 @@ def isolate(tmpdir, monkeypatch): fake_root = os.path.join(str(tmpdir), "fake-root") os.makedirs(fake_root) - if sys.platform == 'win32': + if sys.platform == "win32": # Note: this will only take effect in subprocesses... home_drive, home_path = os.path.splitdrive(home_dir) - monkeypatch.setenv('USERPROFILE', home_dir) - monkeypatch.setenv('HOMEDRIVE', home_drive) - monkeypatch.setenv('HOMEPATH', home_path) + monkeypatch.setenv("USERPROFILE", home_dir) + monkeypatch.setenv("HOMEDRIVE", home_drive) + monkeypatch.setenv("HOMEPATH", home_path) for env_var, sub_path in ( - ('APPDATA', 'AppData/Roaming'), - ('LOCALAPPDATA', 'AppData/Local'), + ("APPDATA", "AppData/Roaming"), + ("LOCALAPPDATA", "AppData/Local"), ): - path = os.path.join(home_dir, *sub_path.split('/')) + path = os.path.join(home_dir, *sub_path.split("/")) monkeypatch.setenv(env_var, path) os.makedirs(path) else: @@ -195,23 +197,46 @@ def isolate(tmpdir, monkeypatch): # of the user's actual $HOME directory. monkeypatch.setenv("HOME", home_dir) # Isolate ourselves from XDG directories - monkeypatch.setenv("XDG_DATA_HOME", os.path.join( - home_dir, ".local", "share", - )) - monkeypatch.setenv("XDG_CONFIG_HOME", os.path.join( - home_dir, ".config", - )) + monkeypatch.setenv( + "XDG_DATA_HOME", + os.path.join( + home_dir, + ".local", + "share", + ), + ) + monkeypatch.setenv( + "XDG_CONFIG_HOME", + os.path.join( + home_dir, + ".config", + ), + ) monkeypatch.setenv("XDG_CACHE_HOME", os.path.join(home_dir, ".cache")) - monkeypatch.setenv("XDG_RUNTIME_DIR", os.path.join( - home_dir, ".runtime", - )) - monkeypatch.setenv("XDG_DATA_DIRS", os.pathsep.join([ - os.path.join(fake_root, "usr", "local", "share"), - os.path.join(fake_root, "usr", "share"), - ])) - monkeypatch.setenv("XDG_CONFIG_DIRS", os.path.join( - fake_root, "etc", "xdg", - )) + monkeypatch.setenv( + "XDG_RUNTIME_DIR", + os.path.join( + home_dir, + ".runtime", + ), + ) + monkeypatch.setenv( + "XDG_DATA_DIRS", + os.pathsep.join( + [ + os.path.join(fake_root, "usr", "local", "share"), + os.path.join(fake_root, "usr", "share"), + ] + ), + ) + monkeypatch.setenv( + "XDG_CONFIG_DIRS", + os.path.join( + fake_root, + "etc", + "xdg", + ), + ) # Configure git, because without an author name/email git will complain # and cause test failures. @@ -228,9 +253,7 @@ def isolate(tmpdir, monkeypatch): # FIXME: Windows... os.makedirs(os.path.join(home_dir, ".config", "git")) with open(os.path.join(home_dir, ".config", "git", "config"), "wb") as fp: - fp.write( - b"[user]\n\tname = pip\n\temail = distutils-sig@python.org\n" - ) + fp.write(b"[user]\n\tname = pip\n\temail = distutils-sig@python.org\n") @pytest.fixture(autouse=True) @@ -249,7 +272,7 @@ def scoped_global_tempdir_manager(request): yield -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def pip_src(tmpdir_factory): def not_code_files_and_folders(path, names): # In the root directory... @@ -269,7 +292,7 @@ def not_code_files_and_folders(path, names): ignored.update(fnmatch.filter(names, pattern)) return ignored - pip_src = Path(str(tmpdir_factory.mktemp('pip_src'))).joinpath('pip_src') + pip_src = Path(str(tmpdir_factory.mktemp("pip_src"))).joinpath("pip_src") # Copy over our source tree so that each use is self contained shutil.copytree( SRC_DIR, @@ -280,83 +303,79 @@ def not_code_files_and_folders(path, names): def _common_wheel_editable_install(tmpdir_factory, common_wheels, package): - wheel_candidates = list( - common_wheels.glob('{package}-*.whl'.format(**locals()))) + wheel_candidates = list(common_wheels.glob("{package}-*.whl".format(**locals()))) assert len(wheel_candidates) == 1, wheel_candidates - install_dir = Path(str(tmpdir_factory.mktemp(package))) / 'install' + install_dir = Path(str(tmpdir_factory.mktemp(package))) / "install" Wheel(wheel_candidates[0]).install_as_egg(install_dir) - (install_dir / 'EGG-INFO').rename( - install_dir / '{package}.egg-info'.format(**locals())) + (install_dir / "EGG-INFO").rename( + install_dir / "{package}.egg-info".format(**locals()) + ) assert compileall.compile_dir(str(install_dir), quiet=1) return install_dir -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def setuptools_install(tmpdir_factory, common_wheels): - return _common_wheel_editable_install(tmpdir_factory, - common_wheels, - 'setuptools') + return _common_wheel_editable_install(tmpdir_factory, common_wheels, "setuptools") -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def wheel_install(tmpdir_factory, common_wheels): - return _common_wheel_editable_install(tmpdir_factory, - common_wheels, - 'wheel') + return _common_wheel_editable_install(tmpdir_factory, common_wheels, "wheel") -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def coverage_install(tmpdir_factory, common_wheels): - return _common_wheel_editable_install(tmpdir_factory, - common_wheels, - 'coverage') + return _common_wheel_editable_install(tmpdir_factory, common_wheels, "coverage") def install_egg_link(venv, project_name, egg_info_dir): - with open(venv.site / 'easy-install.pth', 'a') as fp: - fp.write(str(egg_info_dir.resolve()) + '\n') - with open(venv.site / (project_name + '.egg-link'), 'w') as fp: - fp.write(str(egg_info_dir) + '\n.') + with open(venv.site / "easy-install.pth", "a") as fp: + fp.write(str(egg_info_dir.resolve()) + "\n") + with open(venv.site / (project_name + ".egg-link"), "w") as fp: + fp.write(str(egg_info_dir) + "\n.") -@pytest.fixture(scope='session') -def virtualenv_template(request, tmpdir_factory, pip_src, - setuptools_install, coverage_install): +@pytest.fixture(scope="session") +def virtualenv_template( + request, tmpdir_factory, pip_src, setuptools_install, coverage_install +): - if six.PY3 and request.config.getoption('--use-venv'): - venv_type = 'venv' + if six.PY3 and request.config.getoption("--use-venv"): + venv_type = "venv" else: - venv_type = 'virtualenv' + venv_type = "virtualenv" # Create the virtual environment - tmpdir = Path(str(tmpdir_factory.mktemp('virtualenv'))) - venv = VirtualEnvironment( - tmpdir.joinpath("venv_orig"), venv_type=venv_type - ) + tmpdir = Path(str(tmpdir_factory.mktemp("virtualenv"))) + venv = VirtualEnvironment(tmpdir.joinpath("venv_orig"), venv_type=venv_type) # Install setuptools and pip. - install_egg_link(venv, 'setuptools', setuptools_install) - pip_editable = Path(str(tmpdir_factory.mktemp('pip'))) / 'pip' + install_egg_link(venv, "setuptools", setuptools_install) + pip_editable = Path(str(tmpdir_factory.mktemp("pip"))) / "pip" shutil.copytree(pip_src, pip_editable, symlinks=True) # noxfile.py is Python 3 only assert compileall.compile_dir( - str(pip_editable), quiet=1, rx=re.compile("noxfile.py$"), + str(pip_editable), + quiet=1, + rx=re.compile("noxfile.py$"), + ) + subprocess.check_call( + [venv.bin / "python", "setup.py", "-q", "develop"], cwd=pip_editable ) - subprocess.check_call([venv.bin / 'python', 'setup.py', '-q', 'develop'], - cwd=pip_editable) # Install coverage and pth file for executing it in any spawned processes # in this virtual environment. - install_egg_link(venv, 'coverage', coverage_install) + install_egg_link(venv, "coverage", coverage_install) # zz prefix ensures the file is after easy-install.pth. - with open(venv.site / 'zz-coverage-helper.pth', 'a') as f: - f.write('import coverage; coverage.process_startup()') + with open(venv.site / "zz-coverage-helper.pth", "a") as f: + f.write("import coverage; coverage.process_startup()") # Drop (non-relocatable) launchers. for exe in os.listdir(venv.bin): if not ( - exe.startswith('python') or - exe.startswith('libpy') # Don't remove libpypy-c.so... + exe.startswith("python") + or exe.startswith("libpy") # Don't remove libpypy-c.so... ): (venv.bin / exe).unlink() @@ -391,7 +410,7 @@ def virtualenv(virtualenv_factory, tmpdir): @pytest.fixture def with_wheel(virtualenv, wheel_install): - install_egg_link(virtualenv, 'wheel', wheel_install) + install_egg_link(virtualenv, "wheel", wheel_install) @pytest.fixture(scope="session") @@ -402,21 +421,16 @@ def factory(tmpdir, virtualenv=None): return PipTestEnvironment( # The base location for our test environment tmpdir, - # Tell the Test Environment where our virtualenv is located virtualenv=virtualenv, - # Do not ignore hidden files, they need to be checked as well ignore_hidden=False, - # We are starting with an already empty directory start_clear=False, - # We want to ensure no temporary files are left behind, so the # PipTestEnvironment needs to capture and assert against temp capture_temp=True, assert_no_temp=True, - # Deprecated python versions produce an extra deprecation warning pip_expect_warning=deprecated_python, ) @@ -438,7 +452,7 @@ def script(tmpdir, virtualenv, script_factory): @pytest.fixture(scope="session") def common_wheels(): """Provide a directory with latest setuptools and wheel wheels""" - return DATA_DIR.joinpath('common_wheels') + return DATA_DIR.joinpath("common_wheels") @pytest.fixture(scope="session") @@ -489,8 +503,7 @@ def deprecated_python(): def cert_factory(tmpdir_factory): def factory(): # type: () -> str - """Returns path to cert/key file. - """ + """Returns path to cert/key file.""" output_path = Path(str(tmpdir_factory.mktemp("certs"))) / "cert.pem" # Must be Text on PY2. cert, key = make_tls_cert(u"localhost") @@ -544,12 +557,9 @@ def stop(self): def get_requests(self): # type: () -> Dict[str, str] - """Get environ for each received request. - """ + """Get environ for each received request.""" assert not self._running, "cannot get mock from running server" - return [ - call.args[0] for call in self._server.mock.call_args_list - ] + return [call.args[0] for call in self._server.mock.call_args_list] @pytest.fixture @@ -563,8 +573,8 @@ def mock_server(): @pytest.fixture def utc(): # time.tzset() is not implemented on some platforms, e.g. Windows. - tzset = getattr(time, 'tzset', lambda: None) - with patch.dict(os.environ, {'TZ': 'UTC'}): + tzset = getattr(time, "tzset", lambda: None) + with patch.dict(os.environ, {"TZ": "UTC"}): tzset() yield tzset() diff --git a/tests/data/packages/BrokenEmitsUTF8/setup.py b/tests/data/packages/BrokenEmitsUTF8/setup.py index 81c5baeadba..a40bc60c18f 100644 --- a/tests/data/packages/BrokenEmitsUTF8/setup.py +++ b/tests/data/packages/BrokenEmitsUTF8/setup.py @@ -7,20 +7,32 @@ class FakeError(Exception): pass -if sys.argv[1] == 'install': - if hasattr(sys.stdout, 'buffer'): - sys.stdout.buffer.write('\nThis package prints out UTF-8 stuff like:\n'.encode('utf-8')) - sys.stdout.buffer.write('* return type of ‘main’ is not ‘int’\n'.encode('utf-8')) - sys.stdout.buffer.write('* Björk Guðmundsdóttir [ˈpjÅ“rÌ¥k ˈkvÊðmÊntsËŒtoÊŠhtɪr]'.encode('utf-8')) + +if sys.argv[1] == "install": + if hasattr(sys.stdout, "buffer"): + sys.stdout.buffer.write( + "\nThis package prints out UTF-8 stuff like:\n".encode("utf-8") + ) + sys.stdout.buffer.write( + "* return type of ‘main’ is not ‘int’\n".encode("utf-8") + ) + sys.stdout.buffer.write( + "* Björk Guðmundsdóttir [ˈpjÅ“rÌ¥k ˈkvÊðmÊntsËŒtoÊŠhtɪr]".encode("utf-8") + ) else: pass - sys.stdout.write('\nThis package prints out UTF-8 stuff like:\n') - sys.stdout.write('* return type of \xe2\x80\x98main\xe2\x80\x99 is not \xe2\x80\x98int\xe2\x80\x99\n') - sys.stdout.write('* Bj\xc3\xb6rk Gu\xc3\xb0mundsd\xc3\xb3ttir [\xcb\x88pj\xc5\x93r\xcc\xa5k \xcb\x88kv\xca\x8f\xc3\xb0m\xca\x8fnts\xcb\x8cto\xca\x8aht\xc9\xaar]\n') + sys.stdout.write("\nThis package prints out UTF-8 stuff like:\n") + sys.stdout.write( + "* return type of \xe2\x80\x98main\xe2\x80\x99 is not \xe2\x80\x98int\xe2\x80\x99\n" + ) + sys.stdout.write( + "* Bj\xc3\xb6rk Gu\xc3\xb0mundsd\xc3\xb3ttir [\xcb\x88pj\xc5\x93r\xcc\xa5k \xcb\x88kv\xca\x8f\xc3\xb0m\xca\x8fnts\xcb\x8cto\xca\x8aht\xc9\xaar]\n" + ) - raise FakeError('this package designed to fail on install') + raise FakeError("this package designed to fail on install") -setup(name='broken', - version='0.2', - py_modules=['broken'], - ) +setup( + name="broken", + version="0.2", + py_modules=["broken"], +) diff --git a/tests/data/packages/FSPkg/setup.py b/tests/data/packages/FSPkg/setup.py index d1b725e8cc4..58a78413339 100644 --- a/tests/data/packages/FSPkg/setup.py +++ b/tests/data/packages/FSPkg/setup.py @@ -1,25 +1,26 @@ from setuptools import find_packages, setup -version = '0.1dev' +version = "0.1dev" -setup(name='FSPkg', - version=version, - description="File system test package", - long_description="""\ +setup( + name="FSPkg", + version=version, + description="File system test package", + long_description="""\ File system test package""", - classifiers=[], # Get strings from https://pypi.org/pypi?%3Aaction=list_classifiers - keywords='pip tests', - author='pip', - author_email='pip@openplans.org', - url='http://pip.openplans.org', - license='', - packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), - include_package_data=True, - zip_safe=False, - install_requires=[ - # -*- Extra requirements: -*- - ], - entry_points=""" + classifiers=[], # Get strings from https://pypi.org/pypi?%3Aaction=list_classifiers + keywords="pip tests", + author="pip", + author_email="pip@openplans.org", + url="http://pip.openplans.org", + license="", + packages=find_packages(exclude=["ez_setup", "examples", "tests"]), + include_package_data=True, + zip_safe=False, + install_requires=[ + # -*- Extra requirements: -*- + ], + entry_points=""" # -*- Entry points: -*- """, - ) +) diff --git a/tests/data/packages/HackedEggInfo/setup.py b/tests/data/packages/HackedEggInfo/setup.py index 171f5a2a34b..36201f79e1d 100644 --- a/tests/data/packages/HackedEggInfo/setup.py +++ b/tests/data/packages/HackedEggInfo/setup.py @@ -4,14 +4,14 @@ from setuptools.command import egg_info as orig_egg_info -class egg_info (orig_egg_info.egg_info): +class egg_info(orig_egg_info.egg_info): def run(self): orig_egg_info.egg_info.run(self) setup( name="hackedegginfo", - version='0.0.0', - cmdclass={'egg_info':egg_info}, + version="0.0.0", + cmdclass={"egg_info": egg_info}, zip_safe=False, ) diff --git a/tests/data/packages/LocalEnvironMarker/setup.py b/tests/data/packages/LocalEnvironMarker/setup.py index 36ceb214cf7..0ab6c8a5719 100644 --- a/tests/data/packages/LocalEnvironMarker/setup.py +++ b/tests/data/packages/LocalEnvironMarker/setup.py @@ -11,17 +11,17 @@ def path_to_url(path): path = os.path.normpath(os.path.abspath(path)) drive, path = os.path.splitdrive(path) filepath = path.split(os.path.sep) - url = '/'.join(filepath) + url = "/".join(filepath) if drive: - return 'file:///' + drive + url - return 'file://' + url + return "file:///" + drive + url + return "file://" + url setup( - name='LocalEnvironMarker', - version='0.0.1', + name="LocalEnvironMarker", + version="0.0.1", packages=find_packages(), extras_require={ - ":python_version == '2.7'": ['simple'], - } + ":python_version == '2.7'": ["simple"], + }, ) diff --git a/tests/data/packages/LocalExtras-0.0.2/setup.py b/tests/data/packages/LocalExtras-0.0.2/setup.py index cc5c832837f..6e910d1cbb2 100644 --- a/tests/data/packages/LocalExtras-0.0.2/setup.py +++ b/tests/data/packages/LocalExtras-0.0.2/setup.py @@ -11,16 +11,16 @@ def path_to_url(path): path = os.path.normpath(os.path.abspath(path)) drive, path = os.path.splitdrive(path) filepath = path.split(os.path.sep) - url = '/'.join(filepath) + url = "/".join(filepath) if drive: - return 'file:///' + drive + url - return 'file://' + url + return "file:///" + drive + url + return "file://" + url setup( - name='LocalExtras', - version='0.0.2', + name="LocalExtras", + version="0.0.2", packages=find_packages(), - install_requires=['simple==1.0'], - extras_require={'bar': ['simple==2.0'], 'baz': ['singlemodule']} + install_requires=["simple==1.0"], + extras_require={"bar": ["simple==2.0"], "baz": ["singlemodule"]}, ) diff --git a/tests/data/packages/LocalExtras/setup.py b/tests/data/packages/LocalExtras/setup.py index eb390e32e89..4bf2179da78 100644 --- a/tests/data/packages/LocalExtras/setup.py +++ b/tests/data/packages/LocalExtras/setup.py @@ -11,15 +11,15 @@ def path_to_url(path): path = os.path.normpath(os.path.abspath(path)) drive, path = os.path.splitdrive(path) filepath = path.split(os.path.sep) - url = '/'.join(filepath) + url = "/".join(filepath) if drive: - return 'file:///' + drive + url - return 'file://' + url + return "file:///" + drive + url + return "file://" + url setup( - name='LocalExtras', - version='0.0.1', + name="LocalExtras", + version="0.0.1", packages=find_packages(), - extras_require={'bar': ['simple'], 'baz': ['singlemodule']} + extras_require={"bar": ["simple"], "baz": ["singlemodule"]}, ) diff --git a/tests/data/packages/SetupPyLatin1/setup.py b/tests/data/packages/SetupPyLatin1/setup.py index 3ca77c00c96..bc8967c5199 100644 --- a/tests/data/packages/SetupPyLatin1/setup.py +++ b/tests/data/packages/SetupPyLatin1/setup.py @@ -2,6 +2,7 @@ from distutils.core import setup -setup(name="SetupPyUTF8", - author=u"Saúl Ibarra Corretgé", - ) +setup( + name="SetupPyUTF8", + author=u"Saúl Ibarra Corretgé", +) diff --git a/tests/data/packages/SetupPyUTF8/setup.py b/tests/data/packages/SetupPyUTF8/setup.py index 9b65f5e79fc..e32aa438c5f 100644 --- a/tests/data/packages/SetupPyUTF8/setup.py +++ b/tests/data/packages/SetupPyUTF8/setup.py @@ -2,6 +2,7 @@ from distutils.core import setup -setup(name="SetupPyUTF8", - author="Saúl Ibarra Corretgé", - ) +setup( + name="SetupPyUTF8", + author="Saúl Ibarra Corretgé", +) diff --git a/tests/data/packages/pep517_wrapper_buildsys/mybuildsys.py b/tests/data/packages/pep517_wrapper_buildsys/mybuildsys.py index e2f920ba3f5..08645e8bd5b 100644 --- a/tests/data/packages/pep517_wrapper_buildsys/mybuildsys.py +++ b/tests/data/packages/pep517_wrapper_buildsys/mybuildsys.py @@ -2,9 +2,11 @@ from setuptools.build_meta import build_sdist from setuptools.build_meta import build_wheel as setuptools_build_wheel -from setuptools.build_meta import (get_requires_for_build_sdist, - get_requires_for_build_wheel, - prepare_metadata_for_build_wheel) +from setuptools.build_meta import ( + get_requires_for_build_sdist, + get_requires_for_build_wheel, + prepare_metadata_for_build_wheel, +) def build_wheel(*a, **kw): @@ -12,7 +14,7 @@ def build_wheel(*a, **kw): raise RuntimeError("Failing build_wheel, as requested.") # Create the marker file to record that the hook was called - with open(os.environ['PIP_TEST_MARKER_FILE'], 'wb'): + with open(os.environ["PIP_TEST_MARKER_FILE"], "wb"): pass return setuptools_build_wheel(*a, **kw) diff --git a/tests/data/packages/requiresPaste/requiresPaste.py b/tests/data/packages/requiresPaste/requiresPaste.py index c74209e44fe..84d4ed536d3 100644 --- a/tests/data/packages/requiresPaste/requiresPaste.py +++ b/tests/data/packages/requiresPaste/requiresPaste.py @@ -1,3 +1,3 @@ """Module requiring Paste to test dependencies download of pip wheel.""" -__version__ = '3.1.4' +__version__ = "3.1.4" diff --git a/tests/data/packages/requires_wheelbroken_upper/setup.py b/tests/data/packages/requires_wheelbroken_upper/setup.py index 150f98dfbf7..210b7c67ad8 100644 --- a/tests/data/packages/requires_wheelbroken_upper/setup.py +++ b/tests/data/packages/requires_wheelbroken_upper/setup.py @@ -3,4 +3,5 @@ setuptools.setup( name="requires_wheelbroken_upper", version="0", - install_requires=['wheelbroken', 'upper']) + install_requires=["wheelbroken", "upper"], +) diff --git a/tests/data/packages/symlinks/setup.py b/tests/data/packages/symlinks/setup.py index b71e35f1e1e..8605b6fae95 100644 --- a/tests/data/packages/symlinks/setup.py +++ b/tests/data/packages/symlinks/setup.py @@ -1,8 +1,9 @@ from setuptools import setup -version = '0.1' +version = "0.1" -setup(name='symlinks', - version=version, - packages=["symlinks"], - ) +setup( + name="symlinks", + version=version, + packages=["symlinks"], +) diff --git a/tests/data/src/TopoRequires/setup.py b/tests/data/src/TopoRequires/setup.py index 6cd29a7b656..c4b1029f55c 100644 --- a/tests/data/src/TopoRequires/setup.py +++ b/tests/data/src/TopoRequires/setup.py @@ -1,7 +1,7 @@ from setuptools import setup setup( - name='TopoRequires', - version='0.0.1', - packages=['toporequires'], + name="TopoRequires", + version="0.0.1", + packages=["toporequires"], ) diff --git a/tests/data/src/TopoRequires2/setup.py b/tests/data/src/TopoRequires2/setup.py index 019f43cb231..11d009c4175 100644 --- a/tests/data/src/TopoRequires2/setup.py +++ b/tests/data/src/TopoRequires2/setup.py @@ -1,8 +1,8 @@ from setuptools import setup setup( - name='TopoRequires2', - version='0.0.1', - packages=['toporequires2'], - install_requires=['TopoRequires'], + name="TopoRequires2", + version="0.0.1", + packages=["toporequires2"], + install_requires=["TopoRequires"], ) diff --git a/tests/data/src/TopoRequires3/setup.py b/tests/data/src/TopoRequires3/setup.py index 772ed618e3c..550bb008eb9 100644 --- a/tests/data/src/TopoRequires3/setup.py +++ b/tests/data/src/TopoRequires3/setup.py @@ -1,8 +1,8 @@ from setuptools import setup setup( - name='TopoRequires3', - version='0.0.1', - packages=['toporequires3'], - install_requires=['TopoRequires'], + name="TopoRequires3", + version="0.0.1", + packages=["toporequires3"], + install_requires=["TopoRequires"], ) diff --git a/tests/data/src/TopoRequires4/setup.py b/tests/data/src/TopoRequires4/setup.py index e276f55a240..077eec765a5 100644 --- a/tests/data/src/TopoRequires4/setup.py +++ b/tests/data/src/TopoRequires4/setup.py @@ -1,8 +1,8 @@ from setuptools import setup setup( - name='TopoRequires4', - version='0.0.1', - packages=['toporequires4'], - install_requires=['TopoRequires2', 'TopoRequires', 'TopoRequires3'], + name="TopoRequires4", + version="0.0.1", + packages=["toporequires4"], + install_requires=["TopoRequires2", "TopoRequires", "TopoRequires3"], ) diff --git a/tests/data/src/chattymodule/setup.py b/tests/data/src/chattymodule/setup.py index 01d7720765f..62d0111234e 100644 --- a/tests/data/src/chattymodule/setup.py +++ b/tests/data/src/chattymodule/setup.py @@ -14,7 +14,7 @@ setup( name="chattymodule", - version='0.0.1', + version="0.0.1", description="A sample Python project with a single module", - py_modules=['chattymodule'], + py_modules=["chattymodule"], ) diff --git a/tests/data/src/compilewheel/setup.py b/tests/data/src/compilewheel/setup.py index 8319a2a5c20..da994945048 100644 --- a/tests/data/src/compilewheel/setup.py +++ b/tests/data/src/compilewheel/setup.py @@ -1,7 +1,4 @@ #!/usr/bin/env python from setuptools import find_packages, setup -setup(name='compilewheel', - version='1.0', - packages=find_packages() - ) +setup(name="compilewheel", version="1.0", packages=find_packages()) diff --git a/tests/data/src/extension/setup.py b/tests/data/src/extension/setup.py index b26302b0536..83624965de5 100644 --- a/tests/data/src/extension/setup.py +++ b/tests/data/src/extension/setup.py @@ -1,4 +1,4 @@ from setuptools import Extension, setup -module = Extension('extension', sources=['extension.c']) -setup(name='extension', version='0.0.1', ext_modules = [module]) +module = Extension("extension", sources=["extension.c"]) +setup(name="extension", version="0.0.1", ext_modules=[module]) diff --git a/tests/data/src/pep518-3.0/pep518.py b/tests/data/src/pep518-3.0/pep518.py index 7986d11379a..9ce06a81ea4 100644 --- a/tests/data/src/pep518-3.0/pep518.py +++ b/tests/data/src/pep518-3.0/pep518.py @@ -1 +1 @@ -#dummy +# dummy diff --git a/tests/data/src/pep518-3.0/setup.py b/tests/data/src/pep518-3.0/setup.py index b63f59926f7..587c04fc07d 100644 --- a/tests/data/src/pep518-3.0/setup.py +++ b/tests/data/src/pep518-3.0/setup.py @@ -3,7 +3,8 @@ import simplewheel # ensure dependency is installed -setup(name='pep518', - version='3.0', - py_modules=['pep518'], - ) +setup( + name="pep518", + version="3.0", + py_modules=["pep518"], +) diff --git a/tests/data/src/pep518_conflicting_requires/pep518.py b/tests/data/src/pep518_conflicting_requires/pep518.py index 7986d11379a..9ce06a81ea4 100644 --- a/tests/data/src/pep518_conflicting_requires/pep518.py +++ b/tests/data/src/pep518_conflicting_requires/pep518.py @@ -1 +1 @@ -#dummy +# dummy diff --git a/tests/data/src/pep518_conflicting_requires/setup.py b/tests/data/src/pep518_conflicting_requires/setup.py index 34bdc16b5aa..28f3db53d6e 100644 --- a/tests/data/src/pep518_conflicting_requires/setup.py +++ b/tests/data/src/pep518_conflicting_requires/setup.py @@ -2,7 +2,7 @@ from setuptools import setup setup( - name='pep518_conflicting_requires', - version='1.0.0', - py_modules=['pep518'], + name="pep518_conflicting_requires", + version="1.0.0", + py_modules=["pep518"], ) diff --git a/tests/data/src/pep518_forkbomb-235/setup.py b/tests/data/src/pep518_forkbomb-235/setup.py index c8bc29287c9..f69346cac82 100644 --- a/tests/data/src/pep518_forkbomb-235/setup.py +++ b/tests/data/src/pep518_forkbomb-235/setup.py @@ -1,5 +1,3 @@ from setuptools import setup -setup(name='pep518_forkbomb', - version='235', - py_modules=['pep518_forkbomb']) +setup(name="pep518_forkbomb", version="235", py_modules=["pep518_forkbomb"]) diff --git a/tests/data/src/pep518_invalid_build_system/pep518.py b/tests/data/src/pep518_invalid_build_system/pep518.py index 7986d11379a..9ce06a81ea4 100644 --- a/tests/data/src/pep518_invalid_build_system/pep518.py +++ b/tests/data/src/pep518_invalid_build_system/pep518.py @@ -1 +1 @@ -#dummy +# dummy diff --git a/tests/data/src/pep518_invalid_build_system/setup.py b/tests/data/src/pep518_invalid_build_system/setup.py index ba23cf24ab2..de4161d3a04 100644 --- a/tests/data/src/pep518_invalid_build_system/setup.py +++ b/tests/data/src/pep518_invalid_build_system/setup.py @@ -2,7 +2,7 @@ from setuptools import setup setup( - name='pep518_invalid_build_system', - version='1.0.0', - py_modules=['pep518'], + name="pep518_invalid_build_system", + version="1.0.0", + py_modules=["pep518"], ) diff --git a/tests/data/src/pep518_invalid_requires/pep518.py b/tests/data/src/pep518_invalid_requires/pep518.py index 7986d11379a..9ce06a81ea4 100644 --- a/tests/data/src/pep518_invalid_requires/pep518.py +++ b/tests/data/src/pep518_invalid_requires/pep518.py @@ -1 +1 @@ -#dummy +# dummy diff --git a/tests/data/src/pep518_invalid_requires/setup.py b/tests/data/src/pep518_invalid_requires/setup.py index e8a92da312a..ff6ac8b324d 100644 --- a/tests/data/src/pep518_invalid_requires/setup.py +++ b/tests/data/src/pep518_invalid_requires/setup.py @@ -2,7 +2,7 @@ from setuptools import setup setup( - name='pep518_invalid_requires', - version='1.0.0', - py_modules=['pep518'], + name="pep518_invalid_requires", + version="1.0.0", + py_modules=["pep518"], ) diff --git a/tests/data/src/pep518_missing_requires/pep518.py b/tests/data/src/pep518_missing_requires/pep518.py index 7986d11379a..9ce06a81ea4 100644 --- a/tests/data/src/pep518_missing_requires/pep518.py +++ b/tests/data/src/pep518_missing_requires/pep518.py @@ -1 +1 @@ -#dummy +# dummy diff --git a/tests/data/src/pep518_missing_requires/setup.py b/tests/data/src/pep518_missing_requires/setup.py index cbc5d28af04..4d3c5f3e5f4 100644 --- a/tests/data/src/pep518_missing_requires/setup.py +++ b/tests/data/src/pep518_missing_requires/setup.py @@ -2,7 +2,7 @@ from setuptools import setup setup( - name='pep518_missing_requires', - version='1.0.0', - py_modules=['pep518'], + name="pep518_missing_requires", + version="1.0.0", + py_modules=["pep518"], ) diff --git a/tests/data/src/pep518_twin_forkbombs_first-234/setup.py b/tests/data/src/pep518_twin_forkbombs_first-234/setup.py index 55e9bbfb17d..acb97e18efc 100644 --- a/tests/data/src/pep518_twin_forkbombs_first-234/setup.py +++ b/tests/data/src/pep518_twin_forkbombs_first-234/setup.py @@ -1,5 +1,7 @@ from setuptools import setup -setup(name='pep518_twin_forkbombs_first', - version='234', - py_modules=['pep518_twin_forkbombs_first']) +setup( + name="pep518_twin_forkbombs_first", + version="234", + py_modules=["pep518_twin_forkbombs_first"], +) diff --git a/tests/data/src/pep518_twin_forkbombs_second-238/setup.py b/tests/data/src/pep518_twin_forkbombs_second-238/setup.py index 985af51df82..c14c1cfb025 100644 --- a/tests/data/src/pep518_twin_forkbombs_second-238/setup.py +++ b/tests/data/src/pep518_twin_forkbombs_second-238/setup.py @@ -1,5 +1,7 @@ from setuptools import setup -setup(name='pep518_twin_forkbombs_second', - version='238', - py_modules=['pep518_twin_forkbombs_second']) +setup( + name="pep518_twin_forkbombs_second", + version="238", + py_modules=["pep518_twin_forkbombs_second"], +) diff --git a/tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py b/tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py index 7986d11379a..9ce06a81ea4 100644 --- a/tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py +++ b/tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py @@ -1 +1 @@ -#dummy +# dummy diff --git a/tests/data/src/pep518_with_extra_and_markers-1.0/setup.py b/tests/data/src/pep518_with_extra_and_markers-1.0/setup.py index 29a8175e4d1..08e6eceac1b 100644 --- a/tests/data/src/pep518_with_extra_and_markers-1.0/setup.py +++ b/tests/data/src/pep518_with_extra_and_markers-1.0/setup.py @@ -7,9 +7,10 @@ import simple import simplewheel -assert simplewheel.__version__ == '1.0' if sys.version_info < (3,) else '2.0' +assert simplewheel.__version__ == "1.0" if sys.version_info < (3,) else "2.0" -setup(name='pep518_with_extra_and_markers', - version='1.0', - py_modules=['pep518_with_extra_and_markers'], - ) +setup( + name="pep518_with_extra_and_markers", + version="1.0", + py_modules=["pep518_with_extra_and_markers"], +) diff --git a/tests/data/src/pep518_with_namespace_package-1.0/setup.py b/tests/data/src/pep518_with_namespace_package-1.0/setup.py index 540ede4cf43..263ba19880e 100644 --- a/tests/data/src/pep518_with_namespace_package-1.0/setup.py +++ b/tests/data/src/pep518_with_namespace_package-1.0/setup.py @@ -3,7 +3,7 @@ import simple_namespace.module setup( - name='pep518_with_namespace_package', - version='1.0', - py_modules=['pep518_with_namespace_package'], + name="pep518_with_namespace_package", + version="1.0", + py_modules=["pep518_with_namespace_package"], ) diff --git a/tests/data/src/prjwithdatafile/setup.py b/tests/data/src/prjwithdatafile/setup.py index 94863b57b01..5ed643c96ce 100755 --- a/tests/data/src/prjwithdatafile/setup.py +++ b/tests/data/src/prjwithdatafile/setup.py @@ -2,11 +2,11 @@ from setuptools import setup setup( - name='prjwithdatafile', + name="prjwithdatafile", version="1.0", - packages=['prjwithdatafile'], + packages=["prjwithdatafile"], data_files=[ - (r'packages1', ['prjwithdatafile/README.txt']), - (r'packages2', ['prjwithdatafile/README.txt']) - ] + (r"packages1", ["prjwithdatafile/README.txt"]), + (r"packages2", ["prjwithdatafile/README.txt"]), + ], ) diff --git a/tests/data/src/requires_capitalized/setup.py b/tests/data/src/requires_capitalized/setup.py index b3f37b919a6..287704f8628 100644 --- a/tests/data/src/requires_capitalized/setup.py +++ b/tests/data/src/requires_capitalized/setup.py @@ -1,6 +1,3 @@ from setuptools import setup -setup(name='Requires_Capitalized', - version='0.1', - install_requires=['simple==1.0'] - ) +setup(name="Requires_Capitalized", version="0.1", install_requires=["simple==1.0"]) diff --git a/tests/data/src/requires_requires_capitalized/setup.py b/tests/data/src/requires_requires_capitalized/setup.py index d124d072846..8d099fddd21 100644 --- a/tests/data/src/requires_requires_capitalized/setup.py +++ b/tests/data/src/requires_requires_capitalized/setup.py @@ -1,6 +1,7 @@ from setuptools import setup -setup(name='requires_requires_capitalized', - version='1.0', - install_requires=['requires_Capitalized==0.1'] - ) +setup( + name="requires_requires_capitalized", + version="1.0", + install_requires=["requires_Capitalized==0.1"], +) diff --git a/tests/data/src/requires_simple/setup.py b/tests/data/src/requires_simple/setup.py index 57122041aed..5eebde770d2 100644 --- a/tests/data/src/requires_simple/setup.py +++ b/tests/data/src/requires_simple/setup.py @@ -1,6 +1,3 @@ from setuptools import find_packages, setup -setup(name='requires_simple', - version='0.1', - install_requires=['simple==1.0'] - ) +setup(name="requires_simple", version="0.1", install_requires=["simple==1.0"]) diff --git a/tests/data/src/requires_simple_extra/setup.py b/tests/data/src/requires_simple_extra/setup.py index 3378c2ce7d1..5562ebc9541 100644 --- a/tests/data/src/requires_simple_extra/setup.py +++ b/tests/data/src/requires_simple_extra/setup.py @@ -1,9 +1,8 @@ from setuptools import setup -setup(name='requires_simple_extra', - version='0.1', - py_modules=['requires_simple_extra'], - extras_require={ - 'extra': ['simple==1.0'] - } +setup( + name="requires_simple_extra", + version="0.1", + py_modules=["requires_simple_extra"], + extras_require={"extra": ["simple==1.0"]}, ) diff --git a/tests/data/src/simple_namespace/setup.py b/tests/data/src/simple_namespace/setup.py index 9a49d52b757..c6b5978641c 100644 --- a/tests/data/src/simple_namespace/setup.py +++ b/tests/data/src/simple_namespace/setup.py @@ -1,8 +1,8 @@ from setuptools import setup setup( - name='simple_namespace', - version='1.0', - namespace_packages=['simple_namespace'], - packages=['simple_namespace.module'], + name="simple_namespace", + version="1.0", + namespace_packages=["simple_namespace"], + packages=["simple_namespace.module"], ) diff --git a/tests/data/src/simplewheel-1.0/setup.py b/tests/data/src/simplewheel-1.0/setup.py index 461536dce68..28ee850cd48 100644 --- a/tests/data/src/simplewheel-1.0/setup.py +++ b/tests/data/src/simplewheel-1.0/setup.py @@ -3,7 +3,8 @@ import simplewheel -setup(name='simplewheel', - version=simplewheel.__version__, - packages=['simplewheel'], - ) +setup( + name="simplewheel", + version=simplewheel.__version__, + packages=["simplewheel"], +) diff --git a/tests/data/src/simplewheel-1.0/simplewheel/__init__.py b/tests/data/src/simplewheel-1.0/simplewheel/__init__.py index 7e49527e386..4802e90f8ed 100644 --- a/tests/data/src/simplewheel-1.0/simplewheel/__init__.py +++ b/tests/data/src/simplewheel-1.0/simplewheel/__init__.py @@ -1 +1 @@ -__version__ = '1.0' +__version__ = "1.0" diff --git a/tests/data/src/simplewheel-2.0/setup.py b/tests/data/src/simplewheel-2.0/setup.py index 461536dce68..28ee850cd48 100644 --- a/tests/data/src/simplewheel-2.0/setup.py +++ b/tests/data/src/simplewheel-2.0/setup.py @@ -3,7 +3,8 @@ import simplewheel -setup(name='simplewheel', - version=simplewheel.__version__, - packages=['simplewheel'], - ) +setup( + name="simplewheel", + version=simplewheel.__version__, + packages=["simplewheel"], +) diff --git a/tests/data/src/simplewheel-2.0/simplewheel/__init__.py b/tests/data/src/simplewheel-2.0/simplewheel/__init__.py index 3b3dacb9af5..f2dc0e40061 100644 --- a/tests/data/src/simplewheel-2.0/simplewheel/__init__.py +++ b/tests/data/src/simplewheel-2.0/simplewheel/__init__.py @@ -1 +1 @@ -__version__ = '2.0' +__version__ = "2.0" diff --git a/tests/data/src/singlemodule/setup.py b/tests/data/src/singlemodule/setup.py index 622af1f8e99..e6358e2f7ca 100644 --- a/tests/data/src/singlemodule/setup.py +++ b/tests/data/src/singlemodule/setup.py @@ -2,7 +2,7 @@ setup( name="singlemodule", - version='0.0.1', + version="0.0.1", description="A sample Python project with a single module", - py_modules=['singlemodule'], + py_modules=["singlemodule"], ) diff --git a/tests/data/src/withpyproject/setup.py b/tests/data/src/withpyproject/setup.py index 1ea9e3e41c5..af10b3e3f37 100644 --- a/tests/data/src/withpyproject/setup.py +++ b/tests/data/src/withpyproject/setup.py @@ -1,3 +1,3 @@ from setuptools import setup -setup(name='withpyproject', version='0.0.1') +setup(name="withpyproject", version="0.0.1") diff --git a/tests/functional/test_broken_stdout.py b/tests/functional/test_broken_stdout.py index cb98e31f017..c154566a005 100644 --- a/tests/functional/test_broken_stdout.py +++ b/tests/functional/test_broken_stdout.py @@ -12,14 +12,16 @@ def setup_broken_stdout_test(args, deprecated_python): proc = subprocess.Popen( - args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, ) # Call close() on stdout to cause a broken pipe. proc.stdout.close() returncode = proc.wait() - stderr = proc.stderr.read().decode('utf-8') + stderr = proc.stderr.read().decode("utf-8") - expected_msg = 'ERROR: Pipe to stdout was broken' + expected_msg = "ERROR: Pipe to stdout was broken" if deprecated_python: assert expected_msg in stderr else: @@ -33,12 +35,13 @@ def test_broken_stdout_pipe(deprecated_python): Test a broken pipe to stdout. """ stderr, returncode = setup_broken_stdout_test( - ['pip', 'list'], deprecated_python=deprecated_python, + ["pip", "list"], + deprecated_python=deprecated_python, ) # Check that no traceback occurs. - assert 'raise BrokenStdoutLoggingError()' not in stderr - assert stderr.count('Traceback') == 0 + assert "raise BrokenStdoutLoggingError()" not in stderr + assert stderr.count("Traceback") == 0 assert returncode == _BROKEN_STDOUT_RETURN_CODE @@ -47,15 +50,15 @@ def test_broken_stdout_pipe__log_option(deprecated_python, tmpdir): """ Test a broken pipe to stdout when --log is passed. """ - log_path = os.path.join(str(tmpdir), 'log.txt') + log_path = os.path.join(str(tmpdir), "log.txt") stderr, returncode = setup_broken_stdout_test( - ['pip', '--log', log_path, 'list'], + ["pip", "--log", log_path, "list"], deprecated_python=deprecated_python, ) # Check that no traceback occurs. - assert 'raise BrokenStdoutLoggingError()' not in stderr - assert stderr.count('Traceback') == 0 + assert "raise BrokenStdoutLoggingError()" not in stderr + assert stderr.count("Traceback") == 0 assert returncode == _BROKEN_STDOUT_RETURN_CODE @@ -65,12 +68,13 @@ def test_broken_stdout_pipe__verbose(deprecated_python): Test a broken pipe to stdout with verbose logging enabled. """ stderr, returncode = setup_broken_stdout_test( - ['pip', '-v', 'list'], deprecated_python=deprecated_python, + ["pip", "-v", "list"], + deprecated_python=deprecated_python, ) # Check that a traceback occurs and that it occurs at most once. # We permit up to two because the exception can be chained. - assert 'raise BrokenStdoutLoggingError()' in stderr - assert 1 <= stderr.count('Traceback') <= 2 + assert "raise BrokenStdoutLoggingError()" in stderr + assert 1 <= stderr.count("Traceback") <= 2 assert returncode == _BROKEN_STDOUT_RETURN_CODE diff --git a/tests/functional/test_cache.py b/tests/functional/test_cache.py index 603e11b5b0e..3d158998708 100644 --- a/tests/functional/test_cache.py +++ b/tests/functional/test_cache.py @@ -8,26 +8,26 @@ @pytest.fixture def cache_dir(script): result = script.run( - 'python', '-c', - 'from pip._internal.locations import USER_CACHE_DIR;' - 'print(USER_CACHE_DIR)' + "python", + "-c", + "from pip._internal.locations import USER_CACHE_DIR;" "print(USER_CACHE_DIR)", ) return result.stdout.strip() @pytest.fixture def wheel_cache_dir(cache_dir): - return os.path.normcase(os.path.join(cache_dir, 'wheels')) + return os.path.normcase(os.path.join(cache_dir, "wheels")) @pytest.fixture def wheel_cache_files(wheel_cache_dir): - destination = os.path.join(wheel_cache_dir, 'arbitrary', 'pathname') + destination = os.path.join(wheel_cache_dir, "arbitrary", "pathname") if not os.path.exists(destination): return [] - filenames = glob(os.path.join(destination, '*.whl')) + filenames = glob(os.path.join(destination, "*.whl")) files = [] for filename in filenames: files.append(os.path.join(destination, filename)) @@ -36,18 +36,18 @@ def wheel_cache_files(wheel_cache_dir): @pytest.fixture def populate_wheel_cache(wheel_cache_dir): - destination = os.path.join(wheel_cache_dir, 'arbitrary', 'pathname') + destination = os.path.join(wheel_cache_dir, "arbitrary", "pathname") os.makedirs(destination) files = [ - ('yyy-1.2.3', os.path.join(destination, 'yyy-1.2.3-py3-none-any.whl')), - ('zzz-4.5.6', os.path.join(destination, 'zzz-4.5.6-py3-none-any.whl')), - ('zzz-4.5.7', os.path.join(destination, 'zzz-4.5.7-py3-none-any.whl')), - ('zzz-7.8.9', os.path.join(destination, 'zzz-7.8.9-py3-none-any.whl')), + ("yyy-1.2.3", os.path.join(destination, "yyy-1.2.3-py3-none-any.whl")), + ("zzz-4.5.6", os.path.join(destination, "zzz-4.5.6-py3-none-any.whl")), + ("zzz-4.5.7", os.path.join(destination, "zzz-4.5.7-py3-none-any.whl")), + ("zzz-7.8.9", os.path.join(destination, "zzz-7.8.9-py3-none-any.whl")), ] for _name, filename in files: - with open(filename, 'w'): + with open(filename, "w"): pass return files @@ -66,7 +66,7 @@ def list_matches_wheel(wheel_name, result): E.g., If wheel_name is `foo-1.2.3` it searches for a line starting with `- foo-1.2.3-py3-none-any.whl `.""" lines = result.stdout.splitlines() - expected = ' - {}-py3-none-any.whl '.format(wheel_name) + expected = " - {}-py3-none-any.whl ".format(wheel_name) return any(map(lambda l: l.startswith(expected), lines)) @@ -78,9 +78,13 @@ def list_matches_wheel_abspath(wheel_name, result): E.g., If wheel_name is `foo-1.2.3` it searches for a line starting with `foo-1.2.3-py3-none-any.whl`.""" lines = result.stdout.splitlines() - expected = '{}-py3-none-any.whl'.format(wheel_name) - return any(map(lambda l: os.path.basename(l).startswith(expected) - and os.path.exists(l), lines)) + expected = "{}-py3-none-any.whl".format(wheel_name) + return any( + map( + lambda l: os.path.basename(l).startswith(expected) and os.path.exists(l), + lines, + ) + ) @pytest.fixture @@ -95,73 +99,76 @@ def remove_matches_wheel(wheel_cache_dir): def _remove_matches_wheel(wheel_name, result): lines = result.stdout.splitlines() - wheel_filename = '{}-py3-none-any.whl'.format(wheel_name) + wheel_filename = "{}-py3-none-any.whl".format(wheel_name) # The "/arbitrary/pathname/" bit is an implementation detail of how # the `populate_wheel_cache` fixture is implemented. path = os.path.join( - wheel_cache_dir, 'arbitrary', 'pathname', wheel_filename, + wheel_cache_dir, + "arbitrary", + "pathname", + wheel_filename, ) - expected = 'Removed {}'.format(path) + expected = "Removed {}".format(path) return expected in lines return _remove_matches_wheel def test_cache_dir(script, cache_dir): - result = script.pip('cache', 'dir') + result = script.pip("cache", "dir") assert os.path.normcase(cache_dir) == result.stdout.strip() def test_cache_dir_too_many_args(script, cache_dir): - result = script.pip('cache', 'dir', 'aaa', expect_error=True) + result = script.pip("cache", "dir", "aaa", expect_error=True) - assert result.stdout == '' + assert result.stdout == "" # This would be `result.stderr == ...`, but pip prints deprecation # warnings on Python 2.7, so we check if the _line_ is in stderr. - assert 'ERROR: Too many arguments' in result.stderr.splitlines() + assert "ERROR: Too many arguments" in result.stderr.splitlines() @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_info(script, wheel_cache_dir, wheel_cache_files): - result = script.pip('cache', 'info') + result = script.pip("cache", "info") - assert 'Location: {}'.format(wheel_cache_dir) in result.stdout + assert "Location: {}".format(wheel_cache_dir) in result.stdout num_wheels = len(wheel_cache_files) - assert 'Number of wheels: {}'.format(num_wheels) in result.stdout + assert "Number of wheels: {}".format(num_wheels) in result.stdout @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_list(script): """Running `pip cache list` should return exactly what the populate_wheel_cache fixture adds.""" - result = script.pip('cache', 'list') + result = script.pip("cache", "list") - assert list_matches_wheel('yyy-1.2.3', result) - assert list_matches_wheel('zzz-4.5.6', result) - assert list_matches_wheel('zzz-4.5.7', result) - assert list_matches_wheel('zzz-7.8.9', result) + assert list_matches_wheel("yyy-1.2.3", result) + assert list_matches_wheel("zzz-4.5.6", result) + assert list_matches_wheel("zzz-4.5.7", result) + assert list_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_list_abspath(script): """Running `pip cache list --format=abspath` should return full paths of exactly what the populate_wheel_cache fixture adds.""" - result = script.pip('cache', 'list', '--format=abspath') + result = script.pip("cache", "list", "--format=abspath") - assert list_matches_wheel_abspath('yyy-1.2.3', result) - assert list_matches_wheel_abspath('zzz-4.5.6', result) - assert list_matches_wheel_abspath('zzz-4.5.7', result) - assert list_matches_wheel_abspath('zzz-7.8.9', result) + assert list_matches_wheel_abspath("yyy-1.2.3", result) + assert list_matches_wheel_abspath("zzz-4.5.6", result) + assert list_matches_wheel_abspath("zzz-4.5.7", result) + assert list_matches_wheel_abspath("zzz-7.8.9", result) @pytest.mark.usefixtures("empty_wheel_cache") def test_cache_list_with_empty_cache(script): """Running `pip cache list` with an empty cache should print "Nothing cached." and exit.""" - result = script.pip('cache', 'list') + result = script.pip("cache", "list") assert result.stdout == "Nothing cached.\n" @@ -169,124 +176,119 @@ def test_cache_list_with_empty_cache(script): def test_cache_list_with_empty_cache_abspath(script): """Running `pip cache list --format=abspath` with an empty cache should not print anything and exit.""" - result = script.pip('cache', 'list', '--format=abspath') + result = script.pip("cache", "list", "--format=abspath") assert result.stdout.strip() == "" def test_cache_list_too_many_args(script): """Passing `pip cache list` too many arguments should cause an error.""" - script.pip('cache', 'list', 'aaa', 'bbb', - expect_error=True) + script.pip("cache", "list", "aaa", "bbb", expect_error=True) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_list_name_match(script): """Running `pip cache list zzz` should list zzz-4.5.6, zzz-4.5.7, zzz-7.8.9, but nothing else.""" - result = script.pip('cache', 'list', 'zzz', '--verbose') + result = script.pip("cache", "list", "zzz", "--verbose") - assert not list_matches_wheel('yyy-1.2.3', result) - assert list_matches_wheel('zzz-4.5.6', result) - assert list_matches_wheel('zzz-4.5.7', result) - assert list_matches_wheel('zzz-7.8.9', result) + assert not list_matches_wheel("yyy-1.2.3", result) + assert list_matches_wheel("zzz-4.5.6", result) + assert list_matches_wheel("zzz-4.5.7", result) + assert list_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_list_name_match_abspath(script): """Running `pip cache list zzz --format=abspath` should list paths of zzz-4.5.6, zzz-4.5.7, zzz-7.8.9, but nothing else.""" - result = script.pip('cache', 'list', 'zzz', '--format=abspath', - '--verbose') + result = script.pip("cache", "list", "zzz", "--format=abspath", "--verbose") - assert not list_matches_wheel_abspath('yyy-1.2.3', result) - assert list_matches_wheel_abspath('zzz-4.5.6', result) - assert list_matches_wheel_abspath('zzz-4.5.7', result) - assert list_matches_wheel_abspath('zzz-7.8.9', result) + assert not list_matches_wheel_abspath("yyy-1.2.3", result) + assert list_matches_wheel_abspath("zzz-4.5.6", result) + assert list_matches_wheel_abspath("zzz-4.5.7", result) + assert list_matches_wheel_abspath("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_list_name_and_version_match(script): """Running `pip cache list zzz-4.5.6` should list zzz-4.5.6, but nothing else.""" - result = script.pip('cache', 'list', 'zzz-4.5.6', '--verbose') + result = script.pip("cache", "list", "zzz-4.5.6", "--verbose") - assert not list_matches_wheel('yyy-1.2.3', result) - assert list_matches_wheel('zzz-4.5.6', result) - assert not list_matches_wheel('zzz-4.5.7', result) - assert not list_matches_wheel('zzz-7.8.9', result) + assert not list_matches_wheel("yyy-1.2.3", result) + assert list_matches_wheel("zzz-4.5.6", result) + assert not list_matches_wheel("zzz-4.5.7", result) + assert not list_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_list_name_and_version_match_abspath(script): """Running `pip cache list zzz-4.5.6 --format=abspath` should list path of zzz-4.5.6, but nothing else.""" - result = script.pip('cache', 'list', 'zzz-4.5.6', '--format=abspath', - '--verbose') + result = script.pip("cache", "list", "zzz-4.5.6", "--format=abspath", "--verbose") - assert not list_matches_wheel_abspath('yyy-1.2.3', result) - assert list_matches_wheel_abspath('zzz-4.5.6', result) - assert not list_matches_wheel_abspath('zzz-4.5.7', result) - assert not list_matches_wheel_abspath('zzz-7.8.9', result) + assert not list_matches_wheel_abspath("yyy-1.2.3", result) + assert list_matches_wheel_abspath("zzz-4.5.6", result) + assert not list_matches_wheel_abspath("zzz-4.5.7", result) + assert not list_matches_wheel_abspath("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_remove_no_arguments(script): """Running `pip cache remove` with no arguments should cause an error.""" - script.pip('cache', 'remove', expect_error=True) + script.pip("cache", "remove", expect_error=True) def test_cache_remove_too_many_args(script): """Passing `pip cache remove` too many arguments should cause an error.""" - script.pip('cache', 'remove', 'aaa', 'bbb', - expect_error=True) + script.pip("cache", "remove", "aaa", "bbb", expect_error=True) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_remove_name_match(script, remove_matches_wheel): """Running `pip cache remove zzz` should remove zzz-4.5.6 and zzz-7.8.9, but nothing else.""" - result = script.pip('cache', 'remove', 'zzz', '--verbose') + result = script.pip("cache", "remove", "zzz", "--verbose") - assert not remove_matches_wheel('yyy-1.2.3', result) - assert remove_matches_wheel('zzz-4.5.6', result) - assert remove_matches_wheel('zzz-4.5.7', result) - assert remove_matches_wheel('zzz-7.8.9', result) + assert not remove_matches_wheel("yyy-1.2.3", result) + assert remove_matches_wheel("zzz-4.5.6", result) + assert remove_matches_wheel("zzz-4.5.7", result) + assert remove_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_remove_name_and_version_match(script, remove_matches_wheel): """Running `pip cache remove zzz-4.5.6` should remove zzz-4.5.6, but nothing else.""" - result = script.pip('cache', 'remove', 'zzz-4.5.6', '--verbose') + result = script.pip("cache", "remove", "zzz-4.5.6", "--verbose") - assert not remove_matches_wheel('yyy-1.2.3', result) - assert remove_matches_wheel('zzz-4.5.6', result) - assert not remove_matches_wheel('zzz-4.5.7', result) - assert not remove_matches_wheel('zzz-7.8.9', result) + assert not remove_matches_wheel("yyy-1.2.3", result) + assert remove_matches_wheel("zzz-4.5.6", result) + assert not remove_matches_wheel("zzz-4.5.7", result) + assert not remove_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_purge(script, remove_matches_wheel): """Running `pip cache purge` should remove all cached wheels.""" - result = script.pip('cache', 'purge', '--verbose') + result = script.pip("cache", "purge", "--verbose") - assert remove_matches_wheel('yyy-1.2.3', result) - assert remove_matches_wheel('zzz-4.5.6', result) - assert remove_matches_wheel('zzz-4.5.7', result) - assert remove_matches_wheel('zzz-7.8.9', result) + assert remove_matches_wheel("yyy-1.2.3", result) + assert remove_matches_wheel("zzz-4.5.6", result) + assert remove_matches_wheel("zzz-4.5.7", result) + assert remove_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") def test_cache_purge_too_many_args(script, wheel_cache_files): """Running `pip cache purge aaa` should raise an error and remove no cached wheels.""" - result = script.pip('cache', 'purge', 'aaa', '--verbose', - expect_error=True) - assert result.stdout == '' + result = script.pip("cache", "purge", "aaa", "--verbose", expect_error=True) + assert result.stdout == "" # This would be `result.stderr == ...`, but pip prints deprecation # warnings on Python 2.7, so we check if the _line_ is in stderr. - assert 'ERROR: Too many arguments' in result.stderr.splitlines() + assert "ERROR: Too many arguments" in result.stderr.splitlines() # Make sure nothing was deleted. for filename in wheel_cache_files: @@ -297,9 +299,10 @@ def test_cache_purge_too_many_args(script, wheel_cache_files): def test_cache_abort_when_no_cache_dir(script, command): """Running any pip cache command when cache is disabled should abort and log an informative error""" - result = script.pip('cache', command, '--no-cache-dir', - expect_error=True) - assert result.stdout == '' + result = script.pip("cache", command, "--no-cache-dir", expect_error=True) + assert result.stdout == "" - assert ('ERROR: pip cache commands can not function' - ' since cache is disabled.' in result.stderr.splitlines()) + assert ( + "ERROR: pip cache commands can not function" + " since cache is disabled." in result.stderr.splitlines() + ) diff --git a/tests/functional/test_check.py b/tests/functional/test_check.py index 5cb41a97e72..d039e52676a 100644 --- a/tests/functional/test_check.py +++ b/tests/functional/test_check.py @@ -5,20 +5,16 @@ def matches_expected_lines(string, expected_lines): # Ignore empty lines output_lines = list(filter(None, string.splitlines())) # We'll match the last n lines, given n lines to match. - last_few_output_lines = output_lines[-len(expected_lines):] + last_few_output_lines = output_lines[-len(expected_lines) :] # And order does not matter return set(last_few_output_lines) == set(expected_lines) def test_basic_check_clean(script): - """On a clean environment, check should print a helpful message. + """On a clean environment, check should print a helpful message.""" + result = script.pip("check") - """ - result = script.pip('check') - - expected_lines = ( - "No broken requirements found.", - ) + expected_lines = ("No broken requirements found.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 0 @@ -27,17 +23,17 @@ def test_basic_check_missing_dependency(script): # Setup a small project pkga_path = create_test_package_with_setup( script, - name='pkga', version='1.0', install_requires=['missing==0.1'], + name="pkga", + version="1.0", + install_requires=["missing==0.1"], ) # Let's install pkga without its dependency - res = script.pip('install', '--no-index', pkga_path, '--no-deps') + res = script.pip("install", "--no-index", pkga_path, "--no-deps") assert "Successfully installed pkga-1.0" in res.stdout, str(res) - result = script.pip('check', expect_error=True) + result = script.pip("check", expect_error=True) - expected_lines = ( - "pkga 1.0 requires missing, which is not installed.", - ) + expected_lines = ("pkga 1.0 requires missing, which is not installed.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 1 @@ -46,28 +42,32 @@ def test_basic_check_broken_dependency(script): # Setup pkga depending on pkgb>=1.0 pkga_path = create_test_package_with_setup( script, - name='pkga', version='1.0', install_requires=['broken>=1.0'], + name="pkga", + version="1.0", + install_requires=["broken>=1.0"], ) # Let's install pkga without its dependency - res = script.pip('install', '--no-index', pkga_path, '--no-deps') + res = script.pip("install", "--no-index", pkga_path, "--no-deps") assert "Successfully installed pkga-1.0" in res.stdout, str(res) # Setup broken==0.1 broken_path = create_test_package_with_setup( script, - name='broken', version='0.1', + name="broken", + version="0.1", ) # Let's install broken==0.1 res = script.pip( - 'install', '--no-index', broken_path, '--no-warn-conflicts', + "install", + "--no-index", + broken_path, + "--no-warn-conflicts", ) assert "Successfully installed broken-0.1" in res.stdout, str(res) - result = script.pip('check', expect_error=True) + result = script.pip("check", expect_error=True) - expected_lines = ( - "pkga 1.0 has requirement broken>=1.0, but you have broken 0.1.", - ) + expected_lines = ("pkga 1.0 has requirement broken>=1.0, but you have broken 0.1.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 1 @@ -75,26 +75,30 @@ def test_basic_check_broken_dependency(script): def test_basic_check_broken_dependency_and_missing_dependency(script): pkga_path = create_test_package_with_setup( script, - name='pkga', version='1.0', install_requires=['broken>=1.0'], + name="pkga", + version="1.0", + install_requires=["broken>=1.0"], ) # Let's install pkga without its dependency - res = script.pip('install', '--no-index', pkga_path, '--no-deps') + res = script.pip("install", "--no-index", pkga_path, "--no-deps") assert "Successfully installed pkga-1.0" in res.stdout, str(res) # Setup broken==0.1 broken_path = create_test_package_with_setup( script, - name='broken', version='0.1', install_requires=['missing'], + name="broken", + version="0.1", + install_requires=["missing"], ) # Let's install broken==0.1 - res = script.pip('install', '--no-index', broken_path, '--no-deps') + res = script.pip("install", "--no-index", broken_path, "--no-deps") assert "Successfully installed broken-0.1" in res.stdout, str(res) - result = script.pip('check', expect_error=True) + result = script.pip("check", expect_error=True) expected_lines = ( "broken 0.1 requires missing, which is not installed.", - "pkga 1.0 has requirement broken>=1.0, but you have broken 0.1." + "pkga 1.0 has requirement broken>=1.0, but you have broken 0.1.", ) assert matches_expected_lines(result.stdout, expected_lines) @@ -104,18 +108,17 @@ def test_basic_check_broken_dependency_and_missing_dependency(script): def test_check_complicated_name_missing(script): package_a_path = create_test_package_with_setup( script, - name='package_A', version='1.0', - install_requires=['Dependency-B>=1.0'], + name="package_A", + version="1.0", + install_requires=["Dependency-B>=1.0"], ) # Without dependency - result = script.pip('install', '--no-index', package_a_path, '--no-deps') + result = script.pip("install", "--no-index", package_a_path, "--no-deps") assert "Successfully installed package-A-1.0" in result.stdout, str(result) - result = script.pip('check', expect_error=True) - expected_lines = ( - "package-a 1.0 requires dependency-b, which is not installed.", - ) + result = script.pip("check", expect_error=True) + expected_lines = ("package-a 1.0 requires dependency-b, which is not installed.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 1 @@ -123,24 +126,29 @@ def test_check_complicated_name_missing(script): def test_check_complicated_name_broken(script): package_a_path = create_test_package_with_setup( script, - name='package_A', version='1.0', - install_requires=['Dependency-B>=1.0'], + name="package_A", + version="1.0", + install_requires=["Dependency-B>=1.0"], ) dependency_b_path_incompatible = create_test_package_with_setup( script, - name='dependency-b', version='0.1', + name="dependency-b", + version="0.1", ) # With broken dependency - result = script.pip('install', '--no-index', package_a_path, '--no-deps') + result = script.pip("install", "--no-index", package_a_path, "--no-deps") assert "Successfully installed package-A-1.0" in result.stdout, str(result) result = script.pip( - 'install', '--no-index', dependency_b_path_incompatible, '--no-deps', + "install", + "--no-index", + dependency_b_path_incompatible, + "--no-deps", ) assert "Successfully installed dependency-b-0.1" in result.stdout - result = script.pip('check', expect_error=True) + result = script.pip("check", expect_error=True) expected_lines = ( "package-a 1.0 has requirement Dependency-B>=1.0, but you have " "dependency-b 0.1.", @@ -152,26 +160,29 @@ def test_check_complicated_name_broken(script): def test_check_complicated_name_clean(script): package_a_path = create_test_package_with_setup( script, - name='package_A', version='1.0', - install_requires=['Dependency-B>=1.0'], + name="package_A", + version="1.0", + install_requires=["Dependency-B>=1.0"], ) dependency_b_path = create_test_package_with_setup( script, - name='dependency-b', version='1.0', + name="dependency-b", + version="1.0", ) - result = script.pip('install', '--no-index', package_a_path, '--no-deps') + result = script.pip("install", "--no-index", package_a_path, "--no-deps") assert "Successfully installed package-A-1.0" in result.stdout, str(result) result = script.pip( - 'install', '--no-index', dependency_b_path, '--no-deps', + "install", + "--no-index", + dependency_b_path, + "--no-deps", ) assert "Successfully installed dependency-b-1.0" in result.stdout - result = script.pip('check') - expected_lines = ( - "No broken requirements found.", - ) + result = script.pip("check") + expected_lines = ("No broken requirements found.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 0 @@ -179,20 +190,19 @@ def test_check_complicated_name_clean(script): def test_check_considers_conditional_reqs(script): package_a_path = create_test_package_with_setup( script, - name='package_A', version='1.0', + name="package_A", + version="1.0", install_requires=[ "Dependency-B>=1.0; python_version != '2.7'", "Dependency-B>=2.0; python_version == '2.7'", ], ) - result = script.pip('install', '--no-index', package_a_path, '--no-deps') + result = script.pip("install", "--no-index", package_a_path, "--no-deps") assert "Successfully installed package-A-1.0" in result.stdout, str(result) - result = script.pip('check', expect_error=True) - expected_lines = ( - "package-a 1.0 requires dependency-b, which is not installed.", - ) + result = script.pip("check", expect_error=True) + expected_lines = ("package-a 1.0 requires dependency-b, which is not installed.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 1 @@ -201,45 +211,50 @@ def test_check_development_versions_are_also_considered(script): # Setup pkga depending on pkgb>=1.0 pkga_path = create_test_package_with_setup( script, - name='pkga', version='1.0', install_requires=['depend>=1.0'], + name="pkga", + version="1.0", + install_requires=["depend>=1.0"], ) # Let's install pkga without its dependency - res = script.pip('install', '--no-index', pkga_path, '--no-deps') + res = script.pip("install", "--no-index", pkga_path, "--no-deps") assert "Successfully installed pkga-1.0" in res.stdout, str(res) # Setup depend==1.1.0.dev0 depend_path = create_test_package_with_setup( script, - name='depend', version='1.1.0.dev0', + name="depend", + version="1.1.0.dev0", ) # Let's install depend==1.1.0.dev0 res = script.pip( - 'install', '--no-index', depend_path, '--no-warn-conflicts', + "install", + "--no-index", + depend_path, + "--no-warn-conflicts", ) assert "Successfully installed depend-1.1.0.dev0" in res.stdout, str(res) - result = script.pip('check') - expected_lines = ( - "No broken requirements found.", - ) + result = script.pip("check") + expected_lines = ("No broken requirements found.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 0 def test_basic_check_broken_metadata(script): # Create some corrupt metadata - dist_info_dir = script.site_packages_path / 'pkga-1.0.dist-info' + dist_info_dir = script.site_packages_path / "pkga-1.0.dist-info" dist_info_dir.mkdir() - with open(dist_info_dir / 'METADATA', 'w') as f: - f.write('Metadata-Version: 2.1\n' - 'Name: pkga\n' - 'Version: 1.0\n' - 'Requires-Dist: pip; python_version == "3.4";extra == "test"\n' - ) + with open(dist_info_dir / "METADATA", "w") as f: + f.write( + "Metadata-Version: 2.1\n" + "Name: pkga\n" + "Version: 1.0\n" + 'Requires-Dist: pip; python_version == "3.4";extra == "test"\n' + ) - result = script.pip('check', expect_error=True) + result = script.pip("check", expect_error=True) - assert 'Error parsing requirements' in result.stderr + assert "Error parsing requirements" in result.stderr assert result.returncode == 1 @@ -252,18 +267,15 @@ def test_check_skip_work_dir_pkg(script): # Create a test package with dependency missing # and create .egg-info dir pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0', - install_requires=['missing==0.1']) + script, name="simple", version="1.0", install_requires=["missing==0.1"] + ) - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) # Check should not complain about broken requirements # when run from package directory - result = script.pip('check', cwd=pkg_path) - expected_lines = ( - "No broken requirements found.", - ) + result = script.pip("check", cwd=pkg_path) + expected_lines = ("No broken requirements found.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 0 @@ -277,20 +289,17 @@ def test_check_include_work_dir_pkg(script): # Create a test package with dependency missing # and create .egg-info dir pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0', - install_requires=['missing==0.1']) + script, name="simple", version="1.0", install_requires=["missing==0.1"] + ) - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) - script.environ.update({'PYTHONPATH': pkg_path}) + script.environ.update({"PYTHONPATH": pkg_path}) # Check should mention about missing requirement simple # when run from package directory, when package directory # is in PYTHONPATH - result = script.pip('check', expect_error=True, cwd=pkg_path) - expected_lines = ( - "simple 1.0 requires missing, which is not installed.", - ) + result = script.pip("check", expect_error=True, cwd=pkg_path) + expected_lines = ("simple 1.0 requires missing, which is not installed.",) assert matches_expected_lines(result.stdout, expected_lines) assert result.returncode == 1 diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py index e416315125f..1df4836f9b8 100644 --- a/tests/functional/test_cli.py +++ b/tests/functional/test_cli.py @@ -5,15 +5,20 @@ import pytest -@pytest.mark.parametrize("entrypoint", [ - ("fake_pip = pip._internal.main:main",), - ("fake_pip = pip._internal:main",), - ("fake_pip = pip:main",), -]) +@pytest.mark.parametrize( + "entrypoint", + [ + ("fake_pip = pip._internal.main:main",), + ("fake_pip = pip._internal:main",), + ("fake_pip = pip:main",), + ], +) def test_entrypoints_work(entrypoint, script): fake_pkg = script.temp_path / "fake_pkg" fake_pkg.mkdir() - fake_pkg.joinpath("setup.py").write_text(dedent(""" + fake_pkg.joinpath("setup.py").write_text( + dedent( + """ from setuptools import setup setup( @@ -25,7 +30,11 @@ def test_entrypoints_work(entrypoint, script): ] }} ) - """.format(entrypoint))) + """.format( + entrypoint + ) + ) + ) script.pip("install", "-vvv", str(fake_pkg)) result = script.pip("-V") diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py index a3986811b6f..906ab5c7d30 100644 --- a/tests/functional/test_completion.py +++ b/tests/functional/test_completion.py @@ -6,15 +6,20 @@ from tests.lib.path import Path COMPLETION_FOR_SUPPORTED_SHELLS_TESTS = ( - ('bash', """\ + ( + "bash", + """\ _pip_completion() { COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ COMP_CWORD=$COMP_CWORD \\ PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) ) } -complete -o default -F _pip_completion pip"""), - ('fish', """\ +complete -o default -F _pip_completion pip""", + ), + ( + "fish", + """\ function __fish_complete_pip set -lx COMP_WORDS (commandline -o) "" set -lx COMP_CWORD ( \\ @@ -23,8 +28,11 @@ set -lx PIP_AUTO_COMPLETE 1 string split \\ -- (eval $COMP_WORDS[1]) end -complete -fa "(__fish_complete_pip)" -c pip"""), - ('zsh', """\ +complete -fa "(__fish_complete_pip)" -c pip""", + ), + ( + "zsh", + """\ function _pip_completion { local words cword read -Ac words @@ -33,35 +41,30 @@ COMP_CWORD=$(( cword-1 )) \\ PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )) } -compctl -K _pip_completion pip"""), +compctl -K _pip_completion pip""", + ), ) @pytest.fixture(scope="session") -def script_with_launchers( - tmpdir_factory, script_factory, common_wheels, pip_src -): +def script_with_launchers(tmpdir_factory, script_factory, common_wheels, pip_src): tmpdir = Path(str(tmpdir_factory.mktemp("script_with_launchers"))) script = script_factory(tmpdir.joinpath("workspace")) # Re-install pip so we get the launchers. - script.pip_install_local('-f', common_wheels, pip_src) + script.pip_install_local("-f", common_wheels, pip_src) return script @pytest.mark.parametrize( - 'shell, completion', + "shell, completion", COMPLETION_FOR_SUPPORTED_SHELLS_TESTS, ids=[t[0] for t in COMPLETION_FOR_SUPPORTED_SHELLS_TESTS], ) -def test_completion_for_supported_shells( - script_with_launchers, shell, completion -): +def test_completion_for_supported_shells(script_with_launchers, shell, completion): """ Test getting completion for bash shell """ - result = script_with_launchers.pip( - 'completion', '--' + shell, use_module=False - ) + result = script_with_launchers.pip("completion", "--" + shell, use_module=False) assert completion in result.stdout, str(result.stdout) @@ -73,16 +76,17 @@ def autocomplete_script(tmpdir_factory, script_factory): @pytest.fixture def autocomplete(autocomplete_script, monkeypatch): - monkeypatch.setattr(autocomplete_script, 'environ', os.environ.copy()) - autocomplete_script.environ['PIP_AUTO_COMPLETE'] = '1' + monkeypatch.setattr(autocomplete_script, "environ", os.environ.copy()) + autocomplete_script.environ["PIP_AUTO_COMPLETE"] = "1" def do_autocomplete(words, cword, cwd=None): - autocomplete_script.environ['COMP_WORDS'] = words - autocomplete_script.environ['COMP_CWORD'] = cword + autocomplete_script.environ["COMP_WORDS"] = words + autocomplete_script.environ["COMP_CWORD"] = cword result = autocomplete_script.run( - 'python', '-c', - 'from pip._internal.cli.autocompletion import autocomplete;' - 'autocomplete()', + "python", + "-c", + "from pip._internal.cli.autocompletion import autocomplete;" + "autocomplete()", expect_error=True, cwd=cwd, ) @@ -96,20 +100,19 @@ def test_completion_for_unknown_shell(autocomplete_script): """ Test getting completion for an unknown shell """ - error_msg = 'no such option: --myfooshell' - result = autocomplete_script.pip( - 'completion', '--myfooshell', expect_error=True - ) - assert error_msg in result.stderr, 'tests for an unknown shell failed' + error_msg = "no such option: --myfooshell" + result = autocomplete_script.pip("completion", "--myfooshell", expect_error=True) + assert error_msg in result.stderr, "tests for an unknown shell failed" def test_completion_alone(autocomplete_script): """ Test getting completion for none shell, just pip completion """ - result = autocomplete_script.pip('completion', allow_stderr_error=True) - assert 'ERROR: You must pass --bash or --fish or --zsh' in result.stderr, \ - 'completion alone failed -- ' + result.stderr + result = autocomplete_script.pip("completion", allow_stderr_error=True) + assert "ERROR: You must pass --bash or --fish or --zsh" in result.stderr, ( + "completion alone failed -- " + result.stderr + ) def test_completion_for_un_snippet(autocomplete): @@ -117,8 +120,8 @@ def test_completion_for_un_snippet(autocomplete): Test getting completion for ``un`` should return uninstall """ - res, env = autocomplete('pip un', '1') - assert res.stdout.strip().split() == ['uninstall'], res.stdout + res, env = autocomplete("pip un", "1") + assert res.stdout.strip().split() == ["uninstall"], res.stdout def test_completion_for_default_parameters(autocomplete): @@ -126,9 +129,8 @@ def test_completion_for_default_parameters(autocomplete): Test getting completion for ``--`` should contain --help """ - res, env = autocomplete('pip --', '1') - assert '--help' in res.stdout,\ - "autocomplete function could not complete ``--``" + res, env = autocomplete("pip --", "1") + assert "--help" in res.stdout, "autocomplete function could not complete ``--``" def test_completion_option_for_command(autocomplete): @@ -136,9 +138,8 @@ def test_completion_option_for_command(autocomplete): Test getting completion for ``--`` in command (e.g. ``pip search --``) """ - res, env = autocomplete('pip search --', '2') - assert '--help' in res.stdout,\ - "autocomplete function could not complete ``--``" + res, env = autocomplete("pip search --", "2") + assert "--help" in res.stdout, "autocomplete function could not complete ``--``" def test_completion_short_option(autocomplete): @@ -146,10 +147,11 @@ def test_completion_short_option(autocomplete): Test getting completion for short options after ``-`` (eg. pip -) """ - res, env = autocomplete('pip -', '1') + res, env = autocomplete("pip -", "1") - assert '-h' in res.stdout.split(),\ - "autocomplete function could not complete short options after ``-``" + assert ( + "-h" in res.stdout.split() + ), "autocomplete function could not complete short options after ``-``" def test_completion_short_option_for_command(autocomplete): @@ -158,10 +160,11 @@ def test_completion_short_option_for_command(autocomplete): (eg. pip search -) """ - res, env = autocomplete('pip search -', '2') + res, env = autocomplete("pip search -", "2") - assert '-h' in res.stdout.split(),\ - "autocomplete function could not complete short options after ``-``" + assert ( + "-h" in res.stdout.split() + ), "autocomplete function could not complete short options after ``-``" def test_completion_files_after_option(autocomplete, data): @@ -170,32 +173,29 @@ def test_completion_files_after_option(autocomplete, data): (e.g. ``pip install -r``) """ res, env = autocomplete( - words=('pip install -r r'), - cword='3', + words=("pip install -r r"), + cword="3", cwd=data.completion_paths, ) - assert 'requirements.txt' in res.stdout, ( - "autocomplete function could not complete " - "after options in command" + assert "requirements.txt" in res.stdout, ( + "autocomplete function could not complete " "after options in command" ) - assert os.path.join('resources', '') in res.stdout, ( - "autocomplete function could not complete " - "after options in command" + assert os.path.join("resources", "") in res.stdout, ( + "autocomplete function could not complete " "after options in command" ) - assert not any(out in res.stdout for out in - (os.path.join('REPLAY', ''), 'README.txt')), ( + assert not any( + out in res.stdout for out in (os.path.join("REPLAY", ""), "README.txt") + ), ( "autocomplete function completed or that " "should not be completed" ) - if sys.platform != 'win32': + if sys.platform != "win32": return - assert 'readme.txt' in res.stdout, ( - "autocomplete function could not complete " - "after options in command" + assert "readme.txt" in res.stdout, ( + "autocomplete function could not complete " "after options in command" ) - assert os.path.join('replay', '') in res.stdout, ( - "autocomplete function could not complete " - "after options in command" + assert os.path.join("replay", "") in res.stdout, ( + "autocomplete function could not complete " "after options in command" ) @@ -205,45 +205,35 @@ def test_completion_not_files_after_option(autocomplete, data): (e.g. ``pip install``) """ res, env = autocomplete( - words=('pip install r'), - cword='2', + words=("pip install r"), + cword="2", cwd=data.completion_paths, ) - assert not any(out in res.stdout for out in - ('requirements.txt', 'readme.txt',)), ( - "autocomplete function completed when " - "it should not complete" - ) - assert not any(os.path.join(out, '') in res.stdout - for out in ('replay', 'resources')), ( - "autocomplete function completed when " - "it should not complete" + assert not any(out in res.stdout for out in ("requirements.txt", "readme.txt",)), ( + "autocomplete function completed when " "it should not complete" ) + assert not any( + os.path.join(out, "") in res.stdout for out in ("replay", "resources") + ), ("autocomplete function completed when " "it should not complete") @pytest.mark.parametrize("cl_opts", ["-U", "--user", "-h"]) -def test_completion_not_files_after_nonexpecting_option( - autocomplete, data, cl_opts -): +def test_completion_not_files_after_nonexpecting_option(autocomplete, data, cl_opts): """ Test not getting completion files after options which not applicable (e.g. ``pip install``) """ res, env = autocomplete( - words=('pip install {cl_opts} r'.format(**locals())), - cword='2', + words=("pip install {cl_opts} r".format(**locals())), + cword="2", cwd=data.completion_paths, ) - assert not any(out in res.stdout for out in - ('requirements.txt', 'readme.txt',)), ( - "autocomplete function completed when " - "it should not complete" - ) - assert not any(os.path.join(out, '') in res.stdout - for out in ('replay', 'resources')), ( - "autocomplete function completed when " - "it should not complete" + assert not any(out in res.stdout for out in ("requirements.txt", "readme.txt",)), ( + "autocomplete function completed when " "it should not complete" ) + assert not any( + os.path.join(out, "") in res.stdout for out in ("replay", "resources") + ), ("autocomplete function completed when " "it should not complete") def test_completion_directories_after_option(autocomplete, data): @@ -252,22 +242,21 @@ def test_completion_directories_after_option(autocomplete, data): (e.g. ``pip --cache-dir``) """ res, env = autocomplete( - words=('pip --cache-dir r'), - cword='2', + words=("pip --cache-dir r"), + cword="2", cwd=data.completion_paths, ) - assert os.path.join('resources', '') in res.stdout, ( - "autocomplete function could not complete after options" - ) - assert not any(out in res.stdout for out in ( - 'requirements.txt', 'README.txt', os.path.join('REPLAY', ''))), ( - "autocomplete function completed when " - "it should not complete" - ) - if sys.platform == 'win32': - assert os.path.join('replay', '') in res.stdout, ( - "autocomplete function could not complete after options" - ) + assert ( + os.path.join("resources", "") in res.stdout + ), "autocomplete function could not complete after options" + assert not any( + out in res.stdout + for out in ("requirements.txt", "README.txt", os.path.join("REPLAY", "")) + ), ("autocomplete function completed when " "it should not complete") + if sys.platform == "win32": + assert ( + os.path.join("replay", "") in res.stdout + ), "autocomplete function could not complete after options" def test_completion_subdirectories_after_option(autocomplete, data): @@ -276,12 +265,11 @@ def test_completion_subdirectories_after_option(autocomplete, data): given path of a directory """ res, env = autocomplete( - words=('pip --cache-dir ' + os.path.join('resources', '')), - cword='2', + words=("pip --cache-dir " + os.path.join("resources", "")), + cword="2", cwd=data.completion_paths, ) - assert os.path.join('resources', - os.path.join('images', '')) in res.stdout, ( + assert os.path.join("resources", os.path.join("images", "")) in res.stdout, ( "autocomplete function could not complete " "given path of a directory after options" ) @@ -293,24 +281,28 @@ def test_completion_path_after_option(autocomplete, data): given absolute path """ res, env = autocomplete( - words=('pip install -e ' + os.path.join(data.completion_paths, 'R')), - cword='3', + words=("pip install -e " + os.path.join(data.completion_paths, "R")), + cword="3", ) - assert all(os.path.normcase(os.path.join(data.completion_paths, out)) - in res.stdout for out in ( - 'README.txt', os.path.join('REPLAY', ''))), ( + assert all( + os.path.normcase(os.path.join(data.completion_paths, out)) in res.stdout + for out in ("README.txt", os.path.join("REPLAY", "")) + ), ( "autocomplete function could not complete " "after options in command given absolute path" ) -@pytest.mark.parametrize('flag', ['--bash', '--zsh', '--fish']) +@pytest.mark.parametrize("flag", ["--bash", "--zsh", "--fish"]) def test_completion_uses_same_executable_name( autocomplete_script, flag, deprecated_python ): - executable_name = 'pip{}'.format(sys.version_info[0]) + executable_name = "pip{}".format(sys.version_info[0]) # Deprecated python versions produce an extra deprecation warning result = autocomplete_script.run( - executable_name, 'completion', flag, expect_stderr=deprecated_python, + executable_name, + "completion", + flag, + expect_stderr=deprecated_python, ) assert executable_name in result.stdout diff --git a/tests/functional/test_configuration.py b/tests/functional/test_configuration.py index 63b243f788e..615f356f6c8 100644 --- a/tests/functional/test_configuration.py +++ b/tests/functional/test_configuration.py @@ -7,20 +7,16 @@ import pytest from pip._internal.cli.status_codes import ERROR -from pip._internal.configuration import ( - CONFIG_BASENAME, - get_configuration_files, -) +from pip._internal.configuration import CONFIG_BASENAME, get_configuration_files from tests.lib.configuration_helpers import ConfigurationMixin, kinds def test_no_options_passed_should_error(script): - result = script.pip('config', expect_error=True) + result = script.pip("config", expect_error=True) assert result.returncode == ERROR class TestBasicLoading(ConfigurationMixin): - @pytest.mark.skip("Can't modify underlying file for any mode") def test_reads_file_appropriately(self, script): contents = """ @@ -50,10 +46,9 @@ def test_listing_is_correct(self, script): result = script.pip("config", "list") - lines = list(filter( - lambda x: x.startswith("test.listing-"), - result.stdout.splitlines() - )) + lines = list( + filter(lambda x: x.startswith("test.listing-"), result.stdout.splitlines()) + ) expected = """ test.listing-alpha='1' @@ -64,8 +59,7 @@ def test_listing_is_correct(self, script): assert lines == textwrap.dedent(expected).strip().splitlines() def test_forget_section(self, script): - result = script.pip("config", "set", "isolated", "true", - expect_error=True) + result = script.pip("config", "set", "isolated", "true", expect_error=True) assert "global.isolated" in result.stderr def test_env_var_values(self, script): @@ -75,7 +69,7 @@ def test_env_var_values(self, script): env_vars = { "PIP_DEFAULT_TIMEOUT": "60", - "PIP_FIND_LINKS": "http://mirror.example.com" + "PIP_FIND_LINKS": "http://mirror.example.com", } script.environ.update(env_vars) @@ -91,14 +85,18 @@ def test_env_values(self, script): """ config_file = script.scratch_path / "test-pip.cfg" - script.environ['PIP_CONFIG_FILE'] = str(config_file) - config_file.write_text(textwrap.dedent("""\ + script.environ["PIP_CONFIG_FILE"] = str(config_file) + config_file.write_text( + textwrap.dedent( + """\ [global] timeout = 60 [freeze] timeout = 10 - """)) + """ + ) + ) result = script.pip("config", "debug") assert "{}, exists: True".format(config_file) in result.stdout @@ -106,7 +104,10 @@ def test_env_values(self, script): assert "freeze.timeout: 10" in result.stdout assert re.search(r"env:\n( .+\n)+", result.stdout) - def test_user_values(self, script,): + def test_user_values( + self, + script, + ): """Test that the user pip configuration set using --user is correctly displayed under "user". This configuration takes place of custom path location using the environment variable PIP_CONFIG_FILE diff --git a/tests/functional/test_debug.py b/tests/functional/test_debug.py index f309604df58..d94554e409a 100644 --- a/tests/functional/test_debug.py +++ b/tests/functional/test_debug.py @@ -4,26 +4,28 @@ from pip._internal.utils import compatibility_tags -@pytest.mark.parametrize('expected_text', [ - 'sys.executable: ', - 'sys.getdefaultencoding: ', - 'sys.getfilesystemencoding: ', - 'locale.getpreferredencoding: ', - 'sys.platform: ', - 'sys.implementation:', - '\'cert\' config value: ', - 'REQUESTS_CA_BUNDLE: ', - 'CURL_CA_BUNDLE: ', - 'pip._vendor.certifi.where(): ', - 'pip._vendor.DEBUNDLED: ', - 'vendored library versions:', - -]) +@pytest.mark.parametrize( + "expected_text", + [ + "sys.executable: ", + "sys.getdefaultencoding: ", + "sys.getfilesystemencoding: ", + "locale.getpreferredencoding: ", + "sys.platform: ", + "sys.implementation:", + "'cert' config value: ", + "REQUESTS_CA_BUNDLE: ", + "CURL_CA_BUNDLE: ", + "pip._vendor.certifi.where(): ", + "pip._vendor.DEBUNDLED: ", + "vendored library versions:", + ], +) def test_debug(script, expected_text): """ Check that certain strings are present in the output. """ - args = ['debug'] + args = ["debug"] result = script.pip(*args, allow_stderr_warning=True) stdout = result.stdout @@ -34,53 +36,53 @@ def test_debug__library_versions(script): """ Check the library versions normal output. """ - args = ['debug'] + args = ["debug"] result = script.pip(*args, allow_stderr_warning=True) print(result.stdout) vendored_versions = create_vendor_txt_map() for name, value in vendored_versions.items(): - assert '{}=={}'.format(name, value) in result.stdout + assert "{}=={}".format(name, value) in result.stdout @pytest.mark.parametrize( - 'args', + "args", [ [], - ['--verbose'], - ] + ["--verbose"], + ], ) def test_debug__tags(script, args): """ Check the compatible tag output. """ - args = ['debug'] + args + args = ["debug"] + args result = script.pip(*args, allow_stderr_warning=True) stdout = result.stdout tags = compatibility_tags.get_supported() - expected_tag_header = 'Compatible tags: {}'.format(len(tags)) + expected_tag_header = "Compatible tags: {}".format(len(tags)) assert expected_tag_header in stdout - show_verbose_note = '--verbose' not in args + show_verbose_note = "--verbose" not in args assert ( - '...\n [First 10 tags shown. Pass --verbose to show all.]' in stdout + "...\n [First 10 tags shown. Pass --verbose to show all.]" in stdout ) == show_verbose_note @pytest.mark.parametrize( - 'args, expected', + "args, expected", [ - (['--python-version', '3.7'], "(target: version_info='3.7')"), - ] + (["--python-version", "3.7"], "(target: version_info='3.7')"), + ], ) def test_debug__target_options(script, args, expected): """ Check passing target-related options. """ - args = ['debug'] + args + args = ["debug"] + args result = script.pip(*args, allow_stderr_warning=True) stdout = result.stdout - assert 'Compatible tags: ' in stdout + assert "Compatible tags: " in stdout assert expected in stdout diff --git a/tests/functional/test_download.py b/tests/functional/test_download.py index 3291d580d23..4245057f3f8 100644 --- a/tests/functional/test_download.py +++ b/tests/functional/test_download.py @@ -25,13 +25,9 @@ def test_download_if_requested(script): """ It should download (in the scratch path) and not install if requested. """ - result = script.pip( - 'download', '-d', 'pip_downloads', 'INITools==0.1' - ) - result.did_create( - Path('scratch') / 'pip_downloads' / 'INITools-0.1.tar.gz' - ) - result.did_not_create(script.site_packages / 'initools') + result = script.pip("download", "-d", "pip_downloads", "INITools==0.1") + result.did_create(Path("scratch") / "pip_downloads" / "INITools-0.1.tar.gz") + result.did_not_create(script.site_packages / "initools") @pytest.mark.network @@ -39,11 +35,9 @@ def test_basic_download_setuptools(script): """ It should download (in the scratch path) and not install if requested. """ - result = script.pip('download', 'setuptools') - setuptools_prefix = str(Path('scratch') / 'setuptools') - assert any( - path.startswith(setuptools_prefix) for path in result.files_created - ) + result = script.pip("download", "setuptools") + setuptools_prefix = str(Path("scratch") / "setuptools") + assert any(path.startswith(setuptools_prefix) for path in result.files_created) def test_download_wheel(script, data): @@ -51,13 +45,10 @@ def test_download_wheel(script, data): Test using "pip download" to download a *.whl archive. """ result = script.pip( - 'download', - '--no-index', - '-f', data.packages, - '-d', '.', 'meta' + "download", "--no-index", "-f", data.packages, "-d", ".", "meta" ) - result.did_create(Path('scratch') / 'meta-1.0-py2.py3-none-any.whl') - result.did_not_create(script.site_packages / 'piptestpackage') + result.did_create(Path("scratch") / "meta-1.0-py2.py3-none-any.whl") + result.did_not_create(script.site_packages / "piptestpackage") @pytest.mark.network @@ -66,14 +57,22 @@ def test_single_download_from_requirements_file(script): It should support download (in the scratch path) from PyPI from a requirements file """ - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ INITools==0.1 - """)) + """ + ) + ) result = script.pip( - 'download', '-r', script.scratch_path / 'test-req.txt', '-d', '.', + "download", + "-r", + script.scratch_path / "test-req.txt", + "-d", + ".", ) - result.did_create(Path('scratch') / 'INITools-0.1.tar.gz') - result.did_not_create(script.site_packages / 'initools') + result.did_create(Path("scratch") / "INITools-0.1.tar.gz") + result.did_not_create(script.site_packages / "initools") @pytest.mark.network @@ -81,43 +80,35 @@ def test_basic_download_should_download_dependencies(script): """ It should download dependencies (in the scratch path) """ - result = script.pip( - 'download', 'Paste[openid]==1.7.5.1', '-d', '.' - ) - result.did_create(Path('scratch') / 'Paste-1.7.5.1.tar.gz') - openid_tarball_prefix = str(Path('scratch') / 'python-openid-') - assert any( - path.startswith(openid_tarball_prefix) for path in result.files_created - ) - result.did_not_create(script.site_packages / 'openid') + result = script.pip("download", "Paste[openid]==1.7.5.1", "-d", ".") + result.did_create(Path("scratch") / "Paste-1.7.5.1.tar.gz") + openid_tarball_prefix = str(Path("scratch") / "python-openid-") + assert any(path.startswith(openid_tarball_prefix) for path in result.files_created) + result.did_not_create(script.site_packages / "openid") def test_download_wheel_archive(script, data): """ It should download a wheel archive path """ - wheel_filename = 'colander-0.9.9-py2.py3-none-any.whl' - wheel_path = '/'.join((data.find_links, wheel_filename)) - result = script.pip( - 'download', wheel_path, - '-d', '.', '--no-deps' - ) - result.did_create(Path('scratch') / wheel_filename) + wheel_filename = "colander-0.9.9-py2.py3-none-any.whl" + wheel_path = "/".join((data.find_links, wheel_filename)) + result = script.pip("download", wheel_path, "-d", ".", "--no-deps") + result.did_create(Path("scratch") / wheel_filename) def test_download_should_download_wheel_deps(script, data): """ It should download dependencies for wheels(in the scratch path) """ - wheel_filename = 'colander-0.9.9-py2.py3-none-any.whl' - dep_filename = 'translationstring-1.1.tar.gz' - wheel_path = '/'.join((data.find_links, wheel_filename)) + wheel_filename = "colander-0.9.9-py2.py3-none-any.whl" + dep_filename = "translationstring-1.1.tar.gz" + wheel_path = "/".join((data.find_links, wheel_filename)) result = script.pip( - 'download', wheel_path, - '-d', '.', '--find-links', data.find_links, '--no-index' + "download", wheel_path, "-d", ".", "--find-links", data.find_links, "--no-index" ) - result.did_create(Path('scratch') / wheel_filename) - result.did_create(Path('scratch') / dep_filename) + result.did_create(Path("scratch") / wheel_filename) + result.did_create(Path("scratch") / dep_filename) @pytest.mark.network @@ -125,33 +116,47 @@ def test_download_should_skip_existing_files(script): """ It should not download files already existing in the scratch dir """ - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ INITools==0.1 - """)) + """ + ) + ) result = script.pip( - 'download', '-r', script.scratch_path / 'test-req.txt', '-d', '.', + "download", + "-r", + script.scratch_path / "test-req.txt", + "-d", + ".", ) - result.did_create(Path('scratch') / 'INITools-0.1.tar.gz') - result.did_not_create(script.site_packages / 'initools') + result.did_create(Path("scratch") / "INITools-0.1.tar.gz") + result.did_not_create(script.site_packages / "initools") # adding second package to test-req.txt - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ INITools==0.1 python-openid==2.2.5 - """)) + """ + ) + ) # only the second package should be downloaded result = script.pip( - 'download', '-r', script.scratch_path / 'test-req.txt', '-d', '.', + "download", + "-r", + script.scratch_path / "test-req.txt", + "-d", + ".", ) - openid_tarball_prefix = str(Path('scratch') / 'python-openid-') - assert any( - path.startswith(openid_tarball_prefix) for path in result.files_created - ) - result.did_not_create(Path('scratch') / 'INITools-0.1.tar.gz') - result.did_not_create(script.site_packages / 'initools') - result.did_not_create(script.site_packages / 'openid') + openid_tarball_prefix = str(Path("scratch") / "python-openid-") + assert any(path.startswith(openid_tarball_prefix) for path in result.files_created) + result.did_not_create(Path("scratch") / "INITools-0.1.tar.gz") + result.did_not_create(script.site_packages / "initools") + result.did_not_create(script.site_packages / "openid") @pytest.mark.network @@ -160,10 +165,10 @@ def test_download_vcs_link(script): It should allow -d flag for vcs links, regression test for issue #798. """ result = script.pip( - 'download', '-d', '.', 'git+git://github.com/pypa/pip-test-package.git' + "download", "-d", ".", "git+git://github.com/pypa/pip-test-package.git" ) - result.did_create(Path('scratch') / 'pip-test-package-0.1.1.zip') - result.did_not_create(script.site_packages / 'piptestpackage') + result.did_create(Path("scratch") / "pip-test-package-0.1.1.zip") + result.did_not_create(script.site_packages / "piptestpackage") def test_only_binary_set_then_download_specific_platform(script, data): @@ -171,16 +176,21 @@ def test_only_binary_set_then_download_specific_platform(script, data): Confirm that specifying an interpreter/platform constraint is allowed when ``--only-binary=:all:`` is set. """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake", ) - result.did_create(Path('scratch') / 'fake-1.0-py2.py3-none-any.whl') + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") def test_no_deps_set_then_download_specific_platform(script, data): @@ -188,16 +198,21 @@ def test_no_deps_set_then_download_specific_platform(script, data): Confirm that specifying an interpreter/platform constraint is allowed when ``--no-deps`` is set. """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--no-deps', - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--no-deps", + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake", ) - result.did_create(Path('scratch') / 'fake-1.0-py2.py3-none-any.whl') + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") def test_download_specific_platform_fails(script, data): @@ -205,16 +220,21 @@ def test_download_specific_platform_fails(script, data): Confirm that specifying an interpreter/platform constraint enforces that ``--no-deps`` or ``--only-binary=:all:`` is set. """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake', + "download", + "--no-index", + "--find-links", + data.find_links, + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake", expect_error=True, ) - assert '--only-binary=:all:' in result.stderr + assert "--only-binary=:all:" in result.stderr def test_no_binary_set_then_download_specific_platform_fails(script, data): @@ -222,18 +242,23 @@ def test_no_binary_set_then_download_specific_platform_fails(script, data): Confirm that specifying an interpreter/platform constraint enforces that ``--only-binary=:all:`` is set without ``--no-binary``. """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--no-binary=fake', - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake', + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--no-binary=fake", + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake", expect_error=True, ) - assert '--only-binary=:all:' in result.stderr + assert "--only-binary=:all:" in result.stderr def test_download_specify_platform(script, data): @@ -241,73 +266,98 @@ def test_download_specify_platform(script, data): Test using "pip download --platform" to download a .whl archive supported for a specific platform """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") # Confirm that universal wheels are returned even for specific # platforms. result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake", ) - result.did_create(Path('scratch') / 'fake-1.0-py2.py3-none-any.whl') + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'macosx_10_9_x86_64', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "macosx_10_9_x86_64", + "fake", ) data.reset() - fake_wheel(data, 'fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl') - fake_wheel(data, 'fake-2.0-py2.py3-none-linux_x86_64.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl") + fake_wheel(data, "fake-2.0-py2.py3-none-linux_x86_64.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'macosx_10_10_x86_64', - 'fake' - ) - result.did_create( - Path('scratch') / - 'fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "macosx_10_10_x86_64", + "fake", ) + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl") # OSX platform wheels are not backward-compatible. result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'macosx_10_8_x86_64', - 'fake', + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "macosx_10_8_x86_64", + "fake", expect_error=True, ) # No linux wheel provided for this version. result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake==1', + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake==1", expect_error=True, ) result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake==2' - ) - result.did_create( - Path('scratch') / 'fake-2.0-py2.py3-none-linux_x86_64.whl' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake==2", ) + result.did_create(Path("scratch") / "fake-2.0-py2.py3-none-linux_x86_64.whl") class TestDownloadPlatformManylinuxes(object): @@ -316,50 +366,70 @@ class TestDownloadPlatformManylinuxes(object): manylinux platforms. """ - @pytest.mark.parametrize("platform", [ - "linux_x86_64", - "manylinux1_x86_64", - "manylinux2010_x86_64", - "manylinux2014_x86_64", - ]) + @pytest.mark.parametrize( + "platform", + [ + "linux_x86_64", + "manylinux1_x86_64", + "manylinux2010_x86_64", + "manylinux2014_x86_64", + ], + ) def test_download_universal(self, platform, script, data): """ Universal wheels are returned even for specific platforms. """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', platform, - 'fake', + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + platform, + "fake", ) - result.did_create(Path('scratch') / 'fake-1.0-py2.py3-none-any.whl') - - @pytest.mark.parametrize("wheel_abi,platform", [ - ("manylinux1_x86_64", "manylinux1_x86_64"), - ("manylinux1_x86_64", "manylinux2010_x86_64"), - ("manylinux2010_x86_64", "manylinux2010_x86_64"), - ("manylinux1_x86_64", "manylinux2014_x86_64"), - ("manylinux2010_x86_64", "manylinux2014_x86_64"), - ("manylinux2014_x86_64", "manylinux2014_x86_64"), - ]) + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + + @pytest.mark.parametrize( + "wheel_abi,platform", + [ + ("manylinux1_x86_64", "manylinux1_x86_64"), + ("manylinux1_x86_64", "manylinux2010_x86_64"), + ("manylinux2010_x86_64", "manylinux2010_x86_64"), + ("manylinux1_x86_64", "manylinux2014_x86_64"), + ("manylinux2010_x86_64", "manylinux2014_x86_64"), + ("manylinux2014_x86_64", "manylinux2014_x86_64"), + ], + ) def test_download_compatible_manylinuxes( - self, wheel_abi, platform, script, data, + self, + wheel_abi, + platform, + script, + data, ): """ Earlier manylinuxes are compatible with later manylinuxes. """ - wheel = 'fake-1.0-py2.py3-none-{}.whl'.format(wheel_abi) + wheel = "fake-1.0-py2.py3-none-{}.whl".format(wheel_abi) fake_wheel(data, wheel) result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', platform, - 'fake', + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + platform, + "fake", ) - result.did_create(Path('scratch') / wheel) + result.did_create(Path("scratch") / wheel) def test_explicit_platform_only(self, data, script): """ @@ -367,13 +437,18 @@ def test_explicit_platform_only(self, data, script): explicit platform--it won't ever be added to the compatible tags. """ - fake_wheel(data, 'fake-1.0-py2.py3-none-linux_x86_64.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-linux_x86_64.whl") script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--platform', 'linux_x86_64', - 'fake', + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--platform", + "linux_x86_64", + "fake", ) @@ -382,79 +457,119 @@ def test_download__python_version(script, data): Test using "pip download --python-version" to download a .whl archive supported for a specific interpreter """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '2', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "2", + "fake", ) - result.did_create(Path('scratch') / 'fake-1.0-py2.py3-none-any.whl') + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '3', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "3", + "fake", ) result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '27', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "27", + "fake", ) result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '33', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "33", + "fake", ) data.reset() - fake_wheel(data, 'fake-1.0-py2-none-any.whl') - fake_wheel(data, 'fake-2.0-py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2-none-any.whl") + fake_wheel(data, "fake-2.0-py3-none-any.whl") # No py3 provided for version 1. result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '3', - 'fake==1.0', + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "3", + "fake==1.0", expect_error=True, ) result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '2', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "2", + "fake", ) - result.did_create(Path('scratch') / 'fake-1.0-py2-none-any.whl') + result.did_create(Path("scratch") / "fake-1.0-py2-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '26', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "26", + "fake", ) result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '3', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "3", + "fake", ) - result.did_create(Path('scratch') / 'fake-2.0-py3-none-any.whl') + result.did_create(Path("scratch") / "fake-2.0-py3-none-any.whl") def make_wheel_with_python_requires(script, package_name, python_requires): @@ -466,52 +581,67 @@ def make_wheel_with_python_requires(script, package_name, python_requires): package_dir = script.scratch_path / package_name package_dir.mkdir() - text = textwrap.dedent("""\ + text = textwrap.dedent( + """\ from setuptools import setup setup(name='{}', python_requires='{}', version='1.0') - """).format(package_name, python_requires) - package_dir.joinpath('setup.py').write_text(text) + """ + ).format(package_name, python_requires) + package_dir.joinpath("setup.py").write_text(text) script.run( - 'python', 'setup.py', 'bdist_wheel', '--universal', cwd=package_dir, + "python", + "setup.py", + "bdist_wheel", + "--universal", + cwd=package_dir, allow_stderr_warning=PY2, ) - file_name = '{}-1.0-py2.py3-none-any.whl'.format(package_name) - return package_dir / 'dist' / file_name + file_name = "{}-1.0-py2.py3-none-any.whl".format(package_name) + return package_dir / "dist" / file_name def test_download__python_version_used_for_python_requires( - script, data, with_wheel, + script, + data, + with_wheel, ): """ Test that --python-version is used for the Requires-Python check. """ wheel_path = make_wheel_with_python_requires( - script, 'mypackage', python_requires='==3.2', + script, + "mypackage", + python_requires="==3.2", ) wheel_dir = os.path.dirname(wheel_path) def make_args(python_version): return [ - 'download', '--no-index', '--find-links', wheel_dir, - '--only-binary=:all:', - '--dest', '.', - '--python-version', python_version, - 'mypackage==1.0', + "download", + "--no-index", + "--find-links", + wheel_dir, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + python_version, + "mypackage==1.0", ] - args = make_args('33') + args = make_args("33") result = script.pip(*args, expect_error=True) expected_err = ( "ERROR: Package 'mypackage' requires a different Python: " "3.3.0 not in '==3.2'" ) - assert expected_err in result.stderr, 'stderr: {}'.format(result.stderr) + assert expected_err in result.stderr, "stderr: {}".format(result.stderr) # Now try with a --python-version that satisfies the Requires-Python. - args = make_args('32') + args = make_args("32") script.pip(*args) # no exception @@ -520,58 +650,88 @@ def test_download_specify_abi(script, data): Test using "pip download --abi" to download a .whl archive supported for a specific abi """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') - result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--implementation', 'fk', - '--abi', 'fake_abi', - 'fake' - ) - result.did_create(Path('scratch') / 'fake-1.0-py2.py3-none-any.whl') - - result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--implementation', 'fk', - '--abi', 'none', - 'fake' - ) - - result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--abi', 'cp27m', - 'fake', + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") + result = script.pip( + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--implementation", + "fk", + "--abi", + "fake_abi", + "fake", + ) + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") + + result = script.pip( + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--implementation", + "fk", + "--abi", + "none", + "fake", + ) + + result = script.pip( + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--abi", + "cp27m", + "fake", ) data.reset() - fake_wheel(data, 'fake-1.0-fk2-fakeabi-fake_platform.whl') - result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--python-version', '2', - '--implementation', 'fk', - '--platform', 'fake_platform', - '--abi', 'fakeabi', - 'fake' - ) - result.did_create( - Path('scratch') / 'fake-1.0-fk2-fakeabi-fake_platform.whl' - ) - - result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--implementation', 'fk', - '--platform', 'fake_platform', - '--abi', 'none', - 'fake', + fake_wheel(data, "fake-1.0-fk2-fakeabi-fake_platform.whl") + result = script.pip( + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--python-version", + "2", + "--implementation", + "fk", + "--platform", + "fake_platform", + "--abi", + "fakeabi", + "fake", + ) + result.did_create(Path("scratch") / "fake-1.0-fk2-fakeabi-fake_platform.whl") + + result = script.pip( + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--implementation", + "fk", + "--platform", + "fake_platform", + "--abi", + "none", + "fake", expect_error=True, ) @@ -581,35 +741,52 @@ def test_download_specify_implementation(script, data): Test using "pip download --abi" to download a .whl archive supported for a specific abi """ - fake_wheel(data, 'fake-1.0-py2.py3-none-any.whl') + fake_wheel(data, "fake-1.0-py2.py3-none-any.whl") result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--implementation', 'fk', - 'fake' + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--implementation", + "fk", + "fake", ) - result.did_create(Path('scratch') / 'fake-1.0-py2.py3-none-any.whl') + result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl") data.reset() - fake_wheel(data, 'fake-1.0-fk3-none-any.whl') - result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--implementation', 'fk', - '--python-version', '3', - 'fake' - ) - result.did_create(Path('scratch') / 'fake-1.0-fk3-none-any.whl') - - result = script.pip( - 'download', '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--dest', '.', - '--implementation', 'fk', - '--python-version', '2', - 'fake', + fake_wheel(data, "fake-1.0-fk3-none-any.whl") + result = script.pip( + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--implementation", + "fk", + "--python-version", + "3", + "fake", + ) + result.did_create(Path("scratch") / "fake-1.0-fk3-none-any.whl") + + result = script.pip( + "download", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--dest", + ".", + "--implementation", + "fk", + "--python-version", + "2", + "fake", expect_error=True, ) @@ -618,10 +795,8 @@ def test_download_exit_status_code_when_no_requirements(script): """ Test download exit status code when no requirements specified """ - result = script.pip('download', expect_error=True) - assert ( - "You must give at least one requirement to download" in result.stderr - ) + result = script.pip("download", expect_error=True) + assert "You must give at least one requirement to download" in result.stderr assert result.returncode == ERROR @@ -630,100 +805,134 @@ def test_download_exit_status_code_when_blank_requirements_file(script): Test download exit status code when blank requirements file specified """ script.scratch_path.joinpath("blank.txt").write_text("\n") - script.pip('download', '-r', 'blank.txt') + script.pip("download", "-r", "blank.txt") def test_download_prefer_binary_when_tarball_higher_than_wheel(script, data): - fake_wheel(data, 'source-0.8-py2.py3-none-any.whl') + fake_wheel(data, "source-0.8-py2.py3-none-any.whl") result = script.pip( - 'download', - '--prefer-binary', - '--no-index', - '-f', data.packages, - '-d', '.', 'source' + "download", + "--prefer-binary", + "--no-index", + "-f", + data.packages, + "-d", + ".", + "source", ) - result.did_create(Path('scratch') / 'source-0.8-py2.py3-none-any.whl') - result.did_not_create(Path('scratch') / 'source-1.0.tar.gz') + result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") + result.did_not_create(Path("scratch") / "source-1.0.tar.gz") def test_prefer_binary_tarball_higher_than_wheel_req_file(script, data): - fake_wheel(data, 'source-0.8-py2.py3-none-any.whl') - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + fake_wheel(data, "source-0.8-py2.py3-none-any.whl") + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ --prefer-binary source - """)) + """ + ) + ) result = script.pip( - 'download', - '-r', script.scratch_path / 'test-req.txt', - '--no-index', - '-f', data.packages, - '-d', '.' + "download", + "-r", + script.scratch_path / "test-req.txt", + "--no-index", + "-f", + data.packages, + "-d", + ".", ) - result.did_create(Path('scratch') / 'source-0.8-py2.py3-none-any.whl') - result.did_not_create(Path('scratch') / 'source-1.0.tar.gz') + result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") + result.did_not_create(Path("scratch") / "source-1.0.tar.gz") def test_download_prefer_binary_when_wheel_doesnt_satisfy_req(script, data): - fake_wheel(data, 'source-0.8-py2.py3-none-any.whl') - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + fake_wheel(data, "source-0.8-py2.py3-none-any.whl") + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ source>0.9 - """)) + """ + ) + ) result = script.pip( - 'download', - '--prefer-binary', - '--no-index', - '-f', data.packages, - '-d', '.', - '-r', script.scratch_path / 'test-req.txt' + "download", + "--prefer-binary", + "--no-index", + "-f", + data.packages, + "-d", + ".", + "-r", + script.scratch_path / "test-req.txt", ) - result.did_create(Path('scratch') / 'source-1.0.tar.gz') - result.did_not_create(Path('scratch') / 'source-0.8-py2.py3-none-any.whl') + result.did_create(Path("scratch") / "source-1.0.tar.gz") + result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") def test_prefer_binary_when_wheel_doesnt_satisfy_req_req_file(script, data): - fake_wheel(data, 'source-0.8-py2.py3-none-any.whl') - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + fake_wheel(data, "source-0.8-py2.py3-none-any.whl") + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ --prefer-binary source>0.9 - """)) + """ + ) + ) result = script.pip( - 'download', - '--no-index', - '-f', data.packages, - '-d', '.', - '-r', script.scratch_path / 'test-req.txt' + "download", + "--no-index", + "-f", + data.packages, + "-d", + ".", + "-r", + script.scratch_path / "test-req.txt", ) - result.did_create(Path('scratch') / 'source-1.0.tar.gz') - result.did_not_create(Path('scratch') / 'source-0.8-py2.py3-none-any.whl') + result.did_create(Path("scratch") / "source-1.0.tar.gz") + result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl") def test_download_prefer_binary_when_only_tarball_exists(script, data): result = script.pip( - 'download', - '--prefer-binary', - '--no-index', - '-f', data.packages, - '-d', '.', 'source' + "download", + "--prefer-binary", + "--no-index", + "-f", + data.packages, + "-d", + ".", + "source", ) - result.did_create(Path('scratch') / 'source-1.0.tar.gz') + result.did_create(Path("scratch") / "source-1.0.tar.gz") def test_prefer_binary_when_only_tarball_exists_req_file(script, data): - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ --prefer-binary source - """)) + """ + ) + ) result = script.pip( - 'download', - '--no-index', - '-f', data.packages, - '-d', '.', - '-r', script.scratch_path / 'test-req.txt' + "download", + "--no-index", + "-f", + data.packages, + "-d", + ".", + "-r", + script.scratch_path / "test-req.txt", ) - result.did_create(Path('scratch') / 'source-1.0.tar.gz') + result.did_create(Path("scratch") / "source-1.0.tar.gz") @pytest.fixture(scope="session") @@ -734,17 +943,17 @@ def shared_script(tmpdir_factory, script_factory): def test_download_file_url(shared_script, shared_data, tmpdir): - download_dir = tmpdir / 'download' + download_dir = tmpdir / "download" download_dir.mkdir() - downloaded_path = download_dir / 'simple-1.0.tar.gz' + downloaded_path = download_dir / "simple-1.0.tar.gz" - simple_pkg = shared_data.packages / 'simple-1.0.tar.gz' + simple_pkg = shared_data.packages / "simple-1.0.tar.gz" shared_script.pip( - 'download', - '-d', + "download", + "-d", str(download_dir), - '--no-index', + "--no-index", path_to_url(str(simple_pkg)), ) @@ -752,69 +961,61 @@ def test_download_file_url(shared_script, shared_data, tmpdir): assert simple_pkg.read_bytes() == downloaded_path.read_bytes() -def test_download_file_url_existing_ok_download( - shared_script, shared_data, tmpdir -): - download_dir = tmpdir / 'download' +def test_download_file_url_existing_ok_download(shared_script, shared_data, tmpdir): + download_dir = tmpdir / "download" download_dir.mkdir() - downloaded_path = download_dir / 'simple-1.0.tar.gz' - fake_existing_package = shared_data.packages / 'simple-2.0.tar.gz' + downloaded_path = download_dir / "simple-1.0.tar.gz" + fake_existing_package = shared_data.packages / "simple-2.0.tar.gz" shutil.copy(str(fake_existing_package), str(downloaded_path)) downloaded_path_bytes = downloaded_path.read_bytes() digest = sha256(downloaded_path_bytes).hexdigest() - simple_pkg = shared_data.packages / 'simple-1.0.tar.gz' + simple_pkg = shared_data.packages / "simple-1.0.tar.gz" url = "{}#sha256={}".format(path_to_url(simple_pkg), digest) - shared_script.pip('download', '-d', str(download_dir), url) + shared_script.pip("download", "-d", str(download_dir), url) assert downloaded_path_bytes == downloaded_path.read_bytes() -def test_download_file_url_existing_bad_download( - shared_script, shared_data, tmpdir -): - download_dir = tmpdir / 'download' +def test_download_file_url_existing_bad_download(shared_script, shared_data, tmpdir): + download_dir = tmpdir / "download" download_dir.mkdir() - downloaded_path = download_dir / 'simple-1.0.tar.gz' - fake_existing_package = shared_data.packages / 'simple-2.0.tar.gz' + downloaded_path = download_dir / "simple-1.0.tar.gz" + fake_existing_package = shared_data.packages / "simple-2.0.tar.gz" shutil.copy(str(fake_existing_package), str(downloaded_path)) - simple_pkg = shared_data.packages / 'simple-1.0.tar.gz' + simple_pkg = shared_data.packages / "simple-1.0.tar.gz" simple_pkg_bytes = simple_pkg.read_bytes() digest = sha256(simple_pkg_bytes).hexdigest() url = "{}#sha256={}".format(path_to_url(simple_pkg), digest) - shared_script.pip('download', '-d', str(download_dir), url) + shared_script.pip("download", "-d", str(download_dir), url) assert simple_pkg_bytes == downloaded_path.read_bytes() -def test_download_http_url_bad_hash( - shared_script, shared_data, tmpdir, mock_server -): - download_dir = tmpdir / 'download' +def test_download_http_url_bad_hash(shared_script, shared_data, tmpdir, mock_server): + download_dir = tmpdir / "download" download_dir.mkdir() - downloaded_path = download_dir / 'simple-1.0.tar.gz' - fake_existing_package = shared_data.packages / 'simple-2.0.tar.gz' + downloaded_path = download_dir / "simple-1.0.tar.gz" + fake_existing_package = shared_data.packages / "simple-2.0.tar.gz" shutil.copy(str(fake_existing_package), str(downloaded_path)) - simple_pkg = shared_data.packages / 'simple-1.0.tar.gz' + simple_pkg = shared_data.packages / "simple-1.0.tar.gz" simple_pkg_bytes = simple_pkg.read_bytes() digest = sha256(simple_pkg_bytes).hexdigest() - mock_server.set_responses([ - file_response(simple_pkg) - ]) + mock_server.set_responses([file_response(simple_pkg)]) mock_server.start() - base_address = 'http://{}:{}'.format(mock_server.host, mock_server.port) + base_address = "http://{}:{}".format(mock_server.host, mock_server.port) url = "{}/simple-1.0.tar.gz#sha256={}".format(base_address, digest) - shared_script.pip('download', '-d', str(download_dir), url) + shared_script.pip("download", "-d", str(download_dir), url) assert simple_pkg_bytes == downloaded_path.read_bytes() mock_server.stop() requests = mock_server.get_requests() assert len(requests) == 1 - assert requests[0]['PATH_INFO'] == '/simple-1.0.tar.gz' - assert requests[0]['HTTP_ACCEPT_ENCODING'] == 'identity' + assert requests[0]["PATH_INFO"] == "/simple-1.0.tar.gz" + assert requests[0]["HTTP_ACCEPT_ENCODING"] == "identity" diff --git a/tests/functional/test_fast_deps.py b/tests/functional/test_fast_deps.py index 655440b881b..bfdab4285f5 100644 --- a/tests/functional/test_fast_deps.py +++ b/tests/functional/test_fast_deps.py @@ -8,72 +8,87 @@ def pip(script, command, requirement): return script.pip( - command, '--prefer-binary', '--no-cache-dir', - '--use-feature=fast-deps', requirement, + command, + "--prefer-binary", + "--no-cache-dir", + "--use-feature=fast-deps", + requirement, allow_stderr_warning=True, ) def assert_installed(script, names): - list_output = json.loads(script.pip('list', '--format=json').stdout) - installed = {canonicalize_name(item['name']) for item in list_output} + list_output = json.loads(script.pip("list", "--format=json").stdout) + installed = {canonicalize_name(item["name"]) for item in list_output} assert installed.issuperset(map(canonicalize_name, names)) @mark.network -@mark.parametrize(('requirement', 'expected'), ( - ('Paste==3.4.2', ('Paste', 'six')), - ('Paste[flup]==3.4.2', ('Paste', 'six', 'flup')), -)) +@mark.parametrize( + ("requirement", "expected"), + ( + ("Paste==3.4.2", ("Paste", "six")), + ("Paste[flup]==3.4.2", ("Paste", "six", "flup")), + ), +) def test_install_from_pypi(requirement, expected, script): - pip(script, 'install', requirement) + pip(script, "install", requirement) assert_installed(script, expected) @mark.network -@mark.parametrize(('requirement', 'expected'), ( - ('Paste==3.4.2', ('Paste-3.4.2-*.whl', 'six-*.whl')), - ('Paste[flup]==3.4.2', ('Paste-3.4.2-*.whl', 'six-*.whl', 'flup-*')), -)) +@mark.parametrize( + ("requirement", "expected"), + ( + ("Paste==3.4.2", ("Paste-3.4.2-*.whl", "six-*.whl")), + ("Paste[flup]==3.4.2", ("Paste-3.4.2-*.whl", "six-*.whl", "flup-*")), + ), +) def test_download_from_pypi(requirement, expected, script): - result = pip(script, 'download', requirement) + result = pip(script, "download", requirement) created = list(map(basename, result.files_created)) assert all(fnmatch.filter(created, f) for f in expected) @mark.network def test_build_wheel_with_deps(data, script): - result = pip(script, 'wheel', data.packages/'requiresPaste') + result = pip(script, "wheel", data.packages / "requiresPaste") created = list(map(basename, result.files_created)) - assert fnmatch.filter(created, 'requiresPaste-3.1.4-*.whl') - assert fnmatch.filter(created, 'Paste-3.4.2-*.whl') - assert fnmatch.filter(created, 'six-*.whl') + assert fnmatch.filter(created, "requiresPaste-3.1.4-*.whl") + assert fnmatch.filter(created, "Paste-3.4.2-*.whl") + assert fnmatch.filter(created, "six-*.whl") @mark.network def test_require_hash(script, tmp_path): - reqs = tmp_path / 'requirements.txt' + reqs = tmp_path / "requirements.txt" reqs.write_text( - u'idna==2.10' - ' --hash=sha256:' - 'b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0' - ' --hash=sha256:' - 'b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6' + u"idna==2.10" + " --hash=sha256:" + "b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + " --hash=sha256:" + "b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6" ) result = script.pip( - 'download', '--use-feature=fast-deps', '-r', str(reqs), + "download", + "--use-feature=fast-deps", + "-r", + str(reqs), allow_stderr_warning=True, ) created = list(map(basename, result.files_created)) - assert fnmatch.filter(created, 'idna-2.10*') + assert fnmatch.filter(created, "idna-2.10*") @mark.network def test_hash_mismatch(script, tmp_path): - reqs = tmp_path / 'requirements.txt' - reqs.write_text(u'idna==2.10 --hash=sha256:irna') + reqs = tmp_path / "requirements.txt" + reqs.write_text(u"idna==2.10 --hash=sha256:irna") result = script.pip( - 'download', '--use-feature=fast-deps', '-r', str(reqs), + "download", + "--use-feature=fast-deps", + "-r", + str(reqs), expect_error=True, ) - assert 'DO NOT MATCH THE HASHES' in result.stderr + assert "DO NOT MATCH THE HASHES" in result.stderr diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py index ef22169869b..77f423a9484 100644 --- a/tests/functional/test_freeze.py +++ b/tests/functional/test_freeze.py @@ -18,7 +18,7 @@ path_to_url, ) -distribute_re = re.compile('^distribute==[0-9.]+\n', re.MULTILINE) +distribute_re = re.compile("^distribute==[0-9.]+\n", re.MULTILINE) def _check_output(result, expected): @@ -33,19 +33,18 @@ def _check_output(result, expected): # but then you have to remember to upcase . The right # thing to do in the end is probably to find out how to report # the proper fully-cased package name in our error message. - if sys.platform == 'win32': - actual = actual.replace('initools', 'INITools') + if sys.platform == "win32": + actual = actual.replace("initools", "INITools") # This allows our existing tests to work when run in a context # with distribute installed. - actual = distribute_re.sub('', actual) + actual = distribute_re.sub("", actual) def banner(msg): - return '\n========== {msg} ==========\n'.format(**locals()) + return "\n========== {msg} ==========\n".format(**locals()) assert checker.check_output(expected, actual, ELLIPSIS), ( - banner('EXPECTED') + expected + banner('ACTUAL') + actual + - banner(6 * '=') + banner("EXPECTED") + expected + banner("ACTUAL") + actual + banner(6 * "=") ) @@ -58,26 +57,33 @@ def test_basic_freeze(script): currently it is not). """ - script.scratch_path.joinpath("initools-req.txt").write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("initools-req.txt").write_text( + textwrap.dedent( + """\ simple==2.0 # and something else to test out: simple2<=3.0 - """)) + """ + ) + ) script.pip_install_local( - '-r', script.scratch_path / 'initools-req.txt', + "-r", + script.scratch_path / "initools-req.txt", ) - result = script.pip('freeze', expect_stderr=True) - expected = textwrap.dedent("""\ + result = script.pip("freeze", expect_stderr=True) + expected = textwrap.dedent( + """\ ...simple==2.0 simple2==3.0... - """) + """ + ) _check_output(result.stdout, expected) def test_freeze_with_pip(script): """Test pip shows itself""" - result = script.pip('freeze', '--all') - assert 'pip==' in result.stdout + result = script.pip("freeze", "--all") + assert "pip==" in result.stdout def test_freeze_with_invalid_names(script): @@ -87,39 +93,43 @@ def test_freeze_with_invalid_names(script): def fake_install(pkgname, dest): egg_info_path = os.path.join( - dest, '{}-1.0-py{}.{}.egg-info'.format( - pkgname.replace('-', '_'), - sys.version_info[0], - sys.version_info[1] - ) + dest, + "{}-1.0-py{}.{}.egg-info".format( + pkgname.replace("-", "_"), sys.version_info[0], sys.version_info[1] + ), ) - with open(egg_info_path, 'w') as egg_info_file: - egg_info_file.write(textwrap.dedent("""\ + with open(egg_info_path, "w") as egg_info_file: + egg_info_file.write( + textwrap.dedent( + """\ Metadata-Version: 1.0 Name: {} Version: 1.0 - """.format(pkgname) - )) + """.format( + pkgname + ) + ) + ) - valid_pkgnames = ('middle-dash', 'middle_underscore', 'middle.dot') + valid_pkgnames = ("middle-dash", "middle_underscore", "middle.dot") invalid_pkgnames = ( - '-leadingdash', '_leadingunderscore', '.leadingdot', - 'trailingdash-', 'trailingunderscore_', 'trailingdot.' + "-leadingdash", + "_leadingunderscore", + ".leadingdot", + "trailingdash-", + "trailingunderscore_", + "trailingdot.", ) for pkgname in valid_pkgnames + invalid_pkgnames: fake_install(pkgname, script.site_packages_path) - result = script.pip('freeze', expect_stderr=True) + result = script.pip("freeze", expect_stderr=True) for pkgname in valid_pkgnames: - _check_output( - result.stdout, - '...{}==1.0...'.format(pkgname.replace('_', '-')) - ) + _check_output(result.stdout, "...{}==1.0...".format(pkgname.replace("_", "-"))) for pkgname in invalid_pkgnames: # Check that the full distribution repr is present. - dist_repr = '{} 1.0 ('.format(pkgname.replace('_', '-')) - expected = ( - '...Could not generate requirement for ' - 'distribution {}...'.format(dist_repr) + dist_repr = "{} 1.0 (".format(pkgname.replace("_", "-")) + expected = "...Could not generate requirement for " "distribution {}...".format( + dist_repr ) _check_output(result.stderr, expected) @@ -138,16 +148,20 @@ def test_freeze_editable_not_vcs(script, tmpdir): pkg_path = _create_test_package(script) # Rename the .git directory so the directory is no longer recognized # as a VCS directory. - os.rename(os.path.join(pkg_path, '.git'), os.path.join(pkg_path, '.bak')) - script.pip('install', '-e', pkg_path) - result = script.pip('freeze') + os.rename(os.path.join(pkg_path, ".git"), os.path.join(pkg_path, ".bak")) + script.pip("install", "-e", pkg_path) + result = script.pip("freeze") # We need to apply os.path.normcase() to the path since that is what # the freeze code does. - expected = textwrap.dedent("""\ + expected = textwrap.dedent( + """\ ...# Editable install with no version control (version-pkg==0.1) -e {} - ...""".format(os.path.normcase(pkg_path))) + ...""".format( + os.path.normcase(pkg_path) + ) + ) _check_output(result.stdout, expected) @@ -157,18 +171,22 @@ def test_freeze_editable_git_with_no_remote(script, tmpdir, deprecated_python): Test an editable Git install with no remote url. """ pkg_path = _create_test_package(script) - script.pip('install', '-e', pkg_path) - result = script.pip('freeze') + script.pip("install", "-e", pkg_path) + result = script.pip("freeze") if not deprecated_python: - assert result.stderr == '' + assert result.stderr == "" # We need to apply os.path.normcase() to the path since that is what # the freeze code does. - expected = textwrap.dedent("""\ + expected = textwrap.dedent( + """\ ...# Editable Git install with no remote (version-pkg==0.1) -e {} - ...""".format(os.path.normcase(pkg_path))) + ...""".format( + os.path.normcase(pkg_path) + ) + ) _check_output(result.stdout, expected) @@ -176,17 +194,16 @@ def test_freeze_editable_git_with_no_remote(script, tmpdir, deprecated_python): def test_freeze_svn(script, tmpdir): """Test freezing a svn checkout""" - checkout_path = _create_test_package(script, vcs='svn') + checkout_path = _create_test_package(script, vcs="svn") # Install with develop - script.run( - 'python', 'setup.py', 'develop', - cwd=checkout_path, expect_stderr=True - ) - result = script.pip('freeze', expect_stderr=True) - expected = textwrap.dedent("""\ + script.run("python", "setup.py", "develop", cwd=checkout_path, expect_stderr=True) + result = script.pip("freeze", expect_stderr=True) + expected = textwrap.dedent( + """\ ...-e svn+...#egg=version_pkg - ...""") + ...""" + ) _check_output(result.stdout, expected) @@ -205,16 +222,21 @@ def test_freeze_exclude_editable(script, tmpdir): pkg_version = _create_test_package(script) result = script.run( - 'git', 'clone', pkg_version, 'pip-test-package', + "git", + "clone", + pkg_version, + "pip-test-package", expect_stderr=True, ) - repo_dir = script.scratch_path / 'pip-test-package' + repo_dir = script.scratch_path / "pip-test-package" result = script.run( - 'python', 'setup.py', 'develop', + "python", + "setup.py", + "develop", cwd=repo_dir, expect_stderr=True, ) - result = script.pip('freeze', '--exclude-editable', expect_stderr=True) + result = script.pip("freeze", "--exclude-editable", expect_stderr=True) expected = textwrap.dedent( """ ...-e git+...#egg=version_pkg @@ -233,16 +255,21 @@ def test_freeze_git_clone(script, tmpdir): pkg_version = _create_test_package(script) result = script.run( - 'git', 'clone', pkg_version, 'pip-test-package', + "git", + "clone", + pkg_version, + "pip-test-package", expect_stderr=True, ) - repo_dir = script.scratch_path / 'pip-test-package' + repo_dir = script.scratch_path / "pip-test-package" result = script.run( - 'python', 'setup.py', 'develop', + "python", + "setup.py", + "develop", cwd=repo_dir, expect_stderr=True, ) - result = script.pip('freeze', expect_stderr=True) + result = script.pip("freeze", expect_stderr=True) expected = textwrap.dedent( """ ...-e git+...#egg=version_pkg @@ -252,7 +279,9 @@ def test_freeze_git_clone(script, tmpdir): _check_output(result.stdout, expected) result = script.pip( - 'freeze', '-f', '{repo_dir}#egg=pip_test_package'.format(**locals()), + "freeze", + "-f", + "{repo_dir}#egg=pip_test_package".format(**locals()), expect_stderr=True, ) expected = textwrap.dedent( @@ -260,24 +289,29 @@ def test_freeze_git_clone(script, tmpdir): -f {repo}#egg=pip_test_package... -e git+...#egg=version_pkg ... - """.format(repo=repo_dir), + """.format( + repo=repo_dir + ), ).strip() _check_output(result.stdout, expected) # Check that slashes in branch or tag names are translated. # See also issue #1083: https://github.com/pypa/pip/issues/1083 script.run( - 'git', 'checkout', '-b', 'branch/name/with/slash', + "git", + "checkout", + "-b", + "branch/name/with/slash", cwd=repo_dir, expect_stderr=True, ) # Create a new commit to ensure that the commit has only one branch # or tag name associated to it (to avoid the non-determinism reported # in issue #1867). - (repo_dir / 'newfile').touch() - script.run('git', 'add', 'newfile', cwd=repo_dir) - _git_commit(script, repo_dir, message='...') - result = script.pip('freeze', expect_stderr=True) + (repo_dir / "newfile").touch() + script.run("git", "add", "newfile", cwd=repo_dir) + _git_commit(script, repo_dir, message="...") + result = script.pip("freeze", expect_stderr=True) expected = textwrap.dedent( """ ...-e ...@...#egg=version_pkg @@ -298,16 +332,21 @@ def test_freeze_git_clone_srcdir(script, tmpdir): pkg_version = _create_test_package_with_srcdir(script) result = script.run( - 'git', 'clone', pkg_version, 'pip-test-package', + "git", + "clone", + pkg_version, + "pip-test-package", expect_stderr=True, ) - repo_dir = script.scratch_path / 'pip-test-package' + repo_dir = script.scratch_path / "pip-test-package" result = script.run( - 'python', 'setup.py', 'develop', - cwd=repo_dir / 'subdir', + "python", + "setup.py", + "develop", + cwd=repo_dir / "subdir", expect_stderr=True, ) - result = script.pip('freeze', expect_stderr=True) + result = script.pip("freeze", expect_stderr=True) expected = textwrap.dedent( """ ...-e git+...#egg=version_pkg&subdirectory=subdir @@ -317,7 +356,9 @@ def test_freeze_git_clone_srcdir(script, tmpdir): _check_output(result.stdout, expected) result = script.pip( - 'freeze', '-f', '{repo_dir}#egg=pip_test_package'.format(**locals()), + "freeze", + "-f", + "{repo_dir}#egg=pip_test_package".format(**locals()), expect_stderr=True, ) expected = textwrap.dedent( @@ -325,7 +366,9 @@ def test_freeze_git_clone_srcdir(script, tmpdir): -f {repo}#egg=pip_test_package... -e git+...#egg=version_pkg&subdirectory=subdir ... - """.format(repo=repo_dir), + """.format( + repo=repo_dir + ), ).strip() _check_output(result.stdout, expected) @@ -338,17 +381,12 @@ def test_freeze_mercurial_clone_srcdir(script, tmpdir): relative to setup.py. """ # Returns path to a generated package called "version_pkg" - pkg_version = _create_test_package_with_srcdir(script, vcs='hg') + pkg_version = _create_test_package_with_srcdir(script, vcs="hg") - result = script.run( - 'hg', 'clone', pkg_version, 'pip-test-package' - ) - repo_dir = script.scratch_path / 'pip-test-package' - result = script.run( - 'python', 'setup.py', 'develop', - cwd=repo_dir / 'subdir' - ) - result = script.pip('freeze') + result = script.run("hg", "clone", pkg_version, "pip-test-package") + repo_dir = script.scratch_path / "pip-test-package" + result = script.run("python", "setup.py", "develop", cwd=repo_dir / "subdir") + result = script.pip("freeze") expected = textwrap.dedent( """ ...-e hg+...#egg=version_pkg&subdirectory=subdir @@ -358,14 +396,16 @@ def test_freeze_mercurial_clone_srcdir(script, tmpdir): _check_output(result.stdout, expected) result = script.pip( - 'freeze', '-f', '{repo_dir}#egg=pip_test_package'.format(**locals()) + "freeze", "-f", "{repo_dir}#egg=pip_test_package".format(**locals()) ) expected = textwrap.dedent( """ -f {repo}#egg=pip_test_package... -e hg+...#egg=version_pkg&subdirectory=subdir ... - """.format(repo=repo_dir), + """.format( + repo=repo_dir + ), ).strip() _check_output(result.stdout, expected) @@ -379,47 +419,64 @@ def test_freeze_git_remote(script, tmpdir): pkg_version = _create_test_package(script) result = script.run( - 'git', 'clone', pkg_version, 'pip-test-package', + "git", + "clone", + pkg_version, + "pip-test-package", expect_stderr=True, ) - repo_dir = script.scratch_path / 'pip-test-package' + repo_dir = script.scratch_path / "pip-test-package" result = script.run( - 'python', 'setup.py', 'develop', + "python", + "setup.py", + "develop", cwd=repo_dir, expect_stderr=True, ) origin_remote = pkg_version - other_remote = pkg_version + '-other' + other_remote = pkg_version + "-other" # check frozen remote after clone - result = script.pip('freeze', expect_stderr=True) - expected = textwrap.dedent( - """ + result = script.pip("freeze", expect_stderr=True) + expected = ( + textwrap.dedent( + """ ...-e git+{remote}@...#egg=version_pkg ... """ - ).format(remote=origin_remote).strip() + ) + .format(remote=origin_remote) + .strip() + ) _check_output(result.stdout, expected) # check frozen remote when there is no remote named origin - script.run('git', 'remote', 'remove', 'origin', cwd=repo_dir) - script.run('git', 'remote', 'add', 'other', other_remote, cwd=repo_dir) - result = script.pip('freeze', expect_stderr=True) - expected = textwrap.dedent( - """ + script.run("git", "remote", "remove", "origin", cwd=repo_dir) + script.run("git", "remote", "add", "other", other_remote, cwd=repo_dir) + result = script.pip("freeze", expect_stderr=True) + expected = ( + textwrap.dedent( + """ ...-e git+{remote}@...#egg=version_pkg ... """ - ).format(remote=other_remote).strip() + ) + .format(remote=other_remote) + .strip() + ) _check_output(result.stdout, expected) # when there are more than one origin, priority is given to the # remote named origin - script.run('git', 'remote', 'add', 'origin', origin_remote, cwd=repo_dir) - result = script.pip('freeze', expect_stderr=True) - expected = textwrap.dedent( - """ + script.run("git", "remote", "add", "origin", origin_remote, cwd=repo_dir) + result = script.pip("freeze", expect_stderr=True) + expected = ( + textwrap.dedent( + """ ...-e git+{remote}@...#egg=version_pkg ... """ - ).format(remote=origin_remote).strip() + ) + .format(remote=origin_remote) + .strip() + ) _check_output(result.stdout, expected) @@ -430,19 +487,24 @@ def test_freeze_mercurial_clone(script, tmpdir): """ # Returns path to a generated package called "version_pkg" - pkg_version = _create_test_package(script, vcs='hg') + pkg_version = _create_test_package(script, vcs="hg") result = script.run( - 'hg', 'clone', pkg_version, 'pip-test-package', + "hg", + "clone", + pkg_version, + "pip-test-package", expect_stderr=True, ) - repo_dir = script.scratch_path / 'pip-test-package' + repo_dir = script.scratch_path / "pip-test-package" result = script.run( - 'python', 'setup.py', 'develop', + "python", + "setup.py", + "develop", cwd=repo_dir, expect_stderr=True, ) - result = script.pip('freeze', expect_stderr=True) + result = script.pip("freeze", expect_stderr=True) expected = textwrap.dedent( """ ...-e hg+...#egg=version_pkg @@ -452,7 +514,9 @@ def test_freeze_mercurial_clone(script, tmpdir): _check_output(result.stdout, expected) result = script.pip( - 'freeze', '-f', '{repo_dir}#egg=pip_test_package'.format(**locals()), + "freeze", + "-f", + "{repo_dir}#egg=pip_test_package".format(**locals()), expect_stderr=True, ) expected = textwrap.dedent( @@ -460,7 +524,9 @@ def test_freeze_mercurial_clone(script, tmpdir): -f {repo}#egg=pip_test_package... ...-e hg+...#egg=version_pkg ... - """.format(repo=repo_dir), + """.format( + repo=repo_dir + ), ).strip() _check_output(result.stdout, expected) @@ -472,33 +538,40 @@ def test_freeze_bazaar_clone(script, tmpdir): """ try: - checkout_path = _create_test_package(script, vcs='bazaar') + checkout_path = _create_test_package(script, vcs="bazaar") except OSError as e: - pytest.fail('Invoking `bzr` failed: {e}'.format(e=e)) + pytest.fail("Invoking `bzr` failed: {e}".format(e=e)) + result = script.run("bzr", "checkout", checkout_path, "bzr-package") result = script.run( - 'bzr', 'checkout', checkout_path, 'bzr-package' - ) - result = script.run( - 'python', 'setup.py', 'develop', - cwd=script.scratch_path / 'bzr-package', + "python", + "setup.py", + "develop", + cwd=script.scratch_path / "bzr-package", expect_stderr=True, ) - result = script.pip('freeze', expect_stderr=True) - expected = textwrap.dedent("""\ + result = script.pip("freeze", expect_stderr=True) + expected = textwrap.dedent( + """\ ...-e bzr+file://...@1#egg=version_pkg - ...""") + ...""" + ) _check_output(result.stdout, expected) result = script.pip( - 'freeze', '-f', - '{checkout_path}/#egg=django-wikiapp'.format(**locals()), + "freeze", + "-f", + "{checkout_path}/#egg=django-wikiapp".format(**locals()), expect_stderr=True, ) - expected = textwrap.dedent("""\ + expected = textwrap.dedent( + """\ -f {repo}/#egg=django-wikiapp ...-e bzr+file://...@...#egg=version_pkg - ...""".format(repo=checkout_path)) + ...""".format( + repo=checkout_path + ) + ) _check_output(result.stdout, expected) @@ -509,8 +582,7 @@ def test_freeze_bazaar_clone(script, tmpdir): [("hg", "git"), ("git", "hg")], ) def test_freeze_nested_vcs(script, outer_vcs, inner_vcs): - """Test VCS can be correctly freezed when resides inside another VCS repo. - """ + """Test VCS can be correctly freezed when resides inside another VCS repo.""" # Create Python package. pkg_path = _create_test_package(script, vcs=inner_vcs) @@ -536,7 +608,8 @@ def test_freeze_nested_vcs(script, outer_vcs, inner_vcs): # used by the test_freeze_with_requirement_* tests below -_freeze_req_opts = textwrap.dedent("""\ +_freeze_req_opts = textwrap.dedent( + """\ # Unchanged requirements below this line -r ignore.txt --requirement ignore.txt @@ -549,25 +622,30 @@ def test_freeze_nested_vcs(script, outer_vcs, inner_vcs): --find-links http://ignore --index-url http://ignore --use-feature 2020-resolver -""") +""" +) def test_freeze_with_requirement_option_file_url_egg_not_installed( - script, deprecated_python): + script, deprecated_python +): """ Test "freeze -r requirements.txt" with a local file URL whose egg name is not installed. """ - url = path_to_url('my-package.tar.gz') + '#egg=Does.Not-Exist' - requirements_path = script.scratch_path.joinpath('requirements.txt') - requirements_path.write_text(url + '\n') + url = path_to_url("my-package.tar.gz") + "#egg=Does.Not-Exist" + requirements_path = script.scratch_path.joinpath("requirements.txt") + requirements_path.write_text(url + "\n") result = script.pip( - 'freeze', '--requirement', 'requirements.txt', expect_stderr=True, + "freeze", + "--requirement", + "requirements.txt", + expect_stderr=True, ) expected_err = ( - 'WARNING: Requirement file [requirements.txt] contains {}, ' + "WARNING: Requirement file [requirements.txt] contains {}, " "but package 'Does.Not-Exist' is not installed\n" ).format(url) if deprecated_python: @@ -582,26 +660,40 @@ def test_freeze_with_requirement_option(script): """ - script.scratch_path.joinpath("hint1.txt").write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("hint1.txt").write_text( + textwrap.dedent( + """\ INITools==0.1 NoExist==4.2 # A comment that ensures end of line comments work. simple==3.0; python_version > '1.0' - """) + _freeze_req_opts) - script.scratch_path.joinpath("hint2.txt").write_text(textwrap.dedent("""\ + """ + ) + + _freeze_req_opts + ) + script.scratch_path.joinpath("hint2.txt").write_text( + textwrap.dedent( + """\ iniTools==0.1 Noexist==4.2 # A comment that ensures end of line comments work. Simple==3.0; python_version > '1.0' - """) + _freeze_req_opts) - result = script.pip_install_local('initools==0.2') - result = script.pip_install_local('simple') + """ + ) + + _freeze_req_opts + ) + result = script.pip_install_local("initools==0.2") + result = script.pip_install_local("simple") result = script.pip( - 'freeze', '--requirement', 'hint1.txt', + "freeze", + "--requirement", + "hint1.txt", expect_stderr=True, ) - expected = textwrap.dedent("""\ + expected = textwrap.dedent( + """\ INITools==0.2 simple==3.0 - """) + """ + ) expected += _freeze_req_opts expected += "## The following requirements were added by pip freeze:..." _check_output(result.stdout, expected) @@ -610,7 +702,9 @@ def test_freeze_with_requirement_option(script): "'NoExist' is not installed" ) in result.stderr result = script.pip( - 'freeze', '--requirement', 'hint2.txt', + "freeze", + "--requirement", + "hint2.txt", expect_stderr=True, ) _check_output(result.stdout, expected) @@ -626,35 +720,55 @@ def test_freeze_with_requirement_option_multiple(script): --requirement hints """ - script.scratch_path.joinpath('hint1.txt').write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("hint1.txt").write_text( + textwrap.dedent( + """\ INITools==0.1 NoExist==4.2 simple==3.0; python_version > '1.0' - """) + _freeze_req_opts) - script.scratch_path.joinpath('hint2.txt').write_text(textwrap.dedent("""\ + """ + ) + + _freeze_req_opts + ) + script.scratch_path.joinpath("hint2.txt").write_text( + textwrap.dedent( + """\ NoExist2==2.0 simple2==1.0 - """) + _freeze_req_opts) - result = script.pip_install_local('initools==0.2') - result = script.pip_install_local('simple') - result = script.pip_install_local('simple2==1.0') - result = script.pip_install_local('meta') + """ + ) + + _freeze_req_opts + ) + result = script.pip_install_local("initools==0.2") + result = script.pip_install_local("simple") + result = script.pip_install_local("simple2==1.0") + result = script.pip_install_local("meta") result = script.pip( - 'freeze', '--requirement', 'hint1.txt', '--requirement', 'hint2.txt', + "freeze", + "--requirement", + "hint1.txt", + "--requirement", + "hint2.txt", expect_stderr=True, ) - expected = textwrap.dedent("""\ + expected = textwrap.dedent( + """\ INITools==0.2 simple==1.0 - """) + """ + ) expected += _freeze_req_opts - expected += textwrap.dedent("""\ + expected += textwrap.dedent( + """\ simple2==1.0 - """) + """ + ) expected += "## The following requirements were added by pip freeze:" - expected += '\n' + textwrap.dedent("""\ + expected += "\n" + textwrap.dedent( + """\ ...meta==1.0... - """) + """ + ) _check_output(result.stdout, expected) assert ( "Requirement file [hint1.txt] contains NoExist==4.2, but package " @@ -674,71 +788,102 @@ def test_freeze_with_requirement_option_package_repeated_one_file(script): Test freezing with single requirements file that contains a package multiple times """ - script.scratch_path.joinpath('hint1.txt').write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("hint1.txt").write_text( + textwrap.dedent( + """\ simple2 simple2 NoExist - """) + _freeze_req_opts) - result = script.pip_install_local('simple2==1.0') - result = script.pip_install_local('meta') + """ + ) + + _freeze_req_opts + ) + result = script.pip_install_local("simple2==1.0") + result = script.pip_install_local("meta") result = script.pip( - 'freeze', '--requirement', 'hint1.txt', + "freeze", + "--requirement", + "hint1.txt", expect_stderr=True, ) - expected_out = textwrap.dedent("""\ + expected_out = textwrap.dedent( + """\ simple2==1.0 - """) + """ + ) expected_out += _freeze_req_opts expected_out += "## The following requirements were added by pip freeze:" - expected_out += '\n' + textwrap.dedent("""\ + expected_out += "\n" + textwrap.dedent( + """\ ...meta==1.0... - """) + """ + ) _check_output(result.stdout, expected_out) - err1 = ("Requirement file [hint1.txt] contains NoExist, " - "but package 'NoExist' is not installed\n") + err1 = ( + "Requirement file [hint1.txt] contains NoExist, " + "but package 'NoExist' is not installed\n" + ) err2 = "Requirement simple2 included multiple times [hint1.txt]\n" assert err1 in result.stderr assert err2 in result.stderr # there shouldn't be any other 'is not installed' warnings - assert result.stderr.count('is not installed') == 1 + assert result.stderr.count("is not installed") == 1 def test_freeze_with_requirement_option_package_repeated_multi_file(script): """ Test freezing with multiple requirements file that contain a package """ - script.scratch_path.joinpath('hint1.txt').write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("hint1.txt").write_text( + textwrap.dedent( + """\ simple - """) + _freeze_req_opts) - script.scratch_path.joinpath('hint2.txt').write_text(textwrap.dedent("""\ + """ + ) + + _freeze_req_opts + ) + script.scratch_path.joinpath("hint2.txt").write_text( + textwrap.dedent( + """\ simple NoExist - """) + _freeze_req_opts) - result = script.pip_install_local('simple==1.0') - result = script.pip_install_local('meta') + """ + ) + + _freeze_req_opts + ) + result = script.pip_install_local("simple==1.0") + result = script.pip_install_local("meta") result = script.pip( - 'freeze', '--requirement', 'hint1.txt', - '--requirement', 'hint2.txt', + "freeze", + "--requirement", + "hint1.txt", + "--requirement", + "hint2.txt", expect_stderr=True, ) - expected_out = textwrap.dedent("""\ + expected_out = textwrap.dedent( + """\ simple==1.0 - """) + """ + ) expected_out += _freeze_req_opts expected_out += "## The following requirements were added by pip freeze:" - expected_out += '\n' + textwrap.dedent("""\ + expected_out += "\n" + textwrap.dedent( + """\ ...meta==1.0... - """) + """ + ) _check_output(result.stdout, expected_out) - err1 = ("Requirement file [hint2.txt] contains NoExist, but package " - "'NoExist' is not installed\n") - err2 = ("Requirement simple included multiple times " - "[hint1.txt, hint2.txt]\n") + err1 = ( + "Requirement file [hint2.txt] contains NoExist, but package " + "'NoExist' is not installed\n" + ) + err2 = "Requirement simple included multiple times " "[hint1.txt, hint2.txt]\n" assert err1 in result.stderr assert err2 in result.stderr # there shouldn't be any other 'is not installed' warnings - assert result.stderr.count('is not installed') == 1 + assert result.stderr.count("is not installed") == 1 @pytest.mark.network @@ -747,17 +892,17 @@ def test_freeze_user(script, virtualenv, data): """ Testing freeze with --user, first we have to install some stuff. """ - script.pip('download', 'setuptools', 'wheel', '-d', data.packages) - script.pip_install_local('--find-links', data.find_links, - '--user', 'simple==2.0') - script.pip_install_local('--find-links', data.find_links, - 'simple2==3.0') - result = script.pip('freeze', '--user', expect_stderr=True) - expected = textwrap.dedent("""\ + script.pip("download", "setuptools", "wheel", "-d", data.packages) + script.pip_install_local("--find-links", data.find_links, "--user", "simple==2.0") + script.pip_install_local("--find-links", data.find_links, "simple2==3.0") + result = script.pip("freeze", "--user", expect_stderr=True) + expected = textwrap.dedent( + """\ simple==2.0 - """) + """ + ) _check_output(result.stdout, expected) - assert 'simple2' not in result.stdout + assert "simple2" not in result.stdout @pytest.mark.network @@ -765,12 +910,15 @@ def test_freeze_path(tmpdir, script, data): """ Test freeze with --path. """ - script.pip('install', '--find-links', data.find_links, - '--target', tmpdir, 'simple==2.0') - result = script.pip('freeze', '--path', tmpdir) - expected = textwrap.dedent("""\ + script.pip( + "install", "--find-links", data.find_links, "--target", tmpdir, "simple==2.0" + ) + result = script.pip("freeze", "--path", tmpdir) + expected = textwrap.dedent( + """\ simple==2.0 - """) + """ + ) _check_output(result.stdout, expected) @@ -781,19 +929,23 @@ def test_freeze_path_exclude_user(tmpdir, script, data): Test freeze with --path and make sure packages from --user are not picked up. """ - script.pip_install_local('--find-links', data.find_links, - '--user', 'simple2') - script.pip('install', '--find-links', data.find_links, - '--target', tmpdir, 'simple==1.0') - result = script.pip('freeze', '--user') - expected = textwrap.dedent("""\ + script.pip_install_local("--find-links", data.find_links, "--user", "simple2") + script.pip( + "install", "--find-links", data.find_links, "--target", tmpdir, "simple==1.0" + ) + result = script.pip("freeze", "--user") + expected = textwrap.dedent( + """\ simple2==3.0 - """) + """ + ) _check_output(result.stdout, expected) - result = script.pip('freeze', '--path', tmpdir) - expected = textwrap.dedent("""\ + result = script.pip("freeze", "--path", tmpdir) + expected = textwrap.dedent( + """\ simple==1.0 - """) + """ + ) _check_output(result.stdout, expected) @@ -806,20 +958,26 @@ def test_freeze_path_multiple(tmpdir, script, data): os.mkdir(path1) path2 = tmpdir / "path2" os.mkdir(path2) - script.pip('install', '--find-links', data.find_links, - '--target', path1, 'simple==2.0') - script.pip('install', '--find-links', data.find_links, - '--target', path2, 'simple2==3.0') - result = script.pip('freeze', '--path', path1) - expected = textwrap.dedent("""\ + script.pip( + "install", "--find-links", data.find_links, "--target", path1, "simple==2.0" + ) + script.pip( + "install", "--find-links", data.find_links, "--target", path2, "simple2==3.0" + ) + result = script.pip("freeze", "--path", path1) + expected = textwrap.dedent( + """\ simple==2.0 - """) + """ + ) _check_output(result.stdout, expected) - result = script.pip('freeze', '--path', path1, '--path', path2) - expected = textwrap.dedent("""\ + result = script.pip("freeze", "--path", path1, "--path", path2) + expected = textwrap.dedent( + """\ simple==2.0 simple2==3.0 - """) + """ + ) _check_output(result.stdout, expected) @@ -838,14 +996,12 @@ def test_freeze_skip_work_dir_pkg(script): """ # Create a test package and create .egg-info dir - pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0') - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + pkg_path = create_test_package_with_setup(script, name="simple", version="1.0") + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) # Freeze should not include package simple when run from package directory - result = script.pip('freeze', cwd=pkg_path) - assert 'simple' not in result.stdout + result = script.pip("freeze", cwd=pkg_path) + assert "simple" not in result.stdout def test_freeze_include_work_dir_pkg(script): @@ -855,14 +1011,12 @@ def test_freeze_include_work_dir_pkg(script): """ # Create a test package and create .egg-info dir - pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0') - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + pkg_path = create_test_package_with_setup(script, name="simple", version="1.0") + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) - script.environ.update({'PYTHONPATH': pkg_path}) + script.environ.update({"PYTHONPATH": pkg_path}) # Freeze should include package simple when run from package directory, # when package directory is in PYTHONPATH - result = script.pip('freeze', cwd=pkg_path) - assert 'simple==1.0' in result.stdout + result = script.pip("freeze", cwd=pkg_path) + assert "simple==1.0" in result.stdout diff --git a/tests/functional/test_hash.py b/tests/functional/test_hash.py index 5d7bd975e18..f6dd8b2a3d5 100644 --- a/tests/functional/test_hash.py +++ b/tests/functional/test_hash.py @@ -3,30 +3,35 @@ def test_basic_hash(script, tmpdir): """Run 'pip hash' through its default behavior.""" - expected = ('--hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425' - 'e73043362938b9824') - result = script.pip('hash', _hello_file(tmpdir)) + expected = ( + "--hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425" + "e73043362938b9824" + ) + result = script.pip("hash", _hello_file(tmpdir)) assert expected in str(result) def test_good_algo_option(script, tmpdir): """Make sure the -a option works.""" - expected = ('--hash=sha512:9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caad' - 'ae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e' - '5c3adef46f73bcdec043') - result = script.pip('hash', '-a', 'sha512', _hello_file(tmpdir)) + expected = ( + "--hash=sha512:9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caad" + "ae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e" + "5c3adef46f73bcdec043" + ) + result = script.pip("hash", "-a", "sha512", _hello_file(tmpdir)) assert expected in str(result) def test_bad_algo_option(script, tmpdir): """Make sure the -a option raises an error when given a bad operand.""" - result = script.pip('hash', '-a', 'invalidname', _hello_file(tmpdir), - expect_error=True) + result = script.pip( + "hash", "-a", "invalidname", _hello_file(tmpdir), expect_error=True + ) assert "invalid choice: 'invalidname'" in str(result) def _hello_file(tmpdir): """Return a temp file to hash containing "hello".""" - file = tmpdir / 'hashable' - file.write_text('hello') + file = tmpdir / "hashable" + file.write_text("hello") return file diff --git a/tests/functional/test_help.py b/tests/functional/test_help.py index 00a395006b7..bf6cbca9b56 100644 --- a/tests/functional/test_help.py +++ b/tests/functional/test_help.py @@ -11,8 +11,8 @@ def test_run_method_should_return_success_when_finds_command_name(): Test HelpCommand.run for existing command """ options_mock = Mock() - args = ('freeze',) - help_cmd = create_command('help') + args = ("freeze",) + help_cmd = create_command("help") status = help_cmd.run(options_mock, args) assert status == SUCCESS @@ -23,7 +23,7 @@ def test_run_method_should_return_success_when_command_name_not_specified(): """ options_mock = Mock() args = () - help_cmd = create_command('help') + help_cmd = create_command("help") status = help_cmd.run(options_mock, args) assert status == SUCCESS @@ -33,8 +33,8 @@ def test_run_method_should_raise_command_error_when_command_does_not_exist(): Test HelpCommand.run for non-existing command """ options_mock = Mock() - args = ('mycommand',) - help_cmd = create_command('help') + args = ("mycommand",) + help_cmd = create_command("help") with pytest.raises(CommandError): help_cmd.run(options_mock, args) @@ -44,7 +44,7 @@ def test_help_command_should_exit_status_ok_when_command_exists(script): """ Test `help` command for existing command """ - result = script.pip('help', 'freeze') + result = script.pip("help", "freeze") assert result.returncode == SUCCESS @@ -52,7 +52,7 @@ def test_help_command_should_exit_status_ok_when_no_cmd_is_specified(script): """ Test `help` command for no command """ - result = script.pip('help') + result = script.pip("help") assert result.returncode == SUCCESS @@ -60,7 +60,7 @@ def test_help_command_should_exit_status_error_when_cmd_does_not_exist(script): """ Test `help` command for non-existing command """ - result = script.pip('help', 'mycommand', expect_error=True) + result = script.pip("help", "mycommand", expect_error=True) assert result.returncode == ERROR @@ -68,19 +68,20 @@ def test_help_commands_equally_functional(in_memory_pip): """ Test if `pip help` and 'pip --help' behave the same way. """ - results = list(map(in_memory_pip.pip, ('help', '--help'))) + results = list(map(in_memory_pip.pip, ("help", "--help"))) results.append(in_memory_pip.pip()) out = map(lambda x: x.stdout, results) ret = map(lambda x: x.returncode, results) msg = '"pip --help" != "pip help" != "pip"' - assert len(set(out)) == 1, 'output of: ' + msg - assert sum(ret) == 0, 'exit codes of: ' + msg + assert len(set(out)) == 1, "output of: " + msg + assert sum(ret) == 0, "exit codes of: " + msg assert all(len(o) > 0 for o in out) for name in commands_dict: assert ( - in_memory_pip.pip('help', name).stdout == - in_memory_pip.pip(name, '--help').stdout != "" + in_memory_pip.pip("help", name).stdout + == in_memory_pip.pip(name, "--help").stdout + != "" ) diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index 17a72bca82e..bdfdb488960 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -41,59 +41,76 @@ ) -@pytest.mark.parametrize('command', ('install', 'wheel')) -@pytest.mark.parametrize('variant', ('missing_setuptools', 'bad_setuptools')) +@pytest.mark.parametrize("command", ("install", "wheel")) +@pytest.mark.parametrize("variant", ("missing_setuptools", "bad_setuptools")) def test_pep518_uses_build_env(script, data, common_wheels, command, variant): - if variant == 'missing_setuptools': + if variant == "missing_setuptools": script.pip("uninstall", "-y", "setuptools") - elif variant == 'bad_setuptools': + elif variant == "bad_setuptools": setuptools_mod = script.site_packages_path.joinpath("setuptools.py") - with open(setuptools_mod, 'a') as f: + with open(setuptools_mod, "a") as f: f.write('\nraise ImportError("toto")') else: raise ValueError(variant) script.pip( - command, '--no-index', '-f', common_wheels, '-f', data.packages, + command, + "--no-index", + "-f", + common_wheels, + "-f", + data.packages, data.src.joinpath("pep518-3.0"), ) def test_pep518_build_env_uses_same_pip( - script, data, pip_src, common_wheels, deprecated_python): + script, data, pip_src, common_wheels, deprecated_python +): """Ensure the subprocess call to pip for installing the build dependencies is using the same version of pip. """ - with open(script.scratch_path / 'pip.py', 'w') as fp: - fp.write('raise ImportError') + with open(script.scratch_path / "pip.py", "w") as fp: + fp.write("raise ImportError") script.run( - 'python', pip_src / 'src/pip', 'install', '--no-index', - '-f', common_wheels, '-f', data.packages, + "python", + pip_src / "src/pip", + "install", + "--no-index", + "-f", + common_wheels, + "-f", + data.packages, data.src.joinpath("pep518-3.0"), expect_stderr=deprecated_python, ) def test_pep518_refuses_conflicting_requires(script, data): - create_basic_wheel_for_package(script, 'setuptools', '1.0') - create_basic_wheel_for_package(script, 'wheel', '1.0') + create_basic_wheel_for_package(script, "setuptools", "1.0") + create_basic_wheel_for_package(script, "wheel", "1.0") project_dir = data.src.joinpath("pep518_conflicting_requires") - result = script.pip_install_local('-f', script.scratch_path, - project_dir, expect_error=True) + result = script.pip_install_local( + "-f", script.scratch_path, project_dir, expect_error=True + ) assert ( - result.returncode != 0 and ( - 'Some build dependencies for {url} conflict ' - 'with PEP 517/518 supported ' - 'requirements: setuptools==1.0 is incompatible with ' - 'setuptools>=40.8.0.' - .format(url=path_to_url(project_dir))) in result.stderr + result.returncode != 0 + and ( + "Some build dependencies for {url} conflict " + "with PEP 517/518 supported " + "requirements: setuptools==1.0 is incompatible with " + "setuptools>=40.8.0.".format(url=path_to_url(project_dir)) + ) + in result.stderr ), str(result) def test_pep518_refuses_invalid_requires(script, data, common_wheels): result = script.pip( - 'install', '-f', common_wheels, + "install", + "-f", + common_wheels, data.src.joinpath("pep518_invalid_requires"), - expect_error=True + expect_error=True, ) assert result.returncode == 1 assert "does not comply with PEP 518" in result.stderr @@ -101,9 +118,11 @@ def test_pep518_refuses_invalid_requires(script, data, common_wheels): def test_pep518_refuses_invalid_build_system(script, data, common_wheels): result = script.pip( - 'install', '-f', common_wheels, + "install", + "-f", + common_wheels, data.src.joinpath("pep518_invalid_build_system"), - expect_error=True + expect_error=True, ) assert result.returncode == 1 assert "does not comply with PEP 518" in result.stderr @@ -111,9 +130,11 @@ def test_pep518_refuses_invalid_build_system(script, data, common_wheels): def test_pep518_allows_missing_requires(script, data, common_wheels): result = script.pip( - 'install', '-f', common_wheels, + "install", + "-f", + common_wheels, data.src.joinpath("pep518_missing_requires"), - expect_stderr=True + expect_stderr=True, ) # Make sure we don't warn when this occurs. assert "does not comply with PEP 518" not in result.stderr @@ -136,81 +157,97 @@ def test_pep518_with_user_pip(script, pip_src, data, common_wheels): non-isolated environment, and break pip in the system site-packages, so that isolated uses of pip will fail. """ - script.pip("install", "--ignore-installed", - "-f", common_wheels, "--user", pip_src) - system_pip_dir = script.site_packages_path / 'pip' + script.pip("install", "--ignore-installed", "-f", common_wheels, "--user", pip_src) + system_pip_dir = script.site_packages_path / "pip" assert not system_pip_dir.exists() system_pip_dir.mkdir() - with open(system_pip_dir / '__init__.py', 'w') as fp: - fp.write('raise ImportError\n') + with open(system_pip_dir / "__init__.py", "w") as fp: + fp.write("raise ImportError\n") script.pip( - 'wheel', '--no-index', '-f', common_wheels, '-f', data.packages, + "wheel", + "--no-index", + "-f", + common_wheels, + "-f", + data.packages, data.src.joinpath("pep518-3.0"), ) def test_pep518_with_extra_and_markers(script, data, common_wheels): script.pip( - 'wheel', '--no-index', - '-f', common_wheels, - '-f', data.find_links, + "wheel", + "--no-index", + "-f", + common_wheels, + "-f", + data.find_links, data.src.joinpath("pep518_with_extra_and_markers-1.0"), ) def test_pep518_with_namespace_package(script, data, common_wheels): script.pip( - 'wheel', '--no-index', - '-f', common_wheels, - '-f', data.find_links, + "wheel", + "--no-index", + "-f", + common_wheels, + "-f", + data.find_links, data.src.joinpath("pep518_with_namespace_package-1.0"), use_module=True, ) @pytest.mark.timeout(60) -@pytest.mark.parametrize('command', ('install', 'wheel')) -@pytest.mark.parametrize('package', ('pep518_forkbomb', - 'pep518_twin_forkbombs_first', - 'pep518_twin_forkbombs_second')) +@pytest.mark.parametrize("command", ("install", "wheel")) +@pytest.mark.parametrize( + "package", + ("pep518_forkbomb", "pep518_twin_forkbombs_first", "pep518_twin_forkbombs_second"), +) def test_pep518_forkbombs(script, data, common_wheels, command, package): - package_source = next(data.packages.glob(package + '-[0-9]*.tar.gz')) + package_source = next(data.packages.glob(package + "-[0-9]*.tar.gz")) result = script.pip( - command, '--no-index', '-v', - '-f', common_wheels, - '-f', data.find_links, + command, + "--no-index", + "-v", + "-f", + common_wheels, + "-f", + data.find_links, package, expect_error=True, ) - assert '{1} is already being built: {0} from {1}'.format( - package, path_to_url(package_source), - ) in result.stderr, str(result) + assert ( + "{1} is already being built: {0} from {1}".format( + package, + path_to_url(package_source), + ) + in result.stderr + ), str(result) @pytest.mark.network def test_pip_second_command_line_interface_works( - script, pip_src, data, common_wheels, deprecated_python, with_wheel + script, pip_src, data, common_wheels, deprecated_python, with_wheel ): """ Check if ``pip`` commands behaves equally """ # Re-install pip so we get the launchers. - script.pip_install_local('-f', common_wheels, pip_src) + script.pip_install_local("-f", common_wheels, pip_src) # On old versions of Python, urllib3/requests will raise a warning about # the lack of an SSLContext. - kwargs = {'expect_stderr': deprecated_python} + kwargs = {"expect_stderr": deprecated_python} if pyversion_tuple < (2, 7, 9): - kwargs['expect_stderr'] = True + kwargs["expect_stderr"] = True - args = ['pip{pyversion}'.format(**globals())] - args.extend(['install', 'INITools==0.2']) - args.extend(['-f', data.packages]) + args = ["pip{pyversion}".format(**globals())] + args.extend(["install", "INITools==0.2"]) + args.extend(["-f", data.packages]) result = script.run(*args, **kwargs) - dist_info_folder = ( - script.site_packages / - 'INITools-0.2.dist-info' - ) - initools_folder = script.site_packages / 'initools' + dist_info_folder = script.site_packages / "INITools-0.2.dist-info" + initools_folder = script.site_packages / "initools" result.did_create(dist_info_folder) result.did_create(initools_folder) @@ -219,7 +256,7 @@ def test_install_exit_status_code_when_no_requirements(script): """ Test install exit status code when no requirements specified """ - result = script.pip('install', expect_error=True) + result = script.pip("install", expect_error=True) assert "You must give at least one requirement to install" in result.stderr assert result.returncode == ERROR @@ -229,7 +266,7 @@ def test_install_exit_status_code_when_blank_requirements_file(script): Test install exit status code when blank requirements file specified """ script.scratch_path.joinpath("blank.txt").write_text("\n") - script.pip('install', '-r', 'blank.txt') + script.pip("install", "-r", "blank.txt") @pytest.mark.network @@ -237,12 +274,9 @@ def test_basic_install_from_pypi(script, with_wheel): """ Test installing a package from PyPI. """ - result = script.pip('install', 'INITools==0.2') - dist_info_folder = ( - script.site_packages / - 'INITools-0.2.dist-info' - ) - initools_folder = script.site_packages / 'initools' + result = script.pip("install", "INITools==0.2") + dist_info_folder = script.site_packages / "INITools-0.2.dist-info" + initools_folder = script.site_packages / "initools" result.did_create(dist_info_folder) result.did_create(initools_folder) @@ -262,11 +296,8 @@ def test_basic_editable_install(script): """ Test editable installation. """ - result = script.pip('install', '-e', 'INITools==0.2', expect_error=True) - assert ( - "INITools==0.2 is not a valid editable requirement" - in result.stderr - ) + result = script.pip("install", "-e", "INITools==0.2", expect_error=True) + assert "INITools==0.2 is not a valid editable requirement" in result.stderr assert not result.files_created @@ -277,30 +308,27 @@ def test_basic_install_editable_from_svn(script): """ checkout_path = _create_test_package(script) repo_url = _create_svn_repo(script, checkout_path) - result = script.pip( - 'install', - '-e', 'svn+' + repo_url + '#egg=version-pkg' - ) - result.assert_installed('version-pkg', with_files=['.svn']) + result = script.pip("install", "-e", "svn+" + repo_url + "#egg=version-pkg") + result.assert_installed("version-pkg", with_files=[".svn"]) def _test_install_editable_from_git(script, tmpdir): """Test cloning from Git.""" - pkg_path = _create_test_package(script, name='testpackage', vcs='git') + pkg_path = _create_test_package(script, name="testpackage", vcs="git") args = [ - 'install', '-e', - 'git+{url}#egg=testpackage'.format(url=path_to_url(pkg_path)), + "install", + "-e", + "git+{url}#egg=testpackage".format(url=path_to_url(pkg_path)), ] result = script.pip(*args) - result.assert_installed('testpackage', with_files=['.git']) + result.assert_installed("testpackage", with_files=[".git"]) def test_basic_install_editable_from_git(script, tmpdir): _test_install_editable_from_git(script, tmpdir) -def test_install_editable_from_git_autobuild_wheel( - script, tmpdir, with_wheel): +def test_install_editable_from_git_autobuild_wheel(script, tmpdir, with_wheel): _test_install_editable_from_git(script, tmpdir) @@ -314,20 +342,23 @@ def test_install_editable_uninstalls_existing(data, script, tmpdir): """ to_install = data.packages.joinpath("pip-test-package-0.1.tar.gz") result = script.pip_install_local(to_install) - assert 'Successfully installed pip-test-package' in result.stdout - result.assert_installed('piptestpackage', editable=False) + assert "Successfully installed pip-test-package" in result.stdout + result.assert_installed("piptestpackage", editable=False) result = script.pip( - 'install', '-e', - '{dir}#egg=pip-test-package'.format( + "install", + "-e", + "{dir}#egg=pip-test-package".format( dir=local_checkout( - 'git+https://github.com/pypa/pip-test-package.git', tmpdir, - )), + "git+https://github.com/pypa/pip-test-package.git", + tmpdir, + ) + ), ) - result.assert_installed('pip-test-package', with_files=['.git']) - assert 'Found existing installation: pip-test-package 0.1' in result.stdout - assert 'Uninstalling pip-test-package-' in result.stdout - assert 'Successfully uninstalled pip-test-package' in result.stdout + result.assert_installed("pip-test-package", with_files=[".git"]) + assert "Found existing installation: pip-test-package 0.1" in result.stdout + assert "Uninstalling pip-test-package-" in result.stdout + assert "Successfully uninstalled pip-test-package" in result.stdout def test_install_editable_uninstalls_existing_from_path(script, data): @@ -335,34 +366,35 @@ def test_install_editable_uninstalls_existing_from_path(script, data): Test that installing an editable uninstalls a previously installed non-editable version from path """ - to_install = data.src.joinpath('simplewheel-1.0') + to_install = data.src.joinpath("simplewheel-1.0") result = script.pip_install_local(to_install) - assert 'Successfully installed simplewheel' in result.stdout - simple_folder = script.site_packages / 'simplewheel' - result.assert_installed('simplewheel', editable=False) + assert "Successfully installed simplewheel" in result.stdout + simple_folder = script.site_packages / "simplewheel" + result.assert_installed("simplewheel", editable=False) result.did_create(simple_folder) result = script.pip( - 'install', '-e', + "install", + "-e", to_install, ) - install_path = script.site_packages / 'simplewheel.egg-link' + install_path = script.site_packages / "simplewheel.egg-link" result.did_create(install_path) - assert 'Found existing installation: simplewheel 1.0' in result.stdout - assert 'Uninstalling simplewheel-' in result.stdout - assert 'Successfully uninstalled simplewheel' in result.stdout + assert "Found existing installation: simplewheel 1.0" in result.stdout + assert "Uninstalling simplewheel-" in result.stdout + assert "Successfully uninstalled simplewheel" in result.stdout assert simple_folder in result.files_deleted, str(result.stdout) @need_mercurial def test_basic_install_editable_from_hg(script, tmpdir): """Test cloning and hg+file install from Mercurial.""" - pkg_path = _create_test_package(script, name='testpackage', vcs='hg') - url = 'hg+{}#egg=testpackage'.format(path_to_url(pkg_path)) - assert url.startswith('hg+file') - args = ['install', '-e', url] + pkg_path = _create_test_package(script, name="testpackage", vcs="hg") + url = "hg+{}#egg=testpackage".format(path_to_url(pkg_path)) + assert url.startswith("hg+file") + args = ["install", "-e", url] result = script.pip(*args) - result.assert_installed('testpackage', with_files=['.hg']) + result.assert_installed("testpackage", with_files=[".hg"]) @need_mercurial @@ -370,23 +402,27 @@ def test_vcs_url_final_slash_normalization(script, tmpdir): """ Test that presence or absence of final slash in VCS URL is normalized. """ - pkg_path = _create_test_package(script, name='testpackage', vcs='hg') + pkg_path = _create_test_package(script, name="testpackage", vcs="hg") args = [ - 'install', - '-e', 'hg+{url}/#egg=testpackage'.format(url=path_to_url(pkg_path))] + "install", + "-e", + "hg+{url}/#egg=testpackage".format(url=path_to_url(pkg_path)), + ] result = script.pip(*args) - result.assert_installed('testpackage', with_files=['.hg']) + result.assert_installed("testpackage", with_files=[".hg"]) @need_bzr def test_install_editable_from_bazaar(script, tmpdir): """Test checking out from Bazaar.""" - pkg_path = _create_test_package(script, name='testpackage', vcs='bazaar') + pkg_path = _create_test_package(script, name="testpackage", vcs="bazaar") args = [ - 'install', - '-e', 'bzr+{url}/#egg=testpackage'.format(url=path_to_url(pkg_path))] + "install", + "-e", + "bzr+{url}/#egg=testpackage".format(url=path_to_url(pkg_path)), + ] result = script.pip(*args) - result.assert_installed('testpackage', with_files=['.bzr']) + result.assert_installed("testpackage", with_files=[".bzr"]) @pytest.mark.network @@ -396,21 +432,21 @@ def test_vcs_url_urlquote_normalization(script, tmpdir): Test that urlquoted characters are normalized for repo URL comparison. """ script.pip( - 'install', '-e', - '{url}/#egg=django-wikiapp'.format( + "install", + "-e", + "{url}/#egg=django-wikiapp".format( url=local_checkout( - 'bzr+http://bazaar.launchpad.net/' - '%7Edjango-wikiapp/django-wikiapp' - '/release-0.1', + "bzr+http://bazaar.launchpad.net/" + "%7Edjango-wikiapp/django-wikiapp" + "/release-0.1", tmpdir, - )), + ) + ), ) @pytest.mark.parametrize("resolver", ["", "--use-feature=2020-resolver"]) -def test_basic_install_from_local_directory( - script, data, resolver, with_wheel -): +def test_basic_install_from_local_directory(script, data, resolver, with_wheel): """ Test installing from a local directory. """ @@ -420,45 +456,38 @@ def test_basic_install_from_local_directory( to_install = data.packages.joinpath("FSPkg") args.append(to_install) result = script.pip(*args) - fspkg_folder = script.site_packages / 'fspkg' - dist_info_folder = ( - script.site_packages / - 'FSPkg-0.1.dev0.dist-info' - ) + fspkg_folder = script.site_packages / "fspkg" + dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" result.did_create(fspkg_folder) result.did_create(dist_info_folder) -@pytest.mark.parametrize("test_type,editable", [ - ("rel_path", False), - ("rel_path", True), - ("rel_url", False), - ("rel_url", True), - ("embedded_rel_path", False), - ("embedded_rel_path", True), -]) +@pytest.mark.parametrize( + "test_type,editable", + [ + ("rel_path", False), + ("rel_path", True), + ("rel_url", False), + ("rel_url", True), + ("embedded_rel_path", False), + ("embedded_rel_path", True), + ], +) def test_basic_install_relative_directory( script, data, test_type, editable, with_wheel ): """ Test installing a requirement using a relative path. """ - dist_info_folder = ( - script.site_packages / - 'FSPkg-0.1.dev0.dist-info' - ) - egg_link_file = ( - script.site_packages / 'FSPkg.egg-link' - ) - package_folder = script.site_packages / 'fspkg' + dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" + egg_link_file = script.site_packages / "FSPkg.egg-link" + package_folder = script.site_packages / "fspkg" # Compute relative install path to FSPkg from scratch path. full_rel_path = Path( - os.path.relpath(data.packages.joinpath('FSPkg'), script.scratch_path) - ) - full_rel_url = ( - 'file:' + full_rel_path.replace(os.path.sep, '/') + '#egg=FSPkg' + os.path.relpath(data.packages.joinpath("FSPkg"), script.scratch_path) ) + full_rel_url = "file:" + full_rel_path.replace(os.path.sep, "/") + "#egg=FSPkg" embedded_rel_path = script.scratch_path.joinpath(full_rel_path) req_path = { @@ -469,14 +498,12 @@ def test_basic_install_relative_directory( # Install as either editable or not. if not editable: - result = script.pip('install', req_path, - cwd=script.scratch_path) + result = script.pip("install", req_path, cwd=script.scratch_path) result.did_create(dist_info_folder) result.did_create(package_folder) else: # Editable install. - result = script.pip('install', '-e' + req_path, - cwd=script.scratch_path) + result = script.pip("install", "-e" + req_path, cwd=script.scratch_path) result.did_create(egg_link_file) @@ -489,7 +516,7 @@ def test_install_quiet(script, data): # https://github.com/pypa/pip/issues/3418 # https://github.com/docker-library/python/issues/83 to_install = data.packages.joinpath("FSPkg") - result = script.pip('install', '-qqq', to_install) + result = script.pip("install", "-qqq", to_install) assert result.stdout == "" assert result.stderr == "" @@ -503,15 +530,15 @@ def test_hashed_install_success(script, data, tmpdir): scenes). """ - file_url = path_to_url( - (data.packages / 'simple-1.0.tar.gz').resolve()) + file_url = path_to_url((data.packages / "simple-1.0.tar.gz").resolve()) with requirements_file( - 'simple2==1.0 --hash=sha256:9336af72ca661e6336eb87bc7de3e8844d853e' - '3848c2b9bbd2e8bf01db88c2c7\n' - '{simple} --hash=sha256:393043e672415891885c9a2a0929b1af95fb866d6c' - 'a016b42d2e6ce53619b653'.format(simple=file_url), - tmpdir) as reqs_file: - script.pip_install_local('-r', reqs_file.resolve()) + "simple2==1.0 --hash=sha256:9336af72ca661e6336eb87bc7de3e8844d853e" + "3848c2b9bbd2e8bf01db88c2c7\n" + "{simple} --hash=sha256:393043e672415891885c9a2a0929b1af95fb866d6c" + "a016b42d2e6ce53619b653".format(simple=file_url), + tmpdir, + ) as reqs_file: + script.pip_install_local("-r", reqs_file.resolve()) def test_hashed_install_failure(script, tmpdir): @@ -522,19 +549,17 @@ def test_hashed_install_failure(script, tmpdir): kinds of hashes are in test_req.py. """ - with requirements_file('simple2==1.0 --hash=sha256:9336af72ca661e6336eb87b' - 'c7de3e8844d853e3848c2b9bbd2e8bf01db88c2c\n', - tmpdir) as reqs_file: - result = script.pip_install_local('-r', - reqs_file.resolve(), - expect_error=True) + with requirements_file( + "simple2==1.0 --hash=sha256:9336af72ca661e6336eb87b" + "c7de3e8844d853e3848c2b9bbd2e8bf01db88c2c\n", + tmpdir, + ) as reqs_file: + result = script.pip_install_local("-r", reqs_file.resolve(), expect_error=True) assert len(result.files_created) == 0 def assert_re_match(pattern, text): - assert re.search(pattern, text), ( - "Could not find {!r} in {!r}".format(pattern, text) - ) + assert re.search(pattern, text), "Could not find {!r} in {!r}".format(pattern, text) @pytest.mark.network @@ -549,37 +574,32 @@ def test_hashed_install_failure_later_flag(script, tmpdir): "packages/source/p/peep/peep-3.1.1.tar.gz\n", tmpdir, ) as reqs_file: - result = script.pip( - "install", "-r", reqs_file.resolve(), expect_error=True - ) + result = script.pip("install", "-r", reqs_file.resolve(), expect_error=True) assert_re_match( - r'Hashes are required in --require-hashes mode, but they are ' - r'missing .*\n' - r' https://files\.pythonhosted\.org/packages/source/p/peep/peep' - r'-3\.1\.1\.tar\.gz --hash=sha256:[0-9a-f]+\n' - r' blessings==1.0 --hash=sha256:[0-9a-f]+\n' - r'THESE PACKAGES DO NOT MATCH THE HASHES.*\n' - r' tracefront==0.1 .*:\n' - r' Expected sha256 somehash\n' - r' Got [0-9a-f]+', + r"Hashes are required in --require-hashes mode, but they are " + r"missing .*\n" + r" https://files\.pythonhosted\.org/packages/source/p/peep/peep" + r"-3\.1\.1\.tar\.gz --hash=sha256:[0-9a-f]+\n" + r" blessings==1.0 --hash=sha256:[0-9a-f]+\n" + r"THESE PACKAGES DO NOT MATCH THE HASHES.*\n" + r" tracefront==0.1 .*:\n" + r" Expected sha256 somehash\n" + r" Got [0-9a-f]+", result.stderr, ) def test_install_from_local_directory_with_symlinks_to_directories( - script, data, with_wheel + script, data, with_wheel ): """ Test installing from a local directory containing symlinks to directories. """ to_install = data.packages.joinpath("symlinks") - result = script.pip('install', to_install) - pkg_folder = script.site_packages / 'symlinks' - dist_info_folder = ( - script.site_packages / - 'symlinks-0.1.dev0.dist-info' - ) + result = script.pip("install", to_install) + pkg_folder = script.site_packages / "symlinks" + dist_info_folder = script.site_packages / "symlinks-0.1.dev0.dist-info" result.did_create(pkg_folder) result.did_create(dist_info_folder) @@ -591,10 +611,7 @@ def test_install_from_local_directory_with_socket_file( """ Test installing from a local directory containing a socket file. """ - dist_info_folder = ( - script.site_packages / - "FSPkg-0.1.dev0.dist-info" - ) + dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" package_folder = script.site_packages / "fspkg" to_copy = data.packages.joinpath("FSPkg") to_install = tmpdir.joinpath("src") @@ -614,18 +631,17 @@ def test_install_from_local_directory_with_no_setup_py(script, data): """ Test installing from a local directory with no 'setup.py'. """ - result = script.pip('install', data.root, expect_error=True) + result = script.pip("install", data.root, expect_error=True) assert not result.files_created assert "is not installable." in result.stderr assert "Neither 'setup.py' nor 'pyproject.toml' found." in result.stderr -def test_editable_install__local_dir_no_setup_py( - script, data, deprecated_python): +def test_editable_install__local_dir_no_setup_py(script, data, deprecated_python): """ Test installing in editable mode from a local directory with no setup.py. """ - result = script.pip('install', '-e', data.root, expect_error=True) + result = script.pip("install", "-e", data.root, expect_error=True) assert not result.files_created msg = result.stderr @@ -633,21 +649,22 @@ def test_editable_install__local_dir_no_setup_py( assert 'File "setup.py" not found. ' in msg else: assert msg.startswith('ERROR: File "setup.py" not found. ') - assert 'pyproject.toml' not in msg + assert "pyproject.toml" not in msg def test_editable_install__local_dir_no_setup_py_with_pyproject( - script, deprecated_python): + script, deprecated_python +): """ Test installing in editable mode from a local directory with no setup.py but that does have pyproject.toml. """ - local_dir = script.scratch_path.joinpath('temp') + local_dir = script.scratch_path.joinpath("temp") local_dir.mkdir() - pyproject_path = local_dir.joinpath('pyproject.toml') - pyproject_path.write_text('') + pyproject_path = local_dir.joinpath("pyproject.toml") + pyproject_path.write_text("") - result = script.pip('install', '-e', local_dir, expect_error=True) + result = script.pip("install", "-e", local_dir, expect_error=True) assert not result.files_created msg = result.stderr @@ -668,7 +685,7 @@ def test_install_argparse_shadowed(script): # bad. # XXX: Note, this test hits the outside-environment check, not the # in-stdlib check, because our tests run in virtualenvs... - result = script.pip('install', 'argparse>=1.4') + result = script.pip("install", "argparse>=1.4") assert "Not uninstalling argparse" in result.stdout @@ -677,8 +694,8 @@ def test_install_argparse_shadowed(script): def test_upgrade_argparse_shadowed(script): # If argparse is installed - even if shadowed for imported - we support # upgrading it and properly remove the older versions files. - script.pip('install', 'argparse==1.3') - result = script.pip('install', 'argparse>=1.4') + script.pip("install", "argparse==1.3") + result = script.pip("install", "argparse>=1.4") assert "Not uninstalling argparse" not in result.stdout @@ -691,12 +708,9 @@ def test_install_curdir(script, data, with_wheel): egg_info = join(run_from, "FSPkg.egg-info") if os.path.isdir(egg_info): rmtree(egg_info) - result = script.pip('install', curdir, cwd=run_from) - fspkg_folder = script.site_packages / 'fspkg' - dist_info_folder = ( - script.site_packages / - 'FSPkg-0.1.dev0.dist-info' - ) + result = script.pip("install", curdir, cwd=run_from) + fspkg_folder = script.site_packages / "fspkg" + dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" result.did_create(fspkg_folder) result.did_create(dist_info_folder) @@ -706,12 +720,9 @@ def test_install_pardir(script, data, with_wheel): Test installing parent directory ('..'). """ run_from = data.packages.joinpath("FSPkg", "fspkg") - result = script.pip('install', pardir, cwd=run_from) - fspkg_folder = script.site_packages / 'fspkg' - dist_info_folder = ( - script.site_packages / - 'FSPkg-0.1.dev0.dist-info' - ) + result = script.pip("install", pardir, cwd=run_from) + fspkg_folder = script.site_packages / "fspkg" + dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" result.did_create(fspkg_folder) result.did_create(dist_info_folder) @@ -723,9 +734,9 @@ def test_install_global_option(script): (In particular those that disable the actual install action) """ result = script.pip( - 'install', '--global-option=--version', "INITools==0.1", - expect_stderr=True) - assert 'INITools==0.1\n' in result.stdout + "install", "--global-option=--version", "INITools==0.1", expect_stderr=True + ) + assert "INITools==0.1\n" in result.stdout assert not result.files_created @@ -734,8 +745,8 @@ def test_install_with_hacked_egg_info(script, data): test installing a package which defines its own egg_info class """ run_from = data.packages.joinpath("HackedEggInfo") - result = script.pip('install', '.', cwd=run_from) - assert 'Successfully installed hackedegginfo-0.0.0\n' in result.stdout + result = script.pip("install", ".", cwd=run_from) + assert "Successfully installed hackedegginfo-0.0.0\n" in result.stdout @pytest.mark.network @@ -743,17 +754,19 @@ def test_install_using_install_option_and_editable(script, tmpdir): """ Test installing a tool using -e and --install-option """ - folder = 'script_folder' + folder = "script_folder" script.scratch_path.joinpath(folder).mkdir() - url = 'git+git://github.com/pypa/pip-test-package' + url = "git+git://github.com/pypa/pip-test-package" result = script.pip( - 'install', '-e', '{url}#egg=pip-test-package' - .format(url=local_checkout(url, tmpdir)), - '--install-option=--script-dir={folder}'.format(**locals()), - expect_stderr=True) + "install", + "-e", + "{url}#egg=pip-test-package".format(url=local_checkout(url, tmpdir)), + "--install-option=--script-dir={folder}".format(**locals()), + expect_stderr=True, + ) script_file = ( - script.venv / 'src' / 'pip-test-package' / - folder / 'pip-test-package' + script.exe + script.venv / "src" / "pip-test-package" / folder / "pip-test-package" + + script.exe ) result.did_create(script_file) @@ -766,12 +779,15 @@ def test_install_global_option_using_editable(script, tmpdir): """ Test using global distutils options, but in an editable installation """ - url = 'hg+http://bitbucket.org/runeh/anyjson' + url = "hg+http://bitbucket.org/runeh/anyjson" result = script.pip( - 'install', '--global-option=--version', '-e', - '{url}@0.2.5#egg=anyjson'.format(url=local_checkout(url, tmpdir)), - expect_stderr=True) - assert 'Successfully installed anyjson' in result.stdout + "install", + "--global-option=--version", + "-e", + "{url}@0.2.5#egg=anyjson".format(url=local_checkout(url, tmpdir)), + expect_stderr=True, + ) + assert "Successfully installed anyjson" in result.stdout @pytest.mark.network @@ -780,18 +796,17 @@ def test_install_package_with_same_name_in_curdir(script, with_wheel): Test installing a package with the same name of a local folder """ script.scratch_path.joinpath("mock==0.6").mkdir() - result = script.pip('install', 'mock==0.6') - dist_info_folder = ( - script.site_packages / - 'mock-0.6.0.dist-info' - ) + result = script.pip("install", "mock==0.6") + dist_info_folder = script.site_packages / "mock-0.6.0.dist-info" result.did_create(dist_info_folder) -mock100_setup_py = textwrap.dedent('''\ +mock100_setup_py = textwrap.dedent( + """\ from setuptools import setup setup(name='mock', - version='100.1')''') + version='100.1')""" +) def test_install_folder_using_dot_slash(script, with_wheel): @@ -799,13 +814,10 @@ def test_install_folder_using_dot_slash(script, with_wheel): Test installing a folder using pip install ./foldername """ script.scratch_path.joinpath("mock").mkdir() - pkg_path = script.scratch_path / 'mock' + pkg_path = script.scratch_path / "mock" pkg_path.joinpath("setup.py").write_text(mock100_setup_py) - result = script.pip('install', './mock') - dist_info_folder = ( - script.site_packages / - 'mock-100.1.dist-info' - ) + result = script.pip("install", "./mock") + dist_info_folder = script.site_packages / "mock-100.1.dist-info" result.did_create(dist_info_folder) @@ -814,13 +826,10 @@ def test_install_folder_using_slash_in_the_end(script, with_wheel): Test installing a folder using pip install foldername/ or foldername\ """ script.scratch_path.joinpath("mock").mkdir() - pkg_path = script.scratch_path / 'mock' + pkg_path = script.scratch_path / "mock" pkg_path.joinpath("setup.py").write_text(mock100_setup_py) - result = script.pip('install', 'mock' + os.path.sep) - dist_info_folder = ( - script.site_packages / - 'mock-100.1.dist-info' - ) + result = script.pip("install", "mock" + os.path.sep) + dist_info_folder = script.site_packages / "mock-100.1.dist-info" result.did_create(dist_info_folder) @@ -830,13 +839,10 @@ def test_install_folder_using_relative_path(script, with_wheel): """ script.scratch_path.joinpath("initools").mkdir() script.scratch_path.joinpath("initools", "mock").mkdir() - pkg_path = script.scratch_path / 'initools' / 'mock' + pkg_path = script.scratch_path / "initools" / "mock" pkg_path.joinpath("setup.py").write_text(mock100_setup_py) - result = script.pip('install', Path('initools') / 'mock') - dist_info_folder = ( - script.site_packages / - 'mock-100.1.dist-info'.format(**globals()) - ) + result = script.pip("install", Path("initools") / "mock") + dist_info_folder = script.site_packages / "mock-100.1.dist-info".format(**globals()) result.did_create(dist_info_folder) @@ -845,12 +851,9 @@ def test_install_package_which_contains_dev_in_name(script, with_wheel): """ Test installing package from PyPI which contains 'dev' in name """ - result = script.pip('install', 'django-devserver==0.0.4') - devserver_folder = script.site_packages / 'devserver' - dist_info_folder = ( - script.site_packages / - 'django_devserver-0.0.4.dist-info' - ) + result = script.pip("install", "django-devserver==0.0.4") + devserver_folder = script.site_packages / "devserver" + dist_info_folder = script.site_packages / "django_devserver-0.0.4.dist-info" result.did_create(devserver_folder) result.did_create(dist_info_folder) @@ -859,116 +862,121 @@ def test_install_package_with_target(script, with_wheel): """ Test installing a package using pip install --target """ - target_dir = script.scratch_path / 'target' - result = script.pip_install_local('-t', target_dir, "simple==1.0") - result.did_create(Path('scratch') / 'target' / 'simple') + target_dir = script.scratch_path / "target" + result = script.pip_install_local("-t", target_dir, "simple==1.0") + result.did_create(Path("scratch") / "target" / "simple") # Test repeated call without --upgrade, no files should have changed result = script.pip_install_local( - '-t', target_dir, "simple==1.0", expect_stderr=True, + "-t", + target_dir, + "simple==1.0", + expect_stderr=True, ) - result.did_not_update(Path('scratch') / 'target' / 'simple') + result.did_not_update(Path("scratch") / "target" / "simple") # Test upgrade call, check that new version is installed - result = script.pip_install_local('--upgrade', '-t', - target_dir, "simple==2.0") - result.did_update(Path('scratch') / 'target' / 'simple') - dist_info_folder = ( - Path('scratch') / 'target' / - 'simple-2.0.dist-info' - ) + result = script.pip_install_local("--upgrade", "-t", target_dir, "simple==2.0") + result.did_update(Path("scratch") / "target" / "simple") + dist_info_folder = Path("scratch") / "target" / "simple-2.0.dist-info" result.did_create(dist_info_folder) # Test install and upgrade of single-module package - result = script.pip_install_local('-t', target_dir, 'singlemodule==0.0.0') - singlemodule_py = Path('scratch') / 'target' / 'singlemodule.py' + result = script.pip_install_local("-t", target_dir, "singlemodule==0.0.0") + singlemodule_py = Path("scratch") / "target" / "singlemodule.py" result.did_create(singlemodule_py) - result = script.pip_install_local('-t', target_dir, 'singlemodule==0.0.1', - '--upgrade') + result = script.pip_install_local( + "-t", target_dir, "singlemodule==0.0.1", "--upgrade" + ) result.did_update(singlemodule_py) -@pytest.mark.parametrize("target_option", ['--target', '-t']) -def test_install_package_to_usersite_with_target_must_fail(script, - target_option): +@pytest.mark.parametrize("target_option", ["--target", "-t"]) +def test_install_package_to_usersite_with_target_must_fail(script, target_option): """ Test that installing package to usersite with target must raise error """ - target_dir = script.scratch_path / 'target' + target_dir = script.scratch_path / "target" result = script.pip_install_local( - '--user', target_option, target_dir, "simple==1.0", expect_error=True - ) - assert "Can not combine '--user' and '--target'" in result.stderr, ( - str(result) + "--user", target_option, target_dir, "simple==1.0", expect_error=True ) + assert "Can not combine '--user' and '--target'" in result.stderr, str(result) def test_install_nonlocal_compatible_wheel(script, data): - target_dir = script.scratch_path / 'target' + target_dir = script.scratch_path / "target" # Test install with --target result = script.pip( - 'install', - '-t', target_dir, - '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--python', '3', - '--platform', 'fakeplat', - '--abi', 'fakeabi', - 'simplewheel', + "install", + "-t", + target_dir, + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--python", + "3", + "--platform", + "fakeplat", + "--abi", + "fakeabi", + "simplewheel", ) assert result.returncode == SUCCESS - distinfo = Path('scratch') / 'target' / 'simplewheel-2.0-1.dist-info' + distinfo = Path("scratch") / "target" / "simplewheel-2.0-1.dist-info" result.did_create(distinfo) # Test install without --target result = script.pip( - 'install', - '--no-index', '--find-links', data.find_links, - '--only-binary=:all:', - '--python', '3', - '--platform', 'fakeplat', - '--abi', 'fakeabi', - 'simplewheel', - expect_error=True + "install", + "--no-index", + "--find-links", + data.find_links, + "--only-binary=:all:", + "--python", + "3", + "--platform", + "fakeplat", + "--abi", + "fakeabi", + "simplewheel", + expect_error=True, ) assert result.returncode == ERROR -def test_install_nonlocal_compatible_wheel_path( - script, - data, - use_new_resolver -): - target_dir = script.scratch_path / 'target' +def test_install_nonlocal_compatible_wheel_path(script, data, use_new_resolver): + target_dir = script.scratch_path / "target" # Test a full path requirement result = script.pip( - 'install', - '-t', target_dir, - '--no-index', - '--only-binary=:all:', - Path(data.packages) / 'simplewheel-2.0-py3-fakeabi-fakeplat.whl', - expect_error=use_new_resolver + "install", + "-t", + target_dir, + "--no-index", + "--only-binary=:all:", + Path(data.packages) / "simplewheel-2.0-py3-fakeabi-fakeplat.whl", + expect_error=use_new_resolver, ) if use_new_resolver: assert result.returncode == ERROR else: assert result.returncode == SUCCESS - distinfo = Path('scratch') / 'target' / 'simplewheel-2.0.dist-info' + distinfo = Path("scratch") / "target" / "simplewheel-2.0.dist-info" result.did_create(distinfo) # Test a full path requirement (without --target) result = script.pip( - 'install', - '--no-index', - '--only-binary=:all:', - Path(data.packages) / 'simplewheel-2.0-py3-fakeabi-fakeplat.whl', - expect_error=True + "install", + "--no-index", + "--only-binary=:all:", + Path(data.packages) / "simplewheel-2.0-py3-fakeabi-fakeplat.whl", + expect_error=True, ) assert result.returncode == ERROR @@ -978,10 +986,12 @@ def test_install_with_target_and_scripts_no_warning(script, with_wheel): Test that installing with --target does not trigger the "script not in PATH" warning (issue #5201) """ - target_dir = script.scratch_path / 'target' - pkga_path = script.scratch_path / 'pkga' + target_dir = script.scratch_path / "target" + pkga_path = script.scratch_path / "pkga" pkga_path.mkdir() - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', version='0.1', @@ -990,11 +1000,17 @@ def test_install_with_target_and_scripts_no_warning(script, with_wheel): 'console_scripts': ['pkga=pkga:main'] } ) - """)) - pkga_path.joinpath("pkga.py").write_text(textwrap.dedent(""" + """ + ) + ) + pkga_path.joinpath("pkga.py").write_text( + textwrap.dedent( + """ def main(): pass - """)) - result = script.pip('install', '--target', target_dir, pkga_path) + """ + ) + ) + result = script.pip("install", "--target", target_dir, pkga_path) # This assertion isn't actually needed, if we get the script warning # the script.pip() call will fail with "stderr not expected". But we # leave the assertion to make the intention of the code clearer. @@ -1005,21 +1021,23 @@ def test_install_package_with_root(script, data, with_wheel): """ Test installing a package using pip install --root """ - root_dir = script.scratch_path / 'root' + root_dir = script.scratch_path / "root" result = script.pip( - 'install', '--root', root_dir, '-f', data.find_links, '--no-index', - 'simple==1.0', + "install", + "--root", + root_dir, + "-f", + data.find_links, + "--no-index", + "simple==1.0", ) normal_install_path = ( - script.base_path / script.site_packages / - 'simple-1.0.dist-info' + script.base_path / script.site_packages / "simple-1.0.dist-info" ) # use distutils to change the root exactly how the --root option does it from distutils.util import change_root - root_path = change_root( - os.path.join(script.scratch, 'root'), - normal_install_path - ) + + root_path = change_root(os.path.join(script.scratch, "root"), normal_install_path) result.did_create(root_path) # Should show find-links location in output @@ -1031,36 +1049,49 @@ def test_install_package_with_prefix(script, data): """ Test installing a package using pip install --prefix """ - prefix_path = script.scratch_path / 'prefix' + prefix_path = script.scratch_path / "prefix" result = script.pip( - 'install', '--prefix', prefix_path, '-f', data.find_links, - '--no-binary', 'simple', '--no-index', 'simple==1.0', - ) - - rel_prefix_path = script.scratch / 'prefix' + "install", + "--prefix", + prefix_path, + "-f", + data.find_links, + "--no-binary", + "simple", + "--no-index", + "simple==1.0", + ) + + rel_prefix_path = script.scratch / "prefix" install_path = ( - distutils.sysconfig.get_python_lib(prefix=rel_prefix_path) / + distutils.sysconfig.get_python_lib(prefix=rel_prefix_path) + / # we still test for egg-info because no-binary implies setup.py install - 'simple-1.0-py{}.egg-info'.format(pyversion) + "simple-1.0-py{}.egg-info".format(pyversion) ) result.did_create(install_path) def test_install_editable_with_prefix(script): # make a dummy project - pkga_path = script.scratch_path / 'pkga' + pkga_path = script.scratch_path / "pkga" pkga_path.mkdir() - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', version='0.1') - """)) + """ + ) + ) if hasattr(sys, "pypy_version_info"): site_packages = os.path.join( - 'prefix', 'lib', 'python{}'.format(pyversion), 'site-packages') + "prefix", "lib", "python{}".format(pyversion), "site-packages" + ) else: - site_packages = distutils.sysconfig.get_python_lib(prefix='prefix') + site_packages = distutils.sysconfig.get_python_lib(prefix="prefix") # make sure target path is in PYTHONPATH pythonpath = script.scratch_path / site_packages @@ -1068,12 +1099,11 @@ def test_install_editable_with_prefix(script): script.environ["PYTHONPATH"] = pythonpath # install pkga package into the absolute prefix directory - prefix_path = script.scratch_path / 'prefix' - result = script.pip( - 'install', '--editable', pkga_path, '--prefix', prefix_path) + prefix_path = script.scratch_path / "prefix" + result = script.pip("install", "--editable", pkga_path, "--prefix", prefix_path) # assert pkga is installed at correct location - install_path = script.scratch / site_packages / 'pkga.egg-link' + install_path = script.scratch / site_packages / "pkga.egg-link" result.did_create(install_path) @@ -1081,15 +1111,20 @@ def test_install_package_conflict_prefix_and_user(script, data): """ Test installing a package using pip install --prefix --user errors out """ - prefix_path = script.scratch_path / 'prefix' + prefix_path = script.scratch_path / "prefix" result = script.pip( - 'install', '-f', data.find_links, '--no-index', '--user', - '--prefix', prefix_path, 'simple==1.0', - expect_error=True, quiet=True, - ) - assert ( - "Can not combine '--user' and '--prefix'" in result.stderr + "install", + "-f", + data.find_links, + "--no-index", + "--user", + "--prefix", + prefix_path, + "simple==1.0", + expect_error=True, + quiet=True, ) + assert "Can not combine '--user' and '--prefix'" in result.stderr def test_install_package_that_emits_unicode(script, data): @@ -1100,25 +1135,29 @@ def test_install_package_that_emits_unicode(script, data): """ to_install = data.packages.joinpath("BrokenEmitsUTF8") result = script.pip( - 'install', to_install, expect_error=True, expect_temp=True, quiet=True, + "install", + to_install, + expect_error=True, + expect_temp=True, + quiet=True, ) assert ( - 'FakeError: this package designed to fail on install' in result.stderr - ), 'stderr: {}'.format(result.stderr) - assert 'UnicodeDecodeError' not in result.stderr - assert 'UnicodeDecodeError' not in result.stdout + "FakeError: this package designed to fail on install" in result.stderr + ), "stderr: {}".format(result.stderr) + assert "UnicodeDecodeError" not in result.stderr + assert "UnicodeDecodeError" not in result.stdout def test_install_package_with_utf8_setup(script, data): """Install a package with a setup.py that declares a utf-8 encoding.""" to_install = data.packages.joinpath("SetupPyUTF8") - script.pip('install', to_install) + script.pip("install", to_install) def test_install_package_with_latin1_setup(script, data): """Install a package with a setup.py that declares a latin-1 encoding.""" to_install = data.packages.joinpath("SetupPyLatin1") - script.pip('install', to_install) + script.pip("install", to_install) def test_url_req_case_mismatch_no_index(script, data, with_wheel): @@ -1130,17 +1169,15 @@ def test_url_req_case_mismatch_no_index(script, data, with_wheel): tests/data/packages contains Upper-1.0.tar.gz and Upper-2.0.tar.gz 'requiresupper' has install_requires = ['upper'] """ - Upper = '/'.join((data.find_links, 'Upper-1.0.tar.gz')) + Upper = "/".join((data.find_links, "Upper-1.0.tar.gz")) result = script.pip( - 'install', '--no-index', '-f', data.find_links, Upper, 'requiresupper' + "install", "--no-index", "-f", data.find_links, Upper, "requiresupper" ) # only Upper-1.0.tar.gz should get installed. - dist_info_folder = script.site_packages / \ - 'Upper-1.0.dist-info' + dist_info_folder = script.site_packages / "Upper-1.0.dist-info" result.did_create(dist_info_folder) - dist_info_folder = script.site_packages / \ - 'Upper-2.0.dist-info' + dist_info_folder = script.site_packages / "Upper-2.0.dist-info" result.did_not_create(dist_info_folder) @@ -1159,17 +1196,15 @@ def test_url_req_case_mismatch_file_index(script, data, with_wheel): set of packages as it requires a prepared index.html file and subdirectory-per-package structure. """ - Dinner = '/'.join((data.find_links3, 'dinner', 'Dinner-1.0.tar.gz')) + Dinner = "/".join((data.find_links3, "dinner", "Dinner-1.0.tar.gz")) result = script.pip( - 'install', '--index-url', data.find_links3, Dinner, 'requiredinner' + "install", "--index-url", data.find_links3, Dinner, "requiredinner" ) # only Upper-1.0.tar.gz should get installed. - dist_info_folder = script.site_packages / \ - 'Dinner-1.0.dist-info' + dist_info_folder = script.site_packages / "Dinner-1.0.dist-info" result.did_create(dist_info_folder) - dist_info_folder = script.site_packages / \ - 'Dinner-2.0.dist-info' + dist_info_folder = script.site_packages / "Dinner-2.0.dist-info" result.did_not_create(dist_info_folder) @@ -1180,15 +1215,17 @@ def test_url_incorrect_case_no_index(script, data, with_wheel): rather than in a requirements file. """ result = script.pip( - 'install', '--no-index', '-f', data.find_links, "upper", + "install", + "--no-index", + "-f", + data.find_links, + "upper", ) # only Upper-2.0.tar.gz should get installed. - dist_info_folder = script.site_packages / \ - 'Upper-1.0.dist-info' + dist_info_folder = script.site_packages / "Upper-1.0.dist-info" result.did_not_create(dist_info_folder) - dist_info_folder = script.site_packages / \ - 'Upper-2.0.dist-info' + dist_info_folder = script.site_packages / "Upper-2.0.dist-info" result.did_create(dist_info_folder) @@ -1199,16 +1236,17 @@ def test_url_incorrect_case_file_index(script, data, with_wheel): rather than in a requirements file. """ result = script.pip( - 'install', '--index-url', data.find_links3, "dinner", + "install", + "--index-url", + data.find_links3, + "dinner", expect_stderr=True, ) # only Upper-2.0.tar.gz should get installed. - dist_info_folder = script.site_packages / \ - 'Dinner-1.0.dist-info' + dist_info_folder = script.site_packages / "Dinner-1.0.dist-info" result.did_not_create(dist_info_folder) - dist_info_folder = script.site_packages / \ - 'Dinner-2.0.dist-info' + dist_info_folder = script.site_packages / "Dinner-2.0.dist-info" result.did_create(dist_info_folder) # Should show index-url location in output @@ -1260,31 +1298,39 @@ def test_no_compiles_pyc(script): def test_install_upgrade_editable_depending_on_other_editable(script): script.scratch_path.joinpath("pkga").mkdir() - pkga_path = script.scratch_path / 'pkga' - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path = script.scratch_path / "pkga" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', version='0.1') - """)) - script.pip('install', '--editable', pkga_path) - result = script.pip('list', '--format=freeze') + """ + ) + ) + script.pip("install", "--editable", pkga_path) + result = script.pip("list", "--format=freeze") assert "pkga==0.1" in result.stdout script.scratch_path.joinpath("pkgb").mkdir() - pkgb_path = script.scratch_path / 'pkgb' - pkgb_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkgb_path = script.scratch_path / "pkgb" + pkgb_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkgb', version='0.1', install_requires=['pkga']) - """)) - script.pip('install', '--upgrade', '--editable', pkgb_path, '--no-index') - result = script.pip('list', '--format=freeze') + """ + ) + ) + script.pip("install", "--upgrade", "--editable", pkgb_path, "--no-index") + result = script.pip("list", "--format=freeze") assert "pkgb==0.1" in result.stdout def test_install_subprocess_output_handling(script, data): - args = ['install', data.src.joinpath('chattymodule')] + args = ["install", data.src.joinpath("chattymodule")] # Regular install should not show output from the chatty setup.py result = script.pip(*args) @@ -1300,47 +1346,50 @@ def test_install_subprocess_output_handling(script, data): # If the install fails, then we *should* show the output... but only once, # even if --verbose is given. - result = script.pip(*(args + ["--global-option=--fail"]), - expect_error=True) + result = script.pip(*(args + ["--global-option=--fail"]), expect_error=True) assert 1 == result.stderr.count("I DIE, I DIE") - result = script.pip(*(args + ["--global-option=--fail", "--verbose"]), - expect_error=True) + result = script.pip( + *(args + ["--global-option=--fail", "--verbose"]), expect_error=True + ) assert 1 == result.stderr.count("I DIE, I DIE") def test_install_log(script, data, tmpdir): # test that verbose logs go to "--log" file f = tmpdir.joinpath("log.txt") - args = ['--log={f}'.format(**locals()), - 'install', data.src.joinpath('chattymodule')] + args = [ + "--log={f}".format(**locals()), + "install", + data.src.joinpath("chattymodule"), + ] result = script.pip(*args) assert 0 == result.stdout.count("HELLO FROM CHATTYMODULE") - with open(f, 'r') as fp: + with open(f, "r") as fp: # one from egg_info, one from install assert 2 == fp.read().count("HELLO FROM CHATTYMODULE") def test_install_topological_sort(script, data): - args = ['install', 'TopoRequires4', '--no-index', '-f', data.packages] + args = ["install", "TopoRequires4", "--no-index", "-f", data.packages] res = str(script.pip(*args)) - order1 = 'TopoRequires, TopoRequires2, TopoRequires3, TopoRequires4' - order2 = 'TopoRequires, TopoRequires3, TopoRequires2, TopoRequires4' + order1 = "TopoRequires, TopoRequires2, TopoRequires3, TopoRequires4" + order2 = "TopoRequires, TopoRequires3, TopoRequires2, TopoRequires4" assert order1 in res or order2 in res, res def test_install_wheel_broken(script, with_wheel): - res = script.pip_install_local('wheelbroken', expect_stderr=True) + res = script.pip_install_local("wheelbroken", expect_stderr=True) assert "Successfully installed wheelbroken-0.1" in str(res), str(res) def test_cleanup_after_failed_wheel(script, with_wheel): - res = script.pip_install_local('wheelbrokenafter', expect_stderr=True) + res = script.pip_install_local("wheelbrokenafter", expect_stderr=True) # One of the effects of not cleaning up is broken scripts: script_py = script.bin_path / "script.py" assert script_py.exists(), script_py - shebang = open(script_py, 'r').readline().strip() - assert shebang != '#!python', shebang + shebang = open(script_py, "r").readline().strip() + assert shebang != "#!python", shebang # OK, assert that we *said* we were cleaning up: # /!\ if in need to change this, also change test_pep517_no_legacy_cleanup assert "Running setup.py clean for wheelbrokenafter" in str(res), str(res) @@ -1348,20 +1397,26 @@ def test_cleanup_after_failed_wheel(script, with_wheel): def test_install_builds_wheels(script, data, with_wheel): # We need to use a subprocess to get the right value on Windows. - res = script.run('python', '-c', ( - 'from pip._internal.utils import appdirs; ' - 'print(appdirs.user_cache_dir("pip"))' - )) - wheels_cache = os.path.join(res.stdout.rstrip('\n'), 'wheels') + res = script.run( + "python", + "-c", + ( + "from pip._internal.utils import appdirs; " + 'print(appdirs.user_cache_dir("pip"))' + ), + ) + wheels_cache = os.path.join(res.stdout.rstrip("\n"), "wheels") # NB This incidentally tests a local tree + tarball inputs # see test_install_editable_from_git_autobuild_wheel for editable # vcs coverage. - to_install = data.packages.joinpath('requires_wheelbroken_upper') + to_install = data.packages.joinpath("requires_wheelbroken_upper") res = script.pip( - 'install', '--no-index', '-f', data.find_links, - to_install, expect_stderr=True) - expected = ("Successfully installed requires-wheelbroken-upper-0" - " upper-2.0 wheelbroken-0.1") + "install", "--no-index", "-f", data.find_links, to_install, expect_stderr=True + ) + expected = ( + "Successfully installed requires-wheelbroken-upper-0" + " upper-2.0 wheelbroken-0.1" + ) # Must have installed it all assert expected in str(res), str(res) wheels = [] @@ -1388,12 +1443,20 @@ def test_install_builds_wheels(script, data, with_wheel): def test_install_no_binary_disables_building_wheels(script, data, with_wheel): - to_install = data.packages.joinpath('requires_wheelbroken_upper') + to_install = data.packages.joinpath("requires_wheelbroken_upper") res = script.pip( - 'install', '--no-index', '--no-binary=upper', '-f', data.find_links, - to_install, expect_stderr=True) - expected = ("Successfully installed requires-wheelbroken-upper-0" - " upper-2.0 wheelbroken-0.1") + "install", + "--no-index", + "--no-binary=upper", + "-f", + data.find_links, + to_install, + expect_stderr=True, + ) + expected = ( + "Successfully installed requires-wheelbroken-upper-0" + " upper-2.0 wheelbroken-0.1" + ) # Must have installed it all assert expected in str(res), str(res) # and built wheels for wheelbroken only @@ -1412,11 +1475,9 @@ def test_install_no_binary_disables_building_wheels(script, data, with_wheel): @pytest.mark.network @windows_workaround_7667 def test_install_no_binary_builds_pep_517_wheel(script, data, with_wheel): - to_install = data.packages.joinpath('pep517_setup_and_pyproject') - res = script.pip( - 'install', '--no-binary=:all:', '-f', data.find_links, to_install - ) - expected = ("Successfully installed pep517-setup-and-pyproject") + to_install = data.packages.joinpath("pep517_setup_and_pyproject") + res = script.pip("install", "--no-binary=:all:", "-f", data.find_links, to_install) + expected = "Successfully installed pep517-setup-and-pyproject" # Must have installed the package assert expected in str(res), str(res) @@ -1426,13 +1487,10 @@ def test_install_no_binary_builds_pep_517_wheel(script, data, with_wheel): @pytest.mark.network @windows_workaround_7667 -def test_install_no_binary_uses_local_backend( - script, data, with_wheel, tmpdir): - to_install = data.packages.joinpath('pep517_wrapper_buildsys') - script.environ['PIP_TEST_MARKER_FILE'] = marker = str(tmpdir / 'marker') - res = script.pip( - 'install', '--no-binary=:all:', '-f', data.find_links, to_install - ) +def test_install_no_binary_uses_local_backend(script, data, with_wheel, tmpdir): + to_install = data.packages.joinpath("pep517_wrapper_buildsys") + script.environ["PIP_TEST_MARKER_FILE"] = marker = str(tmpdir / "marker") + res = script.pip("install", "--no-binary=:all:", "-f", data.find_links, to_install) expected = "Successfully installed pep517-wrapper-buildsys" # Must have installed the package assert expected in str(res), str(res) @@ -1442,13 +1500,17 @@ def test_install_no_binary_uses_local_backend( def test_install_no_binary_disables_cached_wheels(script, data, with_wheel): # Seed the cache - script.pip( - 'install', '--no-index', '-f', data.find_links, - 'upper') - script.pip('uninstall', 'upper', '-y') + script.pip("install", "--no-index", "-f", data.find_links, "upper") + script.pip("uninstall", "upper", "-y") res = script.pip( - 'install', '--no-index', '--no-binary=:all:', '-f', data.find_links, - 'upper', expect_stderr=True) + "install", + "--no-index", + "--no-binary=:all:", + "-f", + data.find_links, + "upper", + expect_stderr=True, + ) assert "Successfully installed upper-2.0" in str(res), str(res) # No wheel building for upper, which was blacklisted assert "Building wheel for upper" not in str(res), str(res) @@ -1458,20 +1520,27 @@ def test_install_no_binary_disables_cached_wheels(script, data, with_wheel): def test_install_editable_with_wrong_egg_name(script, use_new_resolver): script.scratch_path.joinpath("pkga").mkdir() - pkga_path = script.scratch_path / 'pkga' - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path = script.scratch_path / "pkga" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', version='0.1') - """)) + """ + ) + ) result = script.pip( - 'install', '--editable', - 'file://{pkga_path}#egg=pkgb'.format(**locals()), + "install", + "--editable", + "file://{pkga_path}#egg=pkgb".format(**locals()), expect_error=use_new_resolver, ) - assert ("Generating metadata for package pkgb produced metadata " - "for project name pkga. Fix your #egg=pkgb " - "fragments.") in result.stderr + assert ( + "Generating metadata for package pkgb produced metadata " + "for project name pkga. Fix your #egg=pkgb " + "fragments." + ) in result.stderr if use_new_resolver: assert "has different name in metadata" in result.stderr, str(result) else: @@ -1483,7 +1552,7 @@ def test_install_tar_xz(script, data): import lzma # noqa except ImportError: pytest.skip("No lzma support") - res = script.pip('install', data.packages / 'singlemodule-0.0.1.tar.xz') + res = script.pip("install", data.packages / "singlemodule-0.0.1.tar.xz") assert "Successfully installed singlemodule-0.0.1" in res.stdout, res @@ -1492,7 +1561,7 @@ def test_install_tar_lzma(script, data): import lzma # noqa except ImportError: pytest.skip("No lzma support") - res = script.pip('install', data.packages / 'singlemodule-0.0.1.tar.lzma') + res = script.pip("install", data.packages / "singlemodule-0.0.1.tar.lzma") assert "Successfully installed singlemodule-0.0.1" in res.stdout, res @@ -1500,7 +1569,7 @@ def test_double_install(script): """ Test double install passing with two same version requirements """ - result = script.pip('install', 'pip', 'pip') + result = script.pip("install", "pip", "pip") msg = "Double requirement given: pip (already in pip, name='pip')" assert msg not in result.stderr @@ -1510,92 +1579,114 @@ def test_double_install_fail(script, use_new_resolver): Test double install failing with two different version requirements """ result = script.pip( - 'install', - 'pip==7.*', - 'pip==7.1.2', + "install", + "pip==7.*", + "pip==7.1.2", # The new resolver is perfectly capable of handling this - expect_error=(not use_new_resolver) + expect_error=(not use_new_resolver), ) if not use_new_resolver: - msg = ("Double requirement given: pip==7.1.2 (already in pip==7.*, " - "name='pip')") + msg = ( + "Double requirement given: pip==7.1.2 (already in pip==7.*, " "name='pip')" + ) assert msg in result.stderr def _get_expected_error_text(): - return ( - "Package 'pkga' requires a different Python: {} not in '<1.0'" - ).format('.'.join(map(str, sys.version_info[:3]))) + return ("Package 'pkga' requires a different Python: {} not in '<1.0'").format( + ".".join(map(str, sys.version_info[:3])) + ) def test_install_incompatible_python_requires(script): script.scratch_path.joinpath("pkga").mkdir() - pkga_path = script.scratch_path / 'pkga' - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path = script.scratch_path / "pkga" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', python_requires='<1.0', version='0.1') - """)) - result = script.pip('install', pkga_path, expect_error=True) + """ + ) + ) + result = script.pip("install", pkga_path, expect_error=True) assert _get_expected_error_text() in result.stderr, str(result) def test_install_incompatible_python_requires_editable(script): script.scratch_path.joinpath("pkga").mkdir() - pkga_path = script.scratch_path / 'pkga' - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path = script.scratch_path / "pkga" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', python_requires='<1.0', version='0.1') - """)) + """ + ) + ) result = script.pip( - 'install', - '--editable={pkga_path}'.format(**locals()), - expect_error=True) + "install", "--editable={pkga_path}".format(**locals()), expect_error=True + ) assert _get_expected_error_text() in result.stderr, str(result) def test_install_incompatible_python_requires_wheel(script, with_wheel): script.scratch_path.joinpath("pkga").mkdir() - pkga_path = script.scratch_path / 'pkga' - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path = script.scratch_path / "pkga" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', python_requires='<1.0', version='0.1') - """)) + """ + ) + ) script.run( - 'python', 'setup.py', 'bdist_wheel', '--universal', - cwd=pkga_path, allow_stderr_warning=PY2, + "python", + "setup.py", + "bdist_wheel", + "--universal", + cwd=pkga_path, + allow_stderr_warning=PY2, + ) + result = script.pip( + "install", "./pkga/dist/pkga-0.1-py2.py3-none-any.whl", expect_error=True ) - result = script.pip('install', './pkga/dist/pkga-0.1-py2.py3-none-any.whl', - expect_error=True) assert _get_expected_error_text() in result.stderr, str(result) def test_install_compatible_python_requires(script): script.scratch_path.joinpath("pkga").mkdir() - pkga_path = script.scratch_path / 'pkga' - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path = script.scratch_path / "pkga" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', python_requires='>1.0', version='0.1') - """)) - res = script.pip('install', pkga_path) + """ + ) + ) + res = script.pip("install", pkga_path) assert "Successfully installed pkga-0.1" in res.stdout, res @pytest.mark.network def test_install_pep508_with_url(script): res = script.pip( - 'install', '--no-index', - 'packaging@https://files.pythonhosted.org/packages/2f/2b/' - 'c681de3e1dbcd469537aefb15186b800209aa1f299d933d23b48d85c9d56/' - 'packaging-15.3-py2.py3-none-any.whl#sha256=' - 'ce1a869fe039fbf7e217df36c4653d1dbe657778b2d41709593a0003584405f4' + "install", + "--no-index", + "packaging@https://files.pythonhosted.org/packages/2f/2b/" + "c681de3e1dbcd469537aefb15186b800209aa1f299d933d23b48d85c9d56/" + "packaging-15.3-py2.py3-none-any.whl#sha256=" + "ce1a869fe039fbf7e217df36c4653d1dbe657778b2d41709593a0003584405f4", ) assert "Successfully installed packaging-15.3" in str(res), str(res) @@ -1603,26 +1694,28 @@ def test_install_pep508_with_url(script): @pytest.mark.network def test_install_pep508_with_url_in_install_requires(script): pkga_path = create_test_package_with_setup( - script, name='pkga', version='1.0', + script, + name="pkga", + version="1.0", install_requires=[ - 'packaging@https://files.pythonhosted.org/packages/2f/2b/' - 'c681de3e1dbcd469537aefb15186b800209aa1f299d933d23b48d85c9d56/' - 'packaging-15.3-py2.py3-none-any.whl#sha256=' - 'ce1a869fe039fbf7e217df36c4653d1dbe657778b2d41709593a0003584405f4' + "packaging@https://files.pythonhosted.org/packages/2f/2b/" + "c681de3e1dbcd469537aefb15186b800209aa1f299d933d23b48d85c9d56/" + "packaging-15.3-py2.py3-none-any.whl#sha256=" + "ce1a869fe039fbf7e217df36c4653d1dbe657778b2d41709593a0003584405f4" ], ) - res = script.pip('install', pkga_path) + res = script.pip("install", pkga_path) assert "Successfully installed packaging-15.3" in str(res), str(res) @pytest.mark.network -@pytest.mark.parametrize('index', (PyPI.simple_url, TestPyPI.simple_url)) +@pytest.mark.parametrize("index", (PyPI.simple_url, TestPyPI.simple_url)) def test_install_from_test_pypi_with_ext_url_dep_is_blocked(script, index): res = script.pip( - 'install', - '--index-url', + "install", + "--index-url", index, - 'pep-508-url-deps', + "pep-508-url-deps", expect_error=True, ) error_message = ( @@ -1639,17 +1732,14 @@ def test_install_from_test_pypi_with_ext_url_dep_is_blocked(script, index): def test_installing_scripts_outside_path_prints_warning(script): - result = script.pip_install_local( - "--prefix", script.scratch_path, "script_wheel1" - ) + result = script.pip_install_local("--prefix", script.scratch_path, "script_wheel1") assert "Successfully installed script-wheel1" in result.stdout, str(result) assert "--no-warn-script-location" in result.stderr def test_installing_scripts_outside_path_can_suppress_warning(script): result = script.pip_install_local( - "--prefix", script.scratch_path, "--no-warn-script-location", - "script_wheel1" + "--prefix", script.scratch_path, "--no-warn-script-location", "script_wheel1" ) assert "Successfully installed script-wheel1" in result.stdout, str(result) assert "--no-warn-script-location" not in result.stderr @@ -1667,18 +1757,16 @@ def test_installed_files_recorded_in_deterministic_order(script, data): order, to make installs reproducible. """ to_install = data.packages.joinpath("FSPkg") - result = script.pip('install', to_install) - fspkg_folder = script.site_packages / 'fspkg' - egg_info = 'FSPkg-0.1.dev0-py{pyversion}.egg-info'.format(**globals()) - installed_files_path = ( - script.site_packages / egg_info / 'installed-files.txt' - ) + result = script.pip("install", to_install) + fspkg_folder = script.site_packages / "fspkg" + egg_info = "FSPkg-0.1.dev0-py{pyversion}.egg-info".format(**globals()) + installed_files_path = script.site_packages / egg_info / "installed-files.txt" result.did_create(fspkg_folder) result.did_create(installed_files_path) installed_files_path = result.files_created[installed_files_path].full installed_files_lines = [ - p for p in Path(installed_files_path).read_text().split('\n') if p + p for p in Path(installed_files_path).read_text().split("\n") if p ] assert installed_files_lines == sorted(installed_files_lines) @@ -1686,20 +1774,26 @@ def test_installed_files_recorded_in_deterministic_order(script, data): def test_install_conflict_results_in_warning(script, data): pkgA_path = create_test_package_with_setup( script, - name='pkgA', version='1.0', install_requires=['pkgb == 1.0'], + name="pkgA", + version="1.0", + install_requires=["pkgb == 1.0"], ) pkgB_path = create_test_package_with_setup( script, - name='pkgB', version='2.0', + name="pkgB", + version="2.0", ) # Install pkgA without its dependency - result1 = script.pip('install', '--no-index', pkgA_path, '--no-deps') + result1 = script.pip("install", "--no-index", pkgA_path, "--no-deps") assert "Successfully installed pkgA-1.0" in result1.stdout, str(result1) # Then install an incorrect version of the dependency result2 = script.pip( - 'install', '--no-index', pkgB_path, allow_stderr_error=True, + "install", + "--no-index", + pkgB_path, + allow_stderr_error=True, ) assert "pkga 1.0 requires pkgb==1.0" in result2.stderr, str(result2) assert "Successfully installed pkgB-2.0" in result2.stdout, str(result2) @@ -1708,36 +1802,43 @@ def test_install_conflict_results_in_warning(script, data): def test_install_conflict_warning_can_be_suppressed(script, data): pkgA_path = create_test_package_with_setup( script, - name='pkgA', version='1.0', install_requires=['pkgb == 1.0'], + name="pkgA", + version="1.0", + install_requires=["pkgb == 1.0"], ) pkgB_path = create_test_package_with_setup( script, - name='pkgB', version='2.0', + name="pkgB", + version="2.0", ) # Install pkgA without its dependency - result1 = script.pip('install', '--no-index', pkgA_path, '--no-deps') + result1 = script.pip("install", "--no-index", pkgA_path, "--no-deps") assert "Successfully installed pkgA-1.0" in result1.stdout, str(result1) # Then install an incorrect version of the dependency; suppressing warning - result2 = script.pip( - 'install', '--no-index', pkgB_path, '--no-warn-conflicts' - ) + result2 = script.pip("install", "--no-index", pkgB_path, "--no-warn-conflicts") assert "Successfully installed pkgB-2.0" in result2.stdout, str(result2) def test_target_install_ignores_distutils_config_install_prefix(script): - prefix = script.scratch_path / 'prefix' - distutils_config = Path(os.path.expanduser('~'), - 'pydistutils.cfg' if sys.platform == 'win32' - else '.pydistutils.cfg') - distutils_config.write_text(textwrap.dedent( - ''' + prefix = script.scratch_path / "prefix" + distutils_config = Path( + os.path.expanduser("~"), + "pydistutils.cfg" if sys.platform == "win32" else ".pydistutils.cfg", + ) + distutils_config.write_text( + textwrap.dedent( + """ [install] prefix={prefix} - '''.format(**locals()))) - target = script.scratch_path / 'target' - result = script.pip_install_local('simplewheel', '-t', target) + """.format( + **locals() + ) + ) + ) + target = script.scratch_path / "target" + result = script.pip_install_local("simplewheel", "-t", target) assert "Successfully installed simplewheel" in result.stdout @@ -1751,34 +1852,34 @@ def test_target_install_ignores_distutils_config_install_prefix(script): def test_user_config_accepted(script): # user set in the config file is parsed as 0/1 instead of True/False. # Check that this doesn't cause a problem. - config_file = script.scratch_path / 'pip.conf' - script.environ['PIP_CONFIG_FILE'] = str(config_file) + config_file = script.scratch_path / "pip.conf" + script.environ["PIP_CONFIG_FILE"] = str(config_file) config_file.write_text("[install]\nuser = true") - result = script.pip_install_local('simplewheel') + result = script.pip_install_local("simplewheel") assert "Successfully installed simplewheel" in result.stdout relative_user = os.path.relpath(script.user_site_path, script.base_path) - result.did_create(join(relative_user, 'simplewheel')) + result.did_create(join(relative_user, "simplewheel")) @pytest.mark.parametrize( - 'install_args, expected_message', [ - ([], 'Requirement already satisfied: pip'), - (['--upgrade'], 'Requirement already {}: pip in'), - ] + "install_args, expected_message", + [ + ([], "Requirement already satisfied: pip"), + (["--upgrade"], "Requirement already {}: pip in"), + ], ) @pytest.mark.parametrize("use_module", [True, False]) def test_install_pip_does_not_modify_pip_when_satisfied( - script, install_args, expected_message, use_module, use_new_resolver): + script, install_args, expected_message, use_module, use_new_resolver +): """ Test it doesn't upgrade the pip if it already satisfies the requirement. """ variation = "satisfied" if use_new_resolver else "up-to-date" expected_message = expected_message.format(variation) - result = script.pip_install_local( - 'pip', *install_args, use_module=use_module - ) + result = script.pip_install_local("pip", *install_args, use_module=use_module) assert expected_message in result.stdout, str(result) @@ -1787,11 +1888,13 @@ def test_ignore_yanked_file(script, data): Test ignore a "yanked" file. """ result = script.pip( - 'install', 'simple', - '--index-url', data.index_url('yanked'), + "install", + "simple", + "--index-url", + data.index_url("yanked"), ) # Make sure a "yanked" release is ignored - assert 'Successfully installed simple-2.0\n' in result.stdout, str(result) + assert "Successfully installed simple-2.0\n" in result.stdout, str(result) def test_invalid_index_url_argument(script, shared_data): @@ -1799,12 +1902,19 @@ def test_invalid_index_url_argument(script, shared_data): Test the behaviour of an invalid --index-url argument """ - result = script.pip('install', '--index-url', '--user', - shared_data.find_links3, "Dinner", - expect_error=True) + result = script.pip( + "install", + "--index-url", + "--user", + shared_data.find_links3, + "Dinner", + expect_error=True, + ) - assert 'WARNING: The index url "--user" seems invalid, ' \ - 'please provide a scheme.' in result.stderr, str(result) + assert ( + 'WARNING: The index url "--user" seems invalid, ' + "please provide a scheme." in result.stderr + ), str(result) def test_valid_index_url_argument(script, shared_data): @@ -1812,11 +1922,9 @@ def test_valid_index_url_argument(script, shared_data): Test the behaviour of an valid --index-url argument """ - result = script.pip('install', '--index-url', - shared_data.find_links3, - "Dinner") + result = script.pip("install", "--index-url", shared_data.find_links3, "Dinner") - assert 'Successfully installed Dinner' in result.stdout, str(result) + assert "Successfully installed Dinner" in result.stdout, str(result) def test_install_yanked_file_and_print_warning(script, data): @@ -1827,20 +1935,25 @@ def test_install_yanked_file_and_print_warning(script, data): matches a version specifier that "pins" to an exact version (PEP 592). """ result = script.pip( - 'install', 'simple==3.0', - '--index-url', data.index_url('yanked'), + "install", + "simple==3.0", + "--index-url", + data.index_url("yanked"), expect_stderr=True, ) - expected_warning = 'Reason for being yanked: test reason message' + expected_warning = "Reason for being yanked: test reason message" assert expected_warning in result.stderr, str(result) # Make sure a "yanked" release is installed - assert 'Successfully installed simple-3.0\n' in result.stdout, str(result) + assert "Successfully installed simple-3.0\n" in result.stdout, str(result) -@pytest.mark.parametrize("install_args", [ - (), - ("--trusted-host", "localhost"), -]) +@pytest.mark.parametrize( + "install_args", + [ + (), + ("--trusted-host", "localhost"), + ], +) def test_install_sends_client_cert(install_args, script, cert_factory, data): cert_path = cert_factory() ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) @@ -1850,9 +1963,11 @@ def test_install_sends_client_cert(install_args, script, cert_factory, data): server = make_mock_server(ssl_context=ctx) server.mock.side_effect = [ - package_page({ - "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", - }), + package_page( + { + "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", + } + ), file_response(str(data.packages / "simple-3.0.tar.gz")), ] @@ -1881,25 +1996,29 @@ def test_install_skip_work_dir_pkg(script, data): """ # Create a test package, install it and then uninstall it - pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0') - script.pip('install', '-e', '.', - expect_stderr=True, cwd=pkg_path) + pkg_path = create_test_package_with_setup(script, name="simple", version="1.0") + script.pip("install", "-e", ".", expect_stderr=True, cwd=pkg_path) - script.pip('uninstall', 'simple', '-y') + script.pip("uninstall", "simple", "-y") # Running the install command again from the working directory # will install the package as it was uninstalled earlier - result = script.pip('install', '--find-links', - data.find_links, 'simple', - expect_stderr=True, cwd=pkg_path) + result = script.pip( + "install", + "--find-links", + data.find_links, + "simple", + expect_stderr=True, + cwd=pkg_path, + ) - assert 'Requirement already satisfied: simple' not in result.stdout - assert 'Successfully installed simple' in result.stdout + assert "Requirement already satisfied: simple" not in result.stdout + assert "Successfully installed simple" in result.stdout -@pytest.mark.parametrize('package_name', ('simple-package', 'simple_package', - 'simple.package')) +@pytest.mark.parametrize( + "package_name", ("simple-package", "simple_package", "simple.package") +) def test_install_verify_package_name_normalization(script, package_name): """ @@ -1908,18 +2027,17 @@ def test_install_verify_package_name_normalization(script, package_name): since the package is already installed """ pkg_path = create_test_package_with_setup( - script, name='simple-package', version='1.0') - result = script.pip('install', '-e', '.', - expect_stderr=True, cwd=pkg_path) - assert 'Successfully installed simple-package' in result.stdout + script, name="simple-package", version="1.0" + ) + result = script.pip("install", "-e", ".", expect_stderr=True, cwd=pkg_path) + assert "Successfully installed simple-package" in result.stdout - result = script.pip('install', package_name) - assert 'Requirement already satisfied: {}'.format( - package_name) in result.stdout + result = script.pip("install", package_name) + assert "Requirement already satisfied: {}".format(package_name) in result.stdout def test_install_logs_pip_version_in_debug(script, shared_data): - fake_package = shared_data.packages / 'simple-2.0.tar.gz' - result = script.pip('install', '-v', fake_package) + fake_package = shared_data.packages / "simple-2.0.tar.gz" + result = script.pip("install", "-v", fake_package) pattern = "Using pip .* from .*" assert_re_match(pattern, result.stdout) diff --git a/tests/functional/test_install_check.py b/tests/functional/test_install_check.py index a173cb5504f..0b61bdae496 100644 --- a/tests/functional/test_install_check.py +++ b/tests/functional/test_install_check.py @@ -3,36 +3,38 @@ def assert_contains_expected_lines(string, expected_lines): for expected_line in expected_lines: - assert (expected_line + '\n') in string + assert (expected_line + "\n") in string def test_check_install_canonicalization(script): pkga_path = create_test_package_with_setup( script, - name='pkgA', - version='1.0', - install_requires=['normal-missing', 'SPECIAL.missing'], + name="pkgA", + version="1.0", + install_requires=["normal-missing", "SPECIAL.missing"], ) normal_path = create_test_package_with_setup( script, - name='normal-missing', version='0.1', + name="normal-missing", + version="0.1", ) special_path = create_test_package_with_setup( script, - name='SPECIAL.missing', version='0.1', + name="SPECIAL.missing", + version="0.1", ) # Let's install pkgA without its dependency - result = script.pip('install', '--no-index', pkga_path, '--no-deps') + result = script.pip("install", "--no-index", pkga_path, "--no-deps") assert "Successfully installed pkgA-1.0" in result.stdout, str(result) # Install the first missing dependency. Only an error for the # second dependency should remain. result = script.pip( - 'install', - '--no-index', + "install", + "--no-index", normal_path, - '--quiet', + "--quiet", allow_stderr_error=True, ) expected_lines = [ @@ -46,13 +48,16 @@ def test_check_install_canonicalization(script): # during the installation. This is special as the package name requires # name normalization (as in https://github.com/pypa/pip/issues/5134) result = script.pip( - 'install', '--no-index', special_path, '--quiet', + "install", + "--no-index", + special_path, + "--quiet", ) assert "requires" not in result.stderr assert result.returncode == 0 # Double check that all errors are resolved in the end - result = script.pip('check') + result = script.pip("check") expected_lines = [ "No broken requirements found.", ] @@ -63,43 +68,52 @@ def test_check_install_canonicalization(script): def test_check_install_does_not_warn_for_out_of_graph_issues(script): pkg_broken_path = create_test_package_with_setup( script, - name='broken', - version='1.0', - install_requires=['missing', 'conflict < 1.0'], + name="broken", + version="1.0", + install_requires=["missing", "conflict < 1.0"], ) pkg_unrelated_path = create_test_package_with_setup( script, - name='unrelated', - version='1.0', + name="unrelated", + version="1.0", ) pkg_conflict_path = create_test_package_with_setup( script, - name='conflict', - version='1.0', + name="conflict", + version="1.0", ) # Install a package without it's dependencies - result = script.pip('install', '--no-index', pkg_broken_path, '--no-deps') + result = script.pip("install", "--no-index", pkg_broken_path, "--no-deps") assert "requires" not in result.stderr # Install conflict package result = script.pip( - 'install', '--no-index', pkg_conflict_path, allow_stderr_error=True, + "install", + "--no-index", + pkg_conflict_path, + allow_stderr_error=True, + ) + assert_contains_expected_lines( + result.stderr, + [ + "broken 1.0 requires missing, which is not installed.", + "broken 1.0 requires conflict<1.0, " + "but you'll have conflict 1.0 which is incompatible.", + ], ) - assert_contains_expected_lines(result.stderr, [ - "broken 1.0 requires missing, which is not installed.", - "broken 1.0 requires conflict<1.0, " - "but you'll have conflict 1.0 which is incompatible." - ]) # Install unrelated package result = script.pip( - 'install', '--no-index', pkg_unrelated_path, '--quiet', + "install", + "--no-index", + pkg_unrelated_path, + "--quiet", ) # should not warn about broken's deps when installing unrelated package assert "requires" not in result.stderr - result = script.pip('check', expect_error=True) + result = script.pip("check", expect_error=True) expected_lines = [ "broken 1.0 requires missing, which is not installed.", "broken 1.0 has requirement conflict<1.0, but you have conflict 1.0.", diff --git a/tests/functional/test_install_cleanup.py b/tests/functional/test_install_cleanup.py index c01c47c3e3e..44fd1420cf4 100644 --- a/tests/functional/test_install_cleanup.py +++ b/tests/functional/test_install_cleanup.py @@ -11,10 +11,15 @@ def test_no_clean_option_blocks_cleaning_after_install(script, data): """ Test --no-clean option blocks cleaning after install """ - build = script.base_path / 'pip-build' + build = script.base_path / "pip-build" script.pip( - 'install', '--no-clean', '--no-index', '--build', build, - '--find-links={}'.format(data.find_links), 'simple', + "install", + "--no-clean", + "--no-index", + "--build", + build, + "--find-links={}".format(data.find_links), + "simple", expect_temp=True, # TODO: allow_stderr_warning is used for the --build deprecation, # remove it when removing support for --build @@ -32,21 +37,25 @@ def test_cleanup_prevented_upon_build_dir_exception( """ Test no cleanup occurs after a PreviousBuildDirError """ - build = script.venv_path / 'build' - build_simple = build / 'simple' + build = script.venv_path / "build" + build_simple = build / "simple" os.makedirs(build_simple) build_simple.joinpath("setup.py").write_text("#") result = script.pip( - 'install', '-f', data.find_links, '--no-index', 'simple', - '--build', build, + "install", + "-f", + data.find_links, + "--no-index", + "simple", + "--build", + build, expect_error=(not use_new_resolver), expect_temp=(not use_new_resolver), expect_stderr=True, ) assert ( - "The -b/--build/--build-dir/--build-directory " - "option is deprecated." + "The -b/--build/--build-dir/--build-directory " "option is deprecated." ) in result.stderr if not use_new_resolver: @@ -58,12 +67,9 @@ def test_cleanup_prevented_upon_build_dir_exception( @pytest.mark.network def test_pep517_no_legacy_cleanup(script, data, with_wheel): """Test a PEP 517 failed build does not attempt a legacy cleanup""" - to_install = data.packages.joinpath('pep517_wrapper_buildsys') + to_install = data.packages.joinpath("pep517_wrapper_buildsys") script.environ["PIP_TEST_FAIL_BUILD_WHEEL"] = "1" - res = script.pip( - 'install', '-f', data.find_links, to_install, - expect_error=True - ) + res = script.pip("install", "-f", data.find_links, to_install, expect_error=True) # Must not have built the package expected = "Failed building wheel for pep517-wrapper-buildsys" assert expected in str(res) diff --git a/tests/functional/test_install_compat.py b/tests/functional/test_install_compat.py index a5a0df65218..2b964093f64 100644 --- a/tests/functional/test_install_compat.py +++ b/tests/functional/test_install_compat.py @@ -22,26 +22,22 @@ def test_debian_egg_name_workaround(script): https://bitbucket.org/ianb/pip/issue/104/pip-uninstall-on-ubuntu-linux """ - result = script.pip('install', 'INITools==0.2') + result = script.pip("install", "INITools==0.2") egg_info = os.path.join( - script.site_packages, - "INITools-0.2-py{pyversion}.egg-info".format(**globals())) + script.site_packages, "INITools-0.2-py{pyversion}.egg-info".format(**globals()) + ) # Debian only removes pyversion for global installs, not inside a venv # so even if this test runs on a Debian/Ubuntu system with broken # setuptools, since our test runs inside a venv we'll still have the normal # .egg-info - result.did_create( - egg_info, - message="Couldn't find {egg_info}".format(**locals()) - ) + result.did_create(egg_info, message="Couldn't find {egg_info}".format(**locals())) # The Debian no-pyversion version of the .egg-info mangled = os.path.join(script.site_packages, "INITools-0.2.egg-info") result.did_not_create( - mangled, - message="Found unexpected {mangled}".format(**locals()) + mangled, message="Found unexpected {mangled}".format(**locals()) ) # Simulate a Debian install by copying the .egg-info to their name for it @@ -53,7 +49,7 @@ def test_debian_egg_name_workaround(script): # Try the uninstall and verify that everything is removed. result2 = script.pip("uninstall", "INITools", "-y") - assert_all_changes(result, result2, [script.venv / 'build', 'cache']) + assert_all_changes(result, result2, [script.venv / "build", "cache"]) def test_setup_py_with_dos_line_endings(script, data): @@ -63,4 +59,4 @@ def test_setup_py_with_dos_line_endings(script, data): Refs https://github.com/pypa/pip/issues/237 """ to_install = data.packages.joinpath("LineEndings") - script.pip('install', to_install) + script.pip("install", to_install) diff --git a/tests/functional/test_install_config.py b/tests/functional/test_install_config.py index dcc9c66d5a4..0c24e1ae149 100644 --- a/tests/functional/test_install_config.py +++ b/tests/functional/test_install_config.py @@ -19,8 +19,8 @@ def test_options_from_env_vars(script): Test if ConfigOptionParser reads env vars (e.g. not using PyPI here) """ - script.environ['PIP_NO_INDEX'] = '1' - result = script.pip('install', '-vvv', 'INITools', expect_error=True) + script.environ["PIP_NO_INDEX"] = "1" + result = script.pip("install", "-vvv", "INITools", expect_error=True) assert "Ignoring indexes:" in result.stdout, str(result) msg = "DistributionNotFound: No matching distribution found for INITools" # Case insensitive as the new resolver canonicalises the project name @@ -32,16 +32,16 @@ def test_command_line_options_override_env_vars(script, virtualenv): Test that command line options override environmental variables. """ - script.environ['PIP_INDEX_URL'] = 'https://example.com/simple/' - result = script.pip('install', '-vvv', 'INITools', expect_error=True) - assert ( - "Getting page https://example.com/simple/initools" - in result.stdout - ) + script.environ["PIP_INDEX_URL"] = "https://example.com/simple/" + result = script.pip("install", "-vvv", "INITools", expect_error=True) + assert "Getting page https://example.com/simple/initools" in result.stdout virtualenv.clear() result = script.pip( - 'install', '-vvv', '--index-url', 'https://download.zope.org/ppix', - 'INITools', + "install", + "-vvv", + "--index-url", + "https://download.zope.org/ppix", + "INITools", expect_error=True, ) assert "example.com" not in result.stdout @@ -55,22 +55,26 @@ def test_env_vars_override_config_file(script, virtualenv): """ config_file = script.scratch_path / "test-pip.cfg" # set this to make pip load it - script.environ['PIP_CONFIG_FILE'] = str(config_file) + script.environ["PIP_CONFIG_FILE"] = str(config_file) # It's important that we test this particular config value ('no-index') # because there is/was a bug which only shows up in cases in which # 'config-item' and 'config_item' hash to the same value modulo the size # of the config dictionary. - config_file.write_text(textwrap.dedent("""\ + config_file.write_text( + textwrap.dedent( + """\ [global] no-index = 1 - """)) - result = script.pip('install', '-vvv', 'INITools', expect_error=True) + """ + ) + ) + result = script.pip("install", "-vvv", "INITools", expect_error=True) msg = "DistributionNotFound: No matching distribution found for INITools" # Case insensitive as the new resolver canonicalises the project name assert msg.lower() in result.stdout.lower(), str(result) - script.environ['PIP_NO_INDEX'] = '0' + script.environ["PIP_NO_INDEX"] = "0" virtualenv.clear() - result = script.pip('install', '-vvv', 'INITools') + result = script.pip("install", "-vvv", "INITools") assert "Successfully installed INITools" in result.stdout @@ -81,10 +85,13 @@ def test_command_line_append_flags(script, virtualenv, data): variables. """ - script.environ['PIP_FIND_LINKS'] = 'https://test.pypi.org' + script.environ["PIP_FIND_LINKS"] = "https://test.pypi.org" result = script.pip( - 'install', '-vvv', 'INITools', '--trusted-host', - 'test.pypi.org', + "install", + "-vvv", + "INITools", + "--trusted-host", + "test.pypi.org", ) assert ( "Fetching project page and analyzing links: https://test.pypi.org" @@ -92,17 +99,21 @@ def test_command_line_append_flags(script, virtualenv, data): ), str(result) virtualenv.clear() result = script.pip( - 'install', '-vvv', '--find-links', data.find_links, 'INITools', - '--trusted-host', 'test.pypi.org', + "install", + "-vvv", + "--find-links", + data.find_links, + "INITools", + "--trusted-host", + "test.pypi.org", ) assert ( "Fetching project page and analyzing links: https://test.pypi.org" in result.stdout ) assert ( - 'Skipping link: not a file: {}'.format(data.find_links) in - result.stdout - ), 'stdout: {}'.format(result.stdout) + "Skipping link: not a file: {}".format(data.find_links) in result.stdout + ), "stdout: {}".format(result.stdout) @pytest.mark.network @@ -111,12 +122,15 @@ def test_command_line_appends_correctly(script, data): Test multiple appending options set by environmental variables. """ - script.environ['PIP_FIND_LINKS'] = ( - 'https://test.pypi.org {data.find_links}'.format(**locals()) + script.environ["PIP_FIND_LINKS"] = "https://test.pypi.org {data.find_links}".format( + **locals() ) result = script.pip( - 'install', '-vvv', 'INITools', '--trusted-host', - 'test.pypi.org', + "install", + "-vvv", + "INITools", + "--trusted-host", + "test.pypi.org", ) assert ( @@ -124,50 +138,63 @@ def test_command_line_appends_correctly(script, data): in result.stdout ), result.stdout assert ( - 'Skipping link: not a file: {}'.format(data.find_links) in - result.stdout - ), 'stdout: {}'.format(result.stdout) + "Skipping link: not a file: {}".format(data.find_links) in result.stdout + ), "stdout: {}".format(result.stdout) -def test_config_file_override_stack( - script, virtualenv, mock_server, shared_data -): +def test_config_file_override_stack(script, virtualenv, mock_server, shared_data): """ Test config files (global, overriding a global config with a local, overriding all with a command line flag). """ - mock_server.set_responses([ - package_page({}), - package_page({}), - package_page({"INITools-0.2.tar.gz": "/files/INITools-0.2.tar.gz"}), - file_response(shared_data.packages.joinpath("INITools-0.2.tar.gz")), - ]) + mock_server.set_responses( + [ + package_page({}), + package_page({}), + package_page({"INITools-0.2.tar.gz": "/files/INITools-0.2.tar.gz"}), + file_response(shared_data.packages.joinpath("INITools-0.2.tar.gz")), + ] + ) mock_server.start() base_address = "http://{}:{}".format(mock_server.host, mock_server.port) config_file = script.scratch_path / "test-pip.cfg" # set this to make pip load it - script.environ['PIP_CONFIG_FILE'] = str(config_file) + script.environ["PIP_CONFIG_FILE"] = str(config_file) - config_file.write_text(textwrap.dedent("""\ + config_file.write_text( + textwrap.dedent( + """\ [global] index-url = {}/simple1 - """.format(base_address))) - script.pip('install', '-vvv', 'INITools', expect_error=True) + """.format( + base_address + ) + ) + ) + script.pip("install", "-vvv", "INITools", expect_error=True) virtualenv.clear() - config_file.write_text(textwrap.dedent("""\ + config_file.write_text( + textwrap.dedent( + """\ [global] index-url = {address}/simple1 [install] index-url = {address}/simple2 - """.format(address=base_address)) + """.format( + address=base_address + ) + ) ) - script.pip('install', '-vvv', 'INITools', expect_error=True) + script.pip("install", "-vvv", "INITools", expect_error=True) script.pip( - 'install', '-vvv', '--index-url', "{}/simple3".format(base_address), - 'INITools', + "install", + "-vvv", + "--index-url", + "{}/simple3".format(base_address), + "INITools", ) mock_server.stop() @@ -185,30 +212,34 @@ def test_options_from_venv_config(script, virtualenv): """ from pip._internal.configuration import CONFIG_BASENAME + conf = "[global]\nno-index = true" ini = virtualenv.location / CONFIG_BASENAME - with open(ini, 'w') as f: + with open(ini, "w") as f: f.write(conf) - result = script.pip('install', '-vvv', 'INITools', expect_error=True) + result = script.pip("install", "-vvv", "INITools", expect_error=True) assert "Ignoring indexes:" in result.stdout, str(result) msg = "DistributionNotFound: No matching distribution found for INITools" # Case insensitive as the new resolver canonicalises the project name assert msg.lower() in result.stdout.lower(), str(result) -def test_install_no_binary_via_config_disables_cached_wheels( - script, data, with_wheel): - config_file = tempfile.NamedTemporaryFile(mode='wt', delete=False) +def test_install_no_binary_via_config_disables_cached_wheels(script, data, with_wheel): + config_file = tempfile.NamedTemporaryFile(mode="wt", delete=False) try: - script.environ['PIP_CONFIG_FILE'] = config_file.name - config_file.write(textwrap.dedent("""\ + script.environ["PIP_CONFIG_FILE"] = config_file.name + config_file.write( + textwrap.dedent( + """\ [global] no-binary = :all: - """)) + """ + ) + ) config_file.close() res = script.pip( - 'install', '--no-index', '-f', data.find_links, - 'upper', expect_stderr=True) + "install", "--no-index", "-f", data.find_links, "upper", expect_stderr=True + ) finally: os.unlink(config_file.name) assert "Successfully installed upper-2.0" in str(res), str(res) @@ -230,21 +261,32 @@ def test_prompt_for_authentication(script, data, cert_factory): server = make_mock_server(ssl_context=ctx) server.mock.side_effect = [ - package_page({ - "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", - }), + package_page( + { + "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", + } + ), authorization_response(str(data.packages / "simple-3.0.tar.gz")), ] url = "https://{}:{}/simple".format(server.host, server.port) with server_running(server): - result = script.pip('install', "--index-url", url, - "--cert", cert_path, "--client-cert", cert_path, - 'simple', expect_error=True) - - assert 'User for {}:{}'.format(server.host, server.port) in \ - result.stdout, str(result) + result = script.pip( + "install", + "--index-url", + url, + "--cert", + cert_path, + "--client-cert", + cert_path, + "simple", + expect_error=True, + ) + + assert "User for {}:{}".format(server.host, server.port) in result.stdout, str( + result + ) def test_do_not_prompt_for_authentication(script, data, cert_factory): @@ -260,17 +302,28 @@ def test_do_not_prompt_for_authentication(script, data, cert_factory): server = make_mock_server(ssl_context=ctx) server.mock.side_effect = [ - package_page({ - "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", - }), + package_page( + { + "simple-3.0.tar.gz": "/files/simple-3.0.tar.gz", + } + ), authorization_response(str(data.packages / "simple-3.0.tar.gz")), ] url = "https://{}:{}/simple".format(server.host, server.port) with server_running(server): - result = script.pip('install', "--index-url", url, - "--cert", cert_path, "--client-cert", cert_path, - '--no-input', 'simple', expect_error=True) + result = script.pip( + "install", + "--index-url", + url, + "--cert", + cert_path, + "--client-cert", + cert_path, + "--no-input", + "simple", + expect_error=True, + ) assert "ERROR: HTTP error 401" in result.stderr diff --git a/tests/functional/test_install_extras.py b/tests/functional/test_install_extras.py index d70067b6bca..ab75c3ab7dc 100644 --- a/tests/functional/test_install_extras.py +++ b/tests/functional/test_install_extras.py @@ -11,9 +11,11 @@ def test_simple_extras_install_from_pypi(script): Test installing a package from PyPI using extras dependency Paste[openid]. """ result = script.pip( - 'install', 'Paste[openid]==1.7.5.1', expect_stderr=True, + "install", + "Paste[openid]==1.7.5.1", + expect_stderr=True, ) - initools_folder = script.site_packages / 'openid' + initools_folder = script.site_packages / "openid" result.did_create(initools_folder) @@ -21,17 +23,25 @@ def test_extras_after_wheel(script, data): """ Test installing a package with extras after installing from a wheel. """ - simple = script.site_packages / 'simple' + simple = script.site_packages / "simple" no_extra = script.pip( - 'install', '--no-index', '-f', data.find_links, - 'requires_simple_extra', expect_stderr=True, + "install", + "--no-index", + "-f", + data.find_links, + "requires_simple_extra", + expect_stderr=True, ) no_extra.did_not_create(simple) extra = script.pip( - 'install', '--no-index', '-f', data.find_links, - 'requires_simple_extra[extra]', expect_stderr=True, + "install", + "--no-index", + "-f", + data.find_links, + "requires_simple_extra[extra]", + expect_stderr=True, ) extra.did_create(simple) @@ -42,13 +52,15 @@ def test_no_extras_uninstall(script): No extras dependency gets uninstalled when the root package is uninstalled """ result = script.pip( - 'install', 'Paste[openid]==1.7.5.1', expect_stderr=True, + "install", + "Paste[openid]==1.7.5.1", + expect_stderr=True, ) - result.did_create(join(script.site_packages, 'paste')) - result.did_create(join(script.site_packages, 'openid')) - result2 = script.pip('uninstall', 'Paste', '-y') + result.did_create(join(script.site_packages, "paste")) + result.did_create(join(script.site_packages, "openid")) + result2 = script.pip("uninstall", "Paste", "-y") # openid should not be uninstalled - initools_folder = script.site_packages / 'openid' + initools_folder = script.site_packages / "openid" assert initools_folder not in result2.files_deleted, result.files_deleted @@ -60,14 +72,16 @@ def test_nonexistent_extra_warns_user_no_wheel(script, data): This exercises source installs. """ result = script.pip( - 'install', '--no-binary=:all:', '--no-index', - '--find-links=' + data.find_links, - 'simple[nonexistent]', expect_stderr=True, + "install", + "--no-binary=:all:", + "--no-index", + "--find-links=" + data.find_links, + "simple[nonexistent]", + expect_stderr=True, + ) + assert "simple 3.0 does not provide the extra 'nonexistent'" in result.stderr, str( + result ) - assert ( - "simple 3.0 does not provide the extra 'nonexistent'" - in result.stderr - ), str(result) def test_nonexistent_extra_warns_user_with_wheel(script, data): @@ -78,14 +92,13 @@ def test_nonexistent_extra_warns_user_with_wheel(script, data): This exercises wheel installs. """ result = script.pip( - 'install', '--no-index', - '--find-links=' + data.find_links, - 'simplewheel[nonexistent]', expect_stderr=True, - ) - assert ( - "simplewheel 2.0 does not provide the extra 'nonexistent'" - in result.stderr + "install", + "--no-index", + "--find-links=" + data.find_links, + "simplewheel[nonexistent]", + expect_stderr=True, ) + assert "simplewheel 2.0 does not provide the extra 'nonexistent'" in result.stderr def test_nonexistent_options_listed_in_order(script, data): @@ -93,15 +106,16 @@ def test_nonexistent_options_listed_in_order(script, data): Warn the user for each extra that doesn't exist. """ result = script.pip( - 'install', '--no-index', - '--find-links=' + data.find_links, - 'simplewheel[nonexistent, nope]', expect_stderr=True, + "install", + "--no-index", + "--find-links=" + data.find_links, + "simplewheel[nonexistent, nope]", + expect_stderr=True, ) matches = re.findall( - "WARNING: simplewheel 2.0 does not provide the extra '([a-z]*)'", - result.stderr + "WARNING: simplewheel 2.0 does not provide the extra '([a-z]*)'", result.stderr ) - assert matches == ['nonexistent', 'nope'] + assert matches == ["nonexistent", "nope"] def test_install_deprecated_extra(script, data): @@ -114,50 +128,65 @@ def test_install_deprecated_extra(script, data): script.scratch_path.joinpath("requirements.txt").write_text( "requires_simple_extra>=0.1[extra]" ) - simple = script.site_packages / 'simple' + simple = script.site_packages / "simple" result = script.pip( - 'install', '--no-index', '--find-links=' + data.find_links, - '-r', script.scratch_path / 'requirements.txt', expect_stderr=True, + "install", + "--no-index", + "--find-links=" + data.find_links, + "-r", + script.scratch_path / "requirements.txt", + expect_stderr=True, ) result.did_create(simple) - assert ("DEPRECATION: Extras after version" in result.stderr) + assert "DEPRECATION: Extras after version" in result.stderr def test_install_special_extra(script): # Check that uppercase letters and '-' are dealt with # make a dummy project - pkga_path = script.scratch_path / 'pkga' + pkga_path = script.scratch_path / "pkga" pkga_path.mkdir() - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', version='0.1', extras_require={'Hop_hOp-hoP': ['missing_pkg']}, ) - """)) + """ + ) + ) result = script.pip( - 'install', '--no-index', '{pkga_path}[Hop_hOp-hoP]'.format(**locals()), - expect_error=True) + "install", + "--no-index", + "{pkga_path}[Hop_hOp-hoP]".format(**locals()), + expect_error=True, + ) assert ( "Could not find a version that satisfies the requirement missing_pkg" ) in result.stderr, str(result) @pytest.mark.parametrize( - "extra_to_install, simple_version", [ - ['', '3.0'], - pytest.param('[extra1]', '2.0', marks=pytest.mark.xfail), - pytest.param('[extra2]', '1.0', marks=pytest.mark.xfail), - pytest.param('[extra1,extra2]', '1.0', marks=pytest.mark.xfail), - ]) + "extra_to_install, simple_version", + [ + ["", "3.0"], + pytest.param("[extra1]", "2.0", marks=pytest.mark.xfail), + pytest.param("[extra2]", "1.0", marks=pytest.mark.xfail), + pytest.param("[extra1,extra2]", "1.0", marks=pytest.mark.xfail), + ], +) def test_install_extra_merging(script, data, extra_to_install, simple_version): # Check that extra specifications in the extras section are honoured. - pkga_path = script.scratch_path / 'pkga' + pkga_path = script.scratch_path / "pkga" pkga_path.mkdir() - pkga_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkga_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup setup(name='pkga', version='0.1', @@ -165,11 +194,14 @@ def test_install_extra_merging(script, data, extra_to_install, simple_version): extras_require={'extra1': ['simple<3'], 'extra2': ['simple==1.*']}, ) - """)) + """ + ) + ) result = script.pip_install_local( - '{pkga_path}{extra_to_install}'.format(**locals()), + "{pkga_path}{extra_to_install}".format(**locals()), ) - assert ('Successfully installed pkga-0.1 simple-{}'.format(simple_version) - ) in result.stdout + assert ( + "Successfully installed pkga-0.1 simple-{}".format(simple_version) + ) in result.stdout diff --git a/tests/functional/test_install_force_reinstall.py b/tests/functional/test_install_force_reinstall.py index 0fbdeb276c4..88ffda62172 100644 --- a/tests/functional/test_install_force_reinstall.py +++ b/tests/functional/test_install_force_reinstall.py @@ -4,14 +4,14 @@ def check_installed_version(script, package, expected): - result = script.pip('show', package) + result = script.pip("show", package) lines = result.stdout.splitlines() version = None for line in lines: - if line.startswith('Version: '): + if line.startswith("Version: "): version = line.split()[-1] break - assert version == expected, 'version {} != {}'.format(version, expected) + assert version == expected, "version {} != {}".format(version, expected) def check_force_reinstall(script, specifier, expected): @@ -20,23 +20,23 @@ def check_force_reinstall(script, specifier, expected): specifier: the requirement specifier to force-reinstall. expected: the expected version after force-reinstalling. """ - result = script.pip_install_local('simplewheel==1.0') - check_installed_version(script, 'simplewheel', '1.0') + result = script.pip_install_local("simplewheel==1.0") + check_installed_version(script, "simplewheel", "1.0") # Remove an installed file to test whether --force-reinstall fixes it. to_fix = script.site_packages_path.joinpath("simplewheel", "__init__.py") to_fix.unlink() - result2 = script.pip_install_local('--force-reinstall', specifier) - check_installed_version(script, 'simplewheel', expected) + result2 = script.pip_install_local("--force-reinstall", specifier) + check_installed_version(script, "simplewheel", expected) # site_packages_path is absolute, but files_created mapping uses # relative paths as key. fixed_key = os.path.relpath(to_fix, script.base_path) - result2.did_create(fixed_key, message='force-reinstall failed') + result2.did_create(fixed_key, message="force-reinstall failed") - result3 = script.pip('uninstall', 'simplewheel', '-y') - assert_all_changes(result, result3, [script.venv / 'build', 'cache']) + result3 = script.pip("uninstall", "simplewheel", "-y") + assert_all_changes(result, result3, [script.venv / "build", "cache"]) def test_force_reinstall_with_no_version_specifier(script): @@ -44,7 +44,7 @@ def test_force_reinstall_with_no_version_specifier(script): Check --force-reinstall when there is no version specifier and the installed version is not the newest version. """ - check_force_reinstall(script, 'simplewheel', '2.0') + check_force_reinstall(script, "simplewheel", "2.0") def test_force_reinstall_with_same_version_specifier(script): @@ -52,4 +52,4 @@ def test_force_reinstall_with_same_version_specifier(script): Check --force-reinstall when the version specifier equals the installed version and the installed version is not the newest version. """ - check_force_reinstall(script, 'simplewheel==1.0', '1.0') + check_force_reinstall(script, "simplewheel==1.0", "1.0") diff --git a/tests/functional/test_install_index.py b/tests/functional/test_install_index.py index e887595b937..cf87eaab9b3 100644 --- a/tests/functional/test_install_index.py +++ b/tests/functional/test_install_index.py @@ -7,38 +7,40 @@ def test_find_links_relative_path(script, data, with_wheel): """Test find-links as a relative path.""" result = script.pip( - 'install', - 'parent==0.1', - '--no-index', - '--find-links', - 'packages/', + "install", + "parent==0.1", + "--no-index", + "--find-links", + "packages/", cwd=data.root, ) - dist_info_folder = ( - script.site_packages / 'parent-0.1.dist-info' - ) - initools_folder = script.site_packages / 'parent' + dist_info_folder = script.site_packages / "parent-0.1.dist-info" + initools_folder = script.site_packages / "parent" result.did_create(dist_info_folder) result.did_create(initools_folder) def test_find_links_requirements_file_relative_path(script, data, with_wheel): """Test find-links as a relative path to a reqs file.""" - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent(""" + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """ --no-index --find-links={} parent==0.1 - """ .format(data.packages.replace(os.path.sep, '/')))) + """.format( + data.packages.replace(os.path.sep, "/") + ) + ) + ) result = script.pip( - 'install', - '-r', + "install", + "-r", script.scratch_path / "test-req.txt", cwd=data.root, ) - dist_info_folder = ( - script.site_packages / 'parent-0.1.dist-info' - ) - initools_folder = script.site_packages / 'parent' + dist_info_folder = script.site_packages / "parent-0.1.dist-info" + initools_folder = script.site_packages / "parent" result.did_create(dist_info_folder) result.did_create(initools_folder) @@ -48,10 +50,8 @@ def test_install_from_file_index_hash_link(script, data, with_wheel): Test that a pkg can be installed from a file:// index using a link with a hash """ - result = script.pip('install', '-i', data.index_url(), 'simple==1.0') - dist_info_folder = ( - script.site_packages / 'simple-1.0.dist-info' - ) + result = script.pip("install", "-i", data.index_url(), "simple==1.0") + dist_info_folder = script.site_packages / "simple-1.0.dist-info" result.did_create(dist_info_folder) @@ -60,10 +60,6 @@ def test_file_index_url_quoting(script, data, with_wheel): Test url quoting of file index url with a space """ index_url = data.index_url(urllib_parse.quote("in dex")) - result = script.pip( - 'install', '-vvv', '--index-url', index_url, 'simple' - ) - result.did_create(script.site_packages / 'simple') - result.did_create( - script.site_packages / 'simple-1.0.dist-info' - ) + result = script.pip("install", "-vvv", "--index-url", index_url, "simple") + result.did_create(script.site_packages / "simple") + result.did_create(script.site_packages / "simple-1.0.dist-info") diff --git a/tests/functional/test_install_reqs.py b/tests/functional/test_install_reqs.py index c879b6903dd..da404ab4365 100644 --- a/tests/functional/test_install_reqs.py +++ b/tests/functional/test_install_reqs.py @@ -43,18 +43,14 @@ def arg_recording_sdist_maker(script): setup(name={name!r}, version="0.1.0") """ ) - output_dir = script.scratch_path.joinpath( - "args_recording_sdist_maker_output" - ) + output_dir = script.scratch_path.joinpath("args_recording_sdist_maker_output") output_dir.mkdir(parents=True) script.environ["OUTPUT_DIR"] = str(output_dir) def _arg_recording_sdist_maker(name): # type: (str) -> ArgRecordingSdist extra_files = {"setup.py": arg_writing_setup_py.format(name=name)} - sdist_path = create_basic_sdist_for_package( - script, name, "0.1.0", extra_files - ) + sdist_path = create_basic_sdist_for_package(script, name, "0.1.0", extra_files) args_path = output_dir / "{}.json".format(name) return ArgRecordingSdist(sdist_path, args_path) @@ -67,22 +63,23 @@ def test_requirements_file(script, with_wheel): Test installing from a requirements file. """ - other_lib_name, other_lib_version = 'anyjson', '0.3' - script.scratch_path.joinpath("initools-req.txt").write_text(textwrap.dedent("""\ + other_lib_name, other_lib_version = "anyjson", "0.3" + script.scratch_path.joinpath("initools-req.txt").write_text( + textwrap.dedent( + """\ INITools==0.2 # and something else to test out: {other_lib_name}<={other_lib_version} - """.format(**locals()))) - result = script.pip( - 'install', '-r', script.scratch_path / 'initools-req.txt' - ) - result.did_create( - script.site_packages / 'INITools-0.2.dist-info' + """.format( + **locals() + ) + ) ) - result.did_create(script.site_packages / 'initools') + result = script.pip("install", "-r", script.scratch_path / "initools-req.txt") + result.did_create(script.site_packages / "INITools-0.2.dist-info") + result.did_create(script.site_packages / "initools") assert result.files_created[script.site_packages / other_lib_name].dir - fn = '{}-{}.dist-info'.format( - other_lib_name, other_lib_version) + fn = "{}-{}.dist-info".format(other_lib_name, other_lib_version) assert result.files_created[script.site_packages / fn].dir @@ -99,41 +96,35 @@ def test_schema_check_in_requirements_file(script): ) with pytest.raises(AssertionError): - script.pip( - "install", "-vvv", "-r", script.scratch_path / "file-egg-req.txt" - ) - - -@pytest.mark.parametrize("test_type,editable", [ - ("rel_path", False), - ("rel_path", True), - ("rel_url", False), - ("rel_url", True), - ("embedded_rel_path", False), - ("embedded_rel_path", True), -]) -def test_relative_requirements_file( - script, data, test_type, editable, with_wheel -): + script.pip("install", "-vvv", "-r", script.scratch_path / "file-egg-req.txt") + + +@pytest.mark.parametrize( + "test_type,editable", + [ + ("rel_path", False), + ("rel_path", True), + ("rel_url", False), + ("rel_url", True), + ("embedded_rel_path", False), + ("embedded_rel_path", True), + ], +) +def test_relative_requirements_file(script, data, test_type, editable, with_wheel): """ Test installing from a requirements file with a relative path. For path URLs, use an egg= definition. """ - dist_info_folder = ( - script.site_packages / - 'FSPkg-0.1.dev0.dist-info' - ) - egg_link_file = ( - script.site_packages / 'FSPkg.egg-link' - ) - package_folder = script.site_packages / 'fspkg' + dist_info_folder = script.site_packages / "FSPkg-0.1.dev0.dist-info" + egg_link_file = script.site_packages / "FSPkg.egg-link" + package_folder = script.site_packages / "fspkg" # Compute relative install path to FSPkg from scratch path. full_rel_path = Path( - os.path.relpath(data.packages.joinpath('FSPkg'), script.scratch_path) + os.path.relpath(data.packages.joinpath("FSPkg"), script.scratch_path) ) - full_rel_url = 'file:' + full_rel_path + '#egg=FSPkg' + full_rel_url = "file:" + full_rel_path + "#egg=FSPkg" embedded_rel_path = script.scratch_path.joinpath(full_rel_path) req_path = { @@ -142,20 +133,22 @@ def test_relative_requirements_file( "embedded_rel_path": embedded_rel_path, }[test_type] - req_path = req_path.replace(os.path.sep, '/') + req_path = req_path.replace(os.path.sep, "/") # Install as either editable or not. if not editable: - with requirements_file(req_path + '\n', - script.scratch_path) as reqs_file: - result = script.pip('install', '-vvv', '-r', reqs_file.name, - cwd=script.scratch_path) + with requirements_file(req_path + "\n", script.scratch_path) as reqs_file: + result = script.pip( + "install", "-vvv", "-r", reqs_file.name, cwd=script.scratch_path + ) result.did_create(dist_info_folder) result.did_create(package_folder) else: - with requirements_file('-e ' + req_path + '\n', - script.scratch_path) as reqs_file: - result = script.pip('install', '-vvv', '-r', reqs_file.name, - cwd=script.scratch_path) + with requirements_file( + "-e " + req_path + "\n", script.scratch_path + ) as reqs_file: + result = script.pip( + "install", "-vvv", "-r", reqs_file.name, cwd=script.scratch_path + ) result.did_create(egg_link_file) @@ -167,144 +160,162 @@ def test_multiple_requirements_files(script, tmpdir, with_wheel): Test installing from multiple nested requirements files. """ - other_lib_name, other_lib_version = 'anyjson', '0.3' + other_lib_name, other_lib_version = "anyjson", "0.3" script.scratch_path.joinpath("initools-req.txt").write_text( - textwrap.dedent(""" + textwrap.dedent( + """ -e {}@10#egg=INITools -r {}-req.txt - """).format - ( - local_checkout('svn+http://svn.colorstudy.com/INITools', tmpdir), - other_lib_name + """ + ).format( + local_checkout("svn+http://svn.colorstudy.com/INITools", tmpdir), + other_lib_name, ), ) script.scratch_path.joinpath( - "{other_lib_name}-req.txt".format(**locals())).write_text( - "{other_lib_name}<={other_lib_version}".format(**locals()) - ) - result = script.pip( - 'install', '-r', script.scratch_path / 'initools-req.txt' - ) + "{other_lib_name}-req.txt".format(**locals()) + ).write_text("{other_lib_name}<={other_lib_version}".format(**locals())) + result = script.pip("install", "-r", script.scratch_path / "initools-req.txt") assert result.files_created[script.site_packages / other_lib_name].dir - fn = '{other_lib_name}-{other_lib_version}.dist-info'.format(**locals()) + fn = "{other_lib_name}-{other_lib_version}.dist-info".format(**locals()) assert result.files_created[script.site_packages / fn].dir - result.did_create(script.venv / 'src' / 'initools') + result.did_create(script.venv / "src" / "initools") def test_package_in_constraints_and_dependencies(script, data): script.scratch_path.joinpath("constraints.txt").write_text( "TopoRequires2==0.0.1\nTopoRequires==0.0.1" ) - result = script.pip('install', '--no-index', '-f', - data.find_links, '-c', script.scratch_path / - 'constraints.txt', 'TopoRequires2') - assert 'installed TopoRequires-0.0.1' in result.stdout + result = script.pip( + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "constraints.txt", + "TopoRequires2", + ) + assert "installed TopoRequires-0.0.1" in result.stdout def test_multiple_constraints_files(script, data): script.scratch_path.joinpath("outer.txt").write_text("-c inner.txt") - script.scratch_path.joinpath("inner.txt").write_text( - "Upper==1.0") + script.scratch_path.joinpath("inner.txt").write_text("Upper==1.0") result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'outer.txt', 'Upper') - assert 'installed Upper-1.0' in result.stdout + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "outer.txt", + "Upper", + ) + assert "installed Upper-1.0" in result.stdout def test_respect_order_in_requirements_file(script, data): - script.scratch_path.joinpath("frameworks-req.txt").write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("frameworks-req.txt").write_text( + textwrap.dedent( + """\ parent child simple - """)) + """ + ) + ) result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-r', - script.scratch_path / 'frameworks-req.txt' + "install", + "--no-index", + "-f", + data.find_links, + "-r", + script.scratch_path / "frameworks-req.txt", ) - downloaded = [line for line in result.stdout.split('\n') - if 'Processing' in line] + downloaded = [line for line in result.stdout.split("\n") if "Processing" in line] - assert 'parent' in downloaded[0], ( - 'First download should be "parent" but was "{}"'.format(downloaded[0]) - ) - assert 'child' in downloaded[1], ( - 'Second download should be "child" but was "{}"'.format(downloaded[1]) - ) - assert 'simple' in downloaded[2], ( - 'Third download should be "simple" but was "{}"'.format(downloaded[2]) - ) + assert ( + "parent" in downloaded[0] + ), 'First download should be "parent" but was "{}"'.format(downloaded[0]) + assert ( + "child" in downloaded[1] + ), 'Second download should be "child" but was "{}"'.format(downloaded[1]) + assert ( + "simple" in downloaded[2] + ), 'Third download should be "simple" but was "{}"'.format(downloaded[2]) def test_install_local_editable_with_extras(script, data): to_install = data.packages.joinpath("LocalExtras") res = script.pip_install_local( - '-e', to_install + '[bar]', allow_stderr_warning=True + "-e", to_install + "[bar]", allow_stderr_warning=True ) - res.did_update(script.site_packages / 'easy-install.pth') - res.did_create(script.site_packages / 'LocalExtras.egg-link') - res.did_create(script.site_packages / 'simple') + res.did_update(script.site_packages / "easy-install.pth") + res.did_create(script.site_packages / "LocalExtras.egg-link") + res.did_create(script.site_packages / "simple") def test_install_collected_dependencies_first(script): result = script.pip_install_local( - 'toporequires2', + "toporequires2", ) - text = [line for line in result.stdout.split('\n') - if 'Installing' in line][0] - assert text.endswith('toporequires2') + text = [line for line in result.stdout.split("\n") if "Installing" in line][0] + assert text.endswith("toporequires2") @pytest.mark.network def test_install_local_editable_with_subdirectory(script): - version_pkg_path = _create_test_package_with_subdirectory(script, - 'version_subdir') + version_pkg_path = _create_test_package_with_subdirectory(script, "version_subdir") result = script.pip( - 'install', '-e', - '{uri}#egg=version_subpkg&subdirectory=version_subdir'.format( - uri='git+' + path_to_url(version_pkg_path), + "install", + "-e", + "{uri}#egg=version_subpkg&subdirectory=version_subdir".format( + uri="git+" + path_to_url(version_pkg_path), ), ) - result.assert_installed('version-subpkg', sub_dir='version_subdir') + result.assert_installed("version-subpkg", sub_dir="version_subdir") @pytest.mark.network def test_install_local_with_subdirectory(script): - version_pkg_path = _create_test_package_with_subdirectory(script, - 'version_subdir') + version_pkg_path = _create_test_package_with_subdirectory(script, "version_subdir") result = script.pip( - 'install', - '{uri}#egg=version_subpkg&subdirectory=version_subdir'.format( - uri='git+' + path_to_url(version_pkg_path), + "install", + "{uri}#egg=version_subpkg&subdirectory=version_subdir".format( + uri="git+" + path_to_url(version_pkg_path), ), ) - result.assert_installed('version_subpkg.py', editable=False) + result.assert_installed("version_subpkg.py", editable=False) @pytest.mark.incompatible_with_test_venv -def test_wheel_user_with_prefix_in_pydistutils_cfg( - script, data, with_wheel): - if os.name == 'posix': +def test_wheel_user_with_prefix_in_pydistutils_cfg(script, data, with_wheel): + if os.name == "posix": user_filename = ".pydistutils.cfg" else: user_filename = "pydistutils.cfg" - user_cfg = os.path.join(os.path.expanduser('~'), user_filename) + user_cfg = os.path.join(os.path.expanduser("~"), user_filename) script.scratch_path.joinpath("bin").mkdir() with open(user_cfg, "w") as cfg: - cfg.write(textwrap.dedent(""" + cfg.write( + textwrap.dedent( + """ [install] - prefix={script.scratch_path}""".format(**locals()))) + prefix={script.scratch_path}""".format( + **locals() + ) + ) + ) result = script.pip( - 'install', '--user', '--no-index', - '-f', data.find_links, - 'requiresupper') + "install", "--user", "--no-index", "-f", data.find_links, "requiresupper" + ) # Check that we are really installing a wheel - assert 'Running setup.py install for requiresupper' not in result.stdout - assert 'installed requiresupper' in result.stdout + assert "Running setup.py install for requiresupper" not in result.stdout + assert "installed requiresupper" in result.stdout def test_install_option_in_requirements_file_overrides_cli( @@ -316,82 +327,108 @@ def test_install_option_in_requirements_file_overrides_cli( reqs_file.write_text("simple --install-option='-O0'") script.pip( - 'install', '--no-index', '-f', str(simple_sdist.sdist_path.parent), - '-r', str(reqs_file), '--install-option=-O1', + "install", + "--no-index", + "-f", + str(simple_sdist.sdist_path.parent), + "-r", + str(reqs_file), + "--install-option=-O1", ) simple_args = simple_sdist.args() - assert 'install' in simple_args - assert simple_args.index('-O1') < simple_args.index('-O0') + assert "install" in simple_args + assert simple_args.index("-O1") < simple_args.index("-O0") def test_constraints_not_installed_by_default(script, data): script.scratch_path.joinpath("c.txt").write_text("requiresupper") result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'c.txt', 'Upper') - assert 'requiresupper' not in result.stdout + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "c.txt", + "Upper", + ) + assert "requiresupper" not in result.stdout def test_constraints_only_causes_error(script, data): script.scratch_path.joinpath("c.txt").write_text("requiresupper") result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'c.txt', expect_error=True) - assert 'installed requiresupper' not in result.stdout + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "c.txt", + expect_error=True, + ) + assert "installed requiresupper" not in result.stdout def test_constraints_local_editable_install_causes_error(script, data): - script.scratch_path.joinpath("constraints.txt").write_text( - "singlemodule==0.0.0" - ) + script.scratch_path.joinpath("constraints.txt").write_text("singlemodule==0.0.0") to_install = data.src.joinpath("singlemodule") result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'constraints.txt', '-e', - to_install, expect_error=True) - assert 'Could not satisfy constraints for' in result.stderr + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "constraints.txt", + "-e", + to_install, + expect_error=True, + ) + assert "Could not satisfy constraints for" in result.stderr @pytest.mark.network def test_constraints_local_editable_install_pep518(script, data): to_install = data.src.joinpath("pep518-3.0") - script.pip('download', 'setuptools', 'wheel', '-d', data.packages) - script.pip( - 'install', '--no-index', '-f', data.find_links, '-e', to_install) + script.pip("download", "setuptools", "wheel", "-d", data.packages) + script.pip("install", "--no-index", "-f", data.find_links, "-e", to_install) def test_constraints_local_install_causes_error(script, data): - script.scratch_path.joinpath("constraints.txt").write_text( - "singlemodule==0.0.0" - ) + script.scratch_path.joinpath("constraints.txt").write_text("singlemodule==0.0.0") to_install = data.src.joinpath("singlemodule") result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'constraints.txt', - to_install, expect_error=True) - assert 'Could not satisfy constraints for' in result.stderr + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "constraints.txt", + to_install, + expect_error=True, + ) + assert "Could not satisfy constraints for" in result.stderr -def test_constraints_constrain_to_local_editable( - script, - data, - use_new_resolver -): +def test_constraints_constrain_to_local_editable(script, data, use_new_resolver): to_install = data.src.joinpath("singlemodule") script.scratch_path.joinpath("constraints.txt").write_text( "-e {url}#egg=singlemodule".format(url=path_to_url(to_install)) ) result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'constraints.txt', 'singlemodule', + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "constraints.txt", + "singlemodule", allow_stderr_warning=True, - expect_error=use_new_resolver + expect_error=use_new_resolver, ) if use_new_resolver: - assert 'Links are not allowed as constraints' in result.stderr + assert "Links are not allowed as constraints" in result.stderr else: - assert 'Running setup.py develop for singlemodule' in result.stdout + assert "Running setup.py develop for singlemodule" in result.stdout def test_constraints_constrain_to_local(script, data, use_new_resolver): @@ -400,15 +437,20 @@ def test_constraints_constrain_to_local(script, data, use_new_resolver): "{url}#egg=singlemodule".format(url=path_to_url(to_install)) ) result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'constraints.txt', 'singlemodule', + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "constraints.txt", + "singlemodule", allow_stderr_warning=True, - expect_error=use_new_resolver + expect_error=use_new_resolver, ) if use_new_resolver: - assert 'Links are not allowed as constraints' in result.stderr + assert "Links are not allowed as constraints" in result.stderr else: - assert 'Running setup.py install for singlemodule' in result.stdout + assert "Running setup.py install for singlemodule" in result.stdout def test_constrained_to_url_install_same_url(script, data, use_new_resolver): @@ -416,20 +458,23 @@ def test_constrained_to_url_install_same_url(script, data, use_new_resolver): constraints = path_to_url(to_install) + "#egg=singlemodule" script.scratch_path.joinpath("constraints.txt").write_text(constraints) result = script.pip( - 'install', '--no-index', '-f', data.find_links, '-c', - script.scratch_path / 'constraints.txt', to_install, + "install", + "--no-index", + "-f", + data.find_links, + "-c", + script.scratch_path / "constraints.txt", + to_install, allow_stderr_warning=True, - expect_error=use_new_resolver + expect_error=use_new_resolver, ) if use_new_resolver: - assert 'Links are not allowed as constraints' in result.stderr + assert "Links are not allowed as constraints" in result.stderr else: - assert ('Running setup.py install for singlemodule' - in result.stdout), str(result) + assert "Running setup.py install for singlemodule" in result.stdout, str(result) -def test_double_install_spurious_hash_mismatch( - script, tmpdir, data, with_wheel): +def test_double_install_spurious_hash_mismatch(script, tmpdir, data, with_wheel): """Make sure installing the same hashed sdist twice doesn't throw hash mismatch errors. @@ -440,26 +485,32 @@ def test_double_install_spurious_hash_mismatch( """ # Install wheel package, otherwise, it won't try to build wheels. - with requirements_file('simple==1.0 --hash=sha256:393043e672415891885c9a2a' - '0929b1af95fb866d6ca016b42d2e6ce53619b653', - tmpdir) as reqs_file: + with requirements_file( + "simple==1.0 --hash=sha256:393043e672415891885c9a2a" + "0929b1af95fb866d6ca016b42d2e6ce53619b653", + tmpdir, + ) as reqs_file: # Install a package (and build its wheel): result = script.pip_install_local( - '--find-links', data.find_links, - '-r', reqs_file.resolve(), + "--find-links", + data.find_links, + "-r", + reqs_file.resolve(), ) - assert 'Successfully installed simple-1.0' in str(result) + assert "Successfully installed simple-1.0" in str(result) # Uninstall it: - script.pip('uninstall', '-y', 'simple') + script.pip("uninstall", "-y", "simple") # Then install it again. We should not hit a hash mismatch, and the # package should install happily. result = script.pip_install_local( - '--find-links', data.find_links, - '-r', reqs_file.resolve(), + "--find-links", + data.find_links, + "-r", + reqs_file.resolve(), ) - assert 'Successfully installed simple-1.0' in str(result) + assert "Successfully installed simple-1.0" in str(result) def test_install_with_extras_from_constraints(script, data, use_new_resolver): @@ -468,14 +519,16 @@ def test_install_with_extras_from_constraints(script, data, use_new_resolver): "{url}#egg=LocalExtras[bar]".format(url=path_to_url(to_install)) ) result = script.pip_install_local( - '-c', script.scratch_path / 'constraints.txt', 'LocalExtras', + "-c", + script.scratch_path / "constraints.txt", + "LocalExtras", allow_stderr_warning=True, - expect_error=use_new_resolver + expect_error=use_new_resolver, ) if use_new_resolver: - assert 'Links are not allowed as constraints' in result.stderr + assert "Links are not allowed as constraints" in result.stderr else: - result.did_create(script.site_packages / 'simple') + result.did_create(script.site_packages / "simple") def test_install_with_extras_from_install(script): @@ -487,11 +540,13 @@ def test_install_with_extras_from_install(script): ) script.scratch_path.joinpath("constraints.txt").write_text("LocalExtras") result = script.pip_install_local( - '--find-links', script.scratch_path, - '-c', script.scratch_path / 'constraints.txt', - 'LocalExtras[baz]', + "--find-links", + script.scratch_path, + "-c", + script.scratch_path / "constraints.txt", + "LocalExtras[baz]", ) - result.did_create(script.site_packages / 'singlemodule.py') + result.did_create(script.site_packages / "singlemodule.py") def test_install_with_extras_joined(script, data, use_new_resolver): @@ -500,15 +555,17 @@ def test_install_with_extras_joined(script, data, use_new_resolver): "{url}#egg=LocalExtras[bar]".format(url=path_to_url(to_install)) ) result = script.pip_install_local( - '-c', script.scratch_path / 'constraints.txt', 'LocalExtras[baz]', + "-c", + script.scratch_path / "constraints.txt", + "LocalExtras[baz]", allow_stderr_warning=True, - expect_error=use_new_resolver + expect_error=use_new_resolver, ) if use_new_resolver: - assert 'Links are not allowed as constraints' in result.stderr + assert "Links are not allowed as constraints" in result.stderr else: - result.did_create(script.site_packages / 'simple') - result.did_create(script.site_packages / 'singlemodule.py') + result.did_create(script.site_packages / "simple") + result.did_create(script.site_packages / "singlemodule.py") def test_install_with_extras_editable_joined(script, data, use_new_resolver): @@ -517,24 +574,27 @@ def test_install_with_extras_editable_joined(script, data, use_new_resolver): "-e {url}#egg=LocalExtras[bar]".format(url=path_to_url(to_install)) ) result = script.pip_install_local( - '-c', script.scratch_path / 'constraints.txt', 'LocalExtras[baz]', + "-c", + script.scratch_path / "constraints.txt", + "LocalExtras[baz]", allow_stderr_warning=True, - expect_error=use_new_resolver + expect_error=use_new_resolver, ) if use_new_resolver: - assert 'Links are not allowed as constraints' in result.stderr + assert "Links are not allowed as constraints" in result.stderr else: - result.did_create(script.site_packages / 'simple') - result.did_create(script.site_packages / 'singlemodule.py') + result.did_create(script.site_packages / "simple") + result.did_create(script.site_packages / "singlemodule.py") def test_install_distribution_full_union(script, data): to_install = data.packages.joinpath("LocalExtras") result = script.pip_install_local( - to_install, to_install + "[bar]", to_install + "[baz]") - assert 'Running setup.py install for LocalExtras' in result.stdout - result.did_create(script.site_packages / 'simple') - result.did_create(script.site_packages / 'singlemodule.py') + to_install, to_install + "[bar]", to_install + "[baz]" + ) + assert "Running setup.py install for LocalExtras" in result.stdout + result.did_create(script.site_packages / "simple") + result.did_create(script.site_packages / "singlemodule.py") def test_install_distribution_duplicate_extras(script, data): @@ -542,30 +602,28 @@ def test_install_distribution_duplicate_extras(script, data): package_name = to_install + "[bar]" with pytest.raises(AssertionError): result = script.pip_install_local(package_name, package_name) - expected = ( - 'Double requirement given: {package_name}'.format(**locals())) + expected = "Double requirement given: {package_name}".format(**locals()) assert expected in result.stderr -def test_install_distribution_union_with_constraints( - script, - data, - use_new_resolver -): +def test_install_distribution_union_with_constraints(script, data, use_new_resolver): to_install = data.packages.joinpath("LocalExtras") script.scratch_path.joinpath("constraints.txt").write_text( - "{to_install}[bar]".format(**locals())) + "{to_install}[bar]".format(**locals()) + ) result = script.pip_install_local( - '-c', script.scratch_path / 'constraints.txt', to_install + '[baz]', + "-c", + script.scratch_path / "constraints.txt", + to_install + "[baz]", allow_stderr_warning=True, - expect_error=use_new_resolver + expect_error=use_new_resolver, ) if use_new_resolver: - msg = 'Unnamed requirements are not allowed as constraints' + msg = "Unnamed requirements are not allowed as constraints" assert msg in result.stderr else: - assert 'Running setup.py install for LocalExtras' in result.stdout - result.did_create(script.site_packages / 'singlemodule.py') + assert "Running setup.py install for LocalExtras" in result.stdout + result.did_create(script.site_packages / "singlemodule.py") def test_install_distribution_union_with_versions( @@ -585,16 +643,11 @@ def test_install_distribution_union_with_versions( "Cannot install localextras[bar] 0.0.1 and localextras[baz] 0.0.2 " "because these package versions have conflicting dependencies." ) in result.stderr - assert ( - "localextras[bar] 0.0.1 depends on localextras 0.0.1" - ) in result.stdout - assert ( - "localextras[baz] 0.0.2 depends on localextras 0.0.2" - ) in result.stdout + assert ("localextras[bar] 0.0.1 depends on localextras 0.0.1") in result.stdout + assert ("localextras[baz] 0.0.2 depends on localextras 0.0.2") in result.stdout else: assert ( - "Successfully installed LocalExtras-0.0.1 simple-3.0 " - "singlemodule-0.0.1" + "Successfully installed LocalExtras-0.0.1 simple-3.0 " "singlemodule-0.0.1" ) in result.stdout @@ -605,27 +658,30 @@ def test_install_distribution_union_conflicting_extras(script, data): # and simple==2.0. Once a resolver is added, this conflict should be # detected. to_install = data.packages.joinpath("LocalExtras-0.0.2") - result = script.pip_install_local(to_install, to_install + "[bar]", - expect_error=True) - assert 'installed' not in result.stdout + result = script.pip_install_local( + to_install, to_install + "[bar]", expect_error=True + ) + assert "installed" not in result.stdout assert "Conflict" in result.stderr def test_install_unsupported_wheel_link_with_marker(script): script.scratch_path.joinpath("with-marker.txt").write_text( - textwrap.dedent("""\ + textwrap.dedent( + """\ {url}; {req} - """).format( - url='https://github.com/a/b/c/asdf-1.5.2-cp27-none-xyz.whl', + """ + ).format( + url="https://github.com/a/b/c/asdf-1.5.2-cp27-none-xyz.whl", req='sys_platform == "xyz"', ) ) - result = script.pip( - 'install', '-r', script.scratch_path / 'with-marker.txt' - ) + result = script.pip("install", "-r", script.scratch_path / "with-marker.txt") - assert ("Ignoring asdf: markers 'sys_platform == \"xyz\"' don't match " - "your environment") in result.stdout + assert ( + "Ignoring asdf: markers 'sys_platform == \"xyz\"' don't match " + "your environment" + ) in result.stdout assert len(result.files_created) == 0 @@ -633,16 +689,27 @@ def test_install_unsupported_wheel_file(script, data): # Trying to install a local wheel with an incompatible version/type # should fail. path = data.packages.joinpath("simple.dist-0.1-py1-none-invalid.whl") - script.scratch_path.joinpath("wheel-file.txt").write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("wheel-file.txt").write_text( + textwrap.dedent( + """\ {path} - """.format(**locals()))) + """.format( + **locals() + ) + ) + ) result = script.pip( - 'install', '-r', script.scratch_path / 'wheel-file.txt', + "install", + "-r", + script.scratch_path / "wheel-file.txt", expect_error=True, expect_stderr=True, ) - assert ("simple.dist-0.1-py1-none-invalid.whl is not a supported " + - "wheel on this platform" in result.stderr) + assert ( + "simple.dist-0.1-py1-none-invalid.whl is not a supported " + + "wheel on this platform" + in result.stderr + ) assert len(result.files_created) == 0 @@ -668,17 +735,20 @@ def test_install_options_local_to_package(script, arg_recording_sdist_maker): ) ) script.pip( - 'install', - '--no-index', '-f', str(simple1_sdist.sdist_path.parent), - '-r', reqs_file, + "install", + "--no-index", + "-f", + str(simple1_sdist.sdist_path.parent), + "-r", + reqs_file, ) simple1_args = simple1_sdist.args() - assert 'install' in simple1_args - assert '-O0' in simple1_args + assert "install" in simple1_args + assert "-O0" in simple1_args simple2_args = simple2_sdist.args() - assert 'install' in simple2_args - assert '-O0' not in simple2_args + assert "install" in simple2_args + assert "-O0" not in simple2_args def test_location_related_install_option_fails(script): @@ -686,9 +756,12 @@ def test_location_related_install_option_fails(script): reqs_file = script.scratch_path.joinpath("reqs.txt") reqs_file.write_text("simple --install-option='--home=/tmp'") result = script.pip( - 'install', - '--no-index', '-f', str(simple_sdist.parent), - '-r', reqs_file, - expect_error=True + "install", + "--no-index", + "-f", + str(simple_sdist.parent), + "-r", + reqs_file, + expect_error=True, ) assert "['--home'] from simple" in result.stderr diff --git a/tests/functional/test_install_requested.py b/tests/functional/test_install_requested.py index 6caec988eb5..1f3977078ed 100644 --- a/tests/functional/test_install_requested.py +++ b/tests/functional/test_install_requested.py @@ -22,9 +22,7 @@ def test_install_requested_basic(script, data, with_wheel): def test_install_requested_requirements(script, data, with_wheel): - script.scratch_path.joinpath("requirements.txt").write_text( - "require_simple\n" - ) + script.scratch_path.joinpath("requirements.txt").write_text("require_simple\n") result = script.pip( "install", "--no-index", @@ -55,9 +53,7 @@ def test_install_requested_dep_in_requirements(script, data, with_wheel): def test_install_requested_reqs_and_constraints(script, data, with_wheel): - script.scratch_path.joinpath("requirements.txt").write_text( - "require_simple\n" - ) + script.scratch_path.joinpath("requirements.txt").write_text("require_simple\n") script.scratch_path.joinpath("constraints.txt").write_text("simple<3\n") result = script.pip( "install", diff --git a/tests/functional/test_install_upgrade.py b/tests/functional/test_install_upgrade.py index 02e221101c5..15b55df44ae 100644 --- a/tests/functional/test_install_upgrade.py +++ b/tests/functional/test_install_upgrade.py @@ -17,11 +17,11 @@ def test_no_upgrade_unless_requested(script): No upgrade if not specifically requested. """ - script.pip('install', 'INITools==0.1') - result = script.pip('install', 'INITools') - assert not result.files_created, ( - 'pip install INITools upgraded when it should not have' - ) + script.pip("install", "INITools==0.1") + result = script.pip("install", "INITools") + assert ( + not result.files_created + ), "pip install INITools upgraded when it should not have" def test_invalid_upgrade_strategy_causes_error(script): @@ -30,8 +30,7 @@ def test_invalid_upgrade_strategy_causes_error(script): """ result = script.pip_install_local( - '--upgrade', '--upgrade-strategy=bazinga', 'simple', - expect_error=True + "--upgrade", "--upgrade-strategy=bazinga", "simple", expect_error=True ) assert result.returncode @@ -39,27 +38,23 @@ def test_invalid_upgrade_strategy_causes_error(script): def test_only_if_needed_does_not_upgrade_deps_when_satisfied( - script, - use_new_resolver, - with_wheel + script, use_new_resolver, with_wheel ): """ It doesn't upgrade a dependency if it already satisfies the requirements. """ - script.pip_install_local('simple==2.0') + script.pip_install_local("simple==2.0") result = script.pip_install_local( - '--upgrade', '--upgrade-strategy=only-if-needed', 'require_simple' + "--upgrade", "--upgrade-strategy=only-if-needed", "require_simple" ) assert ( - (script.site_packages / 'require_simple-1.0.dist-info') - not in result.files_deleted - ), "should have installed require_simple==1.0" + script.site_packages / "require_simple-1.0.dist-info" + ) not in result.files_deleted, "should have installed require_simple==1.0" assert ( - (script.site_packages / 'simple-2.0.dist-info') - not in result.files_deleted - ), "should not have uninstalled simple==2.0" + script.site_packages / "simple-2.0.dist-info" + ) not in result.files_deleted, "should not have uninstalled simple==2.0" msg = "Requirement already satisfied" if not use_new_resolver: @@ -69,83 +64,62 @@ def test_only_if_needed_does_not_upgrade_deps_when_satisfied( ), "did not print correct message for not-upgraded requirement" -def test_only_if_needed_does_upgrade_deps_when_no_longer_satisfied( - script, with_wheel -): +def test_only_if_needed_does_upgrade_deps_when_no_longer_satisfied(script, with_wheel): """ It does upgrade a dependency if it no longer satisfies the requirements. """ - script.pip_install_local('simple==1.0') + script.pip_install_local("simple==1.0") result = script.pip_install_local( - '--upgrade', '--upgrade-strategy=only-if-needed', 'require_simple' + "--upgrade", "--upgrade-strategy=only-if-needed", "require_simple" ) assert ( - (script.site_packages / 'require_simple-1.0.dist-info') - not in result.files_deleted - ), "should have installed require_simple==1.0" - expected = ( - script.site_packages / - 'simple-3.0.dist-info' - ) + script.site_packages / "require_simple-1.0.dist-info" + ) not in result.files_deleted, "should have installed require_simple==1.0" + expected = script.site_packages / "simple-3.0.dist-info" result.did_create(expected, message="should have installed simple==3.0") - expected = ( - script.site_packages / - 'simple-1.0.dist-info' - ) - assert ( - expected in result.files_deleted - ), "should have uninstalled simple==1.0" + expected = script.site_packages / "simple-1.0.dist-info" + assert expected in result.files_deleted, "should have uninstalled simple==1.0" -def test_eager_does_upgrade_dependecies_when_currently_satisfied( - script, with_wheel -): +def test_eager_does_upgrade_dependecies_when_currently_satisfied(script, with_wheel): """ It does upgrade a dependency even if it already satisfies the requirements. """ - script.pip_install_local('simple==2.0') + script.pip_install_local("simple==2.0") result = script.pip_install_local( - '--upgrade', '--upgrade-strategy=eager', 'require_simple' + "--upgrade", "--upgrade-strategy=eager", "require_simple" ) assert ( - (script.site_packages / - 'require_simple-1.0.dist-info') - not in result.files_deleted - ), "should have installed require_simple==1.0" + script.site_packages / "require_simple-1.0.dist-info" + ) not in result.files_deleted, "should have installed require_simple==1.0" assert ( - (script.site_packages / - 'simple-2.0.dist-info') - in result.files_deleted - ), "should have uninstalled simple==2.0" + script.site_packages / "simple-2.0.dist-info" + ) in result.files_deleted, "should have uninstalled simple==2.0" -def test_eager_does_upgrade_dependecies_when_no_longer_satisfied( - script, with_wheel -): +def test_eager_does_upgrade_dependecies_when_no_longer_satisfied(script, with_wheel): """ It does upgrade a dependency if it no longer satisfies the requirements. """ - script.pip_install_local('simple==1.0') + script.pip_install_local("simple==1.0") result = script.pip_install_local( - '--upgrade', '--upgrade-strategy=eager', 'require_simple' + "--upgrade", "--upgrade-strategy=eager", "require_simple" ) assert ( - (script.site_packages / 'require_simple-1.0.dist-info') - not in result.files_deleted - ), "should have installed require_simple==1.0" + script.site_packages / "require_simple-1.0.dist-info" + ) not in result.files_deleted, "should have installed require_simple==1.0" result.did_create( - script.site_packages / 'simple-3.0.dist-info', - message="should have installed simple==3.0" + script.site_packages / "simple-3.0.dist-info", + message="should have installed simple==3.0", ) assert ( - script.site_packages / 'simple-1.0.dist-info' - in result.files_deleted + script.site_packages / "simple-1.0.dist-info" in result.files_deleted ), "should have uninstalled simple==1.0" @@ -155,18 +129,11 @@ def test_upgrade_to_specific_version(script, with_wheel): It does upgrade to specific version requested. """ - script.pip('install', 'INITools==0.1') - result = script.pip('install', 'INITools==0.2') - assert result.files_created, ( - 'pip install with specific version did not upgrade' - ) - assert ( - script.site_packages / 'INITools-0.1.dist-info' - in result.files_deleted - ) - result.did_create( - script.site_packages / 'INITools-0.2.dist-info' - ) + script.pip("install", "INITools==0.1") + result = script.pip("install", "INITools==0.2") + assert result.files_created, "pip install with specific version did not upgrade" + assert script.site_packages / "INITools-0.1.dist-info" in result.files_deleted + result.did_create(script.site_packages / "INITools-0.2.dist-info") @pytest.mark.network @@ -175,13 +142,10 @@ def test_upgrade_if_requested(script, with_wheel): And it does upgrade if requested. """ - script.pip('install', 'INITools==0.1') - result = script.pip('install', '--upgrade', 'INITools') - assert result.files_created, 'pip install --upgrade did not upgrade' - result.did_not_create( - script.site_packages / - 'INITools-0.1.dist-info' - ) + script.pip("install", "INITools==0.1") + result = script.pip("install", "--upgrade", "INITools") + assert result.files_created, "pip install --upgrade did not upgrade" + result.did_not_create(script.site_packages / "INITools-0.1.dist-info") def test_upgrade_with_newest_already_installed(script, data, use_new_resolver): @@ -189,11 +153,11 @@ def test_upgrade_with_newest_already_installed(script, data, use_new_resolver): If the newest version of a package is already installed, the package should not be reinstalled and the user should be informed. """ - script.pip('install', '-f', data.find_links, '--no-index', 'simple') + script.pip("install", "-f", data.find_links, "--no-index", "simple") result = script.pip( - 'install', '--upgrade', '-f', data.find_links, '--no-index', 'simple' + "install", "--upgrade", "-f", data.find_links, "--no-index", "simple" ) - assert not result.files_created, 'simple upgraded when it should not have' + assert not result.files_created, "simple upgraded when it should not have" if use_new_resolver: msg = "Requirement already satisfied" else: @@ -207,14 +171,12 @@ def test_upgrade_force_reinstall_newest(script): Force reinstallation of a package even if it is already at its newest version if --force-reinstall is supplied. """ - result = script.pip('install', 'INITools') - result.did_create(script.site_packages / 'initools') - result2 = script.pip( - 'install', '--upgrade', '--force-reinstall', 'INITools' - ) - assert result2.files_updated, 'upgrade to INITools 0.3 failed' - result3 = script.pip('uninstall', 'initools', '-y') - assert_all_changes(result, result3, [script.venv / 'build', 'cache']) + result = script.pip("install", "INITools") + result.did_create(script.site_packages / "initools") + result2 = script.pip("install", "--upgrade", "--force-reinstall", "INITools") + assert result2.files_updated, "upgrade to INITools 0.3 failed" + result3 = script.pip("uninstall", "initools", "-y") + assert_all_changes(result, result3, [script.venv / "build", "cache"]) @pytest.mark.network @@ -223,12 +185,12 @@ def test_uninstall_before_upgrade(script): Automatic uninstall-before-upgrade. """ - result = script.pip('install', 'INITools==0.2') - result.did_create(script.site_packages / 'initools') - result2 = script.pip('install', 'INITools==0.3') - assert result2.files_created, 'upgrade to INITools 0.3 failed' - result3 = script.pip('uninstall', 'initools', '-y') - assert_all_changes(result, result3, [script.venv / 'build', 'cache']) + result = script.pip("install", "INITools==0.2") + result.did_create(script.site_packages / "initools") + result2 = script.pip("install", "INITools==0.3") + assert result2.files_created, "upgrade to INITools 0.3 failed" + result3 = script.pip("uninstall", "initools", "-y") + assert_all_changes(result, result3, [script.venv / "build", "cache"]) @pytest.mark.network @@ -237,16 +199,16 @@ def test_uninstall_before_upgrade_from_url(script): Automatic uninstall-before-upgrade from URL. """ - result = script.pip('install', 'INITools==0.2') - result.did_create(script.site_packages / 'initools') + result = script.pip("install", "INITools==0.2") + result.did_create(script.site_packages / "initools") result2 = script.pip( - 'install', - 'https://files.pythonhosted.org/packages/source/I/INITools/INITools-' - '0.3.tar.gz', + "install", + "https://files.pythonhosted.org/packages/source/I/INITools/INITools-" + "0.3.tar.gz", ) - assert result2.files_created, 'upgrade to INITools 0.3 failed' - result3 = script.pip('uninstall', 'initools', '-y') - assert_all_changes(result, result3, [script.venv / 'build', 'cache']) + assert result2.files_created, "upgrade to INITools 0.3 failed" + result3 = script.pip("uninstall", "initools", "-y") + assert_all_changes(result, result3, [script.venv / "build", "cache"]) @pytest.mark.network @@ -256,18 +218,18 @@ def test_upgrade_to_same_version_from_url(script): need to uninstall and reinstall if --upgrade is not specified. """ - result = script.pip('install', 'INITools==0.3') - result.did_create(script.site_packages / 'initools') + result = script.pip("install", "INITools==0.3") + result.did_create(script.site_packages / "initools") result2 = script.pip( - 'install', - 'https://files.pythonhosted.org/packages/source/I/INITools/INITools-' - '0.3.tar.gz', + "install", + "https://files.pythonhosted.org/packages/source/I/INITools/INITools-" + "0.3.tar.gz", ) - assert script.site_packages / 'initools' not in result2.files_updated, ( - 'INITools 0.3 reinstalled same version' - ) - result3 = script.pip('uninstall', 'initools', '-y') - assert_all_changes(result, result3, [script.venv / 'build', 'cache']) + assert ( + script.site_packages / "initools" not in result2.files_updated + ), "INITools 0.3 reinstalled same version" + result3 = script.pip("uninstall", "initools", "-y") + assert_all_changes(result, result3, [script.venv / "build", "cache"]) @pytest.mark.network @@ -276,29 +238,33 @@ def test_upgrade_from_reqs_file(script): Upgrade from a requirements file. """ - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """\ PyLogo<0.4 # and something else to test out: INITools==0.3 - """)) - install_result = script.pip( - 'install', '-r', script.scratch_path / 'test-req.txt' + """ + ) ) - script.scratch_path.joinpath("test-req.txt").write_text(textwrap.dedent("""\ + install_result = script.pip("install", "-r", script.scratch_path / "test-req.txt") + script.scratch_path.joinpath("test-req.txt").write_text( + textwrap.dedent( + """\ PyLogo # and something else to test out: INITools - """)) - script.pip( - 'install', '--upgrade', '-r', script.scratch_path / 'test-req.txt' + """ + ) ) + script.pip("install", "--upgrade", "-r", script.scratch_path / "test-req.txt") uninstall_result = script.pip( - 'uninstall', '-r', script.scratch_path / 'test-req.txt', '-y' + "uninstall", "-r", script.scratch_path / "test-req.txt", "-y" ) assert_all_changes( install_result, uninstall_result, - [script.venv / 'build', 'cache', script.scratch / 'test-req.txt'], + [script.venv / "build", "cache", script.scratch / "test-req.txt"], ) @@ -308,22 +274,25 @@ def test_uninstall_rollback(script, data): crafted to fail on install). """ - result = script.pip( - 'install', '-f', data.find_links, '--no-index', 'broken==0.1' - ) - result.did_create(script.site_packages / 'broken.py') + result = script.pip("install", "-f", data.find_links, "--no-index", "broken==0.1") + result.did_create(script.site_packages / "broken.py") result2 = script.pip( - 'install', '-f', data.find_links, '--no-index', 'broken===0.2broken', + "install", + "-f", + data.find_links, + "--no-index", + "broken===0.2broken", expect_error=True, ) assert result2.returncode == 1, str(result2) - assert script.run( - 'python', '-c', "import broken; print(broken.VERSION)" - ).stdout == '0.1\n' + assert ( + script.run("python", "-c", "import broken; print(broken.VERSION)").stdout + == "0.1\n" + ) assert_all_changes( result.files_after, result2, - [script.venv / 'build'], + [script.venv / "build"], ) @@ -333,17 +302,11 @@ def test_should_not_install_always_from_cache(script, with_wheel): If there is an old cached package, pip should download the newer version Related to issue #175 """ - script.pip('install', 'INITools==0.2') - script.pip('uninstall', '-y', 'INITools') - result = script.pip('install', 'INITools==0.1') - result.did_not_create( - script.site_packages / - 'INITools-0.2.dist-info' - ) - result.did_create( - script.site_packages / - 'INITools-0.1.dist-info' - ) + script.pip("install", "INITools==0.2") + script.pip("uninstall", "-y", "INITools") + result = script.pip("install", "INITools==0.1") + result.did_not_create(script.site_packages / "INITools-0.2.dist-info") + result.did_create(script.site_packages / "INITools-0.1.dist-info") @pytest.mark.network @@ -351,18 +314,12 @@ def test_install_with_ignoreinstalled_requested(script, with_wheel): """ Test old conflicting package is completely ignored """ - script.pip('install', 'INITools==0.1') - result = script.pip('install', '-I', 'INITools==0.3') - assert result.files_created, 'pip install -I did not install' + script.pip("install", "INITools==0.1") + result = script.pip("install", "-I", "INITools==0.3") + assert result.files_created, "pip install -I did not install" # both the old and new metadata should be present. - assert os.path.exists( - script.site_packages_path / - 'INITools-0.1.dist-info' - ) - assert os.path.exists( - script.site_packages_path / - 'INITools-0.3.dist-info' - ) + assert os.path.exists(script.site_packages_path / "INITools-0.1.dist-info") + assert os.path.exists(script.site_packages_path / "INITools-0.3.dist-info") @pytest.mark.network @@ -370,7 +327,8 @@ def test_upgrade_vcs_req_with_no_dists_found(script, tmpdir): """It can upgrade a VCS requirement that has no distributions otherwise.""" req = "{checkout}#egg=pip-test-package".format( checkout=local_checkout( - "git+https://github.com/pypa/pip-test-package.git", tmpdir, + "git+https://github.com/pypa/pip-test-package.git", + tmpdir, ) ) script.pip("install", req) @@ -383,13 +341,11 @@ def test_upgrade_vcs_req_with_dist_found(script): """It can upgrade a VCS requirement that has distributions on the index.""" # TODO(pnasrat) Using local_checkout fails on windows - oddness with the # test path urls/git. - req = ( - "{url}#egg=pretend".format( - url=( - "git+git://github.com/alex/pretend@e7f26ad7dbcb4a02a4995aade4" - "743aad47656b27" - ), - ) + req = "{url}#egg=pretend".format( + url=( + "git+git://github.com/alex/pretend@e7f26ad7dbcb4a02a4995aade4" + "743aad47656b27" + ), ) script.pip("install", req, expect_stderr=True) result = script.pip("install", "-U", req, expect_stderr=True) @@ -421,31 +377,38 @@ class TestUpgradeDistributeToSetuptools(object): def prep_ve(self, script, version, pip_src, distribute=False): self.script = script - self.script.pip_install_local( - 'virtualenv=={version}'.format(**locals())) - args = ['virtualenv', self.script.scratch_path / 'VE'] + self.script.pip_install_local("virtualenv=={version}".format(**locals())) + args = ["virtualenv", self.script.scratch_path / "VE"] if distribute: - args.insert(1, '--distribute') + args.insert(1, "--distribute") if version == "1.9.1" and not distribute: # setuptools 0.6 didn't support PYTHONDONTWRITEBYTECODE del self.script.environ["PYTHONDONTWRITEBYTECODE"] self.script.run(*args) - if sys.platform == 'win32': + if sys.platform == "win32": bindir = "Scripts" else: bindir = "bin" - self.ve_bin = self.script.scratch_path / 'VE' / bindir - self.script.run(self.ve_bin / 'pip', 'uninstall', '-y', 'pip') + self.ve_bin = self.script.scratch_path / "VE" / bindir + self.script.run(self.ve_bin / "pip", "uninstall", "-y", "pip") self.script.run( - self.ve_bin / 'python', 'setup.py', 'install', + self.ve_bin / "python", + "setup.py", + "install", cwd=pip_src, expect_stderr=True, ) -@pytest.mark.parametrize("req1, req2", list(itertools.product( - ["foo.bar", "foo_bar", "foo-bar"], ["foo.bar", "foo_bar", "foo-bar"], -))) +@pytest.mark.parametrize( + "req1, req2", + list( + itertools.product( + ["foo.bar", "foo_bar", "foo-bar"], + ["foo.bar", "foo_bar", "foo-bar"], + ) + ), +) def test_install_find_existing_package_canonicalize(script, req1, req2): """Ensure an already-installed dist is found no matter how the dist name was normalized on installation. (pypa/pip#8645) @@ -468,7 +431,11 @@ def test_install_find_existing_package_canonicalize(script, req1, req2): # Ensure the previously installed package can be correctly used to match # the dependency. result = script.pip( - "install", "--no-index", "--find-links", pkg_container, "pkg", + "install", + "--no-index", + "--find-links", + pkg_container, + "pkg", ) satisfied_message = "Requirement already satisfied: {}".format(req2) assert satisfied_message in result.stdout, str(result) diff --git a/tests/functional/test_install_user.py b/tests/functional/test_install_user.py index c5d7acced80..3cc10eed435 100644 --- a/tests/functional/test_install_user.py +++ b/tests/functional/test_install_user.py @@ -17,7 +17,8 @@ def _patch_dist_in_site_packages(virtualenv): # error: Monkey patch `pip._internal.req.req_install.dist_in_site_packages` # and `pip._internal.resolution.resolvelib.factory.dist_in_site_packages` # so it's possible to install a conflicting distribution in the user site. - virtualenv.sitecustomize = textwrap.dedent(""" + virtualenv.sitecustomize = textwrap.dedent( + """ def dist_in_site_packages(dist): return False @@ -25,67 +26,71 @@ def dist_in_site_packages(dist): from pip._internal.resolution.resolvelib import factory req_install.dist_in_site_packages = dist_in_site_packages factory.dist_in_site_packages = dist_in_site_packages - """) + """ + ) class Tests_UserSite: - @pytest.mark.network @pytest.mark.incompatible_with_test_venv def test_reset_env_system_site_packages_usersite(self, script): """ Check user site works as expected. """ - script.pip('install', '--user', 'INITools==0.2') + script.pip("install", "--user", "INITools==0.2") result = script.run( - 'python', '-c', + "python", + "-c", "import pkg_resources; print(pkg_resources.get_distribution" "('initools').project_name)", ) project_name = result.stdout.strip() - assert 'INITools' == project_name, project_name + assert "INITools" == project_name, project_name @pytest.mark.xfail @pytest.mark.network @need_svn @pytest.mark.incompatible_with_test_venv - def test_install_subversion_usersite_editable_with_distribute( - self, script, tmpdir): + def test_install_subversion_usersite_editable_with_distribute(self, script, tmpdir): """ Test installing current directory ('.') into usersite after installing distribute """ result = script.pip( - 'install', '--user', '-e', - '{checkout}#egg=initools'.format( + "install", + "--user", + "-e", + "{checkout}#egg=initools".format( checkout=local_checkout( - 'svn+http://svn.colorstudy.com/INITools', tmpdir) - ) + "svn+http://svn.colorstudy.com/INITools", tmpdir + ) + ), ) - result.assert_installed('INITools', use_user_site=True) + result.assert_installed("INITools", use_user_site=True) @pytest.mark.incompatible_with_test_venv def test_install_from_current_directory_into_usersite( - self, script, data, with_wheel): + self, script, data, with_wheel + ): """ Test installing current directory ('.') into usersite """ run_from = data.packages.joinpath("FSPkg") result = script.pip( - 'install', '-vvv', '--user', curdir, + "install", + "-vvv", + "--user", + curdir, cwd=run_from, ) - fspkg_folder = script.user_site / 'fspkg' + fspkg_folder = script.user_site / "fspkg" result.did_create(fspkg_folder) - dist_info_folder = ( - script.user_site / 'FSPkg-0.1.dev0.dist-info' - ) + dist_info_folder = script.user_site / "FSPkg-0.1.dev0.dist-info" result.did_create(dist_info_folder) - def test_install_user_venv_nositepkgs_fails(self, virtualenv, - script, data): + def test_install_user_venv_nositepkgs_fails(self, virtualenv, script, data): """ user install in virtualenv (with no system packages) fails with message """ @@ -94,7 +99,9 @@ def test_install_user_venv_nositepkgs_fails(self, virtualenv, virtualenv.user_site_packages = False run_from = data.packages.joinpath("FSPkg") result = script.pip( - 'install', '--user', curdir, + "install", + "--user", + curdir, cwd=run_from, expect_error=True, ) @@ -110,21 +117,21 @@ def test_install_user_conflict_in_usersite(self, script): Test user install with conflict in usersite updates usersite. """ - script.pip('install', '--user', 'INITools==0.3', '--no-binary=:all:') + script.pip("install", "--user", "INITools==0.3", "--no-binary=:all:") - result2 = script.pip( - 'install', '--user', 'INITools==0.1', '--no-binary=:all:') + result2 = script.pip("install", "--user", "INITools==0.1", "--no-binary=:all:") # usersite has 0.1 # we still test for egg-info because no-binary implies setup.py install egg_info_folder = ( - script.user_site / - 'INITools-0.1-py{pyversion}.egg-info'.format(**globals()) + script.user_site / "INITools-0.1-py{pyversion}.egg-info".format(**globals()) ) initools_v3_file = ( # file only in 0.3 - script.base_path / script.user_site / 'initools' / - 'configparser.py' + script.base_path + / script.user_site + / "initools" + / "configparser.py" ) result2.did_create(egg_info_folder) assert not isfile(initools_v3_file), initools_v3_file @@ -138,27 +145,26 @@ def test_install_user_conflict_in_globalsite(self, virtualenv, script): """ _patch_dist_in_site_packages(virtualenv) - script.pip('install', 'INITools==0.2', '--no-binary=:all:') + script.pip("install", "INITools==0.2", "--no-binary=:all:") - result2 = script.pip( - 'install', '--user', 'INITools==0.1', '--no-binary=:all:') + result2 = script.pip("install", "--user", "INITools==0.1", "--no-binary=:all:") # usersite has 0.1 # we still test for egg-info because no-binary implies setup.py install egg_info_folder = ( - script.user_site / - 'INITools-0.1-py{pyversion}.egg-info'.format(**globals()) + script.user_site / "INITools-0.1-py{pyversion}.egg-info".format(**globals()) ) - initools_folder = script.user_site / 'initools' + initools_folder = script.user_site / "initools" result2.did_create(egg_info_folder) result2.did_create(initools_folder) # site still has 0.2 (can't look in result1; have to check) egg_info_folder = ( - script.base_path / script.site_packages / - 'INITools-0.2-py{pyversion}.egg-info'.format(**globals()) + script.base_path + / script.site_packages + / "INITools-0.2-py{pyversion}.egg-info".format(**globals()) ) - initools_folder = script.base_path / script.site_packages / 'initools' + initools_folder = script.base_path / script.site_packages / "initools" assert isdir(egg_info_folder) assert isdir(initools_folder) @@ -171,85 +177,89 @@ def test_upgrade_user_conflict_in_globalsite(self, virtualenv, script): """ _patch_dist_in_site_packages(virtualenv) - script.pip('install', 'INITools==0.2', '--no-binary=:all:') + script.pip("install", "INITools==0.2", "--no-binary=:all:") result2 = script.pip( - 'install', '--user', '--upgrade', 'INITools', '--no-binary=:all:') + "install", "--user", "--upgrade", "INITools", "--no-binary=:all:" + ) # usersite has 0.3.1 # we still test for egg-info because no-binary implies setup.py install egg_info_folder = ( - script.user_site / - 'INITools-0.3.1-py{pyversion}.egg-info'.format(**globals()) + script.user_site + / "INITools-0.3.1-py{pyversion}.egg-info".format(**globals()) ) - initools_folder = script.user_site / 'initools' + initools_folder = script.user_site / "initools" result2.did_create(egg_info_folder) result2.did_create(initools_folder) # site still has 0.2 (can't look in result1; have to check) egg_info_folder = ( - script.base_path / script.site_packages / - 'INITools-0.2-py{pyversion}.egg-info'.format(**globals()) + script.base_path + / script.site_packages + / "INITools-0.2-py{pyversion}.egg-info".format(**globals()) ) - initools_folder = script.base_path / script.site_packages / 'initools' + initools_folder = script.base_path / script.site_packages / "initools" assert isdir(egg_info_folder), result2.stdout assert isdir(initools_folder) @pytest.mark.network @pytest.mark.incompatible_with_test_venv - def test_install_user_conflict_in_globalsite_and_usersite( - self, virtualenv, script): + def test_install_user_conflict_in_globalsite_and_usersite(self, virtualenv, script): """ Test user install with conflict in globalsite and usersite ignores global site and updates usersite. """ _patch_dist_in_site_packages(virtualenv) - script.pip('install', 'INITools==0.2', '--no-binary=:all:') - script.pip('install', '--user', 'INITools==0.3', '--no-binary=:all:') + script.pip("install", "INITools==0.2", "--no-binary=:all:") + script.pip("install", "--user", "INITools==0.3", "--no-binary=:all:") - result3 = script.pip( - 'install', '--user', 'INITools==0.1', '--no-binary=:all:') + result3 = script.pip("install", "--user", "INITools==0.1", "--no-binary=:all:") # usersite has 0.1 # we still test for egg-info because no-binary implies setup.py install egg_info_folder = ( - script.user_site / - 'INITools-0.1-py{pyversion}.egg-info'.format(**globals()) + script.user_site / "INITools-0.1-py{pyversion}.egg-info".format(**globals()) ) initools_v3_file = ( # file only in 0.3 - script.base_path / script.user_site / 'initools' / - 'configparser.py' + script.base_path + / script.user_site + / "initools" + / "configparser.py" ) result3.did_create(egg_info_folder) assert not isfile(initools_v3_file), initools_v3_file # site still has 0.2 (can't just look in result1; have to check) egg_info_folder = ( - script.base_path / script.site_packages / - 'INITools-0.2-py{pyversion}.egg-info'.format(**globals()) + script.base_path + / script.site_packages + / "INITools-0.2-py{pyversion}.egg-info".format(**globals()) ) - initools_folder = script.base_path / script.site_packages / 'initools' + initools_folder = script.base_path / script.site_packages / "initools" assert isdir(egg_info_folder) assert isdir(initools_folder) @pytest.mark.network @pytest.mark.incompatible_with_test_venv - def test_install_user_in_global_virtualenv_with_conflict_fails( - self, script): + def test_install_user_in_global_virtualenv_with_conflict_fails(self, script): """ Test user install in --system-site-packages virtualenv with conflict in site fails. """ - script.pip('install', 'INITools==0.2') + script.pip("install", "INITools==0.2") result2 = script.pip( - 'install', '--user', 'INITools==0.1', + "install", + "--user", + "INITools==0.1", expect_error=True, ) resultp = script.run( - 'python', '-c', + "python", + "-c", "import pkg_resources; print(pkg_resources.get_distribution" "('initools').location)", ) @@ -257,7 +267,7 @@ def test_install_user_in_global_virtualenv_with_conflict_fails( assert ( "Will not install to the user site because it will lack sys.path " "precedence to {name} in {location}".format( - name='INITools', + name="INITools", location=dist_location, ) in result2.stderr diff --git a/tests/functional/test_install_vcs_git.py b/tests/functional/test_install_vcs_git.py index 59393d34747..c630551ffa3 100644 --- a/tests/functional/test_install_vcs_git.py +++ b/tests/functional/test_install_vcs_git.py @@ -18,7 +18,7 @@ def _get_editable_repo_dir(script, package_name): """ Return the repository directory for an editable install. """ - return script.venv_path / 'src' / package_name + return script.venv_path / "src" / package_name def _get_editable_branch(script, package_name): @@ -26,19 +26,15 @@ def _get_editable_branch(script, package_name): Return the current branch of an editable install. """ repo_dir = _get_editable_repo_dir(script, package_name) - result = script.run( - 'git', 'rev-parse', '--abbrev-ref', 'HEAD', cwd=repo_dir - ) + result = script.run("git", "rev-parse", "--abbrev-ref", "HEAD", cwd=repo_dir) return result.stdout.strip() def _get_branch_remote(script, package_name, branch): - """ - - """ + """""" repo_dir = _get_editable_repo_dir(script, package_name) result = script.run( - 'git', 'config', 'branch.{}.remote'.format(branch), cwd=repo_dir + "git", "config", "branch.{}.remote".format(branch), cwd=repo_dir ) return result.stdout.strip() @@ -56,13 +52,13 @@ def _github_checkout(url_path, temp_dir, rev=None, egg=None, scheme=None): scheme: the scheme without the "git+" prefix. Defaults to "https". """ if scheme is None: - scheme = 'https' - url = 'git+{}://github.com/{}'.format(scheme, url_path) + scheme = "https" + url = "git+{}://github.com/{}".format(scheme, url_path) local_url = local_checkout(url, temp_dir) if rev is not None: - local_url += '@{}'.format(rev) + local_url += "@{}".format(rev) if egg is not None: - local_url += '#egg={}'.format(egg) + local_url += "#egg={}".format(egg) return local_url @@ -77,8 +73,8 @@ def _make_version_pkg_url(path, rev=None, name="version_pkg"): rev: an optional revision to install like a branch name, tag, or SHA. """ file_url = _test_path_to_file_url(path) - url_rev = '' if rev is None else '@{}'.format(rev) - url = 'git+{}{}#egg={}'.format(file_url, url_rev, name) + url_rev = "" if rev is None else "@{}".format(rev) + url = "git+{}{}#egg={}".format(file_url, url_rev, name) return url @@ -94,7 +90,7 @@ def _install_version_pkg_only(script, path, rev=None, expect_stderr=False): rev: an optional revision to install like a branch name or tag. """ version_pkg_url = _make_version_pkg_url(path, rev=rev) - script.pip('install', '-e', version_pkg_url, expect_stderr=expect_stderr) + script.pip("install", "-e", version_pkg_url, expect_stderr=expect_stderr) def _install_version_pkg(script, path, rev=None, expect_stderr=False): @@ -108,9 +104,12 @@ def _install_version_pkg(script, path, rev=None, expect_stderr=False): rev: an optional revision to install like a branch name or tag. """ _install_version_pkg_only( - script, path, rev=rev, expect_stderr=expect_stderr, + script, + path, + rev=rev, + expect_stderr=expect_stderr, ) - result = script.run('version_pkg') + result = script.run("version_pkg") version = result.stdout.strip() return version @@ -127,11 +126,11 @@ def test_git_install_again_after_changes(script): """ version_pkg_path = _create_test_package(script) version = _install_version_pkg(script, version_pkg_path) - assert version == '0.1' + assert version == "0.1" _change_test_package_version(script, version_pkg_path) version = _install_version_pkg(script, version_pkg_path) - assert version == 'some different version' + assert version == "some different version" def test_git_install_branch_again_after_branch_changes(script): @@ -140,12 +139,12 @@ def test_git_install_branch_again_after_branch_changes(script): repository. """ version_pkg_path = _create_test_package(script) - version = _install_version_pkg(script, version_pkg_path, rev='master') - assert version == '0.1' + version = _install_version_pkg(script, version_pkg_path, rev="master") + assert version == "0.1" _change_test_package_version(script, version_pkg_path) - version = _install_version_pkg(script, version_pkg_path, rev='master') - assert version == 'some different version' + version = _install_version_pkg(script, version_pkg_path, rev="master") + assert version == "some different version" @pytest.mark.network @@ -153,10 +152,10 @@ def test_install_editable_from_git_with_https(script, tmpdir): """ Test cloning from Git with https. """ - url_path = 'pypa/pip-test-package.git' - local_url = _github_checkout(url_path, tmpdir, egg='pip-test-package') - result = script.pip('install', '-e', local_url) - result.assert_installed('pip-test-package', with_files=['.git']) + url_path = "pypa/pip-test-package.git" + local_url = _github_checkout(url_path, tmpdir, egg="pip-test-package") + result = script.pip("install", "-e", local_url) + result.assert_installed("pip-test-package", with_files=[".git"]) @pytest.mark.network @@ -165,17 +164,12 @@ def test_install_noneditable_git(script, tmpdir, with_wheel): Test installing from a non-editable git URL with a given tag. """ result = script.pip( - 'install', - 'git+https://github.com/pypa/pip-test-package.git' - '@0.1.1#egg=pip-test-package' + "install", + "git+https://github.com/pypa/pip-test-package.git" + "@0.1.1#egg=pip-test-package", ) - dist_info_folder = ( - script.site_packages / - 'pip_test_package-0.1.1.dist-info' - ) - result.assert_installed('piptestpackage', - without_egg_link=True, - editable=False) + dist_info_folder = script.site_packages / "pip_test_package-0.1.1.dist-info" + result.assert_installed("piptestpackage", without_egg_link=True, editable=False) result.did_create(dist_info_folder) @@ -186,11 +180,13 @@ def test_git_with_sha1_revisions(script): version_pkg_path = _create_test_package(script) _change_test_package_version(script, version_pkg_path) sha1 = script.run( - 'git', 'rev-parse', 'HEAD~1', + "git", + "rev-parse", + "HEAD~1", cwd=version_pkg_path, ).stdout.strip() version = _install_version_pkg(script, version_pkg_path, rev=sha1) - assert '0.1' == version + assert "0.1" == version def test_git_with_short_sha1_revisions(script): @@ -200,11 +196,13 @@ def test_git_with_short_sha1_revisions(script): version_pkg_path = _create_test_package(script) _change_test_package_version(script, version_pkg_path) sha1 = script.run( - 'git', 'rev-parse', 'HEAD~1', + "git", + "rev-parse", + "HEAD~1", cwd=version_pkg_path, ).stdout.strip()[:7] version = _install_version_pkg(script, version_pkg_path, rev=sha1) - assert '0.1' == version + assert "0.1" == version def test_git_with_branch_name_as_revision(script): @@ -212,11 +210,11 @@ def test_git_with_branch_name_as_revision(script): Git backend should be able to install from branch names """ version_pkg_path = _create_test_package(script) - branch = 'test_branch' - script.run('git', 'checkout', '-b', branch, cwd=version_pkg_path) + branch = "test_branch" + script.run("git", "checkout", "-b", branch, cwd=version_pkg_path) _change_test_package_version(script, version_pkg_path) version = _install_version_pkg(script, version_pkg_path, rev=branch) - assert 'some different version' == version + assert "some different version" == version def test_git_with_tag_name_as_revision(script): @@ -224,17 +222,17 @@ def test_git_with_tag_name_as_revision(script): Git backend should be able to install from tag names """ version_pkg_path = _create_test_package(script) - script.run('git', 'tag', 'test_tag', cwd=version_pkg_path) + script.run("git", "tag", "test_tag", cwd=version_pkg_path) _change_test_package_version(script, version_pkg_path) - version = _install_version_pkg(script, version_pkg_path, rev='test_tag') - assert '0.1' == version + version = _install_version_pkg(script, version_pkg_path, rev="test_tag") + assert "0.1" == version def _add_ref(script, path, ref): """ Add a new ref to a repository at the given path. """ - script.run('git', 'update-ref', ref, 'HEAD', cwd=path) + script.run("git", "update-ref", ref, "HEAD", cwd=path) def test_git_install_ref(script): @@ -242,13 +240,15 @@ def test_git_install_ref(script): The Git backend should be able to install a ref with the first install. """ version_pkg_path = _create_test_package(script) - _add_ref(script, version_pkg_path, 'refs/foo/bar') + _add_ref(script, version_pkg_path, "refs/foo/bar") _change_test_package_version(script, version_pkg_path) version = _install_version_pkg( - script, version_pkg_path, rev='refs/foo/bar', + script, + version_pkg_path, + rev="refs/foo/bar", ) - assert '0.1' == version + assert "0.1" == version def test_git_install_then_install_ref(script): @@ -257,17 +257,19 @@ def test_git_install_then_install_ref(script): already been installed. """ version_pkg_path = _create_test_package(script) - _add_ref(script, version_pkg_path, 'refs/foo/bar') + _add_ref(script, version_pkg_path, "refs/foo/bar") _change_test_package_version(script, version_pkg_path) version = _install_version_pkg(script, version_pkg_path) - assert 'some different version' == version + assert "some different version" == version # Now install the ref. version = _install_version_pkg( - script, version_pkg_path, rev='refs/foo/bar', + script, + version_pkg_path, + rev="refs/foo/bar", ) - assert '0.1' == version + assert "0.1" == version @pytest.mark.network @@ -275,18 +277,21 @@ def test_git_with_tag_name_and_update(script, tmpdir): """ Test cloning a git repository and updating to a different version. """ - url_path = 'pypa/pip-test-package.git' + url_path = "pypa/pip-test-package.git" base_local_url = _github_checkout(url_path, tmpdir) - local_url = '{}#egg=pip-test-package'.format(base_local_url) - result = script.pip('install', '-e', local_url) - result.assert_installed('pip-test-package', with_files=['.git']) + local_url = "{}#egg=pip-test-package".format(base_local_url) + result = script.pip("install", "-e", local_url) + result.assert_installed("pip-test-package", with_files=[".git"]) - new_local_url = '{}@0.1.2#egg=pip-test-package'.format(base_local_url) + new_local_url = "{}@0.1.2#egg=pip-test-package".format(base_local_url) result = script.pip( - 'install', '--global-option=--version', '-e', new_local_url, + "install", + "--global-option=--version", + "-e", + new_local_url, ) - assert '0.1.2' in result.stdout + assert "0.1.2" in result.stdout @pytest.mark.network @@ -295,11 +300,11 @@ def test_git_branch_should_not_be_changed(script, tmpdir): Editable installations should not change branch related to issue #32 and #161 """ - url_path = 'pypa/pip-test-package.git' - local_url = _github_checkout(url_path, tmpdir, egg='pip-test-package') - script.pip('install', '-e', local_url) - branch = _get_editable_branch(script, 'pip-test-package') - assert 'master' == branch + url_path = "pypa/pip-test-package.git" + local_url = _github_checkout(url_path, tmpdir, egg="pip-test-package") + script.pip("install", "-e", local_url) + branch = _get_editable_branch(script, "pip-test-package") + assert "master" == branch @pytest.mark.network @@ -307,12 +312,15 @@ def test_git_with_non_editable_unpacking(script, tmpdir): """ Test cloning a git repository from a non-editable URL with a given tag. """ - url_path = 'pypa/pip-test-package.git' + url_path = "pypa/pip-test-package.git" local_url = _github_checkout( - url_path, tmpdir, rev='0.1.2', egg='pip-test-package', + url_path, + tmpdir, + rev="0.1.2", + egg="pip-test-package", ) - result = script.pip('install', '--global-option=--version', local_url) - assert '0.1.2' in result.stdout + result = script.pip("install", "--global-option=--version", local_url) + assert "0.1.2" in result.stdout @pytest.mark.network @@ -321,12 +329,15 @@ def test_git_with_editable_where_egg_contains_dev_string(script, tmpdir): Test cloning a git repository from an editable url which contains "dev" string """ - url_path = 'dcramer/django-devserver.git' + url_path = "dcramer/django-devserver.git" local_url = _github_checkout( - url_path, tmpdir, egg='django-devserver', scheme='git', + url_path, + tmpdir, + egg="django-devserver", + scheme="git", ) - result = script.pip('install', '-e', local_url) - result.assert_installed('django-devserver', with_files=['.git']) + result = script.pip("install", "-e", local_url) + result.assert_installed("django-devserver", with_files=[".git"]) @pytest.mark.network @@ -335,12 +346,15 @@ def test_git_with_non_editable_where_egg_contains_dev_string(script, tmpdir): Test cloning a git repository from a non-editable url which contains "dev" string """ - url_path = 'dcramer/django-devserver.git' + url_path = "dcramer/django-devserver.git" local_url = _github_checkout( - url_path, tmpdir, egg='django-devserver', scheme='git', + url_path, + tmpdir, + egg="django-devserver", + scheme="git", ) - result = script.pip('install', local_url) - devserver_folder = script.site_packages / 'devserver' + result = script.pip("install", local_url) + devserver_folder = script.site_packages / "devserver" result.did_create(devserver_folder) @@ -349,13 +363,13 @@ def test_git_with_ambiguous_revs(script): Test git with two "names" (tag/branch) pointing to the same commit """ version_pkg_path = _create_test_package(script) - version_pkg_url = _make_version_pkg_url(version_pkg_path, rev='0.1') - script.run('git', 'tag', '0.1', cwd=version_pkg_path) - result = script.pip('install', '-e', version_pkg_url) - assert 'Could not find a tag or branch' not in result.stdout + version_pkg_url = _make_version_pkg_url(version_pkg_path, rev="0.1") + script.run("git", "tag", "0.1", cwd=version_pkg_path) + result = script.pip("install", "-e", version_pkg_url) + assert "Could not find a tag or branch" not in result.stdout # it is 'version-pkg' instead of 'version_pkg' because # egg-link name is version-pkg.egg-link because it is a single .py module - result.assert_installed('version-pkg', with_files=['.git']) + result.assert_installed("version-pkg", with_files=[".git"]) def test_editable__no_revision(script): @@ -365,11 +379,11 @@ def test_editable__no_revision(script): version_pkg_path = _create_test_package(script) _install_version_pkg_only(script, version_pkg_path) - branch = _get_editable_branch(script, 'version-pkg') - assert branch == 'master' + branch = _get_editable_branch(script, "version-pkg") + assert branch == "master" - remote = _get_branch_remote(script, 'version-pkg', 'master') - assert remote == 'origin' + remote = _get_branch_remote(script, "version-pkg", "master") + assert remote == "origin" def test_editable__branch_with_sha_same_as_default(script): @@ -379,14 +393,14 @@ def test_editable__branch_with_sha_same_as_default(script): """ version_pkg_path = _create_test_package(script) # Create a second branch with the same SHA. - script.run('git', 'branch', 'develop', cwd=version_pkg_path) - _install_version_pkg_only(script, version_pkg_path, rev='develop') + script.run("git", "branch", "develop", cwd=version_pkg_path) + _install_version_pkg_only(script, version_pkg_path, rev="develop") - branch = _get_editable_branch(script, 'version-pkg') - assert branch == 'develop' + branch = _get_editable_branch(script, "version-pkg") + assert branch == "develop" - remote = _get_branch_remote(script, 'version-pkg', 'develop') - assert remote == 'origin' + remote = _get_branch_remote(script, "version-pkg", "develop") + assert remote == "origin" def test_editable__branch_with_sha_different_from_default(script): @@ -396,18 +410,18 @@ def test_editable__branch_with_sha_different_from_default(script): """ version_pkg_path = _create_test_package(script) # Create a second branch. - script.run('git', 'branch', 'develop', cwd=version_pkg_path) + script.run("git", "branch", "develop", cwd=version_pkg_path) # Add another commit to the master branch to give it a different sha. _change_test_package_version(script, version_pkg_path) - version = _install_version_pkg(script, version_pkg_path, rev='develop') - assert version == '0.1' + version = _install_version_pkg(script, version_pkg_path, rev="develop") + assert version == "0.1" - branch = _get_editable_branch(script, 'version-pkg') - assert branch == 'develop' + branch = _get_editable_branch(script, "version-pkg") + assert branch == "develop" - remote = _get_branch_remote(script, 'version-pkg', 'develop') - assert remote == 'origin' + remote = _get_branch_remote(script, "version-pkg", "develop") + assert remote == "origin" def test_editable__non_master_default_branch(script): @@ -418,11 +432,11 @@ def test_editable__non_master_default_branch(script): version_pkg_path = _create_test_package(script) # Change the default branch of the remote repo to a name that is # alphabetically after "master". - script.run('git', 'checkout', '-b', 'release', cwd=version_pkg_path) + script.run("git", "checkout", "-b", "release", cwd=version_pkg_path) _install_version_pkg_only(script, version_pkg_path) - branch = _get_editable_branch(script, 'version-pkg') - assert branch == 'release' + branch = _get_editable_branch(script, "version-pkg") + assert branch == "release" def test_reinstalling_works_with_editable_non_master_branch(script): @@ -433,14 +447,14 @@ def test_reinstalling_works_with_editable_non_master_branch(script): version_pkg_path = _create_test_package(script) # Switch the default branch to something other than 'master' - script.run('git', 'branch', '-m', 'foobar', cwd=version_pkg_path) + script.run("git", "branch", "-m", "foobar", cwd=version_pkg_path) version = _install_version_pkg(script, version_pkg_path) - assert '0.1' == version + assert "0.1" == version _change_test_package_version(script, version_pkg_path) version = _install_version_pkg(script, version_pkg_path) - assert 'some different version' == version + assert "some different version" == version # TODO(pnasrat) fix all helpers to do right things with paths on windows. @@ -449,31 +463,31 @@ def test_check_submodule_addition(script): """ Submodules are pulled in on install and updated on upgrade. """ - module_path, submodule_path = ( - _create_test_package_with_submodule(script, rel_path='testpkg/static') + module_path, submodule_path = _create_test_package_with_submodule( + script, rel_path="testpkg/static" ) install_result = script.pip( - 'install', '-e', 'git+' + module_path + '#egg=version_pkg' - ) - install_result.did_create( - script.venv / 'src/version-pkg/testpkg/static/testfile' + "install", "-e", "git+" + module_path + "#egg=version_pkg" ) + install_result.did_create(script.venv / "src/version-pkg/testpkg/static/testfile") _change_test_package_submodule(script, submodule_path) _pull_in_submodule_changes_to_module( - script, module_path, rel_path='testpkg/static', + script, + module_path, + rel_path="testpkg/static", ) # expect error because git may write to stderr update_result = script.pip( - 'install', '-e', 'git+' + module_path + '#egg=version_pkg', - '--upgrade', + "install", + "-e", + "git+" + module_path + "#egg=version_pkg", + "--upgrade", ) - update_result.did_create( - script.venv / 'src/version-pkg/testpkg/static/testfile2' - ) + update_result.did_create(script.venv / "src/version-pkg/testpkg/static/testfile2") def test_install_git_branch_not_cached(script, with_wheel): @@ -488,9 +502,7 @@ def test_install_git_branch_not_cached(script, with_wheel): script.pip("uninstall", "-y", PKG) # build occurs on the second install too because it is not cached result = script.pip("install", url) - assert ( - "Successfully built {}".format(PKG) in result.stdout - ), result.stdout + assert "Successfully built {}".format(PKG) in result.stdout, result.stdout def test_install_git_sha_cached(script, with_wheel): @@ -499,15 +511,11 @@ def test_install_git_sha_cached(script, with_wheel): """ PKG = "gitshacached" repo_dir = _create_test_package(script, name=PKG) - commit = script.run( - 'git', 'rev-parse', 'HEAD', cwd=repo_dir - ).stdout.strip() + commit = script.run("git", "rev-parse", "HEAD", cwd=repo_dir).stdout.strip() url = _make_version_pkg_url(repo_dir, rev=commit, name=PKG) result = script.pip("install", url) assert "Successfully built {}".format(PKG) in result.stdout, result.stdout script.pip("uninstall", "-y", PKG) # build does not occur on the second install because it is cached result = script.pip("install", url) - assert ( - "Successfully built {}".format(PKG) not in result.stdout - ), result.stdout + assert "Successfully built {}".format(PKG) not in result.stdout, result.stdout diff --git a/tests/functional/test_install_wheel.py b/tests/functional/test_install_wheel.py index ad4e749676f..90422527746 100644 --- a/tests/functional/test_install_wheel.py +++ b/tests/functional/test_install_wheel.py @@ -27,27 +27,24 @@ def test_install_from_future_wheel_version(script, tmpdir): - a minor version ahead of what we expect (ok) """ from tests.lib import TestFailure + package = make_wheel_with_file( name="futurewheel", version="3.0", wheel_metadata_updates={"Wheel-Version": "3.0"}, ).save_to_dir(tmpdir) - result = script.pip('install', package, '--no-index', expect_error=True) + result = script.pip("install", package, "--no-index", expect_error=True) with pytest.raises(TestFailure): - result.assert_installed('futurewheel', without_egg_link=True, - editable=False) + result.assert_installed("futurewheel", without_egg_link=True, editable=False) package = make_wheel_with_file( name="futurewheel", version="1.9", wheel_metadata_updates={"Wheel-Version": "1.9"}, ).save_to_dir(tmpdir) - result = script.pip( - 'install', package, '--no-index', expect_stderr=True - ) - result.assert_installed('futurewheel', without_egg_link=True, - editable=False) + result = script.pip("install", package, "--no-index", expect_stderr=True) + result.assert_installed("futurewheel", without_egg_link=True, editable=False) def test_install_from_broken_wheel(script, data): @@ -55,27 +52,28 @@ def test_install_from_broken_wheel(script, data): Test that installing a broken wheel fails properly """ from tests.lib import TestFailure + package = data.packages.joinpath("brokenwheel-1.0-py2.py3-none-any.whl") - result = script.pip('install', package, '--no-index', expect_error=True) + result = script.pip("install", package, "--no-index", expect_error=True) with pytest.raises(TestFailure): - result.assert_installed('futurewheel', without_egg_link=True, - editable=False) + result.assert_installed("futurewheel", without_egg_link=True, editable=False) def test_basic_install_from_wheel(script, shared_data, tmpdir): """ Test installing from a wheel (that has a script) """ - shutil.copy( - shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'has.script==1.0', '--no-index', - '--find-links', tmpdir, + "install", + "has.script==1.0", + "--no-index", + "--find-links", + tmpdir, ) - dist_info_folder = script.site_packages / 'has.script-1.0.dist-info' + dist_info_folder = script.site_packages / "has.script-1.0.dist-info" result.did_create(dist_info_folder) - script_file = script.bin / 'script.py' + script_file = script.bin / "script.py" result.did_create(script_file) @@ -83,19 +81,18 @@ def test_basic_install_from_wheel_with_extras(script, shared_data, tmpdir): """ Test installing from a wheel with extras. """ - shutil.copy( - shared_data.packages / "complex_dist-0.1-py2.py3-none-any.whl", tmpdir - ) - shutil.copy( - shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "complex_dist-0.1-py2.py3-none-any.whl", tmpdir) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'complex-dist[simple]', '--no-index', - '--find-links', tmpdir, + "install", + "complex-dist[simple]", + "--no-index", + "--find-links", + tmpdir, ) - dist_info_folder = script.site_packages / 'complex_dist-0.1.dist-info' + dist_info_folder = script.site_packages / "complex_dist-0.1.dist-info" result.did_create(dist_info_folder) - dist_info_folder = script.site_packages / 'simple.dist-0.1.dist-info' + dist_info_folder = script.site_packages / "simple.dist-0.1.dist-info" result.did_create(dist_info_folder) @@ -104,15 +101,15 @@ def test_basic_install_from_wheel_file(script, data): Test installing directly from a wheel file. """ package = data.packages.joinpath("simple.dist-0.1-py2.py3-none-any.whl") - result = script.pip('install', package, '--no-index') - dist_info_folder = script.site_packages / 'simple.dist-0.1.dist-info' + result = script.pip("install", package, "--no-index") + dist_info_folder = script.site_packages / "simple.dist-0.1.dist-info" result.did_create(dist_info_folder) - installer = dist_info_folder / 'INSTALLER' + installer = dist_info_folder / "INSTALLER" result.did_create(installer) - with open(script.base_path / installer, 'rb') as installer_file: + with open(script.base_path / installer, "rb") as installer_file: installer_details = installer_file.read() - assert installer_details == b'pip\n' - installer_temp = dist_info_folder / 'INSTALLER.pip' + assert installer_details == b"pip\n" + installer_temp = dist_info_folder / "INSTALLER.pip" result.did_not_create(installer_temp) @@ -124,25 +121,28 @@ def test_basic_install_from_unicode_wheel(script, data): Test installing from a wheel (that has a script) """ make_wheel( - 'unicode_package', - '1.0', + "unicode_package", + "1.0", extra_files={ - 'வணகà¯à®•à®®à¯/__init__.py': b'', - 'வணகà¯à®•à®®à¯/નમસà«àª¤à«‡.py': b'', + "வணகà¯à®•à®®à¯/__init__.py": b"", + "வணகà¯à®•à®®à¯/નમસà«àª¤à«‡.py": b"", }, ).save_to_dir(script.scratch_path) result = script.pip( - 'install', 'unicode_package==1.0', '--no-index', - '--find-links', script.scratch_path, + "install", + "unicode_package==1.0", + "--no-index", + "--find-links", + script.scratch_path, ) - dist_info_folder = script.site_packages / 'unicode_package-1.0.dist-info' + dist_info_folder = script.site_packages / "unicode_package-1.0.dist-info" result.did_create(dist_info_folder) - file1 = script.site_packages.joinpath('வணகà¯à®•à®®à¯', '__init__.py') + file1 = script.site_packages.joinpath("வணகà¯à®•à®®à¯", "__init__.py") result.did_create(file1) - file2 = script.site_packages.joinpath('வணகà¯à®•à®®à¯', 'નમસà«àª¤à«‡.py') + file2 = script.site_packages.joinpath("வணகà¯à®•à®®à¯", "નમસà«àª¤à«‡.py") result.did_create(file2) @@ -152,7 +152,7 @@ def get_header_scheme_path_for_script(script, dist_name): "scheme = get_scheme({!r});" "print(scheme.headers);" ).format(dist_name) - result = script.run('python', '-c', command).stdout + result = script.run("python", "-c", command).stdout return Path(result.strip()) @@ -160,22 +160,18 @@ def test_install_from_wheel_with_headers(script): """ Test installing from a wheel file with headers """ - header_text = '/* hello world */\n' + header_text = "/* hello world */\n" package = make_wheel( - 'headers.dist', - '0.1', - extra_data_files={ - 'headers/header.h': header_text - }, + "headers.dist", + "0.1", + extra_data_files={"headers/header.h": header_text}, ).save_to_dir(script.scratch_path) - result = script.pip('install', package, '--no-index') - dist_info_folder = script.site_packages / 'headers.dist-0.1.dist-info' + result = script.pip("install", package, "--no-index") + dist_info_folder = script.site_packages / "headers.dist-0.1.dist-info" result.did_create(dist_info_folder) - header_scheme_path = get_header_scheme_path_for_script( - script, 'headers.dist' - ) - header_path = header_scheme_path / 'header.h' + header_scheme_path = get_header_scheme_path_for_script(script, "headers.dist") + header_path = header_scheme_path / "header.h" assert header_path.read_text() == header_text @@ -183,15 +179,18 @@ def test_install_wheel_with_target(script, shared_data, with_wheel, tmpdir): """ Test installing a wheel using pip install --target """ - shutil.copy( - shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir - ) - target_dir = script.scratch_path / 'target' + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) + target_dir = script.scratch_path / "target" result = script.pip( - 'install', 'simple.dist==0.1', '-t', target_dir, - '--no-index', '--find-links', tmpdir, + "install", + "simple.dist==0.1", + "-t", + target_dir, + "--no-index", + "--find-links", + tmpdir, ) - result.did_create(Path('scratch') / 'target' / 'simpledist') + result.did_create(Path("scratch") / "target" / "simpledist") def test_install_wheel_with_target_and_data_files(script, data, with_wheel): @@ -213,47 +212,49 @@ def test_install_wheel_with_target_and_data_files(script, data, with_wheel): ] ) """ - target_dir = script.scratch_path / 'prjwithdatafile' - package = data.packages.joinpath( - "prjwithdatafile-1.0-py2.py3-none-any.whl" - ) - result = script.pip('install', package, - '-t', target_dir, - '--no-index') - project_path = Path('scratch') / 'prjwithdatafile' - result.did_create(project_path / 'packages1' / 'README.txt') - result.did_create(project_path / 'packages2' / 'README.txt') - result.did_not_create(project_path / 'lib' / 'python') + target_dir = script.scratch_path / "prjwithdatafile" + package = data.packages.joinpath("prjwithdatafile-1.0-py2.py3-none-any.whl") + result = script.pip("install", package, "-t", target_dir, "--no-index") + project_path = Path("scratch") / "prjwithdatafile" + result.did_create(project_path / "packages1" / "README.txt") + result.did_create(project_path / "packages2" / "README.txt") + result.did_not_create(project_path / "lib" / "python") def test_install_wheel_with_root(script, shared_data, tmpdir): """ Test installing a wheel using pip install --root """ - root_dir = script.scratch_path / 'root' - shutil.copy( - shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir - ) + root_dir = script.scratch_path / "root" + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'simple.dist==0.1', '--root', root_dir, - '--no-index', '--find-links', tmpdir, + "install", + "simple.dist==0.1", + "--root", + root_dir, + "--no-index", + "--find-links", + tmpdir, ) - result.did_create(Path('scratch') / 'root') + result.did_create(Path("scratch") / "root") def test_install_wheel_with_prefix(script, shared_data, tmpdir): """ Test installing a wheel using pip install --prefix """ - prefix_dir = script.scratch_path / 'prefix' - shutil.copy( - shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir - ) + prefix_dir = script.scratch_path / "prefix" + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'simple.dist==0.1', '--prefix', prefix_dir, - '--no-index', '--find-links', tmpdir, + "install", + "simple.dist==0.1", + "--prefix", + prefix_dir, + "--no-index", + "--find-links", + tmpdir, ) - lib = distutils.sysconfig.get_python_lib(prefix=Path('scratch') / 'prefix') + lib = distutils.sysconfig.get_python_lib(prefix=Path("scratch") / "prefix") result.did_create(lib) @@ -262,14 +263,16 @@ def test_install_from_wheel_installs_deps(script, data, tmpdir): Test can install dependencies of wheels """ # 'requires_source' depends on the 'source' project - package = data.packages.joinpath( - "requires_source-1.0-py2.py3-none-any.whl" - ) + package = data.packages.joinpath("requires_source-1.0-py2.py3-none-any.whl") shutil.copy(data.packages / "source-1.0.tar.gz", tmpdir) result = script.pip( - 'install', '--no-index', '--find-links', tmpdir, package, + "install", + "--no-index", + "--find-links", + tmpdir, + package, ) - result.assert_installed('source', editable=False) + result.assert_installed("source", editable=False) def test_install_from_wheel_no_deps(script, data, tmpdir): @@ -277,32 +280,32 @@ def test_install_from_wheel_no_deps(script, data, tmpdir): Test --no-deps works with wheel installs """ # 'requires_source' depends on the 'source' project - package = data.packages.joinpath( - "requires_source-1.0-py2.py3-none-any.whl" - ) + package = data.packages.joinpath("requires_source-1.0-py2.py3-none-any.whl") shutil.copy(data.packages / "source-1.0.tar.gz", tmpdir) result = script.pip( - 'install', '--no-index', '--find-links', tmpdir, '--no-deps', + "install", + "--no-index", + "--find-links", + tmpdir, + "--no-deps", package, ) - pkg_folder = script.site_packages / 'source' + pkg_folder = script.site_packages / "source" result.did_not_create(pkg_folder) def test_wheel_record_lines_in_deterministic_order(script, data): to_install = data.packages.joinpath("simplewheel-1.0-py2.py3-none-any.whl") - result = script.pip('install', to_install) + result = script.pip("install", to_install) - dist_info_folder = script.site_packages / 'simplewheel-1.0.dist-info' - record_path = dist_info_folder / 'RECORD' + dist_info_folder = script.site_packages / "simplewheel-1.0.dist-info" + record_path = dist_info_folder / "RECORD" result.did_create(dist_info_folder) result.did_create(record_path) record_path = result.files_created[record_path].full - record_lines = [ - p for p in Path(record_path).read_text().split('\n') if p - ] + record_lines = [p for p in Path(record_path).read_text().split("\n") if p] assert record_lines == sorted(record_lines) @@ -315,16 +318,13 @@ def test_wheel_record_lines_have_hash_for_data_files(script): }, ).save_to_dir(script.scratch_path) script.pip("install", package) - record_file = ( - script.site_packages_path / "simple-0.1.0.dist-info" / "RECORD" - ) + record_file = script.site_packages_path / "simple-0.1.0.dist-info" / "RECORD" record_text = record_file.read_text() record_rows = list(csv.reader(record_text.splitlines())) - records = { - r[0]: r[1:] for r in record_rows - } + records = {r[0]: r[1:] for r in record_rows} assert records["info.txt"] == [ - "sha256=Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y", "1" + "sha256=Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y", + "1", ] @@ -333,16 +333,18 @@ def test_install_user_wheel(script, shared_data, with_wheel, tmpdir): """ Test user install from wheel (that has a script) """ - shutil.copy( - shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "has.script-1.0-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'has.script==1.0', '--user', '--no-index', - '--find-links', tmpdir, + "install", + "has.script==1.0", + "--user", + "--no-index", + "--find-links", + tmpdir, ) - dist_info_folder = script.user_site / 'has.script-1.0.dist-info' + dist_info_folder = script.user_site / "has.script-1.0.dist-info" result.did_create(dist_info_folder) - script_file = script.user_bin / 'script.py' + script_file = script.user_bin / "script.py" result.did_create(script_file) @@ -355,39 +357,42 @@ def test_install_from_wheel_gen_entrypoint(script, shared_data, tmpdir): tmpdir, ) result = script.pip( - 'install', 'script.wheel1a==0.1', '--no-index', - '--find-links', tmpdir, + "install", + "script.wheel1a==0.1", + "--no-index", + "--find-links", + tmpdir, ) - if os.name == 'nt': - wrapper_file = script.bin / 't1.exe' + if os.name == "nt": + wrapper_file = script.bin / "t1.exe" else: - wrapper_file = script.bin / 't1' + wrapper_file = script.bin / "t1" result.did_create(wrapper_file) if os.name != "nt": assert bool(os.access(script.base_path / wrapper_file, os.X_OK)) -def test_install_from_wheel_gen_uppercase_entrypoint( - script, shared_data, tmpdir -): +def test_install_from_wheel_gen_uppercase_entrypoint(script, shared_data, tmpdir): """ Test installing scripts with uppercase letters in entry point names """ shutil.copy( - shared_data.packages / - "console_scripts_uppercase-1.0-py2.py3-none-any.whl", + shared_data.packages / "console_scripts_uppercase-1.0-py2.py3-none-any.whl", tmpdir, ) result = script.pip( - 'install', 'console-scripts-uppercase==1.0', '--no-index', - '--find-links', tmpdir, + "install", + "console-scripts-uppercase==1.0", + "--no-index", + "--find-links", + tmpdir, ) - if os.name == 'nt': + if os.name == "nt": # Case probably doesn't make any difference on NT - wrapper_file = script.bin / 'cmdName.exe' + wrapper_file = script.bin / "cmdName.exe" else: - wrapper_file = script.bin / 'cmdName' + wrapper_file = script.bin / "cmdName" result.did_create(wrapper_file) if os.name != "nt": @@ -425,36 +430,38 @@ def test_install_from_wheel_with_legacy(script, shared_data, tmpdir): tmpdir, ) result = script.pip( - 'install', 'script.wheel2a==0.1', '--no-index', - '--find-links', tmpdir, + "install", + "script.wheel2a==0.1", + "--no-index", + "--find-links", + tmpdir, ) - legacy_file1 = script.bin / 'testscript1.bat' - legacy_file2 = script.bin / 'testscript2' + legacy_file1 = script.bin / "testscript1.bat" + legacy_file2 = script.bin / "testscript2" result.did_create(legacy_file1) result.did_create(legacy_file2) -def test_install_from_wheel_no_setuptools_entrypoint( - script, shared_data, tmpdir -): +def test_install_from_wheel_no_setuptools_entrypoint(script, shared_data, tmpdir): """ Test that when we generate scripts, any existing setuptools wrappers in the wheel are skipped. """ - shutil.copy( - shared_data.packages / "script.wheel1-0.1-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "script.wheel1-0.1-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'script.wheel1==0.1', '--no-index', - '--find-links', tmpdir, + "install", + "script.wheel1==0.1", + "--no-index", + "--find-links", + tmpdir, ) - if os.name == 'nt': - wrapper_file = script.bin / 't1.exe' + if os.name == "nt": + wrapper_file = script.bin / "t1.exe" else: - wrapper_file = script.bin / 't1' - wrapper_helper = script.bin / 't1-script.py' + wrapper_file = script.bin / "t1" + wrapper_helper = script.bin / "t1-script.py" # The wheel has t1.exe and t1-script.py. We will be generating t1 or # t1.exe depending on the platform. So we check that the correct wrapper @@ -470,17 +477,18 @@ def test_skipping_setuptools_doesnt_skip_legacy(script, shared_data, tmpdir): Test installing scripts (legacy scripts are preserved even when we skip setuptools wrappers) """ - shutil.copy( - shared_data.packages / "script.wheel2-0.1-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "script.wheel2-0.1-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'script.wheel2==0.1', '--no-index', - '--find-links', tmpdir, + "install", + "script.wheel2==0.1", + "--no-index", + "--find-links", + tmpdir, ) - legacy_file1 = script.bin / 'testscript1.bat' - legacy_file2 = script.bin / 'testscript2' - wrapper_helper = script.bin / 't1-script.py' + legacy_file1 = script.bin / "testscript1.bat" + legacy_file2 = script.bin / "testscript2" + wrapper_helper = script.bin / "t1-script.py" result.did_create(legacy_file1) result.did_create(legacy_file2) @@ -491,17 +499,18 @@ def test_install_from_wheel_gui_entrypoint(script, shared_data, tmpdir): """ Test installing scripts (gui entry points are generated) """ - shutil.copy( - shared_data.packages / "script.wheel3-0.1-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "script.wheel3-0.1-py2.py3-none-any.whl", tmpdir) result = script.pip( - 'install', 'script.wheel3==0.1', '--no-index', - '--find-links', tmpdir, + "install", + "script.wheel3==0.1", + "--no-index", + "--find-links", + tmpdir, ) - if os.name == 'nt': - wrapper_file = script.bin / 't1.exe' + if os.name == "nt": + wrapper_file = script.bin / "t1.exe" else: - wrapper_file = script.bin / 't1' + wrapper_file = script.bin / "t1" result.did_create(wrapper_file) @@ -509,12 +518,14 @@ def test_wheel_compiles_pyc(script, shared_data, tmpdir): """ Test installing from wheel with --compile on """ - shutil.copy( - shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) script.pip( - "install", "--compile", "simple.dist==0.1", "--no-index", - "--find-links", tmpdir, + "install", + "--compile", + "simple.dist==0.1", + "--no-index", + "--find-links", + tmpdir, ) # There are many locations for the __init__.pyc file so attempt to find # any of them @@ -533,12 +544,14 @@ def test_wheel_no_compiles_pyc(script, shared_data, tmpdir): """ Test installing from wheel with --compile on """ - shutil.copy( - shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir - ) + shutil.copy(shared_data.packages / "simple.dist-0.1-py2.py3-none-any.whl", tmpdir) script.pip( - "install", "--no-compile", "simple.dist==0.1", "--no-index", - "--find-links", tmpdir, + "install", + "--no-compile", + "simple.dist==0.1", + "--no-index", + "--find-links", + tmpdir, ) # There are many locations for the __init__.pyc file so attempt to find # any of them @@ -556,28 +569,27 @@ def test_wheel_no_compiles_pyc(script, shared_data, tmpdir): def test_install_from_wheel_uninstalls_old_version(script, data): # regression test for https://github.com/pypa/pip/issues/1825 package = data.packages.joinpath("simplewheel-1.0-py2.py3-none-any.whl") - result = script.pip('install', package, '--no-index') + result = script.pip("install", package, "--no-index") package = data.packages.joinpath("simplewheel-2.0-py2.py3-none-any.whl") - result = script.pip('install', package, '--no-index') - dist_info_folder = script.site_packages / 'simplewheel-2.0.dist-info' + result = script.pip("install", package, "--no-index") + dist_info_folder = script.site_packages / "simplewheel-2.0.dist-info" result.did_create(dist_info_folder) - dist_info_folder = script.site_packages / 'simplewheel-1.0.dist-info' + dist_info_folder = script.site_packages / "simplewheel-1.0.dist-info" result.did_not_create(dist_info_folder) def test_wheel_compile_syntax_error(script, data): package = data.packages.joinpath("compilewheel-1.0-py2.py3-none-any.whl") - result = script.pip('install', '--compile', package, '--no-index') - assert 'yield from' not in result.stdout - assert 'SyntaxError: ' not in result.stdout + result = script.pip("install", "--compile", package, "--no-index") + assert "yield from" not in result.stdout + assert "SyntaxError: " not in result.stdout def test_wheel_install_with_no_cache_dir(script, tmpdir, data): - """Check wheel installations work, even with no cache. - """ + """Check wheel installations work, even with no cache.""" package = data.packages.joinpath("simple.dist-0.1-py2.py3-none-any.whl") - result = script.pip('install', '--no-cache-dir', '--no-index', package) - result.assert_installed('simpledist', editable=False) + result = script.pip("install", "--no-cache-dir", "--no-index", package) + result.assert_installed("simpledist", editable=False) def test_wheel_install_fails_with_extra_dist_info(script): @@ -587,9 +599,7 @@ def test_wheel_install_fails_with_extra_dist_info(script): "0.1.0", extra_files={ "unrelated-2.0.0.dist-info/WHEEL": "Wheel-Version: 1.0", - "unrelated-2.0.0.dist-info/METADATA": ( - "Name: unrelated\nVersion: 2.0.0\n" - ), + "unrelated-2.0.0.dist-info/METADATA": ("Name: unrelated\nVersion: 2.0.0\n"), }, ) result = script.pip( @@ -612,10 +622,7 @@ def test_wheel_install_fails_with_unrelated_dist_info(script): expect_error=True, ) - assert ( - "'simple-0.1.0.dist-info' does not start with 'unrelated'" - in result.stderr - ) + assert "'simple-0.1.0.dist-info' does not start with 'unrelated'" in result.stderr def test_wheel_installs_ok_with_nested_dist_info(script): @@ -630,25 +637,17 @@ def test_wheel_installs_ok_with_nested_dist_info(script): ), }, ) - script.pip( - "install", "--no-cache-dir", "--no-index", package - ) + script.pip("install", "--no-cache-dir", "--no-index", package) -def test_wheel_installs_ok_with_badly_encoded_irrelevant_dist_info_file( - script -): +def test_wheel_installs_ok_with_badly_encoded_irrelevant_dist_info_file(script): package = create_basic_wheel_for_package( script, "simple", "0.1.0", - extra_files={ - "simple-0.1.0.dist-info/AUTHORS.txt": b"\xff" - }, - ) - script.pip( - "install", "--no-cache-dir", "--no-index", package + extra_files={"simple-0.1.0.dist-info/AUTHORS.txt": b"\xff"}, ) + script.pip("install", "--no-cache-dir", "--no-index", package) # Metadata is not decoded on Python 2. @@ -658,9 +657,7 @@ def test_wheel_install_fails_with_badly_encoded_metadata(script): script, "simple", "0.1.0", - extra_files={ - "simple-0.1.0.dist-info/METADATA": b"\xff" - }, + extra_files={"simple-0.1.0.dist-info/METADATA": b"\xff"}, ) result = script.pip( "install", "--no-cache-dir", "--no-index", package, expect_error=True @@ -671,22 +668,20 @@ def test_wheel_install_fails_with_badly_encoded_metadata(script): @pytest.mark.parametrize( - 'package_name', - ['simple-package', 'simple_package'], + "package_name", + ["simple-package", "simple_package"], ) def test_correct_package_name_while_creating_wheel_bug(script, package_name): """Check that the package name is correctly named while creating a .whl file with a given format """ - package = create_basic_wheel_for_package(script, package_name, '1.0') + package = create_basic_wheel_for_package(script, package_name, "1.0") wheel_name = os.path.basename(package) - assert wheel_name == 'simple_package-1.0-py2.py3-none-any.whl' + assert wheel_name == "simple_package-1.0-py2.py3-none-any.whl" @pytest.mark.parametrize("name", ["purelib", "abc"]) -def test_wheel_with_file_in_data_dir_has_reasonable_error( - script, tmpdir, name -): +def test_wheel_with_file_in_data_dir_has_reasonable_error(script, tmpdir, name): """Normally we expect entities in the .data directory to be in a subdirectory, but if they are not then we should show a reasonable error message that includes the path. @@ -695,22 +690,14 @@ def test_wheel_with_file_in_data_dir_has_reasonable_error( "simple", "0.1.0", extra_data_files={name: "hello world"} ).save_to_dir(tmpdir) - result = script.pip( - "install", "--no-index", str(wheel_path), expect_error=True - ) + result = script.pip("install", "--no-index", str(wheel_path), expect_error=True) assert "simple-0.1.0.data/{}".format(name) in result.stderr -def test_wheel_with_unknown_subdir_in_data_dir_has_reasonable_error( - script, tmpdir -): +def test_wheel_with_unknown_subdir_in_data_dir_has_reasonable_error(script, tmpdir): wheel_path = make_wheel( - "simple", - "0.1.0", - extra_data_files={"unknown/hello.txt": "hello world"} + "simple", "0.1.0", extra_data_files={"unknown/hello.txt": "hello world"} ).save_to_dir(tmpdir) - result = script.pip( - "install", "--no-index", str(wheel_path), expect_error=True - ) + result = script.pip("install", "--no-index", str(wheel_path), expect_error=True) assert "simple-0.1.0.data/unknown/hello.txt" in result.stderr diff --git a/tests/functional/test_list.py b/tests/functional/test_list.py index 37787246bd0..870b5dce378 100644 --- a/tests/functional/test_list.py +++ b/tests/functional/test_list.py @@ -12,8 +12,12 @@ def simple_script(tmpdir_factory, script_factory, shared_data): tmpdir = Path(str(tmpdir_factory.mktemp("pip_test_package"))) script = script_factory(tmpdir.joinpath("workspace")) script.pip( - 'install', '-f', shared_data.find_links, '--no-index', 'simple==1.0', - 'simple2==3.0', + "install", + "-f", + shared_data.find_links, + "--no-index", + "simple==1.0", + "simple2==3.0", ) return script @@ -23,54 +27,55 @@ def test_basic_list(simple_script): Test default behavior of list command without format specifier. """ - result = simple_script.pip('list') - assert 'simple 1.0' in result.stdout, str(result) - assert 'simple2 3.0' in result.stdout, str(result) + result = simple_script.pip("list") + assert "simple 1.0" in result.stdout, str(result) + assert "simple2 3.0" in result.stdout, str(result) def test_verbose_flag(simple_script): """ Test the list command with the '-v' option """ - result = simple_script.pip('list', '-v', '--format=columns') - assert 'Package' in result.stdout, str(result) - assert 'Version' in result.stdout, str(result) - assert 'Location' in result.stdout, str(result) - assert 'Installer' in result.stdout, str(result) - assert 'simple 1.0' in result.stdout, str(result) - assert 'simple2 3.0' in result.stdout, str(result) + result = simple_script.pip("list", "-v", "--format=columns") + assert "Package" in result.stdout, str(result) + assert "Version" in result.stdout, str(result) + assert "Location" in result.stdout, str(result) + assert "Installer" in result.stdout, str(result) + assert "simple 1.0" in result.stdout, str(result) + assert "simple2 3.0" in result.stdout, str(result) def test_columns_flag(simple_script): """ Test the list command with the '--format=columns' option """ - result = simple_script.pip('list', '--format=columns') - assert 'Package' in result.stdout, str(result) - assert 'Version' in result.stdout, str(result) - assert 'simple (1.0)' not in result.stdout, str(result) - assert 'simple 1.0' in result.stdout, str(result) - assert 'simple2 3.0' in result.stdout, str(result) + result = simple_script.pip("list", "--format=columns") + assert "Package" in result.stdout, str(result) + assert "Version" in result.stdout, str(result) + assert "simple (1.0)" not in result.stdout, str(result) + assert "simple 1.0" in result.stdout, str(result) + assert "simple2 3.0" in result.stdout, str(result) def test_format_priority(simple_script): """ Test that latest format has priority over previous ones. """ - result = simple_script.pip('list', '--format=columns', '--format=freeze', - expect_stderr=True) - assert 'simple==1.0' in result.stdout, str(result) - assert 'simple2==3.0' in result.stdout, str(result) - assert 'simple 1.0' not in result.stdout, str(result) - assert 'simple2 3.0' not in result.stdout, str(result) + result = simple_script.pip( + "list", "--format=columns", "--format=freeze", expect_stderr=True + ) + assert "simple==1.0" in result.stdout, str(result) + assert "simple2==3.0" in result.stdout, str(result) + assert "simple 1.0" not in result.stdout, str(result) + assert "simple2 3.0" not in result.stdout, str(result) - result = simple_script.pip('list', '--format=freeze', '--format=columns') - assert 'Package' in result.stdout, str(result) - assert 'Version' in result.stdout, str(result) - assert 'simple==1.0' not in result.stdout, str(result) - assert 'simple2==3.0' not in result.stdout, str(result) - assert 'simple 1.0' in result.stdout, str(result) - assert 'simple2 3.0' in result.stdout, str(result) + result = simple_script.pip("list", "--format=freeze", "--format=columns") + assert "Package" in result.stdout, str(result) + assert "Version" in result.stdout, str(result) + assert "simple==1.0" not in result.stdout, str(result) + assert "simple2==3.0" not in result.stdout, str(result) + assert "simple 1.0" in result.stdout, str(result) + assert "simple2 3.0" in result.stdout, str(result) def test_local_flag(simple_script): @@ -78,7 +83,7 @@ def test_local_flag(simple_script): Test the behavior of --local flag in the list command """ - result = simple_script.pip('list', '--local', '--format=json') + result = simple_script.pip("list", "--local", "--format=json") assert {"name": "simple", "version": "1.0"} in json.loads(result.stdout) @@ -87,11 +92,11 @@ def test_local_columns_flag(simple_script): Test the behavior of --local --format=columns flags in the list command """ - result = simple_script.pip('list', '--local', '--format=columns') - assert 'Package' in result.stdout - assert 'Version' in result.stdout - assert 'simple (1.0)' not in result.stdout - assert 'simple 1.0' in result.stdout, str(result) + result = simple_script.pip("list", "--local", "--format=columns") + assert "Package" in result.stdout + assert "Version" in result.stdout + assert "simple (1.0)" not in result.stdout + assert "simple 1.0" in result.stdout, str(result) @pytest.mark.network @@ -101,13 +106,11 @@ def test_user_flag(script, data): Test the behavior of --user flag in the list command """ - script.pip('download', 'setuptools', 'wheel', '-d', data.packages) - script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0') - script.pip('install', '-f', data.find_links, '--no-index', - '--user', 'simple2==2.0') - result = script.pip('list', '--user', '--format=json') - assert {"name": "simple", "version": "1.0"} \ - not in json.loads(result.stdout) + script.pip("download", "setuptools", "wheel", "-d", data.packages) + script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") + script.pip("install", "-f", data.find_links, "--no-index", "--user", "simple2==2.0") + result = script.pip("list", "--user", "--format=json") + assert {"name": "simple", "version": "1.0"} not in json.loads(result.stdout) assert {"name": "simple2", "version": "2.0"} in json.loads(result.stdout) @@ -118,15 +121,14 @@ def test_user_columns_flag(script, data): Test the behavior of --user --format=columns flags in the list command """ - script.pip('download', 'setuptools', 'wheel', '-d', data.packages) - script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0') - script.pip('install', '-f', data.find_links, '--no-index', - '--user', 'simple2==2.0') - result = script.pip('list', '--user', '--format=columns') - assert 'Package' in result.stdout - assert 'Version' in result.stdout - assert 'simple2 (2.0)' not in result.stdout - assert 'simple2 2.0' in result.stdout, str(result) + script.pip("download", "setuptools", "wheel", "-d", data.packages) + script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") + script.pip("install", "-f", data.find_links, "--no-index", "--user", "simple2==2.0") + result = script.pip("list", "--user", "--format=columns") + assert "Package" in result.stdout + assert "Version" in result.stdout + assert "simple2 (2.0)" not in result.stdout + assert "simple2 2.0" in result.stdout, str(result) @pytest.mark.network @@ -136,21 +138,32 @@ def test_uptodate_flag(script, data): """ script.pip( - 'install', '-f', data.find_links, '--no-index', 'simple==1.0', - 'simple2==3.0', + "install", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + "simple2==3.0", ) script.pip( - 'install', '-e', - 'git+https://github.com/pypa/pip-test-package.git#egg=pip-test-package' + "install", + "-e", + "git+https://github.com/pypa/pip-test-package.git#egg=pip-test-package", ) result = script.pip( - 'list', '-f', data.find_links, '--no-index', '--uptodate', - '--format=json', - ) - assert {"name": "simple", "version": "1.0"} \ - not in json.loads(result.stdout) # 3.0 is latest - assert {"name": "pip-test-package", "version": "0.1.1"} \ - in json.loads(result.stdout) # editables included + "list", + "-f", + data.find_links, + "--no-index", + "--uptodate", + "--format=json", + ) + assert {"name": "simple", "version": "1.0"} not in json.loads( + result.stdout + ) # 3.0 is latest + assert {"name": "pip-test-package", "version": "0.1.1"} in json.loads( + result.stdout + ) # editables included assert {"name": "simple2", "version": "3.0"} in json.loads(result.stdout) @@ -161,23 +174,32 @@ def test_uptodate_columns_flag(script, data): """ script.pip( - 'install', '-f', data.find_links, '--no-index', 'simple==1.0', - 'simple2==3.0', + "install", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + "simple2==3.0", ) script.pip( - 'install', '-e', - 'git+https://github.com/pypa/pip-test-package.git#egg=pip-test-package' + "install", + "-e", + "git+https://github.com/pypa/pip-test-package.git#egg=pip-test-package", ) result = script.pip( - 'list', '-f', data.find_links, '--no-index', '--uptodate', - '--format=columns', + "list", + "-f", + data.find_links, + "--no-index", + "--uptodate", + "--format=columns", ) - assert 'Package' in result.stdout - assert 'Version' in result.stdout - assert 'Location' in result.stdout # editables included - assert 'pip-test-package (0.1.1,' not in result.stdout - assert 'pip-test-package 0.1.1' in result.stdout, str(result) - assert 'simple2 3.0' in result.stdout, str(result) + assert "Package" in result.stdout + assert "Version" in result.stdout + assert "Location" in result.stdout # editables included + assert "pip-test-package (0.1.1," not in result.stdout + assert "pip-test-package 0.1.1" in result.stdout, str(result) + assert "simple2 3.0" in result.stdout, str(result) @pytest.mark.network @@ -187,27 +209,45 @@ def test_outdated_flag(script, data): """ script.pip( - 'install', '-f', data.find_links, '--no-index', 'simple==1.0', - 'simple2==3.0', 'simplewheel==1.0', + "install", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + "simple2==3.0", + "simplewheel==1.0", ) script.pip( - 'install', '-e', - 'git+https://github.com/pypa/pip-test-package.git' - '@0.1#egg=pip-test-package' + "install", + "-e", + "git+https://github.com/pypa/pip-test-package.git" "@0.1#egg=pip-test-package", ) result = script.pip( - 'list', '-f', data.find_links, '--no-index', '--outdated', - '--format=json', - ) - assert {"name": "simple", "version": "1.0", - "latest_version": "3.0", "latest_filetype": "sdist"} \ - in json.loads(result.stdout) - assert dict(name="simplewheel", version="1.0", - latest_version="2.0", latest_filetype="wheel") \ - in json.loads(result.stdout) - assert dict(name="pip-test-package", version="0.1", - latest_version="0.1.1", latest_filetype="sdist") \ + "list", + "-f", + data.find_links, + "--no-index", + "--outdated", + "--format=json", + ) + assert { + "name": "simple", + "version": "1.0", + "latest_version": "3.0", + "latest_filetype": "sdist", + } in json.loads(result.stdout) + assert dict( + name="simplewheel", version="1.0", latest_version="2.0", latest_filetype="wheel" + ) in json.loads(result.stdout) + assert ( + dict( + name="pip-test-package", + version="0.1", + latest_version="0.1.1", + latest_filetype="sdist", + ) in json.loads(result.stdout) + ) assert "simple2" not in {p["name"] for p in json.loads(result.stdout)} @@ -218,43 +258,47 @@ def test_outdated_columns_flag(script, data): """ script.pip( - 'install', '-f', data.find_links, '--no-index', 'simple==1.0', - 'simple2==3.0', 'simplewheel==1.0', + "install", + "-f", + data.find_links, + "--no-index", + "simple==1.0", + "simple2==3.0", + "simplewheel==1.0", ) script.pip( - 'install', '-e', - 'git+https://github.com/pypa/pip-test-package.git' - '@0.1#egg=pip-test-package' + "install", + "-e", + "git+https://github.com/pypa/pip-test-package.git" "@0.1#egg=pip-test-package", ) result = script.pip( - 'list', '-f', data.find_links, '--no-index', '--outdated', - '--format=columns', - ) - assert 'Package' in result.stdout - assert 'Version' in result.stdout - assert 'Latest' in result.stdout - assert 'Type' in result.stdout - assert 'simple (1.0) - Latest: 3.0 [sdist]' not in result.stdout - assert 'simplewheel (1.0) - Latest: 2.0 [wheel]' not in result.stdout - assert 'simple 1.0 3.0 sdist' in result.stdout, ( - str(result) - ) - assert 'simplewheel 1.0 2.0 wheel' in result.stdout, ( - str(result) - ) - assert 'simple2' not in result.stdout, str(result) # 3.0 is latest + "list", + "-f", + data.find_links, + "--no-index", + "--outdated", + "--format=columns", + ) + assert "Package" in result.stdout + assert "Version" in result.stdout + assert "Latest" in result.stdout + assert "Type" in result.stdout + assert "simple (1.0) - Latest: 3.0 [sdist]" not in result.stdout + assert "simplewheel (1.0) - Latest: 2.0 [wheel]" not in result.stdout + assert "simple 1.0 3.0 sdist" in result.stdout, str(result) + assert "simplewheel 1.0 2.0 wheel" in result.stdout, str(result) + assert "simple2" not in result.stdout, str(result) # 3.0 is latest @pytest.fixture(scope="session") def pip_test_package_script(tmpdir_factory, script_factory, shared_data): tmpdir = Path(str(tmpdir_factory.mktemp("pip_test_package"))) script = script_factory(tmpdir.joinpath("workspace")) + script.pip("install", "-f", shared_data.find_links, "--no-index", "simple==1.0") script.pip( - 'install', '-f', shared_data.find_links, '--no-index', 'simple==1.0' - ) - script.pip( - 'install', '-e', - 'git+https://github.com/pypa/pip-test-package.git#egg=pip-test-package' + "install", + "-e", + "git+https://github.com/pypa/pip-test-package.git#egg=pip-test-package", ) return script @@ -264,11 +308,10 @@ def test_editables_flag(pip_test_package_script): """ Test the behavior of --editables flag in the list command """ - result = pip_test_package_script.pip('list', '--editable', '--format=json') - result2 = pip_test_package_script.pip('list', '--editable') - assert {"name": "simple", "version": "1.0"} \ - not in json.loads(result.stdout) - assert os.path.join('src', 'pip-test-package') in result2.stdout + result = pip_test_package_script.pip("list", "--editable", "--format=json") + result2 = pip_test_package_script.pip("list", "--editable") + assert {"name": "simple", "version": "1.0"} not in json.loads(result.stdout) + assert os.path.join("src", "pip-test-package") in result2.stdout @pytest.mark.network @@ -276,12 +319,9 @@ def test_exclude_editable_flag(pip_test_package_script): """ Test the behavior of --editables flag in the list command """ - result = pip_test_package_script.pip( - 'list', '--exclude-editable', '--format=json' - ) + result = pip_test_package_script.pip("list", "--exclude-editable", "--format=json") assert {"name": "simple", "version": "1.0"} in json.loads(result.stdout) - assert "pip-test-package" \ - not in {p["name"] for p in json.loads(result.stdout)} + assert "pip-test-package" not in {p["name"] for p in json.loads(result.stdout)} @pytest.mark.network @@ -289,15 +329,11 @@ def test_editables_columns_flag(pip_test_package_script): """ Test the behavior of --editables flag in the list command """ - result = pip_test_package_script.pip( - 'list', '--editable', '--format=columns' - ) - assert 'Package' in result.stdout - assert 'Version' in result.stdout - assert 'Location' in result.stdout - assert os.path.join('src', 'pip-test-package') in result.stdout, ( - str(result) - ) + result = pip_test_package_script.pip("list", "--editable", "--format=columns") + assert "Package" in result.stdout + assert "Version" in result.stdout + assert "Location" in result.stdout + assert os.path.join("src", "pip-test-package") in result.stdout, str(result) @pytest.mark.network @@ -306,13 +342,15 @@ def test_uptodate_editables_flag(pip_test_package_script, data): test the behavior of --editable --uptodate flag in the list command """ result = pip_test_package_script.pip( - 'list', '-f', data.find_links, '--no-index', - '--editable', '--uptodate', - ) - assert 'simple' not in result.stdout - assert os.path.join('src', 'pip-test-package') in result.stdout, ( - str(result) + "list", + "-f", + data.find_links, + "--no-index", + "--editable", + "--uptodate", ) + assert "simple" not in result.stdout + assert os.path.join("src", "pip-test-package") in result.stdout, str(result) @pytest.mark.network @@ -322,15 +360,18 @@ def test_uptodate_editables_columns_flag(pip_test_package_script, data): list command """ result = pip_test_package_script.pip( - 'list', '-f', data.find_links, '--no-index', - '--editable', '--uptodate', '--format=columns', - ) - assert 'Package' in result.stdout - assert 'Version' in result.stdout - assert 'Location' in result.stdout - assert os.path.join('src', 'pip-test-package') in result.stdout, ( - str(result) + "list", + "-f", + data.find_links, + "--no-index", + "--editable", + "--uptodate", + "--format=columns", ) + assert "Package" in result.stdout + assert "Version" in result.stdout + assert "Location" in result.stdout + assert os.path.join("src", "pip-test-package") in result.stdout, str(result) @pytest.mark.network @@ -338,18 +379,22 @@ def test_outdated_editables_flag(script, data): """ test the behavior of --editable --outdated flag in the list command """ - script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0') + script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") result = script.pip( - 'install', '-e', - 'git+https://github.com/pypa/pip-test-package.git' - '@0.1#egg=pip-test-package' + "install", + "-e", + "git+https://github.com/pypa/pip-test-package.git" "@0.1#egg=pip-test-package", ) result = script.pip( - 'list', '-f', data.find_links, '--no-index', - '--editable', '--outdated', + "list", + "-f", + data.find_links, + "--no-index", + "--editable", + "--outdated", ) - assert 'simple' not in result.stdout - assert os.path.join('src', 'pip-test-package') in result.stdout + assert "simple" not in result.stdout + assert os.path.join("src", "pip-test-package") in result.stdout @pytest.mark.network @@ -357,22 +402,25 @@ def test_outdated_editables_columns_flag(script, data): """ test the behavior of --editable --outdated flag in the list command """ - script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0') + script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") result = script.pip( - 'install', '-e', - 'git+https://github.com/pypa/pip-test-package.git' - '@0.1#egg=pip-test-package' + "install", + "-e", + "git+https://github.com/pypa/pip-test-package.git" "@0.1#egg=pip-test-package", ) result = script.pip( - 'list', '-f', data.find_links, '--no-index', - '--editable', '--outdated', '--format=columns', - ) - assert 'Package' in result.stdout - assert 'Version' in result.stdout - assert 'Location' in result.stdout - assert os.path.join('src', 'pip-test-package') in result.stdout, ( - str(result) + "list", + "-f", + data.find_links, + "--no-index", + "--editable", + "--outdated", + "--format=columns", ) + assert "Package" in result.stdout + assert "Version" in result.stdout + assert "Location" in result.stdout + assert os.path.join("src", "pip-test-package") in result.stdout, str(result) def test_outdated_not_required_flag(script, data): @@ -380,94 +428,139 @@ def test_outdated_not_required_flag(script, data): test the behavior of --outdated --not-required flag in the list command """ script.pip( - 'install', '-f', data.find_links, '--no-index', - 'simple==2.0', 'require_simple==1.0' + "install", + "-f", + data.find_links, + "--no-index", + "simple==2.0", + "require_simple==1.0", ) result = script.pip( - 'list', '-f', data.find_links, '--no-index', '--outdated', - '--not-required', '--format=json', + "list", + "-f", + data.find_links, + "--no-index", + "--outdated", + "--not-required", + "--format=json", ) assert [] == json.loads(result.stdout) def test_outdated_pre(script, data): - script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0') + script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") # Let's build a fake wheelhouse script.scratch_path.joinpath("wheelhouse").mkdir() - wheelhouse_path = script.scratch_path / 'wheelhouse' - wheelhouse_path.joinpath('simple-1.1-py2.py3-none-any.whl').write_text('') - wheelhouse_path.joinpath( - 'simple-2.0.dev0-py2.py3-none-any.whl' - ).write_text('') + wheelhouse_path = script.scratch_path / "wheelhouse" + wheelhouse_path.joinpath("simple-1.1-py2.py3-none-any.whl").write_text("") + wheelhouse_path.joinpath("simple-2.0.dev0-py2.py3-none-any.whl").write_text("") result = script.pip( - 'list', '--no-index', '--find-links', wheelhouse_path, - '--format=json', + "list", + "--no-index", + "--find-links", + wheelhouse_path, + "--format=json", ) assert {"name": "simple", "version": "1.0"} in json.loads(result.stdout) result = script.pip( - 'list', '--no-index', '--find-links', wheelhouse_path, '--outdated', - '--format=json', - ) - assert {"name": "simple", "version": "1.0", - "latest_version": "1.1", "latest_filetype": "wheel"} \ - in json.loads(result.stdout) - result_pre = script.pip('list', '--no-index', - '--find-links', wheelhouse_path, - '--outdated', '--pre', '--format=json') - assert {"name": "simple", "version": "1.0", - "latest_version": "2.0.dev0", "latest_filetype": "wheel"} \ - in json.loads(result_pre.stdout) + "list", + "--no-index", + "--find-links", + wheelhouse_path, + "--outdated", + "--format=json", + ) + assert { + "name": "simple", + "version": "1.0", + "latest_version": "1.1", + "latest_filetype": "wheel", + } in json.loads(result.stdout) + result_pre = script.pip( + "list", + "--no-index", + "--find-links", + wheelhouse_path, + "--outdated", + "--pre", + "--format=json", + ) + assert { + "name": "simple", + "version": "1.0", + "latest_version": "2.0.dev0", + "latest_filetype": "wheel", + } in json.loads(result_pre.stdout) def test_outdated_formats(script, data): """ Test of different outdated formats """ - script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0') + script.pip("install", "-f", data.find_links, "--no-index", "simple==1.0") # Let's build a fake wheelhouse script.scratch_path.joinpath("wheelhouse").mkdir() - wheelhouse_path = script.scratch_path / 'wheelhouse' - wheelhouse_path.joinpath('simple-1.1-py2.py3-none-any.whl').write_text('') + wheelhouse_path = script.scratch_path / "wheelhouse" + wheelhouse_path.joinpath("simple-1.1-py2.py3-none-any.whl").write_text("") result = script.pip( - 'list', '--no-index', '--find-links', wheelhouse_path, - '--format=freeze', + "list", + "--no-index", + "--find-links", + wheelhouse_path, + "--format=freeze", ) - assert 'simple==1.0' in result.stdout + assert "simple==1.0" in result.stdout # Check columns result = script.pip( - 'list', '--no-index', '--find-links', wheelhouse_path, - '--outdated', '--format=columns', + "list", + "--no-index", + "--find-links", + wheelhouse_path, + "--outdated", + "--format=columns", ) - assert 'Package Version Latest Type' in result.stdout - assert 'simple 1.0 1.1 wheel' in result.stdout + assert "Package Version Latest Type" in result.stdout + assert "simple 1.0 1.1 wheel" in result.stdout # Check freeze result = script.pip( - 'list', '--no-index', '--find-links', wheelhouse_path, - '--outdated', '--format=freeze', + "list", + "--no-index", + "--find-links", + wheelhouse_path, + "--outdated", + "--format=freeze", ) - assert 'simple==1.0' in result.stdout + assert "simple==1.0" in result.stdout # Check json result = script.pip( - 'list', '--no-index', '--find-links', wheelhouse_path, - '--outdated', '--format=json', + "list", + "--no-index", + "--find-links", + wheelhouse_path, + "--outdated", + "--format=json", ) data = json.loads(result.stdout) - assert data == [{'name': 'simple', 'version': '1.0', - 'latest_version': '1.1', 'latest_filetype': 'wheel'}] + assert data == [ + { + "name": "simple", + "version": "1.0", + "latest_version": "1.1", + "latest_filetype": "wheel", + } + ] def test_not_required_flag(script, data): - script.pip( - 'install', '-f', data.find_links, '--no-index', 'TopoRequires4' - ) - result = script.pip('list', '--not-required', expect_stderr=True) - assert 'TopoRequires4 ' in result.stdout, str(result) - assert 'TopoRequires ' not in result.stdout - assert 'TopoRequires2 ' not in result.stdout - assert 'TopoRequires3 ' not in result.stdout + script.pip("install", "-f", data.find_links, "--no-index", "TopoRequires4") + result = script.pip("list", "--not-required", expect_stderr=True) + assert "TopoRequires4 " in result.stdout, str(result) + assert "TopoRequires " not in result.stdout + assert "TopoRequires2 " not in result.stdout + assert "TopoRequires3 " not in result.stdout def test_list_freeze(simple_script): @@ -475,9 +568,9 @@ def test_list_freeze(simple_script): Test freeze formatting of list command """ - result = simple_script.pip('list', '--format=freeze') - assert 'simple==1.0' in result.stdout, str(result) - assert 'simple2==3.0' in result.stdout, str(result) + result = simple_script.pip("list", "--format=freeze") + assert "simple==1.0" in result.stdout, str(result) + assert "simple2==3.0" in result.stdout, str(result) def test_list_json(simple_script): @@ -485,24 +578,24 @@ def test_list_json(simple_script): Test json formatting of list command """ - result = simple_script.pip('list', '--format=json') + result = simple_script.pip("list", "--format=json") data = json.loads(result.stdout) - assert {'name': 'simple', 'version': '1.0'} in data - assert {'name': 'simple2', 'version': '3.0'} in data + assert {"name": "simple", "version": "1.0"} in data + assert {"name": "simple2", "version": "3.0"} in data def test_list_path(tmpdir, script, data): """ Test list with --path. """ - result = script.pip('list', '--path', tmpdir, '--format=json') + result = script.pip("list", "--path", tmpdir, "--format=json") json_result = json.loads(result.stdout) - assert {'name': 'simple', 'version': '2.0'} not in json_result + assert {"name": "simple", "version": "2.0"} not in json_result - script.pip_install_local('--target', tmpdir, 'simple==2.0') - result = script.pip('list', '--path', tmpdir, '--format=json') + script.pip_install_local("--target", tmpdir, "simple==2.0") + result = script.pip("list", "--path", tmpdir, "--format=json") json_result = json.loads(result.stdout) - assert {'name': 'simple', 'version': '2.0'} in json_result + assert {"name": "simple", "version": "2.0"} in json_result @pytest.mark.incompatible_with_test_venv @@ -511,16 +604,16 @@ def test_list_path_exclude_user(tmpdir, script, data): Test list with --path and make sure packages from --user are not picked up. """ - script.pip_install_local('--user', 'simple2') - script.pip_install_local('--target', tmpdir, 'simple==1.0') + script.pip_install_local("--user", "simple2") + script.pip_install_local("--target", tmpdir, "simple==1.0") - result = script.pip('list', '--user', '--format=json') + result = script.pip("list", "--user", "--format=json") json_result = json.loads(result.stdout) - assert {'name': 'simple2', 'version': '3.0'} in json_result + assert {"name": "simple2", "version": "3.0"} in json_result - result = script.pip('list', '--path', tmpdir, '--format=json') + result = script.pip("list", "--path", tmpdir, "--format=json") json_result = json.loads(result.stdout) - assert {'name': 'simple', 'version': '1.0'} in json_result + assert {"name": "simple", "version": "1.0"} in json_result def test_list_path_multiple(tmpdir, script, data): @@ -532,18 +625,17 @@ def test_list_path_multiple(tmpdir, script, data): path2 = tmpdir / "path2" os.mkdir(path2) - script.pip_install_local('--target', path1, 'simple==2.0') - script.pip_install_local('--target', path2, 'simple2==3.0') + script.pip_install_local("--target", path1, "simple==2.0") + script.pip_install_local("--target", path2, "simple2==3.0") - result = script.pip('list', '--path', path1, '--format=json') + result = script.pip("list", "--path", path1, "--format=json") json_result = json.loads(result.stdout) - assert {'name': 'simple', 'version': '2.0'} in json_result + assert {"name": "simple", "version": "2.0"} in json_result - result = script.pip('list', '--path', path1, '--path', path2, - '--format=json') + result = script.pip("list", "--path", path1, "--path", path2, "--format=json") json_result = json.loads(result.stdout) - assert {'name': 'simple', 'version': '2.0'} in json_result - assert {'name': 'simple2', 'version': '3.0'} in json_result + assert {"name": "simple", "version": "2.0"} in json_result + assert {"name": "simple2", "version": "3.0"} in json_result def test_list_skip_work_dir_pkg(script): @@ -552,15 +644,13 @@ def test_list_skip_work_dir_pkg(script): """ # Create a test package and create .egg-info dir - pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0') - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + pkg_path = create_test_package_with_setup(script, name="simple", version="1.0") + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) # List should not include package simple when run from package directory - result = script.pip('list', '--format=json', cwd=pkg_path) + result = script.pip("list", "--format=json", cwd=pkg_path) json_result = json.loads(result.stdout) - assert {'name': 'simple', 'version': '1.0'} not in json_result + assert {"name": "simple", "version": "1.0"} not in json_result def test_list_include_work_dir_pkg(script): @@ -570,15 +660,13 @@ def test_list_include_work_dir_pkg(script): """ # Create a test package and create .egg-info dir - pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0') - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + pkg_path = create_test_package_with_setup(script, name="simple", version="1.0") + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) - script.environ.update({'PYTHONPATH': pkg_path}) + script.environ.update({"PYTHONPATH": pkg_path}) # List should include package simple when run from package directory # when the package directory is in PYTHONPATH - result = script.pip('list', '--format=json', cwd=pkg_path) + result = script.pip("list", "--format=json", cwd=pkg_path) json_result = json.loads(result.stdout) - assert {'name': 'simple', 'version': '1.0'} in json_result + assert {"name": "simple", "version": "1.0"} in json_result diff --git a/tests/functional/test_new_resolver.py b/tests/functional/test_new_resolver.py index 1dab8d47091..d4049b0a733 100644 --- a/tests/functional/test_new_resolver.py +++ b/tests/functional/test_new_resolver.py @@ -14,27 +14,24 @@ def assert_installed(script, **kwargs): - ret = script.pip('list', '--format=json') + ret = script.pip("list", "--format=json") installed = set( - (canonicalize_name(val['name']), val['version']) + (canonicalize_name(val["name"]), val["version"]) for val in json.loads(ret.stdout) ) expected = set((canonicalize_name(k), v) for k, v in kwargs.items()) - assert expected <= installed, \ - "{!r} not all in {!r}".format(expected, installed) + assert expected <= installed, "{!r} not all in {!r}".format(expected, installed) def assert_not_installed(script, *args): ret = script.pip("list", "--format=json") - installed = set( - canonicalize_name(val["name"]) - for val in json.loads(ret.stdout) - ) + installed = set(canonicalize_name(val["name"]) for val in json.loads(ret.stdout)) # None of the given names should be listed as installed, i.e. their # intersection should be empty. expected = set(canonicalize_name(k) for k in args) - assert not (expected & installed), \ - "{!r} contained in {!r}".format(expected, installed) + assert not (expected & installed), "{!r} contained in {!r}".format( + expected, installed + ) def assert_editable(script, *args): @@ -42,8 +39,9 @@ def assert_editable(script, *args): # corresponding .egg-link file installed. # TODO: Implement a more rigorous way to test for editable installations. egg_links = set("{}.egg-link".format(arg) for arg in args) - assert egg_links <= set(os.listdir(script.site_packages_path)), \ - "{!r} not all found in {!r}".format(args, script.site_packages_path) + assert egg_links <= set( + os.listdir(script.site_packages_path) + ), "{!r} not all found in {!r}".format(args, script.site_packages_path) def test_new_resolver_can_install(script): @@ -53,10 +51,13 @@ def test_new_resolver_can_install(script): "0.1.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "simple" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "simple", ) assert_installed(script, simple="0.1.0") @@ -68,10 +69,13 @@ def test_new_resolver_can_install_with_version(script): "0.1.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "simple==0.1.0" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "simple==0.1.0", ) assert_installed(script, simple="0.1.0") @@ -88,10 +92,13 @@ def test_new_resolver_picks_latest_version(script): "0.2.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "simple" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "simple", ) assert_installed(script, simple="0.2.0") @@ -108,18 +115,24 @@ def test_new_resolver_picks_installed_version(script): "0.2.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "simple==0.1.0" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "simple==0.1.0", ) assert_installed(script, simple="0.1.0") result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "simple" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "simple", ) assert "Collecting" not in result.stdout, "Should not fetch new version" assert_installed(script, simple="0.1.0") @@ -137,17 +150,22 @@ def test_new_resolver_picks_installed_version_if_no_match_found(script): "0.2.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "simple==0.1.0" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "simple==0.1.0", ) assert_installed(script, simple="0.1.0") result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "simple" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "simple", ) assert "Collecting" not in result.stdout, "Should not fetch new version" assert_installed(script, simple="0.1.0") @@ -166,10 +184,13 @@ def test_new_resolver_installs_dependencies(script): "0.1.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "base" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "base", ) assert_installed(script, base="0.1.0", dep="0.1.0") @@ -187,10 +208,14 @@ def test_new_resolver_ignore_dependencies(script): "0.1.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", "--no-deps", - "--find-links", script.scratch_path, - "base" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--no-deps", + "--find-links", + script.scratch_path, + "base", ) assert_installed(script, base="0.1.0") assert_not_installed(script, "dep") @@ -219,10 +244,14 @@ def test_new_resolver_installs_extras(tmpdir, script, root_dep): "0.1.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "-r", req_file, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "-r", + req_file, ) assert_installed(script, base="0.1.0", dep="0.1.0") @@ -243,11 +272,15 @@ def test_new_resolver_installs_extras_deprecated(tmpdir, script): "0.1.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "-r", req_file, - expect_stderr=True + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "-r", + req_file, + expect_stderr=True, ) assert "DEPRECATION: Extras after version" in result.stderr assert_installed(script, base="0.1.0", dep="0.1.0") @@ -266,9 +299,12 @@ def test_new_resolver_installs_extras_warn_missing(script): "0.1.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base[add,missing]", expect_stderr=True, ) @@ -280,9 +316,12 @@ def test_new_resolver_installs_extras_warn_missing(script): def test_new_resolver_installed_message(script): create_basic_wheel_for_package(script, "A", "1.0") result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "A", expect_stderr=False, ) @@ -292,9 +331,12 @@ def test_new_resolver_installed_message(script): def test_new_resolver_no_dist_message(script): create_basic_wheel_for_package(script, "A", "1.0") result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "B", expect_error=True, expect_stderr=True, @@ -305,8 +347,9 @@ def test_new_resolver_no_dist_message(script): # requirement xxx (from versions: none) # ERROR: No matching distribution found for xxx - assert "Could not find a version that satisfies the requirement B" \ - in result.stderr, str(result) + assert ( + "Could not find a version that satisfies the requirement B" in result.stderr + ), str(result) assert "No matching distribution found for B" in result.stderr, str(result) @@ -323,11 +366,15 @@ def test_new_resolver_installs_editable(script): version="0.1.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base", - "--editable", source_dir, + "--editable", + source_dir, ) assert_installed(script, base="0.1.0", dep="0.1.0") assert_editable(script, "dep") @@ -339,7 +386,6 @@ def test_new_resolver_installs_editable(script): # Something impossible to satisfy. ("<2", False, "0.1.0"), ("<2", True, "0.2.0"), - # Something guaranteed to satisfy. (">=2", False, "0.2.0"), (">=2", True, "0.2.0"), @@ -374,7 +420,8 @@ def test_new_resolver_requires_python( "--use-feature=2020-resolver", "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "--find-links", + script.scratch_path, ] if ignore_requires_python: args.append("--ignore-requires-python") @@ -393,9 +440,12 @@ def test_new_resolver_requires_python_error(script): requires_python="<2", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base", expect_error=True, ) @@ -421,24 +471,28 @@ def test_new_resolver_installed(script): ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base", ) assert "Requirement already satisfied" not in result.stdout, str(result) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base~=0.1.0", ) - assert "Requirement already satisfied: base~=0.1.0" in result.stdout, \ - str(result) + assert "Requirement already satisfied: base~=0.1.0" in result.stdout, str(result) result.did_not_update( - script.site_packages / "base", - message="base 0.1.0 reinstalled" + script.site_packages / "base", message="base 0.1.0 reinstalled" ) @@ -451,23 +505,29 @@ def test_new_resolver_ignore_installed(script): satisfied_output = "Requirement already satisfied" result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base", ) assert satisfied_output not in result.stdout, str(result) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", "--ignore-installed", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--ignore-installed", + "--find-links", + script.scratch_path, "base", ) assert satisfied_output not in result.stdout, str(result) result.did_update( - script.site_packages / "base", - message="base 0.1.0 not reinstalled" + script.site_packages / "base", message="base 0.1.0 not reinstalled" ) @@ -492,19 +552,26 @@ def test_new_resolver_only_builds_sdists_when_needed(script): ) # We only ever need to check dep 0.2.0 as it's the latest version script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "base" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "base", ) assert_installed(script, base="0.1.0", dep="0.2.0") # We merge criteria here, as we have two "dep" requirements script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "base", "dep" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "base", + "dep", ) assert_installed(script, base="0.1.0", dep="0.2.0") @@ -514,26 +581,29 @@ def test_new_resolver_install_different_version(script): create_basic_wheel_for_package(script, "base", "0.2.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==0.1.0", ) # This should trigger an uninstallation of base. result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==0.2.0", ) assert "Uninstalling base-0.1.0" in result.stdout, str(result) assert "Successfully uninstalled base-0.1.0" in result.stdout, str(result) - result.did_update( - script.site_packages / "base", - message="base not upgraded" - ) + result.did_update(script.site_packages / "base", message="base not upgraded") assert_installed(script, base="0.2.0") @@ -541,28 +611,31 @@ def test_new_resolver_force_reinstall(script): create_basic_wheel_for_package(script, "base", "0.1.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==0.1.0", ) # This should trigger an uninstallation of base due to --force-reinstall, # even though the installed version matches. result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--force-reinstall", "base==0.1.0", ) assert "Uninstalling base-0.1.0" in result.stdout, str(result) assert "Successfully uninstalled base-0.1.0" in result.stdout, str(result) - result.did_update( - script.site_packages / "base", - message="base not reinstalled" - ) + result.did_update(script.site_packages / "base", message="base not reinstalled") assert_installed(script, base="0.1.0") @@ -589,9 +662,12 @@ def test_new_resolver_handles_prerelease( for version in available_versions: create_basic_wheel_for_package(script, "pkg", version) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, *pip_args ) assert_installed(script, pkg=expected_version) @@ -604,16 +680,19 @@ def test_new_resolver_handles_prerelease( (["dep; os_name == 'nonexist_os'"], ["pkg"]), # This tests the marker is picked up from a root dependency. ([], ["pkg", "dep; os_name == 'nonexist_os'"]), - ] + ], ) def test_new_reolver_skips_marker(script, pkg_deps, root_deps): create_basic_wheel_for_package(script, "pkg", "1.0", depends=pkg_deps) create_basic_wheel_for_package(script, "dep", "1.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, *root_deps ) assert_installed(script, pkg="1.0") @@ -627,7 +706,7 @@ def test_new_reolver_skips_marker(script, pkg_deps, root_deps): # This also tests the pkg constraint don't get merged with the # requirement prematurely. (pypa/pip#8134) ["pkg<2.0"], - ] + ], ) def test_new_resolver_constraints(script, constraints): create_basic_wheel_for_package(script, "pkg", "1.0") @@ -636,11 +715,15 @@ def test_new_resolver_constraints(script, constraints): constraints_file = script.scratch_path / "constraints.txt" constraints_file.write_text("\n".join(constraints)) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "-c", constraints_file, - "pkg" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "-c", + constraints_file, + "pkg", ) assert_installed(script, pkg="1.0") assert_not_installed(script, "constraint_only") @@ -652,11 +735,15 @@ def test_new_resolver_constraint_no_specifier(script): constraints_file = script.scratch_path / "constraints.txt" constraints_file.write_text("pkg") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "-c", constraints_file, - "pkg" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "-c", + constraints_file, + "pkg", ) assert_installed(script, pkg="1.0") @@ -683,10 +770,14 @@ def test_new_resolver_constraint_reject_invalid(script, constraint, error): constraints_file = script.scratch_path / "constraints.txt" constraints_file.write_text(constraint) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "-c", constraints_file, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "-c", + constraints_file, "pkg", expect_error=True, expect_stderr=True, @@ -702,11 +793,15 @@ def test_new_resolver_constraint_on_dependency(script): constraints_file = script.scratch_path / "constraints.txt" constraints_file.write_text("dep==2.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "-c", constraints_file, - "base" + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "-c", + constraints_file, + "base", ) assert_installed(script, base="1.0") assert_installed(script, dep="2.0") @@ -719,9 +814,12 @@ def test_new_resolver_constraint_on_path(script): constraints_txt = script.scratch_path / "constraints.txt" constraints_txt.write_text("foo==1.0") result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "-c", constraints_txt, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "-c", + constraints_txt, str(script.scratch_path), expect_error=True, ) @@ -745,10 +843,14 @@ def test_new_resolver_constraint_only_marker_match(script): constraints_txt.write_text(constrants_content) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "-c", constraints_txt, - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "-c", + constraints_txt, + "--find-links", + script.scratch_path, "pkg", ) assert_installed(script, pkg="1.0") @@ -758,9 +860,12 @@ def test_new_resolver_upgrade_needs_option(script): # Install pkg 1.0.0 create_basic_wheel_for_package(script, "pkg", "1.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "pkg", ) @@ -769,9 +874,12 @@ def test_new_resolver_upgrade_needs_option(script): # This should not upgrade because we don't specify --upgrade result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "pkg", ) @@ -780,19 +888,19 @@ def test_new_resolver_upgrade_needs_option(script): # This should upgrade result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--upgrade", "PKG", # Deliberately uppercase to check canonicalization ) assert "Uninstalling pkg-1.0.0" in result.stdout, str(result) assert "Successfully uninstalled pkg-1.0.0" in result.stdout, str(result) - result.did_update( - script.site_packages / "pkg", - message="pkg not upgraded" - ) + result.did_update(script.site_packages / "pkg", message="pkg not upgraded") assert_installed(script, pkg="2.0.0") @@ -800,9 +908,12 @@ def test_new_resolver_upgrade_strategy(script): create_basic_wheel_for_package(script, "base", "1.0.0", depends=["dep"]) create_basic_wheel_for_package(script, "dep", "1.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base", ) @@ -814,9 +925,12 @@ def test_new_resolver_upgrade_strategy(script): create_basic_wheel_for_package(script, "dep", "2.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--upgrade", "base", ) @@ -828,10 +942,14 @@ def test_new_resolver_upgrade_strategy(script): create_basic_wheel_for_package(script, "base", "3.0.0", depends=["dep"]) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "--upgrade", "--upgrade-strategy=eager", + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "--upgrade", + "--upgrade-strategy=eager", "base", ) @@ -847,8 +965,7 @@ class TestExtraMerge(object): """ def _local_with_setup(script, name, version, requires, extras): - """Create the package as a local source directory to install from path. - """ + """Create the package as a local source directory to install from path.""" return create_test_package_with_setup( script, name=name, @@ -858,8 +975,7 @@ def _local_with_setup(script, name, version, requires, extras): ) def _direct_wheel(script, name, version, requires, extras): - """Create the package as a wheel to install from path directly. - """ + """Create the package as a wheel to install from path directly.""" return create_basic_wheel_for_package( script, name=name, @@ -869,8 +985,7 @@ def _direct_wheel(script, name, version, requires, extras): ) def _wheel_from_index(script, name, version, requires, extras): - """Create the package as a wheel to install from index. - """ + """Create the package as a wheel to install from index.""" create_basic_wheel_for_package( script, name=name, @@ -889,7 +1004,10 @@ def _wheel_from_index(script, name, version, requires, extras): ], ) def test_new_resolver_extra_merge_in_package( - self, monkeypatch, script, pkg_builder, + self, + monkeypatch, + script, + pkg_builder, ): create_basic_wheel_for_package(script, "depdev", "1.0.0") create_basic_wheel_for_package( @@ -907,9 +1025,12 @@ def test_new_resolver_extra_merge_in_package( ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, requirement + "[dev]", ) assert_installed(script, pkg="1.0.0", dep="1.0.0", depdev="1.0.0") @@ -937,7 +1058,10 @@ def test_new_resolver_build_directory_error_zazo_19(script): can delete this. Please delete it and try again. """ create_basic_wheel_for_package( - script, "pkg_a", "3.0.0", depends=["pkg-b<2"], + script, + "pkg_a", + "3.0.0", + depends=["pkg-b<2"], ) create_basic_wheel_for_package(script, "pkg_a", "2.0.0") create_basic_wheel_for_package(script, "pkg_a", "1.0.0") @@ -946,10 +1070,14 @@ def test_new_resolver_build_directory_error_zazo_19(script): create_basic_sdist_for_package(script, "pkg_b", "1.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "pkg-a", "pkg-b", + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "pkg-a", + "pkg-b", ) assert_installed(script, pkg_a="3.0.0", pkg_b="1.0.0") @@ -959,17 +1087,23 @@ def test_new_resolver_upgrade_same_version(script): create_basic_wheel_for_package(script, "pkg", "1") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "pkg", ) assert_installed(script, pkg="2") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--upgrade", "pkg", ) @@ -983,9 +1117,12 @@ def test_new_resolver_local_and_req(script): version="0.1.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - source_dir, "pkg!=0.1.0", + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + source_dir, + "pkg!=0.1.0", expect_error=True, ) @@ -1010,7 +1147,8 @@ def test_new_resolver_no_deps_checks_requires_python(script): "--no-cache-dir", "--no-index", "--no-deps", - "--find-links", script.scratch_path, + "--find-links", + script.scratch_path, "base", expect_error=True, ) diff --git a/tests/functional/test_new_resolver_errors.py b/tests/functional/test_new_resolver_errors.py index 267f2130710..c9a6b3f59be 100644 --- a/tests/functional/test_new_resolver_errors.py +++ b/tests/functional/test_new_resolver_errors.py @@ -5,20 +5,30 @@ def test_new_resolver_conflict_requirements_file(tmpdir, script): create_basic_wheel_for_package(script, "base", "1.0") create_basic_wheel_for_package(script, "base", "2.0") create_basic_wheel_for_package( - script, "pkga", "1.0", depends=["base==1.0"], + script, + "pkga", + "1.0", + depends=["base==1.0"], ) create_basic_wheel_for_package( - script, "pkgb", "1.0", depends=["base==2.0"], + script, + "pkgb", + "1.0", + depends=["base==2.0"], ) req_file = tmpdir.joinpath("requirements.txt") req_file.write_text("pkga\npkgb") result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "-r", req_file, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, + "-r", + req_file, expect_error=True, ) diff --git a/tests/functional/test_new_resolver_hashes.py b/tests/functional/test_new_resolver_hashes.py index 4b13ebc307d..449fa7e1d27 100644 --- a/tests/functional/test_new_resolver_hashes.py +++ b/tests/functional/test_new_resolver_hashes.py @@ -4,13 +4,11 @@ import pytest from pip._internal.utils.urls import path_to_url -from tests.lib import ( - create_basic_sdist_for_package, - create_basic_wheel_for_package, -) +from tests.lib import create_basic_sdist_for_package, create_basic_wheel_for_package _FindLinks = collections.namedtuple( - "_FindLinks", "index_html sdist_hash wheel_hash", + "_FindLinks", + "index_html sdist_hash wheel_hash", ) @@ -79,9 +77,11 @@ def test_new_resolver_hash_intersect(script, requirements_template, message): "--no-cache-dir", "--no-deps", "--no-index", - "--find-links", find_links.index_html, + "--find-links", + find_links.index_html, "--verbose", - "--requirement", requirements_txt, + "--requirement", + requirements_txt, ) assert message.format(name=u"base") in result.stdout, str(result) @@ -112,10 +112,13 @@ def test_new_resolver_hash_intersect_from_constraint(script): "--no-cache-dir", "--no-deps", "--no-index", - "--find-links", find_links.index_html, + "--find-links", + find_links.index_html, "--verbose", - "--constraint", constraints_txt, - "--requirement", requirements_txt, + "--constraint", + constraints_txt, + "--requirement", + requirements_txt, ) message = ( @@ -143,7 +146,9 @@ def test_new_resolver_hash_intersect_from_constraint(script): ids=["both-requirements", "one-each"], ) def test_new_resolver_hash_intersect_empty( - script, requirements_template, constraints_template, + script, + requirements_template, + constraints_template, ): find_links = _create_find_links(script) @@ -169,9 +174,12 @@ def test_new_resolver_hash_intersect_empty( "--no-cache-dir", "--no-deps", "--no-index", - "--find-links", find_links.index_html, - "--constraint", constraints_txt, - "--requirement", requirements_txt, + "--find-links", + find_links.index_html, + "--constraint", + constraints_txt, + "--requirement", + requirements_txt, expect_error=True, ) @@ -200,8 +208,10 @@ def test_new_resolver_hash_intersect_empty_from_constraint(script): "--no-cache-dir", "--no-deps", "--no-index", - "--find-links", find_links.index_html, - "--constraint", constraints_txt, + "--find-links", + find_links.index_html, + "--constraint", + constraints_txt, "base==0.1.0", expect_error=True, ) diff --git a/tests/functional/test_new_resolver_target.py b/tests/functional/test_new_resolver_target.py index 6189e1cb5bc..fe5276daf07 100644 --- a/tests/functional/test_new_resolver_target.py +++ b/tests/functional/test_new_resolver_target.py @@ -7,7 +7,6 @@ @pytest.fixture() def make_fake_wheel(script): - def _make_fake_wheel(wheel_tag): wheel_house = script.scratch_path.joinpath("wheelhouse") wheel_house.mkdir() @@ -37,10 +36,13 @@ def test_new_resolver_target_checks_compatibility_failure( ): fake_wheel_tag = "fakepy1-fakeabi-fakeplat" args = [ - "install", "--use-feature=2020-resolver", + "install", + "--use-feature=2020-resolver", "--only-binary=:all:", - "--no-cache-dir", "--no-index", - "--target", str(script.scratch_path.joinpath("target")), + "--no-cache-dir", + "--no-index", + "--target", + str(script.scratch_path.joinpath("target")), make_fake_wheel(fake_wheel_tag), ] if implementation: @@ -58,7 +60,7 @@ def test_new_resolver_target_checks_compatibility_failure( abi, platform, ) - wheel_tag_matches = (args_tag == fake_wheel_tag) + wheel_tag_matches = args_tag == fake_wheel_tag result = script.pip(*args, expect_error=(not wheel_tag_matches)) diff --git a/tests/functional/test_new_resolver_user.py b/tests/functional/test_new_resolver_user.py index 2aae3eb16cb..7d583f881da 100644 --- a/tests/functional/test_new_resolver_user.py +++ b/tests/functional/test_new_resolver_user.py @@ -10,9 +10,12 @@ def test_new_resolver_install_user(script): create_basic_wheel_for_package(script, "base", "0.1.0") result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "base", ) @@ -28,15 +31,21 @@ def test_new_resolver_install_user_satisfied_by_global_site(script): create_basic_wheel_for_package(script, "base", "1.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==1.0.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "base==1.0.0", ) @@ -54,17 +63,23 @@ def test_new_resolver_install_user_conflict_in_user_site(script): create_basic_wheel_for_package(script, "base", "2.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "base==2.0.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "base==1.0.0", ) @@ -82,15 +97,21 @@ def test_new_resolver_install_user_in_virtualenv_with_conflict_fails(script): create_basic_wheel_for_package(script, "base", "2.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==2.0.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "base==1.0.0", expect_error=True, @@ -109,13 +130,15 @@ def patch_dist_in_site_packages(virtualenv): # install to the usersite because it will lack sys.path precedence..." # error: Monkey patch `dist_in_site_packages` in the resolver module so # it's possible to install a conflicting distribution in the user site. - virtualenv.sitecustomize = textwrap.dedent(""" + virtualenv.sitecustomize = textwrap.dedent( + """ def dist_in_site_packages(dist): return False from pip._internal.resolution.resolvelib import factory factory.dist_in_site_packages = dist_in_site_packages - """) + """ + ) @pytest.mark.incompatible_with_test_venv @@ -128,15 +151,21 @@ def test_new_resolver_install_user_reinstall_global_site(script): create_basic_wheel_for_package(script, "base", "1.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==1.0.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "--force-reinstall", "base==1.0.0", @@ -159,16 +188,22 @@ def test_new_resolver_install_user_conflict_in_global_site(script): create_basic_wheel_for_package(script, "base", "2.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==1.0.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "base==2.0.0", ) @@ -191,24 +226,33 @@ def test_new_resolver_install_user_conflict_in_global_and_user_sites(script): create_basic_wheel_for_package(script, "base", "2.0.0") script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "base==2.0.0", ) script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "--force-reinstall", "base==2.0.0", ) result = script.pip( - "install", "--use-feature=2020-resolver", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, + "install", + "--use-feature=2020-resolver", + "--no-cache-dir", + "--no-index", + "--find-links", + script.scratch_path, "--user", "base==1.0.0", ) diff --git a/tests/functional/test_no_color.py b/tests/functional/test_no_color.py index 48ed3ff7848..09f5a7c0f27 100644 --- a/tests/functional/test_no_color.py +++ b/tests/functional/test_no_color.py @@ -8,8 +8,7 @@ def test_no_color(script): - """Ensure colour output disabled when --no-color is passed. - """ + """Ensure colour output disabled when --no-color is passed.""" # Using 'script' in this test allows for transparently testing pip's output # since pip is smart enough to disable colour output when piped, which is # not the behaviour we want to be testing here. @@ -19,14 +18,17 @@ def test_no_color(script): # # This test will stay until someone has the time to rewrite it. command = ( - 'script --flush --quiet --return /tmp/pip-test-no-color.txt ' + "script --flush --quiet --return /tmp/pip-test-no-color.txt " '--command "pip uninstall {} noSuchPackage"' ) def get_run_output(option): cmd = command.format(option) proc = subprocess.Popen( - cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, ) proc.communicate() if proc.returncode: @@ -40,5 +42,6 @@ def get_run_output(option): os.unlink("/tmp/pip-test-no-color.txt") assert "\x1b" in get_run_output(option=""), "Expected color in output" - assert "\x1b" not in get_run_output(option="--no-color"), \ - "Expected no color in output" + assert "\x1b" not in get_run_output( + option="--no-color" + ), "Expected no color in output" diff --git a/tests/functional/test_pep517.py b/tests/functional/test_pep517.py index bcad4793672..c30582a9723 100644 --- a/tests/functional/test_pep517.py +++ b/tests/functional/test_pep517.py @@ -8,15 +8,15 @@ def make_project(tmpdir, requires=None, backend=None, backend_path=None): requires = requires or [] - project_dir = tmpdir / 'project' + project_dir = tmpdir / "project" project_dir.mkdir() - buildsys = {'requires': requires} + buildsys = {"requires": requires} if backend: - buildsys['build-backend'] = backend + buildsys["build-backend"] = backend if backend_path: - buildsys['backend-path'] = backend_path - data = toml.dumps({'build-system': buildsys}) - project_dir.joinpath('pyproject.toml').write_text(data) + buildsys["backend-path"] = backend_path + data = toml.dumps({"build-system": buildsys}) + project_dir.joinpath("pyproject.toml").write_text(data) return project_dir @@ -28,10 +28,10 @@ def test_backend(tmpdir, data): req.load_pyproject_toml() env = BuildEnvironment() finder = make_test_finder(find_links=[data.backends]) - env.install_requirements(finder, ["dummy_backend"], 'normal', "Installing") + env.install_requirements(finder, ["dummy_backend"], "normal", "Installing") conflicting, missing = env.check_requirements(["dummy_backend"]) assert not conflicting and not missing - assert hasattr(req.pep517_backend, 'build_wheel') + assert hasattr(req.pep517_backend, "build_wheel") with env: assert req.pep517_backend.build_wheel("dir") == "Backend called" @@ -48,16 +48,14 @@ def build_wheel( def test_backend_path(tmpdir, data): """Check we can call a backend inside the project""" - project_dir = make_project( - tmpdir, backend="dummy_backend", backend_path=['.'] - ) - (project_dir / 'dummy_backend.py').write_text(dummy_backend_code) + project_dir = make_project(tmpdir, backend="dummy_backend", backend_path=["."]) + (project_dir / "dummy_backend.py").write_text(dummy_backend_code) req = InstallRequirement(None, None) req.source_dir = project_dir # make req believe it has been unpacked req.load_pyproject_toml() env = BuildEnvironment() - assert hasattr(req.pep517_backend, 'build_wheel') + assert hasattr(req.pep517_backend, "build_wheel") with env: assert req.pep517_backend.build_wheel("dir") == "Backend called" @@ -65,9 +63,9 @@ def test_backend_path(tmpdir, data): def test_backend_path_and_dep(tmpdir, data): """Check we can call a requirement's backend successfully""" project_dir = make_project( - tmpdir, backend="dummy_internal_backend", backend_path=['.'] + tmpdir, backend="dummy_internal_backend", backend_path=["."] ) - (project_dir / 'dummy_internal_backend.py').write_text( + (project_dir / "dummy_internal_backend.py").write_text( "from dummy_backend import build_wheel" ) req = InstallRequirement(None, None) @@ -75,9 +73,9 @@ def test_backend_path_and_dep(tmpdir, data): req.load_pyproject_toml() env = BuildEnvironment() finder = make_test_finder(find_links=[data.backends]) - env.install_requirements(finder, ["dummy_backend"], 'normal', "Installing") + env.install_requirements(finder, ["dummy_backend"], "normal", "Installing") - assert hasattr(req.pep517_backend, 'build_wheel') + assert hasattr(req.pep517_backend, "build_wheel") with env: assert req.pep517_backend.build_wheel("dir") == "Backend called" @@ -85,170 +83,172 @@ def test_backend_path_and_dep(tmpdir, data): def test_pep517_install(script, tmpdir, data): """Check we can build with a custom backend""" project_dir = make_project( - tmpdir, requires=['test_backend'], - backend="test_backend" + tmpdir, requires=["test_backend"], backend="test_backend" ) - result = script.pip( - 'install', '--no-index', '-f', data.backends, project_dir - ) - result.assert_installed('project', editable=False) + result = script.pip("install", "--no-index", "-f", data.backends, project_dir) + result.assert_installed("project", editable=False) def test_pep517_install_with_reqs(script, tmpdir, data): """Backend generated requirements are installed in the build env""" project_dir = make_project( - tmpdir, requires=['test_backend'], - backend="test_backend" + tmpdir, requires=["test_backend"], backend="test_backend" ) project_dir.joinpath("backend_reqs.txt").write_text("simplewheel") result = script.pip( - 'install', '--no-index', - '-f', data.backends, - '-f', data.packages, - project_dir + "install", "--no-index", "-f", data.backends, "-f", data.packages, project_dir ) - result.assert_installed('project', editable=False) + result.assert_installed("project", editable=False) def test_no_use_pep517_without_setup_py(script, tmpdir, data): """Using --no-use-pep517 requires setup.py""" project_dir = make_project( - tmpdir, requires=['test_backend'], - backend="test_backend" + tmpdir, requires=["test_backend"], backend="test_backend" ) result = script.pip( - 'install', '--no-index', '--no-use-pep517', - '-f', data.backends, + "install", + "--no-index", + "--no-use-pep517", + "-f", + data.backends, project_dir, - expect_error=True + expect_error=True, ) - assert 'project does not have a setup.py' in result.stderr + assert "project does not have a setup.py" in result.stderr def test_conflicting_pep517_backend_requirements(script, tmpdir, data): project_dir = make_project( - tmpdir, requires=['test_backend', 'simplewheel==1.0'], - backend="test_backend" + tmpdir, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" ) project_dir.joinpath("backend_reqs.txt").write_text("simplewheel==2.0") result = script.pip( - 'install', '--no-index', - '-f', data.backends, - '-f', data.packages, + "install", + "--no-index", + "-f", + data.backends, + "-f", + data.packages, project_dir, - expect_error=True + expect_error=True, ) msg = ( - 'Some build dependencies for {url} conflict with the backend ' - 'dependencies: simplewheel==1.0 is incompatible with ' - 'simplewheel==2.0.'.format(url=path_to_url(project_dir))) - assert ( - result.returncode != 0 and - msg in result.stderr - ), str(result) + "Some build dependencies for {url} conflict with the backend " + "dependencies: simplewheel==1.0 is incompatible with " + "simplewheel==2.0.".format(url=path_to_url(project_dir)) + ) + assert result.returncode != 0 and msg in result.stderr, str(result) def test_pep517_backend_requirements_already_satisfied(script, tmpdir, data): project_dir = make_project( - tmpdir, requires=['test_backend', 'simplewheel==1.0'], - backend="test_backend" + tmpdir, requires=["test_backend", "simplewheel==1.0"], backend="test_backend" ) project_dir.joinpath("backend_reqs.txt").write_text("simplewheel") result = script.pip( - 'install', '--no-index', - '-f', data.backends, - '-f', data.packages, + "install", + "--no-index", + "-f", + data.backends, + "-f", + data.packages, project_dir, ) - assert 'Installing backend dependencies:' not in result.stdout + assert "Installing backend dependencies:" not in result.stdout def test_pep517_install_with_no_cache_dir(script, tmpdir, data): - """Check builds with a custom backends work, even with no cache. - """ + """Check builds with a custom backends work, even with no cache.""" project_dir = make_project( - tmpdir, requires=['test_backend'], - backend="test_backend" + tmpdir, requires=["test_backend"], backend="test_backend" ) result = script.pip( - 'install', '--no-cache-dir', '--no-index', '-f', data.backends, + "install", + "--no-cache-dir", + "--no-index", + "-f", + data.backends, project_dir, ) - result.assert_installed('project', editable=False) + result.assert_installed("project", editable=False) def make_pyproject_with_setup(tmpdir, build_system=True, set_backend=True): - project_dir = tmpdir / 'project' + project_dir = tmpdir / "project" project_dir.mkdir() - setup_script = ( - 'from setuptools import setup\n' - ) + setup_script = "from setuptools import setup\n" expect_script_dir_on_path = True if build_system: buildsys = { - 'requires': ['setuptools', 'wheel'], + "requires": ["setuptools", "wheel"], } if set_backend: - buildsys['build-backend'] = 'setuptools.build_meta' + buildsys["build-backend"] = "setuptools.build_meta" expect_script_dir_on_path = False - project_data = toml.dumps({'build-system': buildsys}) + project_data = toml.dumps({"build-system": buildsys}) else: - project_data = '' + project_data = "" if expect_script_dir_on_path: - setup_script += ( - 'from pep517_test import __version__\n' - ) + setup_script += "from pep517_test import __version__\n" else: setup_script += ( - 'try:\n' - ' import pep517_test\n' - 'except ImportError:\n' - ' pass\n' - 'else:\n' + "try:\n" + " import pep517_test\n" + "except ImportError:\n" + " pass\n" + "else:\n" ' raise RuntimeError("Source dir incorrectly on sys.path")\n' ) - setup_script += ( - 'setup(name="pep517_test", version="0.1", packages=["pep517_test"])' - ) + setup_script += 'setup(name="pep517_test", version="0.1", packages=["pep517_test"])' - project_dir.joinpath('pyproject.toml').write_text(project_data) - project_dir.joinpath('setup.py').write_text(setup_script) + project_dir.joinpath("pyproject.toml").write_text(project_data) + project_dir.joinpath("setup.py").write_text(setup_script) package_dir = project_dir / "pep517_test" package_dir.mkdir() - package_dir.joinpath('__init__.py').write_text('__version__ = "0.1"') + package_dir.joinpath("__init__.py").write_text('__version__ = "0.1"') return project_dir, "pep517_test" def test_no_build_system_section(script, tmpdir, data, common_wheels): - """Check builds with setup.py, pyproject.toml, but no build-system section. - """ + """Check builds with setup.py, pyproject.toml, but no build-system section.""" project_dir, name = make_pyproject_with_setup(tmpdir, build_system=False) result = script.pip( - 'install', '--no-cache-dir', '--no-index', '-f', common_wheels, + "install", + "--no-cache-dir", + "--no-index", + "-f", + common_wheels, project_dir, ) result.assert_installed(name, editable=False) def test_no_build_backend_entry(script, tmpdir, data, common_wheels): - """Check builds with setup.py, pyproject.toml, but no build-backend entry. - """ + """Check builds with setup.py, pyproject.toml, but no build-backend entry.""" project_dir, name = make_pyproject_with_setup(tmpdir, set_backend=False) result = script.pip( - 'install', '--no-cache-dir', '--no-index', '-f', common_wheels, + "install", + "--no-cache-dir", + "--no-index", + "-f", + common_wheels, project_dir, ) result.assert_installed(name, editable=False) def test_explicit_setuptools_backend(script, tmpdir, data, common_wheels): - """Check builds with setup.py, pyproject.toml, and a build-backend entry. - """ + """Check builds with setup.py, pyproject.toml, and a build-backend entry.""" project_dir, name = make_pyproject_with_setup(tmpdir) result = script.pip( - 'install', '--no-cache-dir', '--no-index', '-f', common_wheels, + "install", + "--no-cache-dir", + "--no-index", + "-f", + common_wheels, project_dir, ) result.assert_installed(name, editable=False) @@ -260,11 +260,15 @@ def test_pep517_and_build_options(script, tmpdir, data, common_wheels): """Backend generated requirements are installed in the build env""" project_dir, name = make_pyproject_with_setup(tmpdir) result = script.pip( - 'wheel', '--wheel-dir', tmpdir, - '--build-option', 'foo', - '-f', common_wheels, + "wheel", + "--wheel-dir", + tmpdir, + "--build-option", + "foo", + "-f", + common_wheels, project_dir, - expect_error=True + expect_error=True, ) - assert 'Cannot build wheel' in result.stderr - assert 'when --build-option is present' in result.stderr + assert "Cannot build wheel" in result.stderr + assert "when --build-option is present" in result.stderr diff --git a/tests/functional/test_requests.py b/tests/functional/test_requests.py index f8eef787c95..3921c39fbc2 100644 --- a/tests/functional/test_requests.py +++ b/tests/functional/test_requests.py @@ -4,14 +4,15 @@ @pytest.mark.skipif def test_timeout(script): result = script.pip( - "--timeout", "0.01", "install", "-vvv", "INITools", + "--timeout", + "0.01", + "install", + "-vvv", + "INITools", expect_error=True, ) assert ( "Could not fetch URL https://pypi.org/simple/INITools/: " "timed out" in result.stdout ) - assert ( - "Could not fetch URL https://pypi.org/simple/: " - "timed out" in result.stdout - ) + assert "Could not fetch URL https://pypi.org/simple/: " "timed out" in result.stdout diff --git a/tests/functional/test_search.py b/tests/functional/test_search.py index 5918b4f64f9..804b0bb1a15 100644 --- a/tests/functional/test_search.py +++ b/tests/functional/test_search.py @@ -5,14 +5,10 @@ from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS from pip._internal.commands import create_command -from pip._internal.commands.search import ( - highest_version, - print_results, - transform_hits, -) +from pip._internal.commands.search import highest_version, print_results, transform_hits from tests.lib import pyversion -if pyversion >= '3': +if pyversion >= "3": VERBOSE_FALSE = False else: VERBOSE_FALSE = 0 @@ -23,8 +19,8 @@ def test_version_compare(): Test version comparison. """ - assert highest_version(['1.0', '2.0', '0.1']) == '2.0' - assert highest_version(['1.0a1', '1.0']) == '1.0' + assert highest_version(["1.0", "2.0", "0.1"]) == "2.0" + assert highest_version(["1.0a1", "1.0"]) == "1.0" def test_pypi_xml_transformation(): @@ -34,32 +30,32 @@ def test_pypi_xml_transformation(): """ pypi_hits = [ { - 'name': 'foo', - 'summary': 'foo summary', - 'version': '1.0', + "name": "foo", + "summary": "foo summary", + "version": "1.0", }, { - 'name': 'foo', - 'summary': 'foo summary v2', - 'version': '2.0', + "name": "foo", + "summary": "foo summary v2", + "version": "2.0", }, { - '_pypi_ordering': 50, - 'name': 'bar', - 'summary': 'bar summary', - 'version': '1.0', + "_pypi_ordering": 50, + "name": "bar", + "summary": "bar summary", + "version": "1.0", }, ] expected = [ { - 'versions': ['1.0', '2.0'], - 'name': 'foo', - 'summary': 'foo summary v2', + "versions": ["1.0", "2.0"], + "name": "foo", + "summary": "foo summary v2", }, { - 'versions': ['1.0'], - 'name': 'bar', - 'summary': 'bar summary', + "versions": ["1.0"], + "name": "bar", + "summary": "bar summary", }, ] assert transform_hits(pypi_hits) == expected @@ -71,39 +67,39 @@ def test_basic_search(script): End to end test of search command. """ - output = script.pip('search', 'pip') + output = script.pip("search", "pip") assert ( - 'The PyPA recommended tool for installing ' - 'Python packages.' in output.stdout + "The PyPA recommended tool for installing " "Python packages." in output.stdout ) @pytest.mark.network @pytest.mark.skip( - reason=("Warehouse search behavior is different and no longer returns " - "multiple results. See " - "https://github.com/pypa/warehouse/issues/3717 for more " - "information."), + reason=( + "Warehouse search behavior is different and no longer returns " + "multiple results. See " + "https://github.com/pypa/warehouse/issues/3717 for more " + "information." + ), ) def test_multiple_search(script): """ Test searching for multiple packages at once. """ - output = script.pip('search', 'pip', 'INITools') + output = script.pip("search", "pip", "INITools") assert ( - 'The PyPA recommended tool for installing ' - 'Python packages.' in output.stdout + "The PyPA recommended tool for installing " "Python packages." in output.stdout ) - assert 'Tools for parsing and using INI-style files' in output.stdout + assert "Tools for parsing and using INI-style files" in output.stdout def test_search_missing_argument(script): """ Test missing required argument for search """ - result = script.pip('search', expect_error=True) - assert 'ERROR: Missing required argument (search query).' in result.stderr + result = script.pip("search", expect_error=True) + assert "ERROR: Missing required argument (search query)." in result.stderr @pytest.mark.network @@ -111,7 +107,7 @@ def test_run_method_should_return_success_when_find_packages(): """ Test SearchCommand.run for found package """ - command = create_command('search') + command = create_command("search") cmdline = "--index=https://pypi.org/pypi pip" with command.main_context(): options, args = command.parse_args(cmdline.split()) @@ -124,7 +120,7 @@ def test_run_method_should_return_no_matches_found_when_does_not_find_pkgs(): """ Test SearchCommand.run for no matches """ - command = create_command('search') + command = create_command("search") cmdline = "--index=https://pypi.org/pypi nonexistentpackage" with command.main_context(): options, args = command.parse_args(cmdline.split()) @@ -137,7 +133,7 @@ def test_search_should_exit_status_code_zero_when_find_packages(script): """ Test search exit status code for package found """ - result = script.pip('search', 'pip') + result = script.pip("search", "pip") assert result.returncode == SUCCESS @@ -146,7 +142,7 @@ def test_search_exit_status_code_when_finds_no_package(script): """ Test search exit status code for no matches """ - result = script.pip('search', 'nonexistentpackage', expect_error=True) + result = script.pip("search", "nonexistentpackage", expect_error=True) assert result.returncode == NO_MATCHES_FOUND, result.returncode @@ -156,26 +152,24 @@ def test_latest_prerelease_install_message(caplog, monkeypatch): """ hits = [ { - 'name': 'ni', - 'summary': 'For knights who say Ni!', - 'versions': ['1.0.0', '1.0.1a'] + "name": "ni", + "summary": "For knights who say Ni!", + "versions": ["1.0.0", "1.0.1a"], } ] installed_package = pretend.stub(project_name="ni") - monkeypatch.setattr("pip._vendor.pkg_resources.working_set", - [installed_package]) + monkeypatch.setattr("pip._vendor.pkg_resources.working_set", [installed_package]) dist = pretend.stub(version="1.0.0") get_dist = pretend.call_recorder(lambda x: dist) - monkeypatch.setattr("pip._internal.commands.search.get_distribution", - get_dist) + monkeypatch.setattr("pip._internal.commands.search.get_distribution", get_dist) with caplog.at_level(logging.INFO): print_results(hits) message = caplog.records[-1].getMessage() assert 'pre-release; install with "pip install --pre"' in message - assert get_dist.calls == [pretend.call('ni')] + assert get_dist.calls == [pretend.call("ni")] def test_search_print_results_should_contain_latest_versions(caplog): @@ -184,20 +178,20 @@ def test_search_print_results_should_contain_latest_versions(caplog): """ hits = [ { - 'name': 'testlib1', - 'summary': 'Test library 1.', - 'versions': ['1.0.5', '1.0.3'] + "name": "testlib1", + "summary": "Test library 1.", + "versions": ["1.0.5", "1.0.3"], }, { - 'name': 'testlib2', - 'summary': 'Test library 1.', - 'versions': ['2.0.1', '2.0.3'] - } + "name": "testlib2", + "summary": "Test library 1.", + "versions": ["2.0.1", "2.0.3"], + }, ] with caplog.at_level(logging.INFO): print_results(hits) log_messages = sorted([r.getMessage() for r in caplog.records]) - assert log_messages[0].startswith('testlib1 (1.0.5)') - assert log_messages[1].startswith('testlib2 (2.0.3)') + assert log_messages[0].startswith("testlib1 (1.0.5)") + assert log_messages[1].startswith("testlib2 (2.0.3)") diff --git a/tests/functional/test_show.py b/tests/functional/test_show.py index c19228b566c..8a75608c5f0 100644 --- a/tests/functional/test_show.py +++ b/tests/functional/test_show.py @@ -12,13 +12,13 @@ def test_basic_show(script): """ Test end to end test for show command. """ - result = script.pip('show', 'pip') + result = script.pip("show", "pip") lines = result.stdout.splitlines() assert len(lines) == 10 - assert 'Name: pip' in lines - assert 'Version: {}'.format(__version__) in lines - assert any(line.startswith('Location: ') for line in lines) - assert 'Requires: ' in lines + assert "Name: pip" in lines + assert "Version: {}".format(__version__) in lines + assert any(line.startswith("Location: ") for line in lines) + assert "Requires: " in lines def test_show_with_files_not_found(script, data): @@ -26,29 +26,29 @@ def test_show_with_files_not_found(script, data): Test for show command with installed files listing enabled and installed-files.txt not found. """ - editable = data.packages.joinpath('SetupPyUTF8') - script.pip('install', '-e', editable) - result = script.pip('show', '-f', 'SetupPyUTF8') + editable = data.packages.joinpath("SetupPyUTF8") + script.pip("install", "-e", editable) + result = script.pip("show", "-f", "SetupPyUTF8") lines = result.stdout.splitlines() assert len(lines) == 12 - assert 'Name: SetupPyUTF8' in lines - assert 'Version: 0.0.0' in lines - assert any(line.startswith('Location: ') for line in lines) - assert 'Requires: ' in lines - assert 'Files:' in lines - assert 'Cannot locate installed-files.txt' in lines + assert "Name: SetupPyUTF8" in lines + assert "Version: 0.0.0" in lines + assert any(line.startswith("Location: ") for line in lines) + assert "Requires: " in lines + assert "Files:" in lines + assert "Cannot locate installed-files.txt" in lines def test_show_with_files_from_wheel(script, data): """ Test that a wheel's files can be listed """ - wheel_file = data.packages.joinpath('simple.dist-0.1-py2.py3-none-any.whl') - script.pip('install', '--no-index', wheel_file) - result = script.pip('show', '-f', 'simple.dist') + wheel_file = data.packages.joinpath("simple.dist-0.1-py2.py3-none-any.whl") + script.pip("install", "--no-index", wheel_file) + result = script.pip("show", "-f", "simple.dist") lines = result.stdout.splitlines() - assert 'Name: simple.dist' in lines - assert 'Cannot locate installed-files.txt' not in lines[6], lines[6] + assert "Name: simple.dist" in lines + assert "Cannot locate installed-files.txt" not in lines[6], lines[6] assert re.search(r"Files:\n( .+\n)+", result.stdout) @@ -57,10 +57,10 @@ def test_show_with_all_files(script): """ Test listing all files in the show command. """ - script.pip('install', 'initools==0.2') - result = script.pip('show', '--files', 'initools') + script.pip("install", "initools==0.2") + result = script.pip("show", "--files", "initools") lines = result.stdout.splitlines() - assert 'Cannot locate installed-files.txt' not in lines[6], lines[6] + assert "Cannot locate installed-files.txt" not in lines[6], lines[6] assert re.search(r"Files:\n( .+\n)+", result.stdout) @@ -68,15 +68,15 @@ def test_missing_argument(script): """ Test show command with no arguments. """ - result = script.pip('show', expect_error=True) - assert 'ERROR: Please provide a package name or names.' in result.stderr + result = script.pip("show", expect_error=True) + assert "ERROR: Please provide a package name or names." in result.stderr def test_find_package_not_found(): """ Test trying to get info about a nonexistent package. """ - result = search_packages_info(['abcd3']) + result = search_packages_info(["abcd3"]) assert len(list(result)) == 0 @@ -89,8 +89,8 @@ def test_report_single_not_found(script): # Also, the following should report an error as there are no results # to print. Consequently, there is no need to pass # allow_stderr_warning=True since this is implied by expect_error=True. - result = script.pip('show', 'Abcd-3', expect_error=True) - assert 'WARNING: Package(s) not found: Abcd-3' in result.stderr + result = script.pip("show", "Abcd-3", expect_error=True) + assert "WARNING: Package(s) not found: Abcd-3" in result.stderr assert not result.stdout.splitlines() @@ -99,13 +99,11 @@ def test_report_mixed_not_found(script): Test passing a mixture of found and not-found names. """ # We test passing non-canonicalized names. - result = script.pip( - 'show', 'Abcd3', 'A-B-C', 'pip', allow_stderr_warning=True - ) - assert 'WARNING: Package(s) not found: A-B-C, Abcd3' in result.stderr + result = script.pip("show", "Abcd3", "A-B-C", "pip", allow_stderr_warning=True) + assert "WARNING: Package(s) not found: A-B-C, Abcd3" in result.stderr lines = result.stdout.splitlines() assert len(lines) == 10 - assert 'Name: pip' in lines + assert "Name: pip" in lines def test_search_any_case(): @@ -113,9 +111,9 @@ def test_search_any_case(): Search for a package in any case. """ - result = list(search_packages_info(['PIP'])) + result = list(search_packages_info(["PIP"])) assert len(result) == 1 - assert result[0]['name'] == 'pip' + assert result[0]["name"] == "pip" def test_more_than_one_package(): @@ -123,7 +121,7 @@ def test_more_than_one_package(): Search for more than one package. """ - result = list(search_packages_info(['pIp', 'pytest', 'Virtualenv'])) + result = list(search_packages_info(["pIp", "pytest", "Virtualenv"])) assert len(result) == 3 @@ -131,9 +129,9 @@ def test_show_verbose_with_classifiers(script): """ Test that classifiers can be listed """ - result = script.pip('show', 'pip', '--verbose') + result = script.pip("show", "pip", "--verbose") lines = result.stdout.splitlines() - assert 'Name: pip' in lines + assert "Name: pip" in lines assert re.search(r"Classifiers:\n( .+\n)+", result.stdout) assert "Intended Audience :: Developers" in result.stdout @@ -142,36 +140,45 @@ def test_show_verbose_installer(script, data): """ Test that the installer is shown (this currently needs a wheel install) """ - wheel_file = data.packages.joinpath('simple.dist-0.1-py2.py3-none-any.whl') - script.pip('install', '--no-index', wheel_file) - result = script.pip('show', '--verbose', 'simple.dist') + wheel_file = data.packages.joinpath("simple.dist-0.1-py2.py3-none-any.whl") + script.pip("install", "--no-index", wheel_file) + result = script.pip("show", "--verbose", "simple.dist") lines = result.stdout.splitlines() - assert 'Name: simple.dist' in lines - assert 'Installer: pip' in lines + assert "Name: simple.dist" in lines + assert "Installer: pip" in lines def test_show_verbose(script): """ Test end to end test for verbose show command. """ - result = script.pip('show', '--verbose', 'pip') + result = script.pip("show", "--verbose", "pip") lines = result.stdout.splitlines() - assert any(line.startswith('Metadata-Version: ') for line in lines) - assert any(line.startswith('Installer: ') for line in lines) - assert 'Entry-points:' in lines - assert 'Classifiers:' in lines + assert any(line.startswith("Metadata-Version: ") for line in lines) + assert any(line.startswith("Installer: ") for line in lines) + assert "Entry-points:" in lines + assert "Classifiers:" in lines def test_all_fields(script): """ Test that all the fields are present """ - result = script.pip('show', 'pip') + result = script.pip("show", "pip") lines = result.stdout.splitlines() - expected = {'Name', 'Version', 'Summary', 'Home-page', 'Author', - 'Author-email', 'License', 'Location', 'Requires', - 'Required-by'} - actual = {re.sub(':.*$', '', line) for line in lines} + expected = { + "Name", + "Version", + "Summary", + "Home-page", + "Author", + "Author-email", + "License", + "Location", + "Requires", + "Required-by", + } + actual = {re.sub(":.*$", "", line) for line in lines} assert actual == expected @@ -179,7 +186,7 @@ def test_pip_show_is_short(script): """ Test that pip show stays short """ - result = script.pip('show', 'pip') + result = script.pip("show", "pip") lines = result.stdout.splitlines() assert len(lines) <= 10 @@ -188,19 +195,17 @@ def test_pip_show_divider(script, data): """ Expect a divider between packages """ - script.pip('install', 'pip-test-package', '--no-index', - '-f', data.packages) - result = script.pip('show', 'pip', 'pip-test-package') + script.pip("install", "pip-test-package", "--no-index", "-f", data.packages) + result = script.pip("show", "pip", "pip-test-package") lines = result.stdout.splitlines() assert "---" in lines def test_package_name_is_canonicalized(script, data): - script.pip('install', 'pip-test-package', '--no-index', '-f', - data.packages) + script.pip("install", "pip-test-package", "--no-index", "-f", data.packages) - dash_show_result = script.pip('show', 'pip-test-package') - underscore_upper_show_result = script.pip('show', 'pip-test_Package') + dash_show_result = script.pip("show", "pip-test-package") + underscore_upper_show_result = script.pip("show", "pip-test_Package") assert underscore_upper_show_result.returncode == 0 assert underscore_upper_show_result.stdout == dash_show_result.stdout @@ -210,16 +215,14 @@ def test_show_required_by_packages_basic(script, data): """ Test that installed packages that depend on this package are shown """ - editable_path = os.path.join(data.src, 'requires_simple') - script.pip( - 'install', '--no-index', '-f', data.find_links, editable_path - ) + editable_path = os.path.join(data.src, "requires_simple") + script.pip("install", "--no-index", "-f", data.find_links, editable_path) - result = script.pip('show', 'simple') + result = script.pip("show", "simple") lines = result.stdout.splitlines() - assert 'Name: simple' in lines - assert 'Required-by: requires-simple' in lines + assert "Name: simple" in lines + assert "Required-by: requires-simple" in lines def test_show_required_by_packages_capitalized(script, data): @@ -227,16 +230,14 @@ def test_show_required_by_packages_capitalized(script, data): Test that the installed packages which depend on a package are shown where the package has a capital letter """ - editable_path = os.path.join(data.src, 'requires_capitalized') - script.pip( - 'install', '--no-index', '-f', data.find_links, editable_path - ) + editable_path = os.path.join(data.src, "requires_capitalized") + script.pip("install", "--no-index", "-f", data.find_links, editable_path) - result = script.pip('show', 'simple') + result = script.pip("show", "simple") lines = result.stdout.splitlines() - assert 'Name: simple' in lines - assert 'Required-by: Requires-Capitalized' in lines + assert "Name: simple" in lines + assert "Required-by: Requires-Capitalized" in lines def test_show_required_by_packages_requiring_capitalized(script, data): @@ -245,21 +246,17 @@ def test_show_required_by_packages_requiring_capitalized(script, data): where the package has a name with a mix of lower and upper case letters """ - required_package_path = os.path.join(data.src, 'requires_capitalized') - script.pip( - 'install', '--no-index', '-f', data.find_links, required_package_path - ) - editable_path = os.path.join(data.src, 'requires_requires_capitalized') - script.pip( - 'install', '--no-index', '-f', data.find_links, editable_path - ) + required_package_path = os.path.join(data.src, "requires_capitalized") + script.pip("install", "--no-index", "-f", data.find_links, required_package_path) + editable_path = os.path.join(data.src, "requires_requires_capitalized") + script.pip("install", "--no-index", "-f", data.find_links, editable_path) - result = script.pip('show', 'Requires_Capitalized') + result = script.pip("show", "Requires_Capitalized") lines = result.stdout.splitlines() print(lines) - assert 'Name: Requires-Capitalized' in lines - assert 'Required-by: requires-requires-capitalized' in lines + assert "Name: Requires-Capitalized" in lines + assert "Required-by: requires-requires-capitalized" in lines def test_show_skip_work_dir_pkg(script): @@ -269,14 +266,12 @@ def test_show_skip_work_dir_pkg(script): """ # Create a test package and create .egg-info dir - pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0') - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + pkg_path = create_test_package_with_setup(script, name="simple", version="1.0") + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) # Show should not include package simple when run from package directory - result = script.pip('show', 'simple', expect_error=True, cwd=pkg_path) - assert 'WARNING: Package(s) not found: simple' in result.stderr + result = script.pip("show", "simple", expect_error=True, cwd=pkg_path) + assert "WARNING: Package(s) not found: simple" in result.stderr def test_show_include_work_dir_pkg(script): @@ -286,15 +281,13 @@ def test_show_include_work_dir_pkg(script): """ # Create a test package and create .egg-info dir - pkg_path = create_test_package_with_setup( - script, name='simple', version='1.0') - script.run('python', 'setup.py', 'egg_info', - expect_stderr=True, cwd=pkg_path) + pkg_path = create_test_package_with_setup(script, name="simple", version="1.0") + script.run("python", "setup.py", "egg_info", expect_stderr=True, cwd=pkg_path) - script.environ.update({'PYTHONPATH': pkg_path}) + script.environ.update({"PYTHONPATH": pkg_path}) # Show should include package simple when run from package directory, # when package directory is in PYTHONPATH - result = script.pip('show', 'simple', cwd=pkg_path) + result = script.pip("show", "simple", cwd=pkg_path) lines = result.stdout.splitlines() - assert 'Name: simple' in lines + assert "Name: simple" in lines diff --git a/tests/functional/test_uninstall.py b/tests/functional/test_uninstall.py index 5def6587174..d06b5c9b410 100644 --- a/tests/functional/test_uninstall.py +++ b/tests/functional/test_uninstall.py @@ -13,11 +13,7 @@ from pip._internal.req.constructors import install_req_from_line from pip._internal.utils.misc import rmtree -from tests.lib import ( - assert_all_changes, - create_test_package_with_setup, - need_svn, -) +from tests.lib import assert_all_changes, create_test_package_with_setup, need_svn from tests.lib.local_repos import local_checkout, local_repo @@ -27,13 +23,13 @@ def test_basic_uninstall(script): Test basic install and uninstall. """ - result = script.pip('install', 'INITools==0.2') - result.did_create(join(script.site_packages, 'initools')) + result = script.pip("install", "INITools==0.2") + result.did_create(join(script.site_packages, "initools")) # the import forces the generation of __pycache__ if the version of python # supports it - script.run('python', '-c', "import initools") - result2 = script.pip('uninstall', 'INITools', '-y') - assert_all_changes(result, result2, [script.venv / 'build', 'cache']) + script.run("python", "-c", "import initools") + result2 = script.pip("uninstall", "INITools", "-y") + assert_all_changes(result, result2, [script.venv / "build", "cache"]) def test_basic_uninstall_distutils(script): @@ -42,20 +38,24 @@ def test_basic_uninstall_distutils(script): """ script.scratch_path.joinpath("distutils_install").mkdir() - pkg_path = script.scratch_path / 'distutils_install' - pkg_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkg_path = script.scratch_path / "distutils_install" + pkg_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from distutils.core import setup setup( name='distutils-install', version='0.1', ) - """)) - result = script.run('python', pkg_path / 'setup.py', 'install') - result = script.pip('list', '--format=json') - assert {"name": "distutils-install", "version": "0.1"} \ - in json.loads(result.stdout) - result = script.pip('uninstall', 'distutils_install', '-y', - expect_stderr=True, expect_error=True) + """ + ) + ) + result = script.run("python", pkg_path / "setup.py", "install") + result = script.pip("list", "--format=json") + assert {"name": "distutils-install", "version": "0.1"} in json.loads(result.stdout) + result = script.pip( + "uninstall", "distutils_install", "-y", expect_stderr=True, expect_error=True + ) assert ( "Cannot uninstall 'distutils-install'. It is a distutils installed " "project and thus we cannot accurately determine which files belong " @@ -69,15 +69,15 @@ def test_basic_uninstall_with_scripts(script): Uninstall an easy_installed package with scripts. """ - result = script.easy_install('PyLogo', expect_stderr=True) - easy_install_pth = script.site_packages / 'easy-install.pth' - pylogo = sys.platform == 'win32' and 'pylogo' or 'PyLogo' - assert(pylogo in result.files_updated[easy_install_pth].bytes) - result2 = script.pip('uninstall', 'pylogo', '-y') + result = script.easy_install("PyLogo", expect_stderr=True) + easy_install_pth = script.site_packages / "easy-install.pth" + pylogo = sys.platform == "win32" and "pylogo" or "PyLogo" + assert pylogo in result.files_updated[easy_install_pth].bytes + result2 = script.pip("uninstall", "pylogo", "-y") assert_all_changes( result, result2, - [script.venv / 'build', 'cache', easy_install_pth], + [script.venv / "build", "cache", easy_install_pth], ) @@ -87,19 +87,19 @@ def test_uninstall_easy_install_after_import(script): Uninstall an easy_installed package after it's been imported """ - result = script.easy_install('INITools==0.2', expect_stderr=True) + result = script.easy_install("INITools==0.2", expect_stderr=True) # the import forces the generation of __pycache__ if the version of python # supports it - script.run('python', '-c', "import initools") - result2 = script.pip('uninstall', 'INITools', '-y') + script.run("python", "-c", "import initools") + result2 = script.pip("uninstall", "INITools", "-y") assert_all_changes( result, result2, [ - script.venv / 'build', - 'cache', - script.site_packages / 'easy-install.pth', - ] + script.venv / "build", + "cache", + script.site_packages / "easy-install.pth", + ], ) @@ -110,26 +110,25 @@ def test_uninstall_trailing_newline(script): lacks a trailing newline """ - script.easy_install('INITools==0.2', expect_stderr=True) - script.easy_install('PyLogo', expect_stderr=True) - easy_install_pth = script.site_packages_path / 'easy-install.pth' + script.easy_install("INITools==0.2", expect_stderr=True) + script.easy_install("PyLogo", expect_stderr=True) + easy_install_pth = script.site_packages_path / "easy-install.pth" # trim trailing newline from easy-install.pth with open(easy_install_pth) as f: pth_before = f.read() - with open(easy_install_pth, 'w') as f: + with open(easy_install_pth, "w") as f: f.write(pth_before.rstrip()) # uninstall initools - script.pip('uninstall', 'INITools', '-y') + script.pip("uninstall", "INITools", "-y") with open(easy_install_pth) as f: pth_after = f.read() # verify that only initools is removed before_without_initools = [ - line for line in pth_before.splitlines() - if 'initools' not in line.lower() + line for line in pth_before.splitlines() if "initools" not in line.lower() ] lines_after = pth_after.splitlines() @@ -143,14 +142,14 @@ def test_basic_uninstall_namespace_package(script): the namespace and everything in it. """ - result = script.pip('install', 'pd.requires==0.0.3') - result.did_create(join(script.site_packages, 'pd')) - result2 = script.pip('uninstall', 'pd.find', '-y') - assert join(script.site_packages, 'pd') not in result2.files_deleted, ( - sorted(result2.files_deleted.keys()) + result = script.pip("install", "pd.requires==0.0.3") + result.did_create(join(script.site_packages, "pd")) + result2 = script.pip("uninstall", "pd.find", "-y") + assert join(script.site_packages, "pd") not in result2.files_deleted, sorted( + result2.files_deleted.keys() ) - assert join(script.site_packages, 'pd', 'find') in result2.files_deleted, ( - sorted(result2.files_deleted.keys()) + assert join(script.site_packages, "pd", "find") in result2.files_deleted, sorted( + result2.files_deleted.keys() ) @@ -165,65 +164,66 @@ def test_uninstall_overlapping_package(script, data): parent_pkg = data.packages.joinpath("parent-0.1.tar.gz") child_pkg = data.packages.joinpath("child-0.1.tar.gz") - result1 = script.pip('install', parent_pkg) - result1.did_create(join(script.site_packages, 'parent')) - result2 = script.pip('install', child_pkg) - result2.did_create(join(script.site_packages, 'child')) - result2.did_create(normpath( - join(script.site_packages, 'parent/plugins/child_plugin.py') - )) + result1 = script.pip("install", parent_pkg) + result1.did_create(join(script.site_packages, "parent")) + result2 = script.pip("install", child_pkg) + result2.did_create(join(script.site_packages, "child")) + result2.did_create( + normpath(join(script.site_packages, "parent/plugins/child_plugin.py")) + ) # The import forces the generation of __pycache__ if the version of python # supports it - script.run('python', '-c', "import parent.plugins.child_plugin, child") - result3 = script.pip('uninstall', '-y', 'child') - assert join(script.site_packages, 'child') in result3.files_deleted, ( - sorted(result3.files_created.keys()) + script.run("python", "-c", "import parent.plugins.child_plugin, child") + result3 = script.pip("uninstall", "-y", "child") + assert join(script.site_packages, "child") in result3.files_deleted, sorted( + result3.files_created.keys() ) - assert normpath( - join(script.site_packages, 'parent/plugins/child_plugin.py') - ) in result3.files_deleted, sorted(result3.files_deleted.keys()) - assert join(script.site_packages, 'parent') not in result3.files_deleted, ( - sorted(result3.files_deleted.keys()) + assert ( + normpath(join(script.site_packages, "parent/plugins/child_plugin.py")) + in result3.files_deleted + ), sorted(result3.files_deleted.keys()) + assert join(script.site_packages, "parent") not in result3.files_deleted, sorted( + result3.files_deleted.keys() ) # Additional check: uninstalling 'child' should return things to the # previous state, without unintended side effects. assert_all_changes(result2, result3, []) -@pytest.mark.parametrize("console_scripts", - ["test_ = distutils_install", - "test_:test_ = distutils_install"]) +@pytest.mark.parametrize( + "console_scripts", ["test_ = distutils_install", "test_:test_ = distutils_install"] +) def test_uninstall_entry_point_colon_in_name(script, console_scripts): """ Test uninstall package with two or more entry points in the same section, whose name contain a colon. """ - pkg_name = 'ep_install' + pkg_name = "ep_install" pkg_path = create_test_package_with_setup( script, name=pkg_name, - version='0.1', - entry_points={"console_scripts": [console_scripts, ], - "pip_test.ep": - ["ep:name1 = distutils_install", - "ep:name2 = distutils_install"] - } - ) - script_name = script.bin_path.joinpath( - console_scripts.split('=')[0].strip() + version="0.1", + entry_points={ + "console_scripts": [ + console_scripts, + ], + "pip_test.ep": [ + "ep:name1 = distutils_install", + "ep:name2 = distutils_install", + ], + }, ) - if sys.platform == 'win32': - script_name += '.exe' - result = script.pip('install', pkg_path) + script_name = script.bin_path.joinpath(console_scripts.split("=")[0].strip()) + if sys.platform == "win32": + script_name += ".exe" + result = script.pip("install", pkg_path) assert script_name.exists() - result = script.pip('list', '--format=json') - assert {"name": "ep-install", "version": "0.1"} \ - in json.loads(result.stdout) - script.pip('uninstall', 'ep_install', '-y') + result = script.pip("list", "--format=json") + assert {"name": "ep-install", "version": "0.1"} in json.loads(result.stdout) + script.pip("uninstall", "ep_install", "-y") assert not script_name.exists() - result2 = script.pip('list', '--format=json') - assert {"name": "ep-install", "version": "0.1"} \ - not in json.loads(result2.stdout) + result2 = script.pip("list", "--format=json") + assert {"name": "ep-install", "version": "0.1"} not in json.loads(result2.stdout) def test_uninstall_gui_scripts(script): @@ -234,15 +234,19 @@ def test_uninstall_gui_scripts(script): pkg_path = create_test_package_with_setup( script, name=pkg_name, - version='0.1', - entry_points={"gui_scripts": ["test_ = distutils_install", ], } + version="0.1", + entry_points={ + "gui_scripts": [ + "test_ = distutils_install", + ], + }, ) - script_name = script.bin_path.joinpath('test_') - if sys.platform == 'win32': - script_name += '.exe' - script.pip('install', pkg_path) + script_name = script.bin_path.joinpath("test_") + if sys.platform == "win32": + script_name += ".exe" + script.pip("install", pkg_path) assert script_name.exists() - script.pip('uninstall', pkg_name, '-y') + script.pip("uninstall", pkg_name, "-y") assert not script_name.exists() @@ -253,14 +257,14 @@ def test_uninstall_console_scripts(script): """ pkg_path = create_test_package_with_setup( script, - name='discover', - version='0.1', - entry_points={'console_scripts': ['discover = discover:main']}, + name="discover", + version="0.1", + entry_points={"console_scripts": ["discover = discover:main"]}, ) - result = script.pip('install', pkg_path) - result.did_create(script.bin / 'discover' + script.exe) - result2 = script.pip('uninstall', 'discover', '-y') - assert_all_changes(result, result2, [script.venv / 'build', 'cache']) + result = script.pip("install", pkg_path) + result.did_create(script.bin / "discover" + script.exe) + result2 = script.pip("uninstall", "discover", "-y") + assert_all_changes(result, result2, [script.venv / "build", "cache"]) def test_uninstall_console_scripts_uppercase_name(script): @@ -269,20 +273,20 @@ def test_uninstall_console_scripts_uppercase_name(script): """ pkg_path = create_test_package_with_setup( script, - name='ep_install', - version='0.1', + name="ep_install", + version="0.1", entry_points={ "console_scripts": [ "Test = distutils_install", ], }, ) - script_name = script.bin_path.joinpath('Test' + script.exe) + script_name = script.bin_path.joinpath("Test" + script.exe) - script.pip('install', pkg_path) + script.pip("install", pkg_path) assert script_name.exists() - script.pip('uninstall', 'ep_install', '-y') + script.pip("uninstall", "ep_install", "-y") assert not script_name.exists() @@ -293,17 +297,17 @@ def test_uninstall_easy_installed_console_scripts(script): """ # setuptools >= 42.0.0 deprecates easy_install and prints a warning when # used - result = script.easy_install('discover', allow_stderr_warning=True) - result.did_create(script.bin / 'discover' + script.exe) - result2 = script.pip('uninstall', 'discover', '-y') + result = script.easy_install("discover", allow_stderr_warning=True) + result.did_create(script.bin / "discover" + script.exe) + result2 = script.pip("uninstall", "discover", "-y") assert_all_changes( result, result2, [ - script.venv / 'build', - 'cache', - script.site_packages / 'easy-install.pth', - ] + script.venv / "build", + "cache", + script.site_packages / "easy-install.pth", + ], ) @@ -315,22 +319,22 @@ def test_uninstall_editable_from_svn(script, tmpdir): Test uninstalling an editable installation from svn. """ result = script.pip( - 'install', '-e', - '{checkout}#egg=initools'.format( - checkout=local_checkout( - 'svn+http://svn.colorstudy.com/INITools', tmpdir) + "install", + "-e", + "{checkout}#egg=initools".format( + checkout=local_checkout("svn+http://svn.colorstudy.com/INITools", tmpdir) ), ) - result.assert_installed('INITools') - result2 = script.pip('uninstall', '-y', 'initools') - assert (script.venv / 'src' / 'initools' in result2.files_after) + result.assert_installed("INITools") + result2 = script.pip("uninstall", "-y", "initools") + assert script.venv / "src" / "initools" in result2.files_after assert_all_changes( result, result2, [ - script.venv / 'src', - script.venv / 'build', - script.site_packages / 'easy-install.pth' + script.venv / "src", + script.venv / "build", + script.site_packages / "easy-install.pth", ], ) @@ -342,7 +346,7 @@ def test_uninstall_editable_with_source_outside_venv(script, tmpdir): """ try: temp = mkdtemp() - temp_pkg_dir = join(temp, 'pip-test-package') + temp_pkg_dir = join(temp, "pip-test-package") _test_uninstall_editable_with_source_outside_venv( script, tmpdir, @@ -353,23 +357,24 @@ def test_uninstall_editable_with_source_outside_venv(script, tmpdir): def _test_uninstall_editable_with_source_outside_venv( - script, tmpdir, temp_pkg_dir, + script, + tmpdir, + temp_pkg_dir, ): result = script.run( - 'git', 'clone', - local_repo('git+git://github.com/pypa/pip-test-package', tmpdir), + "git", + "clone", + local_repo("git+git://github.com/pypa/pip-test-package", tmpdir), temp_pkg_dir, expect_stderr=True, ) - result2 = script.pip('install', '-e', temp_pkg_dir) - result2.did_create(join( - script.site_packages, 'pip-test-package.egg-link' - )) - result3 = script.pip('uninstall', '-y', 'pip-test-package') + result2 = script.pip("install", "-e", temp_pkg_dir) + result2.did_create(join(script.site_packages, "pip-test-package.egg-link")) + result3 = script.pip("uninstall", "-y", "pip-test-package") assert_all_changes( result, result3, - [script.venv / 'build', script.site_packages / 'easy-install.pth'], + [script.venv / "build", script.site_packages / "easy-install.pth"], ) @@ -382,18 +387,22 @@ def test_uninstall_from_reqs_file(script, tmpdir): """ local_svn_url = local_checkout( - 'svn+http://svn.colorstudy.com/INITools', tmpdir, + "svn+http://svn.colorstudy.com/INITools", + tmpdir, ) script.scratch_path.joinpath("test-req.txt").write_text( - textwrap.dedent(""" + textwrap.dedent( + """ -e {url}#egg=initools # and something else to test out: PyLogo<0.4 - """).format(url=local_svn_url) + """ + ).format(url=local_svn_url) ) - result = script.pip('install', '-r', 'test-req.txt') + result = script.pip("install", "-r", "test-req.txt") script.scratch_path.joinpath("test-req.txt").write_text( - textwrap.dedent(""" + textwrap.dedent( + """ # -f, -i, and --extra-index-url should all be ignored by uninstall -f http://www.example.com -i http://www.example.com @@ -402,17 +411,18 @@ def test_uninstall_from_reqs_file(script, tmpdir): -e {url}#egg=initools # and something else to test out: PyLogo<0.4 - """).format(url=local_svn_url) + """ + ).format(url=local_svn_url) ) - result2 = script.pip('uninstall', '-r', 'test-req.txt', '-y') + result2 = script.pip("uninstall", "-r", "test-req.txt", "-y") assert_all_changes( result, result2, [ - script.venv / 'build', - script.venv / 'src', - script.scratch / 'test-req.txt', - script.site_packages / 'easy-install.pth', + script.venv / "build", + script.venv / "src", + script.scratch / "test-req.txt", + script.site_packages / "easy-install.pth", ], ) @@ -428,14 +438,11 @@ def test_uninstallpathset_no_paths(caplog): caplog.set_level(logging.INFO) - test_dist = get_distribution('pip') + test_dist = get_distribution("pip") uninstall_set = UninstallPathSet(test_dist) uninstall_set.remove() # with no files added to set - assert ( - "Can't uninstall 'pip'. No files were found to uninstall." - in caplog.text - ) + assert "Can't uninstall 'pip'. No files were found to uninstall." in caplog.text def test_uninstall_non_local_distutils(caplog, monkeypatch, tmpdir): @@ -464,10 +471,10 @@ def test_uninstall_wheel(script, data): Test uninstalling a wheel """ package = data.packages.joinpath("simple.dist-0.1-py2.py3-none-any.whl") - result = script.pip('install', package, '--no-index') - dist_info_folder = script.site_packages / 'simple.dist-0.1.dist-info' + result = script.pip("install", package, "--no-index") + dist_info_folder = script.site_packages / "simple.dist-0.1.dist-info" result.did_create(dist_info_folder) - result2 = script.pip('uninstall', 'simple.dist', '-y') + result2 = script.pip("uninstall", "simple.dist", "-y") assert_all_changes(result, result2, []) @@ -478,17 +485,17 @@ def test_uninstall_with_symlink(script, data, tmpdir): https://github.com/pypa/pip/issues/6892 """ package = data.packages.joinpath("simple.dist-0.1-py2.py3-none-any.whl") - script.pip('install', package, '--no-index') + script.pip("install", package, "--no-index") symlink_target = tmpdir / "target" symlink_target.mkdir() symlink_source = script.site_packages / "symlink" (script.base_path / symlink_source).symlink_to(symlink_target) st_mode = symlink_target.stat().st_mode - distinfo_path = script.site_packages_path / 'simple.dist-0.1.dist-info' - record_path = distinfo_path / 'RECORD' + distinfo_path = script.site_packages_path / "simple.dist-0.1.dist-info" + record_path = distinfo_path / "RECORD" with open(record_path, "a") as f: f.write("symlink,,\n") - uninstall_result = script.pip('uninstall', 'simple.dist', '-y') + uninstall_result = script.pip("uninstall", "simple.dist", "-y") assert symlink_source in uninstall_result.files_deleted assert symlink_target.stat().st_mode == st_mode @@ -496,22 +503,20 @@ def test_uninstall_with_symlink(script, data, tmpdir): def test_uninstall_setuptools_develop_install(script, data): """Try uninstall after setup.py develop followed of setup.py install""" pkg_path = data.packages.joinpath("FSPkg") - script.run('python', 'setup.py', 'develop', - expect_stderr=True, cwd=pkg_path) - script.run('python', 'setup.py', 'install', - expect_stderr=True, cwd=pkg_path) - list_result = script.pip('list', '--format=json') - assert {"name": os.path.normcase("FSPkg"), "version": "0.1.dev0"} \ - in json.loads(list_result.stdout), str(list_result) + script.run("python", "setup.py", "develop", expect_stderr=True, cwd=pkg_path) + script.run("python", "setup.py", "install", expect_stderr=True, cwd=pkg_path) + list_result = script.pip("list", "--format=json") + assert {"name": os.path.normcase("FSPkg"), "version": "0.1.dev0"} in json.loads( + list_result.stdout + ), str(list_result) # Uninstall both develop and install - uninstall = script.pip('uninstall', 'FSPkg', '-y') - assert any(filename.endswith('.egg') - for filename in uninstall.files_deleted.keys()) - uninstall2 = script.pip('uninstall', 'FSPkg', '-y') - assert join( - script.site_packages, 'FSPkg.egg-link' - ) in uninstall2.files_deleted, list(uninstall2.files_deleted.keys()) - list_result2 = script.pip('list', '--format=json') + uninstall = script.pip("uninstall", "FSPkg", "-y") + assert any(filename.endswith(".egg") for filename in uninstall.files_deleted.keys()) + uninstall2 = script.pip("uninstall", "FSPkg", "-y") + assert ( + join(script.site_packages, "FSPkg.egg-link") in uninstall2.files_deleted + ), list(uninstall2.files_deleted.keys()) + list_result2 = script.pip("list", "--format=json") assert "FSPkg" not in {p["name"] for p in json.loads(list_result2.stdout)} @@ -520,26 +525,24 @@ def test_uninstall_editable_and_pip_install(script, data): # SETUPTOOLS_SYS_PATH_TECHNIQUE=raw removes the assumption that `-e` # installs are always higher priority than regular installs. # This becomes the default behavior in setuptools 25. - script.environ['SETUPTOOLS_SYS_PATH_TECHNIQUE'] = 'raw' + script.environ["SETUPTOOLS_SYS_PATH_TECHNIQUE"] = "raw" pkg_path = data.packages.joinpath("FSPkg") - script.pip('install', '-e', '.', - expect_stderr=True, cwd=pkg_path) + script.pip("install", "-e", ".", expect_stderr=True, cwd=pkg_path) # ensure both are installed with --ignore-installed: - script.pip('install', '--ignore-installed', '.', - expect_stderr=True, cwd=pkg_path) - list_result = script.pip('list', '--format=json') - assert {"name": "FSPkg", "version": "0.1.dev0"} \ - in json.loads(list_result.stdout) + script.pip("install", "--ignore-installed", ".", expect_stderr=True, cwd=pkg_path) + list_result = script.pip("list", "--format=json") + assert {"name": "FSPkg", "version": "0.1.dev0"} in json.loads(list_result.stdout) # Uninstall both develop and install - uninstall = script.pip('uninstall', 'FSPkg', '-y') - assert not any(filename.endswith('.egg-link') - for filename in uninstall.files_deleted.keys()) - uninstall2 = script.pip('uninstall', 'FSPkg', '-y') - assert join( - script.site_packages, 'FSPkg.egg-link' - ) in uninstall2.files_deleted, list(uninstall2.files_deleted.keys()) - list_result2 = script.pip('list', '--format=json') + uninstall = script.pip("uninstall", "FSPkg", "-y") + assert not any( + filename.endswith(".egg-link") for filename in uninstall.files_deleted.keys() + ) + uninstall2 = script.pip("uninstall", "FSPkg", "-y") + assert ( + join(script.site_packages, "FSPkg.egg-link") in uninstall2.files_deleted + ), list(uninstall2.files_deleted.keys()) + list_result2 = script.pip("list", "--format=json") assert "FSPkg" not in {p["name"] for p in json.loads(list_result2.stdout)} @@ -549,52 +552,53 @@ def test_uninstall_editable_and_pip_install_easy_install_remove(script, data): # SETUPTOOLS_SYS_PATH_TECHNIQUE=raw removes the assumption that `-e` # installs are always higher priority than regular installs. # This becomes the default behavior in setuptools 25. - script.environ['SETUPTOOLS_SYS_PATH_TECHNIQUE'] = 'raw' + script.environ["SETUPTOOLS_SYS_PATH_TECHNIQUE"] = "raw" # Rename easy-install.pth to pip-test.pth - easy_install_pth = join(script.site_packages_path, 'easy-install.pth') - pip_test_pth = join(script.site_packages_path, 'pip-test.pth') + easy_install_pth = join(script.site_packages_path, "easy-install.pth") + pip_test_pth = join(script.site_packages_path, "pip-test.pth") os.rename(easy_install_pth, pip_test_pth) # Install FSPkg pkg_path = data.packages.joinpath("FSPkg") - script.pip('install', '-e', '.', - expect_stderr=True, cwd=pkg_path) + script.pip("install", "-e", ".", expect_stderr=True, cwd=pkg_path) # Rename easy-install.pth to pip-test-fspkg.pth - pip_test_fspkg_pth = join(script.site_packages_path, 'pip-test-fspkg.pth') + pip_test_fspkg_pth = join(script.site_packages_path, "pip-test-fspkg.pth") os.rename(easy_install_pth, pip_test_fspkg_pth) # Confirm that FSPkg is installed - list_result = script.pip('list', '--format=json') - assert {"name": "FSPkg", "version": "0.1.dev0"} \ - in json.loads(list_result.stdout) + list_result = script.pip("list", "--format=json") + assert {"name": "FSPkg", "version": "0.1.dev0"} in json.loads(list_result.stdout) # Remove pip-test-fspkg.pth os.remove(pip_test_fspkg_pth) # Uninstall will fail with given warning - uninstall = script.pip('uninstall', 'FSPkg', '-y') + uninstall = script.pip("uninstall", "FSPkg", "-y") assert "Cannot remove entries from nonexistent file" in uninstall.stderr - assert join( - script.site_packages, 'FSPkg.egg-link' - ) in uninstall.files_deleted, list(uninstall.files_deleted.keys()) + assert ( + join(script.site_packages, "FSPkg.egg-link") in uninstall.files_deleted + ), list(uninstall.files_deleted.keys()) # Confirm that FSPkg is uninstalled - list_result = script.pip('list', '--format=json') - assert {"name": "FSPkg", "version": "0.1.dev0"} \ - not in json.loads(list_result.stdout) + list_result = script.pip("list", "--format=json") + assert {"name": "FSPkg", "version": "0.1.dev0"} not in json.loads( + list_result.stdout + ) # Rename pip-test.pth back to easy-install.pth os.rename(pip_test_pth, easy_install_pth) def test_uninstall_ignores_missing_packages(script, data): - """Uninstall of a non existent package prints a warning and exits cleanly - """ + """Uninstall of a non existent package prints a warning and exits cleanly""" result = script.pip( - 'uninstall', '-y', 'non-existent-pkg', expect_stderr=True, + "uninstall", + "-y", + "non-existent-pkg", + expect_stderr=True, ) assert "Skipping non-existent-pkg as it is not installed." in result.stderr @@ -602,9 +606,13 @@ def test_uninstall_ignores_missing_packages(script, data): def test_uninstall_ignores_missing_packages_and_uninstalls_rest(script, data): - script.pip_install_local('simple') + script.pip_install_local("simple") result = script.pip( - 'uninstall', '-y', 'non-existent-pkg', 'simple', expect_stderr=True, + "uninstall", + "-y", + "non-existent-pkg", + "simple", + expect_stderr=True, ) assert "Skipping non-existent-pkg as it is not installed." in result.stderr diff --git a/tests/functional/test_uninstall_user.py b/tests/functional/test_uninstall_user.py index 2dbf032ac38..edaa550df44 100644 --- a/tests/functional/test_uninstall_user.py +++ b/tests/functional/test_uninstall_user.py @@ -12,41 +12,41 @@ @pytest.mark.incompatible_with_test_venv class Tests_UninstallUserSite: - @pytest.mark.network def test_uninstall_from_usersite(self, script): """ Test uninstall from usersite """ - result1 = script.pip('install', '--user', 'INITools==0.3') - result2 = script.pip('uninstall', '-y', 'INITools') - assert_all_changes(result1, result2, [script.venv / 'build', 'cache']) + result1 = script.pip("install", "--user", "INITools==0.3") + result2 = script.pip("uninstall", "-y", "INITools") + assert_all_changes(result1, result2, [script.venv / "build", "cache"]) - def test_uninstall_from_usersite_with_dist_in_global_site( - self, virtualenv, script): + def test_uninstall_from_usersite_with_dist_in_global_site(self, virtualenv, script): """ Test uninstall from usersite (with same dist in global site) """ _patch_dist_in_site_packages(virtualenv) - script.pip_install_local('pip-test-package==0.1', '--no-binary=:all:') + script.pip_install_local("pip-test-package==0.1", "--no-binary=:all:") result2 = script.pip_install_local( - '--user', 'pip-test-package==0.1.1', '--no-binary=:all:') - result3 = script.pip('uninstall', '-vy', 'pip-test-package') + "--user", "pip-test-package==0.1.1", "--no-binary=:all:" + ) + result3 = script.pip("uninstall", "-vy", "pip-test-package") # uninstall console is mentioning user scripts, but not global scripts assert normcase(script.user_bin_path) in result3.stdout, str(result3) assert normcase(script.bin_path) not in result3.stdout, str(result3) # uninstall worked - assert_all_changes(result2, result3, [script.venv / 'build', 'cache']) + assert_all_changes(result2, result3, [script.venv / "build", "cache"]) # site still has 0.2 (can't look in result1; have to check) # keep checking for egg-info because no-binary implies setup.py install egg_info_folder = ( - script.base_path / script.site_packages / - 'pip_test_package-0.1-py{pyversion}.egg-info'.format(**globals()) + script.base_path + / script.site_packages + / "pip_test_package-0.1-py{pyversion}.egg-info".format(**globals()) ) assert isdir(egg_info_folder) @@ -58,22 +58,20 @@ def test_uninstall_editable_from_usersite(self, script, data): # install to_install = data.packages.joinpath("FSPkg") - result1 = script.pip( - 'install', '--user', '-e', to_install - ) - egg_link = script.user_site / 'FSPkg.egg-link' + result1 = script.pip("install", "--user", "-e", to_install) + egg_link = script.user_site / "FSPkg.egg-link" result1.did_create(egg_link) # uninstall - result2 = script.pip('uninstall', '-y', 'FSPkg') + result2 = script.pip("uninstall", "-y", "FSPkg") assert not isfile(script.base_path / egg_link) assert_all_changes( result1, result2, [ - script.venv / 'build', - 'cache', - script.user_site / 'easy-install.pth', - ] + script.venv / "build", + "cache", + script.user_site / "easy-install.pth", + ], ) diff --git a/tests/functional/test_vcs_bazaar.py b/tests/functional/test_vcs_bazaar.py index d928da8b364..7228b94e4d2 100644 --- a/tests/functional/test_vcs_bazaar.py +++ b/tests/functional/test_vcs_bazaar.py @@ -18,8 +18,8 @@ @pytest.mark.skipif( - 'TRAVIS' not in os.environ, - reason='Bazaar is only required under Travis') + "TRAVIS" not in os.environ, reason="Bazaar is only required under Travis" +) def test_ensure_bzr_available(): """Make sure that bzr is available when running in Travis.""" assert is_bzr_installed() @@ -28,40 +28,45 @@ def test_ensure_bzr_available(): @need_bzr def test_export(script, tmpdir): """Test that a Bazaar branch can be exported.""" - source_dir = tmpdir / 'test-source' + source_dir = tmpdir / "test-source" source_dir.mkdir() - create_file(source_dir / 'test_file', 'something') + create_file(source_dir / "test_file", "something") - _vcs_add(script, str(source_dir), vcs='bazaar') + _vcs_add(script, str(source_dir), vcs="bazaar") - export_dir = str(tmpdir / 'export') - url = hide_url('bzr+' + _test_path_to_file_url(source_dir)) + export_dir = str(tmpdir / "export") + url = hide_url("bzr+" + _test_path_to_file_url(source_dir)) Bazaar().export(export_dir, url=url) - assert os.listdir(export_dir) == ['test_file'] + assert os.listdir(export_dir) == ["test_file"] @need_bzr def test_export_rev(script, tmpdir): """Test that a Bazaar branch can be exported, specifying a rev.""" - source_dir = tmpdir / 'test-source' + source_dir = tmpdir / "test-source" source_dir.mkdir() # Create a single file that is changed by two revisions. - create_file(source_dir / 'test_file', 'something initial') - _vcs_add(script, str(source_dir), vcs='bazaar') + create_file(source_dir / "test_file", "something initial") + _vcs_add(script, str(source_dir), vcs="bazaar") - create_file(source_dir / 'test_file', 'something new') + create_file(source_dir / "test_file", "something new") script.run( - 'bzr', 'commit', '-q', - '--author', 'pip ', - '-m', 'change test file', cwd=source_dir, + "bzr", + "commit", + "-q", + "--author", + "pip ", + "-m", + "change test file", + cwd=source_dir, ) - export_dir = tmpdir / 'export' - url = hide_url('bzr+' + _test_path_to_file_url(source_dir) + '@1') + export_dir = tmpdir / "export" + url = hide_url("bzr+" + _test_path_to_file_url(source_dir) + "@1") Bazaar().export(str(export_dir), url=url) - with open(export_dir / 'test_file', 'r') as f: - assert f.read() == 'something initial' + with open(export_dir / "test_file", "r") as f: + assert f.read() == "something initial" diff --git a/tests/functional/test_vcs_git.py b/tests/functional/test_vcs_git.py index 8b07ae6673b..0d13061d23b 100644 --- a/tests/functional/test_vcs_git.py +++ b/tests/functional/test_vcs_git.py @@ -17,24 +17,28 @@ def test_get_backend_for_scheme(): def get_head_sha(script, dest): """Return the HEAD sha.""" - result = script.run('git', 'rev-parse', 'HEAD', cwd=dest) + result = script.run("git", "rev-parse", "HEAD", cwd=dest) sha = result.stdout.strip() return sha def checkout_ref(script, repo_dir, ref): - script.run('git', 'checkout', ref, cwd=repo_dir) + script.run("git", "checkout", ref, cwd=repo_dir) def checkout_new_branch(script, repo_dir, branch): script.run( - 'git', 'checkout', '-b', branch, cwd=repo_dir, + "git", + "checkout", + "-b", + branch, + cwd=repo_dir, ) def do_commit(script, dest): - _git_commit(script, dest, message='test commit', allow_empty=True) + _git_commit(script, dest, message="test commit", allow_empty=True) return get_head_sha(script, dest) @@ -56,43 +60,43 @@ def test_git_dir_ignored(tmpdir): """ Test that a GIT_DIR environment variable is ignored. """ - repo_path = tmpdir / 'test-repo' + repo_path = tmpdir / "test-repo" repo_path.mkdir() repo_dir = str(repo_path) - env = {'GIT_DIR': 'foo'} + env = {"GIT_DIR": "foo"} # If GIT_DIR is not ignored, then os.listdir() will return ['foo']. - Git.run_command(['init', repo_dir], cwd=repo_dir, extra_environ=env) - assert os.listdir(repo_dir) == ['.git'] + Git.run_command(["init", repo_dir], cwd=repo_dir, extra_environ=env) + assert os.listdir(repo_dir) == [".git"] def test_git_work_tree_ignored(tmpdir): """ Test that a GIT_WORK_TREE environment variable is ignored. """ - repo_path = tmpdir / 'test-repo' + repo_path = tmpdir / "test-repo" repo_path.mkdir() repo_dir = str(repo_path) - Git.run_command(['init', repo_dir], cwd=repo_dir) + Git.run_command(["init", repo_dir], cwd=repo_dir) # Choose a directory relative to the cwd that does not exist. # If GIT_WORK_TREE is not ignored, then the command will error out # with: "fatal: This operation must be run in a work tree". - env = {'GIT_WORK_TREE': 'foo'} - Git.run_command(['status', repo_dir], extra_environ=env, cwd=repo_dir) + env = {"GIT_WORK_TREE": "foo"} + Git.run_command(["status", repo_dir], extra_environ=env, cwd=repo_dir) def test_get_remote_url(script, tmpdir): - source_dir = tmpdir / 'source' + source_dir = tmpdir / "source" source_dir.mkdir() source_url = _test_path_to_file_url(source_dir) source_dir = str(source_dir) - script.run('git', 'init', cwd=source_dir) + script.run("git", "init", cwd=source_dir) do_commit(script, source_dir) - repo_dir = str(tmpdir / 'repo') - script.run('git', 'clone', source_url, repo_dir) + repo_dir = str(tmpdir / "repo") + script.run("git", "clone", source_url, repo_dir) remote_url = Git.get_remote_url(repo_dir) assert remote_url == source_url @@ -102,11 +106,11 @@ def test_get_remote_url__no_remote(script, tmpdir): """ Test a repo with no remote. """ - repo_dir = tmpdir / 'temp-repo' + repo_dir = tmpdir / "temp-repo" repo_dir.mkdir() repo_dir = str(repo_dir) - script.run('git', 'init', cwd=repo_dir) + script.run("git", "init", cwd=repo_dir) with pytest.raises(RemoteNotFoundError): Git.get_remote_url(repo_dir) @@ -115,15 +119,15 @@ def test_get_remote_url__no_remote(script, tmpdir): def test_get_current_branch(script): repo_dir = str(script.scratch_path) - script.run('git', 'init', cwd=repo_dir) + script.run("git", "init", cwd=repo_dir) sha = do_commit(script, repo_dir) - assert Git.get_current_branch(repo_dir) == 'master' + assert Git.get_current_branch(repo_dir) == "master" # Switch to a branch with the same SHA as "master" but whose name # is alphabetically after. - checkout_new_branch(script, repo_dir, 'release') - assert Git.get_current_branch(repo_dir) == 'release' + checkout_new_branch(script, repo_dir, "release") + assert Git.get_current_branch(repo_dir) == "release" # Also test the detached HEAD case. checkout_ref(script, repo_dir, sha) @@ -136,23 +140,23 @@ def test_get_current_branch__branch_and_tag_same_name(script, tmpdir): and tag have the same name. """ repo_dir = str(tmpdir) - script.run('git', 'init', cwd=repo_dir) + script.run("git", "init", cwd=repo_dir) do_commit(script, repo_dir) - checkout_new_branch(script, repo_dir, 'dev') + checkout_new_branch(script, repo_dir, "dev") # Create a tag with the same name as the branch. - script.run('git', 'tag', 'dev', cwd=repo_dir) + script.run("git", "tag", "dev", cwd=repo_dir) - assert Git.get_current_branch(repo_dir) == 'dev' + assert Git.get_current_branch(repo_dir) == "dev" # Now try with the tag checked out. - checkout_ref(script, repo_dir, 'refs/tags/dev') + checkout_ref(script, repo_dir, "refs/tags/dev") assert Git.get_current_branch(repo_dir) is None def test_get_revision_sha(script): repo_dir = str(script.scratch_path) - script.run('git', 'init', cwd=repo_dir) + script.run("git", "init", cwd=repo_dir) shas = add_commits(script, repo_dir, count=3) tag_sha = shas[0] @@ -160,45 +164,46 @@ def test_get_revision_sha(script): head_sha = shas[2] assert head_sha == shas[-1] - origin_ref = 'refs/remotes/origin/origin-branch' - generic_ref = 'refs/generic-ref' + origin_ref = "refs/remotes/origin/origin-branch" + generic_ref = "refs/generic-ref" + script.run("git", "branch", "local-branch", head_sha, cwd=repo_dir) + script.run("git", "tag", "v1.0", tag_sha, cwd=repo_dir) + script.run("git", "update-ref", origin_ref, origin_sha, cwd=repo_dir) script.run( - 'git', 'branch', 'local-branch', head_sha, cwd=repo_dir + "git", + "update-ref", + "refs/remotes/upstream/upstream-branch", + head_sha, + cwd=repo_dir, ) - script.run('git', 'tag', 'v1.0', tag_sha, cwd=repo_dir) - script.run('git', 'update-ref', origin_ref, origin_sha, cwd=repo_dir) - script.run( - 'git', 'update-ref', 'refs/remotes/upstream/upstream-branch', - head_sha, cwd=repo_dir - ) - script.run('git', 'update-ref', generic_ref, head_sha, cwd=repo_dir) + script.run("git", "update-ref", generic_ref, head_sha, cwd=repo_dir) # Test two tags pointing to the same sha. - script.run('git', 'tag', 'v2.0', tag_sha, cwd=repo_dir) + script.run("git", "tag", "v2.0", tag_sha, cwd=repo_dir) # Test tags sharing the same suffix as another tag, both before and # after the suffix alphabetically. - script.run('git', 'tag', 'aaa/v1.0', head_sha, cwd=repo_dir) - script.run('git', 'tag', 'zzz/v1.0', head_sha, cwd=repo_dir) + script.run("git", "tag", "aaa/v1.0", head_sha, cwd=repo_dir) + script.run("git", "tag", "zzz/v1.0", head_sha, cwd=repo_dir) - check_rev(repo_dir, 'v1.0', (tag_sha, False)) - check_rev(repo_dir, 'v2.0', (tag_sha, False)) - check_rev(repo_dir, 'origin-branch', (origin_sha, True)) + check_rev(repo_dir, "v1.0", (tag_sha, False)) + check_rev(repo_dir, "v2.0", (tag_sha, False)) + check_rev(repo_dir, "origin-branch", (origin_sha, True)) ignored_names = [ # Local branches should be ignored. - 'local-branch', + "local-branch", # Non-origin remote branches should be ignored. - 'upstream-branch', + "upstream-branch", # Generic refs should be ignored. - 'generic-ref', + "generic-ref", # Fully spelled-out refs should be ignored. origin_ref, generic_ref, # Test passing a valid commit hash. tag_sha, # Test passing a non-existent name. - 'does-not-exist', + "does-not-exist", ] for name in ignored_names: check_rev(repo_dir, name, (None, False)) @@ -209,32 +214,24 @@ def test_is_commit_id_equal(script): Test Git.is_commit_id_equal(). """ version_pkg_path = _create_test_package(script) - script.run('git', 'branch', 'branch0.1', cwd=version_pkg_path) - commit = script.run( - 'git', 'rev-parse', 'HEAD', - cwd=version_pkg_path - ).stdout.strip() + script.run("git", "branch", "branch0.1", cwd=version_pkg_path) + commit = script.run("git", "rev-parse", "HEAD", cwd=version_pkg_path).stdout.strip() assert Git.is_commit_id_equal(version_pkg_path, commit) assert not Git.is_commit_id_equal(version_pkg_path, commit[:7]) - assert not Git.is_commit_id_equal(version_pkg_path, 'branch0.1') - assert not Git.is_commit_id_equal(version_pkg_path, 'abc123') + assert not Git.is_commit_id_equal(version_pkg_path, "branch0.1") + assert not Git.is_commit_id_equal(version_pkg_path, "abc123") # Also check passing a None value. assert not Git.is_commit_id_equal(version_pkg_path, None) def test_is_immutable_rev_checkout(script): version_pkg_path = _create_test_package(script) - commit = script.run( - 'git', 'rev-parse', 'HEAD', - cwd=version_pkg_path - ).stdout.strip() + commit = script.run("git", "rev-parse", "HEAD", cwd=version_pkg_path).stdout.strip() assert Git().is_immutable_rev_checkout( "git+https://g.c/o/r@" + commit, version_pkg_path ) - assert not Git().is_immutable_rev_checkout( - "git+https://g.c/o/r", version_pkg_path - ) + assert not Git().is_immutable_rev_checkout("git+https://g.c/o/r", version_pkg_path) assert not Git().is_immutable_rev_checkout( "git+https://g.c/o/r@master", version_pkg_path ) @@ -267,9 +264,7 @@ def test_resolve_commit_not_on_branch(script, tmp_path): # create a commit repo_file.write_text(u"..") script.run("git", "commit", "-a", "-m", "commit 1", cwd=str(repo_path)) - commit = script.run( - "git", "rev-parse", "HEAD", cwd=str(repo_path) - ).stdout.strip() + commit = script.run("git", "rev-parse", "HEAD", cwd=str(repo_path)).stdout.strip() # make sure our commit is not on a branch script.run("git", "checkout", "master", cwd=str(repo_path)) diff --git a/tests/functional/test_warning.py b/tests/functional/test_warning.py index ff228421e66..5a3502cc957 100644 --- a/tests/functional/test_warning.py +++ b/tests/functional/test_warning.py @@ -8,8 +8,10 @@ @pytest.fixture def warnings_demo(tmpdir): - demo = tmpdir.joinpath('warnings_demo.py') - demo.write_text(textwrap.dedent(''' + demo = tmpdir.joinpath("warnings_demo.py") + demo.write_text( + textwrap.dedent( + """ from logging import basicConfig from pip._internal.utils import deprecation @@ -17,20 +19,22 @@ def warnings_demo(tmpdir): basicConfig() deprecation.deprecated("deprecated!", replacement=None, gone_in=None) - ''')) + """ + ) + ) return demo def test_deprecation_warnings_are_correct(script, warnings_demo): - result = script.run('python', warnings_demo, expect_stderr=True) - expected = 'WARNING:pip._internal.deprecations:DEPRECATION: deprecated!\n' + result = script.run("python", warnings_demo, expect_stderr=True) + expected = "WARNING:pip._internal.deprecations:DEPRECATION: deprecated!\n" assert result.stderr == expected def test_deprecation_warnings_can_be_silenced(script, warnings_demo): - script.environ['PYTHONWARNINGS'] = 'ignore' - result = script.run('python', warnings_demo) - assert result.stderr == '' + script.environ["PYTHONWARNINGS"] = "ignore" + result = script.run("python", warnings_demo) + assert result.stderr == "" DEPRECATION_TEXT = "drop support for Python 2.7" @@ -53,7 +57,7 @@ def test_flag_does_nothing_if_python_version_is_not_2(script): def test_version_warning_is_shown_if_python_version_is_2(script): result = script.pip("debug", allow_stderr_warning=True) assert DEPRECATION_TEXT in result.stderr, str(result) - if platform.python_implementation() == 'CPython': + if platform.python_implementation() == "CPython": assert CPYTHON_DEPRECATION_TEXT in result.stderr, str(result) else: assert CPYTHON_DEPRECATION_TEXT not in result.stderr, str(result) diff --git a/tests/functional/test_wheel.py b/tests/functional/test_wheel.py index 0b58c923785..9046710a14c 100644 --- a/tests/functional/test_wheel.py +++ b/tests/functional/test_wheel.py @@ -16,8 +16,8 @@ def auto_with_wheel(with_wheel): def add_files_to_dist_directory(folder): - (folder / 'dist').mkdir(parents=True) - (folder / 'dist' / 'a_name-0.0.1.tar.gz').write_text("hello") + (folder / "dist").mkdir(parents=True) + (folder / "dist" / "a_name-0.0.1.tar.gz").write_text("hello") # Not adding a wheel file since that confuses setuptools' backend. # (folder / 'dist' / 'a_name-0.0.1-py2.py3-none-any.whl').write_text( # "hello" @@ -28,7 +28,7 @@ def test_wheel_exit_status_code_when_no_requirements(script): """ Test wheel exit status code when no requirements specified """ - result = script.pip('wheel', expect_error=True) + result = script.pip("wheel", expect_error=True) assert "You must give at least one requirement to wheel" in result.stderr assert result.returncode == ERROR @@ -38,7 +38,7 @@ def test_wheel_exit_status_code_when_blank_requirements_file(script): Test wheel exit status code when blank requirements file specified """ script.scratch_path.joinpath("blank.txt").write_text("\n") - script.pip('wheel', '-r', 'blank.txt') + script.pip("wheel", "-r", "blank.txt") def test_pip_wheel_success(script, data): @@ -46,18 +46,22 @@ def test_pip_wheel_success(script, data): Test 'pip wheel' success. """ result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - 'simple==3.0', + "wheel", + "--no-index", + "-f", + data.find_links, + "simple==3.0", ) - wheel_file_name = 'simple-3.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "simple-3.0-py{pyversion[0]}-none-any.whl".format(**globals()) wheel_file_path = script.scratch / wheel_file_name assert re.search( r"Created wheel for simple: " - r"filename={filename} size=\d+ sha256=[A-Fa-f0-9]{{64}}" - .format(filename=re.escape(wheel_file_name)), result.stdout) - assert re.search( - r"^\s+Stored in directory: ", result.stdout, re.M) + r"filename={filename} size=\d+ sha256=[A-Fa-f0-9]{{64}}".format( + filename=re.escape(wheel_file_name) + ), + result.stdout, + ) + assert re.search(r"^\s+Stored in directory: ", result.stdout, re.M) result.did_create(wheel_file_path) assert "Successfully built simple" in result.stdout, result.stdout @@ -67,11 +71,13 @@ def test_pip_wheel_build_cache(script, data): Test 'pip wheel' builds and caches. """ result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - 'simple==3.0', + "wheel", + "--no-index", + "-f", + data.find_links, + "simple==3.0", ) - wheel_file_name = 'simple-3.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "simple-3.0-py{pyversion[0]}-none-any.whl".format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built simple" in result.stdout, result.stdout @@ -80,8 +86,11 @@ def test_pip_wheel_build_cache(script, data): # pip wheel again and test that no build occurs since # we get the wheel from cache result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - 'simple==3.0', + "wheel", + "--no-index", + "-f", + data.find_links, + "simple==3.0", ) result.did_create(wheel_file_path) assert "Successfully built simple" not in result.stdout, result.stdout @@ -92,9 +101,13 @@ def test_basic_pip_wheel_downloads_wheels(script, data): Test 'pip wheel' downloads wheels """ result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, 'simple.dist', + "wheel", + "--no-index", + "-f", + data.find_links, + "simple.dist", ) - wheel_file_name = 'simple.dist-0.1-py2.py3-none-any.whl' + wheel_file_name = "simple.dist-0.1-py2.py3-none-any.whl" wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Saved" in result.stdout, result.stdout @@ -105,20 +118,29 @@ def test_pip_wheel_build_relative_cachedir(script, data): Test 'pip wheel' builds and caches with a non-absolute cache directory. """ result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - '--cache-dir', './cache', - 'simple==3.0', + "wheel", + "--no-index", + "-f", + data.find_links, + "--cache-dir", + "./cache", + "simple==3.0", ) assert result.returncode == 0 def test_pip_wheel_builds_when_no_binary_set(script, data): - data.packages.joinpath('simple-3.0-py2.py3-none-any.whl').touch() + data.packages.joinpath("simple-3.0-py2.py3-none-any.whl").touch() # Check that the wheel package is ignored res = script.pip( - 'wheel', '--no-index', '--no-binary', ':all:', - '-f', data.find_links, - 'simple==3.0') + "wheel", + "--no-index", + "--no-binary", + ":all:", + "-f", + data.find_links, + "simple==3.0", + ) assert "Building wheel for simple" in str(res), str(res) @@ -129,10 +151,13 @@ def test_pip_wheel_readonly_cache(script, data, tmpdir): os.chmod(cache_dir, 0o400) # read-only cache # Check that the wheel package is ignored res = script.pip( - 'wheel', '--no-index', - '-f', data.find_links, - '--cache-dir', cache_dir, - 'simple==3.0', + "wheel", + "--no-index", + "-f", + data.find_links, + "--cache-dir", + cache_dir, + "simple==3.0", allow_stderr_warning=True, ) assert res.returncode == 0 @@ -143,13 +168,11 @@ def test_pip_wheel_builds_editable_deps(script, data): """ Test 'pip wheel' finds and builds dependencies of editables """ - editable_path = os.path.join(data.src, 'requires_simple') + editable_path = os.path.join(data.src, "requires_simple") result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - '-e', editable_path + "wheel", "--no-index", "-f", data.find_links, "-e", editable_path ) - wheel_file_name = 'simple-1.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "simple-1.0-py{pyversion[0]}-none-any.whl".format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) @@ -158,13 +181,13 @@ def test_pip_wheel_builds_editable(script, data): """ Test 'pip wheel' builds an editable package """ - editable_path = os.path.join(data.src, 'simplewheel-1.0') + editable_path = os.path.join(data.src, "simplewheel-1.0") result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - '-e', editable_path + "wheel", "--no-index", "-f", data.find_links, "-e", editable_path + ) + wheel_file_name = "simplewheel-1.0-py{pyversion[0]}-none-any.whl".format( + **globals() ) - wheel_file_name = 'simplewheel-1.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) @@ -174,12 +197,16 @@ def test_pip_wheel_fail(script, data): Test 'pip wheel' failure. """ result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - 'wheelbroken==0.1', + "wheel", + "--no-index", + "-f", + data.find_links, + "wheelbroken==0.1", expect_error=True, ) - wheel_file_name = 'wheelbroken-0.1-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "wheelbroken-0.1-py{pyversion[0]}-none-any.whl".format( + **globals() + ) wheel_file_path = script.scratch / wheel_file_name result.did_not_create(wheel_file_path) assert "FakeError" in result.stderr, result.stderr @@ -195,11 +222,15 @@ def test_no_clean_option_blocks_cleaning_after_wheel( """ Test --no-clean option blocks cleaning after wheel build """ - build = script.venv_path / 'build' + build = script.venv_path / "build" result = script.pip( - 'wheel', '--no-clean', '--no-index', '--build', build, - '--find-links={data.find_links}'.format(**locals()), - 'simple', + "wheel", + "--no-clean", + "--no-index", + "--build", + build, + "--find-links={data.find_links}".format(**locals()), + "simple", expect_temp=True, # TODO: allow_stderr_warning is used for the --build deprecation, # remove it when removing support for --build @@ -207,7 +238,7 @@ def test_no_clean_option_blocks_cleaning_after_wheel( ) if not use_new_resolver: - build = build / 'simple' + build = build / "simple" message = "build/simple should still exist {}".format(result) assert exists(build), message @@ -219,11 +250,13 @@ def test_pip_wheel_source_deps(script, data): """ # 'requires_source' is a wheel that depends on the 'source' project result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - 'requires_source', + "wheel", + "--no-index", + "-f", + data.find_links, + "requires_source", ) - wheel_file_name = 'source-1.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "source-1.0-py{pyversion[0]}-none-any.whl".format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built source" in result.stdout, result.stdout @@ -240,24 +273,25 @@ def test_pip_wheel_fail_cause_of_previous_build_dir( """ # Given that I have a previous build dir of the `simple` package - build = script.venv_path / 'build' / 'simple' + build = script.venv_path / "build" / "simple" os.makedirs(build) - build.joinpath('setup.py').write_text('#') + build.joinpath("setup.py").write_text("#") # When I call pip trying to install things again result = script.pip( - 'wheel', '--no-index', - '--find-links={data.find_links}'.format(**locals()), - '--build', script.venv_path / 'build', - 'simple==3.0', + "wheel", + "--no-index", + "--find-links={data.find_links}".format(**locals()), + "--build", + script.venv_path / "build", + "simple==3.0", expect_error=(not use_new_resolver), expect_temp=(not use_new_resolver), expect_stderr=True, ) assert ( - "The -b/--build/--build-dir/--build-directory " - "option is deprecated." + "The -b/--build/--build-dir/--build-directory " "option is deprecated." ) in result.stderr # Then I see that the error code is the right one @@ -269,15 +303,21 @@ def test_wheel_package_with_latin1_setup(script, data): """Create a wheel from a package with latin-1 encoded setup.py.""" pkg_to_wheel = data.packages.joinpath("SetupPyLatin1") - result = script.pip('wheel', pkg_to_wheel) - assert 'Successfully built SetupPyUTF8' in result.stdout + result = script.pip("wheel", pkg_to_wheel) + assert "Successfully built SetupPyUTF8" in result.stdout def test_pip_wheel_with_pep518_build_reqs(script, data, common_wheels): - result = script.pip('wheel', '--no-index', '-f', data.find_links, - '-f', common_wheels, 'pep518==3.0',) - wheel_file_name = 'pep518-3.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + result = script.pip( + "wheel", + "--no-index", + "-f", + data.find_links, + "-f", + common_wheels, + "pep518==3.0", + ) + wheel_file_name = "pep518-3.0-py{pyversion[0]}-none-any.whl".format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built pep518" in result.stdout, result.stdout @@ -285,13 +325,16 @@ def test_pip_wheel_with_pep518_build_reqs(script, data, common_wheels): def test_pip_wheel_with_pep518_build_reqs_no_isolation(script, data): - script.pip_install_local('simplewheel==2.0') + script.pip_install_local("simplewheel==2.0") result = script.pip( - 'wheel', '--no-index', '-f', data.find_links, - '--no-build-isolation', 'pep518==3.0', + "wheel", + "--no-index", + "-f", + data.find_links, + "--no-build-isolation", + "pep518==3.0", ) - wheel_file_name = 'pep518-3.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "pep518-3.0-py{pyversion[0]}-none-any.whl".format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built pep518" in result.stdout, result.stdout @@ -299,60 +342,60 @@ def test_pip_wheel_with_pep518_build_reqs_no_isolation(script, data): def test_pip_wheel_with_user_set_in_config(script, data, common_wheels): - config_file = script.scratch_path / 'pip.conf' - script.environ['PIP_CONFIG_FILE'] = str(config_file) + config_file = script.scratch_path / "pip.conf" + script.environ["PIP_CONFIG_FILE"] = str(config_file) config_file.write_text("[install]\nuser = true") result = script.pip( - 'wheel', data.src / 'withpyproject', - '--no-index', '-f', common_wheels + "wheel", data.src / "withpyproject", "--no-index", "-f", common_wheels ) assert "Successfully built withpyproject" in result.stdout, result.stdout -@pytest.mark.skipif(sys.platform.startswith('win'), - reason='The empty extension module does not work on Win') +@pytest.mark.skipif( + sys.platform.startswith("win"), + reason="The empty extension module does not work on Win", +) def test_pip_wheel_ext_module_with_tmpdir_inside(script, data, common_wheels): - tmpdir = data.src / 'extension/tmp' + tmpdir = data.src / "extension/tmp" tmpdir.mkdir() - script.environ['TMPDIR'] = str(tmpdir) + script.environ["TMPDIR"] = str(tmpdir) # To avoid a test dependency on a C compiler, we set the env vars to "noop" # The .c source is empty anyway - script.environ['CC'] = script.environ['LDSHARED'] = str('true') + script.environ["CC"] = script.environ["LDSHARED"] = str("true") result = script.pip( - 'wheel', data.src / 'extension', - '--no-index', '-f', common_wheels + "wheel", data.src / "extension", "--no-index", "-f", common_wheels ) assert "Successfully built extension" in result.stdout, result.stdout @pytest.mark.network def test_pep517_wheels_are_not_confused_with_other_files(script, tmpdir, data): - """Check correct wheels are copied. (#6196) - """ - pkg_to_wheel = data.src / 'withpyproject' + """Check correct wheels are copied. (#6196)""" + pkg_to_wheel = data.src / "withpyproject" add_files_to_dist_directory(pkg_to_wheel) - result = script.pip('wheel', pkg_to_wheel, '-w', script.scratch_path) + result = script.pip("wheel", pkg_to_wheel, "-w", script.scratch_path) assert "Installing build dependencies" in result.stdout, result.stdout - wheel_file_name = 'withpyproject-0.0.1-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "withpyproject-0.0.1-py{pyversion[0]}-none-any.whl".format( + **globals() + ) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) def test_legacy_wheels_are_not_confused_with_other_files(script, tmpdir, data): - """Check correct wheels are copied. (#6196) - """ - pkg_to_wheel = data.src / 'simplewheel-1.0' + """Check correct wheels are copied. (#6196)""" + pkg_to_wheel = data.src / "simplewheel-1.0" add_files_to_dist_directory(pkg_to_wheel) - result = script.pip('wheel', pkg_to_wheel, '-w', script.scratch_path) + result = script.pip("wheel", pkg_to_wheel, "-w", script.scratch_path) assert "Installing build dependencies" not in result.stdout, result.stdout - wheel_file_name = 'simplewheel-1.0-py{pyversion[0]}-none-any.whl' \ - .format(**globals()) + wheel_file_name = "simplewheel-1.0-py{pyversion[0]}-none-any.whl".format( + **globals() + ) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) diff --git a/tests/functional/test_yaml.py b/tests/functional/test_yaml.py index e22a01ace91..3322519c43b 100644 --- a/tests/functional/test_yaml.py +++ b/tests/functional/test_yaml.py @@ -22,12 +22,12 @@ def generate_yaml_tests(directory): # Strip the parts of the directory to only get a name without # extension and resolver directory - base_name = str(yml_file)[len(str(directory)) + 1:-4] + base_name = str(yml_file)[len(str(directory)) + 1 : -4] base = data.get("base", {}) cases = data["cases"] - for resolver in 'old', 'new': + for resolver in "old", "new": for i, case_template in enumerate(cases): case = base.copy() case.update(case_template) @@ -39,7 +39,7 @@ def generate_yaml_tests(directory): case[":resolver:"] = resolver skip = case.pop("skip", False) - assert skip in [False, True, 'old', 'new'] + assert skip in [False, True, "old", "new"] if skip is True or skip == resolver: case = pytest.param(case, marks=pytest.mark.xfail) @@ -60,7 +60,6 @@ def id_func(param): def convert_to_dict(string): - def stripping_split(my_str, splitwith, count=None): if count is None: return [x.strip() for x in my_str.strip().split(splitwith)] @@ -85,14 +84,13 @@ def stripping_split(my_str, splitwith, count=None): def handle_request(script, action, requirement, options, new_resolver=False): - if action == 'install': - args = ['install'] + if action == "install": + args = ["install"] if new_resolver: args.append("--use-feature=2020-resolver") - args.extend(["--no-index", "--find-links", - path_to_url(script.scratch_path)]) - elif action == 'uninstall': - args = ['uninstall', '--yes'] + args.extend(["--no-index", "--find-links", path_to_url(script.scratch_path)]) + elif action == "uninstall": + args = ["uninstall", "--yes"] else: raise "Did not excpet action: {!r}".format(action) @@ -106,18 +104,17 @@ def handle_request(script, action, requirement, options, new_resolver=False): args.extend(options) args.append("--verbose") - result = script.pip(*args, - allow_stderr_error=True, - allow_stderr_warning=True, - allow_error=True) + result = script.pip( + *args, allow_stderr_error=True, allow_stderr_warning=True, allow_error=True + ) # Check which packages got installed state = [] for path in os.listdir(script.site_packages_path): if path.endswith(".dist-info"): - name, version = ( - os.path.basename(path)[:-len(".dist-info")] - ).rsplit("-", 1) + name, version = (os.path.basename(path)[: -len(".dist-info")]).rsplit( + "-", 1 + ) # TODO: information about extras. state.append(" ".join((name, version))) @@ -125,11 +122,11 @@ def handle_request(script, action, requirement, options, new_resolver=False): def check_error(error, result): - return_code = error.get('code') + return_code = error.get("code") if return_code: assert result.returncode == return_code - stderr = error.get('stderr') + stderr = error.get("stderr") if not stderr: return @@ -142,8 +139,7 @@ def check_error(error, result): for patter in patters: match = re.search(patter, result.stderr, re.I) - assert match, 'regex %r not found in stderr: %r' % ( - stderr, result.stderr) + assert match, "regex %r not found in stderr: %r" % (stderr, result.stderr) @pytest.mark.yaml @@ -155,9 +151,9 @@ def test_yaml_based(script, case): requests = case.get("request", []) responses = case.get("response", []) - assert len(requests) == len(responses), ( - "Expected requests and responses counts to be same" - ) + assert len(requests) == len( + responses + ), "Expected requests and responses counts to be same" # Create a custom index of all the packages that are supposed to be # available @@ -173,30 +169,34 @@ def test_yaml_based(script, case): # use scratch path for index for request, response in zip(requests, responses): - for action in 'install', 'uninstall': + for action in "install", "uninstall": if action in request: break else: raise "Unsupported request {!r}".format(request) # Perform the requested action - effect = handle_request(script, action, - request[action], - request.get('options', '').split(), - case[':resolver:'] == 'new') - result = effect['result'] + effect = handle_request( + script, + action, + request[action], + request.get("options", "").split(), + case[":resolver:"] == "new", + ) + result = effect["result"] if 0: # for analyzing output easier - with open(DATA_DIR.parent / "yaml" / - case[':name:'].replace('*', '-'), 'w') as fo: + with open( + DATA_DIR.parent / "yaml" / case[":name:"].replace("*", "-"), "w" + ) as fo: fo.write("=== RETURNCODE = %d\n" % result.returncode) fo.write("=== STDERR ===:\n%s\n" % result.stderr) - if 'state' in response: - assert effect['state'] == (response['state'] or []), str(result) + if "state" in response: + assert effect["state"] == (response["state"] or []), str(result) - error = response.get('error') - if error and case[":resolver:"] == 'new' and sys.platform != 'win32': + error = response.get("error") + if error and case[":resolver:"] == "new" and sys.platform != "win32": # Note: we currently skip running these tests on Windows, as they # were failing due to different error codes. There should not # be a reason for not running these this check on Windows. diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py index 07569d814f4..fedba1a984a 100644 --- a/tests/lib/__init__.py +++ b/tests/lib/__init__.py @@ -57,12 +57,12 @@ def path_to_url(path): path = os.path.normpath(os.path.abspath(path)) drive, path = os.path.splitdrive(path) filepath = path.split(os.path.sep) - url = '/'.join(filepath) + url = "/".join(filepath) if drive: # Note: match urllib.request.pathname2url's # behavior: uppercase the drive letter. - return 'file:///' + drive.upper() + url - return 'file://' + url + return "file:///" + drive.upper() + url + return "file://" + url def _test_path_to_file_url(path): @@ -72,12 +72,11 @@ def _test_path_to_file_url(path): Args: path: a tests.lib.path.Path object. """ - return 'file://' + path.resolve().replace('\\', '/') + return "file://" + path.resolve().replace("\\", "/") def create_file(path, contents=None): - """Create a file on the path, with the given contents - """ + """Create a file on the path, with the given contents""" from pip._internal.utils.misc import ensure_dir ensure_dir(os.path.dirname(path)) @@ -103,7 +102,7 @@ def make_test_search_scope( def make_test_link_collector( find_links=None, # type: Optional[List[str]] index_urls=None, # type: Optional[List[str]] - session=None, # type: Optional[PipSession] + session=None, # type: Optional[PipSession] ): # type: (...) -> LinkCollector """ @@ -124,8 +123,8 @@ def make_test_finder( find_links=None, # type: Optional[List[str]] index_urls=None, # type: Optional[List[str]] allow_all_prereleases=False, # type: bool - session=None, # type: Optional[PipSession] - target_python=None, # type: Optional[TargetPython] + session=None, # type: Optional[PipSession] + target_python=None, # type: Optional[TargetPython] ): # type: (...) -> PackageFinder """ @@ -229,51 +228,59 @@ class TestFailure(AssertionError): """ An "assertion" failed during testing. """ + pass class TestPipResult(object): - def __init__(self, impl, verbose=False): self._impl = impl if verbose: print(self.stdout) if self.stderr: - print('======= stderr ========') + print("======= stderr ========") print(self.stderr) - print('=======================') + print("=======================") def __getattr__(self, attr): return getattr(self._impl, attr) - if sys.platform == 'win32': + if sys.platform == "win32": @property def stdout(self): - return self._impl.stdout.replace('\r\n', '\n') + return self._impl.stdout.replace("\r\n", "\n") @property def stderr(self): - return self._impl.stderr.replace('\r\n', '\n') + return self._impl.stderr.replace("\r\n", "\n") def __str__(self): - return str(self._impl).replace('\r\n', '\n') + return str(self._impl).replace("\r\n", "\n") + else: # Python doesn't automatically forward __str__ through __getattr__ def __str__(self): return str(self._impl) - def assert_installed(self, pkg_name, editable=True, with_files=None, - without_files=None, without_egg_link=False, - use_user_site=False, sub_dir=False): + def assert_installed( + self, + pkg_name, + editable=True, + with_files=None, + without_files=None, + without_egg_link=False, + use_user_site=False, + sub_dir=False, + ): with_files = with_files or [] without_files = without_files or [] e = self.test_env if editable: - pkg_dir = e.venv / 'src' / pkg_name.lower() + pkg_dir = e.venv / "src" / pkg_name.lower() # If package was installed in a sub directory if sub_dir: pkg_dir = pkg_dir / sub_dir @@ -282,78 +289,86 @@ def assert_installed(self, pkg_name, editable=True, with_files=None, pkg_dir = e.site_packages / pkg_name if use_user_site: - egg_link_path = e.user_site / pkg_name + '.egg-link' + egg_link_path = e.user_site / pkg_name + ".egg-link" else: - egg_link_path = e.site_packages / pkg_name + '.egg-link' + egg_link_path = e.site_packages / pkg_name + ".egg-link" if without_egg_link: if egg_link_path in self.files_created: raise TestFailure( - 'unexpected egg link file created: ' - '{egg_link_path!r}\n{self}' - .format(**locals()) + "unexpected egg link file created: " + "{egg_link_path!r}\n{self}".format(**locals()) ) else: if egg_link_path not in self.files_created: raise TestFailure( - 'expected egg link file missing: ' - '{egg_link_path!r}\n{self}' - .format(**locals()) + "expected egg link file missing: " + "{egg_link_path!r}\n{self}".format(**locals()) ) egg_link_file = self.files_created[egg_link_path] - egg_link_contents = egg_link_file.bytes.replace(os.linesep, '\n') + egg_link_contents = egg_link_file.bytes.replace(os.linesep, "\n") # FIXME: I don't understand why there's a trailing . here - if not (egg_link_contents.endswith('\n.') and - egg_link_contents[:-2].endswith(pkg_dir)): - raise TestFailure(textwrap.dedent( - u'''\ + if not ( + egg_link_contents.endswith("\n.") + and egg_link_contents[:-2].endswith(pkg_dir) + ): + raise TestFailure( + textwrap.dedent( + u"""\ Incorrect egg_link file {egg_link_file!r} Expected ending: {expected_ending!r} ------- Actual contents ------- {egg_link_contents!r} - -------------------------------'''.format( - expected_ending=pkg_dir + '\n.', - **locals()) - )) + -------------------------------""".format( + expected_ending=pkg_dir + "\n.", **locals() + ) + ) + ) if use_user_site: - pth_file = e.user_site / 'easy-install.pth' + pth_file = e.user_site / "easy-install.pth" else: - pth_file = e.site_packages / 'easy-install.pth' + pth_file = e.site_packages / "easy-install.pth" if (pth_file in self.files_updated) == without_egg_link: raise TestFailure( - '{pth_file} unexpectedly {maybe}updated by install'.format( - maybe=not without_egg_link and 'not ' or '', - **locals())) + "{pth_file} unexpectedly {maybe}updated by install".format( + maybe=not without_egg_link and "not " or "", **locals() + ) + ) if (pkg_dir in self.files_created) == (curdir in without_files): - raise TestFailure(textwrap.dedent('''\ + raise TestFailure( + textwrap.dedent( + """\ expected package directory {pkg_dir!r} {maybe}to be created actually created: {files} - ''').format( - pkg_dir=pkg_dir, - maybe=curdir in without_files and 'not ' or '', - files=sorted(self.files_created.keys()), - )) + """ + ).format( + pkg_dir=pkg_dir, + maybe=curdir in without_files and "not " or "", + files=sorted(self.files_created.keys()), + ) + ) for f in with_files: normalized_path = os.path.normpath(pkg_dir / f) if normalized_path not in self.files_created: raise TestFailure( - 'Package directory {pkg_dir!r} missing ' - 'expected content {f!r}'.format(**locals()) + "Package directory {pkg_dir!r} missing " + "expected content {f!r}".format(**locals()) ) for f in without_files: normalized_path = os.path.normpath(pkg_dir / f) if normalized_path in self.files_created: raise TestFailure( - 'Package directory {pkg_dir!r} has unexpected content {f}' - .format(**locals()) + "Package directory {pkg_dir!r} has unexpected content {f}".format( + **locals() + ) ) def did_create(self, path, message=None): @@ -370,8 +385,7 @@ def did_not_update(self, path, message=None): def _one_or_both(a, b): - """Returns f"{a}\n{b}" if a is truthy, else returns str(b). - """ + """Returns f"{a}\n{b}" if a is truthy, else returns str(b).""" if not a: return str(b) @@ -382,15 +396,19 @@ def make_check_stderr_message(stderr, line, reason): """ Create an exception message to use inside check_stderr(). """ - return dedent("""\ + return dedent( + """\ {reason}: Caused by line: {line!r} Complete stderr: {stderr} - """).format(stderr=stderr, line=line, reason=reason) + """ + ).format(stderr=stderr, line=line, reason=reason) def _check_stderr( - stderr, allow_stderr_warning, allow_stderr_error, + stderr, + allow_stderr_warning, + allow_stderr_error, ): """ Check the given stderr for logged warnings and errors. @@ -411,29 +429,29 @@ def _check_stderr( # sent directly to stderr and so bypass any configured log formatter. # The "--- Logging error ---" string is used in Python 3.4+, and # "Logged from file " is used in Python 2. - if (line.startswith('--- Logging error ---') or - line.startswith('Logged from file ')): - reason = 'stderr has a logging error, which is never allowed' + if line.startswith("--- Logging error ---") or line.startswith( + "Logged from file " + ): + reason = "stderr has a logging error, which is never allowed" msg = make_check_stderr_message(stderr, line=line, reason=reason) raise RuntimeError(msg) if allow_stderr_error: continue - if line.startswith('ERROR: '): + if line.startswith("ERROR: "): reason = ( - 'stderr has an unexpected error ' - '(pass allow_stderr_error=True to permit this)' + "stderr has an unexpected error " + "(pass allow_stderr_error=True to permit this)" ) msg = make_check_stderr_message(stderr, line=line, reason=reason) raise RuntimeError(msg) if allow_stderr_warning: continue - if (line.startswith('WARNING: ') or - line.startswith(DEPRECATION_MSG_PREFIX)): + if line.startswith("WARNING: ") or line.startswith(DEPRECATION_MSG_PREFIX): reason = ( - 'stderr has an unexpected warning ' - '(pass allow_stderr_warning=True to permit this)' + "stderr has an unexpected warning " + "(pass allow_stderr_warning=True to permit this)" ) msg = make_check_stderr_message(stderr, line=line, reason=reason) raise RuntimeError(msg) @@ -453,7 +471,7 @@ class PipTestEnvironment(TestFileEnvironment): # a name of the form xxxx_path and relative paths have a name that # does not end in '_path'. - exe = sys.platform == 'win32' and '.exe' or '' + exe = sys.platform == "win32" and ".exe" or "" verbose = False def __init__(self, base_path, *args, **kwargs): @@ -470,16 +488,16 @@ def __init__(self, base_path, *args, **kwargs): self.user_base_path = self.venv_path.joinpath("user") self.user_site_path = self.venv_path.joinpath( "user", - site.USER_SITE[len(site.USER_BASE) + 1:], + site.USER_SITE[len(site.USER_BASE) + 1 :], ) - if sys.platform == 'win32': + if sys.platform == "win32": if sys.version_info >= (3, 5): scripts_base = Path( - os.path.normpath(self.user_site_path.joinpath('..')) + os.path.normpath(self.user_site_path.joinpath("..")) ) else: scripts_base = self.user_base_path - self.user_bin_path = scripts_base.joinpath('Scripts') + self.user_bin_path = scripts_base.joinpath("Scripts") else: self.user_bin_path = self.user_base_path.joinpath( os.path.relpath(self.bin_path, self.venv_path) @@ -505,18 +523,27 @@ def __init__(self, base_path, *args, **kwargs): # Whether all pip invocations should expect stderr # (useful for Python version deprecation) - self.pip_expect_warning = kwargs.pop('pip_expect_warning', None) + self.pip_expect_warning = kwargs.pop("pip_expect_warning", None) # Call the TestFileEnvironment __init__ super(PipTestEnvironment, self).__init__(base_path, *args, **kwargs) # Expand our absolute path directories into relative - for name in ["base", "venv", "bin", "lib", "site_packages", - "user_base", "user_site", "user_bin", "scratch"]: + for name in [ + "base", + "venv", + "bin", + "lib", + "site_packages", + "user_base", + "user_site", + "user_bin", + "scratch", + ]: real_name = "{name}_path".format(**locals()) - relative_path = Path(os.path.relpath( - getattr(self, real_name), self.base_path - )) + relative_path = Path( + os.path.relpath(getattr(self, real_name), self.base_path) + ) setattr(self, name, relative_path) # Make sure temp_path is a Path object @@ -530,7 +557,7 @@ def __init__(self, base_path, *args, **kwargs): self.user_site_path.joinpath("easy-install.pth").touch() def _ignore_file(self, fn): - if fn.endswith('__pycache__') or fn.endswith(".pyc"): + if fn.endswith("__pycache__") or fn.endswith(".pyc"): result = True else: result = super(PipTestEnvironment, self)._ignore_file(fn) @@ -541,7 +568,7 @@ def _find_traverse(self, path, result): # results because of venv `lib64 -> lib/` symlink on Linux. full = os.path.join(self.base_path, path) if os.path.isdir(full) and os.path.islink(full): - if not self.temp_path or path != 'tmp': + if not self.temp_path or path != "tmp": result[path] = FoundDir(self.base_path, path) else: super(PipTestEnvironment, self)._find_traverse(path, result) @@ -567,50 +594,48 @@ def run(self, *args, **kw): compatibility. """ if self.verbose: - print('>> running {args} {kw}'.format(**locals())) + print(">> running {args} {kw}".format(**locals())) - cwd = kw.pop('cwd', None) - run_from = kw.pop('run_from', None) + cwd = kw.pop("cwd", None) + run_from = kw.pop("run_from", None) assert not cwd or not run_from, "Don't use run_from; it's going away" cwd = cwd or run_from or self.cwd - if sys.platform == 'win32': + if sys.platform == "win32": # Partial fix for ScriptTest.run using `shell=True` on Windows. - args = [str(a).replace('^', '^^').replace('&', '^&') for a in args] + args = [str(a).replace("^", "^^").replace("&", "^&") for a in args] # Remove `allow_stderr_error`, `allow_stderr_warning` and # `allow_error` before calling run() because PipTestEnvironment # doesn't support them. - allow_stderr_error = kw.pop('allow_stderr_error', None) - allow_stderr_warning = kw.pop('allow_stderr_warning', None) - allow_error = kw.pop('allow_error', None) + allow_stderr_error = kw.pop("allow_stderr_error", None) + allow_stderr_warning = kw.pop("allow_stderr_warning", None) + allow_error = kw.pop("allow_error", None) if allow_error: - kw['expect_error'] = True + kw["expect_error"] = True # Propagate default values. - expect_error = kw.get('expect_error') + expect_error = kw.get("expect_error") if expect_error: # Then default to allowing logged errors. if allow_stderr_error is not None and not allow_stderr_error: raise RuntimeError( - 'cannot pass allow_stderr_error=False with ' - 'expect_error=True' + "cannot pass allow_stderr_error=False with " "expect_error=True" ) allow_stderr_error = True - elif kw.get('expect_stderr'): + elif kw.get("expect_stderr"): # Then default to allowing logged warnings. if allow_stderr_warning is not None and not allow_stderr_warning: raise RuntimeError( - 'cannot pass allow_stderr_warning=False with ' - 'expect_stderr=True' + "cannot pass allow_stderr_warning=False with " "expect_stderr=True" ) allow_stderr_warning = True if allow_stderr_error: if allow_stderr_warning is not None and not allow_stderr_warning: raise RuntimeError( - 'cannot pass allow_stderr_warning=False with ' - 'allow_stderr_error=True' + "cannot pass allow_stderr_warning=False with " + "allow_stderr_error=True" ) # Default values if not set. @@ -621,7 +646,7 @@ def run(self, *args, **kw): # Pass expect_stderr=True to allow any stderr. We do this because # we do our checking of stderr further on in check_stderr(). - kw['expect_stderr'] = True + kw["expect_stderr"] = True result = super(PipTestEnvironment, self).run(cwd=cwd, *args, **kw) if expect_error and not allow_error: @@ -630,7 +655,8 @@ def run(self, *args, **kw): raise AssertionError("Script passed unexpectedly.") _check_stderr( - result.stderr, allow_stderr_error=allow_stderr_error, + result.stderr, + allow_stderr_error=allow_stderr_error, allow_stderr_warning=allow_stderr_warning, ) @@ -639,24 +665,27 @@ def run(self, *args, **kw): def pip(self, *args, **kwargs): __tracebackhide__ = True if self.pip_expect_warning: - kwargs['allow_stderr_warning'] = True - if kwargs.pop('use_module', True): - exe = 'python' - args = ('-m', 'pip') + args + kwargs["allow_stderr_warning"] = True + if kwargs.pop("use_module", True): + exe = "python" + args = ("-m", "pip") + args else: - exe = 'pip' + exe = "pip" return self.run(exe, *args, **kwargs) def pip_install_local(self, *args, **kwargs): return self.pip( - "install", "--no-index", - "--find-links", path_to_url(os.path.join(DATA_DIR, "packages")), - *args, **kwargs + "install", + "--no-index", + "--find-links", + path_to_url(os.path.join(DATA_DIR, "packages")), + *args, + **kwargs ) def easy_install(self, *args, **kwargs): - args = ('-m', 'easy_install') + args - return self.run('python', *args, **kwargs) + args = ("-m", "easy_install") + args + return self.run("python", *args, **kwargs) # FIXME ScriptTest does something similar, but only within a single @@ -694,15 +723,15 @@ def prefix_match(path, prefix): prefix = prefix.rstrip(os.path.sep) + os.path.sep return path.startswith(prefix) - start_keys = {k for k in start.keys() - if not any([prefix_match(k, i) for i in ignore])} - end_keys = {k for k in end.keys() - if not any([prefix_match(k, i) for i in ignore])} + start_keys = { + k for k in start.keys() if not any([prefix_match(k, i) for i in ignore]) + } + end_keys = {k for k in end.keys() if not any([prefix_match(k, i) for i in ignore])} deleted = {k: start[k] for k in start_keys.difference(end_keys)} created = {k: end[k] for k in end_keys.difference(start_keys)} updated = {} for k in start_keys.intersection(end_keys): - if (start[k].size != end[k].size): + if start[k].size != end[k].size: updated[k] = end[k] return dict(deleted=deleted, created=created, updated=updated) @@ -731,8 +760,10 @@ def assert_all_changes(start_state, end_state, expected_changes): diff = diff_states(start_files, end_files, ignore=expected_changes) if list(diff.values()) != [{}, {}, {}]: - raise TestFailure('Unexpected changes:\n' + '\n'.join( - [k + ': ' + ', '.join(v.keys()) for k, v in diff.items()])) + raise TestFailure( + "Unexpected changes:\n" + + "\n".join([k + ": " + ", ".join(v.keys()) for k, v in diff.items()]) + ) # Don't throw away this potentially useful information return diff @@ -743,14 +774,18 @@ def _create_main_file(dir_path, name=None, output=None): Create a module with a main() function that prints the given output. """ if name is None: - name = 'version_pkg' + name = "version_pkg" if output is None: - output = '0.1' - text = textwrap.dedent("""\ + output = "0.1" + text = textwrap.dedent( + """\ def main(): print({!r}) - """.format(output)) - filename = '{}.py'.format(name) + """.format( + output + ) + ) + filename = "{}.py".format(name) dir_path.joinpath(filename).write_text(text) @@ -770,7 +805,7 @@ def _git_commit( message: an optional commit message. """ if message is None: - message = 'test commit' + message = "test commit" args = [] @@ -781,100 +816,121 @@ def _git_commit( args.append("--all") new_args = [ - 'git', 'commit', '-q', '--author', 'pip ', + "git", + "commit", + "-q", + "--author", + "pip ", ] new_args.extend(args) - new_args.extend(['-m', message]) + new_args.extend(["-m", message]) env_or_script.run(*new_args, cwd=repo_dir) -def _vcs_add(script, version_pkg_path, vcs='git'): - if vcs == 'git': - script.run('git', 'init', cwd=version_pkg_path) - script.run('git', 'add', '.', cwd=version_pkg_path) - _git_commit(script, version_pkg_path, message='initial version') - elif vcs == 'hg': - script.run('hg', 'init', cwd=version_pkg_path) - script.run('hg', 'add', '.', cwd=version_pkg_path) +def _vcs_add(script, version_pkg_path, vcs="git"): + if vcs == "git": + script.run("git", "init", cwd=version_pkg_path) + script.run("git", "add", ".", cwd=version_pkg_path) + _git_commit(script, version_pkg_path, message="initial version") + elif vcs == "hg": + script.run("hg", "init", cwd=version_pkg_path) + script.run("hg", "add", ".", cwd=version_pkg_path) script.run( - 'hg', 'commit', '-q', - '--user', 'pip ', - '-m', 'initial version', cwd=version_pkg_path, + "hg", + "commit", + "-q", + "--user", + "pip ", + "-m", + "initial version", + cwd=version_pkg_path, ) - elif vcs == 'svn': + elif vcs == "svn": repo_url = _create_svn_repo(script, version_pkg_path) script.run( - 'svn', 'checkout', repo_url, 'pip-test-package', - cwd=script.scratch_path + "svn", "checkout", repo_url, "pip-test-package", cwd=script.scratch_path ) - checkout_path = script.scratch_path / 'pip-test-package' + checkout_path = script.scratch_path / "pip-test-package" # svn internally stores windows drives as uppercase; we'll match that. - checkout_path = checkout_path.replace('c:', 'C:') + checkout_path = checkout_path.replace("c:", "C:") version_pkg_path = checkout_path - elif vcs == 'bazaar': - script.run('bzr', 'init', cwd=version_pkg_path) - script.run('bzr', 'add', '.', cwd=version_pkg_path) + elif vcs == "bazaar": + script.run("bzr", "init", cwd=version_pkg_path) + script.run("bzr", "add", ".", cwd=version_pkg_path) script.run( - 'bzr', 'whoami', 'pip ', - cwd=version_pkg_path) + "bzr", "whoami", "pip ", cwd=version_pkg_path + ) script.run( - 'bzr', 'commit', '-q', - '--author', 'pip ', - '-m', 'initial version', cwd=version_pkg_path, + "bzr", + "commit", + "-q", + "--author", + "pip ", + "-m", + "initial version", + cwd=version_pkg_path, ) else: - raise ValueError('Unknown vcs: {vcs}'.format(**locals())) + raise ValueError("Unknown vcs: {vcs}".format(**locals())) return version_pkg_path def _create_test_package_with_subdirectory(script, subdirectory): script.scratch_path.joinpath("version_pkg").mkdir() - version_pkg_path = script.scratch_path / 'version_pkg' + version_pkg_path = script.scratch_path / "version_pkg" _create_main_file(version_pkg_path, name="version_pkg", output="0.1") version_pkg_path.joinpath("setup.py").write_text( - textwrap.dedent(""" + textwrap.dedent( + """ from setuptools import setup, find_packages setup(name='version_pkg', version='0.1', packages=find_packages(), py_modules=['version_pkg'], entry_points=dict(console_scripts=['version_pkg=version_pkg:main'])) - """)) + """ + ) + ) subdirectory_path = version_pkg_path.joinpath(subdirectory) subdirectory_path.mkdir() _create_main_file(subdirectory_path, name="version_subpkg", output="0.1") - subdirectory_path.joinpath('setup.py').write_text( - textwrap.dedent(""" + subdirectory_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup, find_packages setup(name='version_subpkg', version='0.1', packages=find_packages(), py_modules=['version_subpkg'], entry_points=dict(console_scripts=['version_pkg=version_subpkg:main'])) - """)) + """ + ) + ) - script.run('git', 'init', cwd=version_pkg_path) - script.run('git', 'add', '.', cwd=version_pkg_path) - _git_commit(script, version_pkg_path, message='initial version') + script.run("git", "init", cwd=version_pkg_path) + script.run("git", "add", ".", cwd=version_pkg_path) + _git_commit(script, version_pkg_path, message="initial version") return version_pkg_path -def _create_test_package_with_srcdir(script, name='version_pkg', vcs='git'): +def _create_test_package_with_srcdir(script, name="version_pkg", vcs="git"): script.scratch_path.joinpath(name).mkdir() version_pkg_path = script.scratch_path / name - subdir_path = version_pkg_path.joinpath('subdir') + subdir_path = version_pkg_path.joinpath("subdir") subdir_path.mkdir() - src_path = subdir_path.joinpath('src') + src_path = subdir_path.joinpath("src") src_path.mkdir() - pkg_path = src_path.joinpath('pkg') + pkg_path = src_path.joinpath("pkg") pkg_path.mkdir() - pkg_path.joinpath('__init__.py').write_text('') - subdir_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkg_path.joinpath("__init__.py").write_text("") + subdir_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup, find_packages setup( name='{name}', @@ -882,15 +938,21 @@ def _create_test_package_with_srcdir(script, name='version_pkg', vcs='git'): packages=find_packages(), package_dir={{'': 'src'}}, ) - """.format(name=name))) + """.format( + name=name + ) + ) + ) return _vcs_add(script, version_pkg_path, vcs) -def _create_test_package(script, name='version_pkg', vcs='git'): +def _create_test_package(script, name="version_pkg", vcs="git"): script.scratch_path.joinpath(name).mkdir() version_pkg_path = script.scratch_path / name - _create_main_file(version_pkg_path, name=name, output='0.1') - version_pkg_path.joinpath("setup.py").write_text(textwrap.dedent(""" + _create_main_file(version_pkg_path, name=name, output="0.1") + version_pkg_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup, find_packages setup( name='{name}', @@ -899,33 +961,35 @@ def _create_test_package(script, name='version_pkg', vcs='git'): py_modules=['{name}'], entry_points=dict(console_scripts=['{name}={name}:main']) ) - """.format(name=name))) + """.format( + name=name + ) + ) + ) return _vcs_add(script, version_pkg_path, vcs) def _create_svn_repo(script, version_pkg_path): - repo_url = path_to_url( - script.scratch_path / 'pip-test-package-repo' / 'trunk') + repo_url = path_to_url(script.scratch_path / "pip-test-package-repo" / "trunk") + script.run("svnadmin", "create", "pip-test-package-repo", cwd=script.scratch_path) script.run( - 'svnadmin', 'create', 'pip-test-package-repo', - cwd=script.scratch_path - ) - script.run( - 'svn', 'import', version_pkg_path, repo_url, - '-m', 'Initial import of pip-test-package', - cwd=script.scratch_path + "svn", + "import", + version_pkg_path, + repo_url, + "-m", + "Initial import of pip-test-package", + cwd=script.scratch_path, ) return repo_url def _change_test_package_version(script, version_pkg_path): _create_main_file( - version_pkg_path, name='version_pkg', output='some different version' + version_pkg_path, name="version_pkg", output="some different version" ) # Pass -a to stage the change to the main file. - _git_commit( - script, version_pkg_path, message='messed version', stage_modified=True - ) + _git_commit(script, version_pkg_path, message="messed version", stage_modified=True) def assert_raises_regexp(exception, reg, run, *args, **kwargs): @@ -950,21 +1014,25 @@ def requirements_file(contents, tmpdir): :param tmpdir: A Path to the folder in which to create the file """ - path = tmpdir / 'reqs.txt' + path = tmpdir / "reqs.txt" path.write_text(contents) yield path path.unlink() def create_test_package_with_setup(script, **setup_kwargs): - assert 'name' in setup_kwargs, setup_kwargs - pkg_path = script.scratch_path / setup_kwargs['name'] + assert "name" in setup_kwargs, setup_kwargs + pkg_path = script.scratch_path / setup_kwargs["name"] pkg_path.mkdir() - pkg_path.joinpath("setup.py").write_text(textwrap.dedent(""" + pkg_path.joinpath("setup.py").write_text( + textwrap.dedent( + """ from setuptools import setup kwargs = {setup_kwargs!r} setup(**kwargs) - """).format(**locals())) + """ + ).format(**locals()) + ) return pkg_path @@ -976,9 +1044,7 @@ def urlsafe_b64encode_nopad(data): def create_really_basic_wheel(name, version): # type: (str, str) -> bytes def digest(contents): - return "sha256={}".format( - urlsafe_b64encode_nopad(sha256(contents).digest()) - ) + return "sha256={}".format(urlsafe_b64encode_nopad(sha256(contents).digest())) def add_file(path, text): contents = text.encode("utf-8") @@ -998,7 +1064,9 @@ def add_file(path, text): Metadata-Version: 2.1 Name: {} Version: {} - """.format(name, version) + """.format( + name, version + ) ), ) z.writestr(record_path, "\n".join(",".join(r) for r in records)) @@ -1058,7 +1126,6 @@ def hello(): metadata_updates=metadata_updates, extra_metadata_files={"top_level.txt": name}, extra_files=extra_files, - # Have an empty RECORD because we don't want to be checking hashes. record="", ) @@ -1067,9 +1134,7 @@ def hello(): return archive_path -def create_basic_sdist_for_package( - script, name, version, extra_files=None -): +def create_basic_sdist_for_package(script, name, version, extra_files=None): files = { "setup.py": """ from setuptools import find_packages, setup @@ -1078,17 +1143,13 @@ def create_basic_sdist_for_package( } # Some useful shorthands - archive_name = "{name}-{version}.tar.gz".format( - name=name, version=version - ) + archive_name = "{name}-{version}.tar.gz".format(name=name, version=version) # Replace key-values with formatted values for key, value in list(files.items()): del files[key] key = key.format(name=name) - files[key] = textwrap.dedent(value).format( - name=name, version=version - ).strip() + files[key] = textwrap.dedent(value).format(name=name, version=version).strip() # Add new files after formatting if extra_files: @@ -1105,7 +1166,7 @@ def create_basic_sdist_for_package( retval = script.scratch_path / archive_name generated = shutil.make_archive( retval, - 'gztar', + "gztar", root_dir=script.temp_path, base_dir=text_type(os.curdir), ) @@ -1122,15 +1183,17 @@ def wrapper(fn): try: subprocess.check_output(check_cmd) except (OSError, subprocess.CalledProcessError): - return pytest.mark.skip( - reason='{name} is not available'.format(name=name))(fn) + return pytest.mark.skip(reason="{name} is not available".format(name=name))( + fn + ) return fn + return wrapper def is_bzr_installed(): try: - subprocess.check_output(('bzr', 'version', '--short')) + subprocess.check_output(("bzr", "version", "--short")) except OSError: return False return True @@ -1138,30 +1201,26 @@ def is_bzr_installed(): def is_svn_installed(): try: - subprocess.check_output(('svn', '--version')) + subprocess.check_output(("svn", "--version")) except OSError: return False return True def need_bzr(fn): - return pytest.mark.bzr(need_executable( - 'Bazaar', ('bzr', 'version', '--short') - )(fn)) + return pytest.mark.bzr(need_executable("Bazaar", ("bzr", "version", "--short"))(fn)) def need_svn(fn): - return pytest.mark.svn(need_executable( - 'Subversion', ('svn', '--version') - )(need_executable( - 'Subversion Admin', ('svnadmin', '--version') - )(fn))) + return pytest.mark.svn( + need_executable("Subversion", ("svn", "--version"))( + need_executable("Subversion Admin", ("svnadmin", "--version"))(fn) + ) + ) def need_mercurial(fn): - return pytest.mark.mercurial(need_executable( - 'Mercurial', ('hg', 'version') - )(fn)) + return pytest.mark.mercurial(need_executable("Mercurial", ("hg", "version"))(fn)) skip_if_python2 = pytest.mark.skipif(PY2, reason="Non-Python 2 only") diff --git a/tests/lib/certs.py b/tests/lib/certs.py index 7d86ee4c04e..a1c82c2cc49 100644 --- a/tests/lib/certs.py +++ b/tests/lib/certs.py @@ -15,13 +15,13 @@ def make_tls_cert(hostname): # type: (Text) -> Tuple[x509.Certificate, rsa.RSAPrivateKey] key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - backend=default_backend() + public_exponent=65537, key_size=2048, backend=default_backend() + ) + subject = issuer = x509.Name( + [ + x509.NameAttribute(NameOID.COMMON_NAME, hostname), + ] ) - subject = issuer = x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, hostname), - ]) cert = ( x509.CertificateBuilder() .subject_name(subject) diff --git a/tests/lib/configuration_helpers.py b/tests/lib/configuration_helpers.py index 3e3692696a8..a4f7c051cdc 100644 --- a/tests/lib/configuration_helpers.py +++ b/tests/lib/configuration_helpers.py @@ -15,7 +15,6 @@ class ConfigurationMixin(object): - def setup(self): self.configuration = pip._internal.configuration.Configuration( isolated=False, @@ -41,9 +40,7 @@ def overridden(): @contextlib.contextmanager def tmpfile(self, contents): # Create a temporary file - fd, path = tempfile.mkstemp( - prefix="pip_", suffix="_config.ini", text=True - ) + fd, path = tempfile.mkstemp(prefix="pip_", suffix="_config.ini", text=True) os.close(fd) contents = textwrap.dedent(contents).lstrip() diff --git a/tests/lib/filesystem.py b/tests/lib/filesystem.py index dc14b323e33..05e2db62cfd 100644 --- a/tests/lib/filesystem.py +++ b/tests/lib/filesystem.py @@ -43,6 +43,4 @@ def join(dirpath, dirnames, filenames): (join_dirpath(p) for p in filenames), ) - return set(chain.from_iterable( - join(*dirinfo) for dirinfo in os.walk(base) - )) + return set(chain.from_iterable(join(*dirinfo) for dirinfo in os.walk(base))) diff --git a/tests/lib/git_submodule_helpers.py b/tests/lib/git_submodule_helpers.py index 34295a05dc9..6a4d2822fec 100644 --- a/tests/lib/git_submodule_helpers.py +++ b/tests/lib/git_submodule_helpers.py @@ -7,11 +7,11 @@ def _create_test_package_submodule(env): env.scratch_path.joinpath("version_pkg_submodule").mkdir() - submodule_path = env.scratch_path / 'version_pkg_submodule' - env.run('touch', 'testfile', cwd=submodule_path) - env.run('git', 'init', cwd=submodule_path) - env.run('git', 'add', '.', cwd=submodule_path) - _git_commit(env, submodule_path, message='initial version / submodule') + submodule_path = env.scratch_path / "version_pkg_submodule" + env.run("touch", "testfile", cwd=submodule_path) + env.run("git", "init", cwd=submodule_path) + env.run("git", "add", ".", cwd=submodule_path) + _git_commit(env, submodule_path, message="initial version / submodule") return submodule_path @@ -19,8 +19,8 @@ def _create_test_package_submodule(env): def _change_test_package_submodule(env, submodule_path): submodule_path.joinpath("testfile").write_text("this is a changed file") submodule_path.joinpath("testfile2").write_text("this is an added file") - env.run('git', 'add', '.', cwd=submodule_path) - _git_commit(env, submodule_path, message='submodule change') + env.run("git", "add", ".", cwd=submodule_path) + _git_commit(env, submodule_path, message="submodule change") def _pull_in_submodule_changes_to_module(env, module_path, rel_path): @@ -29,11 +29,9 @@ def _pull_in_submodule_changes_to_module(env, module_path, rel_path): rel_path: the location of the submodule relative to the superproject. """ submodule_path = module_path / rel_path - env.run('git', 'pull', '-q', 'origin', 'master', cwd=submodule_path) + env.run("git", "pull", "-q", "origin", "master", cwd=submodule_path) # Pass -a to stage the submodule changes that were just pulled in. - _git_commit( - env, module_path, message='submodule change', stage_modified=True - ) + _git_commit(env, module_path, message="submodule change", stage_modified=True) def _create_test_package_with_submodule(env, rel_path): @@ -42,33 +40,37 @@ def _create_test_package_with_submodule(env, rel_path): rel_path: the location of the submodule relative to the superproject. """ env.scratch_path.joinpath("version_pkg").mkdir() - version_pkg_path = env.scratch_path / 'version_pkg' + version_pkg_path = env.scratch_path / "version_pkg" version_pkg_path.joinpath("testpkg").mkdir() - pkg_path = version_pkg_path / 'testpkg' + pkg_path = version_pkg_path / "testpkg" pkg_path.joinpath("__init__.py").write_text("# hello there") _create_main_file(pkg_path, name="version_pkg", output="0.1") - version_pkg_path.joinpath("setup.py").write_text(textwrap.dedent('''\ + version_pkg_path.joinpath("setup.py").write_text( + textwrap.dedent( + """\ from setuptools import setup, find_packages setup(name='version_pkg', version='0.1', packages=find_packages(), ) - ''')) - env.run('git', 'init', cwd=version_pkg_path) - env.run('git', 'add', '.', cwd=version_pkg_path) - _git_commit(env, version_pkg_path, message='initial version') + """ + ) + ) + env.run("git", "init", cwd=version_pkg_path) + env.run("git", "add", ".", cwd=version_pkg_path) + _git_commit(env, version_pkg_path, message="initial version") submodule_path = _create_test_package_submodule(env) env.run( - 'git', - 'submodule', - 'add', + "git", + "submodule", + "add", submodule_path, rel_path, cwd=version_pkg_path, ) - _git_commit(env, version_pkg_path, message='initial version w submodule') + _git_commit(env, version_pkg_path, message="initial version w submodule") return version_pkg_path, submodule_path diff --git a/tests/lib/index.py b/tests/lib/index.py index 0f507a0e7ff..b0877c9e61d 100644 --- a/tests/lib/index.py +++ b/tests/lib/index.py @@ -3,12 +3,12 @@ def make_mock_candidate(version, yanked_reason=None, hex_digest=None): - url = 'https://example.com/pkg-{}.tar.gz'.format(version) + url = "https://example.com/pkg-{}.tar.gz".format(version) if hex_digest is not None: assert len(hex_digest) == 64 - url += '#sha256={}'.format(hex_digest) + url += "#sha256={}".format(hex_digest) link = Link(url, yanked_reason=yanked_reason) - candidate = InstallationCandidate('mypackage', version, link) + candidate = InstallationCandidate("mypackage", version, link) return candidate diff --git a/tests/lib/local_repos.py b/tests/lib/local_repos.py index 2a41595f9f2..c95bc3a7ebc 100644 --- a/tests/lib/local_repos.py +++ b/tests/lib/local_repos.py @@ -19,16 +19,16 @@ def _create_svn_initools_repo(initools_dir): Create the SVN INITools repo. """ directory = os.path.dirname(initools_dir) - subprocess.check_call('svnadmin create INITools'.split(), cwd=directory) + subprocess.check_call("svnadmin create INITools".split(), cwd=directory) filename, _ = urllib_request.urlretrieve( - 'http://bitbucket.org/hltbra/pip-initools-dump/raw/8b55c908a320/' - 'INITools_modified.dump' + "http://bitbucket.org/hltbra/pip-initools-dump/raw/8b55c908a320/" + "INITools_modified.dump" ) - devnull = open(os.devnull, 'w') + devnull = open(os.devnull, "w") dump = open(filename) subprocess.check_call( - ['svnadmin', 'load', initools_dir], + ["svnadmin", "load", initools_dir], stdin=dump, stdout=devnull, ) @@ -39,7 +39,7 @@ def _create_svn_initools_repo(initools_dir): def local_checkout( remote_repo, # type: str - temp_path, # type: Path + temp_path, # type: Path ): # type: (...) -> str """ @@ -47,27 +47,27 @@ def local_checkout( temp directory Path object unique to each test function invocation, created as a sub directory of the base temp directory. """ - assert '+' in remote_repo - vcs_name = remote_repo.split('+', 1)[0] + assert "+" in remote_repo + vcs_name = remote_repo.split("+", 1)[0] repository_name = os.path.basename(remote_repo) - directory = temp_path.joinpath('cache') + directory = temp_path.joinpath("cache") repo_url_path = os.path.join(directory, repository_name) assert not os.path.exists(repo_url_path) if not os.path.exists(directory): os.mkdir(directory) - if vcs_name == 'svn': - assert repository_name == 'INITools' + if vcs_name == "svn": + assert repository_name == "INITools" _create_svn_initools_repo(repo_url_path) - repo_url_path = os.path.join(repo_url_path, 'trunk') + repo_url_path = os.path.join(repo_url_path, "trunk") else: vcs_backend = vcs.get_backend(vcs_name) vcs_backend.obtain(repo_url_path, url=hide_url(remote_repo)) - return '{}+{}'.format(vcs_name, path_to_url(repo_url_path)) + return "{}+{}".format(vcs_name, path_to_url(repo_url_path)) def local_repo(remote_repo, temp_path): - return local_checkout(remote_repo, temp_path).split('+', 1)[1] + return local_checkout(remote_repo, temp_path).split("+", 1)[1] diff --git a/tests/lib/options_helpers.py b/tests/lib/options_helpers.py index 2354a818df8..a0525c0b3e6 100644 --- a/tests/lib/options_helpers.py +++ b/tests/lib/options_helpers.py @@ -7,7 +7,6 @@ class FakeCommand(Command): - def main(self, args): index_opts = cmdoptions.make_option_group( cmdoptions.index_group, @@ -18,11 +17,12 @@ def main(self, args): class AddFakeCommandMixin(object): - def setup(self): - commands_dict['fake'] = CommandInfo( - 'tests.lib.options_helpers', 'FakeCommand', 'fake summary', + commands_dict["fake"] = CommandInfo( + "tests.lib.options_helpers", + "FakeCommand", + "fake summary", ) def teardown(self): - commands_dict.pop('fake') + commands_dict.pop("fake") diff --git a/tests/lib/path.py b/tests/lib/path.py index d1ea6bc5e8d..6cb45081daf 100644 --- a/tests/lib/path.py +++ b/tests/lib/path.py @@ -15,7 +15,6 @@ supports_fd = set() - _base = six.text_type if os.path.supports_unicode_filenames else str @@ -170,7 +169,7 @@ def joinpath(self, *parts): # TODO: Remove after removing inheritance from str. def join(self, *parts): - raise RuntimeError('Path.join is invalid, use joinpath instead.') + raise RuntimeError("Path.join is invalid, use joinpath instead.") def read_bytes(self): # type: () -> bytes @@ -201,4 +200,5 @@ def symlink_to(self, target): def stat(self): return os.stat(self) + curdir = Path(os.path.curdir) diff --git a/tests/lib/requests_mocks.py b/tests/lib/requests_mocks.py index e8e3e9c886e..cb90dddcc68 100644 --- a/tests/lib/requests_mocks.py +++ b/tests/lib/requests_mocks.py @@ -5,7 +5,6 @@ class FakeStream(object): - def __init__(self, contents): self._io = BytesIO(contents) @@ -20,7 +19,6 @@ def release_conn(self): class MockResponse(object): - def __init__(self, contents): self.raw = FakeStream(contents) self.content = contents @@ -29,12 +27,11 @@ def __init__(self, contents): self.status_code = 200 self.connection = None self.url = None - self.headers = {'Content-Length': len(contents)} + self.headers = {"Content-Length": len(contents)} self.history = [] class MockConnection(object): - def _send(self, req, **kwargs): raise NotImplementedError("_send must be overridden for tests") @@ -46,7 +43,6 @@ def send(self, req, **kwargs): class MockRequest(object): - def __init__(self, url): self.url = url self.headers = {} diff --git a/tests/lib/server.py b/tests/lib/server.py index ebbf120d3d7..a63cc8b37c0 100644 --- a/tests/lib/server.py +++ b/tests/lib/server.py @@ -41,16 +41,17 @@ class MockServer(BaseWSGIServer): mock = Mock() # type: Mock + # Applies on Python 2 and Windows. if not hasattr(signal, "pthread_sigmask"): # We're not relying on this behavior anywhere currently, it's just best # practice. blocked_signals = nullcontext else: + @contextmanager def blocked_signals(): - """Block all signals for e.g. starting a worker thread. - """ + """Block all signals for e.g. starting a worker thread.""" # valid_signals() was added in Python 3.8 (and not using it results # in a warning on pthread_sigmask() call) try: @@ -95,6 +96,7 @@ def _mock_wsgi_adapter(mock): """Uses a mock to record function arguments and provide the actual function that should respond. """ + def adapter(environ, start_response): # type: (Environ, StartResponse) -> Body responder = mock(environ, start_response) @@ -146,8 +148,7 @@ def make_mock_server(**kwargs): @contextmanager def server_running(server): # type: (BaseWSGIServer) -> None - """Context manager for running the provided server in a separate thread. - """ + """Context manager for running the provided server in a separate thread.""" thread = threading.Thread(target=server.serve_forever) thread.daemon = True with blocked_signals(): @@ -166,45 +167,50 @@ def text_html_response(text): # type: (Text) -> Responder def responder(environ, start_response): # type: (Environ, StartResponse) -> Body - start_response("200 OK", [ - ("Content-Type", "text/html; charset=UTF-8"), - ]) - return [text.encode('utf-8')] + start_response( + "200 OK", + [ + ("Content-Type", "text/html; charset=UTF-8"), + ], + ) + return [text.encode("utf-8")] return responder def html5_page(text): # type: (Union[Text, str]) -> Text - return dedent(u""" + return ( + dedent( + u""" {} - """).strip().format(text) + """ + ) + .strip() + .format(text) + ) def index_page(spec): # type: (Dict[str, str]) -> Responder def link(name, value): - return '{}'.format( - value, name - ) + return '{}'.format(value, name) - links = ''.join(link(*kv) for kv in spec.items()) + links = "".join(link(*kv) for kv in spec.items()) return text_html_response(html5_page(links)) def package_page(spec): # type: (Dict[str, str]) -> Responder def link(name, value): - return '{}'.format( - value, name - ) + return '{}'.format(value, name) - links = ''.join(link(*kv) for kv in spec.items()) + links = "".join(link(*kv) for kv in spec.items()) return text_html_response(html5_page(links)) @@ -214,13 +220,14 @@ def responder(environ, start_response): # type: (Environ, StartResponse) -> Body size = os.stat(path).st_size start_response( - "200 OK", [ + "200 OK", + [ ("Content-Type", "application/octet-stream"), ("Content-Length", str(size)), ], ) - with open(path, 'rb') as f: + with open(path, "rb") as f: return [f.read()] return responder @@ -231,12 +238,13 @@ def responder(environ, start_response): # type: (Environ, StartResponse) -> Body start_response( - "401 Unauthorized", [ + "401 Unauthorized", + [ ("WWW-Authenticate", "Basic"), ], ) - with open(path, 'rb') as f: + with open(path, "rb") as f: return [f.read()] return responder diff --git a/tests/lib/test_lib.py b/tests/lib/test_lib.py index 9c00e9d1f0c..f647c1e6fe7 100644 --- a/tests/lib/test_lib.py +++ b/tests/lib/test_lib.py @@ -20,8 +20,8 @@ def assert_error_startswith(exc_type, expected_start): with pytest.raises(exc_type) as err: yield - assert str(err.value).startswith(expected_start), ( - 'full message: {}'.format(err.value) + assert str(err.value).startswith(expected_start), "full message: {}".format( + err.value ) @@ -33,7 +33,7 @@ def test_tmp_dir_exists_in_env(script): # need these tests to ensure the assert_no_temp feature of scripttest is # working script.assert_no_temp() # this fails if env.tmp_path doesn't exist - assert script.environ['TMPDIR'] == script.temp_path + assert script.environ["TMPDIR"] == script.temp_path assert isdir(script.temp_path) @@ -43,16 +43,16 @@ def test_correct_pip_version(script): """ # output is like: # pip PIPVERSION from PIPDIRECTORY (python PYVERSION) - result = script.pip('--version') + result = script.pip("--version") # compare the directory tree of the invoked pip with that of this source # distribution pip_folder_outputed = re.match( - r'pip \d+(\.[\d]+)+(\.?(b|rc|dev|pre|post)\d+)? from (.*) ' - r'\(python \d(.[\d])+\)$', - result.stdout + r"pip \d+(\.[\d]+)+(\.?(b|rc|dev|pre|post)\d+)? from (.*) " + r"\(python \d(.[\d])+\)$", + result.stdout, ).group(4) - pip_folder = join(SRC_DIR, 'src', 'pip') + pip_folder = join(SRC_DIR, "src", "pip") diffs = filecmp.dircmp(pip_folder, pip_folder_outputed) @@ -61,32 +61,33 @@ def test_correct_pip_version(script): # primary resources other than .py files, this code will need # maintenance mismatch_py = [ - x for x in diffs.left_only + diffs.right_only + diffs.diff_files - if x.endswith('.py') + x + for x in diffs.left_only + diffs.right_only + diffs.diff_files + if x.endswith(".py") ] assert not mismatch_py, ( - 'mismatched source files in {pip_folder!r} ' - 'and {pip_folder_outputed!r}: {mismatch_py!r}'.format(**locals()) + "mismatched source files in {pip_folder!r} " + "and {pip_folder_outputed!r}: {mismatch_py!r}".format(**locals()) ) def test_as_import(script): - """ test that pip.__init__.py does not shadow + """test that pip.__init__.py does not shadow the command submodule with a dictionary """ import pip._internal.commands.install as inst + assert inst is not None class TestPipTestEnvironment: - def run_stderr_with_prefix(self, script, prefix, **kwargs): """ Call run() that prints stderr with the given prefix. """ - text = '{}: hello, world\\n'.format(prefix) + text = "{}: hello, world\\n".format(prefix) command = 'import sys; sys.stderr.write("{}")'.format(text) - args = [sys.executable, '-c', command] + args = [sys.executable, "-c", command] script.run(*args, **kwargs) def run_with_log_command(self, script, sub_string, **kwargs): @@ -98,14 +99,17 @@ def run_with_log_command(self, script, sub_string, **kwargs): "import logging; logging.basicConfig(level='INFO'); " "logging.getLogger().info('sub: {}', 'foo')" ).format(sub_string) - args = [sys.executable, '-c', command] + args = [sys.executable, "-c", command] script.run(*args, **kwargs) - @pytest.mark.parametrize('prefix', ( - 'DEBUG', - 'INFO', - 'FOO', - )) + @pytest.mark.parametrize( + "prefix", + ( + "DEBUG", + "INFO", + "FOO", + ), + ) def test_run__allowed_stderr(self, script, prefix): """ Test calling run() with allowed stderr. @@ -119,21 +123,28 @@ def test_run__allow_stderr_warning(self, script): """ # Check that no error happens. self.run_stderr_with_prefix( - script, 'WARNING', allow_stderr_warning=True, + script, + "WARNING", + allow_stderr_warning=True, ) # Check that an error still happens with ERROR. - expected_start = 'stderr has an unexpected error' + expected_start = "stderr has an unexpected error" with assert_error_startswith(RuntimeError, expected_start): self.run_stderr_with_prefix( - script, 'ERROR', allow_stderr_warning=True, + script, + "ERROR", + allow_stderr_warning=True, ) - @pytest.mark.parametrize('prefix', ( - 'DEPRECATION', - 'WARNING', - 'ERROR', - )) + @pytest.mark.parametrize( + "prefix", + ( + "DEPRECATION", + "WARNING", + "ERROR", + ), + ) def test_run__allow_stderr_error(self, script, prefix): """ Test passing allow_stderr_error=True. @@ -141,11 +152,14 @@ def test_run__allow_stderr_error(self, script, prefix): # Check that no error happens. self.run_stderr_with_prefix(script, prefix, allow_stderr_error=True) - @pytest.mark.parametrize('prefix, expected_start', ( - ('DEPRECATION', 'stderr has an unexpected warning'), - ('WARNING', 'stderr has an unexpected warning'), - ('ERROR', 'stderr has an unexpected error'), - )) + @pytest.mark.parametrize( + "prefix, expected_start", + ( + ("DEPRECATION", "stderr has an unexpected warning"), + ("WARNING", "stderr has an unexpected warning"), + ("ERROR", "stderr has an unexpected error"), + ), + ) def test_run__unexpected_stderr(self, script, prefix, expected_start): """ Test calling run() with unexpected stderr output. @@ -158,70 +172,72 @@ def test_run__logging_error(self, script): Test calling run() with an unexpected logging error. """ # Pass a good substitution string. - self.run_with_log_command(script, sub_string='%r') + self.run_with_log_command(script, sub_string="%r") - expected_start = 'stderr has a logging error, which is never allowed' + expected_start = "stderr has a logging error, which is never allowed" with assert_error_startswith(RuntimeError, expected_start): # Pass a bad substitution string. Also, pass # allow_stderr_error=True to check that the RuntimeError occurs # even under the stricter test condition of when we are allowing # other types of errors. self.run_with_log_command( - script, sub_string='{!r}', allow_stderr_error=True, + script, + sub_string="{!r}", + allow_stderr_error=True, ) def test_run__allow_stderr_error_false_error_with_expect_error( - self, script, + self, + script, ): """ Test passing allow_stderr_error=False with expect_error=True. """ - expected_start = ( - 'cannot pass allow_stderr_error=False with expect_error=True' - ) + expected_start = "cannot pass allow_stderr_error=False with expect_error=True" with assert_error_startswith(RuntimeError, expected_start): - script.run('python', allow_stderr_error=False, expect_error=True) + script.run("python", allow_stderr_error=False, expect_error=True) def test_run__allow_stderr_warning_false_error_with_expect_stderr( - self, script, + self, + script, ): """ Test passing allow_stderr_warning=False with expect_stderr=True. """ expected_start = ( - 'cannot pass allow_stderr_warning=False with expect_stderr=True' + "cannot pass allow_stderr_warning=False with expect_stderr=True" ) with assert_error_startswith(RuntimeError, expected_start): script.run( - 'python', allow_stderr_warning=False, expect_stderr=True, + "python", + allow_stderr_warning=False, + expect_stderr=True, ) - @pytest.mark.parametrize('arg_name', ( - 'expect_error', - 'allow_stderr_error', - )) + @pytest.mark.parametrize( + "arg_name", + ( + "expect_error", + "allow_stderr_error", + ), + ) def test_run__allow_stderr_warning_false_error(self, script, arg_name): """ Test passing allow_stderr_warning=False when it is not allowed. """ - kwargs = {'allow_stderr_warning': False, arg_name: True} + kwargs = {"allow_stderr_warning": False, arg_name: True} expected_start = ( - 'cannot pass allow_stderr_warning=False with ' - 'allow_stderr_error=True' + "cannot pass allow_stderr_warning=False with " "allow_stderr_error=True" ) with assert_error_startswith(RuntimeError, expected_start): - script.run('python', **kwargs) + script.run("python", **kwargs) def test_run__expect_error_fails_when_zero_returncode(self, script): - expected_start = 'Script passed unexpectedly' + expected_start = "Script passed unexpectedly" with assert_error_startswith(AssertionError, expected_start): - script.run( - 'python', expect_error=True - ) + script.run("python", expect_error=True) def test_run__no_expect_error_fails_when_nonzero_returncode(self, script): - expected_start = 'Script returned code: 1' + expected_start = "Script returned code: 1" with assert_error_startswith(AssertionError, expected_start): - script.run( - 'python', '-c', 'import sys; sys.exit(1)' - ) + script.run("python", "-c", "import sys; sys.exit(1)") diff --git a/tests/lib/test_wheel.py b/tests/lib/test_wheel.py index a6f46cd899c..cab2788262d 100644 --- a/tests/lib/test_wheel.py +++ b/tests/lib/test_wheel.py @@ -166,19 +166,20 @@ def test_make_wheel_default_record(): record_bytes = z.read("simple-0.1.0.dist-info/RECORD") record_text = ensure_text(record_bytes) record_rows = list(csv.reader(record_text.splitlines())) - records = { - row[0]: row[1:] for row in record_rows - } + records = {row[0]: row[1:] for row in record_rows} expected = { "simple/__init__.py": [ - "sha256=ypeBEsobvcr6wjGzmiPcTaeG7_gUfE5yuYB3ha_uSLs", "1" + "sha256=ypeBEsobvcr6wjGzmiPcTaeG7_gUfE5yuYB3ha_uSLs", + "1", ], "simple-0.1.0.data/purelib/info.txt": [ - "sha256=Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y", "1" + "sha256=Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y", + "1", ], "simple-0.1.0.dist-info/LICENSE": [ - "sha256=PiPoFgA5WUoziU9lZOGxNIu9egCI1CxKy3PurtWcAJ0", "1" + "sha256=PiPoFgA5WUoziU9lZOGxNIu9egCI1CxKy3PurtWcAJ0", + "1", ], "simple-0.1.0.dist-info/RECORD": ["", ""], } diff --git a/tests/lib/venv.py b/tests/lib/venv.py index cc94e29f254..2e702b2c4bc 100644 --- a/tests/lib/venv.py +++ b/tests/lib/venv.py @@ -22,9 +22,9 @@ class VirtualEnvironment(object): def __init__(self, location, template=None, venv_type=None): assert template is None or venv_type is None - assert venv_type in (None, 'virtualenv', 'venv') + assert venv_type in (None, "virtualenv", "venv") self.location = Path(location) - self._venv_type = venv_type or template._venv_type or 'virtualenv' + self._venv_type = venv_type or template._venv_type or "virtualenv" self._user_site_packages = False self._template = template self._sitecustomize = None @@ -34,12 +34,12 @@ def __init__(self, location, template=None, venv_type=None): def _update_paths(self): home, lib, inc, bin = _virtualenv.path_locations(self.location) self.bin = Path(bin) - self.site = Path(lib) / 'site-packages' + self.site = Path(lib) / "site-packages" # Workaround for https://github.com/pypa/virtualenv/issues/306 if hasattr(sys, "pypy_version_info"): - version_fmt = '{0}' if six.PY3 else '{0}.{1}' + version_fmt = "{0}" if six.PY3 else "{0}.{1}" version_dir = version_fmt.format(*sys.version_info) - self.lib = Path(home, 'lib-python', version_dir) + self.lib = Path(home, "lib-python", version_dir) else: self.lib = Path(lib) @@ -52,17 +52,15 @@ def _create(self, clear=False): if self._template: # On Windows, calling `_virtualenv.path_locations(target)` # will have created the `target` directory... - if sys.platform == 'win32' and self.location.exists(): + if sys.platform == "win32" and self.location.exists(): self.location.rmdir() # Clone virtual environment from template. - shutil.copytree( - self._template.location, self.location, symlinks=True - ) + shutil.copytree(self._template.location, self.location, symlinks=True) self._sitecustomize = self._template.sitecustomize self._user_site_packages = self._template.user_site_packages else: # Create a new virtual environment. - if self._venv_type == 'virtualenv': + if self._venv_type == "virtualenv": _virtualenv.create_environment( self.location, no_pip=True, @@ -70,7 +68,7 @@ def _create(self, clear=False): no_setuptools=True, ) self._fix_virtualenv_site_module() - elif self._venv_type == 'venv': + elif self._venv_type == "venv": builder = _venv.EnvBuilder() context = builder.ensure_directories(self.location) builder.create_configuration(context) @@ -81,46 +79,44 @@ def _create(self, clear=False): def _fix_virtualenv_site_module(self): # Patch `site.py` so user site work as expected. - site_py = self.lib / 'site.py' + site_py = self.lib / "site.py" with open(site_py) as fp: site_contents = fp.read() for pattern, replace in ( ( # Ensure enabling user site does not result in adding # the real site-packages' directory to `sys.path`. + ("\ndef virtual_addsitepackages(known_paths):\n"), ( - '\ndef virtual_addsitepackages(known_paths):\n' - ), - ( - '\ndef virtual_addsitepackages(known_paths):\n' - ' return known_paths\n' + "\ndef virtual_addsitepackages(known_paths):\n" + " return known_paths\n" ), ), ( # Fix sites ordering: user site must be added before system. ( - '\n paths_in_sys = addsitepackages(paths_in_sys)' - '\n paths_in_sys = addusersitepackages(paths_in_sys)\n' + "\n paths_in_sys = addsitepackages(paths_in_sys)" + "\n paths_in_sys = addusersitepackages(paths_in_sys)\n" ), ( - '\n paths_in_sys = addusersitepackages(paths_in_sys)' - '\n paths_in_sys = addsitepackages(paths_in_sys)\n' + "\n paths_in_sys = addusersitepackages(paths_in_sys)" + "\n paths_in_sys = addsitepackages(paths_in_sys)\n" ), ), ): assert pattern in site_contents site_contents = site_contents.replace(pattern, replace) - with open(site_py, 'w') as fp: + with open(site_py, "w") as fp: fp.write(site_contents) # Make sure bytecode is up-to-date too. assert compileall.compile_file(str(site_py), quiet=1, force=True) def _customize_site(self): - contents = '' - if self._venv_type == 'venv': + contents = "" + if self._venv_type == "venv": # Enable user site (before system). contents += textwrap.dedent( - ''' + """ import os, site, sys if not os.environ.get('PYTHONNOUSERSITE', False): @@ -144,9 +140,10 @@ def _customize_site(self): # Third, add back system-sites related paths. for path in site.getsitepackages(): site.addsitedir(path) - ''').strip() + """ + ).strip() if self._sitecustomize is not None: - contents += '\n' + self._sitecustomize + contents += "\n" + self._sitecustomize sitecustomize = self.site / "sitecustomize.py" sitecustomize.write_text(contents) # Make sure bytecode is up-to-date too. @@ -176,11 +173,11 @@ def user_site_packages(self): @user_site_packages.setter def user_site_packages(self, value): self._user_site_packages = value - if self._venv_type == 'virtualenv': + if self._venv_type == "virtualenv": marker = self.lib / "no-global-site-packages.txt" if self._user_site_packages: marker.unlink() else: marker.touch() - elif self._venv_type == 'venv': + elif self._venv_type == "venv": self._customize_site() diff --git a/tests/lib/wheel.py b/tests/lib/wheel.py index d89a680a190..8af5fa8971f 100644 --- a/tests/lib/wheel.py +++ b/tests/lib/wheel.py @@ -34,9 +34,7 @@ # path, digest, size RecordLike = Tuple[str, str, str] - RecordCallback = Callable[ - [List["Record"]], Union[str, bytes, List[RecordLike]] - ] + RecordCallback = Callable[[List["Record"]], Union[str, bytes, List[RecordLike]]] # As would be used in metadata HeaderValue = Union[str, List[str]] @@ -56,8 +54,8 @@ class Default(Enum): T = TypeVar("T") class Defaulted(Union[Default, T]): - """A type which may be defaulted. - """ + """A type which may be defaulted.""" + pass @@ -98,11 +96,13 @@ def make_metadata_file( if value is not _default: return File(path, ensure_binary(value)) - metadata = CaseInsensitiveDict({ - "Metadata-Version": "2.1", - "Name": name, - "Version": version, - }) + metadata = CaseInsensitiveDict( + { + "Metadata-Version": "2.1", + "Name": name, + "Version": version, + } + ) if updates is not _default: metadata.update(updates) @@ -129,12 +129,14 @@ def make_wheel_metadata_file( if value is not _default: return File(path, ensure_binary(value)) - metadata = CaseInsensitiveDict({ - "Wheel-Version": "1.0", - "Generator": "pip-test-suite", - "Root-Is-Purelib": "true", - "Tag": ["-".join(parts) for parts in tags], - }) + metadata = CaseInsensitiveDict( + { + "Wheel-Version": "1.0", + "Generator": "pip-test-suite", + "Root-Is-Purelib": "true", + "Tag": ["-".join(parts) for parts in tags], + } + ) if updates is not _default: metadata.update(updates) @@ -173,10 +175,7 @@ def make_entry_points_file( def make_files(files): # type: (Dict[str, AnyStr]) -> List[File] - return [ - File(name, ensure_binary(contents)) - for name, contents in iteritems(files) - ] + return [File(name, ensure_binary(contents)) for name, contents in iteritems(files)] def make_metadata_files(name, version, files): @@ -204,9 +203,7 @@ def urlsafe_b64encode_nopad(data): def digest(contents): # type: (bytes) -> str - return "sha256={}".format( - urlsafe_b64encode_nopad(sha256(contents).digest()) - ) + return "sha256={}".format(urlsafe_b64encode_nopad(sha256(contents).digest())) def record_file_maker_wrapper( @@ -220,9 +217,7 @@ def record_file_maker_wrapper( records = [] # type: List[Record] for file in files: records.append( - Record( - file.name, digest(file.contents), str(len(file.contents)) - ) + Record(file.name, digest(file.contents), str(len(file.contents))) ) yield file @@ -251,19 +246,20 @@ def record_file_maker_wrapper( def wheel_name(name, version, pythons, abis, platforms): # type: (str, str, str, str, str) -> str - stem = "-".join([ - name, - version, - ".".join(pythons), - ".".join(abis), - ".".join(platforms), - ]) + stem = "-".join( + [ + name, + version, + ".".join(pythons), + ".".join(abis), + ".".join(platforms), + ] + ) return "{}.whl".format(stem) class WheelBuilder(object): - """A wheel that can be saved or converted to several formats. - """ + """A wheel that can be saved or converted to several formats.""" def __init__(self, name, files): # type: (str, List[File]) -> None @@ -391,9 +387,7 @@ def make_wheel( tags = list(itertools.product(pythons, abis, platforms)) possible_files = [ - make_metadata_file( - name, version, metadata, metadata_updates, metadata_body - ), + make_metadata_file(name, version, metadata, metadata_updates, metadata_body), make_wheel_metadata_file( name, version, wheel_metadata, tags, wheel_metadata_updates ), @@ -404,9 +398,7 @@ def make_wheel( possible_files.extend(make_files(extra_files)) if extra_metadata_files is not _default: - possible_files.extend( - make_metadata_files(name, version, extra_metadata_files) - ) + possible_files.extend(make_metadata_files(name, version, extra_metadata_files)) if extra_data_files is not _default: possible_files.extend(make_data_files(name, version, extra_data_files)) diff --git a/tests/unit/resolution_resolvelib/conftest.py b/tests/unit/resolution_resolvelib/conftest.py index 87f5d129cbd..8d2e9e7d3f7 100644 --- a/tests/unit/resolution_resolvelib/conftest.py +++ b/tests/unit/resolution_resolvelib/conftest.py @@ -4,6 +4,7 @@ from pip._internal.commands.install import InstallCommand from pip._internal.index.collector import LinkCollector from pip._internal.index.package_finder import PackageFinder + # from pip._internal.models.index import PyPI from pip._internal.models.search_scope import SearchScope from pip._internal.models.selection_prefs import SelectionPreferences @@ -40,7 +41,7 @@ def preparer(finder): req_tracker=tracker, session=session, finder=finder, - use_user_site=False + use_user_site=False, ) yield preparer diff --git a/tests/unit/resolution_resolvelib/test_requirement.py b/tests/unit/resolution_resolvelib/test_requirement.py index a03edb6f7c2..847f9f92ced 100644 --- a/tests/unit/resolution_resolvelib/test_requirement.py +++ b/tests/unit/resolution_resolvelib/test_requirement.py @@ -63,8 +63,7 @@ def test_new_resolver_correct_number_of_matches(test_cases, factory): def test_new_resolver_candidates_match_requirement(test_cases, factory): - """Candidates returned from find_candidates should satisfy the requirement - """ + """Candidates returned from find_candidates should satisfy the requirement""" for spec, _, _ in test_cases: req = factory.make_requirement_from_spec(spec, comes_from=None) for c in factory.find_candidates([req], Constraint.empty()): @@ -77,4 +76,4 @@ def test_new_resolver_full_resolve(factory, provider): req = factory.make_requirement_from_spec("simplewheel", comes_from=None) r = Resolver(provider, BaseReporter()) result = r.resolve([req]) - assert set(result.mapping.keys()) == {'simplewheel'} + assert set(result.mapping.keys()) == {"simplewheel"} diff --git a/tests/unit/resolution_resolvelib/test_resolver.py b/tests/unit/resolution_resolvelib/test_resolver.py index 0f240ec6ce4..4ebbd80a9dc 100644 --- a/tests/unit/resolution_resolvelib/test_resolver.py +++ b/tests/unit/resolution_resolvelib/test_resolver.py @@ -30,8 +30,7 @@ def resolver(preparer, finder): def _make_graph(edges): - """Build graph from edge declarations. - """ + """Build graph from edge declarations.""" graph = DirectedGraph() for parent, child in edges: diff --git a/tests/unit/test_appdirs.py b/tests/unit/test_appdirs.py index e129c0c0b83..819013f4ca8 100644 --- a/tests/unit/test_appdirs.py +++ b/tests/unit/test_appdirs.py @@ -10,7 +10,6 @@ class TestUserCacheDir: - def test_user_cache_dir_win(self, monkeypatch): @pretend.call_recorder def _get_win_folder(base): @@ -25,8 +24,10 @@ def _get_win_folder(base): monkeypatch.setattr(_appdirs, "system", "win32") monkeypatch.setattr(os, "path", ntpath) - assert (appdirs.user_cache_dir("pip") == - "C:\\Users\\test\\AppData\\Local\\pip\\Cache") + assert ( + appdirs.user_cache_dir("pip") + == "C:\\Users\\test\\AppData\\Local\\pip\\Cache" + ) assert _get_win_folder.calls == [pretend.call("CSIDL_LOCAL_APPDATA")] def test_user_cache_dir_osx(self, monkeypatch): @@ -66,7 +67,7 @@ def test_user_cache_dir_linux_home_slash(self, monkeypatch): assert appdirs.user_cache_dir("pip") == "/.cache/pip" def test_user_cache_dir_unicode(self, monkeypatch): - if sys.platform != 'win32': + if sys.platform != "win32": return def my_get_win_folder(csidl_name): @@ -77,16 +78,16 @@ def my_get_win_folder(csidl_name): # Do not use the isinstance expression directly in the # assert statement, as the Unicode characters in the result # cause pytest to fail with an internal error on Python 2.7 - result_is_str = isinstance(appdirs.user_cache_dir('test'), str) + result_is_str = isinstance(appdirs.user_cache_dir("test"), str) assert result_is_str, "user_cache_dir did not return a str" # Test against regression #3463 from pip._internal.cli.main_parser import create_main_parser + create_main_parser().print_help() # This should not crash class TestSiteConfigDirs: - def test_site_config_dirs_win(self, monkeypatch): @pretend.call_recorder def _get_win_folder(base): @@ -110,8 +111,7 @@ def test_site_config_dirs_osx(self, monkeypatch): monkeypatch.setenv("HOME", "/home/test") monkeypatch.setattr(sys, "platform", "darwin") - assert appdirs.site_config_dirs("pip") == \ - ["/Library/Application Support/pip"] + assert appdirs.site_config_dirs("pip") == ["/Library/Application Support/pip"] def test_site_config_dirs_linux(self, monkeypatch): monkeypatch.setattr(_appdirs, "system", "linux2") @@ -119,36 +119,32 @@ def test_site_config_dirs_linux(self, monkeypatch): monkeypatch.delenv("XDG_CONFIG_DIRS", raising=False) monkeypatch.setattr(sys, "platform", "linux2") - assert appdirs.site_config_dirs("pip") == [ - '/etc/xdg/pip', - '/etc' - ] + assert appdirs.site_config_dirs("pip") == ["/etc/xdg/pip", "/etc"] def test_site_config_dirs_linux_override(self, monkeypatch): monkeypatch.setattr(_appdirs, "system", "linux2") monkeypatch.setattr(os, "path", posixpath) - monkeypatch.setattr(os, "pathsep", ':') + monkeypatch.setattr(os, "pathsep", ":") monkeypatch.setenv("XDG_CONFIG_DIRS", "/spam:/etc:/etc/xdg") monkeypatch.setattr(sys, "platform", "linux2") assert appdirs.site_config_dirs("pip") == [ - '/spam/pip', - '/etc/pip', - '/etc/xdg/pip', - '/etc' + "/spam/pip", + "/etc/pip", + "/etc/xdg/pip", + "/etc", ] def test_site_config_dirs_linux_empty(self, monkeypatch): monkeypatch.setattr(_appdirs, "system", "linux2") monkeypatch.setattr(os, "path", posixpath) - monkeypatch.setattr(os, "pathsep", ':') + monkeypatch.setattr(os, "pathsep", ":") monkeypatch.setenv("XDG_CONFIG_DIRS", "") monkeypatch.setattr(sys, "platform", "linux2") - assert appdirs.site_config_dirs("pip") == ['/etc/xdg/pip', '/etc'] + assert appdirs.site_config_dirs("pip") == ["/etc/xdg/pip", "/etc"] class TestUserConfigDir: - def test_user_config_dir_win_no_roaming(self, monkeypatch): @pretend.call_recorder def _get_win_folder(base): @@ -164,8 +160,8 @@ def _get_win_folder(base): monkeypatch.setattr(os, "path", ntpath) assert ( - appdirs.user_config_dir("pip", roaming=False) == - "C:\\Users\\test\\AppData\\Local\\pip" + appdirs.user_config_dir("pip", roaming=False) + == "C:\\Users\\test\\AppData\\Local\\pip" ) assert _get_win_folder.calls == [pretend.call("CSIDL_LOCAL_APPDATA")] @@ -183,8 +179,9 @@ def _get_win_folder(base): monkeypatch.setattr(_appdirs, "system", "win32") monkeypatch.setattr(os, "path", ntpath) - assert (appdirs.user_config_dir("pip") == - "C:\\Users\\test\\AppData\\Roaming\\pip") + assert ( + appdirs.user_config_dir("pip") == "C:\\Users\\test\\AppData\\Roaming\\pip" + ) assert _get_win_folder.calls == [pretend.call("CSIDL_APPDATA")] def test_user_config_dir_osx(self, monkeypatch): @@ -193,12 +190,13 @@ def test_user_config_dir_osx(self, monkeypatch): monkeypatch.setenv("HOME", "/home/test") monkeypatch.setattr(sys, "platform", "darwin") - if os.path.isdir('/home/test/Library/Application Support/'): - assert (appdirs.user_config_dir("pip") == - "/home/test/Library/Application Support/pip") + if os.path.isdir("/home/test/Library/Application Support/"): + assert ( + appdirs.user_config_dir("pip") + == "/home/test/Library/Application Support/pip" + ) else: - assert (appdirs.user_config_dir("pip") == - "/home/test/.config/pip") + assert appdirs.user_config_dir("pip") == "/home/test/.config/pip" def test_user_config_dir_linux(self, monkeypatch): monkeypatch.setattr(_appdirs, "system", "linux2") diff --git a/tests/unit/test_base_command.py b/tests/unit/test_base_command.py index 8ba3d9e2526..0b3f10a1bab 100644 --- a/tests/unit/test_base_command.py +++ b/tests/unit/test_base_command.py @@ -13,16 +13,17 @@ @pytest.fixture def fixed_time(utc): - with patch('time.time', lambda: 1547704837.040001): + with patch("time.time", lambda: 1547704837.040001): yield class FakeCommand(Command): - _name = 'fake' + _name = "fake" def __init__(self, run_func=None, error=False): if error: + def run_func(): raise SystemExit(1) @@ -43,21 +44,19 @@ def run(self, options, args): class FakeCommandWithUnicode(FakeCommand): - _name = 'fake_unicode' + _name = "fake_unicode" def run(self, options, args): logging.getLogger("pip.tests").info(b"bytes here \xE9") - logging.getLogger("pip.tests").info( - b"unicode here \xC3\xA9".decode("utf-8") - ) + logging.getLogger("pip.tests").info(b"unicode here \xC3\xA9".decode("utf-8")) class TestCommand(object): - def call_main(self, capsys, args): """ Call command.main(), and return the command's stderr. """ + def raise_broken_stdout(): raise BrokenStdoutLoggingError() @@ -74,19 +73,19 @@ def test_raise_broken_stdout(self, capsys): """ stderr = self.call_main(capsys, []) - assert stderr.rstrip() == 'ERROR: Pipe to stdout was broken' + assert stderr.rstrip() == "ERROR: Pipe to stdout was broken" def test_raise_broken_stdout__debug_logging(self, capsys): """ Test raising BrokenStdoutLoggingError with debug logging enabled. """ - stderr = self.call_main(capsys, ['-v']) + stderr = self.call_main(capsys, ["-v"]) - assert 'ERROR: Pipe to stdout was broken' in stderr - assert 'Traceback (most recent call last):' in stderr + assert "ERROR: Pipe to stdout was broken" in stderr + assert "Traceback (most recent call last):" in stderr -@patch('pip._internal.cli.req_command.Command.handle_pip_version_check') +@patch("pip._internal.cli.req_command.Command.handle_pip_version_check") def test_handle_pip_version_check_called(mock_handle_version_check): """ Check that Command.handle_pip_version_check() is called. @@ -99,28 +98,28 @@ def test_handle_pip_version_check_called(mock_handle_version_check): def test_log_command_success(fixed_time, tmpdir): """Test the --log option logs when command succeeds.""" cmd = FakeCommand() - log_path = tmpdir.joinpath('log') - cmd.main(['fake', '--log', log_path]) + log_path = tmpdir.joinpath("log") + cmd.main(["fake", "--log", log_path]) with open(log_path) as f: - assert f.read().rstrip() == '2019-01-17T06:00:37,040 fake' + assert f.read().rstrip() == "2019-01-17T06:00:37,040 fake" def test_log_command_error(fixed_time, tmpdir): """Test the --log option logs when command fails.""" cmd = FakeCommand(error=True) - log_path = tmpdir.joinpath('log') - cmd.main(['fake', '--log', log_path]) + log_path = tmpdir.joinpath("log") + cmd.main(["fake", "--log", log_path]) with open(log_path) as f: - assert f.read().startswith('2019-01-17T06:00:37,040 fake') + assert f.read().startswith("2019-01-17T06:00:37,040 fake") def test_log_file_command_error(fixed_time, tmpdir): """Test the --log-file option logs (when there's an error).""" cmd = FakeCommand(error=True) - log_file_path = tmpdir.joinpath('log_file') - cmd.main(['fake', '--log-file', log_file_path]) + log_file_path = tmpdir.joinpath("log_file") + cmd.main(["fake", "--log-file", log_file_path]) with open(log_file_path) as f: - assert f.read().startswith('2019-01-17T06:00:37,040 fake') + assert f.read().startswith("2019-01-17T06:00:37,040 fake") def test_log_unicode_messages(fixed_time, tmpdir): @@ -128,8 +127,8 @@ def test_log_unicode_messages(fixed_time, tmpdir): don't break logging. """ cmd = FakeCommandWithUnicode() - log_path = tmpdir.joinpath('log') - cmd.main(['fake_unicode', '--log', log_path]) + log_path = tmpdir.joinpath("log") + cmd.main(["fake_unicode", "--log", log_path]) @pytest.mark.no_auto_tempdir_manager @@ -151,9 +150,7 @@ def assert_helpers_set(options, args): not_deleted = "not_deleted" -@pytest.mark.parametrize("kind,exists", [ - (not_deleted, True), ("deleted", False) -]) +@pytest.mark.parametrize("kind,exists", [(not_deleted, True), ("deleted", False)]) @pytest.mark.no_auto_tempdir_manager def test_base_command_global_tempdir_cleanup(kind, exists): assert temp_dir._tempdir_manager is None @@ -174,9 +171,7 @@ def create_temp_dirs(options, args): assert os.path.exists(Holder.value) == exists -@pytest.mark.parametrize("kind,exists", [ - (not_deleted, True), ("deleted", False) -]) +@pytest.mark.parametrize("kind,exists", [(not_deleted, True), ("deleted", False)]) @pytest.mark.no_auto_tempdir_manager def test_base_command_local_tempdir_cleanup(kind, exists): assert temp_dir._tempdir_manager is None diff --git a/tests/unit/test_build_env.py b/tests/unit/test_build_env.py index 1f3b88b4d87..fede5bcf30a 100644 --- a/tests/unit/test_build_env.py +++ b/tests/unit/test_build_env.py @@ -7,16 +7,14 @@ def indent(text, prefix): - return '\n'.join((prefix if line else '') + line - for line in text.split('\n')) + return "\n".join((prefix if line else "") + line for line in text.split("\n")) -def run_with_build_env(script, setup_script_contents, - test_script_contents=None): - build_env_script = script.scratch_path / 'build_env.py' +def run_with_build_env(script, setup_script_contents, test_script_contents=None): + build_env_script = script.scratch_path / "build_env.py" build_env_script.write_text( dedent( - ''' + """ from __future__ import print_function import subprocess import sys @@ -45,22 +43,25 @@ def run_with_build_env(script, setup_script_contents, with global_tempdir_manager(): build_env = BuildEnvironment() - '''.format(scratch=str(script.scratch_path))) + - indent(dedent(setup_script_contents), ' ') + - indent( + """.format( + scratch=str(script.scratch_path) + ) + ) + + indent(dedent(setup_script_contents), " ") + + indent( dedent( - ''' + """ if len(sys.argv) > 1: with build_env: subprocess.check_call((sys.executable, sys.argv[1])) - ''' + """ ), - ' ' + " ", ) ) - args = ['python', build_env_script] + args = ["python", build_env_script] if test_script_contents is not None: - test_script = script.scratch_path / 'test.py' + test_script = script.scratch_path / "test.py" test_script.write_text(dedent(test_script_contents)) args.append(test_script) return script.run(*args) @@ -68,41 +69,41 @@ def run_with_build_env(script, setup_script_contents, def test_build_env_allow_empty_requirements_install(): build_env = BuildEnvironment() - for prefix in ('normal', 'overlay'): + for prefix in ("normal", "overlay"): build_env.install_requirements(None, [], prefix, None) def test_build_env_allow_only_one_install(script): - create_basic_wheel_for_package(script, 'foo', '1.0') - create_basic_wheel_for_package(script, 'bar', '1.0') + create_basic_wheel_for_package(script, "foo", "1.0") + create_basic_wheel_for_package(script, "bar", "1.0") finder = make_test_finder(find_links=[script.scratch_path]) build_env = BuildEnvironment() - for prefix in ('normal', 'overlay'): + for prefix in ("normal", "overlay"): build_env.install_requirements( - finder, ['foo'], prefix, - 'installing foo in {prefix}'.format(**locals())) + finder, ["foo"], prefix, "installing foo in {prefix}".format(**locals()) + ) with pytest.raises(AssertionError): build_env.install_requirements( - finder, ['bar'], prefix, - 'installing bar in {prefix}'.format(**locals())) + finder, ["bar"], prefix, "installing bar in {prefix}".format(**locals()) + ) with pytest.raises(AssertionError): build_env.install_requirements( - finder, [], prefix, - 'installing in {prefix}'.format(**locals())) + finder, [], prefix, "installing in {prefix}".format(**locals()) + ) def test_build_env_requirements_check(script): - create_basic_wheel_for_package(script, 'foo', '2.0') - create_basic_wheel_for_package(script, 'bar', '1.0') - create_basic_wheel_for_package(script, 'bar', '3.0') - create_basic_wheel_for_package(script, 'other', '0.5') + create_basic_wheel_for_package(script, "foo", "2.0") + create_basic_wheel_for_package(script, "bar", "1.0") + create_basic_wheel_for_package(script, "bar", "3.0") + create_basic_wheel_for_package(script, "other", "0.5") - script.pip_install_local('-f', script.scratch_path, 'foo', 'bar', 'other') + script.pip_install_local("-f", script.scratch_path, "foo", "bar", "other") run_with_build_env( script, - ''' + """ r = build_env.check_requirements(['foo', 'bar', 'other']) assert r == (set(), {'foo', 'bar', 'other'}), repr(r) @@ -111,11 +112,12 @@ def test_build_env_requirements_check(script): r = build_env.check_requirements(['foo>3.0', 'bar>=2.5']) assert r == (set(), {'foo>3.0', 'bar>=2.5'}), repr(r) - ''') + """, + ) run_with_build_env( script, - ''' + """ build_env.install_requirements(finder, ['foo', 'bar==3.0'], 'normal', 'installing foo in normal') @@ -127,11 +129,12 @@ def test_build_env_requirements_check(script): r = build_env.check_requirements(['foo>3.0', 'bar>=2.5']) assert r == ({('foo==2.0', 'foo>3.0')}, set()), repr(r) - ''') + """, + ) run_with_build_env( script, - ''' + """ build_env.install_requirements(finder, ['foo', 'bar==3.0'], 'normal', 'installing foo in normal') build_env.install_requirements(finder, ['bar==1.0'], 'overlay', @@ -146,55 +149,56 @@ def test_build_env_requirements_check(script): r = build_env.check_requirements(['foo>3.0', 'bar>=2.5']) assert r == ({('bar==1.0', 'bar>=2.5'), ('foo==2.0', 'foo>3.0')}, \ set()), repr(r) - ''') + """, + ) def test_build_env_overlay_prefix_has_priority(script): - create_basic_wheel_for_package(script, 'pkg', '2.0') - create_basic_wheel_for_package(script, 'pkg', '4.3') + create_basic_wheel_for_package(script, "pkg", "2.0") + create_basic_wheel_for_package(script, "pkg", "4.3") result = run_with_build_env( script, - ''' + """ build_env.install_requirements(finder, ['pkg==2.0'], 'overlay', 'installing pkg==2.0 in overlay') build_env.install_requirements(finder, ['pkg==4.3'], 'normal', 'installing pkg==4.3 in normal') - ''', - ''' + """, + """ from __future__ import print_function print(__import__('pkg').__version__) - ''') - assert result.stdout.strip() == '2.0', str(result) + """, + ) + assert result.stdout.strip() == "2.0", str(result) @pytest.mark.incompatible_with_test_venv def test_build_env_isolation(script): # Create dummy `pkg` wheel. - pkg_whl = create_basic_wheel_for_package(script, 'pkg', '1.0') + pkg_whl = create_basic_wheel_for_package(script, "pkg", "1.0") # Install it to site packages. script.pip_install_local(pkg_whl) # And a copy in the user site. - script.pip_install_local('--ignore-installed', '--user', pkg_whl) + script.pip_install_local("--ignore-installed", "--user", pkg_whl) # And to another directory available through a .pth file. - target = script.scratch_path / 'pth_install' - script.pip_install_local('-t', target, pkg_whl) - (script.site_packages_path / 'build_requires.pth').write_text( - str(target) + '\n' - ) + target = script.scratch_path / "pth_install" + script.pip_install_local("-t", target, pkg_whl) + (script.site_packages_path / "build_requires.pth").write_text(str(target) + "\n") # And finally to yet another directory available through PYTHONPATH. - target = script.scratch_path / 'pypath_install' - script.pip_install_local('-t', target, pkg_whl) + target = script.scratch_path / "pypath_install" + script.pip_install_local("-t", target, pkg_whl) script.environ["PYTHONPATH"] = target run_with_build_env( - script, '', - r''' + script, + "", + r""" from __future__ import print_function from distutils.sysconfig import get_python_lib import sys @@ -213,4 +217,5 @@ def test_build_env_isolation(script): })), file=sys.stderr) print('sys.path:\n ' + '\n '.join(sys.path), file=sys.stderr) sys.exit(1) - ''') + """, + ) diff --git a/tests/unit/test_cache.py b/tests/unit/test_cache.py index a289fb59890..571a80a75b1 100644 --- a/tests/unit/test_cache.py +++ b/tests/unit/test_cache.py @@ -67,9 +67,7 @@ def test_get_path_for_link_legacy(tmpdir): ensure_dir(legacy_path) with open(os.path.join(legacy_path, "test-1.0.0-pyx-none-any.whl"), "w"): pass - expected_candidates = { - "test-1.0.0-pyx-none-any.whl", "test-1.0.0-pyz-none-any.whl" - } + expected_candidates = {"test-1.0.0-pyx-none-any.whl", "test-1.0.0-pyz-none-any.whl"} candidates = {c[0] for c in wc._get_candidates(link, "test")} assert candidates == expected_candidates @@ -86,9 +84,8 @@ def test_get_with_legacy_entry_only(tmpdir): with open(os.path.join(legacy_path, "test-1.0.0-py3-none-any.whl"), "w"): pass cached_link = wc.get(link, "test", [Tag("py3", "none", "any")]) - assert ( - os.path.normcase(os.path.dirname(cached_link.file_path)) == - os.path.normcase(legacy_path) + assert os.path.normcase(os.path.dirname(cached_link.file_path)) == os.path.normcase( + legacy_path ) @@ -106,10 +103,6 @@ def test_get_cache_entry(tmpdir): pass other_link = Link("https://g.c/o/r/other") supported_tags = [Tag("py3", "none", "any")] - assert ( - wc.get_cache_entry(persi_link, "persi", supported_tags).persistent - ) - assert ( - not wc.get_cache_entry(ephem_link, "ephem", supported_tags).persistent - ) + assert wc.get_cache_entry(persi_link, "persi", supported_tags).persistent + assert not wc.get_cache_entry(ephem_link, "ephem", supported_tags).persistent assert wc.get_cache_entry(other_link, "other", supported_tags) is None diff --git a/tests/unit/test_check.py b/tests/unit/test_check.py index 1d1921484ea..8cfcafa58d6 100644 --- a/tests/unit/test_check.py +++ b/tests/unit/test_check.py @@ -7,7 +7,6 @@ class TestInstalledDistributionsCall(object): - def test_passes_correct_default_kwargs(self, monkeypatch): my_mock = mock.MagicMock(return_value=[]) monkeypatch.setattr(check, "get_installed_distributions", my_mock) diff --git a/tests/unit/test_cmdoptions.py b/tests/unit/test_cmdoptions.py index 150570e716e..9bb63007d63 100644 --- a/tests/unit/test_cmdoptions.py +++ b/tests/unit/test_cmdoptions.py @@ -3,22 +3,25 @@ from pip._internal.cli.cmdoptions import _convert_python_version -@pytest.mark.parametrize('value, expected', [ - ('', (None, None)), - ('2', ((2,), None)), - ('3', ((3,), None)), - ('3.7', ((3, 7), None)), - ('3.7.3', ((3, 7, 3), None)), - # Test strings without dots of length bigger than 1. - ('34', ((3, 4), None)), - # Test a 2-digit minor version. - ('310', ((3, 10), None)), - # Test some values that fail to parse. - ('ab', ((), 'each version part must be an integer')), - ('3a', ((), 'each version part must be an integer')), - ('3.7.a', ((), 'each version part must be an integer')), - ('3.7.3.1', ((), 'at most three version parts are allowed')), -]) +@pytest.mark.parametrize( + "value, expected", + [ + ("", (None, None)), + ("2", ((2,), None)), + ("3", ((3,), None)), + ("3.7", ((3, 7), None)), + ("3.7.3", ((3, 7, 3), None)), + # Test strings without dots of length bigger than 1. + ("34", ((3, 4), None)), + # Test a 2-digit minor version. + ("310", ((3, 10), None)), + # Test some values that fail to parse. + ("ab", ((), "each version part must be an integer")), + ("3a", ((), "each version part must be an integer")), + ("3.7.a", ((), "each version part must be an integer")), + ("3.7.3.1", ((), "at most three version parts are allowed")), + ], +) def test_convert_python_version(value, expected): actual = _convert_python_version(value) - assert actual == expected, 'actual: {!r}'.format(actual) + assert actual == expected, "actual: {!r}".format(actual) diff --git a/tests/unit/test_collector.py b/tests/unit/test_collector.py index fa1057b640e..c1d2325649a 100644 --- a/tests/unit/test_collector.py +++ b/tests/unit/test_collector.py @@ -57,24 +57,29 @@ def test_get_html_response_archive_to_naive_scheme(url): ], ) @mock.patch("pip._internal.index.collector.raise_for_status") -def test_get_html_response_archive_to_http_scheme(mock_raise_for_status, url, - content_type): +def test_get_html_response_archive_to_http_scheme( + mock_raise_for_status, url, content_type +): """ `_get_html_response()` should send a HEAD request on an archive-like URL if the scheme supports it, and raise `_NotHTML` if the response isn't HTML. """ session = mock.Mock(PipSession) - session.head.return_value = mock.Mock(**{ - "request.method": "HEAD", - "headers": {"Content-Type": content_type}, - }) + session.head.return_value = mock.Mock( + **{ + "request.method": "HEAD", + "headers": {"Content-Type": content_type}, + } + ) with pytest.raises(_NotHTML) as ctx: _get_html_response(url, session=session) - session.assert_has_calls([ - mock.call.head(url, allow_redirects=True), - ]) + session.assert_has_calls( + [ + mock.call.head(url, allow_redirects=True), + ] + ) mock_raise_for_status.assert_called_once_with(session.head.return_value) assert ctx.value.args == (content_type, "HEAD") @@ -96,12 +101,12 @@ def test_get_html_page_invalid_content_type_archive(caplog, url): session = mock.Mock(PipSession) assert _get_html_page(link, session=session) is None - assert ('pip._internal.index.collector', - logging.WARNING, - 'Skipping page {} because it looks like an archive, and cannot ' - 'be checked by a HTTP HEAD request.'.format( - url)) \ - in caplog.record_tuples + assert ( + "pip._internal.index.collector", + logging.WARNING, + "Skipping page {} because it looks like an archive, and cannot " + "be checked by a HTTP HEAD request.".format(url), + ) in caplog.record_tuples @pytest.mark.parametrize( @@ -112,18 +117,18 @@ def test_get_html_page_invalid_content_type_archive(caplog, url): ], ) @mock.patch("pip._internal.index.collector.raise_for_status") -def test_get_html_response_archive_to_http_scheme_is_html( - mock_raise_for_status, url -): +def test_get_html_response_archive_to_http_scheme_is_html(mock_raise_for_status, url): """ `_get_html_response()` should work with archive-like URLs if the HEAD request is responded with text/html. """ session = mock.Mock(PipSession) - session.head.return_value = mock.Mock(**{ - "request.method": "HEAD", - "headers": {"Content-Type": "text/html"}, - }) + session.head.return_value = mock.Mock( + **{ + "request.method": "HEAD", + "headers": {"Content-Type": "text/html"}, + } + ) session.get.return_value = mock.Mock(headers={"Content-Type": "text/html"}) resp = _get_html_response(url, session=session) @@ -131,13 +136,17 @@ def test_get_html_response_archive_to_http_scheme_is_html( assert resp is not None assert session.mock_calls == [ mock.call.head(url, allow_redirects=True), - mock.call.get(url, headers={ - "Accept": "text/html", "Cache-Control": "max-age=0", - }), + mock.call.get( + url, + headers={ + "Accept": "text/html", + "Cache-Control": "max-age=0", + }, + ), ] assert mock_raise_for_status.mock_calls == [ mock.call(session.head.return_value), - mock.call(resp) + mock.call(resp), ] @@ -158,26 +167,33 @@ def test_get_html_response_no_head(mock_raise_for_status, url): session = mock.Mock(PipSession) # Mock the headers dict to ensure it is accessed. - session.get.return_value = mock.Mock(headers=mock.Mock(**{ - "get.return_value": "text/html", - })) + session.get.return_value = mock.Mock( + headers=mock.Mock( + **{ + "get.return_value": "text/html", + } + ) + ) resp = _get_html_response(url, session=session) assert resp is not None assert session.head.call_count == 0 assert session.get.mock_calls == [ - mock.call(url, headers={ - "Accept": "text/html", "Cache-Control": "max-age=0", - }), + mock.call( + url, + headers={ + "Accept": "text/html", + "Cache-Control": "max-age=0", + }, + ), mock.call().headers.get("Content-Type", ""), ] mock_raise_for_status.assert_called_once_with(resp) @mock.patch("pip._internal.index.collector.raise_for_status") -def test_get_html_response_dont_log_clear_text_password(mock_raise_for_status, - caplog): +def test_get_html_response_dont_log_clear_text_password(mock_raise_for_status, caplog): """ `_get_html_response()` should redact the password from the index URL in its DEBUG log message. @@ -185,9 +201,13 @@ def test_get_html_response_dont_log_clear_text_password(mock_raise_for_status, session = mock.Mock(PipSession) # Mock the headers dict to ensure it is accessed. - session.get.return_value = mock.Mock(headers=mock.Mock(**{ - "get.return_value": "text/html", - })) + session.get.return_value = mock.Mock( + headers=mock.Mock( + **{ + "get.return_value": "text/html", + } + ) + ) caplog.set_level(logging.DEBUG) @@ -200,7 +220,7 @@ def test_get_html_response_dont_log_clear_text_password(mock_raise_for_status, assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'DEBUG' + assert record.levelname == "DEBUG" assert record.message.splitlines() == [ "Getting page https://user:****@example.com/simple/", ] @@ -211,15 +231,13 @@ def test_get_html_response_dont_log_clear_text_password(mock_raise_for_status, [ (b"", "https://example.com/", "https://example.com/"), ( - b"" - b"" - b"", + b"" b'' b"", "https://example.com/", "https://foo.example.com/", ), ( b"" - b"" + b'' b"", "https://example.com/", "https://foo.example.com/", @@ -228,68 +246,70 @@ def test_get_html_response_dont_log_clear_text_password(mock_raise_for_status, ) def test_determine_base_url(html, url, expected): document = html5lib.parse( - html, transport_encoding=None, namespaceHTMLElements=False, + html, + transport_encoding=None, + namespaceHTMLElements=False, ) assert _determine_base_url(document, url) == expected @pytest.mark.parametrize( - ('path', 'expected'), + ("path", "expected"), [ # Test a character that needs quoting. - ('a b', 'a%20b'), + ("a b", "a%20b"), # Test an unquoted "@". - ('a @ b', 'a%20@%20b'), + ("a @ b", "a%20@%20b"), # Test multiple unquoted "@". - ('a @ @ b', 'a%20@%20@%20b'), + ("a @ @ b", "a%20@%20@%20b"), # Test a quoted "@". - ('a %40 b', 'a%20%40%20b'), + ("a %40 b", "a%20%40%20b"), # Test a quoted "@" before an unquoted "@". - ('a %40b@ c', 'a%20%40b@%20c'), + ("a %40b@ c", "a%20%40b@%20c"), # Test a quoted "@" after an unquoted "@". - ('a @b%40 c', 'a%20@b%40%20c'), + ("a @b%40 c", "a%20@b%40%20c"), # Test alternating quoted and unquoted "@". - ('a %40@b %40@c %40', 'a%20%40@b%20%40@c%20%40'), + ("a %40@b %40@c %40", "a%20%40@b%20%40@c%20%40"), # Test an unquoted "/". - ('a / b', 'a%20/%20b'), + ("a / b", "a%20/%20b"), # Test multiple unquoted "/". - ('a / / b', 'a%20/%20/%20b'), + ("a / / b", "a%20/%20/%20b"), # Test a quoted "/". - ('a %2F b', 'a%20%2F%20b'), + ("a %2F b", "a%20%2F%20b"), # Test a quoted "/" before an unquoted "/". - ('a %2Fb/ c', 'a%20%2Fb/%20c'), + ("a %2Fb/ c", "a%20%2Fb/%20c"), # Test a quoted "/" after an unquoted "/". - ('a /b%2F c', 'a%20/b%2F%20c'), + ("a /b%2F c", "a%20/b%2F%20c"), # Test alternating quoted and unquoted "/". - ('a %2F/b %2F/c %2F', 'a%20%2F/b%20%2F/c%20%2F'), + ("a %2F/b %2F/c %2F", "a%20%2F/b%20%2F/c%20%2F"), # Test normalizing non-reserved quoted characters "[" and "]" - ('a %5b %5d b', 'a%20%5B%20%5D%20b'), + ("a %5b %5d b", "a%20%5B%20%5D%20b"), # Test normalizing a reserved quoted "/" - ('a %2f b', 'a%20%2F%20b'), - ] + ("a %2f b", "a%20%2F%20b"), + ], ) -@pytest.mark.parametrize('is_local_path', [True, False]) +@pytest.mark.parametrize("is_local_path", [True, False]) def test_clean_url_path(path, expected, is_local_path): assert _clean_url_path(path, is_local_path=is_local_path) == expected @pytest.mark.parametrize( - ('path', 'expected'), + ("path", "expected"), [ # Test a VCS path with a Windows drive letter and revision. pytest.param( - '/T:/with space/repo.git@1.0', - '///T:/with%20space/repo.git@1.0', + "/T:/with space/repo.git@1.0", + "///T:/with%20space/repo.git@1.0", marks=pytest.mark.skipif("sys.platform != 'win32'"), ), # Test a VCS path with a Windows drive letter and revision, # running on non-windows platform. pytest.param( - '/T:/with space/repo.git@1.0', - '/T%3A/with%20space/repo.git@1.0', + "/T:/with space/repo.git@1.0", + "/T%3A/with%20space/repo.git@1.0", marks=pytest.mark.skipif("sys.platform == 'win32'"), ), - ] + ], ) def test_clean_url_path_with_local_path(path, expected): actual = _clean_url_path(path, is_local_path=True) @@ -300,41 +320,63 @@ def test_clean_url_path_with_local_path(path, expected): ("url", "clean_url"), [ # URL with hostname and port. Port separator should not be quoted. - ("https://localhost.localdomain:8181/path/with space/", - "https://localhost.localdomain:8181/path/with%20space/"), + ( + "https://localhost.localdomain:8181/path/with space/", + "https://localhost.localdomain:8181/path/with%20space/", + ), # URL that is already properly quoted. The quoting `%` # characters should not be quoted again. - ("https://localhost.localdomain:8181/path/with%20quoted%20space/", - "https://localhost.localdomain:8181/path/with%20quoted%20space/"), + ( + "https://localhost.localdomain:8181/path/with%20quoted%20space/", + "https://localhost.localdomain:8181/path/with%20quoted%20space/", + ), # URL with IPv4 address and port. - ("https://127.0.0.1:8181/path/with space/", - "https://127.0.0.1:8181/path/with%20space/"), + ( + "https://127.0.0.1:8181/path/with space/", + "https://127.0.0.1:8181/path/with%20space/", + ), # URL with IPv6 address and port. The `[]` brackets around the # IPv6 address should not be quoted. - ("https://[fd00:0:0:236::100]:8181/path/with space/", - "https://[fd00:0:0:236::100]:8181/path/with%20space/"), + ( + "https://[fd00:0:0:236::100]:8181/path/with space/", + "https://[fd00:0:0:236::100]:8181/path/with%20space/", + ), # URL with query. The leading `?` should not be quoted. - ("https://localhost.localdomain:8181/path/with/query?request=test", - "https://localhost.localdomain:8181/path/with/query?request=test"), + ( + "https://localhost.localdomain:8181/path/with/query?request=test", + "https://localhost.localdomain:8181/path/with/query?request=test", + ), # URL with colon in the path portion. - ("https://localhost.localdomain:8181/path:/with:/colon", - "https://localhost.localdomain:8181/path%3A/with%3A/colon"), + ( + "https://localhost.localdomain:8181/path:/with:/colon", + "https://localhost.localdomain:8181/path%3A/with%3A/colon", + ), # URL with something that looks like a drive letter, but is # not. The `:` should be quoted. - ("https://localhost.localdomain/T:/path/", - "https://localhost.localdomain/T%3A/path/"), + ( + "https://localhost.localdomain/T:/path/", + "https://localhost.localdomain/T%3A/path/", + ), # URL with a quoted "/" in the path portion. - ("https://example.com/access%2Ftoken/path/", - "https://example.com/access%2Ftoken/path/"), + ( + "https://example.com/access%2Ftoken/path/", + "https://example.com/access%2Ftoken/path/", + ), # VCS URL containing revision string. - ("git+ssh://example.com/path to/repo.git@1.0#egg=my-package-1.0", - "git+ssh://example.com/path%20to/repo.git@1.0#egg=my-package-1.0"), + ( + "git+ssh://example.com/path to/repo.git@1.0#egg=my-package-1.0", + "git+ssh://example.com/path%20to/repo.git@1.0#egg=my-package-1.0", + ), # VCS URL with a quoted "#" in the revision string. - ("git+https://example.com/repo.git@hash%23symbol#egg=my-package-1.0", - "git+https://example.com/repo.git@hash%23symbol#egg=my-package-1.0"), + ( + "git+https://example.com/repo.git@hash%23symbol#egg=my-package-1.0", + "git+https://example.com/repo.git@hash%23symbol#egg=my-package-1.0", + ), # VCS URL with a quoted "@" in the revision string. - ("git+https://example.com/repo.git@at%40 space#egg=my-package-1.0", - "git+https://example.com/repo.git@at%40%20space#egg=my-package-1.0"), + ( + "git+https://example.com/repo.git@at%40 space#egg=my-package-1.0", + "git+https://example.com/repo.git@at%40%20space#egg=my-package-1.0", + ), # URL with Windows drive letter. The `:` after the drive # letter should not be quoted. The trailing `/` should be # removed. @@ -363,45 +405,49 @@ def test_clean_url_path_with_local_path(path, expected): "git+file:/T%3A/with%20space/repo.git@1.0#egg=my-package-1.0", marks=pytest.mark.skipif("sys.platform == 'win32'"), ), - ] + ], ) def test_clean_link(url, clean_url): assert _clean_link(url) == clean_url -@pytest.mark.parametrize('anchor_html, expected', [ - # Test not present. - ('', None), - # Test present with no value. - ('', ''), - # Test the empty string. - ('', ''), - # Test a non-empty string. - ('', 'error'), - # Test a value with an escaped character. - ('', - 'version < 1'), - # Test a yanked reason with a non-ascii character. - (u'', - u'curlyquote \u2018'), -]) +@pytest.mark.parametrize( + "anchor_html, expected", + [ + # Test not present. + ('', None), + # Test present with no value. + ('', ""), + # Test the empty string. + ('', ""), + # Test a non-empty string. + ('', "error"), + # Test a value with an escaped character. + ('', "version < 1"), + # Test a yanked reason with a non-ascii character. + ( + u'', + u"curlyquote \u2018", + ), + ], +) def test_parse_links__yanked_reason(anchor_html, expected): html = ( # Mark this as a unicode string for Python 2 since anchor_html # can contain non-ascii. u'' - '{}' + "{}" ).format(anchor_html) - html_bytes = html.encode('utf-8') + html_bytes = html.encode("utf-8") page = HTMLPage( html_bytes, encoding=None, # parse_links() is cached by url, so we inject a random uuid to ensure # the page content isn't cached. - url='https://example.com/simple-{}/'.format(uuid.uuid4()), + url="https://example.com/simple-{}/".format(uuid.uuid4()), ) links = list(parse_links(page)) - link, = links + (link,) = links actual = link.yanked_reason assert actual == expected @@ -412,9 +458,9 @@ def test_parse_links_caches_same_page_by_url(): '' '' ) - html_bytes = html.encode('utf-8') + html_bytes = html.encode("utf-8") - url = 'https://example.com/simple/' + url = "https://example.com/simple/" page_1 = HTMLPage( html_bytes, @@ -424,7 +470,7 @@ def test_parse_links_caches_same_page_by_url(): # Make a second page with zero content, to ensure that it's not accessed, # because the page was cached by url. page_2 = HTMLPage( - b'', + b"", encoding=None, url=url, ) @@ -432,7 +478,7 @@ def test_parse_links_caches_same_page_by_url(): # cached, even for the same url. We modify the page content slightly to # verify that the result is not cached. page_3 = HTMLPage( - re.sub(b'pkg1', b'pkg2', html_bytes), + re.sub(b"pkg1", b"pkg2", html_bytes), encoding=None, url=url, cache_link_parsing=False, @@ -440,7 +486,7 @@ def test_parse_links_caches_same_page_by_url(): parsed_links_1 = list(parse_links(page_1)) assert len(parsed_links_1) == 1 - assert 'pkg1' in parsed_links_1[0].url + assert "pkg1" in parsed_links_1[0].url parsed_links_2 = list(parse_links(page_2)) assert parsed_links_2 == parsed_links_1 @@ -448,47 +494,41 @@ def test_parse_links_caches_same_page_by_url(): parsed_links_3 = list(parse_links(page_3)) assert len(parsed_links_3) == 1 assert parsed_links_3 != parsed_links_1 - assert 'pkg2' in parsed_links_3[0].url + assert "pkg2" in parsed_links_3[0].url @mock.patch("pip._internal.index.collector.raise_for_status") def test_request_http_error(mock_raise_for_status, caplog): caplog.set_level(logging.DEBUG) - link = Link('http://localhost') + link = Link("http://localhost") session = Mock(PipSession) session.get.return_value = Mock() - mock_raise_for_status.side_effect = NetworkConnectionError('Http error') + mock_raise_for_status.side_effect = NetworkConnectionError("Http error") assert _get_html_page(link, session=session) is None - assert ( - 'Could not fetch URL http://localhost: Http error - skipping' - in caplog.text - ) + assert "Could not fetch URL http://localhost: Http error - skipping" in caplog.text def test_request_retries(caplog): caplog.set_level(logging.DEBUG) - link = Link('http://localhost') + link = Link("http://localhost") session = Mock(PipSession) - session.get.side_effect = requests.exceptions.RetryError('Retry error') + session.get.side_effect = requests.exceptions.RetryError("Retry error") assert _get_html_page(link, session=session) is None - assert ( - 'Could not fetch URL http://localhost: Retry error - skipping' - in caplog.text - ) + assert "Could not fetch URL http://localhost: Retry error - skipping" in caplog.text def test_make_html_page(): - headers = {'Content-Type': 'text/html; charset=UTF-8'} + headers = {"Content-Type": "text/html; charset=UTF-8"} response = pretend.stub( - content=b'', - url='https://example.com/index.html', + content=b"", + url="https://example.com/index.html", headers=headers, ) actual = _make_html_page(response) - assert actual.content == b'' - assert actual.encoding == 'UTF-8' - assert actual.url == 'https://example.com/index.html' + assert actual.content == b"" + assert actual.encoding == "UTF-8" + assert actual.url == "https://example.com/index.html" @pytest.mark.parametrize( @@ -525,47 +565,51 @@ def test_get_html_page_invalid_scheme(caplog, url, vcs_scheme): ], ) @mock.patch("pip._internal.index.collector.raise_for_status") -def test_get_html_page_invalid_content_type(mock_raise_for_status, - caplog, content_type): +def test_get_html_page_invalid_content_type( + mock_raise_for_status, caplog, content_type +): """`_get_html_page()` should warn if an invalid content-type is given. Only text/html is allowed. """ caplog.set_level(logging.DEBUG) - url = 'https://pypi.org/simple/pip' + url = "https://pypi.org/simple/pip" link = Link(url) session = mock.Mock(PipSession) - session.get.return_value = mock.Mock(**{ - "request.method": "GET", - "headers": {"Content-Type": content_type}, - }) + session.get.return_value = mock.Mock( + **{ + "request.method": "GET", + "headers": {"Content-Type": content_type}, + } + ) assert _get_html_page(link, session=session) is None mock_raise_for_status.assert_called_once_with(session.get.return_value) - assert ('pip._internal.index.collector', - logging.WARNING, - 'Skipping page {} because the GET request got Content-Type: {}.' - 'The only supported Content-Type is text/html'.format( - url, content_type)) \ - in caplog.record_tuples + assert ( + "pip._internal.index.collector", + logging.WARNING, + "Skipping page {} because the GET request got Content-Type: {}." + "The only supported Content-Type is text/html".format(url, content_type), + ) in caplog.record_tuples def make_fake_html_response(url): """ Create a fake requests.Response object. """ - html = dedent(u"""\ + html = dedent( + u"""\ abc-1.0.tar.gz - """) - content = html.encode('utf-8') + """ + ) + content = html.encode("utf-8") return pretend.stub(content=content, url=url, headers={}) def test_get_html_page_directory_append_index(tmpdir): - """`_get_html_page()` should append "index.html" to a directory URL. - """ + """`_get_html_page()` should append "index.html" to a directory URL.""" dirpath = tmpdir / "something" dirpath.mkdir() dir_url = "file:///{}".format( @@ -581,7 +625,7 @@ def test_get_html_page_directory_append_index(tmpdir): actual = _get_html_page(Link(dir_url), session=session) assert mock_func.mock_calls == [ mock.call(expected_url, session=session), - ], 'actual calls: {}'.format(mock_func.mock_calls) + ], "actual calls: {}".format(mock_func.mock_calls) assert actual.content == fake_response.content assert actual.encoding is None @@ -591,14 +635,14 @@ def test_get_html_page_directory_append_index(tmpdir): def test_remove_duplicate_links(): links = [ # We choose Links that will test that ordering is preserved. - Link('https://example.com/2'), - Link('https://example.com/1'), - Link('https://example.com/2'), + Link("https://example.com/2"), + Link("https://example.com/1"), + Link("https://example.com/2"), ] actual = _remove_duplicate_links(links) assert actual == [ - Link('https://example.com/2'), - Link('https://example.com/1'), + Link("https://example.com/2"), + Link("https://example.com/1"), ] @@ -626,7 +670,7 @@ def test_group_locations__non_existing_path(): """ Test that a non-existing path is ignored. """ - files, urls = group_locations([os.path.join('this', 'doesnt', 'exist')]) + files, urls = group_locations([os.path.join("this", "doesnt", "exist")]) assert not urls and not files, "nothing should have been found" @@ -636,16 +680,15 @@ def check_links_include(links, names): given names, a link whose URL has a base name matching that name. """ for name in names: - assert any(link.url.endswith(name) for link in links), ( - 'name {!r} not among links: {}'.format(name, links) - ) + assert any( + link.url.endswith(name) for link in links + ), "name {!r} not among links: {}".format(name, links) class TestLinkCollector(object): - - @patch('pip._internal.index.collector._get_html_response') + @patch("pip._internal.index.collector._get_html_response") def test_fetch_page(self, mock_get_html_response): - url = 'https://pypi.org/simple/twine/' + url = "https://pypi.org/simple/twine/" fake_response = make_fake_html_response(url) mock_get_html_response.return_value = fake_response @@ -662,7 +705,8 @@ def test_fetch_page(self, mock_get_html_response): # Also check that the right session object was passed to # _get_html_response(). mock_get_html_response.assert_called_once_with( - url, session=link_collector.session, + url, + session=link_collector.session, ) def test_collect_links(self, caplog, data): @@ -674,43 +718,48 @@ def test_collect_links(self, caplog, data): # is skipped. index_urls=[PyPI.simple_url, PyPI.simple_url], ) - actual = link_collector.collect_links('twine') + actual = link_collector.collect_links("twine") # Spot-check the CollectedLinks return value. assert len(actual.files) > 20 - check_links_include(actual.files, names=['simple-1.0.tar.gz']) + check_links_include(actual.files, names=["simple-1.0.tar.gz"]) assert len(actual.find_links) == 1 - check_links_include(actual.find_links, names=['packages']) + check_links_include(actual.find_links, names=["packages"]) # Check that find-links URLs are marked as cacheable. assert actual.find_links[0].cache_link_parsing - assert actual.project_urls == [Link('https://pypi.org/simple/twine/')] + assert actual.project_urls == [Link("https://pypi.org/simple/twine/")] # Check that index URLs are marked as *un*cacheable. assert not actual.project_urls[0].cache_link_parsing - expected_message = dedent("""\ + expected_message = dedent( + """\ 1 location(s) to search for versions of twine: - * https://pypi.org/simple/twine/""") + * https://pypi.org/simple/twine/""" + ) assert caplog.record_tuples == [ - ('pip._internal.index.collector', logging.DEBUG, expected_message), + ("pip._internal.index.collector", logging.DEBUG, expected_message), ] @pytest.mark.parametrize( - 'find_links, no_index, suppress_no_index, expected', [ - (['link1'], False, False, - (['link1'], ['default_url', 'url1', 'url2'])), - (['link1'], False, True, (['link1'], ['default_url', 'url1', 'url2'])), - (['link1'], True, False, (['link1'], [])), + "find_links, no_index, suppress_no_index, expected", + [ + (["link1"], False, False, (["link1"], ["default_url", "url1", "url2"])), + (["link1"], False, True, (["link1"], ["default_url", "url1", "url2"])), + (["link1"], True, False, (["link1"], [])), # Passing suppress_no_index=True suppresses no_index=True. - (['link1'], True, True, (['link1'], ['default_url', 'url1', 'url2'])), + (["link1"], True, True, (["link1"], ["default_url", "url1", "url2"])), # Test options.find_links=False. - (False, False, False, ([], ['default_url', 'url1', 'url2'])), + (False, False, False, ([], ["default_url", "url1", "url2"])), ], ) def test_link_collector_create( - find_links, no_index, suppress_no_index, expected, + find_links, + no_index, + suppress_no_index, + expected, ): """ :param expected: the expected (find_links, index_urls) values. @@ -719,12 +768,14 @@ def test_link_collector_create( session = PipSession() options = pretend.stub( find_links=find_links, - index_url='default_url', - extra_index_urls=['url1', 'url2'], + index_url="default_url", + extra_index_urls=["url1", "url2"], no_index=no_index, ) link_collector = LinkCollector.create( - session, options=options, suppress_no_index=suppress_no_index, + session, + options=options, + suppress_no_index=suppress_no_index, ) assert link_collector.session is session @@ -734,16 +785,17 @@ def test_link_collector_create( assert search_scope.index_urls == expected_index_urls -@patch('pip._internal.utils.misc.expanduser') +@patch("pip._internal.utils.misc.expanduser") def test_link_collector_create_find_links_expansion( - mock_expanduser, tmpdir, + mock_expanduser, + tmpdir, ): """ Test "~" expansion in --find-links paths. """ # This is a mock version of expanduser() that expands "~" to the tmpdir. def expand_path(path): - if path.startswith('~/'): + if path.startswith("~/"): path = os.path.join(tmpdir, path[2:]) return path @@ -751,14 +803,14 @@ def expand_path(path): session = PipSession() options = pretend.stub( - find_links=['~/temp1', '~/temp2'], - index_url='default_url', + find_links=["~/temp1", "~/temp2"], + index_url="default_url", extra_index_urls=[], no_index=False, ) # Only create temp2 and not temp1 to test that "~" expansion only occurs # when the directory exists. - temp2_dir = os.path.join(tmpdir, 'temp2') + temp2_dir = os.path.join(tmpdir, "temp2") os.mkdir(temp2_dir) link_collector = LinkCollector.create(session, options=options) @@ -766,5 +818,5 @@ def expand_path(path): search_scope = link_collector.search_scope # Only ~/temp2 gets expanded. Also, the path is normalized when expanded. expected_temp2_dir = os.path.normcase(temp2_dir) - assert search_scope.find_links == ['~/temp1', expected_temp2_dir] - assert search_scope.index_urls == ['default_url'] + assert search_scope.find_links == ["~/temp1", expected_temp2_dir] + assert search_scope.index_urls == ["default_url"] diff --git a/tests/unit/test_command_install.py b/tests/unit/test_command_install.py index 7b6b38de0fa..78a12da7ca8 100644 --- a/tests/unit/test_command_install.py +++ b/tests/unit/test_command_install.py @@ -14,33 +14,35 @@ class TestDecideUserInstall: - @patch('site.ENABLE_USER_SITE', True) - @patch('pip._internal.commands.install.site_packages_writable') + @patch("site.ENABLE_USER_SITE", True) + @patch("pip._internal.commands.install.site_packages_writable") def test_prefix_and_target(self, sp_writable): sp_writable.return_value = False - assert decide_user_install( - use_user_site=None, prefix_path='foo' - ) is False + assert decide_user_install(use_user_site=None, prefix_path="foo") is False - assert decide_user_install( - use_user_site=None, target_dir='bar' - ) is False + assert decide_user_install(use_user_site=None, target_dir="bar") is False @pytest.mark.parametrize( - "enable_user_site,site_packages_writable,result", [ + "enable_user_site,site_packages_writable,result", + [ (True, True, False), (True, False, True), (False, True, False), (False, False, False), - ]) + ], + ) def test_most_cases( - self, enable_user_site, site_packages_writable, result, monkeypatch, + self, + enable_user_site, + site_packages_writable, + result, + monkeypatch, ): - monkeypatch.setattr('site.ENABLE_USER_SITE', enable_user_site) + monkeypatch.setattr("site.ENABLE_USER_SITE", enable_user_site) monkeypatch.setattr( - 'pip._internal.commands.install.site_packages_writable', - lambda **kw: site_packages_writable + "pip._internal.commands.install.site_packages_writable", + lambda **kw: site_packages_writable, ) assert decide_user_install(use_user_site=None) is result @@ -58,8 +60,7 @@ def test_rejection_for_location_requirement_options(): bad_named_req_options = ["--home=/wow"] bad_named_req = InstallRequirement( - Requirement("hello"), "requirements.txt", - install_options=bad_named_req_options + Requirement("hello"), "requirements.txt", install_options=bad_named_req_options ) bad_unnamed_req_options = ["--install-lib=/lib"] @@ -79,37 +80,75 @@ def test_rejection_for_location_requirement_options(): assert "['--home'] from hello (from requirements.txt)" in str(e.value) -@pytest.mark.parametrize('error, show_traceback, using_user_site, expected', [ - # show_traceback = True, using_user_site = True - (EnvironmentError("Illegal byte sequence"), True, True, 'Could not install' - ' packages due to an EnvironmentError.\n'), - (EnvironmentError(errno.EACCES, "No file permission"), True, True, 'Could' - ' not install packages due to an EnvironmentError.\nCheck the' - ' permissions.\n'), - # show_traceback = True, using_user_site = False - (EnvironmentError("Illegal byte sequence"), True, False, 'Could not' - ' install packages due to an EnvironmentError.\n'), - (EnvironmentError(errno.EACCES, "No file permission"), True, False, 'Could' - ' not install packages due to an EnvironmentError.\nConsider using the' - ' `--user` option or check the permissions.\n'), - # show_traceback = False, using_user_site = True - (EnvironmentError("Illegal byte sequence"), False, True, 'Could not' - ' install packages due to an EnvironmentError: Illegal byte' - ' sequence\n'), - (EnvironmentError(errno.EACCES, "No file permission"), False, True, 'Could' - ' not install packages due to an EnvironmentError: [Errno 13] No file' - ' permission\nCheck the permissions.\n'), - # show_traceback = False, using_user_site = False - (EnvironmentError("Illegal byte sequence"), False, False, 'Could not' - ' install packages due to an EnvironmentError: Illegal byte sequence' - '\n'), - (EnvironmentError(errno.EACCES, "No file permission"), False, False, - 'Could not install packages due to an EnvironmentError: [Errno 13] No' - ' file permission\nConsider using the `--user` option or check the' - ' permissions.\n'), -]) -def test_create_env_error_message( - error, show_traceback, using_user_site, expected -): +@pytest.mark.parametrize( + "error, show_traceback, using_user_site, expected", + [ + # show_traceback = True, using_user_site = True + ( + EnvironmentError("Illegal byte sequence"), + True, + True, + "Could not install" " packages due to an EnvironmentError.\n", + ), + ( + EnvironmentError(errno.EACCES, "No file permission"), + True, + True, + "Could" + " not install packages due to an EnvironmentError.\nCheck the" + " permissions.\n", + ), + # show_traceback = True, using_user_site = False + ( + EnvironmentError("Illegal byte sequence"), + True, + False, + "Could not" " install packages due to an EnvironmentError.\n", + ), + ( + EnvironmentError(errno.EACCES, "No file permission"), + True, + False, + "Could" + " not install packages due to an EnvironmentError.\nConsider using the" + " `--user` option or check the permissions.\n", + ), + # show_traceback = False, using_user_site = True + ( + EnvironmentError("Illegal byte sequence"), + False, + True, + "Could not" + " install packages due to an EnvironmentError: Illegal byte" + " sequence\n", + ), + ( + EnvironmentError(errno.EACCES, "No file permission"), + False, + True, + "Could" + " not install packages due to an EnvironmentError: [Errno 13] No file" + " permission\nCheck the permissions.\n", + ), + # show_traceback = False, using_user_site = False + ( + EnvironmentError("Illegal byte sequence"), + False, + False, + "Could not" + " install packages due to an EnvironmentError: Illegal byte sequence" + "\n", + ), + ( + EnvironmentError(errno.EACCES, "No file permission"), + False, + False, + "Could not install packages due to an EnvironmentError: [Errno 13] No" + " file permission\nConsider using the `--user` option or check the" + " permissions.\n", + ), + ], +) +def test_create_env_error_message(error, show_traceback, using_user_site, expected): msg = create_env_error_message(error, show_traceback, using_user_site) assert msg == expected diff --git a/tests/unit/test_commands.py b/tests/unit/test_commands.py index 7fae427c697..2c2df49f2dd 100644 --- a/tests/unit/test_commands.py +++ b/tests/unit/test_commands.py @@ -10,7 +10,7 @@ # These are the expected names of the commands whose classes inherit from # IndexGroupCommand. -EXPECTED_INDEX_GROUP_COMMANDS = ['download', 'install', 'list', 'wheel'] +EXPECTED_INDEX_GROUP_COMMANDS = ["download", "install", "list", "wheel"] def check_commands(pred, expected): @@ -19,7 +19,7 @@ def check_commands(pred, expected): """ commands = [create_command(name) for name in sorted(commands_dict)] actual = [command.name for command in commands if pred(command)] - assert actual == expected, 'actual: {}'.format(actual) + assert actual == expected, "actual: {}".format(actual) def test_commands_dict__order(): @@ -29,11 +29,11 @@ def test_commands_dict__order(): names = list(commands_dict) # A spot-check is sufficient to check that commands_dict encodes an # ordering. - assert names[0] == 'install' - assert names[-1] == 'help' + assert names[0] == "install" + assert names[-1] == "help" -@pytest.mark.parametrize('name', list(commands_dict)) +@pytest.mark.parametrize("name", list(commands_dict)) def test_create_command(name): """Test creating an instance of each available command.""" command = create_command(name) @@ -45,10 +45,11 @@ def test_session_commands(): """ Test which commands inherit from SessionCommandMixin. """ + def is_session_command(command): return isinstance(command, SessionCommandMixin) - expected = ['download', 'install', 'list', 'search', 'uninstall', 'wheel'] + expected = ["download", "install", "list", "search", "uninstall", "wheel"] check_commands(is_session_command, expected) @@ -56,6 +57,7 @@ def test_index_group_commands(): """ Test the commands inheriting from IndexGroupCommand. """ + def is_index_group_command(command): return isinstance(command, IndexGroupCommand) @@ -64,14 +66,14 @@ def is_index_group_command(command): # Also check that the commands inheriting from IndexGroupCommand are # exactly the commands with the --no-index option. def has_option_no_index(command): - return command.parser.has_option('--no-index') + return command.parser.has_option("--no-index") check_commands(has_option_no_index, EXPECTED_INDEX_GROUP_COMMANDS) -@pytest.mark.parametrize('command_name', EXPECTED_INDEX_GROUP_COMMANDS) +@pytest.mark.parametrize("command_name", EXPECTED_INDEX_GROUP_COMMANDS) @pytest.mark.parametrize( - 'disable_pip_version_check, no_index, expected_called', + "disable_pip_version_check, no_index, expected_called", [ # pip_self_version_check() is only called when both # disable_pip_version_check and no_index are False. @@ -81,9 +83,12 @@ def has_option_no_index(command): (True, True, False), ], ) -@patch('pip._internal.cli.req_command.pip_self_version_check') +@patch("pip._internal.cli.req_command.pip_self_version_check") def test_index_group_handle_pip_version_check( - mock_version_check, command_name, disable_pip_version_check, no_index, + mock_version_check, + command_name, + disable_pip_version_check, + no_index, expected_called, ): """ @@ -107,7 +112,8 @@ def test_requirement_commands(): """ Test which commands inherit from RequirementCommand. """ + def is_requirement_command(command): return isinstance(command, RequirementCommand) - check_commands(is_requirement_command, ['download', 'install', 'wheel']) + check_commands(is_requirement_command, ["download", "install", "wheel"]) diff --git a/tests/unit/test_compat.py b/tests/unit/test_compat.py index 1b7a482a2a3..ad9abdb1062 100644 --- a/tests/unit/test_compat.py +++ b/tests/unit/test_compat.py @@ -34,7 +34,7 @@ def test_get_path_uid_symlink(tmpdir): f = tmpdir / "symlink" / "somefile" f.parent.mkdir() f.write_text("content") - fs = f + '_link' + fs = f + "_link" os.symlink(f, fs) with pytest.raises(OSError): get_path_uid(fs) @@ -47,50 +47,56 @@ def test_get_path_uid_symlink_without_NOFOLLOW(tmpdir, monkeypatch): f = tmpdir / "symlink" / "somefile" f.parent.mkdir() f.write_text("content") - fs = f + '_link' + fs = f + "_link" os.symlink(f, fs) with pytest.raises(OSError): get_path_uid(fs) -@pytest.mark.parametrize('data, expected', [ - ('abc', u'abc'), - # Test text (unicode in Python 2) input. - (u'abc', u'abc'), - # Test text input with non-ascii characters. - (u'déf', u'déf'), -]) +@pytest.mark.parametrize( + "data, expected", + [ + ("abc", u"abc"), + # Test text (unicode in Python 2) input. + (u"abc", u"abc"), + # Test text input with non-ascii characters. + (u"déf", u"déf"), + ], +) def test_str_to_display(data, expected): actual = str_to_display(data) assert actual == expected, ( # Show the encoding for easier troubleshooting. - 'encoding: {!r}'.format(locale.getpreferredencoding()) + "encoding: {!r}".format(locale.getpreferredencoding()) ) -@pytest.mark.parametrize('data, encoding, expected', [ - # Test str input with non-ascii characters. - ('déf', 'utf-8', u'déf'), - # Test bytes input with non-ascii characters: - (u'déf'.encode('utf-8'), 'utf-8', u'déf'), - # Test a Windows encoding. - (u'déf'.encode('cp1252'), 'cp1252', u'déf'), - # Test a Windows encoding with incompatibly encoded text. - (u'déf'.encode('utf-8'), 'cp1252', u'déf'), -]) +@pytest.mark.parametrize( + "data, encoding, expected", + [ + # Test str input with non-ascii characters. + ("déf", "utf-8", u"déf"), + # Test bytes input with non-ascii characters: + (u"déf".encode("utf-8"), "utf-8", u"déf"), + # Test a Windows encoding. + (u"déf".encode("cp1252"), "cp1252", u"déf"), + # Test a Windows encoding with incompatibly encoded text. + (u"déf".encode("utf-8"), "cp1252", u"déf"), + ], +) def test_str_to_display__encoding(monkeypatch, data, encoding, expected): - monkeypatch.setattr(locale, 'getpreferredencoding', lambda: encoding) + monkeypatch.setattr(locale, "getpreferredencoding", lambda: encoding) actual = str_to_display(data) assert actual == expected, ( # Show the encoding for easier troubleshooting. - 'encoding: {!r}'.format(locale.getpreferredencoding()) + "encoding: {!r}".format(locale.getpreferredencoding()) ) def test_str_to_display__decode_error(monkeypatch, caplog): - monkeypatch.setattr(locale, 'getpreferredencoding', lambda: 'utf-8') + monkeypatch.setattr(locale, "getpreferredencoding", lambda: "utf-8") # Encode with an incompatible encoding. - data = u'ab'.encode('utf-16') + data = u"ab".encode("utf-16") actual = str_to_display(data) # Keep the expected value endian safe if sys.byteorder == "little": @@ -100,22 +106,19 @@ def test_str_to_display__decode_error(monkeypatch, caplog): assert actual == expected, ( # Show the encoding for easier troubleshooting. - 'encoding: {!r}'.format(locale.getpreferredencoding()) + "encoding: {!r}".format(locale.getpreferredencoding()) ) assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'WARNING' - assert record.message == ( - 'Bytes object does not appear to be encoded as utf-8' - ) + assert record.levelname == "WARNING" + assert record.message == ("Bytes object does not appear to be encoded as utf-8") def test_console_to_str(monkeypatch): some_bytes = b"a\xE9\xC3\xE9b" - encodings = ('ascii', 'utf-8', 'iso-8859-1', 'iso-8859-5', - 'koi8_r', 'cp850') + encodings = ("ascii", "utf-8", "iso-8859-1", "iso-8859-5", "koi8_r", "cp850") for e in encodings: - monkeypatch.setattr(locale, 'getpreferredencoding', lambda: e) + monkeypatch.setattr(locale, "getpreferredencoding", lambda: e) result = console_to_str(some_bytes) assert result.startswith("a") assert result.endswith("b") @@ -125,21 +128,24 @@ def test_console_to_str_warning(monkeypatch): some_bytes = b"a\xE9b" def check_warning(msg, *args, **kwargs): - assert 'does not appear to be encoded as' in msg - assert args[0] == 'Subprocess output' + assert "does not appear to be encoded as" in msg + assert args[0] == "Subprocess output" - monkeypatch.setattr(locale, 'getpreferredencoding', lambda: 'utf-8') - monkeypatch.setattr(pip_compat.logger, 'warning', check_warning) + monkeypatch.setattr(locale, "getpreferredencoding", lambda: "utf-8") + monkeypatch.setattr(pip_compat.logger, "warning", check_warning) console_to_str(some_bytes) -@pytest.mark.parametrize("home,path,expanded", [ - ("/Users/test", "~", "/Users/test"), - ("/Users/test", "~/.cache", "/Users/test/.cache"), - # Verify that we are not affected by https://bugs.python.org/issue14768 - ("/", "~", "/"), - ("/", "~/.cache", "/.cache"), -]) +@pytest.mark.parametrize( + "home,path,expanded", + [ + ("/Users/test", "~", "/Users/test"), + ("/Users/test", "~/.cache", "/Users/test/.cache"), + # Verify that we are not affected by https://bugs.python.org/issue14768 + ("/", "~", "/"), + ("/", "~/.cache", "/.cache"), + ], +) def test_expanduser(home, path, expanded, monkeypatch): monkeypatch.setenv("HOME", home) monkeypatch.setenv("USERPROFILE", home) diff --git a/tests/unit/test_configuration.py b/tests/unit/test_configuration.py index 0a45fc136d5..de18091b2bd 100644 --- a/tests/unit/test_configuration.py +++ b/tests/unit/test_configuration.py @@ -10,7 +10,6 @@ class TestConfigurationLoading(ConfigurationMixin): - def test_global_loading(self): self.patch_configuration(kinds.GLOBAL, {"test.hello": "1"}) @@ -39,8 +38,9 @@ def test_environment_config_loading(self, monkeypatch): monkeypatch.setenv("PIP_CONFIG_FILE", config_file) self.configuration.load() - assert self.configuration.get_value("test.hello") == "4", \ - self.configuration._config + assert ( + self.configuration.get_value("test.hello") == "4" + ), self.configuration._config def test_environment_var_loading(self, monkeypatch): monkeypatch.setenv("PIP_HELLO", "5") @@ -76,9 +76,8 @@ def test_environment_config_errors_if_malformed(self, monkeypatch): assert "section header" in str(err.value) # error kind assert "1" in str(err.value) # line number - assert ( # file name - config_file in str(err.value) or - repr(config_file) in str(err.value) + assert config_file in str(err.value) or repr(config_file) in str( # file name + err.value ) @@ -190,9 +189,7 @@ def test_site_modification(self): # get the path to site config file assert mymock.call_count == 1 - assert mymock.call_args[0][0] == ( - get_configuration_files()[kinds.SITE][0] - ) + assert mymock.call_args[0][0] == (get_configuration_files()[kinds.SITE][0]) def test_user_modification(self): # get the path to local config file @@ -225,6 +222,4 @@ def test_global_modification(self): # get the path to user config file assert mymock.call_count == 1 - assert mymock.call_args[0][0] == ( - get_configuration_files()[kinds.GLOBAL][-1] - ) + assert mymock.call_args[0][0] == (get_configuration_files()[kinds.GLOBAL][-1]) diff --git a/tests/unit/test_direct_url.py b/tests/unit/test_direct_url.py index ee6b7fbf4ea..97b412aa8e7 100644 --- a/tests/unit/test_direct_url.py +++ b/tests/unit/test_direct_url.py @@ -30,9 +30,7 @@ def test_to_json(): def test_archive_info(): direct_url_dict = { "url": "file:///home/user/archive.tgz", - "archive_info": { - "hash": "sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220" - }, + "archive_info": {"hash": "sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220"}, } direct_url = DirectUrl.from_dict(direct_url_dict) assert isinstance(direct_url.info, ArchiveInfo) @@ -71,47 +69,31 @@ def test_vcs_info(): assert direct_url.url == direct_url_dict["url"] assert direct_url.info.vcs == "git" assert direct_url.info.requested_revision == "master" - assert ( - direct_url.info.commit_id == "1b8c5bc61a86f377fea47b4276c8c8a5842d2220" - ) + assert direct_url.info.commit_id == "1b8c5bc61a86f377fea47b4276c8c8a5842d2220" assert direct_url.to_dict() == direct_url_dict def test_parsing_validation(): - with pytest.raises( - DirectUrlValidationError, match="url must have a value" - ): + with pytest.raises(DirectUrlValidationError, match="url must have a value"): DirectUrl.from_dict({"dir_info": {}}) with pytest.raises( DirectUrlValidationError, match="missing one of archive_info, dir_info, vcs_info", ): DirectUrl.from_dict({"url": "http://..."}) - with pytest.raises( - DirectUrlValidationError, match="unexpected type for editable" - ): - DirectUrl.from_dict( - {"url": "http://...", "dir_info": {"editable": "false"}} - ) - with pytest.raises( - DirectUrlValidationError, match="unexpected type for hash" - ): + with pytest.raises(DirectUrlValidationError, match="unexpected type for editable"): + DirectUrl.from_dict({"url": "http://...", "dir_info": {"editable": "false"}}) + with pytest.raises(DirectUrlValidationError, match="unexpected type for hash"): DirectUrl.from_dict({"url": "http://...", "archive_info": {"hash": 1}}) - with pytest.raises( - DirectUrlValidationError, match="unexpected type for vcs" - ): + with pytest.raises(DirectUrlValidationError, match="unexpected type for vcs"): DirectUrl.from_dict({"url": "http://...", "vcs_info": {"vcs": None}}) - with pytest.raises( - DirectUrlValidationError, match="commit_id must have a value" - ): + with pytest.raises(DirectUrlValidationError, match="commit_id must have a value"): DirectUrl.from_dict({"url": "http://...", "vcs_info": {"vcs": "git"}}) with pytest.raises( DirectUrlValidationError, match="more than one of archive_info, dir_info, vcs_info", ): - DirectUrl.from_dict( - {"url": "http://...", "dir_info": {}, "archive_info": {}} - ) + DirectUrl.from_dict({"url": "http://...", "dir_info": {}, "archive_info": {}}) def test_redact_url(): @@ -130,22 +112,16 @@ def _redact_archive(url): return direct_url.redacted_url assert ( - _redact_git("https://user:password@g.c/u/p.git@branch#egg=pkg") == - "https://g.c/u/p.git@branch#egg=pkg" - ) - assert ( - _redact_git("https://${USER}:password@g.c/u/p.git") == - "https://g.c/u/p.git" - ) - assert ( - _redact_archive("file://${U}:${PIP_PASSWORD}@g.c/u/p.tgz") == - "file://${U}:${PIP_PASSWORD}@g.c/u/p.tgz" + _redact_git("https://user:password@g.c/u/p.git@branch#egg=pkg") + == "https://g.c/u/p.git@branch#egg=pkg" ) + assert _redact_git("https://${USER}:password@g.c/u/p.git") == "https://g.c/u/p.git" assert ( - _redact_git("https://${PIP_TOKEN}@g.c/u/p.git") == - "https://${PIP_TOKEN}@g.c/u/p.git" + _redact_archive("file://${U}:${PIP_PASSWORD}@g.c/u/p.tgz") + == "file://${U}:${PIP_PASSWORD}@g.c/u/p.tgz" ) assert ( - _redact_git("ssh://git@g.c/u/p.git") == - "ssh://git@g.c/u/p.git" + _redact_git("https://${PIP_TOKEN}@g.c/u/p.git") + == "https://${PIP_TOKEN}@g.c/u/p.git" ) + assert _redact_git("ssh://git@g.c/u/p.git") == "ssh://git@g.c/u/p.git" diff --git a/tests/unit/test_direct_url_helpers.py b/tests/unit/test_direct_url_helpers.py index 55cd5855b93..d2821cae02c 100644 --- a/tests/unit/test_direct_url_helpers.py +++ b/tests/unit/test_direct_url_helpers.py @@ -25,20 +25,20 @@ def test_as_pep440_requirement_archive(): ) direct_url.validate() assert ( - direct_url_as_pep440_direct_reference(direct_url, "pkg") == - "pkg @ file:///home/user/archive.tgz" + direct_url_as_pep440_direct_reference(direct_url, "pkg") + == "pkg @ file:///home/user/archive.tgz" ) direct_url.subdirectory = "subdir" direct_url.validate() assert ( - direct_url_as_pep440_direct_reference(direct_url, "pkg") == - "pkg @ file:///home/user/archive.tgz#subdirectory=subdir" + direct_url_as_pep440_direct_reference(direct_url, "pkg") + == "pkg @ file:///home/user/archive.tgz#subdirectory=subdir" ) direct_url.info.hash = "sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220" direct_url.validate() assert ( - direct_url_as_pep440_direct_reference(direct_url, "pkg") == - "pkg @ file:///home/user/archive.tgz" + direct_url_as_pep440_direct_reference(direct_url, "pkg") + == "pkg @ file:///home/user/archive.tgz" "#sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220&subdirectory=subdir" ) @@ -50,29 +50,27 @@ def test_as_pep440_requirement_dir(): ) direct_url.validate() assert ( - direct_url_as_pep440_direct_reference(direct_url, "pkg") == - "pkg @ file:///home/user/project" + direct_url_as_pep440_direct_reference(direct_url, "pkg") + == "pkg @ file:///home/user/project" ) def test_as_pep440_requirement_vcs(): direct_url = DirectUrl( url="https:///g.c/u/p.git", - info=VcsInfo( - vcs="git", commit_id="1b8c5bc61a86f377fea47b4276c8c8a5842d2220" - ) + info=VcsInfo(vcs="git", commit_id="1b8c5bc61a86f377fea47b4276c8c8a5842d2220"), ) direct_url.validate() assert ( - direct_url_as_pep440_direct_reference(direct_url, "pkg") == - "pkg @ git+https:///g.c/u/p.git" + direct_url_as_pep440_direct_reference(direct_url, "pkg") + == "pkg @ git+https:///g.c/u/p.git" "@1b8c5bc61a86f377fea47b4276c8c8a5842d2220" ) direct_url.subdirectory = "subdir" direct_url.validate() assert ( - direct_url_as_pep440_direct_reference(direct_url, "pkg") == - "pkg @ git+https:///g.c/u/p.git" + direct_url_as_pep440_direct_reference(direct_url, "pkg") + == "pkg @ git+https:///g.c/u/p.git" "@1b8c5bc61a86f377fea47b4276c8c8a5842d2220#subdirectory=subdir" ) @@ -94,28 +92,22 @@ def test_from_link_vcs(mock_get_backend_for_scheme): direct_url = _direct_url_from_link(Link("git+https://g.c/u/p.git@branch")) assert direct_url.url == "https://g.c/u/p.git" assert direct_url.info.requested_revision == "branch" - direct_url = _direct_url_from_link( - Link("git+https://g.c/u/p.git@branch#egg=pkg") - ) + direct_url = _direct_url_from_link(Link("git+https://g.c/u/p.git@branch#egg=pkg")) assert direct_url.url == "https://g.c/u/p.git" assert direct_url.info.requested_revision == "branch" - direct_url = _direct_url_from_link( - Link("git+https://token@g.c/u/p.git") - ) + direct_url = _direct_url_from_link(Link("git+https://token@g.c/u/p.git")) assert direct_url.to_dict()["url"] == "https://g.c/u/p.git" def test_from_link_vcs_with_source_dir_obtains_commit_id(script, tmpdir): - repo_path = tmpdir / 'test-repo' + repo_path = tmpdir / "test-repo" repo_path.mkdir() repo_dir = str(repo_path) - script.run('git', 'init', cwd=repo_dir) + script.run("git", "init", cwd=repo_dir) (repo_path / "somefile").touch() - script.run('git', 'add', '.', cwd=repo_dir) - script.run('git', 'commit', '-m', 'commit msg', cwd=repo_dir) - commit_id = script.run( - 'git', 'rev-parse', 'HEAD', cwd=repo_dir - ).stdout.strip() + script.run("git", "add", ".", cwd=repo_dir) + script.run("git", "commit", "-m", "commit msg", cwd=repo_dir) + commit_id = script.run("git", "rev-parse", "HEAD", cwd=repo_dir).stdout.strip() direct_url = direct_url_from_link( Link("git+https://g.c/u/p.git"), source_dir=repo_dir ) @@ -136,15 +128,10 @@ def test_from_link_archive(): assert direct_url.url == "https://g.c/archive.tgz" assert isinstance(direct_url.info, ArchiveInfo) direct_url = direct_url_from_link( - Link( - "https://g.c/archive.tgz" - "#sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220" - ) + Link("https://g.c/archive.tgz" "#sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220") ) assert isinstance(direct_url.info, ArchiveInfo) - assert ( - direct_url.info.hash == "sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220" - ) + assert direct_url.info.hash == "sha1=1b8c5bc61a86f377fea47b4276c8c8a5842d2220" def test_from_link_dir(tmpdir): @@ -187,9 +174,7 @@ def test_dist_get_direct_url_bad_metadata(): def test_dist_get_direct_url_valid_metadata(): dist = MagicMock() dist.has_metadata.return_value = True - dist.get_metadata.return_value = ( - '{"url": "https://e.c/p.tgz", "archive_info": {}}' - ) + dist.get_metadata.return_value = '{"url": "https://e.c/p.tgz", "archive_info": {}}' direct_url = dist_get_direct_url(dist) dist.get_metadata.assert_called_with(DIRECT_URL_METADATA_NAME) assert direct_url.url == "https://e.c/p.tgz" diff --git a/tests/unit/test_finder.py b/tests/unit/test_finder.py index 853af723b5a..739c661bb5f 100644 --- a/tests/unit/test_finder.py +++ b/tests/unit/test_finder.py @@ -8,10 +8,7 @@ from pkg_resources import parse_version import pip._internal.utils.compatibility_tags -from pip._internal.exceptions import ( - BestVersionAlreadyInstalled, - DistributionNotFound, -) +from pip._internal.exceptions import BestVersionAlreadyInstalled, DistributionNotFound from pip._internal.index.package_finder import ( CandidateEvaluator, InstallationCandidate, @@ -63,10 +60,10 @@ def test_no_partial_name_match(data): def test_tilde(): """Finder can accept a path with ~ in it and will normalize it.""" patched_exists = patch( - 'pip._internal.index.collector.os.path.exists', return_value=True + "pip._internal.index.collector.os.path.exists", return_value=True ) with patched_exists: - finder = make_test_finder(find_links=['~/python-pkgs']) + finder = make_test_finder(find_links=["~/python-pkgs"]) req = install_req_from_line("gmpy") with pytest.raises(DistributionNotFound): finder.find_requirement(req, False) @@ -84,7 +81,7 @@ def test_duplicates_sort_ok(data): def test_finder_detects_latest_find_links(data): """Test PackageFinder detects latest using find-links""" - req = install_req_from_line('simple', None) + req = install_req_from_line("simple", None) finder = make_test_finder(find_links=[data.find_links]) found = finder.find_requirement(req, False) assert found.link.url.endswith("simple-3.0.tar.gz") @@ -92,7 +89,7 @@ def test_finder_detects_latest_find_links(data): def test_incorrect_case_file_index(data): """Test PackageFinder detects latest using wrong case""" - req = install_req_from_line('dinner', None) + req = install_req_from_line("dinner", None) finder = make_test_finder(index_urls=[data.find_links3]) found = finder.find_requirement(req, False) assert found.link.url.endswith("Dinner-2.0.tar.gz") @@ -101,13 +98,13 @@ def test_incorrect_case_file_index(data): @pytest.mark.network def test_finder_detects_latest_already_satisfied_find_links(data): """Test PackageFinder detects latest already satisfied using find-links""" - req = install_req_from_line('simple', None) + req = install_req_from_line("simple", None) # the latest simple in local pkgs is 3.0 latest_version = "3.0" satisfied_by = Mock( location="/path", parsed_version=parse_version(latest_version), - version=latest_version + version=latest_version, ) req.satisfied_by = satisfied_by finder = make_test_finder(find_links=[data.find_links]) @@ -119,7 +116,7 @@ def test_finder_detects_latest_already_satisfied_find_links(data): @pytest.mark.network def test_finder_detects_latest_already_satisfied_pypi_links(): """Test PackageFinder detects latest already satisfied using pypi links""" - req = install_req_from_line('initools', None) + req = install_req_from_line("initools", None) # the latest initools on PyPI is 0.3.1 latest_version = "0.3.1" satisfied_by = Mock( @@ -135,7 +132,6 @@ def test_finder_detects_latest_already_satisfied_pypi_links(): class TestWheel: - def test_skip_invalid_wheel_link(self, caplog, data): """ Test if PackageFinder skips invalid wheel filenames @@ -148,7 +144,7 @@ def test_skip_invalid_wheel_link(self, caplog, data): with pytest.raises(DistributionNotFound): finder.find_requirement(req, True) - assert 'Skipping link: invalid wheel filename:' in caplog.text + assert "Skipping link: invalid wheel filename:" in caplog.text def test_not_find_wheel_not_supported(self, data, monkeypatch): """ @@ -173,15 +169,13 @@ def test_find_wheel_supported(self, data, monkeypatch): monkeypatch.setattr( pip._internal.utils.compatibility_tags, "get_supported", - lambda **kw: [('py2', 'none', 'any')], + lambda **kw: [("py2", "none", "any")], ) req = install_req_from_line("simple.dist") finder = make_test_finder(find_links=[data.find_links]) found = finder.find_requirement(req, True) - assert ( - found.link.url.endswith("simple.dist-0.1-py2.py3-none-any.whl") - ), found + assert found.link.url.endswith("simple.dist-0.1-py2.py3-none-any.whl"), found def test_wheel_over_sdist_priority(self, data): """ @@ -191,15 +185,14 @@ def test_wheel_over_sdist_priority(self, data): req = install_req_from_line("priority") finder = make_test_finder(find_links=[data.find_links]) found = finder.find_requirement(req, True) - assert found.link.url.endswith("priority-1.0-py2.py3-none-any.whl"), \ - found + assert found.link.url.endswith("priority-1.0-py2.py3-none-any.whl"), found def test_existing_over_wheel_priority(self, data): """ Test existing install has priority over wheels. `test_link_sorting` also covers this at a lower level """ - req = install_req_from_line('priority', None) + req = install_req_from_line("priority", None) latest_version = "1.0" satisfied_by = Mock( location="/path", @@ -217,36 +210,38 @@ def test_link_sorting(self): Test link sorting """ links = [ - InstallationCandidate("simple", "2.0", Link('simple-2.0.tar.gz')), + InstallationCandidate("simple", "2.0", Link("simple-2.0.tar.gz")), InstallationCandidate( "simple", "1.0", - Link('simple-1.0-pyT-none-TEST.whl'), + Link("simple-1.0-pyT-none-TEST.whl"), ), InstallationCandidate( "simple", - '1.0', - Link('simple-1.0-pyT-TEST-any.whl'), + "1.0", + Link("simple-1.0-pyT-TEST-any.whl"), ), InstallationCandidate( "simple", - '1.0', - Link('simple-1.0-pyT-none-any.whl'), + "1.0", + Link("simple-1.0-pyT-none-any.whl"), ), InstallationCandidate( "simple", - '1.0', - Link('simple-1.0.tar.gz'), + "1.0", + Link("simple-1.0.tar.gz"), ), ] valid_tags = [ - Tag('pyT', 'none', 'TEST'), - Tag('pyT', 'TEST', 'any'), - Tag('pyT', 'none', 'any'), + Tag("pyT", "none", "TEST"), + Tag("pyT", "TEST", "any"), + Tag("pyT", "none", "any"), ] specifier = SpecifierSet() evaluator = CandidateEvaluator( - 'my-project', supported_tags=valid_tags, specifier=specifier, + "my-project", + supported_tags=valid_tags, + specifier=specifier, ) sort_key = evaluator._sort_key results = sorted(links, key=sort_key, reverse=True) @@ -273,7 +268,7 @@ def test_link_sorting_wheels_with_build_tags(self): Link("simplewheel-1.0-py2.py3-none-any.whl"), ), ] - candidate_evaluator = CandidateEvaluator.create('my-project') + candidate_evaluator = CandidateEvaluator.create("my-project") sort_key = candidate_evaluator._sort_key results = sorted(links, key=sort_key, reverse=True) results2 = sorted(reversed(links), key=sort_key, reverse=True) @@ -282,16 +277,17 @@ def test_link_sorting_wheels_with_build_tags(self): def test_finder_priority_file_over_page(data): """Test PackageFinder prefers file links over equivalent page links""" - req = install_req_from_line('gmpy==1.15', None) + req = install_req_from_line("gmpy==1.15", None) finder = make_test_finder( find_links=[data.find_links], index_urls=["http://pypi.org/simple/"], ) all_versions = finder.find_all_candidates(req.name) # 1 file InstallationCandidate followed by all https ones - assert all_versions[0].link.scheme == 'file' - assert all(version.link.scheme == 'https' - for version in all_versions[1:]), all_versions + assert all_versions[0].link.scheme == "file" + assert all( + version.link.scheme == "https" for version in all_versions[1:] + ), all_versions found = finder.find_requirement(req, False) assert found.link.url.startswith("file://") @@ -299,27 +295,27 @@ def test_finder_priority_file_over_page(data): def test_finder_priority_nonegg_over_eggfragments(): """Test PackageFinder prefers non-egg links over "#egg=" links""" - req = install_req_from_line('bar==1.0', None) - links = ['http://foo/bar.py#egg=bar-1.0', 'http://foo/bar-1.0.tar.gz'] + req = install_req_from_line("bar==1.0", None) + links = ["http://foo/bar.py#egg=bar-1.0", "http://foo/bar-1.0.tar.gz"] finder = make_no_network_finder(links) all_versions = finder.find_all_candidates(req.name) - assert all_versions[0].link.url.endswith('tar.gz') - assert all_versions[1].link.url.endswith('#egg=bar-1.0') + assert all_versions[0].link.url.endswith("tar.gz") + assert all_versions[1].link.url.endswith("#egg=bar-1.0") found = finder.find_requirement(req, False) - assert found.link.url.endswith('tar.gz') + assert found.link.url.endswith("tar.gz") links.reverse() finder = make_no_network_finder(links) all_versions = finder.find_all_candidates(req.name) - assert all_versions[0].link.url.endswith('tar.gz') - assert all_versions[1].link.url.endswith('#egg=bar-1.0') + assert all_versions[0].link.url.endswith("tar.gz") + assert all_versions[1].link.url.endswith("#egg=bar-1.0") found = finder.find_requirement(req, False) - assert found.link.url.endswith('tar.gz') + assert found.link.url.endswith("tar.gz") def test_finder_only_installs_stable_releases(data): @@ -363,11 +359,11 @@ def test_finder_only_installs_data_require(data): finder = make_test_finder(index_urls=[data.index_url("datarequire")]) links = finder.find_all_candidates("fakepackage") - expected = ['1.0.0', '9.9.9'] + expected = ["1.0.0", "9.9.9"] if (2, 7) < sys.version_info < (3,): - expected.append('2.7.0') + expected.append("2.7.0") elif sys.version_info > (3, 3): - expected.append('3.3.0') + expected.append("3.3.0") assert {str(v.version) for v in links} == set(expected) @@ -436,83 +432,90 @@ def test_finder_installs_pre_releases_with_version_spec(): class TestLinkEvaluator(object): - def make_test_link_evaluator(self, formats): target_python = TargetPython() return LinkEvaluator( - project_name='pytest', - canonical_name='pytest', + project_name="pytest", + canonical_name="pytest", formats=formats, target_python=target_python, allow_yanked=True, ) - @pytest.mark.parametrize('url, expected_version', [ - ('http:/yo/pytest-1.0.tar.gz', '1.0'), - ('http:/yo/pytest-1.0-py2.py3-none-any.whl', '1.0'), - ]) + @pytest.mark.parametrize( + "url, expected_version", + [ + ("http:/yo/pytest-1.0.tar.gz", "1.0"), + ("http:/yo/pytest-1.0-py2.py3-none-any.whl", "1.0"), + ], + ) def test_evaluate_link__match(self, url, expected_version): """Test that 'pytest' archives match for 'pytest'""" link = Link(url) - evaluator = self.make_test_link_evaluator(formats=['source', 'binary']) + evaluator = self.make_test_link_evaluator(formats=["source", "binary"]) actual = evaluator.evaluate_link(link) assert actual == (True, expected_version) - @pytest.mark.parametrize('url, expected_msg', [ - # TODO: Uncomment this test case when #1217 is fixed. - # 'http:/yo/pytest-xdist-1.0.tar.gz', - ('http:/yo/pytest2-1.0.tar.gz', - 'Missing project version for pytest'), - ('http:/yo/pytest_xdist-1.0-py2.py3-none-any.whl', - 'wrong project name (not pytest)'), - ]) + @pytest.mark.parametrize( + "url, expected_msg", + [ + # TODO: Uncomment this test case when #1217 is fixed. + # 'http:/yo/pytest-xdist-1.0.tar.gz', + ("http:/yo/pytest2-1.0.tar.gz", "Missing project version for pytest"), + ( + "http:/yo/pytest_xdist-1.0-py2.py3-none-any.whl", + "wrong project name (not pytest)", + ), + ], + ) def test_evaluate_link__substring_fails(self, url, expected_msg): """Test that 'pytest archives won't match for 'pytest'.""" link = Link(url) - evaluator = self.make_test_link_evaluator(formats=['source', 'binary']) + evaluator = self.make_test_link_evaluator(formats=["source", "binary"]) actual = evaluator.evaluate_link(link) assert actual == (False, expected_msg) def test_process_project_url(data): - project_name = 'simple' - index_url = data.index_url('simple') - project_url = Link('{}/{}'.format(index_url, project_name)) + project_name = "simple" + index_url = data.index_url("simple") + project_url = Link("{}/{}".format(index_url, project_name)) finder = make_test_finder(index_urls=[index_url]) link_evaluator = finder.make_link_evaluator(project_name) actual = finder.process_project_url( - project_url, link_evaluator=link_evaluator, + project_url, + link_evaluator=link_evaluator, ) assert len(actual) == 1 package_link = actual[0] - assert package_link.name == 'simple' - assert str(package_link.version) == '1.0' + assert package_link.name == "simple" + assert str(package_link.version) == "1.0" def test_find_all_candidates_nothing(): """Find nothing without anything""" finder = make_test_finder() - assert not finder.find_all_candidates('pip') + assert not finder.find_all_candidates("pip") def test_find_all_candidates_find_links(data): finder = make_test_finder(find_links=[data.find_links]) - versions = finder.find_all_candidates('simple') - assert [str(v.version) for v in versions] == ['3.0', '2.0', '1.0'] + versions = finder.find_all_candidates("simple") + assert [str(v.version) for v in versions] == ["3.0", "2.0", "1.0"] def test_find_all_candidates_index(data): - finder = make_test_finder(index_urls=[data.index_url('simple')]) - versions = finder.find_all_candidates('simple') - assert [str(v.version) for v in versions] == ['1.0'] + finder = make_test_finder(index_urls=[data.index_url("simple")]) + versions = finder.find_all_candidates("simple") + assert [str(v.version) for v in versions] == ["1.0"] def test_find_all_candidates_find_links_and_index(data): finder = make_test_finder( find_links=[data.find_links], - index_urls=[data.index_url('simple')], + index_urls=[data.index_url("simple")], ) - versions = finder.find_all_candidates('simple') + versions = finder.find_all_candidates("simple") # first the find-links versions then the page versions - assert [str(v.version) for v in versions] == ['3.0', '2.0', '1.0', '1.0'] + assert [str(v.version) for v in versions] == ["3.0", "2.0", "1.0", "1.0"] diff --git a/tests/unit/test_format_control.py b/tests/unit/test_format_control.py index 0e152798184..6118d3a7c13 100644 --- a/tests/unit/test_format_control.py +++ b/tests/unit/test_format_control.py @@ -6,9 +6,8 @@ class SimpleCommand(Command): - def __init__(self): - super(SimpleCommand, self).__init__('fake', 'fake summary') + super(SimpleCommand, self).__init__("fake", "fake summary") def add_options(self): self.cmd_opts.add_option(cmdoptions.no_binary()) @@ -20,38 +19,36 @@ def run(self, options, args): def test_no_binary_overrides(): cmd = SimpleCommand() - cmd.main(['fake', '--only-binary=:all:', '--no-binary=fred']) - format_control = FormatControl({'fred'}, {':all:'}) + cmd.main(["fake", "--only-binary=:all:", "--no-binary=fred"]) + format_control = FormatControl({"fred"}, {":all:"}) assert cmd.options.format_control == format_control def test_only_binary_overrides(): cmd = SimpleCommand() - cmd.main(['fake', '--no-binary=:all:', '--only-binary=fred']) - format_control = FormatControl({':all:'}, {'fred'}) + cmd.main(["fake", "--no-binary=:all:", "--only-binary=fred"]) + format_control = FormatControl({":all:"}, {"fred"}) assert cmd.options.format_control == format_control def test_none_resets(): cmd = SimpleCommand() - cmd.main(['fake', '--no-binary=:all:', '--no-binary=:none:']) + cmd.main(["fake", "--no-binary=:all:", "--no-binary=:none:"]) format_control = FormatControl(set(), set()) assert cmd.options.format_control == format_control def test_none_preserves_other_side(): cmd = SimpleCommand() - cmd.main( - ['fake', '--no-binary=:all:', '--only-binary=fred', - '--no-binary=:none:']) - format_control = FormatControl(set(), {'fred'}) + cmd.main(["fake", "--no-binary=:all:", "--only-binary=fred", "--no-binary=:none:"]) + format_control = FormatControl(set(), {"fred"}) assert cmd.options.format_control == format_control def test_comma_separated_values(): cmd = SimpleCommand() - cmd.main(['fake', '--no-binary=1,2,3']) - format_control = FormatControl({'1', '2', '3'}, set()) + cmd.main(["fake", "--no-binary=1,2,3"]) + format_control = FormatControl({"1", "2", "3"}, set()) assert cmd.options.format_control == format_control @@ -61,8 +58,8 @@ def test_comma_separated_values(): ({"fred"}, set(), "fred", frozenset(["source"])), ({"fred"}, {":all:"}, "fred", frozenset(["source"])), (set(), {"fred"}, "fred", frozenset(["binary"])), - ({":all:"}, {"fred"}, "fred", frozenset(["binary"])) - ] + ({":all:"}, {"fred"}, "fred", frozenset(["binary"])), + ], ) def test_fmt_ctl_matches(no_binary, only_binary, argument, expected): fmt = FormatControl(no_binary, only_binary) diff --git a/tests/unit/test_index.py b/tests/unit/test_index.py index 2ae847ae0b7..b1958ac325d 100644 --- a/tests/unit/test_index.py +++ b/tests/unit/test_index.py @@ -26,15 +26,18 @@ from tests.lib.index import make_mock_candidate -@pytest.mark.parametrize('requires_python, expected', [ - ('== 3.6.4', False), - ('== 3.6.5', True), - # Test an invalid Requires-Python value. - ('invalid', True), -]) +@pytest.mark.parametrize( + "requires_python, expected", + [ + ("== 3.6.4", False), + ("== 3.6.5", True), + # Test an invalid Requires-Python value. + ("invalid", True), + ], +) def test_check_link_requires_python(requires_python, expected): version_info = (3, 6, 5) - link = Link('https://example.com', requires_python=requires_python) + link = Link("https://example.com", requires_python=requires_python) actual = _check_link_requires_python(link, version_info) assert actual == expected @@ -46,29 +49,43 @@ def check_caplog(caplog, expected_level, expected_message): assert record.message == expected_message -@pytest.mark.parametrize('ignore_requires_python, expected', [ - (None, ( - False, 'DEBUG', - "Link requires a different Python (3.6.5 not in: '== 3.6.4'): " - "https://example.com" - )), - (True, ( - True, 'DEBUG', - "Ignoring failed Requires-Python check (3.6.5 not in: '== 3.6.4') " - "for link: https://example.com" - )), -]) +@pytest.mark.parametrize( + "ignore_requires_python, expected", + [ + ( + None, + ( + False, + "DEBUG", + "Link requires a different Python (3.6.5 not in: '== 3.6.4'): " + "https://example.com", + ), + ), + ( + True, + ( + True, + "DEBUG", + "Ignoring failed Requires-Python check (3.6.5 not in: '== 3.6.4') " + "for link: https://example.com", + ), + ), + ], +) def test_check_link_requires_python__incompatible_python( - caplog, ignore_requires_python, expected, + caplog, + ignore_requires_python, + expected, ): """ Test an incompatible Python. """ expected_return, expected_level, expected_message = expected - link = Link('https://example.com', requires_python='== 3.6.4') + link = Link("https://example.com", requires_python="== 3.6.4") caplog.set_level(logging.DEBUG) actual = _check_link_requires_python( - link, version_info=(3, 6, 5), + link, + version_info=(3, 6, 5), ignore_requires_python=ignore_requires_python, ) assert actual == expected_return @@ -80,74 +97,84 @@ def test_check_link_requires_python__invalid_requires(caplog): """ Test the log message for an invalid Requires-Python. """ - link = Link('https://example.com', requires_python='invalid') + link = Link("https://example.com", requires_python="invalid") caplog.set_level(logging.DEBUG) actual = _check_link_requires_python(link, version_info=(3, 6, 5)) assert actual expected_message = ( - "Ignoring invalid Requires-Python ('invalid') for link: " - "https://example.com" + "Ignoring invalid Requires-Python ('invalid') for link: " "https://example.com" ) - check_caplog(caplog, 'DEBUG', expected_message) + check_caplog(caplog, "DEBUG", expected_message) class TestLinkEvaluator: - @pytest.mark.parametrize( - 'py_version_info,ignore_requires_python,expected', [ - ((3, 6, 5), None, (True, '1.12')), + "py_version_info,ignore_requires_python,expected", + [ + ((3, 6, 5), None, (True, "1.12")), # Test an incompatible Python. ((3, 6, 4), None, (False, None)), # Test an incompatible Python with ignore_requires_python=True. - ((3, 6, 4), True, (True, '1.12')), + ((3, 6, 4), True, (True, "1.12")), ], ) def test_evaluate_link( - self, py_version_info, ignore_requires_python, expected, + self, + py_version_info, + ignore_requires_python, + expected, ): target_python = TargetPython(py_version_info=py_version_info) evaluator = LinkEvaluator( - project_name='twine', - canonical_name='twine', - formats={'source'}, + project_name="twine", + canonical_name="twine", + formats={"source"}, target_python=target_python, allow_yanked=True, ignore_requires_python=ignore_requires_python, ) link = Link( - 'https://example.com/#egg=twine-1.12', - requires_python='== 3.6.5', + "https://example.com/#egg=twine-1.12", + requires_python="== 3.6.5", ) actual = evaluator.evaluate_link(link) assert actual == expected - @pytest.mark.parametrize('yanked_reason, allow_yanked, expected', [ - (None, True, (True, '1.12')), - (None, False, (True, '1.12')), - ('', True, (True, '1.12')), - ('', False, (False, 'yanked for reason: ')), - ('bad metadata', True, (True, '1.12')), - ('bad metadata', False, - (False, 'yanked for reason: bad metadata')), - # Test a unicode string with a non-ascii character. - (u'curly quote: \u2018', True, (True, '1.12')), - (u'curly quote: \u2018', False, - (False, u'yanked for reason: curly quote: \u2018')), - ]) + @pytest.mark.parametrize( + "yanked_reason, allow_yanked, expected", + [ + (None, True, (True, "1.12")), + (None, False, (True, "1.12")), + ("", True, (True, "1.12")), + ("", False, (False, "yanked for reason: ")), + ("bad metadata", True, (True, "1.12")), + ("bad metadata", False, (False, "yanked for reason: bad metadata")), + # Test a unicode string with a non-ascii character. + (u"curly quote: \u2018", True, (True, "1.12")), + ( + u"curly quote: \u2018", + False, + (False, u"yanked for reason: curly quote: \u2018"), + ), + ], + ) def test_evaluate_link__allow_yanked( - self, yanked_reason, allow_yanked, expected, + self, + yanked_reason, + allow_yanked, + expected, ): target_python = TargetPython(py_version_info=(3, 6, 4)) evaluator = LinkEvaluator( - project_name='twine', - canonical_name='twine', - formats={'source'}, + project_name="twine", + canonical_name="twine", + formats={"source"}, target_python=target_python, allow_yanked=allow_yanked, ) link = Link( - 'https://example.com/#egg=twine-1.12', + "https://example.com/#egg=twine-1.12", yanked_reason=yanked_reason, ) actual = evaluator.evaluate_link(link) @@ -161,38 +188,41 @@ def test_evaluate_link__incompatible_wheel(self): # Set the valid tags to an empty list to make sure nothing matches. target_python._valid_tags = [] evaluator = LinkEvaluator( - project_name='sample', - canonical_name='sample', - formats={'binary'}, + project_name="sample", + canonical_name="sample", + formats={"binary"}, target_python=target_python, allow_yanked=True, ) - link = Link('https://example.com/sample-1.0-py2.py3-none-any.whl') + link = Link("https://example.com/sample-1.0-py2.py3-none-any.whl") actual = evaluator.evaluate_link(link) - expected = ( - False, "none of the wheel's tags match: py2-none-any, py3-none-any" - ) + expected = (False, "none of the wheel's tags match: py2-none-any, py3-none-any") assert actual == expected -@pytest.mark.parametrize('hex_digest, expected_versions', [ - (None, ['1.0', '1.1', '1.2']), - (64 * 'a', ['1.0', '1.1']), - (64 * 'b', ['1.0', '1.2']), - (64 * 'c', ['1.0', '1.1', '1.2']), -]) +@pytest.mark.parametrize( + "hex_digest, expected_versions", + [ + (None, ["1.0", "1.1", "1.2"]), + (64 * "a", ["1.0", "1.1"]), + (64 * "b", ["1.0", "1.2"]), + (64 * "c", ["1.0", "1.1", "1.2"]), + ], +) def test_filter_unallowed_hashes(hex_digest, expected_versions): candidates = [ - make_mock_candidate('1.0'), - make_mock_candidate('1.1', hex_digest=(64 * 'a')), - make_mock_candidate('1.2', hex_digest=(64 * 'b')), + make_mock_candidate("1.0"), + make_mock_candidate("1.1", hex_digest=(64 * "a")), + make_mock_candidate("1.2", hex_digest=(64 * "b")), ] hashes_data = { - 'sha256': [hex_digest], + "sha256": [hex_digest], } hashes = Hashes(hashes_data) actual = filter_unallowed_hashes( - candidates, hashes=hashes, project_name='my-project', + candidates, + hashes=hashes, + project_name="my-project", ) actual_versions = [str(candidate.version) for candidate in actual] @@ -205,11 +235,13 @@ def test_filter_unallowed_hashes__no_hashes(caplog): caplog.set_level(logging.DEBUG) candidates = [ - make_mock_candidate('1.0'), - make_mock_candidate('1.1'), + make_mock_candidate("1.0"), + make_mock_candidate("1.1"), ] actual = filter_unallowed_hashes( - candidates, hashes=Hashes(), project_name='my-project', + candidates, + hashes=Hashes(), + project_name="my-project", ) # Check that the return value is a copy. @@ -220,7 +252,7 @@ def test_filter_unallowed_hashes__no_hashes(caplog): "Given no hashes to check 2 links for project 'my-project': " "discarding no candidates" ) - check_caplog(caplog, 'DEBUG', expected_message) + check_caplog(caplog, "DEBUG", expected_message) def test_filter_unallowed_hashes__log_message_with_match(caplog): @@ -229,19 +261,25 @@ def test_filter_unallowed_hashes__log_message_with_match(caplog): # Test 1 match, 2 non-matches, 3 no hashes so all 3 values will be # different. candidates = [ - make_mock_candidate('1.0'), - make_mock_candidate('1.1',), - make_mock_candidate('1.2',), - make_mock_candidate('1.3', hex_digest=(64 * 'a')), - make_mock_candidate('1.4', hex_digest=(64 * 'b')), - make_mock_candidate('1.5', hex_digest=(64 * 'c')), + make_mock_candidate("1.0"), + make_mock_candidate( + "1.1", + ), + make_mock_candidate( + "1.2", + ), + make_mock_candidate("1.3", hex_digest=(64 * "a")), + make_mock_candidate("1.4", hex_digest=(64 * "b")), + make_mock_candidate("1.5", hex_digest=(64 * "c")), ] hashes_data = { - 'sha256': [64 * 'a', 64 * 'd'], + "sha256": [64 * "a", 64 * "d"], } hashes = Hashes(hashes_data) actual = filter_unallowed_hashes( - candidates, hashes=hashes, project_name='my-project', + candidates, + hashes=hashes, + project_name="my-project", ) assert len(actual) == 4 @@ -253,23 +291,25 @@ def test_filter_unallowed_hashes__log_message_with_match(caplog): " https://example.com/pkg-1.5.tar.gz#sha256=" "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" ) - check_caplog(caplog, 'DEBUG', expected_message) + check_caplog(caplog, "DEBUG", expected_message) def test_filter_unallowed_hashes__log_message_with_no_match(caplog): caplog.set_level(logging.DEBUG) candidates = [ - make_mock_candidate('1.0'), - make_mock_candidate('1.1', hex_digest=(64 * 'b')), - make_mock_candidate('1.2', hex_digest=(64 * 'c')), + make_mock_candidate("1.0"), + make_mock_candidate("1.1", hex_digest=(64 * "b")), + make_mock_candidate("1.2", hex_digest=(64 * "c")), ] hashes_data = { - 'sha256': [64 * 'a', 64 * 'd'], + "sha256": [64 * "a", 64 * "d"], } hashes = Hashes(hashes_data) actual = filter_unallowed_hashes( - candidates, hashes=hashes, project_name='my-project', + candidates, + hashes=hashes, + project_name="my-project", ) assert len(actual) == 3 @@ -277,23 +317,25 @@ def test_filter_unallowed_hashes__log_message_with_no_match(caplog): "Checked 3 links for project 'my-project' against 2 hashes " "(0 matches, 1 no digest): discarding no candidates" ) - check_caplog(caplog, 'DEBUG', expected_message) + check_caplog(caplog, "DEBUG", expected_message) class TestCandidateEvaluator: - - @pytest.mark.parametrize('allow_all_prereleases, prefer_binary', [ - (False, False), - (False, True), - (True, False), - (True, True), - ]) + @pytest.mark.parametrize( + "allow_all_prereleases, prefer_binary", + [ + (False, False), + (False, True), + (True, False), + (True, True), + ], + ) def test_create(self, allow_all_prereleases, prefer_binary): target_python = TargetPython() - target_python._valid_tags = [('py36', 'none', 'any')] + target_python._valid_tags = [("py36", "none", "any")] specifier = SpecifierSet() evaluator = CandidateEvaluator.create( - project_name='my-project', + project_name="my-project", target_python=target_python, allow_all_prereleases=allow_all_prereleases, prefer_binary=prefer_binary, @@ -302,13 +344,13 @@ def test_create(self, allow_all_prereleases, prefer_binary): assert evaluator._allow_all_prereleases == allow_all_prereleases assert evaluator._prefer_binary == prefer_binary assert evaluator._specifier is specifier - assert evaluator._supported_tags == [('py36', 'none', 'any')] + assert evaluator._supported_tags == [("py36", "none", "any")] def test_create__target_python_none(self): """ Test passing target_python=None. """ - evaluator = CandidateEvaluator.create('my-project') + evaluator = CandidateEvaluator.create("my-project") expected_tags = get_supported() assert evaluator._supported_tags == expected_tags @@ -316,52 +358,55 @@ def test_create__specifier_none(self): """ Test passing specifier=None. """ - evaluator = CandidateEvaluator.create('my-project') + evaluator = CandidateEvaluator.create("my-project") expected_specifier = SpecifierSet() assert evaluator._specifier == expected_specifier def test_get_applicable_candidates(self): - specifier = SpecifierSet('<= 1.11') - versions = ['1.10', '1.11', '1.12'] - candidates = [ - make_mock_candidate(version) for version in versions - ] + specifier = SpecifierSet("<= 1.11") + versions = ["1.10", "1.11", "1.12"] + candidates = [make_mock_candidate(version) for version in versions] evaluator = CandidateEvaluator.create( - 'my-project', + "my-project", specifier=specifier, ) actual = evaluator.get_applicable_candidates(candidates) expected_applicable = candidates[:2] assert [str(c.version) for c in expected_applicable] == [ - '1.10', - '1.11', + "1.10", + "1.11", ] assert actual == expected_applicable - @pytest.mark.parametrize('specifier, expected_versions', [ - # Test no version constraint. - (SpecifierSet(), ['1.0', '1.2']), - # Test a version constraint that excludes the candidate whose - # hash matches. Then the non-allowed hash is a candidate. - (SpecifierSet('<= 1.1'), ['1.0', '1.1']), - ]) + @pytest.mark.parametrize( + "specifier, expected_versions", + [ + # Test no version constraint. + (SpecifierSet(), ["1.0", "1.2"]), + # Test a version constraint that excludes the candidate whose + # hash matches. Then the non-allowed hash is a candidate. + (SpecifierSet("<= 1.1"), ["1.0", "1.1"]), + ], + ) def test_get_applicable_candidates__hashes( - self, specifier, expected_versions, + self, + specifier, + expected_versions, ): """ Test a non-None hashes value. """ candidates = [ - make_mock_candidate('1.0'), - make_mock_candidate('1.1', hex_digest=(64 * 'a')), - make_mock_candidate('1.2', hex_digest=(64 * 'b')), + make_mock_candidate("1.0"), + make_mock_candidate("1.1", hex_digest=(64 * "a")), + make_mock_candidate("1.2", hex_digest=(64 * "b")), ] hashes_data = { - 'sha256': [64 * 'b'], + "sha256": [64 * "b"], } hashes = Hashes(hashes_data) evaluator = CandidateEvaluator.create( - 'my-project', + "my-project", specifier=specifier, hashes=hashes, ) @@ -370,13 +415,11 @@ def test_get_applicable_candidates__hashes( assert actual_versions == expected_versions def test_compute_best_candidate(self): - specifier = SpecifierSet('<= 1.11') - versions = ['1.10', '1.11', '1.12'] - candidates = [ - make_mock_candidate(version) for version in versions - ] + specifier = SpecifierSet("<= 1.11") + versions = ["1.10", "1.11", "1.12"] + candidates = [make_mock_candidate(version) for version in versions] evaluator = CandidateEvaluator.create( - 'my-project', + "my-project", specifier=specifier, ) result = evaluator.compute_best_candidate(candidates) @@ -384,8 +427,8 @@ def test_compute_best_candidate(self): assert result._candidates == candidates expected_applicable = candidates[:2] assert [str(c.version) for c in expected_applicable] == [ - '1.10', - '1.11', + "1.10", + "1.11", ] assert result._applicable_candidates == expected_applicable @@ -395,13 +438,11 @@ def test_compute_best_candidate__none_best(self): """ Test returning a None best candidate. """ - specifier = SpecifierSet('<= 1.10') - versions = ['1.11', '1.12'] - candidates = [ - make_mock_candidate(version) for version in versions - ] + specifier = SpecifierSet("<= 1.10") + versions = ["1.11", "1.12"] + candidates = [make_mock_candidate(version) for version in versions] evaluator = CandidateEvaluator.create( - 'my-project', + "my-project", specifier=specifier, ) result = evaluator.compute_best_candidate(candidates) @@ -410,41 +451,47 @@ def test_compute_best_candidate__none_best(self): assert result._applicable_candidates == [] assert result.best_candidate is None - @pytest.mark.parametrize('hex_digest, expected', [ - # Test a link with no hash. - (None, 0), - # Test a link with an allowed hash. - (64 * 'a', 1), - # Test a link with a hash that isn't allowed. - (64 * 'b', 0), - ]) + @pytest.mark.parametrize( + "hex_digest, expected", + [ + # Test a link with no hash. + (None, 0), + # Test a link with an allowed hash. + (64 * "a", 1), + # Test a link with a hash that isn't allowed. + (64 * "b", 0), + ], + ) def test_sort_key__hash(self, hex_digest, expected): """ Test the effect of the link's hash on _sort_key()'s return value. """ - candidate = make_mock_candidate('1.0', hex_digest=hex_digest) + candidate = make_mock_candidate("1.0", hex_digest=hex_digest) hashes_data = { - 'sha256': [64 * 'a'], + "sha256": [64 * "a"], } hashes = Hashes(hashes_data) - evaluator = CandidateEvaluator.create('my-project', hashes=hashes) + evaluator = CandidateEvaluator.create("my-project", hashes=hashes) sort_value = evaluator._sort_key(candidate) # The hash is reflected in the first element of the tuple. actual = sort_value[0] assert actual == expected - @pytest.mark.parametrize('yanked_reason, expected', [ - # Test a non-yanked file. - (None, 0), - # Test a yanked file (has a lower value than non-yanked). - ('bad metadata', -1), - ]) + @pytest.mark.parametrize( + "yanked_reason, expected", + [ + # Test a non-yanked file. + (None, 0), + # Test a yanked file (has a lower value than non-yanked). + ("bad metadata", -1), + ], + ) def test_sort_key__is_yanked(self, yanked_reason, expected): """ Test the effect of is_yanked on _sort_key()'s return value. """ - candidate = make_mock_candidate('1.0', yanked_reason=yanked_reason) - evaluator = CandidateEvaluator.create('my-project') + candidate = make_mock_candidate("1.0", yanked_reason=yanked_reason) + evaluator = CandidateEvaluator.create("my-project") sort_value = evaluator._sort_key(candidate) # Yanked / non-yanked is reflected in the second element of the tuple. actual = sort_value[1] @@ -454,44 +501,49 @@ def test_sort_best_candidate__no_candidates(self): """ Test passing an empty list. """ - evaluator = CandidateEvaluator.create('my-project') + evaluator = CandidateEvaluator.create("my-project") actual = evaluator.sort_best_candidate([]) assert actual is None def test_sort_best_candidate__best_yanked_but_not_all( - self, caplog, + self, + caplog, ): """ Test the best candidates being yanked, but not all. """ caplog.set_level(logging.INFO) candidates = [ - make_mock_candidate('4.0', yanked_reason='bad metadata #4'), + make_mock_candidate("4.0", yanked_reason="bad metadata #4"), # Put the best candidate in the middle, to test sorting. - make_mock_candidate('2.0'), - make_mock_candidate('3.0', yanked_reason='bad metadata #3'), - make_mock_candidate('1.0'), + make_mock_candidate("2.0"), + make_mock_candidate("3.0", yanked_reason="bad metadata #3"), + make_mock_candidate("1.0"), ] expected_best = candidates[1] - evaluator = CandidateEvaluator.create('my-project') + evaluator = CandidateEvaluator.create("my-project") actual = evaluator.sort_best_candidate(candidates) assert actual is expected_best - assert str(actual.version) == '2.0' + assert str(actual.version) == "2.0" # Check the log messages. assert len(caplog.records) == 0 class TestPackageFinder: - - @pytest.mark.parametrize('allow_all_prereleases, prefer_binary', [ - (False, False), - (False, True), - (True, False), - (True, True), - ]) + @pytest.mark.parametrize( + "allow_all_prereleases, prefer_binary", + [ + (False, False), + (False, True), + (True, False), + (True, True), + ], + ) def test_create__candidate_prefs( - self, allow_all_prereleases, prefer_binary, + self, + allow_all_prereleases, + prefer_binary, ): """ Test that the _candidate_prefs attribute is set correctly. @@ -566,7 +618,7 @@ def test_create__target_python_none(self): assert actual_target_python._given_py_version_info is None assert actual_target_python.py_version_info == CURRENT_PY_VERSION_INFO - @pytest.mark.parametrize('allow_yanked', [False, True]) + @pytest.mark.parametrize("allow_yanked", [False, True]) def test_create__allow_yanked(self, allow_yanked): """ Test that the _allow_yanked attribute is set correctly. @@ -582,7 +634,7 @@ def test_create__allow_yanked(self, allow_yanked): ) assert finder._allow_yanked == allow_yanked - @pytest.mark.parametrize('ignore_requires_python', [False, True]) + @pytest.mark.parametrize("ignore_requires_python", [False, True]) def test_create__ignore_requires_python(self, ignore_requires_python): """ Test that the _ignore_requires_python attribute is set correctly. @@ -609,7 +661,7 @@ def test_create__format_control(self): session=PipSession(), search_scope=SearchScope([], []), ) - format_control = FormatControl(set(), {':all:'}) + format_control = FormatControl(set(), {":all:"}) selection_prefs = SelectionPreferences( allow_yanked=True, format_control=format_control, @@ -621,22 +673,25 @@ def test_create__format_control(self): actual_format_control = finder.format_control assert actual_format_control is format_control # Check that the attributes weren't reset. - assert actual_format_control.only_binary == {':all:'} + assert actual_format_control.only_binary == {":all:"} @pytest.mark.parametrize( - 'allow_yanked, ignore_requires_python, only_binary, expected_formats', + "allow_yanked, ignore_requires_python, only_binary, expected_formats", [ - (False, False, {}, frozenset({'binary', 'source'})), + (False, False, {}, frozenset({"binary", "source"})), # Test allow_yanked=True. - (True, False, {}, frozenset({'binary', 'source'})), + (True, False, {}, frozenset({"binary", "source"})), # Test ignore_requires_python=True. - (False, True, {}, frozenset({'binary', 'source'})), + (False, True, {}, frozenset({"binary", "source"})), # Test a non-trivial only_binary. - (False, False, {'twine'}, frozenset({'binary'})), - ] + (False, False, {"twine"}, frozenset({"binary"})), + ], ) def test_make_link_evaluator( - self, allow_yanked, ignore_requires_python, only_binary, + self, + allow_yanked, + ignore_requires_python, + only_binary, expected_formats, ): # Create a test TargetPython that we can check for. @@ -657,10 +712,10 @@ def test_make_link_evaluator( ) # Pass a project_name that will be different from canonical_name. - link_evaluator = finder.make_link_evaluator('Twine') + link_evaluator = finder.make_link_evaluator("Twine") - assert link_evaluator.project_name == 'Twine' - assert link_evaluator._canonical_name == 'twine' + assert link_evaluator.project_name == "Twine" + assert link_evaluator._canonical_name == "twine" assert link_evaluator._allow_yanked == allow_yanked assert link_evaluator._ignore_requires_python == ignore_requires_python assert link_evaluator._formats == expected_formats @@ -673,17 +728,22 @@ def test_make_link_evaluator( assert actual_target_python._given_py_version_info == (3, 7) assert actual_target_python.py_version_info == (3, 7, 0) - @pytest.mark.parametrize('allow_all_prereleases, prefer_binary', [ - (False, False), - (False, True), - (True, False), - (True, True), - ]) + @pytest.mark.parametrize( + "allow_all_prereleases, prefer_binary", + [ + (False, False), + (False, True), + (True, False), + (True, True), + ], + ) def test_make_candidate_evaluator( - self, allow_all_prereleases, prefer_binary, + self, + allow_all_prereleases, + prefer_binary, ): target_python = TargetPython() - target_python._valid_tags = [('py36', 'none', 'any')] + target_python._valid_tags = [("py36", "none", "any")] candidate_prefs = CandidatePreferences( prefer_binary=prefer_binary, allow_all_prereleases=allow_all_prereleases, @@ -701,18 +761,18 @@ def test_make_candidate_evaluator( specifier = SpecifierSet() # Pass hashes to check that _hashes is set. - hashes = Hashes({'sha256': [64 * 'a']}) + hashes = Hashes({"sha256": [64 * "a"]}) evaluator = finder.make_candidate_evaluator( - 'my-project', + "my-project", specifier=specifier, hashes=hashes, ) assert evaluator._allow_all_prereleases == allow_all_prereleases assert evaluator._hashes == hashes assert evaluator._prefer_binary == prefer_binary - assert evaluator._project_name == 'my-project' + assert evaluator._project_name == "my-project" assert evaluator._specifier is specifier - assert evaluator._supported_tags == [('py36', 'none', 'any')] + assert evaluator._supported_tags == [("py36", "none", "any")] @pytest.mark.parametrize( @@ -721,26 +781,21 @@ def test_make_candidate_evaluator( # Trivial. ("pip-18.0", "pip", 3), ("zope-interface-4.5.0", "zope-interface", 14), - # Canonicalized name match non-canonicalized egg info. (pypa/pip#5870) ("Jinja2-2.10", "jinja2", 6), ("zope.interface-4.5.0", "zope-interface", 14), ("zope_interface-4.5.0", "zope-interface", 14), - # Should be smart enough to parse ambiguous names from the provided # package name. ("foo-2-2", "foo", 3), ("foo-2-2", "foo-2", 5), - # Should be able to detect collapsed characters in the egg info. ("foo--bar-1.0", "foo-bar", 8), ("foo-_bar-1.0", "foo-bar", 8), - # The package name must not ends with a dash (PEP 508), so the first # dash would be the separator, not the second. ("zope.interface--4.5.0", "zope-interface", 14), ("zope.interface--", "zope-interface", 14), - # The version part is missing, but the split function does not care. ("zope.interface-", "zope-interface", 14), ], @@ -773,23 +828,19 @@ def test_find_name_version_sep_failure(fragment, canonical_name): # Trivial. ("pip-18.0", "pip", "18.0"), ("zope-interface-4.5.0", "zope-interface", "4.5.0"), - # Canonicalized name match non-canonicalized egg info. (pypa/pip#5870) ("Jinja2-2.10", "jinja2", "2.10"), ("zope.interface-4.5.0", "zope-interface", "4.5.0"), ("zope_interface-4.5.0", "zope-interface", "4.5.0"), - # Should be smart enough to parse ambiguous names from the provided # package name. ("foo-2-2", "foo", "2-2"), ("foo-2-2", "foo-2", "2"), ("zope.interface--4.5.0", "zope-interface", "-4.5.0"), ("zope.interface--", "zope-interface", "-"), - # Should be able to detect collapsed characters in the egg info. ("foo--bar-1.0", "foo-bar", "1.0"), ("foo-_bar-1.0", "foo-bar", "1.0"), - # Invalid. ("the-package-name-8.19", "does-not-match", None), ("zope.interface.-4.5.0", "zope.interface", None), diff --git a/tests/unit/test_link.py b/tests/unit/test_link.py index a9e75e38bd3..ac7aa40590f 100644 --- a/tests/unit/test_link.py +++ b/tests/unit/test_link.py @@ -5,136 +5,151 @@ class TestLink: - - @pytest.mark.parametrize('url, expected', [ - ( - 'https://user:password@example.com/path/page.html', - '', - ), - ]) + @pytest.mark.parametrize( + "url, expected", + [ + ( + "https://user:password@example.com/path/page.html", + "", + ), + ], + ) def test_repr(self, url, expected): link = Link(url) assert repr(link) == expected - @pytest.mark.parametrize('url, expected', [ - ('http://yo/wheel.whl', 'wheel.whl'), - ('http://yo/wheel', 'wheel'), - ('https://example.com/path/page.html', 'page.html'), - # Test a quoted character. - ('https://example.com/path/page%231.html', 'page#1.html'), - ( - 'http://yo/myproject-1.0%2Bfoobar.0-py2.py3-none-any.whl', - 'myproject-1.0+foobar.0-py2.py3-none-any.whl', - ), - # Test a path that ends in a slash. - ('https://example.com/path/', 'path'), - ('https://example.com/path//', 'path'), - # Test a url with no filename. - ('https://example.com/', 'example.com'), - # Test a url with no filename and with auth information. - ( - 'https://user:password@example.com/', - 'example.com', - ), - ]) + @pytest.mark.parametrize( + "url, expected", + [ + ("http://yo/wheel.whl", "wheel.whl"), + ("http://yo/wheel", "wheel"), + ("https://example.com/path/page.html", "page.html"), + # Test a quoted character. + ("https://example.com/path/page%231.html", "page#1.html"), + ( + "http://yo/myproject-1.0%2Bfoobar.0-py2.py3-none-any.whl", + "myproject-1.0+foobar.0-py2.py3-none-any.whl", + ), + # Test a path that ends in a slash. + ("https://example.com/path/", "path"), + ("https://example.com/path//", "path"), + # Test a url with no filename. + ("https://example.com/", "example.com"), + # Test a url with no filename and with auth information. + ( + "https://user:password@example.com/", + "example.com", + ), + ], + ) def test_filename(self, url, expected): link = Link(url) assert link.filename == expected def test_splitext(self): - assert ('wheel', '.whl') == Link('http://yo/wheel.whl').splitext() + assert ("wheel", ".whl") == Link("http://yo/wheel.whl").splitext() def test_no_ext(self): - assert '' == Link('http://yo/wheel').ext + assert "" == Link("http://yo/wheel").ext def test_ext(self): - assert '.whl' == Link('http://yo/wheel.whl').ext + assert ".whl" == Link("http://yo/wheel.whl").ext def test_ext_fragment(self): - assert '.whl' == Link('http://yo/wheel.whl#frag').ext + assert ".whl" == Link("http://yo/wheel.whl#frag").ext def test_ext_query(self): - assert '.whl' == Link('http://yo/wheel.whl?a=b').ext + assert ".whl" == Link("http://yo/wheel.whl?a=b").ext def test_is_wheel(self): - assert Link('http://yo/wheel.whl').is_wheel + assert Link("http://yo/wheel.whl").is_wheel def test_is_wheel_false(self): - assert not Link('http://yo/not_a_wheel').is_wheel + assert not Link("http://yo/not_a_wheel").is_wheel def test_fragments(self): - url = 'git+https://example.com/package#egg=eggname' - assert 'eggname' == Link(url).egg_fragment + url = "git+https://example.com/package#egg=eggname" + assert "eggname" == Link(url).egg_fragment assert None is Link(url).subdirectory_fragment - url = 'git+https://example.com/package#egg=eggname&subdirectory=subdir' - assert 'eggname' == Link(url).egg_fragment - assert 'subdir' == Link(url).subdirectory_fragment - url = 'git+https://example.com/package#subdirectory=subdir&egg=eggname' - assert 'eggname' == Link(url).egg_fragment - assert 'subdir' == Link(url).subdirectory_fragment - - @pytest.mark.parametrize('yanked_reason, expected', [ - (None, False), - ('', True), - ('there was a mistake', True), - ]) + url = "git+https://example.com/package#egg=eggname&subdirectory=subdir" + assert "eggname" == Link(url).egg_fragment + assert "subdir" == Link(url).subdirectory_fragment + url = "git+https://example.com/package#subdirectory=subdir&egg=eggname" + assert "eggname" == Link(url).egg_fragment + assert "subdir" == Link(url).subdirectory_fragment + + @pytest.mark.parametrize( + "yanked_reason, expected", + [ + (None, False), + ("", True), + ("there was a mistake", True), + ], + ) def test_is_yanked(self, yanked_reason, expected): link = Link( - 'https://example.com/wheel.whl', + "https://example.com/wheel.whl", yanked_reason=yanked_reason, ) assert link.is_yanked == expected - @pytest.mark.parametrize('hash_name, hex_digest, expected', [ - # Test a value that matches but with the wrong hash_name. - ('sha384', 128 * 'a', False), - # Test matching values, including values other than the first. - ('sha512', 128 * 'a', True), - ('sha512', 128 * 'b', True), - # Test a matching hash_name with a value that doesn't match. - ('sha512', 128 * 'c', False), - # Test a link without a hash value. - ('sha512', '', False), - ]) + @pytest.mark.parametrize( + "hash_name, hex_digest, expected", + [ + # Test a value that matches but with the wrong hash_name. + ("sha384", 128 * "a", False), + # Test matching values, including values other than the first. + ("sha512", 128 * "a", True), + ("sha512", 128 * "b", True), + # Test a matching hash_name with a value that doesn't match. + ("sha512", 128 * "c", False), + # Test a link without a hash value. + ("sha512", "", False), + ], + ) def test_is_hash_allowed(self, hash_name, hex_digest, expected): - url = ( - 'https://example.com/wheel.whl#{hash_name}={hex_digest}'.format( - hash_name=hash_name, - hex_digest=hex_digest, - ) + url = "https://example.com/wheel.whl#{hash_name}={hex_digest}".format( + hash_name=hash_name, + hex_digest=hex_digest, ) link = Link(url) hashes_data = { - 'sha512': [128 * 'a', 128 * 'b'], + "sha512": [128 * "a", 128 * "b"], } hashes = Hashes(hashes_data) assert link.is_hash_allowed(hashes) == expected def test_is_hash_allowed__no_hash(self): - link = Link('https://example.com/wheel.whl') + link = Link("https://example.com/wheel.whl") hashes_data = { - 'sha512': [128 * 'a'], + "sha512": [128 * "a"], } hashes = Hashes(hashes_data) assert not link.is_hash_allowed(hashes) - @pytest.mark.parametrize('hashes, expected', [ - (None, False), - # Also test a success case to show the test is correct. - (Hashes({'sha512': [128 * 'a']}), True), - ]) + @pytest.mark.parametrize( + "hashes, expected", + [ + (None, False), + # Also test a success case to show the test is correct. + (Hashes({"sha512": [128 * "a"]}), True), + ], + ) def test_is_hash_allowed__none_hashes(self, hashes, expected): - url = 'https://example.com/wheel.whl#sha512={}'.format(128 * 'a') + url = "https://example.com/wheel.whl#sha512={}".format(128 * "a") link = Link(url) assert link.is_hash_allowed(hashes) == expected - @pytest.mark.parametrize('url, expected', [ - ('git+https://github.com/org/repo', True), - ('bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject', True), - ('hg+file://hg.company.com/repo', True), - ('https://example.com/some.whl', False), - ('file://home/foo/some.whl', False), - ]) + @pytest.mark.parametrize( + "url, expected", + [ + ("git+https://github.com/org/repo", True), + ("bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject", True), + ("hg+file://hg.company.com/repo", True), + ("https://example.com/some.whl", False), + ("file://home/foo/some.whl", False), + ], + ) def test_is_vcs(self, url, expected): link = Link(url) assert link.is_vcs is expected diff --git a/tests/unit/test_locations.py b/tests/unit/test_locations.py index 2ede236f91f..bfa299917c5 100644 --- a/tests/unit/test_locations.py +++ b/tests/unit/test_locations.py @@ -13,7 +13,7 @@ from pip._internal.locations import distutils_scheme -if sys.platform == 'win32': +if sys.platform == "win32": pwd = Mock() else: import pwd @@ -34,7 +34,7 @@ def patch(self): """ first store and then patch python methods pythons """ self.tempfile_gettempdir = tempfile.gettempdir self.old_os_fstat = os.fstat - if sys.platform != 'win32': + if sys.platform != "win32": # os.geteuid and pwd.getpwuid are not implemented on windows self.old_os_geteuid = os.geteuid self.old_pwd_getpwuid = pwd.getpwuid @@ -46,30 +46,30 @@ def patch(self): os.geteuid = lambda: self.st_uid os.fstat = lambda fd: self.get_mock_fstat(fd) - if sys.platform != 'win32': + if sys.platform != "win32": pwd.getpwuid = lambda uid: self.get_mock_getpwuid(uid) def revert_patch(self): """ revert the patches to python methods """ tempfile.gettempdir = self.tempfile_gettempdir getpass.getuser = self.old_getpass_getuser - if sys.platform != 'win32': + if sys.platform != "win32": # os.geteuid and pwd.getpwuid are not implemented on windows os.geteuid = self.old_os_geteuid pwd.getpwuid = self.old_pwd_getpwuid os.fstat = self.old_os_fstat def get_mock_fstat(self, fd): - """ returns a basic mock fstat call result. - Currently only the st_uid attribute has been set. + """returns a basic mock fstat call result. + Currently only the st_uid attribute has been set. """ result = Mock() result.st_uid = self.st_uid return result def get_mock_getpwuid(self, uid): - """ returns a basic mock pwd.getpwuid call result. - Currently only the pw_name attribute has been set. + """returns a basic mock pwd.getpwuid call result. + Currently only the pw_name attribute has been set. """ result = Mock() result.pw_name = self.username @@ -77,12 +77,12 @@ def get_mock_getpwuid(self, uid): class TestDistutilsScheme: - def test_root_modifies_appropriately(self, monkeypatch): # This deals with nt/posix path differences # root is c:\somewhere\else or /somewhere/else - root = os.path.normcase(os.path.abspath( - os.path.join(os.path.sep, 'somewhere', 'else'))) + root = os.path.normcase( + os.path.abspath(os.path.join(os.path.sep, "somewhere", "else")) + ) norm_scheme = distutils_scheme("example") root_scheme = distutils_scheme("example", root=root) @@ -94,8 +94,9 @@ def test_root_modifies_appropriately(self, monkeypatch): @pytest.mark.incompatible_with_venv def test_distutils_config_file_read(self, tmpdir, monkeypatch): # This deals with nt/posix path differences - install_scripts = os.path.normcase(os.path.abspath( - os.path.join(os.path.sep, 'somewhere', 'else'))) + install_scripts = os.path.normcase( + os.path.abspath(os.path.join(os.path.sep, "somewhere", "else")) + ) f = tmpdir / "config" / "setup.cfg" f.parent.mkdir() f.write_text("[install]\ninstall-scripts=" + install_scripts) @@ -104,11 +105,11 @@ def test_distutils_config_file_read(self, tmpdir, monkeypatch): # patch the function that returns what config files are present monkeypatch.setattr( Distribution, - 'find_config_files', + "find_config_files", lambda self: [f], ) - scheme = distutils_scheme('example') - assert scheme['scripts'] == install_scripts + scheme = distutils_scheme("example") + assert scheme["scripts"] == install_scripts @pytest.mark.incompatible_with_venv # when we request install-lib, we should install everything (.py & @@ -116,8 +117,9 @@ def test_distutils_config_file_read(self, tmpdir, monkeypatch): # this path def test_install_lib_takes_precedence(self, tmpdir, monkeypatch): # This deals with nt/posix path differences - install_lib = os.path.normcase(os.path.abspath( - os.path.join(os.path.sep, 'somewhere', 'else'))) + install_lib = os.path.normcase( + os.path.abspath(os.path.join(os.path.sep, "somewhere", "else")) + ) f = tmpdir / "config" / "setup.cfg" f.parent.mkdir() f.write_text("[install]\ninstall-lib=" + install_lib) @@ -126,15 +128,15 @@ def test_install_lib_takes_precedence(self, tmpdir, monkeypatch): # patch the function that returns what config files are present monkeypatch.setattr( Distribution, - 'find_config_files', + "find_config_files", lambda self: [f], ) - scheme = distutils_scheme('example') - assert scheme['platlib'] == install_lib + os.path.sep - assert scheme['purelib'] == install_lib + os.path.sep + scheme = distutils_scheme("example") + assert scheme["platlib"] == install_lib + os.path.sep + assert scheme["purelib"] == install_lib + os.path.sep def test_prefix_modifies_appropriately(self): - prefix = os.path.abspath(os.path.join('somewhere', 'else')) + prefix = os.path.abspath(os.path.join("somewhere", "else")) normal_scheme = distutils_scheme("example") prefix_scheme = distutils_scheme("example", prefix=prefix) @@ -143,8 +145,5 @@ def _calculate_expected(value): path = os.path.join(prefix, os.path.relpath(value, sys.prefix)) return os.path.normpath(path) - expected = { - k: _calculate_expected(v) - for k, v in normal_scheme.items() - } + expected = {k: _calculate_expected(v) for k, v in normal_scheme.items()} assert prefix_scheme == expected diff --git a/tests/unit/test_logging.py b/tests/unit/test_logging.py index 10d47eb6143..96e69927fa9 100644 --- a/tests/unit/test_logging.py +++ b/tests/unit/test_logging.py @@ -25,7 +25,7 @@ def _make_broken_pipe_error(): if PY2: # This is one way a broken pipe error can show up in Python 2 # (a non-Windows example in this case). - return IOError(errno.EPIPE, 'Broken pipe') + return IOError(errno.EPIPE, "Broken pipe") return BrokenPipeError() # noqa: F821 @@ -46,54 +46,65 @@ def make_record(self, msg, level_name): return record - @pytest.mark.parametrize('level_name, expected', [ - ('DEBUG', 'hello\nworld'), - ('INFO', 'hello\nworld'), - ('WARNING', 'WARNING: hello\nworld'), - ('ERROR', 'ERROR: hello\nworld'), - ('CRITICAL', 'ERROR: hello\nworld'), - ]) + @pytest.mark.parametrize( + "level_name, expected", + [ + ("DEBUG", "hello\nworld"), + ("INFO", "hello\nworld"), + ("WARNING", "WARNING: hello\nworld"), + ("ERROR", "ERROR: hello\nworld"), + ("CRITICAL", "ERROR: hello\nworld"), + ], + ) def test_format(self, level_name, expected, utc): """ Args: level_name: a logging level name (e.g. "WARNING"). """ - record = self.make_record('hello\nworld', level_name=level_name) + record = self.make_record("hello\nworld", level_name=level_name) f = IndentingFormatter(fmt="%(message)s") assert f.format(record) == expected - @pytest.mark.parametrize('level_name, expected', [ - ('INFO', - '2019-01-17T06:00:37,040 hello\n' - '2019-01-17T06:00:37,040 world'), - ('WARNING', - '2019-01-17T06:00:37,040 WARNING: hello\n' - '2019-01-17T06:00:37,040 world'), - ]) + @pytest.mark.parametrize( + "level_name, expected", + [ + ("INFO", "2019-01-17T06:00:37,040 hello\n" "2019-01-17T06:00:37,040 world"), + ( + "WARNING", + "2019-01-17T06:00:37,040 WARNING: hello\n" + "2019-01-17T06:00:37,040 world", + ), + ], + ) def test_format_with_timestamp(self, level_name, expected, utc): - record = self.make_record('hello\nworld', level_name=level_name) + record = self.make_record("hello\nworld", level_name=level_name) f = IndentingFormatter(fmt="%(message)s", add_timestamp=True) assert f.format(record) == expected - @pytest.mark.parametrize('level_name, expected', [ - ('WARNING', 'DEPRECATION: hello\nworld'), - ('ERROR', 'DEPRECATION: hello\nworld'), - ('CRITICAL', 'DEPRECATION: hello\nworld'), - ]) + @pytest.mark.parametrize( + "level_name, expected", + [ + ("WARNING", "DEPRECATION: hello\nworld"), + ("ERROR", "DEPRECATION: hello\nworld"), + ("CRITICAL", "DEPRECATION: hello\nworld"), + ], + ) def test_format_deprecated(self, level_name, expected, utc): """ Test that logged deprecation warnings coming from deprecated() don't get another prefix. """ record = self.make_record( - 'DEPRECATION: hello\nworld', level_name=level_name, + "DEPRECATION: hello\nworld", + level_name=level_name, ) f = IndentingFormatter(fmt="%(message)s") assert f.format(record) == expected def test_thread_safety_base(self, utc): record = self.make_record( - 'DEPRECATION: hello\nworld', level_name='WARNING', + "DEPRECATION: hello\nworld", + level_name="WARNING", ) f = IndentingFormatter(fmt="%(message)s") results = [] @@ -109,7 +120,8 @@ def thread_function(): def test_thread_safety_indent_log(self, utc): record = self.make_record( - 'DEPRECATION: hello\nworld', level_name='WARNING', + "DEPRECATION: hello\nworld", + level_name="WARNING", ) f = IndentingFormatter(fmt="%(message)s") results = [] @@ -126,10 +138,9 @@ def thread_function(): class TestColorizedStreamHandler(object): - def _make_log_record(self): attrs = { - 'msg': 'my error', + "msg": "my error", } record = logging.makeLogRecord(attrs) @@ -145,21 +156,21 @@ def test_broken_pipe_in_stderr_flush(self): with captured_stderr() as stderr: handler = ColorizedStreamHandler(stream=stderr) - with patch('sys.stderr.flush') as mock_flush: + with patch("sys.stderr.flush") as mock_flush: mock_flush.side_effect = _make_broken_pipe_error() # The emit() call raises no exception. handler.emit(record) err_text = stderr.getvalue() - assert err_text.startswith('my error') + assert err_text.startswith("my error") # Check that the logging framework tried to log the exception. if PY2: - assert 'IOError: [Errno 32] Broken pipe' in err_text - assert 'Logged from file' in err_text + assert "IOError: [Errno 32] Broken pipe" in err_text + assert "Logged from file" in err_text else: - assert 'Logging error' in err_text - assert 'BrokenPipeError' in err_text + assert "Logging error" in err_text + assert "BrokenPipeError" in err_text assert "Message: 'my error'" in err_text def test_broken_pipe_in_stdout_write(self): @@ -172,7 +183,7 @@ def test_broken_pipe_in_stdout_write(self): with captured_stdout() as stdout: handler = ColorizedStreamHandler(stream=stdout) - with patch('sys.stdout.write') as mock_write: + with patch("sys.stdout.write") as mock_write: mock_write.side_effect = _make_broken_pipe_error() with pytest.raises(BrokenStdoutLoggingError): handler.emit(record) @@ -187,7 +198,7 @@ def test_broken_pipe_in_stdout_flush(self): with captured_stdout() as stdout: handler = ColorizedStreamHandler(stream=stdout) - with patch('sys.stdout.flush') as mock_flush: + with patch("sys.stdout.flush") as mock_flush: mock_flush.side_effect = _make_broken_pipe_error() with pytest.raises(BrokenStdoutLoggingError): handler.emit(record) @@ -196,4 +207,4 @@ def test_broken_pipe_in_stdout_flush(self): # Sanity check that the log record was written, since flush() happens # after write(). - assert output.startswith('my error') + assert output.startswith("my error") diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index f6363367755..8262908358c 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -7,8 +7,7 @@ class TestPackageIndex(object): - """Tests for pip._internal.models.index.PackageIndex - """ + """Tests for pip._internal.models.index.PackageIndex""" def test_gives_right_urls(self): url = "https://mypypi.internal/path/" @@ -42,7 +41,6 @@ def test_TestPyPI_urls_are_correct(self): class TestInstallationCandidate(object): - def test_sets_correct_variables(self): obj = candidate.InstallationCandidate( "A", "1.0.0", "https://somewhere.com/path/A-1.0.0.tar.gz" diff --git a/tests/unit/test_models_wheel.py b/tests/unit/test_models_wheel.py index f1fef6f09e8..a58c78e2510 100644 --- a/tests/unit/test_models_wheel.py +++ b/tests/unit/test_models_wheel.py @@ -7,80 +7,79 @@ class TestWheelFile(object): - def test_std_wheel_pattern(self): - w = Wheel('simple-1.1.1-py2-none-any.whl') - assert w.name == 'simple' - assert w.version == '1.1.1' - assert w.pyversions == ['py2'] - assert w.abis == ['none'] - assert w.plats == ['any'] + w = Wheel("simple-1.1.1-py2-none-any.whl") + assert w.name == "simple" + assert w.version == "1.1.1" + assert w.pyversions == ["py2"] + assert w.abis == ["none"] + assert w.plats == ["any"] def test_wheel_pattern_multi_values(self): - w = Wheel('simple-1.1-py2.py3-abi1.abi2-any.whl') - assert w.name == 'simple' - assert w.version == '1.1' - assert w.pyversions == ['py2', 'py3'] - assert w.abis == ['abi1', 'abi2'] - assert w.plats == ['any'] + w = Wheel("simple-1.1-py2.py3-abi1.abi2-any.whl") + assert w.name == "simple" + assert w.version == "1.1" + assert w.pyversions == ["py2", "py3"] + assert w.abis == ["abi1", "abi2"] + assert w.plats == ["any"] def test_wheel_with_build_tag(self): # pip doesn't do anything with build tags, but theoretically, we might # see one, in this case the build tag = '4' - w = Wheel('simple-1.1-4-py2-none-any.whl') - assert w.name == 'simple' - assert w.version == '1.1' - assert w.pyversions == ['py2'] - assert w.abis == ['none'] - assert w.plats == ['any'] + w = Wheel("simple-1.1-4-py2-none-any.whl") + assert w.name == "simple" + assert w.version == "1.1" + assert w.pyversions == ["py2"] + assert w.abis == ["none"] + assert w.plats == ["any"] def test_single_digit_version(self): - w = Wheel('simple-1-py2-none-any.whl') - assert w.version == '1' + w = Wheel("simple-1-py2-none-any.whl") + assert w.version == "1" def test_non_pep440_version(self): - w = Wheel('simple-_invalid_-py2-none-any.whl') - assert w.version == '-invalid-' + w = Wheel("simple-_invalid_-py2-none-any.whl") + assert w.version == "-invalid-" def test_missing_version_raises(self): with pytest.raises(InvalidWheelFilename): - Wheel('Cython-cp27-none-linux_x86_64.whl') + Wheel("Cython-cp27-none-linux_x86_64.whl") def test_invalid_filename_raises(self): with pytest.raises(InvalidWheelFilename): - Wheel('invalid.whl') + Wheel("invalid.whl") def test_supported_single_version(self): """ Test single-version wheel is known to be supported """ - w = Wheel('simple-0.1-py2-none-any.whl') - assert w.supported(tags=[Tag('py2', 'none', 'any')]) + w = Wheel("simple-0.1-py2-none-any.whl") + assert w.supported(tags=[Tag("py2", "none", "any")]) def test_supported_multi_version(self): """ Test multi-version wheel is known to be supported """ - w = Wheel('simple-0.1-py2.py3-none-any.whl') - assert w.supported(tags=[Tag('py3', 'none', 'any')]) + w = Wheel("simple-0.1-py2.py3-none-any.whl") + assert w.supported(tags=[Tag("py3", "none", "any")]) def test_not_supported_version(self): """ Test unsupported wheel is known to be unsupported """ - w = Wheel('simple-0.1-py2-none-any.whl') - assert not w.supported(tags=[Tag('py1', 'none', 'any')]) + w = Wheel("simple-0.1-py2-none-any.whl") + assert not w.supported(tags=[Tag("py1", "none", "any")]) def test_supported_osx_version(self): """ Wheels built for macOS 10.6 are supported on 10.9 """ tags = compatibility_tags.get_supported( - '27', platform='macosx_10_9_intel', impl='cp' + "27", platform="macosx_10_9_intel", impl="cp" ) - w = Wheel('simple-0.1-cp27-none-macosx_10_6_intel.whl') + w = Wheel("simple-0.1-cp27-none-macosx_10_6_intel.whl") assert w.supported(tags=tags) - w = Wheel('simple-0.1-cp27-none-macosx_10_9_intel.whl') + w = Wheel("simple-0.1-cp27-none-macosx_10_9_intel.whl") assert w.supported(tags=tags) def test_not_supported_osx_version(self): @@ -88,9 +87,9 @@ def test_not_supported_osx_version(self): Wheels built for macOS 10.9 are not supported on 10.6 """ tags = compatibility_tags.get_supported( - '27', platform='macosx_10_6_intel', impl='cp' + "27", platform="macosx_10_6_intel", impl="cp" ) - w = Wheel('simple-0.1-cp27-none-macosx_10_9_intel.whl') + w = Wheel("simple-0.1-cp27-none-macosx_10_9_intel.whl") assert not w.supported(tags=tags) def test_supported_multiarch_darwin(self): @@ -98,32 +97,32 @@ def test_supported_multiarch_darwin(self): Multi-arch wheels (intel) are supported on components (i386, x86_64) """ universal = compatibility_tags.get_supported( - '27', platform='macosx_10_5_universal', impl='cp' + "27", platform="macosx_10_5_universal", impl="cp" ) intel = compatibility_tags.get_supported( - '27', platform='macosx_10_5_intel', impl='cp' + "27", platform="macosx_10_5_intel", impl="cp" ) x64 = compatibility_tags.get_supported( - '27', platform='macosx_10_5_x86_64', impl='cp' + "27", platform="macosx_10_5_x86_64", impl="cp" ) i386 = compatibility_tags.get_supported( - '27', platform='macosx_10_5_i386', impl='cp' + "27", platform="macosx_10_5_i386", impl="cp" ) ppc = compatibility_tags.get_supported( - '27', platform='macosx_10_5_ppc', impl='cp' + "27", platform="macosx_10_5_ppc", impl="cp" ) ppc64 = compatibility_tags.get_supported( - '27', platform='macosx_10_5_ppc64', impl='cp' + "27", platform="macosx_10_5_ppc64", impl="cp" ) - w = Wheel('simple-0.1-cp27-none-macosx_10_5_intel.whl') + w = Wheel("simple-0.1-cp27-none-macosx_10_5_intel.whl") assert w.supported(tags=intel) assert w.supported(tags=x64) assert w.supported(tags=i386) assert not w.supported(tags=universal) assert not w.supported(tags=ppc) assert not w.supported(tags=ppc64) - w = Wheel('simple-0.1-cp27-none-macosx_10_5_universal.whl') + w = Wheel("simple-0.1-cp27-none-macosx_10_5_universal.whl") assert w.supported(tags=universal) assert w.supported(tags=intel) assert w.supported(tags=x64) @@ -136,16 +135,16 @@ def test_not_supported_multiarch_darwin(self): Single-arch wheels (x86_64) are not supported on multi-arch (intel) """ universal = compatibility_tags.get_supported( - '27', platform='macosx_10_5_universal', impl='cp' + "27", platform="macosx_10_5_universal", impl="cp" ) intel = compatibility_tags.get_supported( - '27', platform='macosx_10_5_intel', impl='cp' + "27", platform="macosx_10_5_intel", impl="cp" ) - w = Wheel('simple-0.1-cp27-none-macosx_10_5_i386.whl') + w = Wheel("simple-0.1-cp27-none-macosx_10_5_i386.whl") assert not w.supported(tags=intel) assert not w.supported(tags=universal) - w = Wheel('simple-0.1-cp27-none-macosx_10_5_x86_64.whl') + w = Wheel("simple-0.1-cp27-none-macosx_10_5_x86_64.whl") assert not w.supported(tags=intel) assert not w.supported(tags=universal) @@ -154,20 +153,20 @@ def test_support_index_min(self): Test results from `support_index_min` """ tags = [ - Tag('py2', 'none', 'TEST'), - Tag('py2', 'TEST', 'any'), - Tag('py2', 'none', 'any'), + Tag("py2", "none", "TEST"), + Tag("py2", "TEST", "any"), + Tag("py2", "none", "any"), ] - w = Wheel('simple-0.1-py2-none-any.whl') + w = Wheel("simple-0.1-py2-none-any.whl") assert w.support_index_min(tags=tags) == 2 - w = Wheel('simple-0.1-py2-none-TEST.whl') + w = Wheel("simple-0.1-py2-none-TEST.whl") assert w.support_index_min(tags=tags) == 0 def test_support_index_min__none_supported(self): """ Test a wheel not supported by the given tags. """ - w = Wheel('simple-0.1-py2-none-any.whl') + w = Wheel("simple-0.1-py2-none-any.whl") with pytest.raises(ValueError): w.support_index_min(tags=[]) @@ -176,5 +175,5 @@ def test_version_underscore_conversion(self): Test that we convert '_' to '-' for versions parsed out of wheel filenames """ - w = Wheel('simple-0.1_1-py2-none-any.whl') - assert w.version == '0.1-1' + w = Wheel("simple-0.1_1-py2-none-any.whl") + assert w.version == "0.1-1" diff --git a/tests/unit/test_network_auth.py b/tests/unit/test_network_auth.py index 8116b627f79..a895ffa1169 100644 --- a/tests/unit/test_network_auth.py +++ b/tests/unit/test_network_auth.py @@ -7,32 +7,35 @@ from tests.lib.requests_mocks import MockConnection, MockRequest, MockResponse -@pytest.mark.parametrize(["input_url", "url", "username", "password"], [ - ( - "http://user%40email.com:password@example.com/path", - "http://example.com/path", - "user@email.com", - "password", - ), - ( - "http://username:password@example.com/path", - "http://example.com/path", - "username", - "password", - ), - ( - "http://token@example.com/path", - "http://example.com/path", - "token", - "", - ), - ( - "http://example.com/path", - "http://example.com/path", - None, - None, - ), -]) +@pytest.mark.parametrize( + ["input_url", "url", "username", "password"], + [ + ( + "http://user%40email.com:password@example.com/path", + "http://example.com/path", + "user@email.com", + "password", + ), + ( + "http://username:password@example.com/path", + "http://example.com/path", + "username", + "password", + ), + ( + "http://token@example.com/path", + "http://example.com/path", + "token", + "", + ), + ( + "http://example.com/path", + "http://example.com/path", + None, + None, + ), + ], +) def test_get_credentials_parses_correctly(input_url, url, username, password): auth = MultiDomainBasicAuth() get = auth._get_url_and_credentials @@ -41,33 +44,30 @@ def test_get_credentials_parses_correctly(input_url, url, username, password): assert get(input_url) == (url, username, password) assert ( # There are no credentials in the URL - (username is None and password is None) or + (username is None and password is None) + or # Credentials were found and "cached" appropriately - auth.passwords['example.com'] == (username, password) + auth.passwords["example.com"] == (username, password) ) def test_get_credentials_uses_cached_credentials(): auth = MultiDomainBasicAuth() - auth.passwords['example.com'] = ('user', 'pass') + auth.passwords["example.com"] = ("user", "pass") got = auth._get_url_and_credentials("http://foo:bar@example.com/path") - expected = ('http://example.com/path', 'user', 'pass') + expected = ("http://example.com/path", "user", "pass") assert got == expected def test_get_index_url_credentials(): - auth = MultiDomainBasicAuth(index_urls=[ - "http://foo:bar@example.com/path" - ]) + auth = MultiDomainBasicAuth(index_urls=["http://foo:bar@example.com/path"]) get = functools.partial( - auth._get_new_credentials, - allow_netrc=False, - allow_keyring=False + auth._get_new_credentials, allow_netrc=False, allow_keyring=False ) # Check resolution of indexes - assert get("http://example.com/path/path2") == ('foo', 'bar') + assert get("http://example.com/path/path2") == ("foo", "bar") assert get("http://example.com/path3/path2") == (None, None) @@ -90,42 +90,44 @@ def set_password(self, system, username, password): self.saved_passwords.append((system, username, password)) -@pytest.mark.parametrize('url, expect', ( - ("http://example.com/path1", (None, None)), - # path1 URLs will be resolved by netloc - ("http://user@example.com/path1", ("user", "user!netloc")), - ("http://user2@example.com/path1", ("user2", "user2!netloc")), - # path2 URLs will be resolved by index URL - ("http://example.com/path2/path3", (None, None)), - ("http://foo@example.com/path2/path3", ("foo", "foo!url")), -)) +@pytest.mark.parametrize( + "url, expect", + ( + ("http://example.com/path1", (None, None)), + # path1 URLs will be resolved by netloc + ("http://user@example.com/path1", ("user", "user!netloc")), + ("http://user2@example.com/path1", ("user2", "user2!netloc")), + # path2 URLs will be resolved by index URL + ("http://example.com/path2/path3", (None, None)), + ("http://foo@example.com/path2/path3", ("foo", "foo!url")), + ), +) def test_keyring_get_password(monkeypatch, url, expect): keyring = KeyringModuleV1() - monkeypatch.setattr('pip._internal.network.auth.keyring', keyring) + monkeypatch.setattr("pip._internal.network.auth.keyring", keyring) auth = MultiDomainBasicAuth(index_urls=["http://example.com/path2"]) - actual = auth._get_new_credentials(url, allow_netrc=False, - allow_keyring=True) + actual = auth._get_new_credentials(url, allow_netrc=False, allow_keyring=True) assert actual == expect def test_keyring_get_password_after_prompt(monkeypatch): keyring = KeyringModuleV1() - monkeypatch.setattr('pip._internal.network.auth.keyring', keyring) + monkeypatch.setattr("pip._internal.network.auth.keyring", keyring) auth = MultiDomainBasicAuth() def ask_input(prompt): assert prompt == "User for example.com: " return "user" - monkeypatch.setattr('pip._internal.network.auth.ask_input', ask_input) + monkeypatch.setattr("pip._internal.network.auth.ask_input", ask_input) actual = auth._prompt_for_password("example.com") assert actual == ("user", "user!netloc", False) def test_keyring_get_password_after_prompt_when_none(monkeypatch): keyring = KeyringModuleV1() - monkeypatch.setattr('pip._internal.network.auth.keyring', keyring) + monkeypatch.setattr("pip._internal.network.auth.keyring", keyring) auth = MultiDomainBasicAuth() def ask_input(prompt): @@ -136,52 +138,60 @@ def ask_password(prompt): assert prompt == "Password: " return "fake_password" - monkeypatch.setattr('pip._internal.network.auth.ask_input', ask_input) - monkeypatch.setattr( - 'pip._internal.network.auth.ask_password', ask_password) + monkeypatch.setattr("pip._internal.network.auth.ask_input", ask_input) + monkeypatch.setattr("pip._internal.network.auth.ask_password", ask_password) actual = auth._prompt_for_password("unknown.com") assert actual == ("user", "fake_password", True) def test_keyring_get_password_username_in_index(monkeypatch): keyring = KeyringModuleV1() - monkeypatch.setattr('pip._internal.network.auth.keyring', keyring) + monkeypatch.setattr("pip._internal.network.auth.keyring", keyring) auth = MultiDomainBasicAuth(index_urls=["http://user@example.com/path2"]) get = functools.partial( - auth._get_new_credentials, - allow_netrc=False, - allow_keyring=True + auth._get_new_credentials, allow_netrc=False, allow_keyring=True ) assert get("http://example.com/path2/path3") == ("user", "user!url") assert get("http://example.com/path4/path1") == (None, None) -@pytest.mark.parametrize("response_status, creds, expect_save", ( - (403, ("user", "pass", True), False), - (200, ("user", "pass", True), True,), - (200, ("user", "pass", False), False,), -)) -def test_keyring_set_password(monkeypatch, response_status, creds, - expect_save): +@pytest.mark.parametrize( + "response_status, creds, expect_save", + ( + (403, ("user", "pass", True), False), + ( + 200, + ("user", "pass", True), + True, + ), + ( + 200, + ("user", "pass", False), + False, + ), + ), +) +def test_keyring_set_password(monkeypatch, response_status, creds, expect_save): keyring = KeyringModuleV1() - monkeypatch.setattr('pip._internal.network.auth.keyring', keyring) + monkeypatch.setattr("pip._internal.network.auth.keyring", keyring) auth = MultiDomainBasicAuth(prompting=True) - monkeypatch.setattr(auth, '_get_url_and_credentials', - lambda u: (u, None, None)) - monkeypatch.setattr(auth, '_prompt_for_password', lambda *a: creds) + monkeypatch.setattr(auth, "_get_url_and_credentials", lambda u: (u, None, None)) + monkeypatch.setattr(auth, "_prompt_for_password", lambda *a: creds) if creds[2]: # when _prompt_for_password indicates to save, we should save def should_save_password_to_keyring(*a): return True + else: # when _prompt_for_password indicates not to save, we should # never call this function def should_save_password_to_keyring(*a): - assert False, ("_should_save_password_to_keyring should not be " + - "called") - monkeypatch.setattr(auth, '_should_save_password_to_keyring', - should_save_password_to_keyring) + assert False, "_should_save_password_to_keyring should not be " + "called" + + monkeypatch.setattr( + auth, "_should_save_password_to_keyring", should_save_password_to_keyring + ) req = MockRequest("https://example.com") resp = MockResponse(b"") @@ -228,20 +238,21 @@ def get_credential(self, system, username): return None -@pytest.mark.parametrize('url, expect', ( - ("http://example.com/path1", ("username", "netloc")), - ("http://example.com/path2/path3", ("username", "url")), - ("http://user2@example.com/path2/path3", ("username", "url")), -)) +@pytest.mark.parametrize( + "url, expect", + ( + ("http://example.com/path1", ("username", "netloc")), + ("http://example.com/path2/path3", ("username", "url")), + ("http://user2@example.com/path2/path3", ("username", "url")), + ), +) def test_keyring_get_credential(monkeypatch, url, expect): - monkeypatch.setattr( - pip._internal.network.auth, 'keyring', KeyringModuleV2() - ) + monkeypatch.setattr(pip._internal.network.auth, "keyring", KeyringModuleV2()) auth = MultiDomainBasicAuth(index_urls=["http://example.com/path2"]) - assert auth._get_new_credentials( - url, allow_netrc=False, allow_keyring=True - ) == expect + assert ( + auth._get_new_credentials(url, allow_netrc=False, allow_keyring=True) == expect + ) class KeyringModuleBroken(object): @@ -257,7 +268,7 @@ def get_credential(self, system, username): def test_broken_keyring_disables_keyring(monkeypatch): keyring_broken = KeyringModuleBroken() - monkeypatch.setattr(pip._internal.network.auth, 'keyring', keyring_broken) + monkeypatch.setattr(pip._internal.network.auth, "keyring", keyring_broken) auth = MultiDomainBasicAuth(index_urls=["http://example.com/"]) diff --git a/tests/unit/test_network_cache.py b/tests/unit/test_network_cache.py index 5f1d0a0975a..63515aac91f 100644 --- a/tests/unit/test_network_cache.py +++ b/tests/unit/test_network_cache.py @@ -56,7 +56,5 @@ def test_safe_delete_no_perms(self, cache_tmpdir): def test_cache_hashes_are_same(self, cache_tmpdir): cache = SafeFileCache(cache_tmpdir) key = "test key" - fake_cache = Mock( - FileCache, directory=cache.directory, encode=FileCache.encode - ) + fake_cache = Mock(FileCache, directory=cache.directory, encode=FileCache.encode) assert cache._get_cache_path(key) == FileCache._fn(fake_cache, key) diff --git a/tests/unit/test_network_download.py b/tests/unit/test_network_download.py index 20f5513a2df..c1bc2ea1e1b 100644 --- a/tests/unit/test_network_download.py +++ b/tests/unit/test_network_download.py @@ -12,23 +12,45 @@ from tests.lib.requests_mocks import MockResponse -@pytest.mark.parametrize("url, headers, from_cache, expected", [ - ('http://example.com/foo.tgz', {}, False, - "Downloading http://example.com/foo.tgz"), - ('http://example.com/foo.tgz', {'content-length': 2}, False, - "Downloading http://example.com/foo.tgz (2 bytes)"), - ('http://example.com/foo.tgz', {'content-length': 2}, True, - "Using cached http://example.com/foo.tgz (2 bytes)"), - ('https://files.pythonhosted.org/foo.tgz', {}, False, - "Downloading foo.tgz"), - ('https://files.pythonhosted.org/foo.tgz', {'content-length': 2}, False, - "Downloading foo.tgz (2 bytes)"), - ('https://files.pythonhosted.org/foo.tgz', {'content-length': 2}, True, - "Using cached foo.tgz"), -]) +@pytest.mark.parametrize( + "url, headers, from_cache, expected", + [ + ( + "http://example.com/foo.tgz", + {}, + False, + "Downloading http://example.com/foo.tgz", + ), + ( + "http://example.com/foo.tgz", + {"content-length": 2}, + False, + "Downloading http://example.com/foo.tgz (2 bytes)", + ), + ( + "http://example.com/foo.tgz", + {"content-length": 2}, + True, + "Using cached http://example.com/foo.tgz (2 bytes)", + ), + ("https://files.pythonhosted.org/foo.tgz", {}, False, "Downloading foo.tgz"), + ( + "https://files.pythonhosted.org/foo.tgz", + {"content-length": 2}, + False, + "Downloading foo.tgz (2 bytes)", + ), + ( + "https://files.pythonhosted.org/foo.tgz", + {"content-length": 2}, + True, + "Using cached foo.tgz", + ), + ], +) def test_prepare_download__log(caplog, url, headers, from_cache, expected): caplog.set_level(logging.INFO) - resp = MockResponse(b'') + resp = MockResponse(b"") resp.url = url resp.headers = headers if from_cache: @@ -38,18 +60,21 @@ def test_prepare_download__log(caplog, url, headers, from_cache, expected): assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'INFO' + assert record.levelname == "INFO" assert expected in record.message -@pytest.mark.parametrize("filename, expected", [ - ('dir/file', 'file'), - ('../file', 'file'), - ('../../file', 'file'), - ('../', ''), - ('../..', '..'), - ('/', ''), -]) +@pytest.mark.parametrize( + "filename, expected", + [ + ("dir/file", "file"), + ("../file", "file"), + ("../../file", "file"), + ("../", ""), + ("../..", ".."), + ("/", ""), + ], +) def test_sanitize_content_filename(filename, expected): """ Test inputs where the result is the same for Windows and non-Windows. @@ -57,36 +82,36 @@ def test_sanitize_content_filename(filename, expected): assert sanitize_content_filename(filename) == expected -@pytest.mark.parametrize("filename, win_expected, non_win_expected", [ - ('dir\\file', 'file', 'dir\\file'), - ('..\\file', 'file', '..\\file'), - ('..\\..\\file', 'file', '..\\..\\file'), - ('..\\', '', '..\\'), - ('..\\..', '..', '..\\..'), - ('\\', '', '\\'), -]) +@pytest.mark.parametrize( + "filename, win_expected, non_win_expected", + [ + ("dir\\file", "file", "dir\\file"), + ("..\\file", "file", "..\\file"), + ("..\\..\\file", "file", "..\\..\\file"), + ("..\\", "", "..\\"), + ("..\\..", "..", "..\\.."), + ("\\", "", "\\"), + ], +) def test_sanitize_content_filename__platform_dependent( - filename, - win_expected, - non_win_expected + filename, win_expected, non_win_expected ): """ Test inputs where the result is different for Windows and non-Windows. """ - if sys.platform == 'win32': + if sys.platform == "win32": expected = win_expected else: expected = non_win_expected assert sanitize_content_filename(filename) == expected -@pytest.mark.parametrize("content_disposition, default_filename, expected", [ - ('attachment;filename="../file"', 'df', 'file'), -]) -def test_parse_content_disposition( - content_disposition, - default_filename, - expected -): +@pytest.mark.parametrize( + "content_disposition, default_filename, expected", + [ + ('attachment;filename="../file"', "df", "file"), + ], +) +def test_parse_content_disposition(content_disposition, default_filename, expected): actual = parse_content_disposition(content_disposition, default_filename) assert actual == expected diff --git a/tests/unit/test_network_lazy_wheel.py b/tests/unit/test_network_lazy_wheel.py index cf0e6213d3f..81fa502dfac 100644 --- a/tests/unit/test_network_lazy_wheel.py +++ b/tests/unit/test_network_lazy_wheel.py @@ -11,14 +11,14 @@ from tests.lib.server import file_response MYPY_0_782_WHL = ( - 'https://files.pythonhosted.org/packages/9d/65/' - 'b96e844150ce18b9892b155b780248955ded13a2581d31872e7daa90a503/' - 'mypy-0.782-py3-none-any.whl' + "https://files.pythonhosted.org/packages/9d/65/" + "b96e844150ce18b9892b155b780248955ded13a2581d31872e7daa90a503/" + "mypy-0.782-py3-none-any.whl" ) MYPY_0_782_REQS = { - Requirement('typed-ast (<1.5.0,>=1.4.0)'), - Requirement('typing-extensions (>=3.7.4)'), - Requirement('mypy-extensions (<0.5.0,>=0.4.3)'), + Requirement("typed-ast (<1.5.0,>=1.4.0)"), + Requirement("typing-extensions (>=3.7.4)"), + Requirement("mypy-extensions (<0.5.0,>=0.4.3)"), Requirement('psutil (>=4.0); extra == "dmypy"'), } @@ -30,32 +30,32 @@ def session(): @fixture def mypy_whl_no_range(mock_server, shared_data): - mypy_whl = shared_data.packages / 'mypy-0.782-py3-none-any.whl' + mypy_whl = shared_data.packages / "mypy-0.782-py3-none-any.whl" mock_server.set_responses([file_response(mypy_whl)]) mock_server.start() - base_address = 'http://{}:{}'.format(mock_server.host, mock_server.port) - yield "{}/{}".format(base_address, 'mypy-0.782-py3-none-any.whl') + base_address = "http://{}:{}".format(mock_server.host, mock_server.port) + yield "{}/{}".format(base_address, "mypy-0.782-py3-none-any.whl") mock_server.stop() @mark.network def test_dist_from_wheel_url(session): """Test if the acquired distribution contain correct information.""" - dist = dist_from_wheel_url('mypy', MYPY_0_782_WHL, session) - assert dist.key == 'mypy' - assert dist.version == '0.782' - assert dist.extras == ['dmypy'] + dist = dist_from_wheel_url("mypy", MYPY_0_782_WHL, session) + assert dist.key == "mypy" + assert dist.version == "0.782" + assert dist.extras == ["dmypy"] assert set(dist.requires(dist.extras)) == MYPY_0_782_REQS def test_dist_from_wheel_url_no_range(session, mypy_whl_no_range): """Test handling when HTTP range requests are not supported.""" with raises(HTTPRangeRequestUnsupported): - dist_from_wheel_url('mypy', mypy_whl_no_range, session) + dist_from_wheel_url("mypy", mypy_whl_no_range, session) @mark.network def test_dist_from_wheel_url_not_zip(session): """Test handling with the given URL does not point to a ZIP.""" with raises(BadZipfile): - dist_from_wheel_url('python', 'https://www.python.org/', session) + dist_from_wheel_url("python", "https://www.python.org/", session) diff --git a/tests/unit/test_network_session.py b/tests/unit/test_network_session.py index a0d1463b2cf..351213a6490 100644 --- a/tests/unit/test_network_session.py +++ b/tests/unit/test_network_session.py @@ -16,14 +16,17 @@ def test_user_agent(): assert user_agent.startswith("pip/{}".format(__version__)) -@pytest.mark.parametrize('name, expected_like_ci', [ - ('BUILD_BUILDID', True), - ('BUILD_ID', True), - ('CI', True), - ('PIP_IS_CI', True), - # Test a prefix substring of one of the variable names we use. - ('BUILD', False), -]) +@pytest.mark.parametrize( + "name, expected_like_ci", + [ + ("BUILD_BUILDID", True), + ("BUILD_ID", True), + ("CI", True), + ("PIP_IS_CI", True), + # Test a prefix substring of one of the variable names we use. + ("BUILD", False), + ], +) def test_user_agent__ci(monkeypatch, name, expected_like_ci): # Delete the variable names we use to check for CI to prevent the # detection from always returning True in case the tests are being run @@ -38,7 +41,7 @@ def test_user_agent__ci(monkeypatch, name, expected_like_ci): assert '"ci":null' in user_agent assert '"ci":true' not in user_agent - monkeypatch.setenv(name, 'true') + monkeypatch.setenv(name, "true") user_agent = get_user_agent() assert ('"ci":true' in user_agent) == expected_like_ci assert ('"ci":null' in user_agent) == (not expected_like_ci) @@ -50,7 +53,6 @@ def test_user_agent_user_data(monkeypatch): class TestPipSession: - def test_cache_defaults_off(self): session = PipSession() @@ -63,9 +65,7 @@ def test_cache_is_enabled(self, tmpdir): assert hasattr(session.adapters["https://"], "cache") - assert ( - session.adapters["https://"].cache.directory == cache_directory - ) + assert session.adapters["https://"].cache.directory == cache_directory def test_http_cache_is_not_enabled(self, tmpdir): session = PipSession(cache=tmpdir.joinpath("test-cache")) @@ -86,42 +86,46 @@ def test_trusted_hosts_adapter(self, tmpdir): def test_add_trusted_host(self): # Leave a gap to test how the ordering is affected. - trusted_hosts = ['host1', 'host3'] + trusted_hosts = ["host1", "host3"] session = PipSession(trusted_hosts=trusted_hosts) trusted_host_adapter = session._trusted_host_adapter - prefix2 = 'https://host2/' - prefix3 = 'https://host3/' - prefix3_wildcard = 'https://host3:' + prefix2 = "https://host2/" + prefix3 = "https://host3/" + prefix3_wildcard = "https://host3:" # Confirm some initial conditions as a baseline. - assert session.pip_trusted_origins == [ - ('host1', None), ('host3', None) - ] + assert session.pip_trusted_origins == [("host1", None), ("host3", None)] assert session.adapters[prefix3] is trusted_host_adapter assert session.adapters[prefix3_wildcard] is trusted_host_adapter assert prefix2 not in session.adapters # Test adding a new host. - session.add_trusted_host('host2') + session.add_trusted_host("host2") assert session.pip_trusted_origins == [ - ('host1', None), ('host3', None), ('host2', None) + ("host1", None), + ("host3", None), + ("host2", None), ] # Check that prefix3 is still present. assert session.adapters[prefix3] is trusted_host_adapter assert session.adapters[prefix2] is trusted_host_adapter # Test that adding the same host doesn't create a duplicate. - session.add_trusted_host('host3') + session.add_trusted_host("host3") assert session.pip_trusted_origins == [ - ('host1', None), ('host3', None), ('host2', None) - ], 'actual: {}'.format(session.pip_trusted_origins) + ("host1", None), + ("host3", None), + ("host2", None), + ], "actual: {}".format(session.pip_trusted_origins) - session.add_trusted_host('host4:8080') - prefix4 = 'https://host4:8080/' + session.add_trusted_host("host4:8080") + prefix4 = "https://host4:8080/" assert session.pip_trusted_origins == [ - ('host1', None), ('host3', None), - ('host2', None), ('host4', 8080) + ("host1", None), + ("host3", None), + ("host2", None), + ("host4", 8080), ] assert session.adapters[prefix4] is trusted_host_adapter @@ -129,36 +133,36 @@ def test_add_trusted_host__logging(self, caplog): """ Test logging when add_trusted_host() is called. """ - trusted_hosts = ['host0', 'host1'] + trusted_hosts = ["host0", "host1"] session = PipSession(trusted_hosts=trusted_hosts) with caplog.at_level(logging.INFO): # Test adding an existing host. - session.add_trusted_host('host1', source='somewhere') - session.add_trusted_host('host2') + session.add_trusted_host("host1", source="somewhere") + session.add_trusted_host("host2") # Test calling add_trusted_host() on the same host twice. - session.add_trusted_host('host2') + session.add_trusted_host("host2") actual = [(r.levelname, r.message) for r in caplog.records] # Observe that "host0" isn't included in the logs. expected = [ - ('INFO', "adding trusted host: 'host1' (from somewhere)"), - ('INFO', "adding trusted host: 'host2'"), - ('INFO', "adding trusted host: 'host2'"), + ("INFO", "adding trusted host: 'host1' (from somewhere)"), + ("INFO", "adding trusted host: 'host2'"), + ("INFO", "adding trusted host: 'host2'"), ] assert actual == expected def test_iter_secure_origins(self): - trusted_hosts = ['host1', 'host2', 'host3:8080'] + trusted_hosts = ["host1", "host2", "host3:8080"] session = PipSession(trusted_hosts=trusted_hosts) actual = list(session.iter_secure_origins()) assert len(actual) == 9 # Spot-check that SECURE_ORIGINS is included. - assert actual[0] == ('https', '*', '*') + assert actual[0] == ("https", "*", "*") assert actual[-3:] == [ - ('*', 'host1', '*'), - ('*', 'host2', '*'), - ('*', 'host3', 8080) + ("*", "host1", "*"), + ("*", "host2", "*"), + ("*", "host3", 8080), ] def test_iter_secure_origins__trusted_hosts_empty(self): @@ -170,10 +174,10 @@ def test_iter_secure_origins__trusted_hosts_empty(self): actual = list(session.iter_secure_origins()) assert len(actual) == 6 # Spot-check that SECURE_ORIGINS is included. - assert actual[0] == ('https', '*', '*') + assert actual[0] == ("https", "*", "*") @pytest.mark.parametrize( - 'location, trusted, expected', + "location, trusted, expected", [ ("http://pypi.org/something", [], False), ("https://pypi.org/something", [], True), @@ -191,11 +195,7 @@ def test_iter_secure_origins__trusted_hosts_empty(self): # Test a trusted_host with a port. ("http://example.com:8080/something/", ["example.com:8080"], True), ("http://example.com/something/", ["example.com:8080"], False), - ( - "http://example.com:8888/something/", - ["example.com:8080"], - False - ), + ("http://example.com:8888/something/", ["example.com:8080"], False), ], ) def test_is_secure_origin(self, caplog, location, trusted, expected): @@ -217,5 +217,5 @@ def warning(self, *args, **kwargs): assert len(log_records) == 1 actual_level, actual_message = log_records[0] - assert actual_level == 'WARNING' - assert 'is not a trusted or secure host' in actual_message + assert actual_level == "WARNING" + assert "is not a trusted or secure host" in actual_message diff --git a/tests/unit/test_network_utils.py b/tests/unit/test_network_utils.py index 09f0684c5ee..8105e16006d 100644 --- a/tests/unit/test_network_utils.py +++ b/tests/unit/test_network_utils.py @@ -5,12 +5,15 @@ from tests.lib.requests_mocks import MockResponse -@pytest.mark.parametrize(("status_code", "error_type"), [ - (401, "Client Error"), - (501, "Server Error"), -]) +@pytest.mark.parametrize( + ("status_code", "error_type"), + [ + (401, "Client Error"), + (501, "Server Error"), + ], +) def test_raise_for_status_raises_exception(status_code, error_type): - contents = b'downloaded' + contents = b"downloaded" resp = MockResponse(contents) resp.status_code = status_code resp.url = "http://www.example.com/whatever.tgz" @@ -19,13 +22,12 @@ def test_raise_for_status_raises_exception(status_code, error_type): raise_for_status(resp) assert str(exc.info) == ( "{} {}: Network Error for url:" - " http://www.example.com/whatever.tgz".format( - status_code, error_type) + " http://www.example.com/whatever.tgz".format(status_code, error_type) ) def test_raise_for_status_does_not_raises_exception(): - contents = b'downloaded' + contents = b"downloaded" resp = MockResponse(contents) resp.status_code = 201 resp.url = "http://www.example.com/whatever.tgz" diff --git a/tests/unit/test_operations_prepare.py b/tests/unit/test_operations_prepare.py index ab6aaf6aa93..b0d225ffff6 100644 --- a/tests/unit/test_operations_prepare.py +++ b/tests/unit/test_operations_prepare.py @@ -13,11 +13,7 @@ from pip._internal.operations.prepare import _copy_source_tree, unpack_url from pip._internal.utils.hashes import Hashes from pip._internal.utils.urls import path_to_url -from tests.lib.filesystem import ( - get_filelist, - make_socket_file, - make_unreadable_file, -) +from tests.lib.filesystem import get_filelist, make_socket_file, make_unreadable_file from tests.lib.path import Path from tests.lib.requests_mocks import MockResponse @@ -48,21 +44,24 @@ def _fake_session_get(*args, **kwargs): download_dir=None, ) assert set(os.listdir(temp_dir)) == { - 'PKG-INFO', 'setup.cfg', 'setup.py', 'simple', 'simple.egg-info' + "PKG-INFO", + "setup.cfg", + "setup.py", + "simple", + "simple.egg-info", } finally: rmtree(temp_dir) @patch("pip._internal.network.download.raise_for_status") -def test_download_http_url__no_directory_traversal(mock_raise_for_status, - tmpdir): +def test_download_http_url__no_directory_traversal(mock_raise_for_status, tmpdir): """ Test that directory traversal doesn't happen on download when the Content-Disposition header contains a filename with a ".." path part. """ - mock_url = 'http://www.example.com/whatever.tgz' - contents = b'downloaded' + mock_url = "http://www.example.com/whatever.tgz" + contents = b"downloaded" link = Link(mock_url) session = Mock() @@ -71,18 +70,18 @@ def test_download_http_url__no_directory_traversal(mock_raise_for_status, resp.headers = { # Set the content-type to a random value to prevent # mimetypes.guess_extension from guessing the extension. - 'content-type': 'random', - 'content-disposition': 'attachment;filename="../out_dir_file"' + "content-type": "random", + "content-disposition": 'attachment;filename="../out_dir_file"', } session.get.return_value = resp download = Downloader(session, progress_bar="on") - download_dir = tmpdir.joinpath('download') + download_dir = tmpdir.joinpath("download") os.mkdir(download_dir) file_path, content_type = download(link, download_dir) # The file should be downloaded to download_dir. actual = os.listdir(download_dir) - assert actual == ['out_dir_file'] + assert actual == ["out_dir_file"] mock_raise_for_status.assert_called_once_with(resp) @@ -121,14 +120,12 @@ def test_copy_source_tree_with_socket(clean_project, tmpdir, caplog): # Warning should have been logged. assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'WARNING' + assert record.levelname == "WARNING" assert socket_path in record.message @pytest.mark.skipif("sys.platform == 'win32' or sys.version_info < (3,)") -def test_copy_source_tree_with_socket_fails_with_no_socket_error( - clean_project, tmpdir -): +def test_copy_source_tree_with_socket_fails_with_no_socket_error(clean_project, tmpdir): target = tmpdir.joinpath("target") expected_files = get_filelist(clean_project) make_socket_file(clean_project.joinpath("aaa")) @@ -166,10 +163,9 @@ def test_copy_source_tree_with_unreadable_dir_fails(clean_project, tmpdir): class Test_unpack_url(object): - def prep(self, tmpdir, data): - self.build_dir = tmpdir.joinpath('build') - self.download_dir = tmpdir.joinpath('download') + self.build_dir = tmpdir.joinpath("build") + self.download_dir = tmpdir.joinpath("download") os.mkdir(self.build_dir) os.mkdir(self.download_dir) self.dist_file = "simple-1.0.tar.gz" @@ -183,45 +179,45 @@ def prep(self, tmpdir, data): def test_unpack_url_no_download(self, tmpdir, data): self.prep(tmpdir, data) unpack_url(self.dist_url, self.build_dir, self.no_download) - assert os.path.isdir(os.path.join(self.build_dir, 'simple')) - assert not os.path.isfile( - os.path.join(self.download_dir, self.dist_file)) + assert os.path.isdir(os.path.join(self.build_dir, "simple")) + assert not os.path.isfile(os.path.join(self.download_dir, self.dist_file)) - def test_unpack_url_bad_hash(self, tmpdir, data, - monkeypatch): + def test_unpack_url_bad_hash(self, tmpdir, data, monkeypatch): """ Test when the file url hash fragment is wrong """ self.prep(tmpdir, data) - url = '{}#md5=bogus'.format(self.dist_url.url) + url = "{}#md5=bogus".format(self.dist_url.url) dist_url = Link(url) with pytest.raises(HashMismatch): - unpack_url(dist_url, - self.build_dir, - download=self.no_download, - hashes=Hashes({'md5': ['bogus']})) + unpack_url( + dist_url, + self.build_dir, + download=self.no_download, + hashes=Hashes({"md5": ["bogus"]}), + ) def test_unpack_url_thats_a_dir(self, tmpdir, data): self.prep(tmpdir, data) dist_path = data.packages.joinpath("FSPkg") dist_url = Link(path_to_url(dist_path)) - unpack_url(dist_url, self.build_dir, - download=self.no_download, - download_dir=self.download_dir) - assert os.path.isdir(os.path.join(self.build_dir, 'fspkg')) + unpack_url( + dist_url, + self.build_dir, + download=self.no_download, + download_dir=self.download_dir, + ) + assert os.path.isdir(os.path.join(self.build_dir, "fspkg")) -@pytest.mark.parametrize('exclude_dir', [ - '.nox', - '.tox' -]) +@pytest.mark.parametrize("exclude_dir", [".nox", ".tox"]) def test_unpack_url_excludes_expected_dirs(tmpdir, exclude_dir): - src_dir = tmpdir / 'src' - dst_dir = tmpdir / 'dst' - src_included_file = src_dir.joinpath('file.txt') + src_dir = tmpdir / "src" + dst_dir = tmpdir / "dst" + src_included_file = src_dir.joinpath("file.txt") src_excluded_dir = src_dir.joinpath(exclude_dir) - src_excluded_file = src_dir.joinpath(exclude_dir, 'file.txt') - src_included_dir = src_dir.joinpath('subdir', exclude_dir) + src_excluded_file = src_dir.joinpath(exclude_dir, "file.txt") + src_included_dir = src_dir.joinpath("subdir", exclude_dir) # set up source directory src_excluded_dir.mkdir(parents=True) @@ -229,18 +225,13 @@ def test_unpack_url_excludes_expected_dirs(tmpdir, exclude_dir): src_included_file.touch() src_excluded_file.touch() - dst_included_file = dst_dir.joinpath('file.txt') + dst_included_file = dst_dir.joinpath("file.txt") dst_excluded_dir = dst_dir.joinpath(exclude_dir) - dst_excluded_file = dst_dir.joinpath(exclude_dir, 'file.txt') - dst_included_dir = dst_dir.joinpath('subdir', exclude_dir) + dst_excluded_file = dst_dir.joinpath(exclude_dir, "file.txt") + dst_included_dir = dst_dir.joinpath("subdir", exclude_dir) src_link = Link(path_to_url(src_dir)) - unpack_url( - src_link, - dst_dir, - Mock(side_effect=AssertionError), - download_dir=None - ) + unpack_url(src_link, dst_dir, Mock(side_effect=AssertionError), download_dir=None) assert not os.path.isdir(dst_excluded_dir) assert not os.path.isfile(dst_excluded_file) assert os.path.isfile(dst_included_file) diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py index 533a4b8db3d..4f858b059cc 100644 --- a/tests/unit/test_options.py +++ b/tests/unit/test_options.py @@ -30,7 +30,7 @@ def assert_option_error(capsys, expected): def assert_is_default_cache_dir(value): # This path looks different on different platforms, but the path always # has the substring "pip". - assert 'pip' in value + assert "pip" in value class TestOptionPrecedence(AddFakeCommandMixin): @@ -42,15 +42,15 @@ class TestOptionPrecedence(AddFakeCommandMixin): def get_config_section(self, section): config = { - 'global': [('timeout', '-3')], - 'fake': [('timeout', '-2')], + "global": [("timeout", "-3")], + "fake": [("timeout", "-2")], } return config[section] def get_config_section_global(self, section): config = { - 'global': [('timeout', '-3')], - 'fake': [], + "global": [("timeout", "-3")], + "fake": [], } return config[section] @@ -58,106 +58,115 @@ def test_env_override_default_int(self, monkeypatch): """ Test that environment variable overrides an int option default. """ - monkeypatch.setenv('PIP_TIMEOUT', '-1') - options, args = main(['fake']) + monkeypatch.setenv("PIP_TIMEOUT", "-1") + options, args = main(["fake"]) assert options.timeout == -1 - @pytest.mark.parametrize('values', (['F1'], ['F1', 'F2'])) + @pytest.mark.parametrize("values", (["F1"], ["F1", "F2"])) def test_env_override_default_append(self, values, monkeypatch): """ Test that environment variable overrides an append option default. """ - monkeypatch.setenv('PIP_FIND_LINKS', ' '.join(values)) - options, args = main(['fake']) + monkeypatch.setenv("PIP_FIND_LINKS", " ".join(values)) + options, args = main(["fake"]) assert options.find_links == values - @pytest.mark.parametrize('choises', (['w'], ['s', 'w'])) + @pytest.mark.parametrize("choises", (["w"], ["s", "w"])) def test_env_override_default_choice(self, choises, monkeypatch): """ Test that environment variable overrides a choice option default. """ - monkeypatch.setenv('PIP_EXISTS_ACTION', ' '.join(choises)) - options, args = main(['fake']) + monkeypatch.setenv("PIP_EXISTS_ACTION", " ".join(choises)) + options, args = main(["fake"]) assert options.exists_action == choises - @pytest.mark.parametrize('name', ('PIP_LOG_FILE', 'PIP_LOCAL_LOG')) + @pytest.mark.parametrize("name", ("PIP_LOG_FILE", "PIP_LOCAL_LOG")) def test_env_alias_override_default(self, name, monkeypatch): """ When an option has multiple long forms, test that the technique of using the env variable, "PIP_" works for all cases. (e.g. PIP_LOG_FILE and PIP_LOCAL_LOG should all work) """ - monkeypatch.setenv(name, 'override.log') - options, args = main(['fake']) - assert options.log == 'override.log' + monkeypatch.setenv(name, "override.log") + options, args = main(["fake"]) + assert options.log == "override.log" def test_cli_override_environment(self, monkeypatch): """ Test the cli overrides and environment variable """ - monkeypatch.setenv('PIP_TIMEOUT', '-1') - options, args = main(['fake', '--timeout', '-2']) + monkeypatch.setenv("PIP_TIMEOUT", "-1") + options, args = main(["fake", "--timeout", "-2"]) assert options.timeout == -2 - @pytest.mark.parametrize('pip_no_cache_dir', [ - # Enabling --no-cache-dir means no cache directory. - '1', - 'true', - 'on', - 'yes', - # For historical / backwards compatibility reasons, we also disable - # the cache directory if provided a value that translates to 0. - '0', - 'false', - 'off', - 'no', - ]) + @pytest.mark.parametrize( + "pip_no_cache_dir", + [ + # Enabling --no-cache-dir means no cache directory. + "1", + "true", + "on", + "yes", + # For historical / backwards compatibility reasons, we also disable + # the cache directory if provided a value that translates to 0. + "0", + "false", + "off", + "no", + ], + ) def test_cache_dir__PIP_NO_CACHE_DIR(self, pip_no_cache_dir, monkeypatch): """ Test setting the PIP_NO_CACHE_DIR environment variable without passing any command-line flags. """ - monkeypatch.setenv('PIP_NO_CACHE_DIR', pip_no_cache_dir) - options, args = main(['fake']) + monkeypatch.setenv("PIP_NO_CACHE_DIR", pip_no_cache_dir) + options, args = main(["fake"]) assert options.cache_dir is False - @pytest.mark.parametrize('pip_no_cache_dir', ['yes', 'no']) + @pytest.mark.parametrize("pip_no_cache_dir", ["yes", "no"]) def test_cache_dir__PIP_NO_CACHE_DIR__with_cache_dir( - self, pip_no_cache_dir, monkeypatch, + self, + pip_no_cache_dir, + monkeypatch, ): """ Test setting PIP_NO_CACHE_DIR while also passing an explicit --cache-dir value. """ - monkeypatch.setenv('PIP_NO_CACHE_DIR', pip_no_cache_dir) - options, args = main(['--cache-dir', '/cache/dir', 'fake']) + monkeypatch.setenv("PIP_NO_CACHE_DIR", pip_no_cache_dir) + options, args = main(["--cache-dir", "/cache/dir", "fake"]) # The command-line flag takes precedence. - assert options.cache_dir == '/cache/dir' + assert options.cache_dir == "/cache/dir" - @pytest.mark.parametrize('pip_no_cache_dir', ['yes', 'no']) + @pytest.mark.parametrize("pip_no_cache_dir", ["yes", "no"]) def test_cache_dir__PIP_NO_CACHE_DIR__with_no_cache_dir( - self, pip_no_cache_dir, monkeypatch, + self, + pip_no_cache_dir, + monkeypatch, ): """ Test setting PIP_NO_CACHE_DIR while also passing --no-cache-dir. """ - monkeypatch.setenv('PIP_NO_CACHE_DIR', pip_no_cache_dir) - options, args = main(['--no-cache-dir', 'fake']) + monkeypatch.setenv("PIP_NO_CACHE_DIR", pip_no_cache_dir) + options, args = main(["--no-cache-dir", "fake"]) # The command-line flag should take precedence (which has the same # value in this case). assert options.cache_dir is False def test_cache_dir__PIP_NO_CACHE_DIR_invalid__with_no_cache_dir( - self, monkeypatch, capsys, + self, + monkeypatch, + capsys, ): """ Test setting PIP_NO_CACHE_DIR to an invalid value while also passing --no-cache-dir. """ - monkeypatch.setenv('PIP_NO_CACHE_DIR', 'maybe') + monkeypatch.setenv("PIP_NO_CACHE_DIR", "maybe") expected_err = "--no-cache-dir error: invalid truth value 'maybe'" with assert_option_error(capsys, expected=expected_err): - main(['--no-cache-dir', 'fake']) + main(["--no-cache-dir", "fake"]) class TestUsePEP517Options(object): @@ -169,7 +178,7 @@ class TestUsePEP517Options(object): def parse_args(self, args): # We use DownloadCommand since that is one of the few Command # classes with the use_pep517 options. - command = create_command('download') + command = create_command("download") options, args = command.parse_args(args) return options @@ -185,21 +194,21 @@ def test_use_pep517(self): """ Test passing --use-pep517. """ - options = self.parse_args(['--use-pep517']) + options = self.parse_args(["--use-pep517"]) assert options.use_pep517 is True def test_no_use_pep517(self): """ Test passing --no-use-pep517. """ - options = self.parse_args(['--no-use-pep517']) + options = self.parse_args(["--no-use-pep517"]) assert options.use_pep517 is False def test_PIP_USE_PEP517_true(self, monkeypatch): """ Test setting PIP_USE_PEP517 to "true". """ - monkeypatch.setenv('PIP_USE_PEP517', 'true') + monkeypatch.setenv("PIP_USE_PEP517", "true") options = self.parse_args([]) # This is an int rather than a boolean because strtobool() in pip's # configuration code returns an int. @@ -209,7 +218,7 @@ def test_PIP_USE_PEP517_false(self, monkeypatch): """ Test setting PIP_USE_PEP517 to "false". """ - monkeypatch.setenv('PIP_USE_PEP517', 'false') + monkeypatch.setenv("PIP_USE_PEP517", "false") options = self.parse_args([]) # This is an int rather than a boolean because strtobool() in pip's # configuration code returns an int. @@ -219,50 +228,49 @@ def test_use_pep517_and_PIP_USE_PEP517_false(self, monkeypatch): """ Test passing --use-pep517 and setting PIP_USE_PEP517 to "false". """ - monkeypatch.setenv('PIP_USE_PEP517', 'false') - options = self.parse_args(['--use-pep517']) + monkeypatch.setenv("PIP_USE_PEP517", "false") + options = self.parse_args(["--use-pep517"]) assert options.use_pep517 is True def test_no_use_pep517_and_PIP_USE_PEP517_true(self, monkeypatch): """ Test passing --no-use-pep517 and setting PIP_USE_PEP517 to "true". """ - monkeypatch.setenv('PIP_USE_PEP517', 'true') - options = self.parse_args(['--no-use-pep517']) + monkeypatch.setenv("PIP_USE_PEP517", "true") + options = self.parse_args(["--no-use-pep517"]) assert options.use_pep517 is False def test_PIP_NO_USE_PEP517(self, monkeypatch, capsys): """ Test setting PIP_NO_USE_PEP517, which isn't allowed. """ - monkeypatch.setenv('PIP_NO_USE_PEP517', 'true') - with assert_option_error(capsys, expected='--no-use-pep517 error'): + monkeypatch.setenv("PIP_NO_USE_PEP517", "true") + with assert_option_error(capsys, expected="--no-use-pep517 error"): self.parse_args([]) class TestOptionsInterspersed(AddFakeCommandMixin): - def test_general_option_after_subcommand(self): - options, args = main(['fake', '--timeout', '-1']) + options, args = main(["fake", "--timeout", "-1"]) assert options.timeout == -1 def test_option_after_subcommand_arg(self): - options, args = main(['fake', 'arg', '--timeout', '-1']) + options, args = main(["fake", "arg", "--timeout", "-1"]) assert options.timeout == -1 def test_additive_before_after_subcommand(self): - options, args = main(['-v', 'fake', '-v']) + options, args = main(["-v", "fake", "-v"]) assert options.verbose == 2 def test_subcommand_option_before_subcommand_fails(self): with pytest.raises(SystemExit): - main(['--find-links', 'F1', 'fake']) + main(["--find-links", "F1", "fake"]) @contextmanager -def tmpconfig(option, value, section='global'): - with NamedTemporaryFile(mode='w', delete=False) as f: - f.write('[{}]\n{}={}\n'.format(section, option, value)) +def tmpconfig(option, value, section="global"): + with NamedTemporaryFile(mode="w", delete=False) as f: + f.write("[{}]\n{}={}\n".format(section, option, value)) name = f.name try: yield name @@ -271,93 +279,92 @@ def tmpconfig(option, value, section='global'): class TestCountOptions(AddFakeCommandMixin): - - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', range(4)) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", range(4)) def test_cli_long(self, option, value): - flags = ['--{}'.format(option)] * value - opt1, args1 = main(flags+['fake']) - opt2, args2 = main(['fake']+flags) + flags = ["--{}".format(option)] * value + opt1, args1 = main(flags + ["fake"]) + opt2, args2 = main(["fake"] + flags) assert getattr(opt1, option) == getattr(opt2, option) == value - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', range(1, 4)) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", range(1, 4)) def test_cli_short(self, option, value): - flag = '-' + option[0]*value - opt1, args1 = main([flag, 'fake']) - opt2, args2 = main(['fake', flag]) + flag = "-" + option[0] * value + opt1, args1 = main([flag, "fake"]) + opt2, args2 = main(["fake", flag]) assert getattr(opt1, option) == getattr(opt2, option) == value - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', range(4)) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", range(4)) def test_env_var(self, option, value, monkeypatch): - monkeypatch.setenv('PIP_'+option.upper(), str(value)) - assert getattr(main(['fake'])[0], option) == value + monkeypatch.setenv("PIP_" + option.upper(), str(value)) + assert getattr(main(["fake"])[0], option) == value - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', range(3)) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", range(3)) def test_env_var_integrate_cli(self, option, value, monkeypatch): - monkeypatch.setenv('PIP_'+option.upper(), str(value)) - assert getattr(main(['fake', '--'+option])[0], option) == value + 1 + monkeypatch.setenv("PIP_" + option.upper(), str(value)) + assert getattr(main(["fake", "--" + option])[0], option) == value + 1 - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', (-1, 'foobar')) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", (-1, "foobar")) def test_env_var_invalid(self, option, value, monkeypatch, capsys): - monkeypatch.setenv('PIP_'+option.upper(), str(value)) - with assert_option_error(capsys, expected='a non-negative integer'): - main(['fake']) + monkeypatch.setenv("PIP_" + option.upper(), str(value)) + with assert_option_error(capsys, expected="a non-negative integer"): + main(["fake"]) # Undocumented, support for backward compatibility - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', ('no', 'false')) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", ("no", "false")) def test_env_var_false(self, option, value, monkeypatch): - monkeypatch.setenv('PIP_'+option.upper(), str(value)) - assert getattr(main(['fake'])[0], option) == 0 + monkeypatch.setenv("PIP_" + option.upper(), str(value)) + assert getattr(main(["fake"])[0], option) == 0 # Undocumented, support for backward compatibility - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', ('yes', 'true')) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", ("yes", "true")) def test_env_var_true(self, option, value, monkeypatch): - monkeypatch.setenv('PIP_'+option.upper(), str(value)) - assert getattr(main(['fake'])[0], option) == 1 + monkeypatch.setenv("PIP_" + option.upper(), str(value)) + assert getattr(main(["fake"])[0], option) == 1 - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', range(4)) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", range(4)) def test_config_file(self, option, value, monkeypatch): with tmpconfig(option, value) as name: - monkeypatch.setenv('PIP_CONFIG_FILE', name) - assert getattr(main(['fake'])[0], option) == value + monkeypatch.setenv("PIP_CONFIG_FILE", name) + assert getattr(main(["fake"])[0], option) == value - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', range(3)) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", range(3)) def test_config_file_integrate_cli(self, option, value, monkeypatch): with tmpconfig(option, value) as name: - monkeypatch.setenv('PIP_CONFIG_FILE', name) - assert getattr(main(['fake', '--'+option])[0], option) == value + 1 + monkeypatch.setenv("PIP_CONFIG_FILE", name) + assert getattr(main(["fake", "--" + option])[0], option) == value + 1 - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', (-1, 'foobar')) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", (-1, "foobar")) def test_config_file_invalid(self, option, value, monkeypatch, capsys): with tmpconfig(option, value) as name: - monkeypatch.setenv('PIP_CONFIG_FILE', name) - with assert_option_error(capsys, expected='non-negative integer'): - main(['fake']) + monkeypatch.setenv("PIP_CONFIG_FILE", name) + with assert_option_error(capsys, expected="non-negative integer"): + main(["fake"]) # Undocumented, support for backward compatibility - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', ('no', 'false')) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", ("no", "false")) def test_config_file_false(self, option, value, monkeypatch): with tmpconfig(option, value) as name: - monkeypatch.setenv('PIP_CONFIG_FILE', name) - assert getattr(main(['fake'])[0], option) == 0 + monkeypatch.setenv("PIP_CONFIG_FILE", name) + assert getattr(main(["fake"])[0], option) == 0 # Undocumented, support for backward compatibility - @pytest.mark.parametrize('option', ('verbose', 'quiet')) - @pytest.mark.parametrize('value', ('yes', 'true')) + @pytest.mark.parametrize("option", ("verbose", "quiet")) + @pytest.mark.parametrize("value", ("yes", "true")) def test_config_file_true(self, option, value, monkeypatch): with tmpconfig(option, value) as name: - monkeypatch.setenv('PIP_CONFIG_FILE', name) - assert getattr(main(['fake'])[0], option) == 1 + monkeypatch.setenv("PIP_CONFIG_FILE", name) + assert getattr(main(["fake"])[0], option) == 1 class TestGeneralOptions(AddFakeCommandMixin): @@ -366,78 +373,76 @@ class TestGeneralOptions(AddFakeCommandMixin): # extra processing they receive, and the number of bugs we've had def test_cache_dir__default(self): - options, args = main(['fake']) + options, args = main(["fake"]) # With no options the default cache dir should be used. assert_is_default_cache_dir(options.cache_dir) def test_cache_dir__provided(self): - options, args = main(['--cache-dir', '/cache/dir', 'fake']) - assert options.cache_dir == '/cache/dir' + options, args = main(["--cache-dir", "/cache/dir", "fake"]) + assert options.cache_dir == "/cache/dir" def test_no_cache_dir__provided(self): - options, args = main(['--no-cache-dir', 'fake']) + options, args = main(["--no-cache-dir", "fake"]) assert options.cache_dir is False def test_require_virtualenv(self): - options1, args1 = main(['--require-virtualenv', 'fake']) - options2, args2 = main(['fake', '--require-virtualenv']) + options1, args1 = main(["--require-virtualenv", "fake"]) + options2, args2 = main(["fake", "--require-virtualenv"]) assert options1.require_venv assert options2.require_venv def test_log(self): - options1, args1 = main(['--log', 'path', 'fake']) - options2, args2 = main(['fake', '--log', 'path']) - assert options1.log == options2.log == 'path' + options1, args1 = main(["--log", "path", "fake"]) + options2, args2 = main(["fake", "--log", "path"]) + assert options1.log == options2.log == "path" def test_local_log(self): - options1, args1 = main(['--local-log', 'path', 'fake']) - options2, args2 = main(['fake', '--local-log', 'path']) - assert options1.log == options2.log == 'path' + options1, args1 = main(["--local-log", "path", "fake"]) + options2, args2 = main(["fake", "--local-log", "path"]) + assert options1.log == options2.log == "path" def test_no_input(self): - options1, args1 = main(['--no-input', 'fake']) - options2, args2 = main(['fake', '--no-input']) + options1, args1 = main(["--no-input", "fake"]) + options2, args2 = main(["fake", "--no-input"]) assert options1.no_input assert options2.no_input def test_proxy(self): - options1, args1 = main(['--proxy', 'path', 'fake']) - options2, args2 = main(['fake', '--proxy', 'path']) - assert options1.proxy == options2.proxy == 'path' + options1, args1 = main(["--proxy", "path", "fake"]) + options2, args2 = main(["fake", "--proxy", "path"]) + assert options1.proxy == options2.proxy == "path" def test_retries(self): - options1, args1 = main(['--retries', '-1', 'fake']) - options2, args2 = main(['fake', '--retries', '-1']) + options1, args1 = main(["--retries", "-1", "fake"]) + options2, args2 = main(["fake", "--retries", "-1"]) assert options1.retries == options2.retries == -1 def test_timeout(self): - options1, args1 = main(['--timeout', '-1', 'fake']) - options2, args2 = main(['fake', '--timeout', '-1']) + options1, args1 = main(["--timeout", "-1", "fake"]) + options2, args2 = main(["fake", "--timeout", "-1"]) assert options1.timeout == options2.timeout == -1 def test_exists_action(self): - options1, args1 = main(['--exists-action', 'w', 'fake']) - options2, args2 = main(['fake', '--exists-action', 'w']) - assert options1.exists_action == options2.exists_action == ['w'] + options1, args1 = main(["--exists-action", "w", "fake"]) + options2, args2 = main(["fake", "--exists-action", "w"]) + assert options1.exists_action == options2.exists_action == ["w"] def test_cert(self): - options1, args1 = main(['--cert', 'path', 'fake']) - options2, args2 = main(['fake', '--cert', 'path']) - assert options1.cert == options2.cert == 'path' + options1, args1 = main(["--cert", "path", "fake"]) + options2, args2 = main(["fake", "--cert", "path"]) + assert options1.cert == options2.cert == "path" def test_client_cert(self): - options1, args1 = main(['--client-cert', 'path', 'fake']) - options2, args2 = main(['fake', '--client-cert', 'path']) - assert options1.client_cert == options2.client_cert == 'path' + options1, args1 = main(["--client-cert", "path", "fake"]) + options2, args2 = main(["fake", "--client-cert", "path"]) + assert options1.client_cert == options2.client_cert == "path" class TestOptionsConfigFiles(object): - def test_venv_config_file_found(self, monkeypatch): # strict limit on the global config files list monkeypatch.setattr( - pip._internal.utils.appdirs, 'site_config_dirs', - lambda _: ['/a/place'] + pip._internal.utils.appdirs, "site_config_dirs", lambda _: ["/a/place"] ) cp = pip._internal.configuration.Configuration(isolated=False) @@ -458,10 +463,10 @@ def test_venv_config_file_found(self, monkeypatch): (["--global", "--user"], PipError), (["--global", "--site"], PipError), (["--global", "--site", "--user"], PipError), - ) + ), ) def test_config_file_options(self, monkeypatch, args, expect): - cmd = create_command('config') + cmd = create_command("config") # Replace a handler with a no-op to avoid side effects monkeypatch.setattr(cmd, "get_name", lambda *a: None) @@ -475,21 +480,21 @@ def test_config_file_options(self, monkeypatch, args, expect): class TestOptionsExpandUser(AddFakeCommandMixin): def test_cache_dir(self): - options, args = main(['--cache-dir', '~/cache/dir', 'fake']) - assert options.cache_dir == os.path.expanduser('~/cache/dir') + options, args = main(["--cache-dir", "~/cache/dir", "fake"]) + assert options.cache_dir == os.path.expanduser("~/cache/dir") def test_log(self): - options, args = main(['--log', '~/path', 'fake']) - assert options.log == os.path.expanduser('~/path') + options, args = main(["--log", "~/path", "fake"]) + assert options.log == os.path.expanduser("~/path") def test_local_log(self): - options, args = main(['--local-log', '~/path', 'fake']) - assert options.log == os.path.expanduser('~/path') + options, args = main(["--local-log", "~/path", "fake"]) + assert options.log == os.path.expanduser("~/path") def test_cert(self): - options, args = main(['--cert', '~/path', 'fake']) - assert options.cert == os.path.expanduser('~/path') + options, args = main(["--cert", "~/path", "fake"]) + assert options.cert == os.path.expanduser("~/path") def test_client_cert(self): - options, args = main(['--client-cert', '~/path', 'fake']) - assert options.client_cert == os.path.expanduser('~/path') + options, args = main(["--client-cert", "~/path", "fake"]) + assert options.client_cert == os.path.expanduser("~/path") diff --git a/tests/unit/test_packaging.py b/tests/unit/test_packaging.py index 448e3806300..2386083dbd1 100644 --- a/tests/unit/test_packaging.py +++ b/tests/unit/test_packaging.py @@ -4,11 +4,14 @@ from pip._internal.utils.packaging import check_requires_python -@pytest.mark.parametrize('version_info, requires_python, expected', [ - ((3, 6, 5), '== 3.6.4', False), - ((3, 6, 5), '== 3.6.5', True), - ((3, 6, 5), None, True), -]) +@pytest.mark.parametrize( + "version_info, requires_python, expected", + [ + ((3, 6, 5), "== 3.6.4", False), + ((3, 6, 5), "== 3.6.5", True), + ((3, 6, 5), None, True), + ], +) def test_check_requires_python(version_info, requires_python, expected): actual = check_requires_python(requires_python, version_info) assert actual == expected @@ -19,4 +22,4 @@ def test_check_requires_python__invalid(): Test an invalid Requires-Python value. """ with pytest.raises(specifiers.InvalidSpecifier): - check_requires_python('invalid', (3, 6, 5)) + check_requires_python("invalid", (3, 6, 5)) diff --git a/tests/unit/test_pep517.py b/tests/unit/test_pep517.py index 18cb178bba7..2242cf92d71 100644 --- a/tests/unit/test_pep517.py +++ b/tests/unit/test_pep517.py @@ -6,11 +6,14 @@ from pip._internal.req import InstallRequirement -@pytest.mark.parametrize(('source', 'expected'), [ - ("pep517_setup_and_pyproject", True), - ("pep517_setup_only", False), - ("pep517_pyproject_only", True), -]) +@pytest.mark.parametrize( + ("source", "expected"), + [ + ("pep517_setup_and_pyproject", True), + ("pep517_setup_only", False), + ("pep517_pyproject_only", True), + ], +) def test_use_pep517(shared_data, source, expected): """ Test that we choose correctly between PEP 517 and legacy code paths @@ -22,10 +25,13 @@ def test_use_pep517(shared_data, source, expected): assert req.use_pep517 is expected -@pytest.mark.parametrize(('source', 'msg'), [ - ("pep517_setup_and_pyproject", "specifies a build backend"), - ("pep517_pyproject_only", "does not have a setup.py"), -]) +@pytest.mark.parametrize( + ("source", "msg"), + [ + ("pep517_setup_and_pyproject", "specifies a build backend"), + ("pep517_pyproject_only", "does not have a setup.py"), + ], +) def test_disabling_pep517_invalid(shared_data, source, msg): """ Test that we fail if we try to disable PEP 517 when it's not acceptable @@ -49,13 +55,17 @@ def test_disabling_pep517_invalid(shared_data, source, msg): ("spec",), [("./foo",), ("git+https://example.com/pkg@dev#egg=myproj",)] ) def test_pep517_parsing_checks_requirements(tmpdir, spec): - tmpdir.joinpath("pyproject.toml").write_text(dedent( - """ + tmpdir.joinpath("pyproject.toml").write_text( + dedent( + """ [build-system] requires = [{!r}] build-backend = "foo" - """.format(spec) - )) + """.format( + spec + ) + ) + ) req = InstallRequirement(None, None) req.source_dir = tmpdir # make req believe it has been unpacked diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 730a26a88d5..e7e060ed904 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -41,7 +41,7 @@ from tests.lib import assert_raises_regexp, make_test_finder, requirements_file -def get_processed_req_from_line(line, fname='file', lineno=1): +def get_processed_req_from_line(line, fname="file", lineno=1): line_parser = get_line_parser(None) args_str, opts = line_parser(line) parsed_line = ParsedLine( @@ -79,14 +79,14 @@ def _basic_resolver(self, finder, require_hashes=False): with get_requirement_tracker() as tracker: preparer = RequirementPreparer( - build_dir=os.path.join(self.tempdir, 'build'), - src_dir=os.path.join(self.tempdir, 'src'), + build_dir=os.path.join(self.tempdir, "build"), + src_dir=os.path.join(self.tempdir, "src"), download_dir=None, wheel_download_dir=None, build_isolation=True, req_tracker=tracker, session=session, - progress_bar='on', + progress_bar="on", finder=finder, require_hashes=require_hashes, use_user_site=False, @@ -97,29 +97,32 @@ def _basic_resolver(self, finder, require_hashes=False): make_install_req=make_install_req, finder=finder, wheel_cache=None, - use_user_site=False, upgrade_strategy="to-satisfy-only", - ignore_dependencies=False, ignore_installed=False, - ignore_requires_python=False, force_reinstall=False, + use_user_site=False, + upgrade_strategy="to-satisfy-only", + ignore_dependencies=False, + ignore_installed=False, + ignore_requires_python=False, + force_reinstall=False, ) def test_no_reuse_existing_build_dir(self, data): """Test prepare_files raise exception with previous build dir""" - build_dir = os.path.join(self.tempdir, 'build', 'simple') + build_dir = os.path.join(self.tempdir, "build", "simple") os.makedirs(build_dir) - with open(os.path.join(build_dir, "setup.py"), 'w'): + with open(os.path.join(build_dir, "setup.py"), "w"): pass reqset = RequirementSet() - req = install_req_from_line('simple') + req = install_req_from_line("simple") req.user_supplied = True reqset.add_requirement(req) finder = make_test_finder(find_links=[data.find_links]) with self._basic_resolver(finder) as resolver: assert_raises_regexp( PreviousBuildDirError, - r"pip can't proceed with [\s\S]*{req}[\s\S]*{build_dir_esc}" - .format( - build_dir_esc=build_dir.replace('\\', '\\\\'), req=req), + r"pip can't proceed with [\s\S]*{req}[\s\S]*{build_dir_esc}".format( + build_dir_esc=build_dir.replace("\\", "\\\\"), req=req + ), resolver.resolve, reqset.all_requirements, True, @@ -132,9 +135,7 @@ def test_environment_marker_extras(self, data): non-wheel installs. """ reqset = RequirementSet() - req = install_req_from_editable( - data.packages.joinpath("LocalEnvironMarker") - ) + req = install_req_from_editable(data.packages.joinpath("LocalEnvironMarker")) req.user_supplied = True reqset.add_requirement(req) finder = make_test_finder(find_links=[data.find_links]) @@ -142,28 +143,26 @@ def test_environment_marker_extras(self, data): reqset = resolver.resolve(reqset.all_requirements, True) # This is hacky but does test both case in py2 and py3 if sys.version_info[:2] == (2, 7): - assert reqset.has_requirement('simple') + assert reqset.has_requirement("simple") else: - assert not reqset.has_requirement('simple') + assert not reqset.has_requirement("simple") def test_missing_hash_with_require_hashes(self, data): """Setting --require-hashes explicitly should raise errors if hashes are missing. """ reqset = RequirementSet() - reqset.add_requirement(get_processed_req_from_line( - 'simple==1.0', lineno=1 - )) + reqset.add_requirement(get_processed_req_from_line("simple==1.0", lineno=1)) finder = make_test_finder(find_links=[data.find_links]) with self._basic_resolver(finder, require_hashes=True) as resolver: assert_raises_regexp( HashErrors, - r'Hashes are required in --require-hashes mode, but they are ' - r'missing .*\n' - r' simple==1.0 --hash=sha256:393043e672415891885c9a2a0929b1' - r'af95fb866d6ca016b42d2e6ce53619b653$', + r"Hashes are required in --require-hashes mode, but they are " + r"missing .*\n" + r" simple==1.0 --hash=sha256:393043e672415891885c9a2a0929b1" + r"af95fb866d6ca016b42d2e6ce53619b653$", resolver.resolve, reqset.all_requirements, True, @@ -175,9 +174,9 @@ def test_missing_hash_with_require_hashes_in_reqs_file(self, data, tmpdir): """ finder = make_test_finder(find_links=[data.find_links]) session = finder._link_collector.session - command = create_command('install') - with requirements_file('--require-hashes', tmpdir) as reqs_file: - options, args = command.parse_args(['-r', reqs_file]) + command = create_command("install") + with requirements_file("--require-hashes", tmpdir) as reqs_file: + options, args = command.parse_args(["-r", reqs_file]) command.get_requirements(args, options, finder, session) assert options.require_hashes @@ -190,20 +189,24 @@ def test_unsupported_hashes(self, data): """ reqset = RequirementSet() - reqset.add_requirement(get_processed_req_from_line( - 'git+git://github.com/pypa/pip-test-package --hash=sha256:123', - lineno=1, - )) - dir_path = data.packages.joinpath('FSPkg') - reqset.add_requirement(get_processed_req_from_line( - 'file://{dir_path}'.format(**locals()), - lineno=2, - )) + reqset.add_requirement( + get_processed_req_from_line( + "git+git://github.com/pypa/pip-test-package --hash=sha256:123", + lineno=1, + ) + ) + dir_path = data.packages.joinpath("FSPkg") + reqset.add_requirement( + get_processed_req_from_line( + "file://{dir_path}".format(**locals()), + lineno=2, + ) + ) finder = make_test_finder(find_links=[data.find_links]) sep = os.path.sep - if sep == '\\': - sep = '\\\\' # This needs to be escaped for the regex + if sep == "\\": + sep = "\\\\" # This needs to be escaped for the regex with self._basic_resolver(finder, require_hashes=True) as resolver: assert_raises_regexp( @@ -227,24 +230,29 @@ def test_unpinned_hash_checking(self, data): """ reqset = RequirementSet() # Test that there must be exactly 1 specifier: - reqset.add_requirement(get_processed_req_from_line( - 'simple --hash=sha256:a90427ae31f5d1d0d7ec06ee97d9fcf2d0fc9a786985' - '250c1c83fd68df5911dd', lineno=1, - )) + reqset.add_requirement( + get_processed_req_from_line( + "simple --hash=sha256:a90427ae31f5d1d0d7ec06ee97d9fcf2d0fc9a786985" + "250c1c83fd68df5911dd", + lineno=1, + ) + ) # Test that the operator must be ==: - reqset.add_requirement(get_processed_req_from_line( - 'simple2>1.0 --hash=sha256:3ad45e1e9aa48b4462af0' - '123f6a7e44a9115db1ef945d4d92c123dfe21815a06', - lineno=2, - )) + reqset.add_requirement( + get_processed_req_from_line( + "simple2>1.0 --hash=sha256:3ad45e1e9aa48b4462af0" + "123f6a7e44a9115db1ef945d4d92c123dfe21815a06", + lineno=2, + ) + ) finder = make_test_finder(find_links=[data.find_links]) with self._basic_resolver(finder, require_hashes=True) as resolver: assert_raises_regexp( HashErrors, # Make sure all failing requirements are listed: - r'versions pinned with ==. These do not:\n' - r' simple .* \(from -r file \(line 1\)\)\n' - r' simple2>1.0 .* \(from -r file \(line 2\)\)', + r"versions pinned with ==. These do not:\n" + r" simple .* \(from -r file \(line 1\)\)\n" + r" simple2>1.0 .* \(from -r file \(line 2\)\)", resolver.resolve, reqset.all_requirements, True, @@ -252,21 +260,23 @@ def test_unpinned_hash_checking(self, data): def test_hash_mismatch(self, data): """A hash mismatch should raise an error.""" - file_url = path_to_url( - (data.packages / 'simple-1.0.tar.gz').resolve()) + file_url = path_to_url((data.packages / "simple-1.0.tar.gz").resolve()) reqset = RequirementSet() - reqset.add_requirement(get_processed_req_from_line( - '{file_url} --hash=sha256:badbad'.format(**locals()), lineno=1, - )) + reqset.add_requirement( + get_processed_req_from_line( + "{file_url} --hash=sha256:badbad".format(**locals()), + lineno=1, + ) + ) finder = make_test_finder(find_links=[data.find_links]) with self._basic_resolver(finder, require_hashes=True) as resolver: assert_raises_regexp( HashErrors, - r'THESE PACKAGES DO NOT MATCH THE HASHES.*\n' - r' file:///.*/data/packages/simple-1\.0\.tar\.gz .*:\n' - r' Expected sha256 badbad\n' - r' Got 393043e672415891885c9a2a0929b1af95fb' - r'866d6ca016b42d2e6ce53619b653$', + r"THESE PACKAGES DO NOT MATCH THE HASHES.*\n" + r" file:///.*/data/packages/simple-1\.0\.tar\.gz .*:\n" + r" Expected sha256 badbad\n" + r" Got 393043e672415891885c9a2a0929b1af95fb" + r"866d6ca016b42d2e6ce53619b653$", resolver.resolve, reqset.all_requirements, True, @@ -277,19 +287,21 @@ def test_unhashed_deps_on_require_hashes(self, data): dependencies get complained about when --require-hashes is on.""" reqset = RequirementSet() finder = make_test_finder(find_links=[data.find_links]) - reqset.add_requirement(get_processed_req_from_line( - 'TopoRequires2==0.0.1 ' # requires TopoRequires - '--hash=sha256:eaf9a01242c9f2f42cf2bd82a6a848cd' - 'e3591d14f7896bdbefcf48543720c970', - lineno=1 - )) + reqset.add_requirement( + get_processed_req_from_line( + "TopoRequires2==0.0.1 " # requires TopoRequires + "--hash=sha256:eaf9a01242c9f2f42cf2bd82a6a848cd" + "e3591d14f7896bdbefcf48543720c970", + lineno=1, + ) + ) with self._basic_resolver(finder, require_hashes=True) as resolver: assert_raises_regexp( HashErrors, - r'In --require-hashes mode, all requirements must have their ' - r'versions pinned.*\n' - r' TopoRequires from .*$', + r"In --require-hashes mode, all requirements must have their " + r"versions pinned.*\n" + r" TopoRequires from .*$", resolver.resolve, reqset.all_requirements, True, @@ -305,18 +317,22 @@ def test_hashed_deps_on_require_hashes(self): """ reqset = RequirementSet() - reqset.add_requirement(get_processed_req_from_line( - 'TopoRequires2==0.0.1 ' # requires TopoRequires - '--hash=sha256:eaf9a01242c9f2f42cf2bd82a6a848cd' - 'e3591d14f7896bdbefcf48543720c970', - lineno=1 - )) - reqset.add_requirement(get_processed_req_from_line( - 'TopoRequires==0.0.1 ' - '--hash=sha256:d6dd1e22e60df512fdcf3640ced3039b3b02a56ab2cee81ebcb' - '3d0a6d4e8bfa6', - lineno=2 - )) + reqset.add_requirement( + get_processed_req_from_line( + "TopoRequires2==0.0.1 " # requires TopoRequires + "--hash=sha256:eaf9a01242c9f2f42cf2bd82a6a848cd" + "e3591d14f7896bdbefcf48543720c970", + lineno=1, + ) + ) + reqset.add_requirement( + get_processed_req_from_line( + "TopoRequires==0.0.1 " + "--hash=sha256:d6dd1e22e60df512fdcf3640ced3039b3b02a56ab2cee81ebcb" + "3d0a6d4e8bfa6", + lineno=2, + ) + ) class TestInstallRequirement(object): @@ -328,32 +344,32 @@ def teardown(self): def test_url_with_query(self): """InstallRequirement should strip the fragment, but not the query.""" - url = 'http://foo.com/?p=bar.git;a=snapshot;h=v0.1;sf=tgz' - fragment = '#egg=bar' + url = "http://foo.com/?p=bar.git;a=snapshot;h=v0.1;sf=tgz" + fragment = "#egg=bar" req = install_req_from_line(url + fragment) assert req.link.url == url + fragment, req.link def test_pep440_wheel_link_requirement(self): - url = 'https://whatever.com/test-0.4-py2.py3-bogus-any.whl' - line = 'test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl' + url = "https://whatever.com/test-0.4-py2.py3-bogus-any.whl" + line = "test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl" req = install_req_from_line(line) - parts = str(req.req).split('@', 1) + parts = str(req.req).split("@", 1) assert len(parts) == 2 - assert parts[0].strip() == 'test' + assert parts[0].strip() == "test" assert parts[1].strip() == url def test_pep440_url_link_requirement(self): - url = 'git+http://foo.com@ref#egg=foo' - line = 'foo @ git+http://foo.com@ref#egg=foo' + url = "git+http://foo.com@ref#egg=foo" + line = "foo @ git+http://foo.com@ref#egg=foo" req = install_req_from_line(line) - parts = str(req.req).split('@', 1) + parts = str(req.req).split("@", 1) assert len(parts) == 2 - assert parts[0].strip() == 'foo' + assert parts[0].strip() == "foo" assert parts[1].strip() == url def test_url_with_authentication_link_requirement(self): - url = 'https://what@whatever.com/test-0.4-py2.py3-bogus-any.whl' - line = 'https://what@whatever.com/test-0.4-py2.py3-bogus-any.whl' + url = "https://what@whatever.com/test-0.4-py2.py3-bogus-any.whl" + line = "https://what@whatever.com/test-0.4-py2.py3-bogus-any.whl" req = install_req_from_line(line) assert req.link is not None assert req.link.is_wheel @@ -363,7 +379,7 @@ def test_url_with_authentication_link_requirement(self): def test_unsupported_wheel_link_requirement_raises(self): reqset = RequirementSet() req = install_req_from_line( - 'https://whatever.com/peppercorn-0.4-py2.py3-bogus-any.whl', + "https://whatever.com/peppercorn-0.4-py2.py3-bogus-any.whl", ) assert req.link is not None assert req.link.is_wheel @@ -375,7 +391,7 @@ def test_unsupported_wheel_link_requirement_raises(self): def test_unsupported_wheel_local_file_requirement_raises(self, data): reqset = RequirementSet() req = install_req_from_line( - data.packages.joinpath('simple.dist-0.1-py1-none-invalid.whl'), + data.packages.joinpath("simple.dist-0.1-py1-none-invalid.whl"), ) assert req.link is not None assert req.link.is_wheel @@ -385,52 +401,53 @@ def test_unsupported_wheel_local_file_requirement_raises(self, data): reqset.add_requirement(req) def test_installed_version_not_installed(self): - req = install_req_from_line('simple-0.1-py2.py3-none-any.whl') + req = install_req_from_line("simple-0.1-py2.py3-none-any.whl") assert req.installed_version is None def test_str(self): - req = install_req_from_line('simple==0.1') - assert str(req) == 'simple==0.1' + req = install_req_from_line("simple==0.1") + assert str(req) == "simple==0.1" def test_repr(self): - req = install_req_from_line('simple==0.1') - assert repr(req) == ( - '' - ) + req = install_req_from_line("simple==0.1") + assert repr(req) == ("") def test_invalid_wheel_requirement_raises(self): with pytest.raises(InvalidWheelFilename): - install_req_from_line('invalid.whl') + install_req_from_line("invalid.whl") def test_wheel_requirement_sets_req_attribute(self): - req = install_req_from_line('simple-0.1-py2.py3-none-any.whl') + req = install_req_from_line("simple-0.1-py2.py3-none-any.whl") assert isinstance(req.req, Requirement) - assert str(req.req) == 'simple==0.1' + assert str(req.req) == "simple==0.1" def test_url_preserved_line_req(self): """Confirm the url is preserved in a non-editable requirement""" - url = 'git+http://foo.com@ref#egg=foo' + url = "git+http://foo.com@ref#egg=foo" req = install_req_from_line(url) assert req.link.url == url def test_url_preserved_editable_req(self): """Confirm the url is preserved in a editable requirement""" - url = 'git+http://foo.com@ref#egg=foo' + url = "git+http://foo.com@ref#egg=foo" req = install_req_from_editable(url) assert req.link.url == url - @pytest.mark.parametrize('path', ( - '/path/to/foo.egg-info'.replace('/', os.path.sep), - # Tests issue fixed by https://github.com/pypa/pip/pull/2530 - '/path/to/foo.egg-info/'.replace('/', os.path.sep), - )) + @pytest.mark.parametrize( + "path", + ( + "/path/to/foo.egg-info".replace("/", os.path.sep), + # Tests issue fixed by https://github.com/pypa/pip/pull/2530 + "/path/to/foo.egg-info/".replace("/", os.path.sep), + ), + ) def test_get_dist(self, path): - req = install_req_from_line('foo') + req = install_req_from_line("foo") req.metadata_directory = path dist = req.get_dist() assert isinstance(dist, pkg_resources.Distribution) - assert dist.project_name == 'foo' - assert dist.location == '/path/to'.replace('/', os.path.sep) + assert dist.project_name == "foo" + assert dist.location == "/path/to".replace("/", os.path.sep) def test_markers(self): for line in ( @@ -442,27 +459,27 @@ def test_markers(self): 'mock3;python_version >= "3"', ): req = install_req_from_line(line) - assert req.req.name == 'mock3' - assert str(req.req.specifier) == '' + assert req.req.name == "mock3" + assert str(req.req.specifier) == "" assert str(req.markers) == 'python_version >= "3"' def test_markers_semicolon(self): # check that the markers can contain a semicolon req = install_req_from_line('semicolon; os_name == "a; b"') - assert req.req.name == 'semicolon' - assert str(req.req.specifier) == '' + assert req.req.name == "semicolon" + assert str(req.req.specifier) == "" assert str(req.markers) == 'os_name == "a; b"' def test_markers_url(self): # test "URL; markers" syntax - url = 'http://foo.com/?p=bar.git;a=snapshot;h=v0.1;sf=tgz' + url = "http://foo.com/?p=bar.git;a=snapshot;h=v0.1;sf=tgz" line = '{}; python_version >= "3"'.format(url) req = install_req_from_line(line) assert req.link.url == url, req.url assert str(req.markers) == 'python_version >= "3"' # without space, markers are part of the URL - url = 'http://foo.com/?p=bar.git;a=snapshot;h=v0.1;sf=tgz' + url = "http://foo.com/?p=bar.git;a=snapshot;h=v0.1;sf=tgz" line = '{};python_version >= "3"'.format(url) req = install_req_from_line(line) assert req.link.url == line, req.url @@ -472,9 +489,9 @@ def test_markers_match_from_line(self): # match for markers in ( 'python_version >= "1.0"', - 'sys_platform == {sys.platform!r}'.format(**globals()), + "sys_platform == {sys.platform!r}".format(**globals()), ): - line = 'name; ' + markers + line = "name; " + markers req = install_req_from_line(line) assert str(req.markers) == str(Marker(markers)) assert req.match_markers() @@ -482,9 +499,9 @@ def test_markers_match_from_line(self): # don't match for markers in ( 'python_version >= "5.0"', - 'sys_platform != {sys.platform!r}'.format(**globals()), + "sys_platform != {sys.platform!r}".format(**globals()), ): - line = 'name; ' + markers + line = "name; " + markers req = install_req_from_line(line) assert str(req.markers) == str(Marker(markers)) assert not req.match_markers() @@ -493,81 +510,80 @@ def test_markers_match(self): # match for markers in ( 'python_version >= "1.0"', - 'sys_platform == {sys.platform!r}'.format(**globals()), + "sys_platform == {sys.platform!r}".format(**globals()), ): - line = 'name; ' + markers - req = install_req_from_line(line, comes_from='') + line = "name; " + markers + req = install_req_from_line(line, comes_from="") assert str(req.markers) == str(Marker(markers)) assert req.match_markers() # don't match for markers in ( 'python_version >= "5.0"', - 'sys_platform != {sys.platform!r}'.format(**globals()), + "sys_platform != {sys.platform!r}".format(**globals()), ): - line = 'name; ' + markers - req = install_req_from_line(line, comes_from='') + line = "name; " + markers + req = install_req_from_line(line, comes_from="") assert str(req.markers) == str(Marker(markers)) assert not req.match_markers() def test_extras_for_line_path_requirement(self): - line = 'SomeProject[ex1,ex2]' - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + line = "SomeProject[ex1,ex2]" + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_line(line, comes_from=comes_from) assert len(req.extras) == 2 - assert req.extras == {'ex1', 'ex2'} + assert req.extras == {"ex1", "ex2"} def test_extras_for_line_url_requirement(self): - line = 'git+https://url#egg=SomeProject[ex1,ex2]' - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + line = "git+https://url#egg=SomeProject[ex1,ex2]" + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_line(line, comes_from=comes_from) assert len(req.extras) == 2 - assert req.extras == {'ex1', 'ex2'} + assert req.extras == {"ex1", "ex2"} def test_extras_for_editable_path_requirement(self): - url = '.[ex1,ex2]' - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + url = ".[ex1,ex2]" + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_editable(url, comes_from=comes_from) assert len(req.extras) == 2 - assert req.extras == {'ex1', 'ex2'} + assert req.extras == {"ex1", "ex2"} def test_extras_for_editable_url_requirement(self): - url = 'git+https://url#egg=SomeProject[ex1,ex2]' - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + url = "git+https://url#egg=SomeProject[ex1,ex2]" + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_editable(url, comes_from=comes_from) assert len(req.extras) == 2 - assert req.extras == {'ex1', 'ex2'} + assert req.extras == {"ex1", "ex2"} def test_unexisting_path(self): with pytest.raises(InstallationError) as e: - install_req_from_line( - os.path.join('this', 'path', 'does', 'not', 'exist')) + install_req_from_line(os.path.join("this", "path", "does", "not", "exist")) err_msg = e.value.args[0] assert "Invalid requirement" in err_msg assert "It looks like a path." in err_msg def test_single_equal_sign(self): with pytest.raises(InstallationError) as e: - install_req_from_line('toto=42') + install_req_from_line("toto=42") err_msg = e.value.args[0] assert "Invalid requirement" in err_msg assert "= is not a valid operator. Did you mean == ?" in err_msg def test_unidentifiable_name(self): - test_name = '-' + test_name = "-" with pytest.raises(InstallationError) as e: install_req_from_line(test_name) err_msg = e.value.args[0] assert "Invalid requirement: '{}'".format(test_name) == err_msg def test_requirement_file(self): - req_file_path = os.path.join(self.tempdir, 'test.txt') - with open(req_file_path, 'w') as req_file: - req_file.write('pip\nsetuptools') + req_file_path = os.path.join(self.tempdir, "test.txt") + with open(req_file_path, "w") as req_file: + req_file.write("pip\nsetuptools") with pytest.raises(InstallationError) as e: install_req_from_line(req_file_path) err_msg = e.value.args[0] @@ -577,71 +593,73 @@ def test_requirement_file(self): assert "If that is the case, use the '-r' flag to install" in err_msg -@patch('pip._internal.req.req_install.os.path.abspath') -@patch('pip._internal.req.req_install.os.path.exists') -@patch('pip._internal.req.req_install.os.path.isdir') -def test_parse_editable_local( - isdir_mock, exists_mock, abspath_mock): +@patch("pip._internal.req.req_install.os.path.abspath") +@patch("pip._internal.req.req_install.os.path.exists") +@patch("pip._internal.req.req_install.os.path.isdir") +def test_parse_editable_local(isdir_mock, exists_mock, abspath_mock): exists_mock.return_value = isdir_mock.return_value = True # mocks needed to support path operations on windows tests abspath_mock.return_value = "/some/path" - assert parse_editable('.') == (None, 'file:///some/path', set()) + assert parse_editable(".") == (None, "file:///some/path", set()) abspath_mock.return_value = "/some/path/foo" - assert parse_editable('foo') == ( - None, 'file:///some/path/foo', set(), + assert parse_editable("foo") == ( + None, + "file:///some/path/foo", + set(), ) def test_parse_editable_explicit_vcs(): - assert parse_editable('svn+https://foo#egg=foo') == ( - 'foo', - 'svn+https://foo#egg=foo', + assert parse_editable("svn+https://foo#egg=foo") == ( + "foo", + "svn+https://foo#egg=foo", set(), ) def test_parse_editable_vcs_extras(): - assert parse_editable('svn+https://foo#egg=foo[extras]') == ( - 'foo[extras]', - 'svn+https://foo#egg=foo[extras]', + assert parse_editable("svn+https://foo#egg=foo[extras]") == ( + "foo[extras]", + "svn+https://foo#egg=foo[extras]", set(), ) -@patch('pip._internal.req.req_install.os.path.abspath') -@patch('pip._internal.req.req_install.os.path.exists') -@patch('pip._internal.req.req_install.os.path.isdir') -def test_parse_editable_local_extras( - isdir_mock, exists_mock, abspath_mock): +@patch("pip._internal.req.req_install.os.path.abspath") +@patch("pip._internal.req.req_install.os.path.exists") +@patch("pip._internal.req.req_install.os.path.isdir") +def test_parse_editable_local_extras(isdir_mock, exists_mock, abspath_mock): exists_mock.return_value = isdir_mock.return_value = True abspath_mock.return_value = "/some/path" - assert parse_editable('.[extras]') == ( - None, 'file://' + "/some/path", {'extras'}, + assert parse_editable(".[extras]") == ( + None, + "file://" + "/some/path", + {"extras"}, ) abspath_mock.return_value = "/some/path/foo" - assert parse_editable('foo[bar,baz]') == ( - None, 'file:///some/path/foo', {'bar', 'baz'}, + assert parse_editable("foo[bar,baz]") == ( + None, + "file:///some/path/foo", + {"bar", "baz"}, ) def test_exclusive_environment_markers(): """Make sure RequirementSet accepts several excluding env markers""" - eq36 = install_req_from_line( - "Django>=1.6.10,<1.7 ; python_version == '3.6'") + eq36 = install_req_from_line("Django>=1.6.10,<1.7 ; python_version == '3.6'") eq36.user_supplied = True - ne36 = install_req_from_line( - "Django>=1.6.10,<1.8 ; python_version != '3.6'") + ne36 = install_req_from_line("Django>=1.6.10,<1.8 ; python_version != '3.6'") ne36.user_supplied = True req_set = RequirementSet() req_set.add_requirement(eq36) req_set.add_requirement(ne36) - assert req_set.has_requirement('Django') + assert req_set.has_requirement("Django") def test_mismatched_versions(caplog): req = InstallRequirement( - req=Requirement('simplewheel==2.0'), + req=Requirement("simplewheel==2.0"), comes_from=None, ) req.source_dir = "/tmp/somewhere" # make req believe it has been unpacked @@ -649,96 +667,117 @@ def test_mismatched_versions(caplog): req._metadata = {"name": "simplewheel", "version": "1.0"} req.assert_source_matches_version() assert caplog.records[-1].message == ( - 'Requested simplewheel==2.0, but installing version 1.0' + "Requested simplewheel==2.0, but installing version 1.0" ) -@pytest.mark.parametrize('args, expected', [ - # Test UNIX-like paths - (('/path/to/installable'), True), - # Test relative paths - (('./path/to/installable'), True), - # Test current path - (('.'), True), - # Test url paths - (('https://whatever.com/test-0.4-py2.py3-bogus-any.whl'), True), - # Test pep440 paths - (('test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl'), True), - # Test wheel - (('simple-0.1-py2.py3-none-any.whl'), False), -]) +@pytest.mark.parametrize( + "args, expected", + [ + # Test UNIX-like paths + (("/path/to/installable"), True), + # Test relative paths + (("./path/to/installable"), True), + # Test current path + (("."), True), + # Test url paths + (("https://whatever.com/test-0.4-py2.py3-bogus-any.whl"), True), + # Test pep440 paths + (("test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl"), True), + # Test wheel + (("simple-0.1-py2.py3-none-any.whl"), False), + ], +) def test_looks_like_path(args, expected): assert _looks_like_path(args) == expected @pytest.mark.skipif( - not sys.platform.startswith("win"), - reason='Test only available on Windows' + not sys.platform.startswith("win"), reason="Test only available on Windows" +) +@pytest.mark.parametrize( + "args, expected", + [ + # Test relative paths + ((".\\path\\to\\installable"), True), + (("relative\\path"), True), + # Test absolute paths + (("C:\\absolute\\path"), True), + ], ) -@pytest.mark.parametrize('args, expected', [ - # Test relative paths - (('.\\path\\to\\installable'), True), - (('relative\\path'), True), - # Test absolute paths - (('C:\\absolute\\path'), True), -]) def test_looks_like_path_win(args, expected): assert _looks_like_path(args) == expected -@pytest.mark.parametrize('args, mock_returns, expected', [ - # Test pep440 urls - (('/path/to/foo @ git+http://foo.com@ref#egg=foo', - 'foo @ git+http://foo.com@ref#egg=foo'), (False, False), None), - # Test pep440 urls without spaces - (('/path/to/foo@git+http://foo.com@ref#egg=foo', - 'foo @ git+http://foo.com@ref#egg=foo'), (False, False), None), - # Test pep440 wheel - (('/path/to/test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl', - 'test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl'), - (False, False), None), - # Test name is not a file - (('/path/to/simple==0.1', - 'simple==0.1'), - (False, False), None), -]) -@patch('pip._internal.req.req_install.os.path.isdir') -@patch('pip._internal.req.req_install.os.path.isfile') -def test_get_url_from_path( - isdir_mock, isfile_mock, args, mock_returns, expected -): +@pytest.mark.parametrize( + "args, mock_returns, expected", + [ + # Test pep440 urls + ( + ( + "/path/to/foo @ git+http://foo.com@ref#egg=foo", + "foo @ git+http://foo.com@ref#egg=foo", + ), + (False, False), + None, + ), + # Test pep440 urls without spaces + ( + ( + "/path/to/foo@git+http://foo.com@ref#egg=foo", + "foo @ git+http://foo.com@ref#egg=foo", + ), + (False, False), + None, + ), + # Test pep440 wheel + ( + ( + "/path/to/test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl", + "test @ https://whatever.com/test-0.4-py2.py3-bogus-any.whl", + ), + (False, False), + None, + ), + # Test name is not a file + (("/path/to/simple==0.1", "simple==0.1"), (False, False), None), + ], +) +@patch("pip._internal.req.req_install.os.path.isdir") +@patch("pip._internal.req.req_install.os.path.isfile") +def test_get_url_from_path(isdir_mock, isfile_mock, args, mock_returns, expected): isdir_mock.return_value = mock_returns[0] isfile_mock.return_value = mock_returns[1] assert _get_url_from_path(*args) is expected -@patch('pip._internal.req.req_install.os.path.isdir') -@patch('pip._internal.req.req_install.os.path.isfile') +@patch("pip._internal.req.req_install.os.path.isdir") +@patch("pip._internal.req.req_install.os.path.isfile") def test_get_url_from_path__archive_file(isdir_mock, isfile_mock): isdir_mock.return_value = False isfile_mock.return_value = True - name = 'simple-0.1-py2.py3-none-any.whl' - path = os.path.join('/path/to/' + name) + name = "simple-0.1-py2.py3-none-any.whl" + path = os.path.join("/path/to/" + name) url = path_to_url(path) assert _get_url_from_path(path, name) == url -@patch('pip._internal.req.req_install.os.path.isdir') -@patch('pip._internal.req.req_install.os.path.isfile') +@patch("pip._internal.req.req_install.os.path.isdir") +@patch("pip._internal.req.req_install.os.path.isfile") def test_get_url_from_path__installable_dir(isdir_mock, isfile_mock): isdir_mock.return_value = True isfile_mock.return_value = True - name = 'some/setuptools/project' - path = os.path.join('/path/to/' + name) + name = "some/setuptools/project" + path = os.path.join("/path/to/" + name) url = path_to_url(path) assert _get_url_from_path(path, name) == url -@patch('pip._internal.req.req_install.os.path.isdir') +@patch("pip._internal.req.req_install.os.path.isdir") def test_get_url_from_path__installable_error(isdir_mock): isdir_mock.return_value = True - name = 'some/setuptools/project' - path = os.path.join('/path/to/' + name) + name = "some/setuptools/project" + path = os.path.join("/path/to/" + name) with pytest.raises(InstallationError) as e: _get_url_from_path(path, name) err_msg = e.value.args[0] diff --git a/tests/unit/test_req_file.py b/tests/unit/test_req_file.py index 69d93a0cdc2..3624a62dc19 100644 --- a/tests/unit/test_req_file.py +++ b/tests/unit/test_req_file.py @@ -10,10 +10,7 @@ from pretend import stub import pip._internal.req.req_file # this will be monkeypatched -from pip._internal.exceptions import ( - InstallationError, - RequirementsFileParseError, -) +from pip._internal.exceptions import InstallationError, RequirementsFileParseError from pip._internal.models.format_control import FormatControl from pip._internal.network.session import PipSession from pip._internal.req.constructors import ( @@ -45,7 +42,7 @@ def finder(session): def options(session): return stub( isolated_mode=False, - index_url='default_url', + index_url="default_url", format_control=FormatControl(set(), set()), features_enabled=[], ) @@ -62,93 +59,105 @@ def parse_reqfile( # Wrap parse_requirements/install_req_from_parsed_requirement to # avoid having to write the same chunk of code in lots of tests. for parsed_req in parse_requirements( - filename, session, finder=finder, - options=options, constraint=constraint, + filename, + session, + finder=finder, + options=options, + constraint=constraint, ): - yield install_req_from_parsed_requirement( - parsed_req, - isolated=isolated - ) + yield install_req_from_parsed_requirement(parsed_req, isolated=isolated) class TestPreprocess(object): """tests for `preprocess`""" def test_comments_and_joins_case1(self): - content = textwrap.dedent("""\ + content = textwrap.dedent( + """\ req1 \\ # comment \\ req2 - """) + """ + ) result = preprocess(content) - assert list(result) == [(1, 'req1'), (3, 'req2')] + assert list(result) == [(1, "req1"), (3, "req2")] def test_comments_and_joins_case2(self): - content = textwrap.dedent("""\ + content = textwrap.dedent( + """\ req1\\ # comment - """) + """ + ) result = preprocess(content) - assert list(result) == [(1, 'req1')] + assert list(result) == [(1, "req1")] def test_comments_and_joins_case3(self): - content = textwrap.dedent("""\ + content = textwrap.dedent( + """\ req1 \\ # comment req2 - """) + """ + ) result = preprocess(content) - assert list(result) == [(1, 'req1'), (3, 'req2')] + assert list(result) == [(1, "req1"), (3, "req2")] class TestIgnoreComments(object): """tests for `ignore_comment`""" def test_ignore_line(self): - lines = [(1, ''), (2, 'req1'), (3, 'req2')] + lines = [(1, ""), (2, "req1"), (3, "req2")] result = ignore_comments(lines) - assert list(result) == [(2, 'req1'), (3, 'req2')] + assert list(result) == [(2, "req1"), (3, "req2")] def test_ignore_comment(self): - lines = [(1, 'req1'), (2, '# comment'), (3, 'req2')] + lines = [(1, "req1"), (2, "# comment"), (3, "req2")] result = ignore_comments(lines) - assert list(result) == [(1, 'req1'), (3, 'req2')] + assert list(result) == [(1, "req1"), (3, "req2")] def test_strip_comment(self): - lines = [(1, 'req1'), (2, 'req # comment'), (3, 'req2')] + lines = [(1, "req1"), (2, "req # comment"), (3, "req2")] result = ignore_comments(lines) - assert list(result) == [(1, 'req1'), (2, 'req'), (3, 'req2')] + assert list(result) == [(1, "req1"), (2, "req"), (3, "req2")] class TestJoinLines(object): """tests for `join_lines`""" def test_join_lines(self): - lines = enumerate([ - 'line 1', - 'line 2:1 \\', - 'line 2:2', - 'line 3:1 \\', - 'line 3:2 \\', - 'line 3:3', - 'line 4' - ], start=1) + lines = enumerate( + [ + "line 1", + "line 2:1 \\", + "line 2:2", + "line 3:1 \\", + "line 3:2 \\", + "line 3:3", + "line 4", + ], + start=1, + ) expect = [ - (1, 'line 1'), - (2, 'line 2:1 line 2:2'), - (4, 'line 3:1 line 3:2 line 3:3'), - (7, 'line 4'), + (1, "line 1"), + (2, "line 2:1 line 2:2"), + (4, "line 3:1 line 3:2 line 3:3"), + (7, "line 4"), ] assert expect == list(join_lines(lines)) def test_last_line_with_escape(self): - lines = enumerate([ - 'line 1', - 'line 2 \\', - ], start=1) + lines = enumerate( + [ + "line 1", + "line 2 \\", + ], + start=1, + ) expect = [ - (1, 'line 1'), - (2, 'line 2 '), + (1, "line 1"), + (2, "line 2 "), ] assert expect == list(join_lines(lines)) @@ -170,19 +179,21 @@ def process_line( if session is None: session = PipSession() - prefix = '\n' * (line_number - 1) + prefix = "\n" * (line_number - 1) path = tmpdir.joinpath(filename) path.parent.mkdir(exist_ok=True) path.write_text(prefix + line) monkeypatch.chdir(str(tmpdir)) - return list(parse_reqfile( - filename, - finder=finder, - options=options, - session=session, - constraint=constraint, - isolated=options.isolated_mode if options else False - )) + return list( + parse_reqfile( + filename, + finder=finder, + options=options, + session=session, + constraint=constraint, + isolated=options.isolated_mode if options else False, + ) + ) return process_line @@ -195,16 +206,16 @@ def test_parser_error(self, line_processor): line_processor("--bogus", "file", 1) def test_parser_offending_line(self, line_processor): - line = 'pkg==1.0.0 --hash=somehash' + line = "pkg==1.0.0 --hash=somehash" with pytest.raises(RequirementsFileParseError) as err: - line_processor(line, 'file', 1) + line_processor(line, "file", 1) assert line in str(err.value) def test_parser_non_offending_line(self, line_processor): try: - line_processor('pkg==1.0.0 --hash=sha256:somehash', 'file', 1) + line_processor("pkg==1.0.0 --hash=sha256:somehash", "file", 1) except RequirementsFileParseError: - pytest.fail('Reported offending line where it should not.') + pytest.fail("Reported offending line where it should not.") def test_only_one_req_per_line(self, line_processor): # pkg_resources raises the ValueError @@ -218,95 +229,89 @@ def test_error_message(self, line_processor): """ with pytest.raises(InstallationError) as exc: line_processor( - 'my-package=1.0', - filename='path/requirements.txt', - line_number=3 + "my-package=1.0", filename="path/requirements.txt", line_number=3 ) package_name = "u'my-package=1.0'" if PY2 else "'my-package=1.0'" expected = ( "Invalid requirement: {} " - '(from line 3 of path/requirements.txt)\n' - 'Hint: = is not a valid operator. Did you mean == ?' + "(from line 3 of path/requirements.txt)\n" + "Hint: = is not a valid operator. Did you mean == ?" ).format(package_name) assert str(exc.value) == expected def test_yield_line_requirement(self, line_processor): - line = 'SomeProject' - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + line = "SomeProject" + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_line(line, comes_from=comes_from) assert repr(line_processor(line, filename, 1)[0]) == repr(req) def test_yield_pep440_line_requirement(self, line_processor): - line = 'SomeProject @ https://url/SomeProject-py2-py3-none-any.whl' - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + line = "SomeProject @ https://url/SomeProject-py2-py3-none-any.whl" + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_line(line, comes_from=comes_from) assert repr(line_processor(line, filename, 1)[0]) == repr(req) def test_yield_line_constraint(self, line_processor): - line = 'SomeProject' - filename = 'filename' - comes_from = '-c {} (line {})'.format(filename, 1) - req = install_req_from_line( - line, comes_from=comes_from, constraint=True) + line = "SomeProject" + filename = "filename" + comes_from = "-c {} (line {})".format(filename, 1) + req = install_req_from_line(line, comes_from=comes_from, constraint=True) found_req = line_processor(line, filename, 1, constraint=True)[0] assert repr(found_req) == repr(req) assert found_req.constraint is True - def test_yield_line_requirement_with_spaces_in_specifier( - self, line_processor - ): - line = 'SomeProject >= 2' - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + def test_yield_line_requirement_with_spaces_in_specifier(self, line_processor): + line = "SomeProject >= 2" + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_line(line, comes_from=comes_from) assert repr(line_processor(line, filename, 1)[0]) == repr(req) - assert str(req.req.specifier) == '>=2' + assert str(req.req.specifier) == ">=2" def test_yield_editable_requirement(self, line_processor): - url = 'git+https://url#egg=SomeProject' - line = '-e {url}'.format(**locals()) - filename = 'filename' - comes_from = '-r {} (line {})'.format(filename, 1) + url = "git+https://url#egg=SomeProject" + line = "-e {url}".format(**locals()) + filename = "filename" + comes_from = "-r {} (line {})".format(filename, 1) req = install_req_from_editable(url, comes_from=comes_from) assert repr(line_processor(line, filename, 1)[0]) == repr(req) def test_yield_editable_constraint(self, line_processor): - url = 'git+https://url#egg=SomeProject' - line = '-e {}'.format(url) - filename = 'filename' - comes_from = '-c {} (line {})'.format(filename, 1) - req = install_req_from_editable( - url, comes_from=comes_from, constraint=True) + url = "git+https://url#egg=SomeProject" + line = "-e {}".format(url) + filename = "filename" + comes_from = "-c {} (line {})".format(filename, 1) + req = install_req_from_editable(url, comes_from=comes_from, constraint=True) found_req = line_processor(line, filename, 1, constraint=True)[0] assert repr(found_req) == repr(req) assert found_req.constraint is True def test_nested_constraints_file(self, monkeypatch, tmpdir): - req_name = 'hello' - req_file = tmpdir / 'parent' / 'req_file.txt' + req_name = "hello" + req_file = tmpdir / "parent" / "req_file.txt" req_file.parent.mkdir() - req_file.write_text('-c reqs.txt') - req_file.parent.joinpath('reqs.txt').write_text(req_name) + req_file.write_text("-c reqs.txt") + req_file.parent.joinpath("reqs.txt").write_text(req_name) monkeypatch.chdir(str(tmpdir)) - reqs = list( - parse_reqfile('./parent/req_file.txt', session=session) - ) + reqs = list(parse_reqfile("./parent/req_file.txt", session=session)) assert len(reqs) == 1 assert reqs[0].name == req_name assert reqs[0].constraint def test_options_on_a_requirement_line(self, line_processor): - line = 'SomeProject --install-option=yo1 --install-option yo2 '\ - '--global-option="yo3" --global-option "yo4"' - filename = 'filename' + line = ( + "SomeProject --install-option=yo1 --install-option yo2 " + '--global-option="yo3" --global-option "yo4"' + ) + filename = "filename" req = line_processor(line, filename, 1)[0] - assert req.global_options == ['yo3', 'yo4'] - assert req.install_options == ['yo1', 'yo2'] + assert req.global_options == ["yo3", "yo4"] + assert req.install_options == ["yo1", "yo2"] def test_hash_options(self, line_processor): """Test the --hash option: mostly its value storage. @@ -314,25 +319,30 @@ def test_hash_options(self, line_processor): Make sure it reads and preserve multiple hashes. """ - line = ('SomeProject --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b1' - '61e5c1fa7425e73043362938b9824 ' - '--hash=sha384:59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c' - '3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f ' - '--hash=sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8' - 'e5a6c65260e9cb8a7') - filename = 'filename' + line = ( + "SomeProject --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b1" + "61e5c1fa7425e73043362938b9824 " + "--hash=sha384:59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c" + "3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f " + "--hash=sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8" + "e5a6c65260e9cb8a7" + ) + filename = "filename" req = line_processor(line, filename, 1)[0] assert req.hash_options == { - 'sha256': ['2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e730433' - '62938b9824', - '486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65' - '260e9cb8a7'], - 'sha384': ['59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcd' - 'b9c666fa90125a3c79f90397bdf5f6a13de828684f']} + "sha256": [ + "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e730433" "62938b9824", + "486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65" "260e9cb8a7", + ], + "sha384": [ + "59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcd" + "b9c666fa90125a3c79f90397bdf5f6a13de828684f" + ], + } def test_set_isolated(self, line_processor, options): - line = 'SomeProject' - filename = 'filename' + line = "SomeProject" + filename = "filename" options.isolated_mode = True result = line_processor(line, filename, 1, options=options) assert result[0].isolated @@ -342,46 +352,38 @@ def test_set_finder_no_index(self, line_processor, finder): assert finder.index_urls == [] def test_set_finder_index_url(self, line_processor, finder, session): - line_processor( - "--index-url=url", "file", 1, finder=finder, session=session) - assert finder.index_urls == ['url'] - assert session.auth.index_urls == ['url'] + line_processor("--index-url=url", "file", 1, finder=finder, session=session) + assert finder.index_urls == ["url"] + assert session.auth.index_urls == ["url"] def test_set_finder_find_links(self, line_processor, finder): line_processor("--find-links=url", "file", 1, finder=finder) - assert finder.find_links == ['url'] + assert finder.find_links == ["url"] - def test_set_finder_extra_index_urls( - self, line_processor, finder, session): + def test_set_finder_extra_index_urls(self, line_processor, finder, session): line_processor( - "--extra-index-url=url", "file", 1, finder=finder, session=session) - assert finder.index_urls == ['url'] - assert session.auth.index_urls == ['url'] + "--extra-index-url=url", "file", 1, finder=finder, session=session + ) + assert finder.index_urls == ["url"] + assert session.auth.index_urls == ["url"] - def test_set_finder_trusted_host( - self, line_processor, caplog, session, finder - ): + def test_set_finder_trusted_host(self, line_processor, caplog, session, finder): with caplog.at_level(logging.INFO): line_processor( "--trusted-host=host1 --trusted-host=host2:8080", - "file.txt", 1, finder=finder, session=session, + "file.txt", + 1, + finder=finder, + session=session, ) - assert list(finder.trusted_hosts) == ['host1', 'host2:8080'] + assert list(finder.trusted_hosts) == ["host1", "host2:8080"] session = finder._link_collector.session - assert ( - session.adapters['https://host1/'] - is session._trusted_host_adapter - ) - assert ( - session.adapters['https://host2:8080/'] - is session._trusted_host_adapter - ) + assert session.adapters["https://host1/"] is session._trusted_host_adapter + assert session.adapters["https://host2:8080/"] is session._trusted_host_adapter # Test the log message. actual = [(r.levelname, r.message) for r in caplog.records] - expected = ( - 'INFO', "adding trusted host: 'host1' (from line 1 of file.txt)" - ) + expected = ("INFO", "adding trusted host: 'host1' (from line 1 of file.txt)") assert expected in actual def test_set_finder_allow_all_prereleases(self, line_processor, finder): @@ -390,9 +392,7 @@ def test_set_finder_allow_all_prereleases(self, line_processor, finder): def test_use_feature(self, line_processor, options): """--use-feature can be set in requirements files.""" - line_processor( - "--use-feature=2020-resolver", "filename", 1, options=options - ) + line_processor("--use-feature=2020-resolver", "filename", 1, options=options) assert "2020-resolver" in options.features_enabled def test_relative_local_find_links( @@ -401,16 +401,14 @@ def test_relative_local_find_links( """ Test a relative find_links path is joined with the req file directory """ - base_path = tmpdir / 'path' + base_path = tmpdir / "path" def normalize(path): - return os.path.normcase( - os.path.abspath(os.path.normpath(str(path))) - ) + return os.path.normcase(os.path.abspath(os.path.normpath(str(path)))) # Make sure the test also passes on windows - req_file = normalize(base_path / 'req_file.txt') - nested_link = normalize(base_path / 'rel_path') + req_file = normalize(base_path / "req_file.txt") + nested_link = normalize(base_path / "rel_path") exists_ = os.path.exists def exists(path): @@ -419,28 +417,26 @@ def exists(path): else: exists_(path) - monkeypatch.setattr(os.path, 'exists', exists) + monkeypatch.setattr(os.path, "exists", exists) line_processor("--find-links=rel_path", req_file, 1, finder=finder) assert finder.find_links == [nested_link] - def test_relative_http_nested_req_files( - self, finder, session, monkeypatch - ): + def test_relative_http_nested_req_files(self, finder, session, monkeypatch): """ Test a relative nested req file path is joined with the req file url """ - req_name = 'hello' - req_file = 'http://me.com/me/req_file.txt' + req_name = "hello" + req_file = "http://me.com/me/req_file.txt" def get_file_content(filename, *args, **kwargs): if filename == req_file: - return None, '-r reqs.txt' - elif filename == 'http://me.com/me/reqs.txt': + return None, "-r reqs.txt" + elif filename == "http://me.com/me/reqs.txt": return None, req_name - assert False, 'Unexpected file requested {}'.format(filename) + assert False, "Unexpected file requested {}".format(filename) monkeypatch.setattr( - pip._internal.req.req_file, 'get_file_content', get_file_content + pip._internal.req.req_file, "get_file_content", get_file_content ) result = list(parse_reqfile(req_file, session=session)) @@ -448,42 +444,36 @@ def get_file_content(filename, *args, **kwargs): assert result[0].name == req_name assert not result[0].constraint - def test_relative_local_nested_req_files( - self, session, monkeypatch, tmpdir - ): + def test_relative_local_nested_req_files(self, session, monkeypatch, tmpdir): """ Test a relative nested req file path is joined with the req file dir """ - req_name = 'hello' - req_file = tmpdir / 'parent' / 'req_file.txt' + req_name = "hello" + req_file = tmpdir / "parent" / "req_file.txt" req_file.parent.mkdir() - req_file.write_text('-r reqs.txt') - req_file.parent.joinpath('reqs.txt').write_text(req_name) + req_file.write_text("-r reqs.txt") + req_file.parent.joinpath("reqs.txt").write_text(req_name) monkeypatch.chdir(str(tmpdir)) - reqs = list( - parse_reqfile('./parent/req_file.txt', session=session) - ) + reqs = list(parse_reqfile("./parent/req_file.txt", session=session)) assert len(reqs) == 1 assert reqs[0].name == req_name assert not reqs[0].constraint - def test_absolute_local_nested_req_files( - self, session, monkeypatch, tmpdir - ): + def test_absolute_local_nested_req_files(self, session, monkeypatch, tmpdir): """ Test an absolute nested req file path """ - req_name = 'hello' - req_file = tmpdir / 'parent' / 'req_file.txt' + req_name = "hello" + req_file = tmpdir / "parent" / "req_file.txt" req_file.parent.mkdir() - other_req_file = tmpdir / 'other' / 'reqs.txt' + other_req_file = tmpdir / "other" / "reqs.txt" other_req_file.parent.mkdir() # POSIX-ify the path, since Windows backslashes aren't supported. - other_req_file_str = str(other_req_file).replace('\\', '/') + other_req_file_str = str(other_req_file).replace("\\", "/") - req_file.write_text('-r {}'.format(other_req_file_str)) + req_file.write_text("-r {}".format(other_req_file_str)) other_req_file.write_text(req_name) reqs = list(parse_reqfile(str(req_file), session=session)) @@ -491,25 +481,23 @@ def test_absolute_local_nested_req_files( assert reqs[0].name == req_name assert not reqs[0].constraint - def test_absolute_http_nested_req_file_in_local( - self, session, monkeypatch, tmpdir - ): + def test_absolute_http_nested_req_file_in_local(self, session, monkeypatch, tmpdir): """ Test a nested req file url in a local req file """ - req_name = 'hello' - req_file = tmpdir / 'req_file.txt' - nested_req_file = 'http://me.com/me/req_file.txt' + req_name = "hello" + req_file = tmpdir / "req_file.txt" + nested_req_file = "http://me.com/me/req_file.txt" def get_file_content(filename, *args, **kwargs): if filename == str(req_file): - return None, '-r {}'.format(nested_req_file) + return None, "-r {}".format(nested_req_file) elif filename == nested_req_file: return None, req_name - assert False, 'Unexpected file requested {}'.format(filename) + assert False, "Unexpected file requested {}".format(filename) monkeypatch.setattr( - pip._internal.req.req_file, 'get_file_content', get_file_content + pip._internal.req.req_file, "get_file_content", get_file_content ) result = list(parse_reqfile(req_file, session=session)) @@ -519,20 +507,19 @@ def get_file_content(filename, *args, **kwargs): class TestBreakOptionsArgs(object): - def test_no_args(self): - assert ('', '--option') == break_args_options('--option') + assert ("", "--option") == break_args_options("--option") def test_no_options(self): - assert ('arg arg', '') == break_args_options('arg arg') + assert ("arg arg", "") == break_args_options("arg arg") def test_args_short_options(self): - result = break_args_options('arg arg -s') - assert ('arg arg', '-s') == result + result = break_args_options("arg arg -s") + assert ("arg arg", "-s") == result def test_args_long_options(self): - result = break_args_options('arg arg --long') - assert ('arg arg', '--long') == result + result = break_args_options("arg arg --long") + assert ("arg arg", "--long") == result class TestOptionVariants(object): @@ -541,23 +528,23 @@ class TestOptionVariants(object): def test_variant1(self, line_processor, finder): line_processor("-i url", "file", 1, finder=finder) - assert finder.index_urls == ['url'] + assert finder.index_urls == ["url"] def test_variant2(self, line_processor, finder): line_processor("-i 'url'", "file", 1, finder=finder) - assert finder.index_urls == ['url'] + assert finder.index_urls == ["url"] def test_variant3(self, line_processor, finder): line_processor("--index-url=url", "file", 1, finder=finder) - assert finder.index_urls == ['url'] + assert finder.index_urls == ["url"] def test_variant4(self, line_processor, finder): line_processor("--index-url url", "file", 1, finder=finder) - assert finder.index_urls == ['url'] + assert finder.index_urls == ["url"] def test_variant5(self, line_processor, finder): line_processor("--index-url='url'", "file", 1, finder=finder) - assert finder.index_urls == ['url'] + assert finder.index_urls == ["url"] class TestParseRequirements(object): @@ -571,9 +558,11 @@ def test_remote_reqs_parse(self): # this requirements file just contains a comment previously this has # failed in py3: https://github.com/pypa/pip/issues/760 for _ in parse_reqfile( - 'https://raw.githubusercontent.com/pypa/' - 'pip-test-package/master/' - 'tests/req_just_comment.txt', session=PipSession()): + "https://raw.githubusercontent.com/pypa/" + "pip-test-package/master/" + "tests/req_just_comment.txt", + session=PipSession(), + ): pass def test_multiple_appending_options(self, tmpdir, finder, options): @@ -581,82 +570,91 @@ def test_multiple_appending_options(self, tmpdir, finder, options): fp.write("--extra-index-url url1 \n") fp.write("--extra-index-url url2 ") - list(parse_reqfile(tmpdir.joinpath("req1.txt"), finder=finder, - session=PipSession(), options=options)) + list( + parse_reqfile( + tmpdir.joinpath("req1.txt"), + finder=finder, + session=PipSession(), + options=options, + ) + ) - assert finder.index_urls == ['url1', 'url2'] + assert finder.index_urls == ["url1", "url2"] def test_expand_existing_env_variables(self, tmpdir, finder): - template = ( - 'https://{}:x-oauth-basic@github.com/' - 'user/{}/archive/master.zip' - ) + template = "https://{}:x-oauth-basic@github.com/" "user/{}/archive/master.zip" def make_var(name): - return '${{{name}}}'.format(**locals()) + return "${{{name}}}".format(**locals()) - env_vars = collections.OrderedDict([ - ('GITHUB_TOKEN', 'notarealtoken'), - ('DO_12_FACTOR', 'awwyeah'), - ]) + env_vars = collections.OrderedDict( + [ + ("GITHUB_TOKEN", "notarealtoken"), + ("DO_12_FACTOR", "awwyeah"), + ] + ) - with open(tmpdir.joinpath('req1.txt'), 'w') as fp: + with open(tmpdir.joinpath("req1.txt"), "w") as fp: fp.write(template.format(*map(make_var, env_vars))) - with patch('pip._internal.req.req_file.os.getenv') as getenv: + with patch("pip._internal.req.req_file.os.getenv") as getenv: getenv.side_effect = lambda n: env_vars[n] - reqs = list(parse_reqfile( - tmpdir.joinpath('req1.txt'), - finder=finder, - session=PipSession() - )) + reqs = list( + parse_reqfile( + tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + ) + ) - assert len(reqs) == 1, \ - 'parsing requirement file with env variable failed' + assert len(reqs) == 1, "parsing requirement file with env variable failed" expected_url = template.format(*env_vars.values()) - assert reqs[0].link.url == expected_url, \ - 'variable expansion in req file failed' + assert reqs[0].link.url == expected_url, "variable expansion in req file failed" def test_expand_missing_env_variables(self, tmpdir, finder): req_url = ( - 'https://${NON_EXISTENT_VARIABLE}:$WRONG_FORMAT@' - '%WINDOWS_FORMAT%github.com/user/repo/archive/master.zip' + "https://${NON_EXISTENT_VARIABLE}:$WRONG_FORMAT@" + "%WINDOWS_FORMAT%github.com/user/repo/archive/master.zip" ) - with open(tmpdir.joinpath('req1.txt'), 'w') as fp: + with open(tmpdir.joinpath("req1.txt"), "w") as fp: fp.write(req_url) - with patch('pip._internal.req.req_file.os.getenv') as getenv: - getenv.return_value = '' + with patch("pip._internal.req.req_file.os.getenv") as getenv: + getenv.return_value = "" - reqs = list(parse_reqfile( - tmpdir.joinpath('req1.txt'), - finder=finder, - session=PipSession() - )) + reqs = list( + parse_reqfile( + tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + ) + ) - assert len(reqs) == 1, \ - 'parsing requirement file with env variable failed' - assert reqs[0].link.url == req_url, \ - 'ignoring invalid env variable in req file failed' + assert len(reqs) == 1, "parsing requirement file with env variable failed" + assert ( + reqs[0].link.url == req_url + ), "ignoring invalid env variable in req file failed" def test_join_lines(self, tmpdir, finder): with open(tmpdir.joinpath("req1.txt"), "w") as fp: fp.write("--extra-index-url url1 \\\n--extra-index-url url2") - list(parse_reqfile(tmpdir.joinpath("req1.txt"), finder=finder, - session=PipSession())) + list( + parse_reqfile( + tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + ) + ) - assert finder.index_urls == ['url1', 'url2'] + assert finder.index_urls == ["url1", "url2"] def test_req_file_parse_no_only_binary(self, data, finder): - list(parse_reqfile( - data.reqfiles.joinpath("supported_options2.txt"), - finder=finder, - session=PipSession())) - expected = FormatControl({'fred'}, {'wilma'}) + list( + parse_reqfile( + data.reqfiles.joinpath("supported_options2.txt"), + finder=finder, + session=PipSession(), + ) + ) + expected = FormatControl({"fred"}, {"wilma"}) assert finder.format_control == expected def test_req_file_parse_comment_start_of_line(self, tmpdir, finder): @@ -666,9 +664,11 @@ def test_req_file_parse_comment_start_of_line(self, tmpdir, finder): with open(tmpdir.joinpath("req1.txt"), "w") as fp: fp.write("# Comment ") - reqs = list(parse_reqfile(tmpdir.joinpath("req1.txt"), - finder=finder, - session=PipSession())) + reqs = list( + parse_reqfile( + tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + ) + ) assert not reqs @@ -679,9 +679,11 @@ def test_req_file_parse_comment_end_of_line_with_url(self, tmpdir, finder): with open(tmpdir.joinpath("req1.txt"), "w") as fp: fp.write("https://example.com/foo.tar.gz # Comment ") - reqs = list(parse_reqfile(tmpdir.joinpath("req1.txt"), - finder=finder, - session=PipSession())) + reqs = list( + parse_reqfile( + tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + ) + ) assert len(reqs) == 1 assert reqs[0].link.url == "https://example.com/foo.tar.gz" @@ -693,9 +695,11 @@ def test_req_file_parse_egginfo_end_of_line_with_url(self, tmpdir, finder): with open(tmpdir.joinpath("req1.txt"), "w") as fp: fp.write("https://example.com/foo.tar.gz#egg=wat") - reqs = list(parse_reqfile(tmpdir.joinpath("req1.txt"), - finder=finder, - session=PipSession())) + reqs = list( + parse_reqfile( + tmpdir.joinpath("req1.txt"), finder=finder, session=PipSession() + ) + ) assert len(reqs) == 1 assert reqs[0].name == "wat" @@ -705,35 +709,39 @@ def test_req_file_no_finder(self, tmpdir): Test parsing a requirements file without a finder """ with open(tmpdir.joinpath("req.txt"), "w") as fp: - fp.write(""" + fp.write( + """ --find-links https://example.com/ --index-url https://example.com/ --extra-index-url https://two.example.com/ --no-use-wheel --no-index - """) + """ + ) parse_reqfile(tmpdir.joinpath("req.txt"), session=PipSession()) - def test_install_requirements_with_options(self, tmpdir, finder, session, - options): - global_option = '--dry-run' - install_option = '--prefix=/opt' + def test_install_requirements_with_options(self, tmpdir, finder, session, options): + global_option = "--dry-run" + install_option = "--prefix=/opt" - content = ''' + content = """ --only-binary :all: INITools==2.0 --global-option="{global_option}" \ --install-option "{install_option}" - '''.format(global_option=global_option, install_option=install_option) + """.format( + global_option=global_option, install_option=install_option + ) with requirements_file(content, tmpdir) as reqs_file: - req = next(parse_reqfile(reqs_file.resolve(), - finder=finder, - options=options, - session=session)) + req = next( + parse_reqfile( + reqs_file.resolve(), finder=finder, options=options, session=session + ) + ) req.source_dir = os.curdir - with patch.object(subprocess, 'Popen') as popen: + with patch.object(subprocess, "Popen") as popen: popen.return_value.stdout.readline.return_value = b"" try: req.install([]) @@ -743,8 +751,10 @@ def test_install_requirements_with_options(self, tmpdir, finder, session, last_call = popen.call_args_list[-1] args = last_call[0][0] assert ( - 0 < args.index(global_option) < args.index('install') < - args.index(install_option) + 0 + < args.index(global_option) + < args.index("install") + < args.index(install_option) ) - assert options.format_control.no_binary == {':all:'} + assert options.format_control.no_binary == {":all:"} assert options.format_control.only_binary == set() diff --git a/tests/unit/test_req_install.py b/tests/unit/test_req_install.py index d0d80035299..f31ec9f58e6 100644 --- a/tests/unit/test_req_install.py +++ b/tests/unit/test_req_install.py @@ -19,13 +19,14 @@ def test_tmp_build_directory(self): # when req is None, we can produce a temporary directory # Make sure we're handling it correctly with real path. requirement = InstallRequirement(None, None) - tmp_dir = tempfile.mkdtemp('-build', 'pip-') + tmp_dir = tempfile.mkdtemp("-build", "pip-") tmp_build_dir = requirement.ensure_build_location( - tmp_dir, autodelete=False, parallel_builds=False, + tmp_dir, + autodelete=False, + parallel_builds=False, ) - assert ( - os.path.dirname(tmp_build_dir) == - os.path.realpath(os.path.dirname(tmp_dir)) + assert os.path.dirname(tmp_build_dir) == os.path.realpath( + os.path.dirname(tmp_dir) ) # are we on a system where /tmp is a symlink if os.path.realpath(tmp_dir) != os.path.abspath(tmp_dir): @@ -41,8 +42,8 @@ def test_forward_slash_results_in_a_link(self, tmpdir): # Just create a file for letting the logic work setup_py_path = install_dir / "setup.py" os.makedirs(str(install_dir)) - with open(setup_py_path, 'w') as f: - f.write('') + with open(setup_py_path, "w") as f: + f.write("") requirement = install_req_from_line( str(install_dir).replace(os.sep, os.altsep or os.sep) @@ -52,7 +53,6 @@ def test_forward_slash_results_in_a_link(self, tmpdir): class TestInstallRequirementFrom(object): - def test_install_req_from_string_invalid_requirement(self): """ Requirement strings that cannot be parsed by @@ -61,9 +61,7 @@ def test_install_req_from_string_invalid_requirement(self): with pytest.raises(InstallationError) as excinfo: install_req_from_req_string("http:/this/is/invalid") - assert str(excinfo.value) == ( - "Invalid requirement: 'http:/this/is/invalid'" - ) + assert str(excinfo.value) == ("Invalid requirement: 'http:/this/is/invalid'") def test_install_req_from_string_without_comes_from(self): """ @@ -71,8 +69,10 @@ def test_install_req_from_string_without_comes_from(self): when called with URL (PEP 508) but without comes_from. """ # Test with a PEP 508 url install string: - wheel_url = ("https://download.pytorch.org/whl/cu90/" - "torch-1.0.0-cp36-cp36m-win_amd64.whl") + wheel_url = ( + "https://download.pytorch.org/whl/cu90/" + "torch-1.0.0-cp36-cp36m-win_amd64.whl" + ) install_str = "torch@ " + wheel_url install_req = install_req_from_req_string(install_str) @@ -89,19 +89,17 @@ def test_install_req_from_string_with_comes_from_without_link(self): does not have a link. """ # Test with a PEP 508 url install string: - wheel_url = ("https://download.pytorch.org/whl/cu90/" - "torch-1.0.0-cp36-cp36m-win_amd64.whl") + wheel_url = ( + "https://download.pytorch.org/whl/cu90/" + "torch-1.0.0-cp36-cp36m-win_amd64.whl" + ) install_str = "torch@ " + wheel_url # Dummy numpy "comes_from" requirement without link: - comes_from = InstallRequirement( - Requirement("numpy>=1.15.0"), comes_from=None - ) + comes_from = InstallRequirement(Requirement("numpy>=1.15.0"), comes_from=None) # Attempt install from install string comes: - install_req = install_req_from_req_string( - install_str, comes_from=comes_from - ) + install_req = install_req_from_req_string(install_str, comes_from=comes_from) assert isinstance(install_req, InstallRequirement) assert install_req.comes_from.link is None diff --git a/tests/unit/test_req_uninstall.py b/tests/unit/test_req_uninstall.py index d4d707e6042..608709fb642 100644 --- a/tests/unit/test_req_uninstall.py +++ b/tests/unit/test_req_uninstall.py @@ -26,23 +26,23 @@ def mock_is_local(path): def test_uninstallation_paths(): class dist(object): def get_metadata_lines(self, record): - return ['file.py,,', - 'file.pyc,,', - 'file.so,,', - 'nopyc.py'] - location = '' + return ["file.py,,", "file.pyc,,", "file.so,,", "nopyc.py"] + + location = "" d = dist() paths = list(uninstallation_paths(d)) - expected = ['file.py', - 'file.pyc', - 'file.pyo', - 'file.so', - 'nopyc.py', - 'nopyc.pyc', - 'nopyc.pyo'] + expected = [ + "file.py", + "file.pyc", + "file.pyo", + "file.so", + "nopyc.py", + "nopyc.pyc", + "nopyc.pyo", + ] assert paths == expected @@ -56,26 +56,26 @@ def test_compressed_listing(tmpdir): def in_tmpdir(paths): li = [] for path in paths: - li.append( - str(os.path.join(tmpdir, path.replace("/", os.path.sep))) - ) + li.append(str(os.path.join(tmpdir, path.replace("/", os.path.sep)))) return li - sample = in_tmpdir([ - "lib/mypkg.dist-info/METADATA", - "lib/mypkg.dist-info/PKG-INFO", - "lib/mypkg/would_be_removed.txt", - "lib/mypkg/would_be_skipped.skip.txt", - "lib/mypkg/__init__.py", - "lib/mypkg/my_awesome_code.py", - "lib/mypkg/__pycache__/my_awesome_code-magic.pyc", - "lib/mypkg/support/support_file.py", - "lib/mypkg/support/more_support.py", - "lib/mypkg/support/would_be_skipped.skip.py", - "lib/mypkg/support/__pycache__/support_file-magic.pyc", - "lib/random_other_place/file_without_a_dot_pyc", - "bin/mybin", - ]) + sample = in_tmpdir( + [ + "lib/mypkg.dist-info/METADATA", + "lib/mypkg.dist-info/PKG-INFO", + "lib/mypkg/would_be_removed.txt", + "lib/mypkg/would_be_skipped.skip.txt", + "lib/mypkg/__init__.py", + "lib/mypkg/my_awesome_code.py", + "lib/mypkg/__pycache__/my_awesome_code-magic.pyc", + "lib/mypkg/support/support_file.py", + "lib/mypkg/support/more_support.py", + "lib/mypkg/support/would_be_skipped.skip.py", + "lib/mypkg/support/__pycache__/support_file-magic.pyc", + "lib/random_other_place/file_without_a_dot_pyc", + "bin/mybin", + ] + ) # Create the required files for fname in sample: @@ -84,30 +84,36 @@ def in_tmpdir(paths): # Remove the files to be skipped from the paths sample = [path for path in sample if ".skip." not in path] - expected_remove = in_tmpdir([ - "bin/mybin", - "lib/mypkg.dist-info/*", - "lib/mypkg/*", - "lib/random_other_place/file_without_a_dot_pyc", - ]) - - expected_skip = in_tmpdir([ - "lib/mypkg/would_be_skipped.skip.txt", - "lib/mypkg/support/would_be_skipped.skip.py", - ]) - - expected_rename = in_tmpdir([ - "bin/", - "lib/mypkg.dist-info/", - "lib/mypkg/would_be_removed.txt", - "lib/mypkg/__init__.py", - "lib/mypkg/my_awesome_code.py", - "lib/mypkg/__pycache__/", - "lib/mypkg/support/support_file.py", - "lib/mypkg/support/more_support.py", - "lib/mypkg/support/__pycache__/", - "lib/random_other_place/", - ]) + expected_remove = in_tmpdir( + [ + "bin/mybin", + "lib/mypkg.dist-info/*", + "lib/mypkg/*", + "lib/random_other_place/file_without_a_dot_pyc", + ] + ) + + expected_skip = in_tmpdir( + [ + "lib/mypkg/would_be_skipped.skip.txt", + "lib/mypkg/support/would_be_skipped.skip.py", + ] + ) + + expected_rename = in_tmpdir( + [ + "bin/", + "lib/mypkg.dist-info/", + "lib/mypkg/would_be_removed.txt", + "lib/mypkg/__init__.py", + "lib/mypkg/my_awesome_code.py", + "lib/mypkg/__pycache__/", + "lib/mypkg/support/support_file.py", + "lib/mypkg/support/more_support.py", + "lib/mypkg/support/__pycache__/", + "lib/random_other_place/", + ] + ) will_remove, will_skip = compress_for_output_listing(sample) will_rename = compress_for_rename(sample) @@ -118,13 +124,11 @@ def in_tmpdir(paths): class TestUninstallPathSet(object): def test_add(self, tmpdir, monkeypatch): - monkeypatch.setattr(pip._internal.req.req_uninstall, 'is_local', - mock_is_local) + monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) # Fix case for windows tests - file_extant = os.path.normcase(os.path.join(tmpdir, 'foo')) - file_nonexistent = os.path.normcase( - os.path.join(tmpdir, 'nonexistent')) - with open(file_extant, 'w'): + file_extant = os.path.normcase(os.path.join(tmpdir, "foo")) + file_nonexistent = os.path.normcase(os.path.join(tmpdir, "nonexistent")) + with open(file_extant, "w"): pass ups = UninstallPathSet(dist=Mock()) @@ -136,23 +140,20 @@ def test_add(self, tmpdir, monkeypatch): assert ups.paths == {file_extant} def test_add_pth(self, tmpdir, monkeypatch): - monkeypatch.setattr(pip._internal.req.req_uninstall, 'is_local', - mock_is_local) + monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) # Fix case for windows tests tmpdir = os.path.normcase(tmpdir) - on_windows = sys.platform == 'win32' - pth_file = os.path.join(tmpdir, 'foo.pth') - relative = '../../example' + on_windows = sys.platform == "win32" + pth_file = os.path.join(tmpdir, "foo.pth") + relative = "../../example" if on_windows: - share = '\\\\example\\share\\' - share_com = '\\\\example.com\\share\\' + share = "\\\\example\\share\\" + share_com = "\\\\example.com\\share\\" # Create a .pth file for testing - with open(pth_file, 'w') as f: - f.writelines([tmpdir, '\n', - relative, '\n']) + with open(pth_file, "w") as f: + f.writelines([tmpdir, "\n", relative, "\n"]) if on_windows: - f.writelines([share, '\n', - share_com, '\n']) + f.writelines([share, "\n", share_com, "\n"]) # Add paths to be removed pth = UninstallPthEntries(pth_file) pth.add(tmpdir) @@ -169,12 +170,11 @@ def test_add_pth(self, tmpdir, monkeypatch): @pytest.mark.skipif("sys.platform == 'win32'") def test_add_symlink(self, tmpdir, monkeypatch): - monkeypatch.setattr(pip._internal.req.req_uninstall, 'is_local', - mock_is_local) - f = os.path.join(tmpdir, 'foo') - with open(f, 'w'): + monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) + f = os.path.join(tmpdir, "foo") + with open(f, "w"): pass - foo_link = os.path.join(tmpdir, 'foo_link') + foo_link = os.path.join(tmpdir, "foo_link") os.symlink(f, foo_link) ups = UninstallPathSet(dist=Mock()) @@ -182,32 +182,31 @@ def test_add_symlink(self, tmpdir, monkeypatch): assert ups.paths == {foo_link} def test_compact_shorter_path(self, monkeypatch): - monkeypatch.setattr(pip._internal.req.req_uninstall, 'is_local', - mock_is_local) - monkeypatch.setattr('os.path.exists', lambda p: True) + monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) + monkeypatch.setattr("os.path.exists", lambda p: True) # This deals with nt/posix path differences - short_path = os.path.normcase(os.path.abspath( - os.path.join(os.path.sep, 'path'))) + short_path = os.path.normcase( + os.path.abspath(os.path.join(os.path.sep, "path")) + ) ups = UninstallPathSet(dist=Mock()) ups.add(short_path) - ups.add(os.path.join(short_path, 'longer')) + ups.add(os.path.join(short_path, "longer")) assert compact(ups.paths) == {short_path} @pytest.mark.skipif("sys.platform == 'win32'") def test_detect_symlink_dirs(self, monkeypatch, tmpdir): - monkeypatch.setattr(pip._internal.req.req_uninstall, 'is_local', - mock_is_local) + monkeypatch.setattr(pip._internal.req.req_uninstall, "is_local", mock_is_local) # construct 2 paths: # tmpdir/dir/file # tmpdir/dirlink/file (where dirlink is a link to dir) - d = tmpdir.joinpath('dir') + d = tmpdir.joinpath("dir") d.mkdir() - dlink = tmpdir.joinpath('dirlink') + dlink = tmpdir.joinpath("dirlink") os.symlink(d, dlink) - d.joinpath('file').touch() - path1 = str(d.joinpath('file')) - path2 = str(dlink.joinpath('file')) + d.joinpath("file").touch() + path1 = str(d.joinpath("file")) + path2 = str(dlink.joinpath("file")) ups = UninstallPathSet(dist=Mock()) ups.add(path1) @@ -232,25 +231,31 @@ def mock_walk(cls, root): for dirname, subdirs, files in cls.WALK_RESULT: dirname = os.path.sep.join(dirname.split("/")) if dirname.startswith(root): - yield dirname[len(root) + 1:], subdirs, files + yield dirname[len(root) + 1 :], subdirs, files def test_compress_for_rename(self, monkeypatch): - paths = [os.path.sep.join(p.split("/")) for p in [ - "A/B/b.py", - "A/B/D/c.py", - "A/C/d.py", - "A/E/f.py", - "A/G/g.py", - ]] - - expected_paths = [os.path.sep.join(p.split("/")) for p in [ - "A/B/", # selected everything below A/B - "A/C/d.py", # did not select everything below A/C - "A/E/", # only empty folders remain under A/E - "A/G/g.py", # non-empty folder remains under A/G - ]] - - monkeypatch.setattr('os.walk', self.mock_walk) + paths = [ + os.path.sep.join(p.split("/")) + for p in [ + "A/B/b.py", + "A/B/D/c.py", + "A/C/d.py", + "A/E/f.py", + "A/G/g.py", + ] + ] + + expected_paths = [ + os.path.sep.join(p.split("/")) + for p in [ + "A/B/", # selected everything below A/B + "A/C/d.py", # did not select everything below A/C + "A/E/", # only empty folders remain under A/E + "A/G/g.py", # non-empty folder remains under A/G + ] + ] + + monkeypatch.setattr("os.walk", self.mock_walk) actual_paths = compress_for_rename(paths) assert set(expected_paths) == set(actual_paths) @@ -269,15 +274,21 @@ def make_stash(cls, tmpdir, paths): pathset = StashedUninstallPathSet() - paths = [os.path.join(tmpdir, *p.split('/')) for p in paths] + paths = [os.path.join(tmpdir, *p.split("/")) for p in paths] stashed_paths = [(p, pathset.stash(p)) for p in paths] return pathset, stashed_paths def test_stash(self, tmpdir): - pathset, stashed_paths = self.make_stash(tmpdir, [ - "A/B/", "A/C/d.py", "A/E/", "A/G/g.py", - ]) + pathset, stashed_paths = self.make_stash( + tmpdir, + [ + "A/B/", + "A/C/d.py", + "A/E/", + "A/G/g.py", + ], + ) for old_path, new_path in stashed_paths: assert not os.path.exists(old_path) @@ -286,9 +297,15 @@ def test_stash(self, tmpdir): assert stashed_paths == pathset._moves def test_commit(self, tmpdir): - pathset, stashed_paths = self.make_stash(tmpdir, [ - "A/B/", "A/C/d.py", "A/E/", "A/G/g.py", - ]) + pathset, stashed_paths = self.make_stash( + tmpdir, + [ + "A/B/", + "A/C/d.py", + "A/E/", + "A/G/g.py", + ], + ) pathset.commit() @@ -297,9 +314,15 @@ def test_commit(self, tmpdir): assert not os.path.exists(new_path) def test_rollback(self, tmpdir): - pathset, stashed_paths = self.make_stash(tmpdir, [ - "A/B/", "A/C/d.py", "A/E/", "A/G/g.py", - ]) + pathset, stashed_paths = self.make_stash( + tmpdir, + [ + "A/B/", + "A/C/d.py", + "A/E/", + "A/G/g.py", + ], + ) pathset.rollback() diff --git a/tests/unit/test_resolution_legacy_resolver.py b/tests/unit/test_resolution_legacy_resolver.py index 561313c002b..df4321513d0 100644 --- a/tests/unit/test_resolution_legacy_resolver.py +++ b/tests/unit/test_resolution_legacy_resolver.py @@ -4,10 +4,7 @@ import pytest from pip._vendor import pkg_resources -from pip._internal.exceptions import ( - NoneMetadataError, - UnsupportedPythonVersion, -) +from pip._internal.exceptions import NoneMetadataError, UnsupportedPythonVersion from pip._internal.req.constructors import install_req_from_line from pip._internal.resolution.legacy.resolver import ( Resolver, @@ -21,7 +18,6 @@ # We need to inherit from DistInfoDistribution for the `isinstance()` # check inside `packaging.get_metadata()` to work. class FakeDist(pkg_resources.DistInfoDistribution): - def __init__(self, metadata, metadata_name=None): """ :param metadata: The value that dist.get_metadata() should return @@ -30,17 +26,17 @@ def __init__(self, metadata, metadata_name=None): (can be "METADATA" or "PKG-INFO"). Defaults to "METADATA". """ if metadata_name is None: - metadata_name = 'METADATA' + metadata_name = "METADATA" - self.project_name = 'my-project' + self.project_name = "my-project" self.metadata_name = metadata_name self.metadata = metadata def __str__(self): - return ''.format(self.project_name) + return "".format(self.project_name) def has_metadata(self, name): - return (name == self.metadata_name) + return name == self.metadata_name def get_metadata(self, name): assert name == self.metadata_name @@ -48,9 +44,9 @@ def get_metadata(self, name): def make_fake_dist(requires_python=None, metadata_name=None): - metadata = 'Name: test\n' + metadata = "Name: test\n" if requires_python is not None: - metadata += 'Requires-Python:{}'.format(requires_python) + metadata += "Requires-Python:{}".format(requires_python) return FakeDist(metadata, metadata_name=metadata_name) @@ -66,7 +62,7 @@ def test_compatible(self, caplog): Test a Python version compatible with the dist's Requires-Python. """ caplog.set_level(logging.DEBUG) - dist = make_fake_dist('== 3.6.5') + dist = make_fake_dist("== 3.6.5") _check_dist_requires_python( dist, @@ -79,7 +75,7 @@ def test_incompatible(self): """ Test a Python version incompatible with the dist's Requires-Python. """ - dist = make_fake_dist('== 3.6.4') + dist = make_fake_dist("== 3.6.4") with pytest.raises(UnsupportedPythonVersion) as exc: _check_dist_requires_python( dist, @@ -97,7 +93,7 @@ def test_incompatible_with_ignore_requires(self, caplog): while passing ignore_requires_python=True. """ caplog.set_level(logging.DEBUG) - dist = make_fake_dist('== 3.6.4') + dist = make_fake_dist("== 3.6.4") _check_dist_requires_python( dist, version_info=(3, 6, 5), @@ -105,7 +101,7 @@ def test_incompatible_with_ignore_requires(self, caplog): ) assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'DEBUG' + assert record.levelname == "DEBUG" assert record.message == ( "Ignoring failed Requires-Python check for package 'my-project': " "3.6.5 not in '== 3.6.4'" @@ -134,7 +130,7 @@ def test_invalid_requires_python(self, caplog): Test a dist with an invalid Requires-Python. """ caplog.set_level(logging.DEBUG) - dist = make_fake_dist('invalid') + dist = make_fake_dist("invalid") _check_dist_requires_python( dist, version_info=(3, 6, 5), @@ -142,16 +138,19 @@ def test_invalid_requires_python(self, caplog): ) assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'WARNING' + assert record.levelname == "WARNING" assert record.message == ( "Package 'my-project' has an invalid Requires-Python: " "Invalid specifier: 'invalid'" ) - @pytest.mark.parametrize('metadata_name', [ - 'METADATA', - 'PKG-INFO', - ]) + @pytest.mark.parametrize( + "metadata_name", + [ + "METADATA", + "PKG-INFO", + ], + ) def test_empty_metadata_error(self, caplog, metadata_name): """ Test dist.has_metadata() returning True and dist.get_metadata() @@ -180,6 +179,7 @@ class TestYankedWarning(object): """ Test _populate_link() emits warning if one or more candidates are yanked. """ + def _make_test_resolver(self, monkeypatch, mock_candidates): def _find_candidates(project_name): return mock_candidates @@ -205,8 +205,8 @@ def test_sort_best_candidate__has_non_yanked(self, caplog, monkeypatch): Test unyanked candidate preferred over yanked. """ candidates = [ - make_mock_candidate('1.0'), - make_mock_candidate('2.0', yanked_reason='bad metadata #2'), + make_mock_candidate("1.0"), + make_mock_candidate("2.0", yanked_reason="bad metadata #2"), ] ireq = install_req_from_line("pkg") @@ -221,10 +221,10 @@ def test_sort_best_candidate__all_yanked(self, caplog, monkeypatch): Test all candidates yanked. """ candidates = [ - make_mock_candidate('1.0', yanked_reason='bad metadata #1'), + make_mock_candidate("1.0", yanked_reason="bad metadata #1"), # Put the best candidate in the middle, to test sorting. - make_mock_candidate('3.0', yanked_reason='bad metadata #3'), - make_mock_candidate('2.0', yanked_reason='bad metadata #2'), + make_mock_candidate("3.0", yanked_reason="bad metadata #3"), + make_mock_candidate("2.0", yanked_reason="bad metadata #2"), ] ireq = install_req_from_line("pkg") @@ -236,28 +236,35 @@ def test_sort_best_candidate__all_yanked(self, caplog, monkeypatch): # Check the log messages. assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'WARNING' + assert record.levelname == "WARNING" assert record.message == ( - 'The candidate selected for download or install is a yanked ' + "The candidate selected for download or install is a yanked " "version: 'mypackage' candidate " - '(version 3.0 at https://example.com/pkg-3.0.tar.gz)\n' - 'Reason for being yanked: bad metadata #3' + "(version 3.0 at https://example.com/pkg-3.0.tar.gz)\n" + "Reason for being yanked: bad metadata #3" ) - @pytest.mark.parametrize('yanked_reason, expected_reason', [ - # Test no reason given. - ('', ''), - # Test a unicode string with a non-ascii character. - (u'curly quote: \u2018', u'curly quote: \u2018'), - ]) + @pytest.mark.parametrize( + "yanked_reason, expected_reason", + [ + # Test no reason given. + ("", ""), + # Test a unicode string with a non-ascii character. + (u"curly quote: \u2018", u"curly quote: \u2018"), + ], + ) def test_sort_best_candidate__yanked_reason( - self, caplog, monkeypatch, yanked_reason, expected_reason, + self, + caplog, + monkeypatch, + yanked_reason, + expected_reason, ): """ Test the log message with various reason strings. """ candidates = [ - make_mock_candidate('1.0', yanked_reason=yanked_reason), + make_mock_candidate("1.0", yanked_reason=yanked_reason), ] ireq = install_req_from_line("pkg") @@ -268,11 +275,11 @@ def test_sort_best_candidate__yanked_reason( assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'WARNING' + assert record.levelname == "WARNING" expected_message = ( - 'The candidate selected for download or install is a yanked ' + "The candidate selected for download or install is a yanked " "version: 'mypackage' candidate " - '(version 1.0 at https://example.com/pkg-1.0.tar.gz)\n' - 'Reason for being yanked: ' + "(version 1.0 at https://example.com/pkg-1.0.tar.gz)\n" + "Reason for being yanked: " ) + expected_reason assert record.message == expected_message diff --git a/tests/unit/test_search_scope.py b/tests/unit/test_search_scope.py index e7f4e3f16b5..b7c86b020e6 100644 --- a/tests/unit/test_search_scope.py +++ b/tests/unit/test_search_scope.py @@ -3,39 +3,37 @@ class TestSearchScope: - def test_get_formatted_locations_basic_auth(self): """ Test that basic authentication credentials defined in URL is not included in formatted output. """ index_urls = [ - 'https://pypi.org/simple', - 'https://repo-user:repo-pass@repo.domain.com', - ] - find_links = [ - 'https://links-user:links-pass@page.domain.com' + "https://pypi.org/simple", + "https://repo-user:repo-pass@repo.domain.com", ] + find_links = ["https://links-user:links-pass@page.domain.com"] search_scope = SearchScope( - find_links=find_links, index_urls=index_urls, + find_links=find_links, + index_urls=index_urls, ) result = search_scope.get_formatted_locations() - assert 'repo-user:****@repo.domain.com' in result - assert 'repo-pass' not in result - assert 'links-user:****@page.domain.com' in result - assert 'links-pass' not in result + assert "repo-user:****@repo.domain.com" in result + assert "repo-pass" not in result + assert "links-user:****@page.domain.com" in result + assert "links-pass" not in result def test_get_index_urls_locations(self): """Check that the canonical name is on all indexes""" search_scope = SearchScope( find_links=[], - index_urls=['file://index1/', 'file://index2'], + index_urls=["file://index1/", "file://index2"], ) actual = search_scope.get_index_urls_locations( - install_req_from_line('Complex_Name').name + install_req_from_line("Complex_Name").name ) assert actual == [ - 'file://index1/complex-name/', - 'file://index2/complex-name/', + "file://index1/complex-name/", + "file://index2/complex-name/", ] diff --git a/tests/unit/test_self_check_outdated.py b/tests/unit/test_self_check_outdated.py index c5e60d92fc4..074425e3073 100644 --- a/tests/unit/test_self_check_outdated.py +++ b/tests/unit/test_self_check_outdated.py @@ -24,15 +24,12 @@ def __init__(self, best): class MockPackageFinder(object): - BASE_URL = 'https://pypi.org/simple/pip-{0}.tar.gz' - PIP_PROJECT_NAME = 'pip' + BASE_URL = "https://pypi.org/simple/pip-{0}.tar.gz" + PIP_PROJECT_NAME = "pip" INSTALLATION_CANDIDATES = [ - InstallationCandidate(PIP_PROJECT_NAME, '6.9.0', - BASE_URL.format('6.9.0')), - InstallationCandidate(PIP_PROJECT_NAME, '3.3.1', - BASE_URL.format('3.3.1')), - InstallationCandidate(PIP_PROJECT_NAME, '1.0', - BASE_URL.format('1.0')), + InstallationCandidate(PIP_PROJECT_NAME, "6.9.0", BASE_URL.format("6.9.0")), + InstallationCandidate(PIP_PROJECT_NAME, "3.3.1", BASE_URL.format("3.3.1")), + InstallationCandidate(PIP_PROJECT_NAME, "1.0", BASE_URL.format("1.0")), ] @classmethod @@ -48,65 +45,76 @@ def __init__(self, installer): self.installer = installer def has_metadata(self, name): - return name == 'INSTALLER' + return name == "INSTALLER" def get_metadata_lines(self, name): if self.has_metadata(name): yield self.installer else: - raise NotImplementedError('nope') + raise NotImplementedError("nope") def _options(): - ''' Some default options that we pass to - self_outdated_check.pip_self_version_check ''' + """Some default options that we pass to + self_outdated_check.pip_self_version_check""" return pretend.stub( - find_links=[], index_url='default_url', extra_index_urls=[], - no_index=False, pre=False, cache_dir='', + find_links=[], + index_url="default_url", + extra_index_urls=[], + no_index=False, + pre=False, + cache_dir="", ) @pytest.mark.parametrize( [ - 'stored_time', - 'installed_ver', - 'new_ver', - 'installer', - 'check_if_upgrade_required', - 'check_warn_logs', + "stored_time", + "installed_ver", + "new_ver", + "installer", + "check_if_upgrade_required", + "check_warn_logs", ], [ # Test we return None when installed version is None - ('1970-01-01T10:00:00Z', None, '1.0', 'pip', False, False), + ("1970-01-01T10:00:00Z", None, "1.0", "pip", False, False), # Need an upgrade - upgrade warning should print - ('1970-01-01T10:00:00Z', '1.0', '6.9.0', 'pip', True, True), + ("1970-01-01T10:00:00Z", "1.0", "6.9.0", "pip", True, True), # Upgrade available, pip installed via rpm - warning should not print - ('1970-01-01T10:00:00Z', '1.0', '6.9.0', 'rpm', True, False), + ("1970-01-01T10:00:00Z", "1.0", "6.9.0", "rpm", True, False), # No upgrade - upgrade warning should not print - ('1970-01-9T10:00:00Z', '6.9.0', '6.9.0', 'pip', False, False), - ] + ("1970-01-9T10:00:00Z", "6.9.0", "6.9.0", "pip", False, False), + ], ) -def test_pip_self_version_check(monkeypatch, stored_time, installed_ver, - new_ver, installer, - check_if_upgrade_required, check_warn_logs): - monkeypatch.setattr(self_outdated_check, 'get_installed_version', - lambda name: installed_ver) - monkeypatch.setattr(self_outdated_check, 'PackageFinder', - MockPackageFinder) - monkeypatch.setattr(logger, 'warning', - pretend.call_recorder(lambda *a, **kw: None)) - monkeypatch.setattr(logger, 'debug', - pretend.call_recorder(lambda s, exc_info=None: None)) - monkeypatch.setattr(self_outdated_check, 'get_distribution', - lambda name: MockDistribution(installer)) +def test_pip_self_version_check( + monkeypatch, + stored_time, + installed_ver, + new_ver, + installer, + check_if_upgrade_required, + check_warn_logs, +): + monkeypatch.setattr( + self_outdated_check, "get_installed_version", lambda name: installed_ver + ) + monkeypatch.setattr(self_outdated_check, "PackageFinder", MockPackageFinder) + monkeypatch.setattr(logger, "warning", pretend.call_recorder(lambda *a, **kw: None)) + monkeypatch.setattr( + logger, "debug", pretend.call_recorder(lambda s, exc_info=None: None) + ) + monkeypatch.setattr( + self_outdated_check, + "get_distribution", + lambda name: MockDistribution(installer), + ) fake_state = pretend.stub( - state={"last_check": stored_time, 'pypi_version': installed_ver}, + state={"last_check": stored_time, "pypi_version": installed_ver}, save=pretend.call_recorder(lambda v, t: None), ) - monkeypatch.setattr( - self_outdated_check, 'SelfCheckState', lambda **kw: fake_state - ) + monkeypatch.setattr(self_outdated_check, "SelfCheckState", lambda **kw: fake_state) with freezegun.freeze_time( "1970-01-09 10:00:00", @@ -114,7 +122,7 @@ def test_pip_self_version_check(monkeypatch, stored_time, installed_ver, "six.moves", "pip._vendor.six.moves", "pip._vendor.requests.packages.urllib3.packages.six.moves", - ] + ], ): latest_pypi_version = pip_self_version_check(None, _options()) @@ -139,19 +147,18 @@ def test_pip_self_version_check(monkeypatch, stored_time, installed_ver, assert len(logger.warning.calls) == 0 -statefile_name_case_1 = ( - "fcd2d5175dd33d5df759ee7b045264230205ef837bf9f582f7c3ada7" -) +statefile_name_case_1 = "fcd2d5175dd33d5df759ee7b045264230205ef837bf9f582f7c3ada7" -statefile_name_case_2 = ( - "902cecc0745b8ecf2509ba473f3556f0ba222fedc6df433acda24aa5" -) +statefile_name_case_2 = "902cecc0745b8ecf2509ba473f3556f0ba222fedc6df433acda24aa5" -@pytest.mark.parametrize("key,expected", [ - ("/hello/world/venv", statefile_name_case_1), - ("C:\\Users\\User\\Desktop\\venv", statefile_name_case_2), -]) +@pytest.mark.parametrize( + "key,expected", + [ + ("/hello/world/venv", statefile_name_case_1), + ("C:\\Users\\User\\Desktop\\venv", statefile_name_case_2), + ], +) def test_get_statefile_name_known_values(key, expected): assert expected == self_outdated_check._get_statefile_name(key) @@ -223,8 +230,7 @@ def test_self_check_state_writes_expected_statefile(monkeypatch, tmpdir): expected = { "key": key, - "last_check": last_check.strftime( - self_outdated_check.SELFCHECK_DATE_FMT), + "last_check": last_check.strftime(self_outdated_check.SELFCHECK_DATE_FMT), "pypi_version": pypi_version, } assert expected == saved diff --git a/tests/unit/test_target_python.py b/tests/unit/test_target_python.py index 0dc2af22bd0..8897df4c8b4 100644 --- a/tests/unit/test_target_python.py +++ b/tests/unit/test_target_python.py @@ -6,16 +6,18 @@ class TestTargetPython: - - @pytest.mark.parametrize('py_version_info, expected', [ - ((), ((0, 0, 0), '0.0')), - ((2, ), ((2, 0, 0), '2.0')), - ((3, ), ((3, 0, 0), '3.0')), - ((3, 7), ((3, 7, 0), '3.7')), - ((3, 7, 3), ((3, 7, 3), '3.7')), - # Check a minor version with two digits. - ((3, 10, 1), ((3, 10, 1), '3.10')), - ]) + @pytest.mark.parametrize( + "py_version_info, expected", + [ + ((), ((0, 0, 0), "0.0")), + ((2,), ((2, 0, 0), "2.0")), + ((3,), ((3, 0, 0), "3.0")), + ((3, 7), ((3, 7, 0), "3.7")), + ((3, 7, 3), ((3, 7, 3), "3.7")), + # Check a minor version with two digits. + ((3, 10, 1), ((3, 10, 1), "3.10")), + ], + ) def test_init__py_version_info(self, py_version_info, expected): """ Test passing the py_version_info argument. @@ -41,61 +43,72 @@ def test_init__py_version_info_none(self): assert target_python.py_version_info == CURRENT_PY_VERSION_INFO assert target_python.py_version == pyversion - @pytest.mark.parametrize('kwargs, expected', [ - ({}, ''), - (dict(py_version_info=(3, 6)), "version_info='3.6'"), - ( - dict(platform='darwin', py_version_info=(3, 6)), - "platform='darwin' version_info='3.6'", - ), - ( - dict( - platform='darwin', py_version_info=(3, 6), abi='cp36m', - implementation='cp' + @pytest.mark.parametrize( + "kwargs, expected", + [ + ({}, ""), + (dict(py_version_info=(3, 6)), "version_info='3.6'"), + ( + dict(platform="darwin", py_version_info=(3, 6)), + "platform='darwin' version_info='3.6'", ), ( - "platform='darwin' version_info='3.6' abi='cp36m' " - "implementation='cp'" + dict( + platform="darwin", + py_version_info=(3, 6), + abi="cp36m", + implementation="cp", + ), + ( + "platform='darwin' version_info='3.6' abi='cp36m' " + "implementation='cp'" + ), ), - ), - ]) + ], + ) def test_format_given(self, kwargs, expected): target_python = TargetPython(**kwargs) actual = target_python.format_given() assert actual == expected - @pytest.mark.parametrize('py_version_info, expected_version', [ - ((), ''), - ((2, ), '2'), - ((3, ), '3'), - ((3, 7), '37'), - ((3, 7, 3), '37'), - # Check a minor version with two digits. - ((3, 10, 1), '310'), - # Check that versions=None is passed to get_tags(). - (None, None), - ]) - @patch('pip._internal.models.target_python.get_supported') + @pytest.mark.parametrize( + "py_version_info, expected_version", + [ + ((), ""), + ((2,), "2"), + ((3,), "3"), + ((3, 7), "37"), + ((3, 7, 3), "37"), + # Check a minor version with two digits. + ((3, 10, 1), "310"), + # Check that versions=None is passed to get_tags(). + (None, None), + ], + ) + @patch("pip._internal.models.target_python.get_supported") def test_get_tags( - self, mock_get_supported, py_version_info, expected_version, + self, + mock_get_supported, + py_version_info, + expected_version, ): - mock_get_supported.return_value = ['tag-1', 'tag-2'] + mock_get_supported.return_value = ["tag-1", "tag-2"] target_python = TargetPython(py_version_info=py_version_info) actual = target_python.get_tags() - assert actual == ['tag-1', 'tag-2'] + assert actual == ["tag-1", "tag-2"] - actual = mock_get_supported.call_args[1]['version'] + actual = mock_get_supported.call_args[1]["version"] assert actual == expected_version # Check that the value was cached. - assert target_python._valid_tags == ['tag-1', 'tag-2'] + assert target_python._valid_tags == ["tag-1", "tag-2"] def test_get_tags__uses_cached_value(self): """ Test that get_tags() uses the cached value. """ target_python = TargetPython(py_version_info=None) - target_python._valid_tags = ['tag-1', 'tag-2'] + target_python._valid_tags = ["tag-1", "tag-2"] actual = target_python.get_tags() - assert actual == ['tag-1', 'tag-2'] + assert actual == ["tag-1", "tag-2"] diff --git a/tests/unit/test_urls.py b/tests/unit/test_urls.py index 7428cef9ebc..026e54cafd6 100644 --- a/tests/unit/test_urls.py +++ b/tests/unit/test_urls.py @@ -7,44 +7,50 @@ from pip._internal.utils.urls import get_url_scheme, path_to_url, url_to_path -@pytest.mark.parametrize("url,expected", [ - ('http://localhost:8080/', 'http'), - ('file:c:/path/to/file', 'file'), - ('file:/dev/null', 'file'), - ('', None), -]) +@pytest.mark.parametrize( + "url,expected", + [ + ("http://localhost:8080/", "http"), + ("file:c:/path/to/file", "file"), + ("file:/dev/null", "file"), + ("", None), + ], +) def test_get_url_scheme(url, expected): assert get_url_scheme(url) == expected @pytest.mark.skipif("sys.platform == 'win32'") def test_path_to_url_unix(): - assert path_to_url('/tmp/file') == 'file:///tmp/file' - path = os.path.join(os.getcwd(), 'file') - assert path_to_url('file') == 'file://' + urllib_request.pathname2url(path) + assert path_to_url("/tmp/file") == "file:///tmp/file" + path = os.path.join(os.getcwd(), "file") + assert path_to_url("file") == "file://" + urllib_request.pathname2url(path) @pytest.mark.skipif("sys.platform != 'win32'") def test_path_to_url_win(): - assert path_to_url('c:/tmp/file') == 'file:///C:/tmp/file' - assert path_to_url('c:\\tmp\\file') == 'file:///C:/tmp/file' - assert path_to_url(r'\\unc\as\path') == 'file://unc/as/path' - path = os.path.join(os.getcwd(), 'file') - assert path_to_url('file') == 'file:' + urllib_request.pathname2url(path) + assert path_to_url("c:/tmp/file") == "file:///C:/tmp/file" + assert path_to_url("c:\\tmp\\file") == "file:///C:/tmp/file" + assert path_to_url(r"\\unc\as\path") == "file://unc/as/path" + path = os.path.join(os.getcwd(), "file") + assert path_to_url("file") == "file:" + urllib_request.pathname2url(path) -@pytest.mark.parametrize("url,win_expected,non_win_expected", [ - ('file:tmp', 'tmp', 'tmp'), - ('file:c:/path/to/file', r'C:\path\to\file', 'c:/path/to/file'), - ('file:/path/to/file', r'\path\to\file', '/path/to/file'), - ('file://localhost/tmp/file', r'\tmp\file', '/tmp/file'), - ('file://localhost/c:/tmp/file', r'C:\tmp\file', '/c:/tmp/file'), - ('file://somehost/tmp/file', r'\\somehost\tmp\file', None), - ('file:///tmp/file', r'\tmp\file', '/tmp/file'), - ('file:///c:/tmp/file', r'C:\tmp\file', '/c:/tmp/file'), -]) +@pytest.mark.parametrize( + "url,win_expected,non_win_expected", + [ + ("file:tmp", "tmp", "tmp"), + ("file:c:/path/to/file", r"C:\path\to\file", "c:/path/to/file"), + ("file:/path/to/file", r"\path\to\file", "/path/to/file"), + ("file://localhost/tmp/file", r"\tmp\file", "/tmp/file"), + ("file://localhost/c:/tmp/file", r"C:\tmp\file", "/c:/tmp/file"), + ("file://somehost/tmp/file", r"\\somehost\tmp\file", None), + ("file:///tmp/file", r"\tmp\file", "/tmp/file"), + ("file:///c:/tmp/file", r"C:\tmp\file", "/c:/tmp/file"), + ], +) def test_url_to_path(url, win_expected, non_win_expected): - if sys.platform == 'win32': + if sys.platform == "win32": expected_path = win_expected else: expected_path = non_win_expected @@ -58,8 +64,8 @@ def test_url_to_path(url, win_expected, non_win_expected): @pytest.mark.skipif("sys.platform != 'win32'") def test_url_to_path_path_to_url_symmetry_win(): - path = r'C:\tmp\file' + path = r"C:\tmp\file" assert url_to_path(path_to_url(path)) == path - unc_path = r'\\unc\share\path' + unc_path = r"\\unc\share\path" assert url_to_path(path_to_url(unc_path)) == unc_path diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 0a1c47cd7ae..60c304d7ab5 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -16,11 +16,7 @@ import pytest from mock import Mock, patch -from pip._internal.exceptions import ( - HashMismatch, - HashMissing, - InstallationError, -) +from pip._internal.exceptions import HashMismatch, HashMissing, InstallationError from pip._internal.utils.deprecation import PipDeprecationWarning, deprecated from pip._internal.utils.encoding import BOMS, auto_decode from pip._internal.utils.glibc import ( @@ -62,42 +58,44 @@ class Tests_EgglinkPath: def setup(self): - project = 'foo' + project = "foo" self.mock_dist = Mock(project_name=project) - self.site_packages = 'SITE_PACKAGES' - self.user_site = 'USER_SITE' + self.site_packages = "SITE_PACKAGES" + self.user_site = "USER_SITE" self.user_site_egglink = os.path.join( - self.user_site, - '{}.egg-link'.format(project) + self.user_site, "{}.egg-link".format(project) ) self.site_packages_egglink = os.path.join( self.site_packages, - '{}.egg-link'.format(project), + "{}.egg-link".format(project), ) # patches from pip._internal.utils import misc as utils + self.old_site_packages = utils.site_packages - self.mock_site_packages = utils.site_packages = 'SITE_PACKAGES' + self.mock_site_packages = utils.site_packages = "SITE_PACKAGES" self.old_running_under_virtualenv = utils.running_under_virtualenv - self.mock_running_under_virtualenv = utils.running_under_virtualenv = \ - Mock() + self.mock_running_under_virtualenv = utils.running_under_virtualenv = Mock() self.old_virtualenv_no_global = utils.virtualenv_no_global self.mock_virtualenv_no_global = utils.virtualenv_no_global = Mock() self.old_user_site = utils.user_site self.mock_user_site = utils.user_site = self.user_site from os import path + self.old_isfile = path.isfile self.mock_isfile = path.isfile = Mock() def teardown(self): from pip._internal.utils import misc as utils + utils.site_packages = self.old_site_packages utils.running_under_virtualenv = self.old_running_under_virtualenv utils.virtualenv_no_global = self.old_virtualenv_no_global utils.user_site = self.old_user_site from os import path + path.isfile = self.old_isfile def eggLinkInUserSite(self, egglink): @@ -191,47 +189,53 @@ def test_noegglink_in_sitepkgs_venv_global(self): assert egg_link_path(self.mock_dist) is None -@patch('pip._internal.utils.misc.dist_in_usersite') -@patch('pip._internal.utils.misc.dist_is_local') -@patch('pip._internal.utils.misc.dist_is_editable') +@patch("pip._internal.utils.misc.dist_in_usersite") +@patch("pip._internal.utils.misc.dist_is_local") +@patch("pip._internal.utils.misc.dist_is_editable") class TestsGetDistributions(object): - """Test get_installed_distributions() and get_distribution(). - """ + """Test get_installed_distributions() and get_distribution().""" + class MockWorkingSet(list): def require(self, name): pass - workingset = MockWorkingSet(( - Mock(test_name="global", key="global"), - Mock(test_name="editable", key="editable"), - Mock(test_name="normal", key="normal"), - Mock(test_name="user", key="user"), - )) + workingset = MockWorkingSet( + ( + Mock(test_name="global", key="global"), + Mock(test_name="editable", key="editable"), + Mock(test_name="normal", key="normal"), + Mock(test_name="user", key="user"), + ) + ) - workingset_stdlib = MockWorkingSet(( - Mock(test_name='normal', key='argparse'), - Mock(test_name='normal', key='wsgiref') - )) + workingset_stdlib = MockWorkingSet( + ( + Mock(test_name="normal", key="argparse"), + Mock(test_name="normal", key="wsgiref"), + ) + ) - workingset_freeze = MockWorkingSet(( - Mock(test_name='normal', key='pip'), - Mock(test_name='normal', key='setuptools'), - Mock(test_name='normal', key='distribute') - )) + workingset_freeze = MockWorkingSet( + ( + Mock(test_name="normal", key="pip"), + Mock(test_name="normal", key="setuptools"), + Mock(test_name="normal", key="distribute"), + ) + ) def dist_is_editable(self, dist): return dist.test_name == "editable" def dist_is_local(self, dist): - return dist.test_name != "global" and dist.test_name != 'user' + return dist.test_name != "global" and dist.test_name != "user" def dist_in_usersite(self, dist): return dist.test_name == "user" - @patch('pip._vendor.pkg_resources.working_set', workingset) - def test_editables_only(self, mock_dist_is_editable, - mock_dist_is_local, - mock_dist_in_usersite): + @patch("pip._vendor.pkg_resources.working_set", workingset) + def test_editables_only( + self, mock_dist_is_editable, mock_dist_is_local, mock_dist_in_usersite + ): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite @@ -239,10 +243,10 @@ def test_editables_only(self, mock_dist_is_editable, assert len(dists) == 1, dists assert dists[0].test_name == "editable" - @patch('pip._vendor.pkg_resources.working_set', workingset) - def test_exclude_editables(self, mock_dist_is_editable, - mock_dist_is_local, - mock_dist_in_usersite): + @patch("pip._vendor.pkg_resources.working_set", workingset) + def test_exclude_editables( + self, mock_dist_is_editable, mock_dist_is_local, mock_dist_in_usersite + ): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite @@ -250,47 +254,45 @@ def test_exclude_editables(self, mock_dist_is_editable, assert len(dists) == 1 assert dists[0].test_name == "normal" - @patch('pip._vendor.pkg_resources.working_set', workingset) - def test_include_globals(self, mock_dist_is_editable, - mock_dist_is_local, - mock_dist_in_usersite): + @patch("pip._vendor.pkg_resources.working_set", workingset) + def test_include_globals( + self, mock_dist_is_editable, mock_dist_is_local, mock_dist_in_usersite + ): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite dists = get_installed_distributions(local_only=False) assert len(dists) == 4 - @patch('pip._vendor.pkg_resources.working_set', workingset) - def test_user_only(self, mock_dist_is_editable, - mock_dist_is_local, - mock_dist_in_usersite): + @patch("pip._vendor.pkg_resources.working_set", workingset) + def test_user_only( + self, mock_dist_is_editable, mock_dist_is_local, mock_dist_in_usersite + ): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite - dists = get_installed_distributions(local_only=False, - user_only=True) + dists = get_installed_distributions(local_only=False, user_only=True) assert len(dists) == 1 assert dists[0].test_name == "user" - @patch('pip._vendor.pkg_resources.working_set', workingset_stdlib) - def test_gte_py27_excludes(self, mock_dist_is_editable, - mock_dist_is_local, - mock_dist_in_usersite): + @patch("pip._vendor.pkg_resources.working_set", workingset_stdlib) + def test_gte_py27_excludes( + self, mock_dist_is_editable, mock_dist_is_local, mock_dist_in_usersite + ): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite dists = get_installed_distributions() assert len(dists) == 0 - @patch('pip._vendor.pkg_resources.working_set', workingset_freeze) - def test_freeze_excludes(self, mock_dist_is_editable, - mock_dist_is_local, - mock_dist_in_usersite): + @patch("pip._vendor.pkg_resources.working_set", workingset_freeze) + def test_freeze_excludes( + self, mock_dist_is_editable, mock_dist_is_local, mock_dist_in_usersite + ): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite - dists = get_installed_distributions( - skip=('setuptools', 'pip', 'distribute')) + dists = get_installed_distributions(skip=("setuptools", "pip", "distribute")) assert len(dists) == 0 @pytest.mark.parametrize( @@ -298,7 +300,8 @@ def test_freeze_excludes(self, mock_dist_is_editable, itertools.chain( itertools.product([workingset], (d.key for d in workingset)), itertools.product( - [workingset_stdlib], (d.key for d in workingset_stdlib), + [workingset_stdlib], + (d.key for d in workingset_stdlib), ), ), ) @@ -310,8 +313,7 @@ def test_get_distribution( working_set, req_name, ): - """Ensure get_distribution() finds all kinds of distributions. - """ + """Ensure get_distribution() finds all kinds of distributions.""" mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite @@ -320,7 +322,7 @@ def test_get_distribution( assert dist is not None assert dist.key == req_name - @patch('pip._vendor.pkg_resources.working_set', workingset) + @patch("pip._vendor.pkg_resources.working_set", workingset) def test_get_distribution_nonexist( self, mock_dist_is_editable, @@ -338,7 +340,7 @@ def test_rmtree_errorhandler_nonexistent_directory(tmpdir): """ Test rmtree_errorhandler ignores the given non-existing directory. """ - nonexistent_path = str(tmpdir / 'foo') + nonexistent_path = str(tmpdir / "foo") mock_func = Mock() rmtree_errorhandler(mock_func, nonexistent_path, None) mock_func.assert_not_called() @@ -349,7 +351,7 @@ def test_rmtree_errorhandler_readonly_directory(tmpdir): Test rmtree_errorhandler makes the given read-only directory writable. """ # Create read only directory - subdir_path = tmpdir / 'subdir' + subdir_path = tmpdir / "subdir" subdir_path.mkdir() path = str(subdir_path) os.chmod(path, stat.S_IREAD) @@ -369,7 +371,7 @@ def test_rmtree_errorhandler_reraises_error(tmpdir): by the given unreadable directory. """ # Create directory without read permission - subdir_path = tmpdir / 'subdir' + subdir_path = tmpdir / "subdir" subdir_path.mkdir() path = str(subdir_path) os.chmod(path, stat.S_IWRITE) @@ -377,10 +379,10 @@ def test_rmtree_errorhandler_reraises_error(tmpdir): mock_func = Mock() try: - raise RuntimeError('test message') + raise RuntimeError("test message") except RuntimeError: # Make sure the handler reraises an exception - with pytest.raises(RuntimeError, match='test message'): + with pytest.raises(RuntimeError, match="test message"): rmtree_errorhandler(mock_func, path, None) mock_func.assert_not_called() @@ -391,7 +393,7 @@ def test_rmtree_skips_nonexistent_directory(): Test wrapped rmtree doesn't raise an error by the given nonexistent directory. """ - rmtree.__wrapped__('nonexistent-subdir') + rmtree.__wrapped__("nonexistent-subdir") class Failer: @@ -408,45 +410,46 @@ def test_rmtree_retries(tmpdir, monkeypatch): """ Test pip._internal.utils.rmtree will retry failures """ - monkeypatch.setattr(shutil, 'rmtree', Failer(duration=1).call) - rmtree('foo') + monkeypatch.setattr(shutil, "rmtree", Failer(duration=1).call) + rmtree("foo") def test_rmtree_retries_for_3sec(tmpdir, monkeypatch): """ Test pip._internal.utils.rmtree will retry failures for no more than 3 sec """ - monkeypatch.setattr(shutil, 'rmtree', Failer(duration=5).call) + monkeypatch.setattr(shutil, "rmtree", Failer(duration=5).call) with pytest.raises(OSError): - rmtree('foo') + rmtree("foo") if sys.byteorder == "little": expected_byte_string = ( - u"b'\\xff\\xfe/\\x00p\\x00a\\x00t\\x00h\\x00/" - "\\x00d\\x00\\xe9\\x00f\\x00'" + u"b'\\xff\\xfe/\\x00p\\x00a\\x00t\\x00h\\x00/" "\\x00d\\x00\\xe9\\x00f\\x00'" ) elif sys.byteorder == "big": expected_byte_string = ( - u"b'\\xfe\\xff\\x00/\\x00p\\x00a\\x00t\\x00h\\" - "x00/\\x00d\\x00\\xe9\\x00f'" + u"b'\\xfe\\xff\\x00/\\x00p\\x00a\\x00t\\x00h\\" "x00/\\x00d\\x00\\xe9\\x00f'" ) -@pytest.mark.parametrize('path, fs_encoding, expected', [ - (None, None, None), - # Test passing a text (unicode) string. - (u'/path/déf', None, u'/path/déf'), - # Test a bytes object with a non-ascii character. - (u'/path/déf'.encode('utf-8'), 'utf-8', u'/path/déf'), - # Test a bytes object with a character that can't be decoded. - (u'/path/déf'.encode('utf-8'), 'ascii', u"b'/path/d\\xc3\\xa9f'"), - (u'/path/déf'.encode('utf-16'), 'utf-8', expected_byte_string), -]) +@pytest.mark.parametrize( + "path, fs_encoding, expected", + [ + (None, None, None), + # Test passing a text (unicode) string. + (u"/path/déf", None, u"/path/déf"), + # Test a bytes object with a non-ascii character. + (u"/path/déf".encode("utf-8"), "utf-8", u"/path/déf"), + # Test a bytes object with a character that can't be decoded. + (u"/path/déf".encode("utf-8"), "ascii", u"b'/path/d\\xc3\\xa9f'"), + (u"/path/déf".encode("utf-16"), "utf-8", expected_byte_string), + ], +) def test_path_to_display(monkeypatch, path, fs_encoding, expected): - monkeypatch.setattr(sys, 'getfilesystemencoding', lambda: fs_encoding) + monkeypatch.setattr(sys, "getfilesystemencoding", lambda: fs_encoding) actual = path_to_display(path) - assert actual == expected, 'actual: {!r}'.format(actual) + assert actual == expected, "actual: {!r}".format(actual) class Test_normalize_path(object): @@ -460,28 +463,28 @@ def test_resolve_symlinks(self, tmpdir): orig_working_dir = os.getcwd() os.chdir(tmpdir) try: - d = os.path.join('foo', 'bar') - f = os.path.join(d, 'file1') + d = os.path.join("foo", "bar") + f = os.path.join(d, "file1") os.makedirs(d) - with open(f, 'w'): # Create the file + with open(f, "w"): # Create the file pass - os.symlink(d, 'dir_link') - os.symlink(f, 'file_link') - - assert normalize_path( - 'dir_link/file1', resolve_symlinks=True - ) == os.path.join(tmpdir, f) - assert normalize_path( - 'dir_link/file1', resolve_symlinks=False - ) == os.path.join(tmpdir, 'dir_link', 'file1') + os.symlink(d, "dir_link") + os.symlink(f, "file_link") assert normalize_path( - 'file_link', resolve_symlinks=True + "dir_link/file1", resolve_symlinks=True ) == os.path.join(tmpdir, f) assert normalize_path( - 'file_link', resolve_symlinks=False - ) == os.path.join(tmpdir, 'file_link') + "dir_link/file1", resolve_symlinks=False + ) == os.path.join(tmpdir, "dir_link", "file1") + + assert normalize_path("file_link", resolve_symlinks=True) == os.path.join( + tmpdir, f + ) + assert normalize_path("file_link", resolve_symlinks=False) == os.path.join( + tmpdir, "file_link" + ) finally: os.chdir(orig_working_dir) @@ -489,18 +492,21 @@ def test_resolve_symlinks(self, tmpdir): class TestHashes(object): """Tests for pip._internal.utils.hashes""" - @pytest.mark.parametrize('hash_name, hex_digest, expected', [ - # Test a value that matches but with the wrong hash_name. - ('sha384', 128 * 'a', False), - # Test matching values, including values other than the first. - ('sha512', 128 * 'a', True), - ('sha512', 128 * 'b', True), - # Test a matching hash_name with a value that doesn't match. - ('sha512', 128 * 'c', False), - ]) + @pytest.mark.parametrize( + "hash_name, hex_digest, expected", + [ + # Test a value that matches but with the wrong hash_name. + ("sha384", 128 * "a", False), + # Test matching values, including values other than the first. + ("sha512", 128 * "a", True), + ("sha512", 128 * "b", True), + # Test a matching hash_name with a value that doesn't match. + ("sha512", 128 * "c", False), + ], + ) def test_is_hash_allowed(self, hash_name, hex_digest, expected): hashes_data = { - 'sha512': [128 * 'a', 128 * 'b'], + "sha512": [128 * "a", 128 * "b"], } hashes = Hashes(hashes_data) assert hashes.is_hash_allowed(hash_name, hex_digest) == expected @@ -511,37 +517,42 @@ def test_success(self, tmpdir): Test check_against_path because it calls everything else. """ - file = tmpdir / 'to_hash' - file.write_text('hello') - hashes = Hashes({ - 'sha256': ['2cf24dba5fb0a30e26e83b2ac5b9e29e' - '1b161e5c1fa7425e73043362938b9824'], - 'sha224': ['wrongwrong'], - 'md5': ['5d41402abc4b2a76b9719d911017c592']}) + file = tmpdir / "to_hash" + file.write_text("hello") + hashes = Hashes( + { + "sha256": [ + "2cf24dba5fb0a30e26e83b2ac5b9e29e" + "1b161e5c1fa7425e73043362938b9824" + ], + "sha224": ["wrongwrong"], + "md5": ["5d41402abc4b2a76b9719d911017c592"], + } + ) hashes.check_against_path(file) def test_failure(self): """Hashes should raise HashMismatch when no hashes match.""" - hashes = Hashes({'sha256': ['wrongwrong']}) + hashes = Hashes({"sha256": ["wrongwrong"]}) with pytest.raises(HashMismatch): - hashes.check_against_file(BytesIO(b'hello')) + hashes.check_against_file(BytesIO(b"hello")) def test_missing_hashes(self): """MissingHashes should raise HashMissing when any check is done.""" with pytest.raises(HashMissing): - MissingHashes().check_against_file(BytesIO(b'hello')) + MissingHashes().check_against_file(BytesIO(b"hello")) def test_unknown_hash(self): """Hashes should raise InstallationError when it encounters an unknown hash.""" - hashes = Hashes({'badbad': ['dummy']}) + hashes = Hashes({"badbad": ["dummy"]}) with pytest.raises(InstallationError): - hashes.check_against_file(BytesIO(b'hello')) + hashes.check_against_file(BytesIO(b"hello")) def test_non_zero(self): """Test that truthiness tests tell whether any known-good hashes exist.""" - assert Hashes({'sha256': 'dummy'}) + assert Hashes({"sha256": "dummy"}) assert not Hashes() assert not Hashes({}) @@ -551,41 +562,41 @@ class TestEncoding(object): def test_auto_decode_utf_16_le(self): data = ( - b'\xff\xfeD\x00j\x00a\x00n\x00g\x00o\x00=\x00' - b'=\x001\x00.\x004\x00.\x002\x00' + b"\xff\xfeD\x00j\x00a\x00n\x00g\x00o\x00=\x00" + b"=\x001\x00.\x004\x00.\x002\x00" ) assert data.startswith(codecs.BOM_UTF16_LE) assert auto_decode(data) == "Django==1.4.2" def test_auto_decode_utf_16_be(self): data = ( - b'\xfe\xff\x00D\x00j\x00a\x00n\x00g\x00o\x00=' - b'\x00=\x001\x00.\x004\x00.\x002' + b"\xfe\xff\x00D\x00j\x00a\x00n\x00g\x00o\x00=" + b"\x00=\x001\x00.\x004\x00.\x002" ) assert data.startswith(codecs.BOM_UTF16_BE) assert auto_decode(data) == "Django==1.4.2" def test_auto_decode_no_bom(self): - assert auto_decode(b'foobar') == u'foobar' + assert auto_decode(b"foobar") == u"foobar" def test_auto_decode_pep263_headers(self): - latin1_req = u'# coding=latin1\n# Pas trop de café' - assert auto_decode(latin1_req.encode('latin1')) == latin1_req + latin1_req = u"# coding=latin1\n# Pas trop de café" + assert auto_decode(latin1_req.encode("latin1")) == latin1_req def test_auto_decode_no_preferred_encoding(self): om, em = Mock(), Mock() - om.return_value = 'ascii' + om.return_value = "ascii" em.return_value = None - data = u'data' - with patch('sys.getdefaultencoding', om): - with patch('locale.getpreferredencoding', em): + data = u"data" + with patch("sys.getdefaultencoding", om): + with patch("locale.getpreferredencoding", em): ret = auto_decode(data.encode(sys.getdefaultencoding())) assert ret == data - @pytest.mark.parametrize('encoding', [encoding for bom, encoding in BOMS]) + @pytest.mark.parametrize("encoding", [encoding for bom, encoding in BOMS]) def test_all_encodings_are_valid(self, encoding): # we really only care that there is no LookupError - assert ''.encode(encoding).decode(encoding) == '' + assert "".encode(encoding).decode(encoding) == "" def raises(error): @@ -596,22 +607,31 @@ class TestGlibc(object): @pytest.mark.skipif("sys.platform == 'win32'") def test_glibc_version_string(self, monkeypatch): monkeypatch.setattr( - os, "confstr", lambda x: "glibc 2.20", raising=False, + os, + "confstr", + lambda x: "glibc 2.20", + raising=False, ) assert glibc_version_string() == "2.20" @pytest.mark.skipif("sys.platform == 'win32'") def test_glibc_version_string_confstr(self, monkeypatch): monkeypatch.setattr( - os, "confstr", lambda x: "glibc 2.20", raising=False, + os, + "confstr", + lambda x: "glibc 2.20", + raising=False, ) assert glibc_version_string_confstr() == "2.20" - @pytest.mark.parametrize("failure", [ - lambda x: raises(ValueError), - lambda x: raises(OSError), - lambda x: "XXX", - ]) + @pytest.mark.parametrize( + "failure", + [ + lambda x: raises(ValueError), + lambda x: raises(OSError), + lambda x: "XXX", + ], + ) def test_glibc_version_string_confstr_fail(self, monkeypatch, failure): monkeypatch.setattr(os, "confstr", failure, raising=False) assert glibc_version_string_confstr() is None @@ -625,206 +645,243 @@ def test_glibc_version_string_ctypes_missing(self, monkeypatch): assert glibc_version_string_ctypes() is None -@pytest.mark.parametrize('version_info, expected', [ - ((), (0, 0, 0)), - ((3, ), (3, 0, 0)), - ((3, 6), (3, 6, 0)), - ((3, 6, 2), (3, 6, 2)), - ((3, 6, 2, 4), (3, 6, 2)), -]) +@pytest.mark.parametrize( + "version_info, expected", + [ + ((), (0, 0, 0)), + ((3,), (3, 0, 0)), + ((3, 6), (3, 6, 0)), + ((3, 6, 2), (3, 6, 2)), + ((3, 6, 2, 4), (3, 6, 2)), + ], +) def test_normalize_version_info(version_info, expected): actual = normalize_version_info(version_info) assert actual == expected class TestGetProg(object): - @pytest.mark.parametrize( ("argv", "executable", "expected"), [ - ('/usr/bin/pip', '', 'pip'), - ('-c', '/usr/bin/python', '/usr/bin/python -m pip'), - ('__main__.py', '/usr/bin/python', '/usr/bin/python -m pip'), - ('/usr/bin/pip3', '', 'pip3'), - ] + ("/usr/bin/pip", "", "pip"), + ("-c", "/usr/bin/python", "/usr/bin/python -m pip"), + ("__main__.py", "/usr/bin/python", "/usr/bin/python -m pip"), + ("/usr/bin/pip3", "", "pip3"), + ], ) def test_get_prog(self, monkeypatch, argv, executable, expected): - monkeypatch.setattr('pip._internal.utils.misc.sys.argv', [argv]) - monkeypatch.setattr( - 'pip._internal.utils.misc.sys.executable', - executable - ) + monkeypatch.setattr("pip._internal.utils.misc.sys.argv", [argv]) + monkeypatch.setattr("pip._internal.utils.misc.sys.executable", executable) assert get_prog() == expected -@pytest.mark.parametrize('host_port, expected_netloc', [ - # Test domain name. - (('example.com', None), 'example.com'), - (('example.com', 5000), 'example.com:5000'), - # Test IPv4 address. - (('127.0.0.1', None), '127.0.0.1'), - (('127.0.0.1', 5000), '127.0.0.1:5000'), - # Test bare IPv6 address. - (('2001:db6::1', None), '2001:db6::1'), - # Test IPv6 with port. - (('2001:db6::1', 5000), '[2001:db6::1]:5000'), -]) +@pytest.mark.parametrize( + "host_port, expected_netloc", + [ + # Test domain name. + (("example.com", None), "example.com"), + (("example.com", 5000), "example.com:5000"), + # Test IPv4 address. + (("127.0.0.1", None), "127.0.0.1"), + (("127.0.0.1", 5000), "127.0.0.1:5000"), + # Test bare IPv6 address. + (("2001:db6::1", None), "2001:db6::1"), + # Test IPv6 with port. + (("2001:db6::1", 5000), "[2001:db6::1]:5000"), + ], +) def test_build_netloc(host_port, expected_netloc): assert build_netloc(*host_port) == expected_netloc -@pytest.mark.parametrize('netloc, expected_url, expected_host_port', [ - # Test domain name. - ('example.com', 'https://example.com', ('example.com', None)), - ('example.com:5000', 'https://example.com:5000', ('example.com', 5000)), - # Test IPv4 address. - ('127.0.0.1', 'https://127.0.0.1', ('127.0.0.1', None)), - ('127.0.0.1:5000', 'https://127.0.0.1:5000', ('127.0.0.1', 5000)), - # Test bare IPv6 address. - ('2001:db6::1', 'https://[2001:db6::1]', ('2001:db6::1', None)), - # Test IPv6 with port. - ( - '[2001:db6::1]:5000', - 'https://[2001:db6::1]:5000', - ('2001:db6::1', 5000) - ), - # Test netloc with auth. - ( - 'user:password@localhost:5000', - 'https://user:password@localhost:5000', - ('localhost', 5000) - ) -]) +@pytest.mark.parametrize( + "netloc, expected_url, expected_host_port", + [ + # Test domain name. + ("example.com", "https://example.com", ("example.com", None)), + ("example.com:5000", "https://example.com:5000", ("example.com", 5000)), + # Test IPv4 address. + ("127.0.0.1", "https://127.0.0.1", ("127.0.0.1", None)), + ("127.0.0.1:5000", "https://127.0.0.1:5000", ("127.0.0.1", 5000)), + # Test bare IPv6 address. + ("2001:db6::1", "https://[2001:db6::1]", ("2001:db6::1", None)), + # Test IPv6 with port. + ("[2001:db6::1]:5000", "https://[2001:db6::1]:5000", ("2001:db6::1", 5000)), + # Test netloc with auth. + ( + "user:password@localhost:5000", + "https://user:password@localhost:5000", + ("localhost", 5000), + ), + ], +) def test_build_url_from_netloc_and_parse_netloc( - netloc, expected_url, expected_host_port, + netloc, + expected_url, + expected_host_port, ): assert build_url_from_netloc(netloc) == expected_url assert parse_netloc(netloc) == expected_host_port -@pytest.mark.parametrize('netloc, expected', [ - # Test a basic case. - ('example.com', ('example.com', (None, None))), - # Test with username and no password. - ('user@example.com', ('example.com', ('user', None))), - # Test with username and password. - ('user:pass@example.com', ('example.com', ('user', 'pass'))), - # Test with username and empty password. - ('user:@example.com', ('example.com', ('user', ''))), - # Test the password containing an @ symbol. - ('user:pass@word@example.com', ('example.com', ('user', 'pass@word'))), - # Test the password containing a : symbol. - ('user:pass:word@example.com', ('example.com', ('user', 'pass:word'))), - # Test URL-encoded reserved characters. - ('user%3Aname:%23%40%5E@example.com', - ('example.com', ('user:name', '#@^'))), -]) +@pytest.mark.parametrize( + "netloc, expected", + [ + # Test a basic case. + ("example.com", ("example.com", (None, None))), + # Test with username and no password. + ("user@example.com", ("example.com", ("user", None))), + # Test with username and password. + ("user:pass@example.com", ("example.com", ("user", "pass"))), + # Test with username and empty password. + ("user:@example.com", ("example.com", ("user", ""))), + # Test the password containing an @ symbol. + ("user:pass@word@example.com", ("example.com", ("user", "pass@word"))), + # Test the password containing a : symbol. + ("user:pass:word@example.com", ("example.com", ("user", "pass:word"))), + # Test URL-encoded reserved characters. + ("user%3Aname:%23%40%5E@example.com", ("example.com", ("user:name", "#@^"))), + ], +) def test_split_auth_from_netloc(netloc, expected): actual = split_auth_from_netloc(netloc) assert actual == expected -@pytest.mark.parametrize('url, expected', [ - # Test a basic case. - ('http://example.com/path#anchor', - ('http://example.com/path#anchor', 'example.com', (None, None))), - # Test with username and no password. - ('http://user@example.com/path#anchor', - ('http://example.com/path#anchor', 'example.com', ('user', None))), - # Test with username and password. - ('http://user:pass@example.com/path#anchor', - ('http://example.com/path#anchor', 'example.com', ('user', 'pass'))), - # Test with username and empty password. - ('http://user:@example.com/path#anchor', - ('http://example.com/path#anchor', 'example.com', ('user', ''))), - # Test the password containing an @ symbol. - ('http://user:pass@word@example.com/path#anchor', - ('http://example.com/path#anchor', 'example.com', ('user', 'pass@word'))), - # Test the password containing a : symbol. - ('http://user:pass:word@example.com/path#anchor', - ('http://example.com/path#anchor', 'example.com', ('user', 'pass:word'))), - # Test URL-encoded reserved characters. - ('http://user%3Aname:%23%40%5E@example.com/path#anchor', - ('http://example.com/path#anchor', 'example.com', ('user:name', '#@^'))), -]) +@pytest.mark.parametrize( + "url, expected", + [ + # Test a basic case. + ( + "http://example.com/path#anchor", + ("http://example.com/path#anchor", "example.com", (None, None)), + ), + # Test with username and no password. + ( + "http://user@example.com/path#anchor", + ("http://example.com/path#anchor", "example.com", ("user", None)), + ), + # Test with username and password. + ( + "http://user:pass@example.com/path#anchor", + ("http://example.com/path#anchor", "example.com", ("user", "pass")), + ), + # Test with username and empty password. + ( + "http://user:@example.com/path#anchor", + ("http://example.com/path#anchor", "example.com", ("user", "")), + ), + # Test the password containing an @ symbol. + ( + "http://user:pass@word@example.com/path#anchor", + ("http://example.com/path#anchor", "example.com", ("user", "pass@word")), + ), + # Test the password containing a : symbol. + ( + "http://user:pass:word@example.com/path#anchor", + ("http://example.com/path#anchor", "example.com", ("user", "pass:word")), + ), + # Test URL-encoded reserved characters. + ( + "http://user%3Aname:%23%40%5E@example.com/path#anchor", + ("http://example.com/path#anchor", "example.com", ("user:name", "#@^")), + ), + ], +) def test_split_auth_netloc_from_url(url, expected): actual = split_auth_netloc_from_url(url) assert actual == expected -@pytest.mark.parametrize('netloc, expected', [ - # Test a basic case. - ('example.com', 'example.com'), - # Test with username and no password. - ('accesstoken@example.com', '****@example.com'), - # Test with username and password. - ('user:pass@example.com', 'user:****@example.com'), - # Test with username and empty password. - ('user:@example.com', 'user:****@example.com'), - # Test the password containing an @ symbol. - ('user:pass@word@example.com', 'user:****@example.com'), - # Test the password containing a : symbol. - ('user:pass:word@example.com', 'user:****@example.com'), - # Test URL-encoded reserved characters. - ('user%3Aname:%23%40%5E@example.com', 'user%3Aname:****@example.com'), -]) +@pytest.mark.parametrize( + "netloc, expected", + [ + # Test a basic case. + ("example.com", "example.com"), + # Test with username and no password. + ("accesstoken@example.com", "****@example.com"), + # Test with username and password. + ("user:pass@example.com", "user:****@example.com"), + # Test with username and empty password. + ("user:@example.com", "user:****@example.com"), + # Test the password containing an @ symbol. + ("user:pass@word@example.com", "user:****@example.com"), + # Test the password containing a : symbol. + ("user:pass:word@example.com", "user:****@example.com"), + # Test URL-encoded reserved characters. + ("user%3Aname:%23%40%5E@example.com", "user%3Aname:****@example.com"), + ], +) def test_redact_netloc(netloc, expected): actual = redact_netloc(netloc) assert actual == expected -@pytest.mark.parametrize('auth_url, expected_url', [ - ('https://user:pass@domain.tld/project/tags/v0.2', - 'https://domain.tld/project/tags/v0.2'), - ('https://domain.tld/project/tags/v0.2', - 'https://domain.tld/project/tags/v0.2',), - ('https://user:pass@domain.tld/svn/project/trunk@8181', - 'https://domain.tld/svn/project/trunk@8181'), - ('https://domain.tld/project/trunk@8181', - 'https://domain.tld/project/trunk@8181',), - ('git+https://pypi.org/something', - 'git+https://pypi.org/something'), - ('git+https://user:pass@pypi.org/something', - 'git+https://pypi.org/something'), - ('git+ssh://git@pypi.org/something', - 'git+ssh://pypi.org/something'), -]) +@pytest.mark.parametrize( + "auth_url, expected_url", + [ + ( + "https://user:pass@domain.tld/project/tags/v0.2", + "https://domain.tld/project/tags/v0.2", + ), + ( + "https://domain.tld/project/tags/v0.2", + "https://domain.tld/project/tags/v0.2", + ), + ( + "https://user:pass@domain.tld/svn/project/trunk@8181", + "https://domain.tld/svn/project/trunk@8181", + ), + ( + "https://domain.tld/project/trunk@8181", + "https://domain.tld/project/trunk@8181", + ), + ("git+https://pypi.org/something", "git+https://pypi.org/something"), + ("git+https://user:pass@pypi.org/something", "git+https://pypi.org/something"), + ("git+ssh://git@pypi.org/something", "git+ssh://pypi.org/something"), + ], +) def test_remove_auth_from_url(auth_url, expected_url): url = remove_auth_from_url(auth_url) assert url == expected_url -@pytest.mark.parametrize('auth_url, expected_url', [ - ('https://accesstoken@example.com/abc', 'https://****@example.com/abc'), - ('https://user:password@example.com', 'https://user:****@example.com'), - ('https://user:@example.com', 'https://user:****@example.com'), - ('https://example.com', 'https://example.com'), - # Test URL-encoded reserved characters. - ('https://user%3Aname:%23%40%5E@example.com', - 'https://user%3Aname:****@example.com'), -]) +@pytest.mark.parametrize( + "auth_url, expected_url", + [ + ("https://accesstoken@example.com/abc", "https://****@example.com/abc"), + ("https://user:password@example.com", "https://user:****@example.com"), + ("https://user:@example.com", "https://user:****@example.com"), + ("https://example.com", "https://example.com"), + # Test URL-encoded reserved characters. + ( + "https://user%3Aname:%23%40%5E@example.com", + "https://user%3Aname:****@example.com", + ), + ], +) def test_redact_auth_from_url(auth_url, expected_url): url = redact_auth_from_url(auth_url) assert url == expected_url class TestHiddenText: - def test_basic(self): """ Test str(), repr(), and attribute access. """ - hidden = HiddenText('my-secret', redacted='######') + hidden = HiddenText("my-secret", redacted="######") assert repr(hidden) == "" - assert str(hidden) == '######' - assert hidden.redacted == '######' - assert hidden.secret == 'my-secret' + assert str(hidden) == "######" + assert hidden.redacted == "######" + assert hidden.secret == "my-secret" def test_equality_with_str(self): """ Test equality (and inequality) with str objects. """ - hidden = HiddenText('secret', redacted='****') + hidden = HiddenText("secret", redacted="****") # Test that the object doesn't compare equal to either its original # or redacted forms. @@ -839,8 +896,8 @@ def test_equality_same_secret(self): Test equality with an object having the same secret. """ # Choose different redactions for the two objects. - hidden1 = HiddenText('secret', redacted='****') - hidden2 = HiddenText('secret', redacted='####') + hidden1 = HiddenText("secret", redacted="****") + hidden2 = HiddenText("secret", redacted="####") assert hidden1 == hidden2 # Also test __ne__. This assertion fails in Python 2 without @@ -851,8 +908,8 @@ def test_equality_different_secret(self): """ Test equality with an object having a different secret. """ - hidden1 = HiddenText('secret-1', redacted='****') - hidden2 = HiddenText('secret-2', redacted='****') + hidden1 = HiddenText("secret-1", redacted="****") + hidden2 = HiddenText("secret-2", redacted="****") assert hidden1 != hidden2 # Also test __eq__. @@ -860,25 +917,26 @@ def test_equality_different_secret(self): def test_hide_value(): - hidden = hide_value('my-secret') + hidden = hide_value("my-secret") assert repr(hidden) == "" - assert str(hidden) == '****' - assert hidden.redacted == '****' - assert hidden.secret == 'my-secret' + assert str(hidden) == "****" + assert hidden.redacted == "****" + assert hidden.secret == "my-secret" def test_hide_url(): - hidden_url = hide_url('https://user:password@example.com') + hidden_url = hide_url("https://user:password@example.com") assert repr(hidden_url) == "" - assert str(hidden_url) == 'https://user:****@example.com' - assert hidden_url.redacted == 'https://user:****@example.com' - assert hidden_url.secret == 'https://user:password@example.com' + assert str(hidden_url) == "https://user:****@example.com" + assert hidden_url.redacted == "https://user:****@example.com" + assert hidden_url.secret == "https://user:password@example.com" @pytest.fixture() def patch_deprecation_check_version(): # We do this, so that the deprecation tests are easier to write. import pip._internal.utils.deprecation as d + old_version = d.current_version d.current_version = "1.0" yield @@ -954,27 +1012,23 @@ def test_deprecated_message_reads_well(): def test_make_setuptools_shim_args(): # Test all arguments at once, including the overall ordering. args = make_setuptools_shim_args( - '/dir/path/setup.py', - global_options=['--some', '--option'], + "/dir/path/setup.py", + global_options=["--some", "--option"], no_user_config=True, unbuffered_output=True, ) - assert args[1:3] == ['-u', '-c'] + assert args[1:3] == ["-u", "-c"] # Spot-check key aspects of the command string. assert "sys.argv[0] = '/dir/path/setup.py'" in args[3] assert "__file__='/dir/path/setup.py'" in args[3] - assert args[4:] == ['--some', '--option', '--no-user-cfg'] + assert args[4:] == ["--some", "--option", "--no-user-cfg"] -@pytest.mark.parametrize('global_options', [ - None, - [], - ['--some', '--option'] -]) +@pytest.mark.parametrize("global_options", [None, [], ["--some", "--option"]]) def test_make_setuptools_shim_args__global_options(global_options): args = make_setuptools_shim_args( - '/dir/path/setup.py', + "/dir/path/setup.py", global_options=global_options, ) @@ -986,61 +1040,77 @@ def test_make_setuptools_shim_args__global_options(global_options): assert len(args) == 3 -@pytest.mark.parametrize('no_user_config', [False, True]) +@pytest.mark.parametrize("no_user_config", [False, True]) def test_make_setuptools_shim_args__no_user_config(no_user_config): args = make_setuptools_shim_args( - '/dir/path/setup.py', + "/dir/path/setup.py", no_user_config=no_user_config, ) - assert ('--no-user-cfg' in args) == no_user_config + assert ("--no-user-cfg" in args) == no_user_config -@pytest.mark.parametrize('unbuffered_output', [False, True]) +@pytest.mark.parametrize("unbuffered_output", [False, True]) def test_make_setuptools_shim_args__unbuffered_output(unbuffered_output): args = make_setuptools_shim_args( - '/dir/path/setup.py', - unbuffered_output=unbuffered_output + "/dir/path/setup.py", unbuffered_output=unbuffered_output ) - assert ('-u' in args) == unbuffered_output + assert ("-u" in args) == unbuffered_output -@pytest.mark.parametrize('isatty,no_stdin,expected', [ - (True, False, True), - (False, False, False), - (True, True, False), - (False, True, False), -]) +@pytest.mark.parametrize( + "isatty,no_stdin,expected", + [ + (True, False, True), + (False, False, False), + (True, True, False), + (False, True, False), + ], +) def test_is_console_interactive(monkeypatch, isatty, no_stdin, expected): - monkeypatch.setattr(sys.stdin, 'isatty', Mock(return_value=isatty)) + monkeypatch.setattr(sys.stdin, "isatty", Mock(return_value=isatty)) if no_stdin: - monkeypatch.setattr(sys, 'stdin', None) + monkeypatch.setattr(sys, "stdin", None) assert is_console_interactive() is expected -@pytest.mark.parametrize('size,expected', [ - (123, "123 bytes"), - (1234, "1.2 kB"), - (123456, "123 kB"), - (1234567890, "1234.6 MB"), -]) +@pytest.mark.parametrize( + "size,expected", + [ + (123, "123 bytes"), + (1234, "1.2 kB"), + (123456, "123 kB"), + (1234567890, "1234.6 MB"), + ], +) def test_format_size(size, expected): assert format_size(size) == expected @pytest.mark.parametrize( - ('rows', 'table', 'sizes'), - [([], [], []), - ([('I?', 'version', 'sdist', 'wheel'), - ('', '1.18.2', 'zip', 'cp38-cp38m-win_amd64'), - ('v', 1.18, 'zip')], - ['I? version sdist wheel', - ' 1.18.2 zip cp38-cp38m-win_amd64', - 'v 1.18 zip'], - [2, 7, 5, 20]), - ([('I?', 'version', 'sdist', 'wheel'), (), ('v', '1.18.1', 'zip')], - ['I? version sdist wheel', '', 'v 1.18.1 zip'], - [2, 7, 5, 5])]) + ("rows", "table", "sizes"), + [ + ([], [], []), + ( + [ + ("I?", "version", "sdist", "wheel"), + ("", "1.18.2", "zip", "cp38-cp38m-win_amd64"), + ("v", 1.18, "zip"), + ], + [ + "I? version sdist wheel", + " 1.18.2 zip cp38-cp38m-win_amd64", + "v 1.18 zip", + ], + [2, 7, 5, 20], + ), + ( + [("I?", "version", "sdist", "wheel"), (), ("v", "1.18.1", "zip")], + ["I? version sdist wheel", "", "v 1.18.1 zip"], + [2, 7, 5, 5], + ), + ], +) def test_tabulate(rows, table, sizes): assert tabulate(rows) == (table, sizes) diff --git a/tests/unit/test_utils_compatibility_tags.py b/tests/unit/test_utils_compatibility_tags.py index 12c8da453d9..ecc8d6f857b 100644 --- a/tests/unit/test_utils_compatibility_tags.py +++ b/tests/unit/test_utils_compatibility_tags.py @@ -6,23 +6,25 @@ from pip._internal.utils import compatibility_tags -@pytest.mark.parametrize('version_info, expected', [ - ((2,), '2'), - ((2, 8), '28'), - ((3,), '3'), - ((3, 6), '36'), - # Test a tuple of length 3. - ((3, 6, 5), '36'), - # Test a 2-digit minor version. - ((3, 10), '310'), -]) +@pytest.mark.parametrize( + "version_info, expected", + [ + ((2,), "2"), + ((2, 8), "28"), + ((3,), "3"), + ((3, 6), "36"), + # Test a tuple of length 3. + ((3, 6, 5), "36"), + # Test a 2-digit minor version. + ((3, 10), "310"), + ], +) def test_version_info_to_nodot(version_info, expected): actual = compatibility_tags.version_info_to_nodot(version_info) assert actual == expected class Testcompatibility_tags(object): - def mock_get_config_var(self, **kwd): """ Patch sysconfig.get_config_var for arbitrary keys. @@ -33,6 +35,7 @@ def _mock_get_config_var(var): if var in kwd: return kwd[var] return get_config_var(var) + return _mock_get_config_var def test_no_hyphen_tag(self): @@ -41,23 +44,25 @@ def test_no_hyphen_tag(self): """ import pip._internal.utils.compatibility_tags - mock_gcf = self.mock_get_config_var(SOABI='cpython-35m-darwin') + mock_gcf = self.mock_get_config_var(SOABI="cpython-35m-darwin") - with patch('sysconfig.get_config_var', mock_gcf): + with patch("sysconfig.get_config_var", mock_gcf): supported = pip._internal.utils.compatibility_tags.get_supported() for tag in supported: - assert '-' not in tag.interpreter - assert '-' not in tag.abi - assert '-' not in tag.platform + assert "-" not in tag.interpreter + assert "-" not in tag.abi + assert "-" not in tag.platform class TestManylinux2010Tags(object): - - @pytest.mark.parametrize("manylinux2010,manylinux1", [ - ("manylinux2010_x86_64", "manylinux1_x86_64"), - ("manylinux2010_i686", "manylinux1_i686"), - ]) + @pytest.mark.parametrize( + "manylinux2010,manylinux1", + [ + ("manylinux2010_x86_64", "manylinux1_x86_64"), + ("manylinux2010_i686", "manylinux1_i686"), + ], + ) def test_manylinux2010_implies_manylinux1(self, manylinux2010, manylinux1): """ Specifying manylinux2010 implies manylinux1. @@ -65,23 +70,22 @@ def test_manylinux2010_implies_manylinux1(self, manylinux2010, manylinux1): groups = {} supported = compatibility_tags.get_supported(platform=manylinux2010) for tag in supported: - groups.setdefault( - (tag.interpreter, tag.abi), [] - ).append(tag.platform) + groups.setdefault((tag.interpreter, tag.abi), []).append(tag.platform) for arches in groups.values(): - if arches == ['any']: + if arches == ["any"]: continue assert arches[:2] == [manylinux2010, manylinux1] class TestManylinux2014Tags(object): - - @pytest.mark.parametrize("manylinuxA,manylinuxB", [ - ("manylinux2014_x86_64", ["manylinux2010_x86_64", - "manylinux1_x86_64"]), - ("manylinux2014_i686", ["manylinux2010_i686", "manylinux1_i686"]), - ]) + @pytest.mark.parametrize( + "manylinuxA,manylinuxB", + [ + ("manylinux2014_x86_64", ["manylinux2010_x86_64", "manylinux1_x86_64"]), + ("manylinux2014_i686", ["manylinux2010_i686", "manylinux1_i686"]), + ], + ) def test_manylinuxA_implies_manylinuxB(self, manylinuxA, manylinuxB): """ Specifying manylinux2014 implies manylinux2010/manylinux1. @@ -89,13 +93,11 @@ def test_manylinuxA_implies_manylinuxB(self, manylinuxA, manylinuxB): groups = {} supported = compatibility_tags.get_supported(platform=manylinuxA) for tag in supported: - groups.setdefault( - (tag.interpreter, tag.abi), [] - ).append(tag.platform) + groups.setdefault((tag.interpreter, tag.abi), []).append(tag.platform) expected_arches = [manylinuxA] expected_arches.extend(manylinuxB) for arches in groups.values(): - if arches == ['any']: + if arches == ["any"]: continue assert arches[:3] == expected_arches diff --git a/tests/unit/test_utils_distutils_args.py b/tests/unit/test_utils_distutils_args.py index 5bca65018ec..57e80a9c8ca 100644 --- a/tests/unit/test_utils_distutils_args.py +++ b/tests/unit/test_utils_distutils_args.py @@ -36,19 +36,22 @@ def test_multiple_invocations_do_not_keep_options(): assert result["root"] == "world1" -@pytest.mark.parametrize("name,value", [ - ("exec-prefix", "1"), - ("home", "2"), - ("install-base", "3"), - ("install-data", "4"), - ("install-headers", "5"), - ("install-lib", "6"), - ("install-platlib", "7"), - ("install-purelib", "8"), - ("install-scripts", "9"), - ("prefix", "10"), - ("root", "11"), -]) +@pytest.mark.parametrize( + "name,value", + [ + ("exec-prefix", "1"), + ("home", "2"), + ("install-base", "3"), + ("install-data", "4"), + ("install-headers", "5"), + ("install-lib", "6"), + ("install-platlib", "7"), + ("install-purelib", "8"), + ("install-scripts", "9"), + ("prefix", "10"), + ("root", "11"), + ], +) def test_all_value_options_work(name, value): result = parse_distutils_args(["--{}={}".format(name, value)]) key_name = name.replace("-", "_") diff --git a/tests/unit/test_utils_filesystem.py b/tests/unit/test_utils_filesystem.py index 3ef814dce4b..c7b3b90d4e8 100644 --- a/tests/unit/test_utils_filesystem.py +++ b/tests/unit/test_utils_filesystem.py @@ -30,13 +30,16 @@ def make_dir(path): @skip_on_windows -@pytest.mark.parametrize("create,result", [ - (make_socket_file, True), - (make_file, False), - (make_valid_symlink, False), - (make_broken_symlink, False), - (make_dir, False), -]) +@pytest.mark.parametrize( + "create,result", + [ + (make_socket_file, True), + (make_file, False), + (make_valid_symlink, False), + (make_broken_symlink, False), + (make_dir, False), + ], +) def test_is_socket(create, result, tmpdir): target = tmpdir.joinpath("target") create(target) @@ -44,12 +47,13 @@ def test_is_socket(create, result, tmpdir): assert is_socket(target) == result -@pytest.mark.parametrize("create,error_type", [ - pytest.param( - make_socket_file, shutil.SpecialFileError, marks=skip_on_windows - ), - (make_unreadable_file, OSError), -]) +@pytest.mark.parametrize( + "create,error_type", + [ + pytest.param(make_socket_file, shutil.SpecialFileError, marks=skip_on_windows), + (make_unreadable_file, OSError), + ], +) def test_copy2_fixed_raises_appropriate_errors(create, error_type, tmpdir): src = tmpdir.joinpath("src") create(src) diff --git a/tests/unit/test_utils_parallel.py b/tests/unit/test_utils_parallel.py index 6086dcaa08b..1d3f561e86c 100644 --- a/tests/unit/test_utils_parallel.py +++ b/tests/unit/test_utils_parallel.py @@ -9,15 +9,15 @@ from pip._vendor.six.moves import map from pytest import mark -DUNDER_IMPORT = '__builtin__.__import__' if PY2 else 'builtins.__import__' +DUNDER_IMPORT = "__builtin__.__import__" if PY2 else "builtins.__import__" FUNC, ITERABLE = factorial, range(42) -MAPS = 'map_multiprocess', 'map_multithread' +MAPS = "map_multiprocess", "map_multithread" _import = __import__ def unload_parallel(): try: - del modules['pip._internal.utils.parallel'] + del modules["pip._internal.utils.parallel"] except KeyError: pass @@ -26,14 +26,14 @@ def unload_parallel(): def tmp_import_parallel(): unload_parallel() try: - yield import_module('pip._internal.utils.parallel') + yield import_module("pip._internal.utils.parallel") finally: unload_parallel() def lack_sem_open(name, *args, **kwargs): """Raise ImportError on import of multiprocessing.synchronize.""" - if name.endswith('synchronize'): + if name.endswith("synchronize"): raise ImportError return _import(name, *args, **kwargs) @@ -42,12 +42,12 @@ def have_sem_open(name, *args, **kwargs): """Make sure multiprocessing.synchronize import is successful.""" # We don't care about the return value # since we don't use the pool with this import. - if name.endswith('synchronize'): + if name.endswith("synchronize"): return return _import(name, *args, **kwargs) -@mark.parametrize('name', MAPS) +@mark.parametrize("name", MAPS) def test_lack_sem_open(name, monkeypatch): """Test fallback when sem_open is not available. @@ -59,17 +59,17 @@ def test_lack_sem_open(name, monkeypatch): assert getattr(parallel, name) is parallel._map_fallback -@mark.parametrize('name', MAPS) +@mark.parametrize("name", MAPS) def test_have_sem_open(name, monkeypatch): """Test fallback when sem_open is available.""" monkeypatch.setattr(DUNDER_IMPORT, have_sem_open) - impl = '_map_fallback' if PY2 else '_{}'.format(name) + impl = "_map_fallback" if PY2 else "_{}".format(name) with tmp_import_parallel() as parallel: assert getattr(parallel, name) is getattr(parallel, impl) -@mark.parametrize('name', MAPS) +@mark.parametrize("name", MAPS) def test_map(name): """Test correctness of result of asynchronous maps.""" - map_async = getattr(import_module('pip._internal.utils.parallel'), name) + map_async = getattr(import_module("pip._internal.utils.parallel"), name) assert set(map_async(FUNC, ITERABLE)) == set(map(FUNC, ITERABLE)) diff --git a/tests/unit/test_utils_pkg_resources.py b/tests/unit/test_utils_pkg_resources.py index d113d6df124..e4d67e513fc 100644 --- a/tests/unit/test_utils_pkg_resources.py +++ b/tests/unit/test_utils_pkg_resources.py @@ -27,9 +27,7 @@ def test_dict_metadata_works(): metadata["Provides-Extra"] = extra metadata["Requires-Python"] = requires_python - inner_metadata = DictMetadata({ - "METADATA": ensure_binary(metadata.as_string()) - }) + inner_metadata = DictMetadata({"METADATA": ensure_binary(metadata.as_string())}) dist = DistInfoDistribution( location="", metadata=inner_metadata, project_name=name ) @@ -39,7 +37,8 @@ def test_dict_metadata_works(): assert set(extras) == set(dist.extras) assert [Requirement.parse(require_a)] == dist.requires([]) assert [ - Requirement.parse(require_a), Requirement.parse(require_b) + Requirement.parse(require_a), + Requirement.parse(require_b), ] == dist.requires(["also_b"]) assert metadata.as_string() == get_metadata(dist).as_string() assert requires_python == get_requires_python(dist) @@ -48,9 +47,7 @@ def test_dict_metadata_works(): # Metadata is not decoded on Python 2, so no chance for error. @skip_if_python2 def test_dict_metadata_throws_on_bad_unicode(): - metadata = DictMetadata({ - "METADATA": b"\xff" - }) + metadata = DictMetadata({"METADATA": b"\xff"}) with pytest.raises(UnicodeDecodeError) as e: metadata.get_metadata("METADATA") diff --git a/tests/unit/test_utils_subprocess.py b/tests/unit/test_utils_subprocess.py index b0de2bf578d..94244863bb4 100644 --- a/tests/unit/test_utils_subprocess.py +++ b/tests/unit/test_utils_subprocess.py @@ -17,30 +17,38 @@ ) -@pytest.mark.parametrize('args, expected', [ - (['pip', 'list'], 'pip list'), - (['foo', 'space space', 'new\nline', 'double"quote', "single'quote"], - """foo 'space space' 'new\nline' 'double"quote' 'single'"'"'quote'"""), - # Test HiddenText arguments. - (make_command(hide_value('secret1'), 'foo', hide_value('secret2')), - "'****' foo '****'"), -]) +@pytest.mark.parametrize( + "args, expected", + [ + (["pip", "list"], "pip list"), + ( + ["foo", "space space", "new\nline", 'double"quote', "single'quote"], + """foo 'space space' 'new\nline' 'double"quote' 'single'"'"'quote'""", + ), + # Test HiddenText arguments. + ( + make_command(hide_value("secret1"), "foo", hide_value("secret2")), + "'****' foo '****'", + ), + ], +) def test_format_command_args(args, expected): actual = format_command_args(args) assert actual == expected def test_make_subprocess_output_error(): - cmd_args = ['test', 'has space'] - cwd = '/path/to/cwd' - lines = ['line1\n', 'line2\n', 'line3\n'] + cmd_args = ["test", "has space"] + cwd = "/path/to/cwd" + lines = ["line1\n", "line2\n", "line3\n"] actual = make_subprocess_output_error( cmd_args=cmd_args, cwd=cwd, lines=lines, exit_status=3, ) - expected = dedent("""\ + expected = dedent( + """\ Command errored out with exit status 3: command: test 'has space' cwd: /path/to/cwd @@ -48,36 +56,39 @@ def test_make_subprocess_output_error(): line1 line2 line3 - ----------------------------------------""") - assert actual == expected, 'actual: {}'.format(actual) + ----------------------------------------""" + ) + assert actual == expected, "actual: {}".format(actual) def test_make_subprocess_output_error__non_ascii_command_arg(monkeypatch): """ Test a command argument with a non-ascii character. """ - cmd_args = ['foo', 'déf'] + cmd_args = ["foo", "déf"] if sys.version_info[0] == 2: # Check in Python 2 that the str (bytes object) with the non-ascii # character has the encoding we expect. (This comes from the source # code encoding at the top of the file.) - assert cmd_args[1].decode('utf-8') == u'déf' + assert cmd_args[1].decode("utf-8") == u"déf" # We need to monkeypatch so the encoding will be correct on Windows. - monkeypatch.setattr(locale, 'getpreferredencoding', lambda: 'utf-8') + monkeypatch.setattr(locale, "getpreferredencoding", lambda: "utf-8") actual = make_subprocess_output_error( cmd_args=cmd_args, - cwd='/path/to/cwd', + cwd="/path/to/cwd", lines=[], exit_status=1, ) - expected = dedent(u"""\ + expected = dedent( + u"""\ Command errored out with exit status 1: command: foo 'déf' cwd: /path/to/cwd Complete output (0 lines): - ----------------------------------------""") - assert actual == expected, u'actual: {}'.format(actual) + ----------------------------------------""" + ) + assert actual == expected, u"actual: {}".format(actual) @pytest.mark.skipif("sys.version_info < (3,)") @@ -85,51 +96,59 @@ def test_make_subprocess_output_error__non_ascii_cwd_python_3(monkeypatch): """ Test a str (text) cwd with a non-ascii character in Python 3. """ - cmd_args = ['test'] - cwd = '/path/to/cwd/déf' + cmd_args = ["test"] + cwd = "/path/to/cwd/déf" actual = make_subprocess_output_error( cmd_args=cmd_args, cwd=cwd, lines=[], exit_status=1, ) - expected = dedent("""\ + expected = dedent( + """\ Command errored out with exit status 1: command: test cwd: /path/to/cwd/déf Complete output (0 lines): - ----------------------------------------""") - assert actual == expected, 'actual: {}'.format(actual) + ----------------------------------------""" + ) + assert actual == expected, "actual: {}".format(actual) -@pytest.mark.parametrize('encoding', [ - 'utf-8', - # Test a Windows encoding. - 'cp1252', -]) +@pytest.mark.parametrize( + "encoding", + [ + "utf-8", + # Test a Windows encoding. + "cp1252", + ], +) @pytest.mark.skipif("sys.version_info >= (3,)") def test_make_subprocess_output_error__non_ascii_cwd_python_2( - monkeypatch, encoding, + monkeypatch, + encoding, ): """ Test a str (bytes object) cwd with a non-ascii character in Python 2. """ - cmd_args = ['test'] - cwd = u'/path/to/cwd/déf'.encode(encoding) - monkeypatch.setattr(sys, 'getfilesystemencoding', lambda: encoding) + cmd_args = ["test"] + cwd = u"/path/to/cwd/déf".encode(encoding) + monkeypatch.setattr(sys, "getfilesystemencoding", lambda: encoding) actual = make_subprocess_output_error( cmd_args=cmd_args, cwd=cwd, lines=[], exit_status=1, ) - expected = dedent(u"""\ + expected = dedent( + u"""\ Command errored out with exit status 1: command: test cwd: /path/to/cwd/déf Complete output (0 lines): - ----------------------------------------""") - assert actual == expected, u'actual: {}'.format(actual) + ----------------------------------------""" + ) + assert actual == expected, u"actual: {}".format(actual) # This test is mainly important for checking unicode in Python 2. @@ -137,25 +156,26 @@ def test_make_subprocess_output_error__non_ascii_line(): """ Test a line with a non-ascii character. """ - lines = [u'curly-quote: \u2018\n'] + lines = [u"curly-quote: \u2018\n"] actual = make_subprocess_output_error( - cmd_args=['test'], - cwd='/path/to/cwd', + cmd_args=["test"], + cwd="/path/to/cwd", lines=lines, exit_status=1, ) - expected = dedent(u"""\ + expected = dedent( + u"""\ Command errored out with exit status 1: command: test cwd: /path/to/cwd Complete output (1 lines): curly-quote: \u2018 - ----------------------------------------""") - assert actual == expected, u'actual: {}'.format(actual) + ----------------------------------------""" + ) + assert actual == expected, u"actual: {}".format(actual) class FakeSpinner(SpinnerInterface): - def __init__(self): self.spin_count = 0 self.final_status = None @@ -174,7 +194,13 @@ class TestCallSubprocess(object): """ def check_result( - self, capfd, caplog, log_level, spinner, result, expected, + self, + capfd, + caplog, + log_level, + spinner, + result, + expected, expected_spinner, ): """ @@ -202,11 +228,11 @@ def check_result( # Confirm that stdout and stderr haven't been written to. captured = capfd.readouterr() - assert (captured.out, captured.err) == ('', '') + assert (captured.out, captured.err) == ("", "") records = caplog.record_tuples if len(records) != len(expected_records): - raise RuntimeError('{} != {}'.format(records, expected_records)) + raise RuntimeError("{} != {}".format(records, expected_records)) for record, expected_record in zip(records, expected_records): # Check the logger_name and log level parts exactly. @@ -227,7 +253,7 @@ def prepare_call(self, caplog, log_level, command=None): caplog.set_level(log_level) spinner = FakeSpinner() - args = [sys.executable, '-c', command] + args = [sys.executable, "-c", command] return (args, spinner) @@ -239,15 +265,23 @@ def test_debug_logging(self, capfd, caplog): args, spinner = self.prepare_call(caplog, log_level) result = call_subprocess(args, spinner=spinner) - expected = (['Hello', 'world'], [ - ('pip.subprocessor', DEBUG, 'Running command '), - ('pip.subprocessor', DEBUG, 'Hello'), - ('pip.subprocessor', DEBUG, 'world'), - ]) + expected = ( + ["Hello", "world"], + [ + ("pip.subprocessor", DEBUG, "Running command "), + ("pip.subprocessor", DEBUG, "Hello"), + ("pip.subprocessor", DEBUG, "world"), + ], + ) # The spinner shouldn't spin in this case since the subprocess # output is already being logged to the console. self.check_result( - capfd, caplog, log_level, spinner, result, expected, + capfd, + caplog, + log_level, + spinner, + result, + expected, expected_spinner=(0, None), ) @@ -259,12 +293,17 @@ def test_info_logging(self, capfd, caplog): args, spinner = self.prepare_call(caplog, log_level) result = call_subprocess(args, spinner=spinner) - expected = (['Hello', 'world'], []) + expected = (["Hello", "world"], []) # The spinner should spin twice in this case since the subprocess # output isn't being written to the console. self.check_result( - capfd, caplog, log_level, spinner, result, expected, - expected_spinner=(2, 'done'), + capfd, + caplog, + log_level, + spinner, + result, + expected, + expected_spinner=(2, "done"), ) def test_info_logging__subprocess_error(self, capfd, caplog): @@ -280,19 +319,25 @@ def test_info_logging__subprocess_error(self, capfd, caplog): call_subprocess(args, spinner=spinner) result = None exc_message = str(exc.value) - assert exc_message.startswith( - 'Command errored out with exit status 1: ' + assert exc_message.startswith("Command errored out with exit status 1: ") + assert exc_message.endswith("Check the logs for full command output.") + + expected = ( + None, + [ + ("pip.subprocessor", ERROR, "Complete output (3 lines):\n"), + ], ) - assert exc_message.endswith('Check the logs for full command output.') - - expected = (None, [ - ('pip.subprocessor', ERROR, 'Complete output (3 lines):\n'), - ]) # The spinner should spin three times in this case since the # subprocess output isn't being written to the console. self.check_result( - capfd, caplog, log_level, spinner, result, expected, - expected_spinner=(3, 'error'), + capfd, + caplog, + log_level, + spinner, + result, + expected, + expected_spinner=(3, "error"), ) # Do some further checking on the captured log records to confirm @@ -310,16 +355,18 @@ def test_info_logging__subprocess_error(self, capfd, caplog): # exact match. command_line = actual.pop(1) assert actual == [ - ' cwd: None', - '----------------------------------------', - 'Command errored out with exit status 1:', - 'Complete output (3 lines):', - 'Hello', - 'fail', - 'world', - ], 'lines: {}'.format(actual) # Show the full output on failure. - - assert command_line.startswith(' command: ') + " cwd: None", + "----------------------------------------", + "Command errored out with exit status 1:", + "Complete output (3 lines):", + "Hello", + "fail", + "world", + ], "lines: {}".format( + actual + ) # Show the full output on failure. + + assert command_line.startswith(" command: ") assert command_line.endswith('print("world"); exit("fail")\'') def test_info_logging_with_show_stdout_true(self, capfd, caplog): @@ -330,26 +377,33 @@ def test_info_logging_with_show_stdout_true(self, capfd, caplog): args, spinner = self.prepare_call(caplog, log_level) result = call_subprocess(args, spinner=spinner, show_stdout=True) - expected = (['Hello', 'world'], [ - ('pip.subprocessor', INFO, 'Running command '), - ('pip.subprocessor', INFO, 'Hello'), - ('pip.subprocessor', INFO, 'world'), - ]) + expected = ( + ["Hello", "world"], + [ + ("pip.subprocessor", INFO, "Running command "), + ("pip.subprocessor", INFO, "Hello"), + ("pip.subprocessor", INFO, "world"), + ], + ) # The spinner shouldn't spin in this case since the subprocess # output is already being written to the console. self.check_result( - capfd, caplog, log_level, spinner, result, expected, + capfd, + caplog, + log_level, + spinner, + result, + expected, expected_spinner=(0, None), ) - @pytest.mark.parametrize(( - 'exit_status', 'show_stdout', 'extra_ok_returncodes', 'log_level', - 'expected'), + @pytest.mark.parametrize( + ("exit_status", "show_stdout", "extra_ok_returncodes", "log_level", "expected"), [ # The spinner should show here because show_stdout=False means # the subprocess should get logged at DEBUG level, but the passed # log level is only INFO. - (0, False, None, INFO, (None, 'done', 2)), + (0, False, None, INFO, (None, "done", 2)), # Test some cases where the spinner should not be shown. (0, False, None, DEBUG, (None, None, 0)), # Test show_stdout=True. @@ -358,15 +412,21 @@ def test_info_logging_with_show_stdout_true(self, capfd, caplog): # The spinner should show here because show_stdout=True means # the subprocess should get logged at INFO level, but the passed # log level is only WARNING. - (0, True, None, WARNING, (None, 'done', 2)), + (0, True, None, WARNING, (None, "done", 2)), # Test a non-zero exit status. - (3, False, None, INFO, (InstallationError, 'error', 2)), + (3, False, None, INFO, (InstallationError, "error", 2)), # Test a non-zero exit status also in extra_ok_returncodes. - (3, False, (3, ), INFO, (None, 'done', 2)), - ]) + (3, False, (3,), INFO, (None, "done", 2)), + ], + ) def test_spinner_finish( - self, exit_status, show_stdout, extra_ok_returncodes, log_level, - caplog, expected, + self, + exit_status, + show_stdout, + extra_ok_returncodes, + log_level, + caplog, + expected, ): """ Test that the spinner finishes correctly. @@ -375,9 +435,7 @@ def test_spinner_finish( expected_final_status = expected[1] expected_spin_count = expected[2] - command = ( - 'print("Hello"); print("world"); exit({})'.format(exit_status) - ) + command = 'print("Hello"); print("world"); exit({})'.format(exit_status) args, spinner = self.prepare_call(caplog, log_level, command=command) try: call_subprocess( @@ -398,6 +456,6 @@ def test_spinner_finish( def test_closes_stdin(self): with pytest.raises(InstallationError): call_subprocess( - [sys.executable, '-c', 'input()'], + [sys.executable, "-c", "input()"], show_stdout=True, ) diff --git a/tests/unit/test_utils_temp_dir.py b/tests/unit/test_utils_temp_dir.py index 0d1b0a5ea20..187d449a2b0 100644 --- a/tests/unit/test_utils_temp_dir.py +++ b/tests/unit/test_utils_temp_dir.py @@ -23,21 +23,14 @@ def test_symlinked_path(): assert os.path.exists(tmp_dir.path) alt_tmp_dir = tempfile.mkdtemp(prefix="pip-test-") - assert ( - os.path.dirname(tmp_dir.path) == - os.path.dirname(os.path.realpath(alt_tmp_dir)) + assert os.path.dirname(tmp_dir.path) == os.path.dirname( + os.path.realpath(alt_tmp_dir) ) # are we on a system where /tmp is a symlink if os.path.realpath(alt_tmp_dir) != os.path.abspath(alt_tmp_dir): - assert ( - os.path.dirname(tmp_dir.path) != - os.path.dirname(alt_tmp_dir) - ) + assert os.path.dirname(tmp_dir.path) != os.path.dirname(alt_tmp_dir) else: - assert ( - os.path.dirname(tmp_dir.path) == - os.path.dirname(alt_tmp_dir) - ) + assert os.path.dirname(tmp_dir.path) == os.path.dirname(alt_tmp_dir) os.rmdir(tmp_dir.path) assert not os.path.exists(tmp_dir.path) @@ -95,16 +88,19 @@ def test_create_and_cleanup_work(): assert not os.path.exists(created_path) -@pytest.mark.parametrize("name", [ - "ABC", - "ABC.dist-info", - "_+-", - "_package", - "A......B", - "AB", - "A", - "2", -]) +@pytest.mark.parametrize( + "name", + [ + "ABC", + "ABC.dist-info", + "_+-", + "_package", + "A......B", + "AB", + "A", + "2", + ], +) def test_adjacent_directory_names(name): def names(): return AdjacentTempDirectory._generate_names(name) @@ -132,15 +128,12 @@ def names(): assert len(some_names) > 0.9 * len(set(some_names)) # Ensure the first few names are the same length as the original - same_len = list(itertools.takewhile( - lambda x: len(x) == len(name), - some_names - )) + same_len = list(itertools.takewhile(lambda x: len(x) == len(name), some_names)) assert len(same_len) > 10 # Check the first group are correct - expected_names = ['~' + name[1:]] - expected_names.extend('~' + c + name[2:] for c in chars) + expected_names = ["~" + name[1:]] + expected_names.extend("~" + c + name[2:] for c in chars) for x, y in zip(some_names, expected_names): assert x == y @@ -159,16 +152,20 @@ def names(): assert all(x.endswith(name) for x in some_names) -@pytest.mark.parametrize("name", [ - "A", - "ABC", - "ABC.dist-info", - "_+-", - "_package", -]) +@pytest.mark.parametrize( + "name", + [ + "A", + "ABC", + "ABC.dist-info", + "_+-", + "_package", + ], +) def test_adjacent_directory_exists(name, tmpdir): block_name, expect_name = itertools.islice( - AdjacentTempDirectory._generate_names(name), 2) + AdjacentTempDirectory._generate_names(name), 2 + ) original = os.path.join(tmpdir, name) blocker = os.path.join(tmpdir, block_name) @@ -215,20 +212,23 @@ def test_tempdirectory_asserts_global_tempdir(monkeypatch): not_deleted_kind = "not-deleted" -@pytest.mark.parametrize("delete,kind,exists", [ - (None, deleted_kind, False), - (_default, deleted_kind, False), - (True, deleted_kind, False), - (False, deleted_kind, True), - (None, not_deleted_kind, True), - (_default, not_deleted_kind, True), - (True, not_deleted_kind, False), - (False, not_deleted_kind, True), - (None, "unspecified", False), - (_default, "unspecified", False), - (True, "unspecified", False), - (False, "unspecified", True), -]) +@pytest.mark.parametrize( + "delete,kind,exists", + [ + (None, deleted_kind, False), + (_default, deleted_kind, False), + (True, deleted_kind, False), + (False, deleted_kind, True), + (None, not_deleted_kind, True), + (_default, not_deleted_kind, True), + (True, not_deleted_kind, False), + (False, not_deleted_kind, True), + (None, "unspecified", False), + (_default, "unspecified", False), + (True, "unspecified", False), + (False, "unspecified", True), + ], +) def test_tempdir_registry(kind, delete, exists): with tempdir_registry() as registry: registry.set_delete(deleted_kind, True) @@ -240,12 +240,8 @@ def test_tempdir_registry(kind, delete, exists): assert os.path.exists(path) == exists -@pytest.mark.parametrize("delete,exists", [ - (_default, True), (None, False) -]) -def test_temp_dir_does_not_delete_explicit_paths_by_default( - tmpdir, delete, exists -): +@pytest.mark.parametrize("delete,exists", [(_default, True), (None, False)]) +def test_temp_dir_does_not_delete_explicit_paths_by_default(tmpdir, delete, exists): path = tmpdir / "example" path.mkdir() diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py index d01ffb9cd0b..f11087f9cb7 100644 --- a/tests/unit/test_utils_unpacking.py +++ b/tests/unit/test_utils_unpacking.py @@ -10,11 +10,7 @@ import pytest from pip._internal.exceptions import InstallationError -from pip._internal.utils.unpacking import ( - is_within_directory, - untar_file, - unzip_file, -) +from pip._internal.utils.unpacking import is_within_directory, untar_file, unzip_file class TestUnpackArchives(object): @@ -53,31 +49,31 @@ def confirm_files(self): # expectations based on 022 umask set above and the unpack logic that # sets execute permissions, not preservation for fname, expected_mode, test, expected_contents in [ - ('file.txt', 0o644, os.path.isfile, b'file\n'), + ("file.txt", 0o644, os.path.isfile, b"file\n"), # We don't test the "symlink.txt" contents for now. - ('symlink.txt', 0o644, os.path.isfile, None), - ('script_owner.sh', 0o755, os.path.isfile, b'file\n'), - ('script_group.sh', 0o755, os.path.isfile, b'file\n'), - ('script_world.sh', 0o755, os.path.isfile, b'file\n'), - ('dir', 0o755, os.path.isdir, None), - (os.path.join('dir', 'dirfile'), 0o644, os.path.isfile, b''), + ("symlink.txt", 0o644, os.path.isfile, None), + ("script_owner.sh", 0o755, os.path.isfile, b"file\n"), + ("script_group.sh", 0o755, os.path.isfile, b"file\n"), + ("script_world.sh", 0o755, os.path.isfile, b"file\n"), + ("dir", 0o755, os.path.isdir, None), + (os.path.join("dir", "dirfile"), 0o644, os.path.isfile, b""), ]: path = os.path.join(self.tempdir, fname) - if path.endswith('symlink.txt') and sys.platform == 'win32': + if path.endswith("symlink.txt") and sys.platform == "win32": # no symlinks created on windows continue assert test(path), path if expected_contents is not None: - with open(path, mode='rb') as f: + with open(path, mode="rb") as f: contents = f.read() - assert contents == expected_contents, 'fname: {}'.format(fname) - if sys.platform == 'win32': + assert contents == expected_contents, "fname: {}".format(fname) + if sys.platform == "win32": # the permissions tests below don't apply in windows # due to os.chmod being a noop continue mode = self.mode(path) - assert mode == expected_mode, ( - "mode: {}, expected mode: {}".format(mode, expected_mode) + assert mode == expected_mode, "mode: {}, expected mode: {}".format( + mode, expected_mode ) def make_zip_file(self, filename, file_list): @@ -85,9 +81,9 @@ def make_zip_file(self, filename, file_list): Create a zip file for test case """ test_zip = os.path.join(self.tempdir, filename) - with zipfile.ZipFile(test_zip, 'w') as myzip: + with zipfile.ZipFile(test_zip, "w") as myzip: for item in file_list: - myzip.writestr(item, 'file content') + myzip.writestr(item, "file content") return test_zip def make_tar_file(self, filename, file_list): @@ -95,10 +91,10 @@ def make_tar_file(self, filename, file_list): Create a tar file for test case """ test_tar = os.path.join(self.tempdir, filename) - with tarfile.open(test_tar, 'w') as mytar: + with tarfile.open(test_tar, "w") as mytar: for item in file_list: file_tarinfo = tarfile.TarInfo(item) - mytar.addfile(file_tarinfo, 'file content') + mytar.addfile(file_tarinfo, "file content") return test_tar def test_unpack_tgz(self, data): @@ -109,7 +105,7 @@ def test_unpack_tgz(self, data): untar_file(test_file, self.tempdir) self.confirm_files() # Check the timestamp of an extracted file - file_txt_path = os.path.join(self.tempdir, 'file.txt') + file_txt_path = os.path.join(self.tempdir, "file.txt") mtime = time.gmtime(os.stat(file_txt_path).st_mtime) assert mtime[0:6] == (2013, 8, 16, 5, 13, 37), mtime @@ -126,11 +122,11 @@ def test_unpack_zip_failure(self): Test unpacking a *.zip with file containing .. path and expect exception """ - files = ['regular_file.txt', os.path.join('..', 'outside_file.txt')] - test_zip = self.make_zip_file('test_zip.zip', files) + files = ["regular_file.txt", os.path.join("..", "outside_file.txt")] + test_zip = self.make_zip_file("test_zip.zip", files) with pytest.raises(InstallationError) as e: unzip_file(test_zip, self.tempdir) - assert 'trying to install outside target directory' in str(e.value) + assert "trying to install outside target directory" in str(e.value) def test_unpack_zip_success(self): """ @@ -139,11 +135,11 @@ def test_unpack_zip_success(self): so no exception raised """ files = [ - 'regular_file1.txt', - os.path.join('dir', 'dir_file1.txt'), - os.path.join('dir', '..', 'dir_file2.txt'), + "regular_file1.txt", + os.path.join("dir", "dir_file1.txt"), + os.path.join("dir", "..", "dir_file2.txt"), ] - test_zip = self.make_zip_file('test_zip.zip', files) + test_zip = self.make_zip_file("test_zip.zip", files) unzip_file(test_zip, self.tempdir) def test_unpack_tar_failure(self): @@ -151,11 +147,11 @@ def test_unpack_tar_failure(self): Test unpacking a *.tar with file containing .. path and expect exception """ - files = ['regular_file.txt', os.path.join('..', 'outside_file.txt')] - test_tar = self.make_tar_file('test_tar.tar', files) + files = ["regular_file.txt", os.path.join("..", "outside_file.txt")] + test_tar = self.make_tar_file("test_tar.tar", files) with pytest.raises(InstallationError) as e: untar_file(test_tar, self.tempdir) - assert 'trying to install outside target directory' in str(e.value) + assert "trying to install outside target directory" in str(e.value) def test_unpack_tar_success(self): """ @@ -164,26 +160,29 @@ def test_unpack_tar_success(self): so no exception raised """ files = [ - 'regular_file1.txt', - os.path.join('dir', 'dir_file1.txt'), - os.path.join('dir', '..', 'dir_file2.txt'), + "regular_file1.txt", + os.path.join("dir", "dir_file1.txt"), + os.path.join("dir", "..", "dir_file2.txt"), ] - test_tar = self.make_tar_file('test_tar.tar', files) + test_tar = self.make_tar_file("test_tar.tar", files) untar_file(test_tar, self.tempdir) -@pytest.mark.parametrize('args, expected', [ - # Test the second containing the first. - (('parent/sub', 'parent/'), False), - # Test the first not ending in a trailing slash. - (('parent', 'parent/foo'), True), - # Test target containing `..` but still inside the parent. - (('parent/', 'parent/foo/../bar'), True), - # Test target within the parent - (('parent/', 'parent/sub'), True), - # Test target outside parent - (('parent/', 'parent/../sub'), False), -]) +@pytest.mark.parametrize( + "args, expected", + [ + # Test the second containing the first. + (("parent/sub", "parent/"), False), + # Test the first not ending in a trailing slash. + (("parent", "parent/foo"), True), + # Test target containing `..` but still inside the parent. + (("parent/", "parent/foo/../bar"), True), + # Test target within the parent + (("parent/", "parent/sub"), True), + # Test target outside parent + (("parent/", "parent/../sub"), False), + ], +) def test_is_within_directory(args, expected): result = is_within_directory(*args) assert result == expected diff --git a/tests/unit/test_utils_virtualenv.py b/tests/unit/test_utils_virtualenv.py index 625539d7617..207c087a823 100644 --- a/tests/unit/test_utils_virtualenv.py +++ b/tests/unit/test_utils_virtualenv.py @@ -7,19 +7,21 @@ from pip._internal.utils import virtualenv -@pytest.mark.parametrize("real_prefix, base_prefix, expected", [ - (None, None, False), # Python 2 base interpreter - (None, sys.prefix, False), # Python 3 base interpreter - (None, "not_sys_prefix", True), # PEP405 venv - (sys.prefix, None, True), # Unknown case - (sys.prefix, sys.prefix, True), # Unknown case - (sys.prefix, "not_sys_prefix", True), # Unknown case - ("not_sys_prefix", None, True), # Python 2 virtualenv - ("not_sys_prefix", sys.prefix, True), # Python 3 virtualenv - ("not_sys_prefix", "not_sys_prefix", True), # Unknown case -]) -def test_running_under_virtualenv( - monkeypatch, real_prefix, base_prefix, expected): +@pytest.mark.parametrize( + "real_prefix, base_prefix, expected", + [ + (None, None, False), # Python 2 base interpreter + (None, sys.prefix, False), # Python 3 base interpreter + (None, "not_sys_prefix", True), # PEP405 venv + (sys.prefix, None, True), # Unknown case + (sys.prefix, sys.prefix, True), # Unknown case + (sys.prefix, "not_sys_prefix", True), # Unknown case + ("not_sys_prefix", None, True), # Python 2 virtualenv + ("not_sys_prefix", sys.prefix, True), # Python 3 virtualenv + ("not_sys_prefix", "not_sys_prefix", True), # Unknown case + ], +) +def test_running_under_virtualenv(monkeypatch, real_prefix, base_prefix, expected): # Use raising=False to prevent AttributeError on missing attribute if real_prefix is None: monkeypatch.delattr(sys, "real_prefix", raising=False) @@ -33,7 +35,8 @@ def test_running_under_virtualenv( @pytest.mark.parametrize( - "under_virtualenv, no_global_file, expected", [ + "under_virtualenv, no_global_file, expected", + [ (False, False, False), (False, True, False), (True, False, False), @@ -47,21 +50,23 @@ def test_virtualenv_no_global_with_regular_virtualenv( no_global_file, expected, ): - monkeypatch.setattr(virtualenv, '_running_under_venv', lambda: False) + monkeypatch.setattr(virtualenv, "_running_under_venv", lambda: False) - monkeypatch.setattr(site, '__file__', tmpdir / 'site.py') + monkeypatch.setattr(site, "__file__", tmpdir / "site.py") monkeypatch.setattr( - virtualenv, '_running_under_regular_virtualenv', + virtualenv, + "_running_under_regular_virtualenv", lambda: under_virtualenv, ) if no_global_file: - (tmpdir / 'no-global-site-packages.txt').touch() + (tmpdir / "no-global-site-packages.txt").touch() assert virtualenv.virtualenv_no_global() == expected @pytest.mark.parametrize( - "pyvenv_cfg_lines, under_venv, expected, expect_warning", [ + "pyvenv_cfg_lines, under_venv, expected, expect_warning", + [ (None, False, False, False), (None, True, True, True), # this has a warning. ( @@ -94,13 +99,9 @@ def test_virtualenv_no_global_with_pep_405_virtual_environment( expected, expect_warning, ): - monkeypatch.setattr( - virtualenv, '_running_under_regular_virtualenv', lambda: False - ) - monkeypatch.setattr( - virtualenv, '_get_pyvenv_cfg_lines', lambda: pyvenv_cfg_lines - ) - monkeypatch.setattr(virtualenv, '_running_under_venv', lambda: under_venv) + monkeypatch.setattr(virtualenv, "_running_under_regular_virtualenv", lambda: False) + monkeypatch.setattr(virtualenv, "_get_pyvenv_cfg_lines", lambda: pyvenv_cfg_lines) + monkeypatch.setattr(virtualenv, "_running_under_venv", lambda: under_venv) with caplog.at_level(logging.WARNING): assert virtualenv.virtualenv_no_global() == expected @@ -115,12 +116,13 @@ def test_virtualenv_no_global_with_pep_405_virtual_environment( @pytest.mark.parametrize( - "contents, expected", [ + "contents, expected", + [ (None, None), ("", []), ("a = b\nc = d\n", ["a = b", "c = d"]), ("a = b\nc = d", ["a = b", "c = d"]), # no trailing newlines - ] + ], ) def test_get_pyvenv_cfg_lines_for_pep_405_virtual_environment( monkeypatch, @@ -128,8 +130,8 @@ def test_get_pyvenv_cfg_lines_for_pep_405_virtual_environment( contents, expected, ): - monkeypatch.setattr(sys, 'prefix', str(tmpdir)) + monkeypatch.setattr(sys, "prefix", str(tmpdir)) if contents is not None: - tmpdir.joinpath('pyvenv.cfg').write_text(contents) + tmpdir.joinpath("pyvenv.cfg").write_text(contents) assert virtualenv._get_pyvenv_cfg_lines() == expected diff --git a/tests/unit/test_utils_wheel.py b/tests/unit/test_utils_wheel.py index cf8bd6dc3ed..e71b6edbf8e 100644 --- a/tests/unit/test_utils_wheel.py +++ b/tests/unit/test_utils_wheel.py @@ -73,9 +73,7 @@ def test_wheel_dist_info_dir_wrong_name(tmpdir, zip_dir): def test_wheel_version_ok(tmpdir, data): - assert wheel.wheel_version( - message_from_string("Wheel-Version: 1.9") - ) == (1, 9) + assert wheel.wheel_version(message_from_string("Wheel-Version: 1.9")) == (1, 9) def test_wheel_metadata_fails_missing_wheel(tmpdir, zip_dir): @@ -106,21 +104,22 @@ def test_wheel_version_fails_on_no_wheel_version(): assert "missing Wheel-Version" in str(e.value) -@pytest.mark.parametrize("version", [ - ("",), - ("1.b",), - ("1.",), -]) +@pytest.mark.parametrize( + "version", + [ + ("",), + ("1.b",), + ("1.",), + ], +) def test_wheel_version_fails_on_bad_wheel_version(version): with pytest.raises(UnsupportedWheel) as e: - wheel.wheel_version( - message_from_string("Wheel-Version: {}".format(version)) - ) + wheel.wheel_version(message_from_string("Wheel-Version: {}".format(version))) assert "invalid Wheel-Version" in str(e.value) def test_check_compatibility(): - name = 'test' + name = "test" vc = wheel.VERSION_COMPATIBLE # Major version is higher - should be incompatible @@ -129,7 +128,7 @@ def test_check_compatibility(): # test raises with correct error with pytest.raises(UnsupportedWheel) as e: wheel.check_compatibility(higher_v, name) - assert 'is not compatible' in str(e) + assert "is not compatible" in str(e) # Should only log.warning - minor version is greater higher_v = (vc[0], vc[1] + 1) diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py index b6ed86b6296..f98a5f25c25 100644 --- a/tests/unit/test_vcs.py +++ b/tests/unit/test_vcs.py @@ -15,60 +15,78 @@ from pip._internal.vcs.versioncontrol import RevOptions, VersionControl from tests.lib import is_svn_installed, need_svn, pyversion -if pyversion >= '3': +if pyversion >= "3": VERBOSE_FALSE = False else: VERBOSE_FALSE = 0 @pytest.mark.skipif( - 'TRAVIS' not in os.environ, - reason='Subversion is only required under Travis') + "TRAVIS" not in os.environ, reason="Subversion is only required under Travis" +) def test_ensure_svn_available(): """Make sure that svn is available when running in Travis.""" assert is_svn_installed() -@pytest.mark.parametrize('args, expected', [ - # Test without subdir. - (('git+https://example.com/pkg', 'dev', 'myproj'), - 'git+https://example.com/pkg@dev#egg=myproj'), - # Test with subdir. - (('git+https://example.com/pkg', 'dev', 'myproj', 'sub/dir'), - 'git+https://example.com/pkg@dev#egg=myproj&subdirectory=sub/dir'), - # Test with None subdir. - (('git+https://example.com/pkg', 'dev', 'myproj', None), - 'git+https://example.com/pkg@dev#egg=myproj'), - # Test an unescaped project name. - (('git+https://example.com/pkg', 'dev', 'zope-interface'), - 'git+https://example.com/pkg@dev#egg=zope_interface'), -]) +@pytest.mark.parametrize( + "args, expected", + [ + # Test without subdir. + ( + ("git+https://example.com/pkg", "dev", "myproj"), + "git+https://example.com/pkg@dev#egg=myproj", + ), + # Test with subdir. + ( + ("git+https://example.com/pkg", "dev", "myproj", "sub/dir"), + "git+https://example.com/pkg@dev#egg=myproj&subdirectory=sub/dir", + ), + # Test with None subdir. + ( + ("git+https://example.com/pkg", "dev", "myproj", None), + "git+https://example.com/pkg@dev#egg=myproj", + ), + # Test an unescaped project name. + ( + ("git+https://example.com/pkg", "dev", "zope-interface"), + "git+https://example.com/pkg@dev#egg=zope_interface", + ), + ], +) def test_make_vcs_requirement_url(args, expected): actual = make_vcs_requirement_url(*args) assert actual == expected def test_rev_options_repr(): - rev_options = RevOptions(Git, 'develop') + rev_options = RevOptions(Git, "develop") assert repr(rev_options) == "" -@pytest.mark.parametrize(('vc_class', 'expected1', 'expected2', 'kwargs'), [ - # First check VCS-specific RevOptions behavior. - (Bazaar, [], ['-r', '123'], {}), - (Git, ['HEAD'], ['123'], {}), - (Mercurial, [], ['123'], {}), - (Subversion, [], ['-r', '123'], {}), - # Test extra_args. For this, test using a single VersionControl class. - (Git, ['HEAD', 'opt1', 'opt2'], ['123', 'opt1', 'opt2'], - dict(extra_args=['opt1', 'opt2'])), -]) +@pytest.mark.parametrize( + ("vc_class", "expected1", "expected2", "kwargs"), + [ + # First check VCS-specific RevOptions behavior. + (Bazaar, [], ["-r", "123"], {}), + (Git, ["HEAD"], ["123"], {}), + (Mercurial, [], ["123"], {}), + (Subversion, [], ["-r", "123"], {}), + # Test extra_args. For this, test using a single VersionControl class. + ( + Git, + ["HEAD", "opt1", "opt2"], + ["123", "opt1", "opt2"], + dict(extra_args=["opt1", "opt2"]), + ), + ], +) def test_rev_options_to_args(vc_class, expected1, expected2, kwargs): """ Test RevOptions.to_args(). """ assert RevOptions(vc_class, **kwargs).to_args() == expected1 - assert RevOptions(vc_class, '123', **kwargs).to_args() == expected2 + assert RevOptions(vc_class, "123", **kwargs).to_args() == expected2 def test_rev_options_to_display(): @@ -78,10 +96,10 @@ def test_rev_options_to_display(): # The choice of VersionControl class doesn't matter here since # the implementation is the same for all of them. rev_options = RevOptions(Git) - assert rev_options.to_display() == '' + assert rev_options.to_display() == "" - rev_options = RevOptions(Git, 'master') - assert rev_options.to_display() == ' (to revision master)' + rev_options = RevOptions(Git, "master") + assert rev_options.to_display() == " (to revision master)" def test_rev_options_make_new(): @@ -90,87 +108,93 @@ def test_rev_options_make_new(): """ # The choice of VersionControl class doesn't matter here since # the implementation is the same for all of them. - rev_options = RevOptions(Git, 'master', extra_args=['foo', 'bar']) - new_options = rev_options.make_new('develop') + rev_options = RevOptions(Git, "master", extra_args=["foo", "bar"]) + new_options = rev_options.make_new("develop") assert new_options is not rev_options - assert new_options.extra_args == ['foo', 'bar'] - assert new_options.rev == 'develop' + assert new_options.extra_args == ["foo", "bar"] + assert new_options.rev == "develop" assert new_options.vc_class is Git -@pytest.mark.parametrize('sha, expected', [ - ((40 * 'a'), True), - ((40 * 'A'), True), - # Test a string containing all valid characters. - ((18 * 'a' + '0123456789abcdefABCDEF'), True), - ((40 * 'g'), False), - ((39 * 'a'), False), - ((41 * 'a'), False) -]) +@pytest.mark.parametrize( + "sha, expected", + [ + ((40 * "a"), True), + ((40 * "A"), True), + # Test a string containing all valid characters. + ((18 * "a" + "0123456789abcdefABCDEF"), True), + ((40 * "g"), False), + ((39 * "a"), False), + ((41 * "a"), False), + ], +) def test_looks_like_hash(sha, expected): assert looks_like_hash(sha) == expected -@pytest.mark.parametrize('vcs_cls, remote_url, expected', [ - # Git is one of the subclasses using the base class implementation. - (Git, 'git://example.com/MyProject', False), - (Git, 'http://example.com/MyProject', True), - # Subversion is the only subclass overriding the base class implementation. - (Subversion, 'svn://example.com/MyProject', True), -]) +@pytest.mark.parametrize( + "vcs_cls, remote_url, expected", + [ + # Git is one of the subclasses using the base class implementation. + (Git, "git://example.com/MyProject", False), + (Git, "http://example.com/MyProject", True), + # Subversion is the only subclass overriding the base class implementation. + (Subversion, "svn://example.com/MyProject", True), + ], +) def test_should_add_vcs_url_prefix(vcs_cls, remote_url, expected): actual = vcs_cls.should_add_vcs_url_prefix(remote_url) assert actual == expected -@patch('pip._internal.vcs.git.Git.get_remote_url') -@patch('pip._internal.vcs.git.Git.get_revision') -@patch('pip._internal.vcs.git.Git.get_subdirectory') +@patch("pip._internal.vcs.git.Git.get_remote_url") +@patch("pip._internal.vcs.git.Git.get_revision") +@patch("pip._internal.vcs.git.Git.get_subdirectory") @pytest.mark.network def test_git_get_src_requirements( mock_get_subdirectory, mock_get_revision, mock_get_remote_url ): - git_url = 'https://github.com/pypa/pip-test-package' - sha = '5547fa909e83df8bd743d3978d6667497983a4b7' + git_url = "https://github.com/pypa/pip-test-package" + sha = "5547fa909e83df8bd743d3978d6667497983a4b7" mock_get_remote_url.return_value = git_url mock_get_revision.return_value = sha mock_get_subdirectory.return_value = None - ret = Git.get_src_requirement('.', 'pip-test-package') + ret = Git.get_src_requirement(".", "pip-test-package") assert ret == ( - 'git+https://github.com/pypa/pip-test-package' - '@5547fa909e83df8bd743d3978d6667497983a4b7#egg=pip_test_package' + "git+https://github.com/pypa/pip-test-package" + "@5547fa909e83df8bd743d3978d6667497983a4b7#egg=pip_test_package" ) -@patch('pip._internal.vcs.git.Git.get_revision_sha') +@patch("pip._internal.vcs.git.Git.get_revision_sha") def test_git_resolve_revision_rev_exists(get_sha_mock): - get_sha_mock.return_value = ('123456', False) - url = 'git+https://git.example.com' - rev_options = Git.make_rev_options('develop') + get_sha_mock.return_value = ("123456", False) + url = "git+https://git.example.com" + rev_options = Git.make_rev_options("develop") - new_options = Git.resolve_revision('.', url, rev_options) - assert new_options.rev == '123456' + new_options = Git.resolve_revision(".", url, rev_options) + assert new_options.rev == "123456" -@patch('pip._internal.vcs.git.Git.get_revision_sha') +@patch("pip._internal.vcs.git.Git.get_revision_sha") def test_git_resolve_revision_rev_not_found(get_sha_mock): get_sha_mock.return_value = (None, False) - url = 'git+https://git.example.com' - rev_options = Git.make_rev_options('develop') + url = "git+https://git.example.com" + rev_options = Git.make_rev_options("develop") - new_options = Git.resolve_revision('.', url, rev_options) - assert new_options.rev == 'develop' + new_options = Git.resolve_revision(".", url, rev_options) + assert new_options.rev == "develop" -@patch('pip._internal.vcs.git.Git.get_revision_sha') +@patch("pip._internal.vcs.git.Git.get_revision_sha") def test_git_resolve_revision_not_found_warning(get_sha_mock, caplog): get_sha_mock.return_value = (None, False) - url = 'git+https://git.example.com' - sha = 40 * 'a' + url = "git+https://git.example.com" + sha = 40 * "a" rev_options = Git.make_rev_options(sha) # resolve_revision with a full sha would fail here because @@ -178,43 +202,48 @@ def test_git_resolve_revision_not_found_warning(get_sha_mock, caplog): # test_resolve_commit_not_on_branch. rev_options = Git.make_rev_options(sha[:6]) - new_options = Git.resolve_revision('.', url, rev_options) - assert new_options.rev == 'aaaaaa' + new_options = Git.resolve_revision(".", url, rev_options) + assert new_options.rev == "aaaaaa" # Check that a warning got logged only for the abbreviated hash. messages = [r.getMessage() for r in caplog.records] - messages = [msg for msg in messages if msg.startswith('Did not find ')] + messages = [msg for msg in messages if msg.startswith("Did not find ")] assert messages == [ "Did not find branch or tag 'aaaaaa', assuming revision or ref." ] -@pytest.mark.parametrize('rev_name,result', ( - ('5547fa909e83df8bd743d3978d6667497983a4b7', True), - ('5547fa909', False), - ('5678', False), - ('abc123', False), - ('foo', False), - (None, False), -)) -@patch('pip._internal.vcs.git.Git.get_revision') +@pytest.mark.parametrize( + "rev_name,result", + ( + ("5547fa909e83df8bd743d3978d6667497983a4b7", True), + ("5547fa909", False), + ("5678", False), + ("abc123", False), + ("foo", False), + (None, False), + ), +) +@patch("pip._internal.vcs.git.Git.get_revision") def test_git_is_commit_id_equal(mock_get_revision, rev_name, result): """ Test Git.is_commit_id_equal(). """ - mock_get_revision.return_value = '5547fa909e83df8bd743d3978d6667497983a4b7' - assert Git.is_commit_id_equal('/path', rev_name) is result + mock_get_revision.return_value = "5547fa909e83df8bd743d3978d6667497983a4b7" + assert Git.is_commit_id_equal("/path", rev_name) is result # The non-SVN backends all use the same get_netloc_and_auth(), so only test # Git as a representative. -@pytest.mark.parametrize('args, expected', [ - # Test a basic case. - (('example.com', 'https'), ('example.com', (None, None))), - # Test with username and password. - (('user:pass@example.com', 'https'), - ('user:pass@example.com', (None, None))), -]) +@pytest.mark.parametrize( + "args, expected", + [ + # Test a basic case. + (("example.com", "https"), ("example.com", (None, None))), + # Test with username and password. + (("user:pass@example.com", "https"), ("user:pass@example.com", (None, None))), + ], +) def test_git__get_netloc_and_auth(args, expected): """ Test VersionControl.get_netloc_and_auth(). @@ -224,20 +253,24 @@ def test_git__get_netloc_and_auth(args, expected): assert actual == expected -@pytest.mark.parametrize('args, expected', [ - # Test https. - (('example.com', 'https'), ('example.com', (None, None))), - # Test https with username and no password. - (('user@example.com', 'https'), ('example.com', ('user', None))), - # Test https with username and password. - (('user:pass@example.com', 'https'), ('example.com', ('user', 'pass'))), - # Test https with URL-encoded reserved characters. - (('user%3Aname:%23%40%5E@example.com', 'https'), - ('example.com', ('user:name', '#@^'))), - # Test ssh with username and password. - (('user:pass@example.com', 'ssh'), - ('user:pass@example.com', (None, None))), -]) +@pytest.mark.parametrize( + "args, expected", + [ + # Test https. + (("example.com", "https"), ("example.com", (None, None))), + # Test https with username and no password. + (("user@example.com", "https"), ("example.com", ("user", None))), + # Test https with username and password. + (("user:pass@example.com", "https"), ("example.com", ("user", "pass"))), + # Test https with URL-encoded reserved characters. + ( + ("user%3Aname:%23%40%5E@example.com", "https"), + ("example.com", ("user:name", "#@^")), + ), + # Test ssh with username and password. + (("user:pass@example.com", "ssh"), ("user:pass@example.com", (None, None))), + ], +) def test_subversion__get_netloc_and_auth(args, expected): """ Test Subversion.get_netloc_and_auth(). @@ -254,21 +287,28 @@ def test_git__get_url_rev__idempotent(): Also check that it doesn't change self.url. """ - url = 'git+git@git.example.com:MyProject#egg=MyProject' + url = "git+git@git.example.com:MyProject#egg=MyProject" result1 = Git.get_url_rev_and_auth(url) result2 = Git.get_url_rev_and_auth(url) - expected = ('git@git.example.com:MyProject', None, (None, None)) + expected = ("git@git.example.com:MyProject", None, (None, None)) assert result1 == expected assert result2 == expected -@pytest.mark.parametrize('url, expected', [ - ('svn+https://svn.example.com/MyProject', - ('https://svn.example.com/MyProject', None, (None, None))), - # Test a "+" in the path portion. - ('svn+https://svn.example.com/My+Project', - ('https://svn.example.com/My+Project', None, (None, None))), -]) +@pytest.mark.parametrize( + "url, expected", + [ + ( + "svn+https://svn.example.com/MyProject", + ("https://svn.example.com/MyProject", None, (None, None)), + ), + # Test a "+" in the path portion. + ( + "svn+https://svn.example.com/My+Project", + ("https://svn.example.com/My+Project", None, (None, None)), + ), + ], +) def test_version_control__get_url_rev_and_auth(url, expected): """ Test the basic case of VersionControl.get_url_rev_and_auth(). @@ -277,11 +317,14 @@ def test_version_control__get_url_rev_and_auth(url, expected): assert actual == expected -@pytest.mark.parametrize('url', [ - 'https://svn.example.com/MyProject', - # Test a URL containing a "+" (but not in the scheme). - 'https://svn.example.com/My+Project', -]) +@pytest.mark.parametrize( + "url", + [ + "https://svn.example.com/MyProject", + # Test a URL containing a "+" (but not in the scheme). + "https://svn.example.com/My+Project", + ], +) def test_version_control__get_url_rev_and_auth__missing_plus(url): """ Test passing a URL to VersionControl.get_url_rev_and_auth() with a "+" @@ -290,13 +333,16 @@ def test_version_control__get_url_rev_and_auth__missing_plus(url): with pytest.raises(ValueError) as excinfo: VersionControl.get_url_rev_and_auth(url) - assert 'malformed VCS url' in str(excinfo.value) + assert "malformed VCS url" in str(excinfo.value) -@pytest.mark.parametrize('url', [ - # Test a URL with revision part as empty. - 'git+https://github.com/MyUser/myProject.git@#egg=py_pkg', -]) +@pytest.mark.parametrize( + "url", + [ + # Test a URL with revision part as empty. + "git+https://github.com/MyUser/myProject.git@#egg=py_pkg", + ], +) def test_version_control__get_url_rev_and_auth__no_revision(url): """ Test passing a URL to VersionControl.get_url_rev_and_auth() with @@ -305,29 +351,41 @@ def test_version_control__get_url_rev_and_auth__no_revision(url): with pytest.raises(InstallationError) as excinfo: VersionControl.get_url_rev_and_auth(url) - assert 'an empty revision (after @)' in str(excinfo.value) - - -@pytest.mark.parametrize('url, expected', [ - # Test http. - ('bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject', - 'http://bzr.myproject.org/MyProject/trunk/'), - # Test https. - ('bzr+https://bzr.myproject.org/MyProject/trunk/#egg=MyProject', - 'https://bzr.myproject.org/MyProject/trunk/'), - # Test ftp. - ('bzr+ftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject', - 'ftp://bzr.myproject.org/MyProject/trunk/'), - # Test sftp. - ('bzr+sftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject', - 'sftp://bzr.myproject.org/MyProject/trunk/'), - # Test launchpad. - ('bzr+lp:MyLaunchpadProject#egg=MyLaunchpadProject', - 'lp:MyLaunchpadProject'), - # Test ssh (special handling). - ('bzr+ssh://bzr.myproject.org/MyProject/trunk/#egg=MyProject', - 'bzr+ssh://bzr.myproject.org/MyProject/trunk/'), -]) + assert "an empty revision (after @)" in str(excinfo.value) + + +@pytest.mark.parametrize( + "url, expected", + [ + # Test http. + ( + "bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject", + "http://bzr.myproject.org/MyProject/trunk/", + ), + # Test https. + ( + "bzr+https://bzr.myproject.org/MyProject/trunk/#egg=MyProject", + "https://bzr.myproject.org/MyProject/trunk/", + ), + # Test ftp. + ( + "bzr+ftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject", + "ftp://bzr.myproject.org/MyProject/trunk/", + ), + # Test sftp. + ( + "bzr+sftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject", + "sftp://bzr.myproject.org/MyProject/trunk/", + ), + # Test launchpad. + ("bzr+lp:MyLaunchpadProject#egg=MyLaunchpadProject", "lp:MyLaunchpadProject"), + # Test ssh (special handling). + ( + "bzr+ssh://bzr.myproject.org/MyProject/trunk/#egg=MyProject", + "bzr+ssh://bzr.myproject.org/MyProject/trunk/", + ), + ], +) def test_bazaar__get_url_rev_and_auth(url, expected): """ Test Bazaar.get_url_rev_and_auth(). @@ -336,20 +394,31 @@ def test_bazaar__get_url_rev_and_auth(url, expected): assert actual == (expected, None, (None, None)) -@pytest.mark.parametrize('url, expected', [ - # Test an https URL. - ('svn+https://svn.example.com/MyProject#egg=MyProject', - ('https://svn.example.com/MyProject', None, (None, None))), - # Test an https URL with a username and password. - ('svn+https://user:pass@svn.example.com/MyProject#egg=MyProject', - ('https://svn.example.com/MyProject', None, ('user', 'pass'))), - # Test an ssh URL. - ('svn+ssh://svn.example.com/MyProject#egg=MyProject', - ('svn+ssh://svn.example.com/MyProject', None, (None, None))), - # Test an ssh URL with a username. - ('svn+ssh://user@svn.example.com/MyProject#egg=MyProject', - ('svn+ssh://user@svn.example.com/MyProject', None, (None, None))), -]) +@pytest.mark.parametrize( + "url, expected", + [ + # Test an https URL. + ( + "svn+https://svn.example.com/MyProject#egg=MyProject", + ("https://svn.example.com/MyProject", None, (None, None)), + ), + # Test an https URL with a username and password. + ( + "svn+https://user:pass@svn.example.com/MyProject#egg=MyProject", + ("https://svn.example.com/MyProject", None, ("user", "pass")), + ), + # Test an ssh URL. + ( + "svn+ssh://svn.example.com/MyProject#egg=MyProject", + ("svn+ssh://svn.example.com/MyProject", None, (None, None)), + ), + # Test an ssh URL with a username. + ( + "svn+ssh://user@svn.example.com/MyProject#egg=MyProject", + ("svn+ssh://user@svn.example.com/MyProject", None, (None, None)), + ), + ], +) def test_subversion__get_url_rev_and_auth(url, expected): """ Test Subversion.get_url_rev_and_auth(). @@ -360,11 +429,14 @@ def test_subversion__get_url_rev_and_auth(url, expected): # The non-SVN backends all use the same make_rev_args(), so only test # Git as a representative. -@pytest.mark.parametrize('username, password, expected', [ - (None, None, []), - ('user', None, []), - ('user', hide_value('pass'), []), -]) +@pytest.mark.parametrize( + "username, password, expected", + [ + (None, None, []), + ("user", None, []), + ("user", hide_value("pass"), []), + ], +) def test_git__make_rev_args(username, password, expected): """ Test VersionControl.make_rev_args(). @@ -373,12 +445,18 @@ def test_git__make_rev_args(username, password, expected): assert actual == expected -@pytest.mark.parametrize('username, password, expected', [ - (None, None, []), - ('user', None, ['--username', 'user']), - ('user', hide_value('pass'), - ['--username', 'user', '--password', hide_value('pass')]), -]) +@pytest.mark.parametrize( + "username, password, expected", + [ + (None, None, []), + ("user", None, ["--username", "user"]), + ( + "user", + hide_value("pass"), + ["--username", "user", "--password", hide_value("pass")], + ), + ], +) def test_subversion__make_rev_args(username, password, expected): """ Test Subversion.make_rev_args(). @@ -391,34 +469,36 @@ def test_subversion__get_url_rev_options(): """ Test Subversion.get_url_rev_options(). """ - secret_url = ( - 'svn+https://user:pass@svn.example.com/MyProject@v1.0#egg=MyProject' - ) + secret_url = "svn+https://user:pass@svn.example.com/MyProject@v1.0#egg=MyProject" hidden_url = hide_url(secret_url) url, rev_options = Subversion().get_url_rev_options(hidden_url) - assert url == hide_url('https://svn.example.com/MyProject') - assert rev_options.rev == 'v1.0' + assert url == hide_url("https://svn.example.com/MyProject") + assert rev_options.rev == "v1.0" assert rev_options.extra_args == ( - ['--username', 'user', '--password', hide_value('pass')] + ["--username", "user", "--password", hide_value("pass")] ) def test_get_git_version(): git_version = Git().get_git_version() - assert git_version >= parse_version('1.0.0') - - -@pytest.mark.parametrize('use_interactive,is_atty,expected', [ - (None, False, False), - (None, True, True), - (False, False, False), - (False, True, False), - (True, False, True), - (True, True, True), -]) -@patch('sys.stdin.isatty') + assert git_version >= parse_version("1.0.0") + + +@pytest.mark.parametrize( + "use_interactive,is_atty,expected", + [ + (None, False, False), + (None, True, True), + (False, False, False), + (False, True, False), + (True, False, True), + (True, True, True), + ], +) +@patch("sys.stdin.isatty") def test_subversion__init_use_interactive( - mock_isatty, use_interactive, is_atty, expected): + mock_isatty, use_interactive, is_atty, expected +): """ Test Subversion.__init__() with mocked sys.stdin.isatty() output. """ @@ -440,25 +520,33 @@ def test_subversion__call_vcs_version(): assert version[0] >= 1 -@pytest.mark.parametrize('svn_output, expected_version', [ - ('svn, version 1.10.3 (r1842928)\n' - ' compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0', - (1, 10, 3)), - ('svn, version 1.12.0-SlikSvn (SlikSvn/1.12.0)\n' - ' compiled May 28 2019, 13:44:56 on x86_64-microsoft-windows6.2', - (1, 12, 0)), - ('svn, version 1.9.7 (r1800392)', (1, 9, 7)), - ('svn, version 1.9.7a1 (r1800392)', ()), - ('svn, version 1.9 (r1800392)', (1, 9)), - ('svn, version .9.7 (r1800392)', ()), - ('svn version 1.9.7 (r1800392)', ()), - ('svn 1.9.7', ()), - ('svn, version . .', ()), - ('', ()), -]) -@patch('pip._internal.vcs.subversion.Subversion.run_command') +@pytest.mark.parametrize( + "svn_output, expected_version", + [ + ( + "svn, version 1.10.3 (r1842928)\n" + " compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0", + (1, 10, 3), + ), + ( + "svn, version 1.12.0-SlikSvn (SlikSvn/1.12.0)\n" + " compiled May 28 2019, 13:44:56 on x86_64-microsoft-windows6.2", + (1, 12, 0), + ), + ("svn, version 1.9.7 (r1800392)", (1, 9, 7)), + ("svn, version 1.9.7a1 (r1800392)", ()), + ("svn, version 1.9 (r1800392)", (1, 9)), + ("svn, version .9.7 (r1800392)", ()), + ("svn version 1.9.7 (r1800392)", ()), + ("svn 1.9.7", ()), + ("svn, version . .", ()), + ("", ()), + ], +) +@patch("pip._internal.vcs.subversion.Subversion.run_command") def test_subversion__call_vcs_version_patched( - mock_run_command, svn_output, expected_version): + mock_run_command, svn_output, expected_version +): """ Test Subversion.call_vcs_version() against patched output. """ @@ -467,7 +555,7 @@ def test_subversion__call_vcs_version_patched( assert version == expected_version -@patch('pip._internal.vcs.subversion.Subversion.run_command') +@patch("pip._internal.vcs.subversion.Subversion.run_command") def test_subversion__call_vcs_version_svn_not_installed(mock_run_command): """ Test Subversion.call_vcs_version() when svn is not installed. @@ -477,12 +565,15 @@ def test_subversion__call_vcs_version_svn_not_installed(mock_run_command): Subversion().call_vcs_version() -@pytest.mark.parametrize('version', [ - (), - (1,), - (1, 8), - (1, 8, 0), -]) +@pytest.mark.parametrize( + "version", + [ + (), + (1,), + (1, 8), + (1, 8, 0), + ], +) def test_subversion__get_vcs_version_cached(version): """ Test Subversion.get_vcs_version() with previously cached result. @@ -492,12 +583,15 @@ def test_subversion__get_vcs_version_cached(version): assert svn.get_vcs_version() == version -@pytest.mark.parametrize('vcs_version', [ - (), - (1, 7), - (1, 8, 0), -]) -@patch('pip._internal.vcs.subversion.Subversion.call_vcs_version') +@pytest.mark.parametrize( + "vcs_version", + [ + (), + (1, 7), + (1, 8, 0), + ], +) +@patch("pip._internal.vcs.subversion.Subversion.call_vcs_version") def test_subversion__get_vcs_version_call_vcs(mock_call_vcs, vcs_version): """ Test Subversion.get_vcs_version() with mocked output from @@ -511,16 +605,20 @@ def test_subversion__get_vcs_version_call_vcs(mock_call_vcs, vcs_version): assert svn._vcs_version == vcs_version -@pytest.mark.parametrize('use_interactive,vcs_version,expected_options', [ - (False, (), ['--non-interactive']), - (False, (1, 7, 0), ['--non-interactive']), - (False, (1, 8, 0), ['--non-interactive']), - (True, (), []), - (True, (1, 7, 0), []), - (True, (1, 8, 0), ['--force-interactive']), -]) +@pytest.mark.parametrize( + "use_interactive,vcs_version,expected_options", + [ + (False, (), ["--non-interactive"]), + (False, (1, 7, 0), ["--non-interactive"]), + (False, (1, 8, 0), ["--non-interactive"]), + (True, (), []), + (True, (1, 7, 0), []), + (True, (1, 8, 0), ["--force-interactive"]), + ], +) def test_subversion__get_remote_call_options( - use_interactive, vcs_version, expected_options): + use_interactive, vcs_version, expected_options +): """ Test Subversion.get_remote_call_options(). """ @@ -531,64 +629,102 @@ def test_subversion__get_remote_call_options( class TestSubversionArgs(TestCase): def setUp(self): - patcher = patch('pip._internal.vcs.versioncontrol.call_subprocess') + patcher = patch("pip._internal.vcs.versioncontrol.call_subprocess") self.addCleanup(patcher.stop) self.call_subprocess_mock = patcher.start() # Test Data. - self.url = 'svn+http://username:password@svn.example.com/' + self.url = "svn+http://username:password@svn.example.com/" # use_interactive is set to False to test that remote call options are # properly added. self.svn = Subversion(use_interactive=False) self.rev_options = RevOptions(Subversion) - self.dest = '/tmp/test' + self.dest = "/tmp/test" def assert_call_args(self, args): assert self.call_subprocess_mock.call_args[0][0] == args def test_obtain(self): self.svn.obtain(self.dest, hide_url(self.url)) - self.assert_call_args([ - 'svn', 'checkout', '-q', '--non-interactive', '--username', - 'username', '--password', hide_value('password'), - hide_url('http://svn.example.com/'), '/tmp/test', - ]) + self.assert_call_args( + [ + "svn", + "checkout", + "-q", + "--non-interactive", + "--username", + "username", + "--password", + hide_value("password"), + hide_url("http://svn.example.com/"), + "/tmp/test", + ] + ) def test_export(self): self.svn.export(self.dest, hide_url(self.url)) - self.assert_call_args([ - 'svn', 'export', '--non-interactive', '--username', 'username', - '--password', hide_value('password'), - hide_url('http://svn.example.com/'), '/tmp/test', - ]) + self.assert_call_args( + [ + "svn", + "export", + "--non-interactive", + "--username", + "username", + "--password", + hide_value("password"), + hide_url("http://svn.example.com/"), + "/tmp/test", + ] + ) def test_fetch_new(self): self.svn.fetch_new(self.dest, hide_url(self.url), self.rev_options) - self.assert_call_args([ - 'svn', 'checkout', '-q', '--non-interactive', - hide_url('svn+http://username:password@svn.example.com/'), - '/tmp/test', - ]) + self.assert_call_args( + [ + "svn", + "checkout", + "-q", + "--non-interactive", + hide_url("svn+http://username:password@svn.example.com/"), + "/tmp/test", + ] + ) def test_fetch_new_revision(self): - rev_options = RevOptions(Subversion, '123') + rev_options = RevOptions(Subversion, "123") self.svn.fetch_new(self.dest, hide_url(self.url), rev_options) - self.assert_call_args([ - 'svn', 'checkout', '-q', '--non-interactive', '-r', '123', - hide_url('svn+http://username:password@svn.example.com/'), - '/tmp/test', - ]) + self.assert_call_args( + [ + "svn", + "checkout", + "-q", + "--non-interactive", + "-r", + "123", + hide_url("svn+http://username:password@svn.example.com/"), + "/tmp/test", + ] + ) def test_switch(self): self.svn.switch(self.dest, hide_url(self.url), self.rev_options) - self.assert_call_args([ - 'svn', 'switch', '--non-interactive', - hide_url('svn+http://username:password@svn.example.com/'), - '/tmp/test', - ]) + self.assert_call_args( + [ + "svn", + "switch", + "--non-interactive", + hide_url("svn+http://username:password@svn.example.com/"), + "/tmp/test", + ] + ) def test_update(self): self.svn.update(self.dest, hide_url(self.url), self.rev_options) - self.assert_call_args([ - 'svn', 'update', '--non-interactive', '/tmp/test', - ]) + self.assert_call_args( + [ + "svn", + "update", + "--non-interactive", + "/tmp/test", + ] + ) diff --git a/tests/unit/test_vcs_mercurial.py b/tests/unit/test_vcs_mercurial.py index 630619b8236..6554d8fc701 100644 --- a/tests/unit/test_vcs_mercurial.py +++ b/tests/unit/test_vcs_mercurial.py @@ -15,19 +15,19 @@ def test_mercurial_switch_updates_config_file_when_found(tmpdir): hg = Mercurial() options = hg.make_rev_options() - hg_dir = os.path.join(tmpdir, '.hg') + hg_dir = os.path.join(tmpdir, ".hg") os.mkdir(hg_dir) config = configparser.RawConfigParser() - config.add_section('paths') - config.set('paths', 'default', 'old_url') + config.add_section("paths") + config.set("paths", "default", "old_url") - hgrc_path = os.path.join(hg_dir, 'hgrc') - with open(hgrc_path, 'w') as f: + hgrc_path = os.path.join(hg_dir, "hgrc") + with open(hgrc_path, "w") as f: config.write(f) - hg.switch(tmpdir, hide_url('new_url'), options) + hg.switch(tmpdir, hide_url("new_url"), options) config.read(hgrc_path) - default_path = config.get('paths', 'default') - assert default_path == 'new_url' + default_path = config.get("paths", "default") + assert default_path == "new_url" diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py index 6c9fe02b32e..463aebdd7be 100644 --- a/tests/unit/test_wheel.py +++ b/tests/unit/test_wheel.py @@ -19,9 +19,7 @@ DirectUrl, ) from pip._internal.models.scheme import Scheme -from pip._internal.operations.build.wheel_legacy import ( - get_legacy_build_wheel_path, -) +from pip._internal.operations.build.wheel_legacy import get_legacy_build_wheel_path from pip._internal.operations.install import wheel from pip._internal.utils.compat import WINDOWS from pip._internal.utils.misc import hash_file @@ -34,17 +32,17 @@ def call_get_legacy_build_wheel_path(caplog, names): wheel_path = get_legacy_build_wheel_path( names=names, - temp_dir='/tmp/abcd', - name='pendulum', - command_args=['arg1', 'arg2'], - command_output='output line 1\noutput line 2\n', + temp_dir="/tmp/abcd", + name="pendulum", + command_args=["arg1", "arg2"], + command_output="output line 1\noutput line 2\n", ) return wheel_path def test_get_legacy_build_wheel_path(caplog): - actual = call_get_legacy_build_wheel_path(caplog, names=['name']) - assert_paths_equal(actual, '/tmp/abcd/name') + actual = call_get_legacy_build_wheel_path(caplog, names=["name"]) + assert_paths_equal(actual, "/tmp/abcd/name") assert not caplog.records @@ -54,11 +52,11 @@ def test_get_legacy_build_wheel_path__no_names(caplog): assert actual is None assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'WARNING' + assert record.levelname == "WARNING" assert record.message.splitlines() == [ "Legacy build of wheel for 'pendulum' created no files.", "Command arguments: arg1 arg2", - 'Command output: [use --verbose to show]', + "Command output: [use --verbose to show]", ] @@ -66,17 +64,18 @@ def test_get_legacy_build_wheel_path__multiple_names(caplog): caplog.set_level(logging.INFO) # Deliberately pass the names in non-sorted order. actual = call_get_legacy_build_wheel_path( - caplog, names=['name2', 'name1'], + caplog, + names=["name2", "name1"], ) - assert_paths_equal(actual, '/tmp/abcd/name1') + assert_paths_equal(actual, "/tmp/abcd/name1") assert len(caplog.records) == 1 record = caplog.records[0] - assert record.levelname == 'WARNING' + assert record.levelname == "WARNING" assert record.message.splitlines() == [ "Legacy build of wheel for 'pendulum' created more than one file.", "Filenames (choosing first): ['name1', 'name2']", "Command arguments: arg1 arg2", - 'Command output: [use --verbose to show]', + "Command output: [use --verbose to show]", ] @@ -95,7 +94,9 @@ def test_get_entrypoints(console_scripts): [section] common:one = module:func common:two = module:other_func - """.format(console_scripts) + """.format( + console_scripts + ) wheel_zip = make_wheel( "simple", @@ -109,7 +110,7 @@ def test_get_entrypoints(console_scripts): ) assert wheel.get_entrypoints(distribution) == ( - dict([console_scripts.split(' = ')]), + dict([console_scripts.split(" = ")]), {}, ) @@ -125,67 +126,84 @@ def test_get_entrypoints_no_entrypoints(): assert gui == {} -@pytest.mark.parametrize("outrows, expected", [ - ([ - (u'', '', 'a'), - (u'', '', ''), - ], [ - ('', '', ''), - ('', '', 'a'), - ]), - ([ - # Include an int to check avoiding the following error: - # > TypeError: '<' not supported between instances of 'str' and 'int' - (u'', '', 1), - (u'', '', ''), - ], [ - ('', '', ''), - ('', '', '1'), - ]), - ([ - # Test the normalization correctly encode everything for csv.writer(). - (u'😉', '', 1), - (u'', '', ''), - ], [ - ('', '', ''), - ('😉', '', '1'), - ]), -]) +@pytest.mark.parametrize( + "outrows, expected", + [ + ( + [ + (u"", "", "a"), + (u"", "", ""), + ], + [ + ("", "", ""), + ("", "", "a"), + ], + ), + ( + [ + # Include an int to check avoiding the following error: + # > TypeError: '<' not supported between instances of 'str' and 'int' + (u"", "", 1), + (u"", "", ""), + ], + [ + ("", "", ""), + ("", "", "1"), + ], + ), + ( + [ + # Test the normalization correctly encode everything for csv.writer(). + (u"😉", "", 1), + (u"", "", ""), + ], + [ + ("", "", ""), + ("😉", "", "1"), + ], + ), + ], +) def test_normalized_outrows(outrows, expected): actual = wheel._normalized_outrows(outrows) assert actual == expected def call_get_csv_rows_for_installed(tmpdir, text): - path = tmpdir.joinpath('temp.txt') + path = tmpdir.joinpath("temp.txt") path.write_text(text) # Test that an installed file appearing in RECORD has its filename # updated in the new RECORD file. - installed = {u'a': 'z'} + installed = {u"a": "z"} changed = set() generated = [] - lib_dir = '/lib/dir' + lib_dir = "/lib/dir" - with open(path, **wheel.csv_io_kwargs('r')) as f: + with open(path, **wheel.csv_io_kwargs("r")) as f: record_rows = list(csv.reader(f)) outrows = wheel.get_csv_rows_for_installed( - record_rows, installed=installed, changed=changed, - generated=generated, lib_dir=lib_dir, + record_rows, + installed=installed, + changed=changed, + generated=generated, + lib_dir=lib_dir, ) return outrows def test_get_csv_rows_for_installed(tmpdir, caplog): - text = textwrap.dedent("""\ + text = textwrap.dedent( + """\ a,b,c d,e,f - """) + """ + ) outrows = call_get_csv_rows_for_installed(tmpdir, text) expected = [ - ('z', 'b', 'c'), - ('d', 'e', 'f'), + ("z", "b", "c"), + ("d", "e", "f"), ] assert outrows == expected # Check there were no warnings. @@ -193,47 +211,50 @@ def test_get_csv_rows_for_installed(tmpdir, caplog): def test_get_csv_rows_for_installed__long_lines(tmpdir, caplog): - text = textwrap.dedent("""\ + text = textwrap.dedent( + """\ a,b,c,d e,f,g h,i,j,k - """) + """ + ) outrows = call_get_csv_rows_for_installed(tmpdir, text) expected = [ - ('z', 'b', 'c'), - ('e', 'f', 'g'), - ('h', 'i', 'j'), + ("z", "b", "c"), + ("e", "f", "g"), + ("h", "i", "j"), ] assert outrows == expected messages = [rec.message for rec in caplog.records] expected = [ "RECORD line has more than three elements: ['a', 'b', 'c', 'd']", - "RECORD line has more than three elements: ['h', 'i', 'j', 'k']" + "RECORD line has more than three elements: ['h', 'i', 'j', 'k']", ] assert messages == expected -@pytest.mark.parametrize("text,expected", [ - ("Root-Is-Purelib: true", True), - ("Root-Is-Purelib: false", False), - ("Root-Is-Purelib: hello", False), - ("", False), - ("root-is-purelib: true", True), - ("root-is-purelib: True", True), -]) +@pytest.mark.parametrize( + "text,expected", + [ + ("Root-Is-Purelib: true", True), + ("Root-Is-Purelib: false", False), + ("Root-Is-Purelib: hello", False), + ("", False), + ("root-is-purelib: true", True), + ("root-is-purelib: True", True), + ], +) def test_wheel_root_is_purelib(text, expected): assert wheel.wheel_root_is_purelib(message_from_string(text)) == expected class TestWheelFile(object): - def test_unpack_wheel_no_flatten(self, tmpdir): - filepath = os.path.join(DATA_DIR, 'packages', - 'meta-1.0-py2.py3-none-any.whl') + filepath = os.path.join(DATA_DIR, "packages", "meta-1.0-py2.py3-none-any.whl") unpack_file(filepath, tmpdir) - assert os.path.isdir(os.path.join(tmpdir, 'meta-1.0.dist-info')) + assert os.path.isdir(os.path.join(tmpdir, "meta-1.0.dist-info")) class TestInstallUnpackedWheel(object): @@ -247,7 +268,7 @@ def prep(self, data, tmpdir): # `compileall.compile_file`) can cause failures, so we normalize it # to a string here. tmpdir = str(tmpdir) - self.name = 'sample' + self.name = "sample" self.wheelpath = make_wheel( "sample", "1.2.0", @@ -294,20 +315,20 @@ def main(): "gui_scripts": ["sample2 = sample:main"], }, ).save_to_dir(tmpdir) - self.req = Requirement('sample') - self.src = os.path.join(tmpdir, 'src') - self.dest = os.path.join(tmpdir, 'dest') + self.req = Requirement("sample") + self.src = os.path.join(tmpdir, "src") + self.dest = os.path.join(tmpdir, "dest") self.scheme = Scheme( - purelib=os.path.join(self.dest, 'lib'), - platlib=os.path.join(self.dest, 'lib'), - headers=os.path.join(self.dest, 'headers'), - scripts=os.path.join(self.dest, 'bin'), - data=os.path.join(self.dest, 'data'), + purelib=os.path.join(self.dest, "lib"), + platlib=os.path.join(self.dest, "lib"), + headers=os.path.join(self.dest, "headers"), + scripts=os.path.join(self.dest, "bin"), + data=os.path.join(self.dest, "data"), ) - self.src_dist_info = os.path.join( - self.src, 'sample-1.2.0.dist-info') + self.src_dist_info = os.path.join(self.src, "sample-1.2.0.dist-info") self.dest_dist_info = os.path.join( - self.scheme.purelib, 'sample-1.2.0.dist-info') + self.scheme.purelib, "sample-1.2.0.dist-info" + ) def assert_permission(self, path, mode): target_mode = os.stat(path).st_mode & 0o777 @@ -315,19 +336,17 @@ def assert_permission(self, path, mode): def assert_installed(self, expected_permission): # lib - assert os.path.isdir( - os.path.join(self.scheme.purelib, 'sample')) + assert os.path.isdir(os.path.join(self.scheme.purelib, "sample")) # dist-info - metadata = os.path.join(self.dest_dist_info, 'METADATA') + metadata = os.path.join(self.dest_dist_info, "METADATA") self.assert_permission(metadata, expected_permission) - record = os.path.join(self.dest_dist_info, 'RECORD') + record = os.path.join(self.dest_dist_info, "RECORD") self.assert_permission(record, expected_permission) # data files - data_file = os.path.join(self.scheme.data, 'my_data', 'data_file') + data_file = os.path.join(self.scheme.data, "my_data", "data_file") assert os.path.isfile(data_file) # package data - pkg_data = os.path.join( - self.scheme.purelib, 'sample', 'package_data.dat') + pkg_data = os.path.join(self.scheme.purelib, "sample", "package_data.dat") assert os.path.isfile(pkg_data) def test_std_install(self, data, tmpdir): @@ -340,11 +359,10 @@ def test_std_install(self, data, tmpdir): ) self.assert_installed(0o644) - @pytest.mark.parametrize("user_mask, expected_permission", [ - (0o27, 0o640) - ]) - def test_std_install_with_custom_umask(self, data, tmpdir, - user_mask, expected_permission): + @pytest.mark.parametrize("user_mask, expected_permission", [(0o27, 0o640)]) + def test_std_install_with_custom_umask( + self, data, tmpdir, user_mask, expected_permission + ): """Test that the files created after install honor the permissions set when the user sets a custom umask""" @@ -371,7 +389,7 @@ def test_std_install_requested(self, data, tmpdir): requested=True, ) self.assert_installed(0o644) - requested_path = os.path.join(self.dest_dist_info, 'REQUESTED') + requested_path = os.path.join(self.dest_dist_info, "REQUESTED") assert os.path.isfile(requested_path) def test_std_install_with_direct_url(self, data, tmpdir): @@ -393,11 +411,9 @@ def test_std_install_with_direct_url(self, data, tmpdir): req_description=str(self.req), direct_url=direct_url, ) - direct_url_path = os.path.join( - self.dest_dist_info, DIRECT_URL_METADATA_NAME - ) + direct_url_path = os.path.join(self.dest_dist_info, DIRECT_URL_METADATA_NAME) self.assert_permission(direct_url_path, 0o644) - with open(direct_url_path, 'rb') as f: + with open(direct_url_path, "rb") as f: expected_direct_url_json = direct_url.to_json() direct_url_json = f.read().decode("utf-8") assert direct_url_json == expected_direct_url_json @@ -406,7 +422,7 @@ def test_std_install_with_direct_url(self, data, tmpdir): assert DIRECT_URL_METADATA_NAME in f.read() def test_install_prefix(self, data, tmpdir): - prefix = os.path.join(os.path.sep, 'some', 'path') + prefix = os.path.join(os.path.sep, "some", "path") self.prep(data, tmpdir) scheme = get_scheme( self.name, @@ -423,9 +439,9 @@ def test_install_prefix(self, data, tmpdir): req_description=str(self.req), ) - bin_dir = 'Scripts' if WINDOWS else 'bin' - assert os.path.exists(os.path.join(tmpdir, 'some', 'path', bin_dir)) - assert os.path.exists(os.path.join(tmpdir, 'some', 'path', 'my_data')) + bin_dir = "Scripts" if WINDOWS else "bin" + assert os.path.exists(os.path.join(tmpdir, "some", "path", bin_dir)) + assert os.path.exists(os.path.join(tmpdir, "some", "path", "my_data")) def test_dist_info_contains_empty_dir(self, data, tmpdir): """ @@ -440,13 +456,9 @@ def test_dist_info_contains_empty_dir(self, data, tmpdir): req_description=str(self.req), ) self.assert_installed(0o644) - assert not os.path.isdir( - os.path.join(self.dest_dist_info, 'empty_dir')) + assert not os.path.isdir(os.path.join(self.dest_dist_info, "empty_dir")) - @pytest.mark.parametrize( - "path", - ["/tmp/example", "../example", "./../example"] - ) + @pytest.mark.parametrize("path", ["/tmp/example", "../example", "./../example"]) def test_wheel_install_rejects_bad_paths(self, data, tmpdir, path): self.prep(data, tmpdir) wheel_path = make_wheel( @@ -465,15 +477,9 @@ def test_wheel_install_rejects_bad_paths(self, data, tmpdir, path): assert "example" in exc_text @pytest.mark.xfail(strict=True) - @pytest.mark.parametrize( - "entrypoint", ["hello = hello", "hello = hello:"] - ) - @pytest.mark.parametrize( - "entrypoint_type", ["console_scripts", "gui_scripts"] - ) - def test_invalid_entrypoints_fail( - self, data, tmpdir, entrypoint, entrypoint_type - ): + @pytest.mark.parametrize("entrypoint", ["hello = hello", "hello = hello:"]) + @pytest.mark.parametrize("entrypoint_type", ["console_scripts", "gui_scripts"]) + def test_invalid_entrypoints_fail(self, data, tmpdir, entrypoint, entrypoint_type): self.prep(data, tmpdir) wheel_path = make_wheel( "simple", "0.1.0", entry_points={entrypoint_type: [entrypoint]} @@ -499,21 +505,15 @@ class TestMessageAboutScriptsNotOnPATH(object): ) def _template(self, paths, scripts): - with patch.dict('os.environ', {'PATH': os.pathsep.join(paths)}): + with patch.dict("os.environ", {"PATH": os.pathsep.join(paths)}): return wheel.message_about_scripts_not_on_PATH(scripts) def test_no_script(self): - retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=[] - ) + retval = self._template(paths=["/a/b", "/c/d/bin"], scripts=[]) assert retval is None def test_single_script__single_dir_not_on_PATH(self): - retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=['/c/d/foo'] - ) + retval = self._template(paths=["/a/b", "/c/d/bin"], scripts=["/c/d/foo"]) assert retval is not None assert "--no-warn-script-location" in retval assert "foo is installed in '/c/d'" in retval @@ -521,8 +521,7 @@ def test_single_script__single_dir_not_on_PATH(self): def test_two_script__single_dir_not_on_PATH(self): retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=['/c/d/foo', '/c/d/baz'] + paths=["/a/b", "/c/d/bin"], scripts=["/c/d/foo", "/c/d/baz"] ) assert retval is not None assert "--no-warn-script-location" in retval @@ -531,8 +530,8 @@ def test_two_script__single_dir_not_on_PATH(self): def test_multi_script__multi_dir_not_on_PATH(self): retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=['/c/d/foo', '/c/d/bar', '/c/d/baz', '/a/b/c/spam'] + paths=["/a/b", "/c/d/bin"], + scripts=["/c/d/foo", "/c/d/bar", "/c/d/baz", "/a/b/c/spam"], ) assert retval is not None assert "--no-warn-script-location" in retval @@ -542,11 +541,8 @@ def test_multi_script__multi_dir_not_on_PATH(self): def test_multi_script_all__multi_dir_not_on_PATH(self): retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=[ - '/c/d/foo', '/c/d/bar', '/c/d/baz', - '/a/b/c/spam', '/a/b/c/eggs' - ] + paths=["/a/b", "/c/d/bin"], + scripts=["/c/d/foo", "/c/d/bar", "/c/d/baz", "/a/b/c/spam", "/a/b/c/eggs"], ) assert retval is not None assert "--no-warn-script-location" in retval @@ -556,37 +552,29 @@ def test_multi_script_all__multi_dir_not_on_PATH(self): def test_two_script__single_dir_on_PATH(self): retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=['/a/b/foo', '/a/b/baz'] + paths=["/a/b", "/c/d/bin"], scripts=["/a/b/foo", "/a/b/baz"] ) assert retval is None def test_multi_script__multi_dir_on_PATH(self): retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=['/a/b/foo', '/a/b/bar', '/a/b/baz', '/c/d/bin/spam'] + paths=["/a/b", "/c/d/bin"], + scripts=["/a/b/foo", "/a/b/bar", "/a/b/baz", "/c/d/bin/spam"], ) assert retval is None def test_multi_script__single_dir_on_PATH(self): retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=['/a/b/foo', '/a/b/bar', '/a/b/baz'] + paths=["/a/b", "/c/d/bin"], scripts=["/a/b/foo", "/a/b/bar", "/a/b/baz"] ) assert retval is None def test_single_script__single_dir_on_PATH(self): - retval = self._template( - paths=['/a/b', '/c/d/bin'], - scripts=['/a/b/foo'] - ) + retval = self._template(paths=["/a/b", "/c/d/bin"], scripts=["/a/b/foo"]) assert retval is None def test_PATH_check_case_insensitive_on_windows(self): - retval = self._template( - paths=['C:\\A\\b'], - scripts=['c:\\a\\b\\c', 'C:/A/b/d'] - ) + retval = self._template(paths=["C:\\A\\b"], scripts=["c:\\a\\b\\c", "C:/A/b/d"]) if WINDOWS: assert retval is None else: @@ -595,36 +583,36 @@ def test_PATH_check_case_insensitive_on_windows(self): def test_trailing_ossep_removal(self): retval = self._template( - paths=[os.path.join('a', 'b', '')], - scripts=[os.path.join('a', 'b', 'c')] + paths=[os.path.join("a", "b", "")], scripts=[os.path.join("a", "b", "c")] ) assert retval is None def test_missing_PATH_env_treated_as_empty_PATH_env(self, monkeypatch): - scripts = ['a/b/foo'] + scripts = ["a/b/foo"] - monkeypatch.delenv('PATH') + monkeypatch.delenv("PATH") retval_missing = wheel.message_about_scripts_not_on_PATH(scripts) - monkeypatch.setenv('PATH', '') + monkeypatch.setenv("PATH", "") retval_empty = wheel.message_about_scripts_not_on_PATH(scripts) assert retval_missing == retval_empty def test_no_script_tilde_in_path(self): - retval = self._template( - paths=['/a/b', '/c/d/bin', '~/e', '/f/g~g'], - scripts=[] - ) + retval = self._template(paths=["/a/b", "/c/d/bin", "~/e", "/f/g~g"], scripts=[]) assert retval is None def test_multi_script_all_tilde__multi_dir_not_on_PATH(self): retval = self._template( - paths=['/a/b', '/c/d/bin', '~e/f'], + paths=["/a/b", "/c/d/bin", "~e/f"], scripts=[ - '/c/d/foo', '/c/d/bar', '/c/d/baz', - '/a/b/c/spam', '/a/b/c/eggs', '/e/f/tilde' - ] + "/c/d/foo", + "/c/d/bar", + "/c/d/baz", + "/a/b/c/spam", + "/a/b/c/eggs", + "/e/f/tilde", + ], ) assert retval is not None assert "--no-warn-script-location" in retval @@ -635,11 +623,14 @@ def test_multi_script_all_tilde__multi_dir_not_on_PATH(self): def test_multi_script_all_tilde_not_at_start__multi_dir_not_on_PATH(self): retval = self._template( - paths=['/e/f~f', '/c/d/bin'], + paths=["/e/f~f", "/c/d/bin"], scripts=[ - '/c/d/foo', '/c/d/bar', '/c/d/baz', - '/e/f~f/c/spam', '/e/f~f/c/eggs' - ] + "/c/d/foo", + "/c/d/bar", + "/c/d/baz", + "/e/f~f/c/spam", + "/e/f~f/c/eggs", + ], ) assert retval is not None assert "--no-warn-script-location" in retval @@ -649,17 +640,18 @@ def test_multi_script_all_tilde_not_at_start__multi_dir_not_on_PATH(self): class TestWheelHashCalculators(object): - def prep(self, tmpdir): self.test_file = tmpdir.joinpath("hash.file") # Want this big enough to trigger the internal read loops. self.test_file_len = 2 * 1024 * 1024 with open(str(self.test_file), "w") as fp: fp.truncate(self.test_file_len) - self.test_file_hash = \ - '5647f05ec18958947d32874eeb788fa396a05d0bab7c1b71f112ceb7e9b31eee' - self.test_file_hash_encoded = \ - 'sha256=VkfwXsGJWJR9ModO63iPo5agXQurfBtx8RLOt-mzHu4' + self.test_file_hash = ( + "5647f05ec18958947d32874eeb788fa396a05d0bab7c1b71f112ceb7e9b31eee" + ) + self.test_file_hash_encoded = ( + "sha256=VkfwXsGJWJR9ModO63iPo5agXQurfBtx8RLOt-mzHu4" + ) def test_hash_file(self, tmpdir): self.prep(tmpdir) diff --git a/tests/unit/test_wheel_builder.py b/tests/unit/test_wheel_builder.py index dcaa1e793ad..0fca3a48635 100644 --- a/tests/unit/test_wheel_builder.py +++ b/tests/unit/test_wheel_builder.py @@ -14,11 +14,9 @@ [ # Trivial. ("pip-18.0", True), - # Ambiguous. ("foo-2-2", True), ("im-valid", True), - # Invalid. ("invalid", False), ("im_invalid", False), @@ -30,7 +28,6 @@ def test_contains_egg_info(s, expected): class ReqMock: - def __init__( self, name="pendulum", @@ -128,9 +125,7 @@ def test_should_cache(req, expected): def test_should_cache_git_sha(script, tmpdir): repo_path = _create_test_package(script, name="mypkg") - commit = script.run( - "git", "rev-parse", "HEAD", cwd=repo_path - ).stdout.strip() + commit = script.run("git", "rev-parse", "HEAD", cwd=repo_path).stdout.strip() # a link referencing a sha should be cached url = "git+https://g.c/o/r@" + commit + "#egg=mypkg" @@ -147,44 +142,47 @@ def test_format_command_result__INFO(caplog): caplog.set_level(logging.INFO) actual = format_command_result( # Include an argument with a space to test argument quoting. - command_args=['arg1', 'second arg'], - command_output='output line 1\noutput line 2\n', + command_args=["arg1", "second arg"], + command_output="output line 1\noutput line 2\n", ) assert actual.splitlines() == [ "Command arguments: arg1 'second arg'", - 'Command output: [use --verbose to show]', + "Command output: [use --verbose to show]", ] -@pytest.mark.parametrize('command_output', [ - # Test trailing newline. - 'output line 1\noutput line 2\n', - # Test no trailing newline. - 'output line 1\noutput line 2', -]) +@pytest.mark.parametrize( + "command_output", + [ + # Test trailing newline. + "output line 1\noutput line 2\n", + # Test no trailing newline. + "output line 1\noutput line 2", + ], +) def test_format_command_result__DEBUG(caplog, command_output): caplog.set_level(logging.DEBUG) actual = format_command_result( - command_args=['arg1', 'arg2'], + command_args=["arg1", "arg2"], command_output=command_output, ) assert actual.splitlines() == [ "Command arguments: arg1 arg2", - 'Command output:', - 'output line 1', - 'output line 2', - '----------------------------------------', + "Command output:", + "output line 1", + "output line 2", + "----------------------------------------", ] -@pytest.mark.parametrize('log_level', ['DEBUG', 'INFO']) +@pytest.mark.parametrize("log_level", ["DEBUG", "INFO"]) def test_format_command_result__empty_output(caplog, log_level): caplog.set_level(log_level) actual = format_command_result( - command_args=['arg1', 'arg2'], - command_output='', + command_args=["arg1", "arg2"], + command_output="", ) assert actual.splitlines() == [ "Command arguments: arg1 arg2", - 'Command output: None', + "Command output: None", ] diff --git a/tests/yaml/linter.py b/tests/yaml/linter.py index ac17bbc41be..7baefe4ef2b 100644 --- a/tests/yaml/linter.py +++ b/tests/yaml/linter.py @@ -4,8 +4,8 @@ import yaml -sys.path.insert(0, '../../src') -sys.path.insert(0, '../..') +sys.path.insert(0, "../../src") +sys.path.insert(0, "../..") def check_dict(d, required=None, optional=None): @@ -21,8 +21,9 @@ def check_dict(d, required=None, optional=None): allowed_keys.update(optional) for key in d.keys(): if key not in allowed_keys: - sys.exit("key %r is not allowed. Allowed keys are: %r" % - (key, allowed_keys)) + sys.exit( + "key %r is not allowed. Allowed keys are: %r" % (key, allowed_keys) + ) def lint_case(case, verbose=False): @@ -32,7 +33,7 @@ def lint_case(case, verbose=False): print("--- linting case ---") pprint(case) - check_dict(case, optional=['available', 'request', 'response', 'skip']) + check_dict(case, optional=["available", "request", "response", "skip"]) available = case.get("available", []) requests = case.get("request", []) responses = case.get("response", []) @@ -46,21 +47,21 @@ def lint_case(case, verbose=False): package = convert_to_dict(package) if verbose: pprint(package) - check_dict(package, - required=['name', 'version'], - optional=['depends', 'extras']) - version = package['version'] + check_dict( + package, required=["name", "version"], optional=["depends", "extras"] + ) + version = package["version"] assert isinstance(version, str), repr(version) for request, response in zip(requests, responses): - check_dict(request, optional=['install', 'uninstall', 'options']) - check_dict(response, optional=['state', 'error']) + check_dict(request, optional=["install", "uninstall", "options"]) + check_dict(response, optional=["state", "error"]) assert len(response) >= 1 - assert isinstance(response.get('state') or [], list) - error = response.get('error') + assert isinstance(response.get("state") or [], list) + error = response.get("error") if error: - check_dict(error, optional=['code', 'stderr']) - stderr = error.get('stderr') + check_dict(error, optional=["code", "stderr"]) + stderr = error.get("stderr") if stderr: if isinstance(stderr, str): patters = [stderr] @@ -81,7 +82,7 @@ def lint_yml(yml_file, verbose=False): if verbose: pprint(data) - check_dict(data, required=['cases'], optional=['base']) + check_dict(data, required=["cases"], optional=["base"]) base = data.get("base", {}) cases = data["cases"] for _, case_template in enumerate(cases): @@ -90,19 +91,20 @@ def lint_yml(yml_file, verbose=False): lint_case(case, verbose) -if __name__ == '__main__': +if __name__ == "__main__": from optparse import OptionParser - p = OptionParser(usage="usage: %prog [options] FILE ...", - description="linter for pip's yaml test FILE(s)") + p = OptionParser( + usage="usage: %prog [options] FILE ...", + description="linter for pip's yaml test FILE(s)", + ) - p.add_option('-v', '--verbose', - action="store_true") + p.add_option("-v", "--verbose", action="store_true") opts, args = p.parse_args() if len(args) < 1: - p.error('at least one argument required, try -h') + p.error("at least one argument required, try -h") for yml_file in args: lint_yml(yml_file, opts.verbose) diff --git a/tools/automation/release/__init__.py b/tools/automation/release/__init__.py index 042723100a8..1bcecd3ca6e 100644 --- a/tools/automation/release/__init__.py +++ b/tools/automation/release/__init__.py @@ -29,7 +29,7 @@ def get_version_from_arguments(session: Session) -> Optional[str]: cmd = [ os.path.join(session.bin, "python"), "tools/automation/release/check_version.py", - version + version, ] not_ok = subprocess.run(cmd).returncode if not_ok: @@ -47,8 +47,7 @@ def modified_files_in_git(*args: str) -> int: def get_author_list() -> List[str]: - """Get the list of authors from Git commits. - """ + """Get the list of authors from Git commits.""" # subprocess because session.run doesn't give us stdout # only use names in list of Authors result = subprocess.run( @@ -76,8 +75,8 @@ def generate_authors(filename: str) -> None: # Write our authors to the AUTHORS file with io.open(filename, "w", encoding="utf-8") as fp: - fp.write(u"\n".join(authors)) - fp.write(u"\n") + fp.write("\n".join(authors)) + fp.write("\n") def commit_file(session: Session, filename: str, *, message: str) -> None: @@ -103,13 +102,18 @@ def update_version_file(version: str, filepath: str) -> None: else: f.write(line) - assert file_modified, \ - "Version file {} did not get modified".format(filepath) + assert file_modified, "Version file {} did not get modified".format(filepath) def create_git_tag(session: Session, tag_name: str, *, message: str) -> None: session.run( - "git", "tag", "-m", message, tag_name, external=True, silent=True, + "git", + "tag", + "-m", + message, + tag_name, + external=True, + silent=True, ) @@ -148,8 +152,8 @@ def have_files_in_folder(folder_name: str) -> bool: @contextlib.contextmanager def workdir( - nox_session: Session, - dir_path: pathlib.Path, + nox_session: Session, + dir_path: pathlib.Path, ) -> Iterator[pathlib.Path]: """Temporarily chdir when entering CM and chdir back on exit.""" orig_dir = pathlib.Path.cwd() @@ -163,35 +167,49 @@ def workdir( @contextlib.contextmanager def isolated_temporary_checkout( - nox_session: Session, - target_ref: str, + nox_session: Session, + target_ref: str, ) -> Iterator[pathlib.Path]: """Make a clean checkout of a given version in tmp dir.""" with tempfile.TemporaryDirectory() as tmp_dir_path: tmp_dir = pathlib.Path(tmp_dir_path) - git_checkout_dir = tmp_dir / f'pip-build-{target_ref}' + git_checkout_dir = tmp_dir / f"pip-build-{target_ref}" nox_session.run( - 'git', 'worktree', 'add', '--force', '--checkout', - str(git_checkout_dir), str(target_ref), - external=True, silent=True, + "git", + "worktree", + "add", + "--force", + "--checkout", + str(git_checkout_dir), + str(target_ref), + external=True, + silent=True, ) try: yield git_checkout_dir finally: nox_session.run( - 'git', 'worktree', 'remove', '--force', + "git", + "worktree", + "remove", + "--force", str(git_checkout_dir), - external=True, silent=True, + external=True, + silent=True, ) def get_git_untracked_files() -> Iterator[str]: """List all local file paths that aren't tracked by Git.""" git_ls_files_cmd = ( - "git", "ls-files", - "--ignored", "--exclude-standard", - "--others", "--", ".", + "git", + "ls-files", + "--ignored", + "--exclude-standard", + "--others", + "--", + ".", ) # session.run doesn't seem to return any output: ls_files_out = subprocess.check_output(git_ls_files_cmd, text=True) diff --git a/tools/tox_pip.py b/tools/tox_pip.py index 5996dade6d2..17d46781da9 100644 --- a/tools/tox_pip.py +++ b/tools/tox_pip.py @@ -7,25 +7,33 @@ import sys from glob import glob -VIRTUAL_ENV = os.environ['VIRTUAL_ENV'] -TOX_PIP_DIR = os.path.join(VIRTUAL_ENV, 'pip') +VIRTUAL_ENV = os.environ["VIRTUAL_ENV"] +TOX_PIP_DIR = os.path.join(VIRTUAL_ENV, "pip") def pip(args): # First things first, get a recent (stable) version of pip. if not os.path.exists(TOX_PIP_DIR): - subprocess.check_call([sys.executable, '-m', 'pip', - '--disable-pip-version-check', - 'install', '-t', TOX_PIP_DIR, - 'pip']) - shutil.rmtree(glob(os.path.join(TOX_PIP_DIR, 'pip-*.dist-info'))[0]) + subprocess.check_call( + [ + sys.executable, + "-m", + "pip", + "--disable-pip-version-check", + "install", + "-t", + TOX_PIP_DIR, + "pip", + ] + ) + shutil.rmtree(glob(os.path.join(TOX_PIP_DIR, "pip-*.dist-info"))[0]) # And use that version. - pypath = os.environ.get('PYTHONPATH') + pypath = os.environ.get("PYTHONPATH") pypath = pypath.split(os.pathsep) if pypath is not None else [] pypath.insert(0, TOX_PIP_DIR) - os.environ['PYTHONPATH'] = os.pathsep.join(pypath) - subprocess.check_call([sys.executable, '-m', 'pip'] + args) + os.environ["PYTHONPATH"] = os.pathsep.join(pypath) + subprocess.check_call([sys.executable, "-m", "pip"] + args) -if __name__ == '__main__': +if __name__ == "__main__": pip(sys.argv[1:])