diff --git a/news/6171.bugfix.rst b/news/6171.bugfix.rst new file mode 100644 index 0000000000..5ff0d0a530 --- /dev/null +++ b/news/6171.bugfix.rst @@ -0,0 +1 @@ +Fixed package sorting when installing a package with extras. diff --git a/pipenv/project.py b/pipenv/project.py index a6bcc87a72..dab4915e35 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -15,6 +15,7 @@ from urllib.parse import unquote, urljoin from pipenv.utils.constants import VCS_LIST +from pipenv.vendor.tomlkit.items import SingleKey, Table try: import tomllib as toml @@ -1107,12 +1108,23 @@ def get_package_name_in_pipfile(self, package_name, category): return name return None - def _sort_category(self, category): - # toml tables won't maintain sorted dictionary order - # so construct the table in the order that we need + def _sort_category(self, category) -> Table: + # copy table or create table from dict-like object table = tomlkit.table() - for key, value in sorted(category.items()): - table.add(key, value) + if isinstance(category, Table): + table.update(category.value) + else: + table.update(category) + + # sort the table internally + table._value._body.sort(key=lambda t: t[0] and t[0].key or "") + for index, (key, _) in enumerate(table._value._body): + assert isinstance(key, SingleKey) + indices = table._value._map[key] + if isinstance(indices, tuple): + table._value._map[key] = (index,) + indices[1:] + else: + table._value._map[key] = index return table diff --git a/pipenv/utils/toml.py b/pipenv/utils/toml.py index 1eec3fed6a..b97d32d3bd 100644 --- a/pipenv/utils/toml.py +++ b/pipenv/utils/toml.py @@ -1,8 +1,9 @@ from typing import Union from pipenv.vendor.plette.models import Package, PackageCollection -from pipenv.vendor.tomlkit.container import Container +from pipenv.vendor.tomlkit.container import Container, OutOfOrderTableProxy from pipenv.vendor.tomlkit.items import AoT, Array, Bool, InlineTable, Item, String, Table +from pipenv.vendor.tomlkit.toml_document import TOMLDocument try: import tomllib as toml @@ -33,26 +34,32 @@ def cleanup_toml(tml): return toml -def convert_toml_outline_tables(parsed, project): +def convert_toml_outline_tables(parsed: TOMLDocument, project) -> TOMLDocument: """Converts all outline tables to inline tables.""" def convert_tomlkit_table(section): - result = section.copy() - if isinstance(section, tomlkit.items.Table): + result: Table = tomlkit.table() + if isinstance(section, Table): body = section.value._body - elif isinstance(section, tomlkit.container.OutOfOrderTableProxy): + elif isinstance(section, OutOfOrderTableProxy): body = section._internal_container._body else: - body = section._body + assert not hasattr(section, "_body") + body = section + + index: int = 0 for key, value in body: if not key: continue - if hasattr(value, "keys") and not isinstance( - value, tomlkit.items.InlineTable - ): + if hasattr(value, "keys") and not isinstance(value, InlineTable): table = tomlkit.inline_table() table.update(value.value) - result[key.key] = table + key.sep = " = " # add separator because it did not exist before + result.append(key, table) + else: + result.append(key, value) + index += 1 + return result def convert_toml_table(section): @@ -66,10 +73,10 @@ def convert_toml_table(section): result[package] = table return result - is_tomlkit_parsed = isinstance(parsed, tomlkit.container.Container) + is_tomlkit_parsed = isinstance(parsed, Container) for section in project.get_package_categories(): table_data = parsed.get(section, {}) - if not table_data: + if table_data is None: continue if is_tomlkit_parsed: result = convert_tomlkit_table(table_data) diff --git a/tests/conftest.py b/tests/conftest.py index fc75b6b572..b8d46e68c8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,4 +4,5 @@ @pytest.fixture() def project(): from pipenv.project import Project + return Project() diff --git a/tests/fixtures/cython-import-package/setup.py b/tests/fixtures/cython-import-package/setup.py index 3a816a94a5..826b80b746 100644 --- a/tests/fixtures/cython-import-package/setup.py +++ b/tests/fixtures/cython-import-package/setup.py @@ -10,34 +10,31 @@ import Cython.Distutils - ROOT = os.path.dirname(__file__) -PACKAGE_NAME = 'cython_import_package' +PACKAGE_NAME = "cython_import_package" VERSION = None -with open(os.path.join(ROOT, 'src', PACKAGE_NAME.replace("-", "_"), '__init__.py')) as f: +with open(os.path.join(ROOT, "src", PACKAGE_NAME.replace("-", "_"), "__init__.py")) as f: for line in f: - if line.startswith('__version__ = '): - VERSION = ast.literal_eval(line[len('__version__ = '):].strip()) + if line.startswith("__version__ = "): + VERSION = ast.literal_eval(line[len("__version__ = ") :].strip()) break if VERSION is None: - raise OSError('failed to read version') + raise OSError("failed to read version") # Put everything in setup.cfg, except those that don't actually work? setup( # These really don't work. - package_dir={'': 'src'}, - packages=find_packages('src'), - + package_dir={"": "src"}, + packages=find_packages("src"), # I don't know how to specify an empty key in setup.cfg. package_data={ - '': ['LICENSE*', 'README*'], + "": ["LICENSE*", "README*"], }, setup_requires=["setuptools_scm", "cython"], - # I need this to be dynamic. version=VERSION, ) diff --git a/tests/fixtures/fake-package/docs/conf.py b/tests/fixtures/fake-package/docs/conf.py index 5f59ed5232..c50a4ea0bd 100644 --- a/tests/fixtures/fake-package/docs/conf.py +++ b/tests/fixtures/fake-package/docs/conf.py @@ -13,6 +13,7 @@ # import os import sys + ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) PACKAGE_DIR = os.path.join(ROOT, "src/fake_package") sys.path.insert(0, PACKAGE_DIR) @@ -20,14 +21,14 @@ # -- Project information ----------------------------------------------------- -project = 'fake_package' -copyright = '2019, Dan Ryan ' -author = 'Dan Ryan ' +project = "fake_package" +copyright = "2019, Dan Ryan " +author = "Dan Ryan " # The short X.Y version -version = '0.0' +version = "0.0" # The full version, including alpha/beta/rc tags -release = '0.0.0.dev0' +release = "0.0.0.dev0" # -- General configuration --------------------------------------------------- @@ -40,39 +41,39 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.viewcode', - 'sphinx.ext.todo', - 'sphinx.ext.intersphinx', - 'sphinx.ext.autosummary' + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.todo", + "sphinx.ext.intersphinx", + "sphinx.ext.autosummary", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . -exclude_patterns = ['_build', '_man', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "_man", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" autosummary_generate = True @@ -81,7 +82,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -92,7 +93,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -108,22 +109,22 @@ # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'fake_packagedoc' +htmlhelp_basename = "fake_packagedoc" extlinks = { - 'issue': ('https://github.com/sarugaku/fake_package/issues/%s', '#'), - 'pull': ('https://github.com/sarugaku/fake_package/pull/%s', 'PR #'), + "issue": ("https://github.com/sarugaku/fake_package/issues/%s", "#"), + "pull": ("https://github.com/sarugaku/fake_package/pull/%s", "PR #"), } html_theme_options = { - 'display_version': True, - 'prev_next_buttons_location': 'bottom', - 'style_external_links': True, - 'vcs_pageview_mode': '', + "display_version": True, + "prev_next_buttons_location": "bottom", + "style_external_links": True, + "vcs_pageview_mode": "", # Toc options - 'collapse_navigation': True, - 'sticky_navigation': True, - 'navigation_depth': 4, - 'includehidden': True, - 'titles_only': False + "collapse_navigation": True, + "sticky_navigation": True, + "navigation_depth": 4, + "includehidden": True, + "titles_only": False, } # -- Options for LaTeX output ------------------------------------------------ @@ -132,15 +133,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -150,8 +148,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'fake_package.tex', 'fake_package Documentation', - 'Dan Ryan \\textless{}dan@danryan.co\\textgreater{}', 'manual'), + ( + master_doc, + "fake_package.tex", + "fake_package Documentation", + "Dan Ryan \\textless{}dan@danryan.co\\textgreater{}", + "manual", + ), ] @@ -159,10 +162,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'fake_package', 'fake_package Documentation', - [author], 1) -] +man_pages = [(master_doc, "fake_package", "fake_package Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -171,9 +171,15 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'fake_package', 'fake_package Documentation', - author, 'fake_package', 'A fake python package.', - 'Miscellaneous'), + ( + master_doc, + "fake_package", + "fake_package Documentation", + author, + "fake_package", + "A fake python package.", + "Miscellaneous", + ), ] @@ -195,7 +201,7 @@ # epub_uid = '' # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] +epub_exclude_files = ["search.html"] # -- Extension configuration ------------------------------------------------- @@ -204,4 +210,4 @@ # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True -intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} +intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} diff --git a/tests/fixtures/fake-package/setup.py b/tests/fixtures/fake-package/setup.py index 3048d50607..7a23b480ac 100644 --- a/tests/fixtures/fake-package/setup.py +++ b/tests/fixtures/fake-package/setup.py @@ -6,30 +6,28 @@ ROOT = os.path.dirname(__file__) -PACKAGE_NAME = 'fake_package' +PACKAGE_NAME = "fake_package" VERSION = None -with open(os.path.join(ROOT, 'src', PACKAGE_NAME.replace("-", "_"), '__init__.py')) as f: +with open(os.path.join(ROOT, "src", PACKAGE_NAME.replace("-", "_"), "__init__.py")) as f: for line in f: - if line.startswith('__version__ = '): - VERSION = ast.literal_eval(line[len('__version__ = '):].strip()) + if line.startswith("__version__ = "): + VERSION = ast.literal_eval(line[len("__version__ = ") :].strip()) break if VERSION is None: - raise OSError('failed to read version') + raise OSError("failed to read version") # Put everything in setup.cfg, except those that don't actually work? setup( # These really don't work. - package_dir={'': 'src'}, - packages=find_packages('src'), - + package_dir={"": "src"}, + packages=find_packages("src"), # I don't know how to specify an empty key in setup.cfg. package_data={ - '': ['LICENSE*', 'README*'], + "": ["LICENSE*", "README*"], }, - # I need this to be dynamic. version=VERSION, ) diff --git a/tests/fixtures/fake-package/src/fake_package/__init__.py b/tests/fixtures/fake-package/src/fake_package/__init__.py index b8023d8bc0..f102a9cadf 100644 --- a/tests/fixtures/fake-package/src/fake_package/__init__.py +++ b/tests/fixtures/fake-package/src/fake_package/__init__.py @@ -1 +1 @@ -__version__ = '0.0.1' +__version__ = "0.0.1" diff --git a/tests/fixtures/fake-package/tasks/__init__.py b/tests/fixtures/fake-package/tasks/__init__.py index 8652dcaa6e..8e9f02bd62 100644 --- a/tests/fixtures/fake-package/tasks/__init__.py +++ b/tests/fixtures/fake-package/tasks/__init__.py @@ -7,16 +7,18 @@ import parver from towncrier._builder import ( - find_fragments, render_fragments, split_fragments, + find_fragments, + render_fragments, + split_fragments, ) from towncrier._settings import load_config ROOT = pathlib.Path(__file__).resolve().parent.parent -PACKAGE_NAME = 'fake_package' +PACKAGE_NAME = "fake_package" -INIT_PY = ROOT.joinpath('src', PACKAGE_NAME, '__init__.py') +INIT_PY = ROOT.joinpath("src", PACKAGE_NAME, "__init__.py") @invoke.task() @@ -30,23 +32,24 @@ def typecheck(ctx): @invoke.task() def clean(ctx): - """Clean previously built package artifacts. - """ - ctx.run('python setup.py clean') - dist = ROOT.joinpath('dist') - print(f'[clean] Removing {dist}') + """Clean previously built package artifacts.""" + ctx.run("python setup.py clean") + dist = ROOT.joinpath("dist") + print(f"[clean] Removing {dist}") if dist.exists(): shutil.rmtree(str(dist)) def _read_version(): - out = subprocess.check_output(['git', 'tag'], encoding='ascii') + out = subprocess.check_output(["git", "tag"], encoding="ascii") try: - version = max(parver.Version.parse(v).normalize() for v in ( - line.strip() for line in out.split('\n') - ) if v) + version = max( + parver.Version.parse(v).normalize() + for v in (line.strip() for line in out.split("\n")) + if v + ) except ValueError: - version = parver.Version.parse('0.0.0') + version = parver.Version.parse("0.0.0") return version @@ -62,8 +65,7 @@ def _write_version(v): def _render_log(): - """Totally tap into Towncrier internals to get an in-memory result. - """ + """Totally tap into Towncrier internals to get an in-memory result.""" config = load_config(ROOT) definitions = config["types"] fragments, fragment_filenames = find_fragments( @@ -101,15 +103,14 @@ def _prebump(version, prebump): return next_version -PREBUMP = 'patch' +PREBUMP = "patch" @invoke.task(pre=[clean]) def release(ctx, type_, repo, prebump=PREBUMP): - """Make a new release. - """ + """Make a new release.""" if prebump not in REL_TYPES: - raise ValueError(f'{type_} not in {REL_TYPES}') + raise ValueError(f"{type_} not in {REL_TYPES}") prebump = REL_TYPES.index(prebump) version = _read_version() @@ -119,26 +120,26 @@ def release(ctx, type_, repo, prebump=PREBUMP): # Needs to happen before Towncrier deletes fragment files. tag_content = _render_log() - ctx.run('towncrier') + ctx.run("towncrier") ctx.run(f'git commit -am "Release {version}"') tag_content = tag_content.replace('"', '\\"') ctx.run(f'git tag -a {version} -m "Version {version}\n\n{tag_content}"') - ctx.run('python setup.py sdist bdist_wheel') + ctx.run("python setup.py sdist bdist_wheel") dist_pattern = f'{PACKAGE_NAME.replace("-", "[-_]")}-*' - artifacts = list(ROOT.joinpath('dist').glob(dist_pattern)) - filename_display = '\n'.join(f' {a}' for a in artifacts) - print(f'[release] Will upload:\n{filename_display}') + artifacts = list(ROOT.joinpath("dist").glob(dist_pattern)) + filename_display = "\n".join(f" {a}" for a in artifacts) + print(f"[release] Will upload:\n{filename_display}") try: - input('[release] Release ready. ENTER to upload, CTRL-C to abort: ') + input("[release] Release ready. ENTER to upload, CTRL-C to abort: ") except KeyboardInterrupt: - print('\nAborted!') + print("\nAborted!") return - arg_display = ' '.join(f'"{n}"' for n in artifacts) + arg_display = " ".join(f'"{n}"' for n in artifacts) ctx.run(f'twine upload --repository="{repo}" {arg_display}') version = _prebump(version, prebump) @@ -151,9 +152,9 @@ def release(ctx, type_, repo, prebump=PREBUMP): def build_docs(ctx): _current_version = _read_version() minor = [str(i) for i in _current_version.release[:2]] - docs_folder = (ROOT / 'docs').as_posix() - if not docs_folder.endswith('/'): - docs_folder = f'{docs_folder}/' + docs_folder = (ROOT / "docs").as_posix() + if not docs_folder.endswith("/"): + docs_folder = f"{docs_folder}/" args = ["--ext-autodoc", "--ext-viewcode", "-o", docs_folder] args.extend(["-A", "'Dan Ryan '"]) args.extend(["-R", str(_current_version)]) diff --git a/tests/fixtures/legacy-backend-package/setup.py b/tests/fixtures/legacy-backend-package/setup.py index bb43fcaa12..b73c90a707 100644 --- a/tests/fixtures/legacy-backend-package/setup.py +++ b/tests/fixtures/legacy-backend-package/setup.py @@ -6,30 +6,28 @@ ROOT = os.path.dirname(__file__) -PACKAGE_NAME = 'legacy_backend_package' +PACKAGE_NAME = "legacy_backend_package" VERSION = None -with open(os.path.join(ROOT, 'src', PACKAGE_NAME.replace("-", "_"), '__init__.py')) as f: +with open(os.path.join(ROOT, "src", PACKAGE_NAME.replace("-", "_"), "__init__.py")) as f: for line in f: - if line.startswith('__version__ = '): - VERSION = ast.literal_eval(line[len('__version__ = '):].strip()) + if line.startswith("__version__ = "): + VERSION = ast.literal_eval(line[len("__version__ = ") :].strip()) break if VERSION is None: - raise OSError('failed to read version') + raise OSError("failed to read version") # Put everything in setup.cfg, except those that don't actually work? setup( # These really don't work. - package_dir={'': 'src'}, - packages=find_packages('src'), - + package_dir={"": "src"}, + packages=find_packages("src"), # I don't know how to specify an empty key in setup.cfg. package_data={ - '': ['LICENSE*', 'README*'], + "": ["LICENSE*", "README*"], }, - # I need this to be dynamic. version=VERSION, ) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 171774767d..4175c21c03 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -26,7 +26,9 @@ HAS_WARNED_GITHUB = False -DEFAULT_PRIVATE_PYPI_SERVER = os.environ.get("PIPENV_PYPI_SERVER", "http://localhost:8080/simple") +DEFAULT_PRIVATE_PYPI_SERVER = os.environ.get( + "PIPENV_PYPI_SERVER", "http://localhost:8080/simple" +) def try_internet(url="http://httpbin.org/ip", timeout=1.5): @@ -61,21 +63,25 @@ def check_github_ssh(): # GitHub does not provide shell access.' if ssh keys are available and # registered with GitHub. Otherwise, the command will fail with # return_code=255 and say 'Permission denied (publickey).' - c = subprocess_run('ssh -o StrictHostKeyChecking=no -o CheckHostIP=no -T git@github.com', timeout=30, shell=True) + c = subprocess_run( + "ssh -o StrictHostKeyChecking=no -o CheckHostIP=no -T git@github.com", + timeout=30, + shell=True, + ) res = c.returncode == 1 except KeyboardInterrupt: warnings.warn( - "KeyboardInterrupt while checking GitHub ssh access", RuntimeWarning, stacklevel=1 + "KeyboardInterrupt while checking GitHub ssh access", + RuntimeWarning, + stacklevel=1, ) except Exception: pass global HAS_WARNED_GITHUB if not res and not HAS_WARNED_GITHUB: + warnings.warn("Cannot connect to GitHub via SSH", RuntimeWarning, stacklevel=1) warnings.warn( - 'Cannot connect to GitHub via SSH', RuntimeWarning, stacklevel=1 - ) - warnings.warn( - 'Will skip tests requiring SSH access to GitHub', RuntimeWarning, stacklevel=1 + "Will skip tests requiring SSH access to GitHub", RuntimeWarning, stacklevel=1 ) HAS_WARNED_GITHUB = True return res @@ -87,25 +93,28 @@ def check_for_mercurial(): TESTS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -PYPI_VENDOR_DIR = os.path.join(TESTS_ROOT, 'pypi') +PYPI_VENDOR_DIR = os.path.join(TESTS_ROOT, "pypi") WE_HAVE_HG = check_for_mercurial() def pytest_runtest_setup(item): - if item.get_closest_marker('needs_internet') is not None and not WE_HAVE_INTERNET: - pytest.skip('requires internet') - if item.get_closest_marker('needs_github_ssh') is not None and not WE_HAVE_GITHUB_SSH_KEYS: - pytest.skip('requires github ssh') - if item.get_closest_marker('needs_hg') is not None and not WE_HAVE_HG: - pytest.skip('requires mercurial') - if item.get_closest_marker('skip_py38') is not None and ( + if item.get_closest_marker("needs_internet") is not None and not WE_HAVE_INTERNET: + pytest.skip("requires internet") + if ( + item.get_closest_marker("needs_github_ssh") is not None + and not WE_HAVE_GITHUB_SSH_KEYS + ): + pytest.skip("requires github ssh") + if item.get_closest_marker("needs_hg") is not None and not WE_HAVE_HG: + pytest.skip("requires mercurial") + if item.get_closest_marker("skip_py38") is not None and ( sys.version_info[:2] == (3, 8) ): - pytest.skip('test not applicable on python 3.8') - if item.get_closest_marker('skip_osx') is not None and sys.platform == 'darwin': - pytest.skip('test does not apply on OSX') - if item.get_closest_marker('skip_windows') is not None and (os.name == 'nt'): - pytest.skip('test does not run on windows') + pytest.skip("test not applicable on python 3.8") + if item.get_closest_marker("skip_osx") is not None and sys.platform == "darwin": + pytest.skip("test does not apply on OSX") + if item.get_closest_marker("skip_windows") is not None and (os.name == "nt"): + pytest.skip("test does not run on windows") WE_HAVE_INTERNET = check_internet() @@ -138,7 +147,11 @@ def install(self, package, value, dev=False): def remove(self, package, dev=False): section = "packages" if not dev else "dev-packages" - if not dev and package not in self.document[section] and package in self.document["dev-packages"]: + if ( + not dev + and package not in self.document[section] + and package in self.document["dev-packages"] + ): section = "dev-packages" del self.document[section][package] self.write() @@ -171,6 +184,7 @@ def get_fixture_path(cls, path, fixtures="test_artifacts"): class _PipenvInstance: """An instance of a Pipenv Project...""" + def __init__(self, pipfile=True, capfd=None, index_url=None): self.index_url = index_url self.pypi = None @@ -182,7 +196,7 @@ def __init__(self, pipfile=True, capfd=None, index_url=None): os.environ.pop("PIPENV_CUSTOM_VENV_NAME", None) self.original_dir = Path(__file__).parent.parent.parent - self._path = TemporaryDirectory(prefix='pipenv-', suffix="-tests") + self._path = TemporaryDirectory(prefix="pipenv-", suffix="-tests") path = Path(self._path.name) try: self.path = str(path.resolve()) @@ -192,14 +206,14 @@ def __init__(self, pipfile=True, capfd=None, index_url=None): # set file creation perms self.pipfile_path = None - p_path = os.sep.join([self.path, 'Pipfile']) + p_path = os.sep.join([self.path, "Pipfile"]) self.pipfile_path = p_path if pipfile: with contextlib.suppress(FileNotFoundError): os.remove(p_path) - with open(p_path, 'a'): + with open(p_path, "a"): os.utime(p_path, None) self._pipfile = _Pipfile(Path(p_path), index=self.index_url) @@ -210,7 +224,7 @@ def __enter__(self): return self def __exit__(self, *args): - warn_msg = 'Failed to remove resource: {!r}' + warn_msg = "Failed to remove resource: {!r}" if self.pipfile_path: with contextlib.suppress(OSError): os.remove(self.pipfile_path) @@ -249,7 +263,7 @@ def pipenv(self, cmd, block=True): if err: r.stderr_bytes = r.stderr_bytes + err if block: - print(f'$ pipenv {cmd}') + print(f"$ pipenv {cmd}") print(r.stdout) print(r.stderr, file=sys.stderr) if r.returncode != 0: @@ -260,7 +274,7 @@ def pipenv(self, cmd, block=True): @property def pipfile(self): - p_path = os.sep.join([self.path, 'Pipfile']) + p_path = os.sep.join([self.path, "Pipfile"]) with open(p_path) as f: return tomlkit.loads(f.read()) @@ -272,7 +286,7 @@ def lockfile(self): @property def lockfile_path(self): - return os.sep.join([self.path, 'Pipfile.lock']) + return os.sep.join([self.path, "Pipfile.lock"]) if sys.version_info[:2] <= (3, 8): @@ -287,6 +301,7 @@ def _rmtree_func(path, ignore_errors=True, onerror=None): # Ignore removal failures where the file doesn't exist if exc.errno != errno.ENOENT: raise + else: _rmtree_func = _rmtree @@ -300,9 +315,13 @@ def pipenv_instance_pypi(capfdbinary, monkeypatch): os.environ["CI"] = "1" os.environ["PIPENV_DONT_USE_PYENV"] = "1" warnings.simplefilter("ignore", category=ResourceWarning) - warnings.filterwarnings("ignore", category=ResourceWarning, message="unclosed.*") + warnings.filterwarnings( + "ignore", category=ResourceWarning, message="unclosed.*" + ) try: - yield functools.partial(_PipenvInstance, capfd=capfdbinary, index_url="https://pypi.org/simple") + yield functools.partial( + _PipenvInstance, capfd=capfdbinary, index_url="https://pypi.org/simple" + ) finally: os.umask(original_umask) @@ -316,9 +335,13 @@ def pipenv_instance_private_pypi(capfdbinary, monkeypatch): os.environ["CI"] = "1" os.environ["PIPENV_DONT_USE_PYENV"] = "1" warnings.simplefilter("ignore", category=ResourceWarning) - warnings.filterwarnings("ignore", category=ResourceWarning, message="unclosed.*") + warnings.filterwarnings( + "ignore", category=ResourceWarning, message="unclosed.*" + ) try: - yield functools.partial(_PipenvInstance, capfd=capfdbinary, index_url=DEFAULT_PRIVATE_PYPI_SERVER) + yield functools.partial( + _PipenvInstance, capfd=capfdbinary, index_url=DEFAULT_PRIVATE_PYPI_SERVER + ) finally: os.umask(original_umask) diff --git a/tests/integration/test_cli.py b/tests/integration/test_cli.py index 87935bccee..09ac867f94 100644 --- a/tests/integration/test_cli.py +++ b/tests/integration/test_cli.py @@ -20,45 +20,55 @@ def test_pipenv_where(pipenv_instance_pypi): @pytest.mark.cli def test_pipenv_venv(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('install dataclasses-json') + c = p.pipenv("install dataclasses-json") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_path = c.stdout.strip() assert os.path.isdir(venv_path) @pytest.mark.cli -@pytest.mark.skipif(sys.version_info[:2] == (3, 8) and os.name == "nt", reason="Python 3.8 on Windows is not supported") +@pytest.mark.skipif( + sys.version_info[:2] == (3, 8) and os.name == "nt", + reason="Python 3.8 on Windows is not supported", +) def test_pipenv_py(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('--python python') + c = p.pipenv("--python python") assert c.returncode == 0 - c = p.pipenv('--py') + c = p.pipenv("--py") assert c.returncode == 0 python = c.stdout.strip() - assert os.path.basename(python).startswith('python') + assert os.path.basename(python).startswith("python") @pytest.mark.cli -@pytest.mark.skipif(os.name == 'nt' and sys.version_info[:2] == (3, 8), reason='Test issue with windows 3.8 CIs') +@pytest.mark.skipif( + os.name == "nt" and sys.version_info[:2] == (3, 8), + reason="Test issue with windows 3.8 CIs", +) def test_pipenv_site_packages(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('--python python --site-packages') + c = p.pipenv("--python python --site-packages") assert c.returncode == 0 - assert 'Making site-packages available' in c.stderr + assert "Making site-packages available" in c.stderr # no-global-site-packages.txt under stdlib dir should not exist. - c = p.pipenv('run python -c "import sysconfig; print(sysconfig.get_path(\'stdlib\'))"') + c = p.pipenv( + "run python -c \"import sysconfig; print(sysconfig.get_path('stdlib'))\"" + ) assert c.returncode == 0 stdlib_path = c.stdout.strip() - assert not os.path.isfile(os.path.join(stdlib_path, 'no-global-site-packages.txt')) + assert not os.path.isfile( + os.path.join(stdlib_path, "no-global-site-packages.txt") + ) @pytest.mark.cli def test_pipenv_support(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('--support') + c = p.pipenv("--support") assert c.returncode == 0 assert c.stdout @@ -66,14 +76,14 @@ def test_pipenv_support(pipenv_instance_pypi): @pytest.mark.cli def test_pipenv_rm(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('--python python') + c = p.pipenv("--python python") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_path = c.stdout.strip() assert os.path.isdir(venv_path) - c = p.pipenv('--rm') + c = p.pipenv("--rm") assert c.returncode == 0 assert c.stdout assert not os.path.isdir(venv_path) @@ -82,7 +92,7 @@ def test_pipenv_rm(pipenv_instance_pypi): @pytest.mark.cli def test_pipenv_graph(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('install tablib') + c = p.pipenv("install tablib") assert c.returncode == 0 graph = p.pipenv("graph") assert graph.returncode == 0 @@ -98,10 +108,12 @@ def test_pipenv_graph(pipenv_instance_pypi): @pytest.mark.cli def test_pipenv_graph_reverse(pipenv_instance_private_pypi): from pipenv.cli import cli - from pipenv.vendor.click.testing import CliRunner # not thread safe but graph is a tricky test + from pipenv.vendor.click.testing import ( + CliRunner, + ) # not thread safe but graph is a tricky test with pipenv_instance_private_pypi() as p: - c = p.pipenv('install tablib==0.13.0') + c = p.pipenv("install tablib==0.13.0") assert c.returncode == 0 cli_runner = CliRunner(mix_stderr=False) c = cli_runner.invoke(cli, "graph --reverse") @@ -109,54 +121,64 @@ def test_pipenv_graph_reverse(pipenv_instance_private_pypi): output = c.stdout requests_dependency = [ - ('backports.csv', 'backports.csv'), - ('odfpy', 'odfpy'), - ('openpyxl', 'openpyxl>=2.4.0'), - ('pyyaml', 'pyyaml'), - ('xlrd', 'xlrd'), - ('xlwt', 'xlwt'), + ("backports.csv", "backports.csv"), + ("odfpy", "odfpy"), + ("openpyxl", "openpyxl>=2.4.0"), + ("pyyaml", "pyyaml"), + ("xlrd", "xlrd"), + ("xlwt", "xlwt"), ] for dep_name, dep_constraint in requests_dependency: - pat = fr'{dep_name}==[\d.]+' - dep_match = re.search(pat, - output, - flags=re.MULTILINE | re.IGNORECASE) - assert dep_match is not None, f'{pat} not found in {output}' + pat = rf"{dep_name}==[\d.]+" + dep_match = re.search(pat, output, flags=re.MULTILINE | re.IGNORECASE) + assert dep_match is not None, f"{pat} not found in {output}" # openpyxl should be indented - if dep_name == 'openpyxl': - openpyxl_dep = re.search(r'^openpyxl', - output, - flags=re.MULTILINE | re.IGNORECASE) - assert openpyxl_dep is None, f'openpyxl should not appear at beginning of lines in {output}' - assert 'openpyxl==2.5.4 [requires: et_xmlfile]' in output + if dep_name == "openpyxl": + openpyxl_dep = re.search( + r"^openpyxl", output, flags=re.MULTILINE | re.IGNORECASE + ) + assert ( + openpyxl_dep is None + ), f"openpyxl should not appear at beginning of lines in {output}" + assert "openpyxl==2.5.4 [requires: et_xmlfile]" in output else: - dep_match = re.search(fr'^[ -]*{dep_name}==[\d.]+$', - output, - flags=re.MULTILINE | re.IGNORECASE) - assert dep_match is not None, f'{dep_name} not found at beginning of line in {output}' - - dep_requests_match = re.search(fr'└── tablib==0.13.0 \[requires: {dep_constraint}', - output, - flags=re.MULTILINE | re.IGNORECASE) - assert dep_requests_match is not None, f'constraint {dep_constraint} not found in {output}' + dep_match = re.search( + rf"^[ -]*{dep_name}==[\d.]+$", + output, + flags=re.MULTILINE | re.IGNORECASE, + ) + assert ( + dep_match is not None + ), f"{dep_name} not found at beginning of line in {output}" + + dep_requests_match = re.search( + rf"└── tablib==0.13.0 \[requires: {dep_constraint}", + output, + flags=re.MULTILINE | re.IGNORECASE, + ) + assert ( + dep_requests_match is not None + ), f"constraint {dep_constraint} not found in {output}" assert dep_requests_match.start() > dep_match.start() -@pytest.mark.skip(reason="There is a disputed vulnerability about pip 24.0 messing up this test.") +@pytest.mark.skip( + reason="There is a disputed vulnerability about pip 24.0 messing up this test." +) @pytest.mark.cli -@pytest.mark.needs_internet(reason='required by check') +@pytest.mark.needs_internet(reason="required by check") def test_pipenv_check(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - c = p.pipenv('install pyyaml') + c = p.pipenv("install pyyaml") assert c.returncode == 0 - c = p.pipenv('check --use-installed') + c = p.pipenv("check --use-installed") assert c.returncode != 0 - assert 'pyyaml' in c.stdout - c = p.pipenv('uninstall pyyaml') + assert "pyyaml" in c.stdout + c = p.pipenv("uninstall pyyaml") assert c.returncode == 0 - c = p.pipenv('install six') + c = p.pipenv("install six") assert c.returncode == 0 c = p.pipenv("run python -m pip install --upgrade pip") assert c.returncode == 0 @@ -167,48 +189,51 @@ def test_pipenv_check(pipenv_instance_private_pypi): # the issue above is still not resolved. # added also 51499 # https://github.com/pypa/wheel/issues/481 - c = p.pipenv('check --use-installed --ignore 35015 -i 51457 -i 51499') + c = p.pipenv("check --use-installed --ignore 35015 -i 51457 -i 51499") assert c.returncode == 0 - assert 'Ignoring' in c.stderr + assert "Ignoring" in c.stderr @pytest.mark.cli -@pytest.mark.needs_internet(reason='required by check') +@pytest.mark.needs_internet(reason="required by check") @pytest.mark.parametrize("category", ["CVE", "packages"]) def test_pipenv_check_check_lockfile_categories(pipenv_instance_pypi, category): with pipenv_instance_pypi() as p: - c = p.pipenv(f'install wheel==0.37.1 --categories={category}') + c = p.pipenv(f"install wheel==0.37.1 --categories={category}") assert c.returncode == 0 - c = p.pipenv(f'check --categories={category}') + c = p.pipenv(f"check --categories={category}") assert c.returncode != 0 - assert 'wheel' in c.stdout + assert "wheel" in c.stdout @pytest.mark.cli -@pytest.mark.skipif(sys.version_info[:2] == (3, 8) and os.name == "nt", reason="This test is not working om Windows Python 3. 8") +@pytest.mark.skipif( + sys.version_info[:2] == (3, 8) and os.name == "nt", + reason="This test is not working om Windows Python 3. 8", +) def test_pipenv_clean(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open('setup.py', 'w') as f: + with open("setup.py", "w") as f: f.write('from setuptools import setup; setup(name="empty")') - c = p.pipenv('install -e .') + c = p.pipenv("install -e .") assert c.returncode == 0 - c = p.pipenv(f'run pip install -i {p.index_url} six') + c = p.pipenv(f"run pip install -i {p.index_url} six") assert c.returncode == 0 - c = p.pipenv('clean') + c = p.pipenv("clean") assert c.returncode == 0 - assert 'six' in c.stdout, f"{c.stdout} -- STDERR: {c.stderr}" + assert "six" in c.stdout, f"{c.stdout} -- STDERR: {c.stderr}" @pytest.mark.cli def test_venv_envs(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - assert p.pipenv('--envs').stdout + assert p.pipenv("--envs").stdout @pytest.mark.cli def test_bare_output(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - assert p.pipenv('').stdout + assert p.pipenv("").stdout @pytest.mark.cli @@ -220,15 +245,15 @@ def test_scripts(pipenv_instance_pypi): pyver = "which python" """.strip() f.write(contents) - c = p.pipenv('scripts') - assert 'pyver' in c.stdout - assert 'which python' in c.stdout + c = p.pipenv("scripts") + assert "pyver" in c.stdout + assert "which python" in c.stdout @pytest.mark.cli def test_help(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - assert p.pipenv('--help').stdout + assert p.pipenv("--help").stdout @pytest.mark.cli @@ -241,28 +266,27 @@ def test_man(pipenv_instance_pypi): @pytest.mark.cli def test_install_parse_error(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - # Make sure unparsable packages don't wind up in the pipfile # Escape $ for shell input - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] [dev-packages] """.strip() f.write(contents) - c = p.pipenv('install requests u/\\/p@r\\$34b13+pkg') + c = p.pipenv("install requests u/\\/p@r\\$34b13+pkg") assert c.returncode != 0 - assert 'u/\\/p@r$34b13+pkg' not in p.pipfile['packages'] + assert "u/\\/p@r$34b13+pkg" not in p.pipfile["packages"] @pytest.mark.skip(reason="This test clears the cache that other tests may be using.") @pytest.mark.cli def test_pipenv_clear(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('--clear') + c = p.pipenv("--clear") assert c.returncode == 0 - assert 'Clearing caches' in c.stdout + assert "Clearing caches" in c.stdout @pytest.mark.outdated @@ -274,46 +298,46 @@ def test_pipenv_outdated_prerelease(pipenv_instance_pypi): sqlalchemy = "<=1.2.3" """.strip() f.write(contents) - c = p.pipenv('update --pre --outdated') + c = p.pipenv("update --pre --outdated") assert c.returncode == 0 @pytest.mark.cli def test_pipenv_verify_without_pipfile(pipenv_instance_pypi): with pipenv_instance_pypi(pipfile=False) as p: - c = p.pipenv('verify') + c = p.pipenv("verify") assert c.returncode == 1 - assert 'No Pipfile present at project home.' in c.stderr + assert "No Pipfile present at project home." in c.stderr @pytest.mark.cli def test_pipenv_verify_without_pipfile_lock(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('verify') + c = p.pipenv("verify") assert c.returncode == 1 - assert 'Pipfile.lock is out-of-date.' in c.stderr + assert "Pipfile.lock is out-of-date." in c.stderr @pytest.mark.cli def test_pipenv_verify_locked_passing(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - p.pipenv('lock') - c = p.pipenv('verify') + p.pipenv("lock") + c = p.pipenv("verify") assert c.returncode == 0 - assert 'Pipfile.lock is up-to-date.' in c.stdout + assert "Pipfile.lock is up-to-date." in c.stdout @pytest.mark.cli def test_pipenv_verify_locked_outdated_failing(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - p.pipenv('lock') + p.pipenv("lock") # modify the Pipfile - pf = Path(p.path).joinpath('Pipfile') + pf = Path(p.path).joinpath("Pipfile") pf_data = pf.read_text() - pf_new = re.sub(r'\[packages\]', '[packages]\nrequests = "*"', pf_data) + pf_new = re.sub(r"\[packages\]", '[packages]\nrequests = "*"', pf_data) pf.write_text(pf_new) - c = p.pipenv('verify') + c = p.pipenv("verify") assert c.returncode == 1 - assert 'Pipfile.lock is out-of-date.' in c.stderr + assert "Pipfile.lock is out-of-date." in c.stderr diff --git a/tests/integration/test_dot_venv.py b/tests/integration/test_dot_venv.py index 23f42aeeaa..bf4c729bac 100644 --- a/tests/integration/test_dot_venv.py +++ b/tests/integration/test_dot_venv.py @@ -1,4 +1,3 @@ - import os from pathlib import Path from tempfile import TemporaryDirectory @@ -13,11 +12,11 @@ @pytest.mark.parametrize("true_value", TRUE_VALUES) def test_venv_in_project(true_value, pipenv_instance_pypi): with temp_environ(): - os.environ['PIPENV_VENV_IN_PROJECT'] = true_value + os.environ["PIPENV_VENV_IN_PROJECT"] = true_value with pipenv_instance_pypi() as p: - c = p.pipenv('install dataclasses-json') + c = p.pipenv("install dataclasses-json") assert c.returncode == 0 - assert p.path in p.pipenv('--venv').stdout + assert p.path in p.pipenv("--venv").stdout @pytest.mark.dotvenv @@ -25,23 +24,23 @@ def test_venv_in_project(true_value, pipenv_instance_pypi): def test_venv_in_project_disabled_ignores_venv(false_value, pipenv_instance_pypi): venv_name = "my_project" with temp_environ(): - os.environ['PIPENV_VENV_IN_PROJECT'] = false_value + os.environ["PIPENV_VENV_IN_PROJECT"] = false_value with pipenv_instance_pypi() as p: - file_path = os.path.join(p.path, '.venv') - with open(file_path, 'w') as f: + file_path = os.path.join(p.path, ".venv") + with open(file_path, "w") as f: f.write(venv_name) with temp_environ(), TemporaryDirectory( - prefix='pipenv-', suffix='temp_workon_home' + prefix="pipenv-", suffix="temp_workon_home" ) as workon_home: - os.environ['WORKON_HOME'] = workon_home - c = p.pipenv('install dataclasses-json') + os.environ["WORKON_HOME"] = workon_home + c = p.pipenv("install dataclasses-json") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_loc = Path(c.stdout.strip()).resolve() assert venv_loc.exists() - assert venv_loc.joinpath('.project').exists() + assert venv_loc.joinpath(".project").exists() venv_path = Path(venv_loc).resolve() venv_expected_path = Path(workon_home).joinpath(venv_name).resolve() assert os.path.samefile(venv_path, venv_expected_path) @@ -51,35 +50,37 @@ def test_venv_in_project_disabled_ignores_venv(false_value, pipenv_instance_pypi @pytest.mark.parametrize("true_value", TRUE_VALUES) def test_venv_at_project_root(true_value, pipenv_instance_pypi): with temp_environ(), pipenv_instance_pypi() as p: - os.environ['PIPENV_VENV_IN_PROJECT'] = true_value - c = p.pipenv('install') + os.environ["PIPENV_VENV_IN_PROJECT"] = true_value + c = p.pipenv("install") assert c.returncode == 0 - assert p.path in p.pipenv('--venv').stdout - del os.environ['PIPENV_VENV_IN_PROJECT'] - os.mkdir('subdir') - os.chdir('subdir') + assert p.path in p.pipenv("--venv").stdout + del os.environ["PIPENV_VENV_IN_PROJECT"] + os.mkdir("subdir") + os.chdir("subdir") # should still detect installed - assert p.path in p.pipenv('--venv').stdout + assert p.path in p.pipenv("--venv").stdout @pytest.mark.dotvenv @pytest.mark.parametrize("false_value", FALSE_VALUES) -def test_venv_in_project_disabled_with_existing_venv_dir(false_value, pipenv_instance_pypi): +def test_venv_in_project_disabled_with_existing_venv_dir( + false_value, pipenv_instance_pypi +): venv_name = "my_project" with temp_environ(), pipenv_instance_pypi() as p, TemporaryDirectory( prefix="pipenv-", suffix="temp_workon_home" ) as workon_home: - os.environ['PIPENV_VENV_IN_PROJECT'] = false_value - os.environ['PIPENV_CUSTOM_VENV_NAME'] = venv_name + os.environ["PIPENV_VENV_IN_PROJECT"] = false_value + os.environ["PIPENV_CUSTOM_VENV_NAME"] = venv_name os.environ["WORKON_HOME"] = workon_home - os.mkdir('.venv') - c = p.pipenv('install') + os.mkdir(".venv") + c = p.pipenv("install") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_loc = Path(c.stdout.strip()).resolve() assert venv_loc.exists() - assert venv_loc.joinpath('.project').exists() + assert venv_loc.joinpath(".project").exists() venv_path = Path(venv_loc).resolve() venv_expected_path = Path(workon_home).joinpath(venv_name).resolve() assert os.path.samefile(venv_path, venv_expected_path) @@ -88,36 +89,36 @@ def test_venv_in_project_disabled_with_existing_venv_dir(false_value, pipenv_ins @pytest.mark.dotvenv def test_reuse_previous_venv(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - os.mkdir('.venv') - c = p.pipenv('install dataclasses-json') + os.mkdir(".venv") + c = p.pipenv("install dataclasses-json") assert c.returncode == 0 - assert p.path in p.pipenv('--venv').stdout + assert p.path in p.pipenv("--venv").stdout @pytest.mark.dotvenv -@pytest.mark.parametrize('venv_name', ('test-venv', os.path.join('foo', 'test-venv'))) +@pytest.mark.parametrize("venv_name", ("test-venv", os.path.join("foo", "test-venv"))) def test_venv_file(venv_name, pipenv_instance_pypi): """Tests virtualenv creation when a .venv file exists at the project root and contains a venv name. """ with pipenv_instance_pypi() as p: - file_path = os.path.join(p.path, '.venv') - with open(file_path, 'w') as f: + file_path = os.path.join(p.path, ".venv") + with open(file_path, "w") as f: f.write(venv_name) with temp_environ(), TemporaryDirectory( - prefix='pipenv-', suffix='temp_workon_home' + prefix="pipenv-", suffix="temp_workon_home" ) as workon_home: - os.environ['WORKON_HOME'] = workon_home + os.environ["WORKON_HOME"] = workon_home - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_loc = Path(c.stdout.strip()).resolve() assert venv_loc.exists() - assert venv_loc.joinpath('.project').exists() + assert venv_loc.joinpath(".project").exists() venv_path = Path(venv_loc).resolve() if os.path.sep in venv_name: venv_expected_path = Path(p.path).joinpath(venv_name) @@ -128,26 +129,25 @@ def test_venv_file(venv_name, pipenv_instance_pypi): @pytest.mark.dotvenv def test_empty_venv_file(pipenv_instance_pypi): - """Tests virtualenv creation when an empty .venv file exists at the project root - """ + """Tests virtualenv creation when an empty .venv file exists at the project root""" with pipenv_instance_pypi() as p: - file_path = os.path.join(p.path, '.venv') - with open(file_path, 'w'): + file_path = os.path.join(p.path, ".venv") + with open(file_path, "w"): pass with temp_environ(), TemporaryDirectory( - prefix='pipenv-', suffix='temp_workon_home' + prefix="pipenv-", suffix="temp_workon_home" ) as workon_home: - os.environ['WORKON_HOME'] = workon_home + os.environ["WORKON_HOME"] = workon_home - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_loc = Path(c.stdout.strip()).absolute() assert venv_loc.exists() - assert venv_loc.joinpath('.project').exists() + assert venv_loc.joinpath(".project").exists() venv_path = Path(venv_loc) venv_path_parent = Path(venv_path.parent) assert venv_path_parent == Path(workon_home) @@ -155,36 +155,34 @@ def test_empty_venv_file(pipenv_instance_pypi): @pytest.mark.dotvenv def test_venv_in_project_default_when_venv_exists(pipenv_instance_pypi): - """Tests virtualenv creation when a .venv file exists at the project root. - """ + """Tests virtualenv creation when a .venv file exists at the project root.""" with temp_environ(), pipenv_instance_pypi() as p, TemporaryDirectory( - prefix='pipenv-', suffix='-test_venv' + prefix="pipenv-", suffix="-test_venv" ) as venv_path: - file_path = os.path.join(p.path, '.venv') - with open(file_path, 'w') as f: + file_path = os.path.join(p.path, ".venv") + with open(file_path, "w") as f: f.write(venv_path) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_loc = Path(c.stdout.strip()) - assert venv_loc.joinpath('.project').exists() + assert venv_loc.joinpath(".project").exists() assert venv_loc == Path(venv_path) @pytest.mark.dotenv def test_venv_name_accepts_custom_name_environment_variable(pipenv_instance_pypi): - """Tests that virtualenv reads PIPENV_CUSTOM_VENV_NAME and accepts it as a name - """ + """Tests that virtualenv reads PIPENV_CUSTOM_VENV_NAME and accepts it as a name""" with pipenv_instance_pypi() as p: test_name = "sensible_custom_venv_name" with temp_environ(): - os.environ['PIPENV_CUSTOM_VENV_NAME'] = test_name - c = p.pipenv('install') + os.environ["PIPENV_CUSTOM_VENV_NAME"] = test_name + c = p.pipenv("install") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_path = c.stdout.strip() assert test_name == Path(venv_path).parts[-1] diff --git a/tests/integration/test_import_requirements.py b/tests/integration/test_import_requirements.py index 07080fbb75..b2a496a5b7 100644 --- a/tests/integration/test_import_requirements.py +++ b/tests/integration/test_import_requirements.py @@ -13,69 +13,110 @@ @pytest.mark.cli @pytest.mark.deploy @pytest.mark.system -@mock.patch("pipenv.utils.dependencies.unpack_url", mock.MagicMock(return_value=File("/some/path/to/project", content_type=None))) +@mock.patch( + "pipenv.utils.dependencies.unpack_url", + mock.MagicMock(return_value=File("/some/path/to/project", content_type=None)), +) @mock.patch("pipenv.utils.dependencies.find_package_name_from_directory") -def test_auth_with_pw_redacted(mock_find_package_name_from_directory, pipenv_instance_pypi): +def test_auth_with_pw_redacted( + mock_find_package_name_from_directory, pipenv_instance_pypi +): mock_find_package_name_from_directory.return_value = "myproject" with pipenv_instance_pypi() as p: p.pipenv("run shell") project = Project() requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False) - requirements_file.write("""git+https://${AUTH_USER}:mypw1@github.com/user/myproject.git@main#egg=myproject""") + requirements_file.write( + """git+https://${AUTH_USER}:mypw1@github.com/user/myproject.git@main#egg=myproject""" + ) requirements_file.close() import_requirements(project, r=requirements_file.name) os.unlink(requirements_file.name) - assert p.pipfile["packages"]["myproject"] == {'git': 'git+https://${AUTH_USER}:****@github.com/user/myproject.git', 'ref': 'main'} + assert p.pipfile["packages"]["myproject"] == { + "git": "git+https://${AUTH_USER}:****@github.com/user/myproject.git", + "ref": "main", + } @pytest.mark.cli @pytest.mark.deploy @pytest.mark.system -@mock.patch("pipenv.utils.dependencies.unpack_url", mock.MagicMock(return_value=File("/some/path/to/project", content_type=None))) +@mock.patch( + "pipenv.utils.dependencies.unpack_url", + mock.MagicMock(return_value=File("/some/path/to/project", content_type=None)), +) @mock.patch("pipenv.utils.dependencies.find_package_name_from_directory") -def test_auth_with_username_redacted(mock_find_package_name_from_directory, pipenv_instance_pypi): +def test_auth_with_username_redacted( + mock_find_package_name_from_directory, pipenv_instance_pypi +): mock_find_package_name_from_directory.return_value = "myproject" with pipenv_instance_pypi() as p: p.pipenv("run shell") project = Project() requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False) - requirements_file.write("""git+https://username@github.com/user/myproject.git@main#egg=myproject""") + requirements_file.write( + """git+https://username@github.com/user/myproject.git@main#egg=myproject""" + ) requirements_file.close() import_requirements(project, r=requirements_file.name) os.unlink(requirements_file.name) - assert p.pipfile["packages"]["myproject"] == {'git': 'git+https://****@github.com/user/myproject.git', 'ref': 'main'} + assert p.pipfile["packages"]["myproject"] == { + "git": "git+https://****@github.com/user/myproject.git", + "ref": "main", + } @pytest.mark.cli @pytest.mark.deploy @pytest.mark.system -@mock.patch("pipenv.utils.dependencies.unpack_url", mock.MagicMock(return_value=File("/some/path/to/project", content_type=None))) +@mock.patch( + "pipenv.utils.dependencies.unpack_url", + mock.MagicMock(return_value=File("/some/path/to/project", content_type=None)), +) @mock.patch("pipenv.utils.dependencies.find_package_name_from_directory") -def test_auth_with_pw_are_variables_passed_to_pipfile(mock_find_package_name_from_directory, pipenv_instance_pypi): +def test_auth_with_pw_are_variables_passed_to_pipfile( + mock_find_package_name_from_directory, pipenv_instance_pypi +): mock_find_package_name_from_directory.return_value = "myproject" with pipenv_instance_pypi() as p: p.pipenv("run shell") project = Project() requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False) - requirements_file.write("""git+https://${AUTH_USER}:${AUTH_PW}@github.com/user/myproject.git@main#egg=myproject""") + requirements_file.write( + """git+https://${AUTH_USER}:${AUTH_PW}@github.com/user/myproject.git@main#egg=myproject""" + ) requirements_file.close() import_requirements(project, r=requirements_file.name) os.unlink(requirements_file.name) - assert p.pipfile["packages"]["myproject"] == {'git': 'git+https://${AUTH_USER}:${AUTH_PW}@github.com/user/myproject.git', 'ref': 'main'} + assert p.pipfile["packages"]["myproject"] == { + "git": "git+https://${AUTH_USER}:${AUTH_PW}@github.com/user/myproject.git", + "ref": "main", + } + @pytest.mark.cli @pytest.mark.deploy @pytest.mark.system -@mock.patch("pipenv.utils.dependencies.unpack_url", mock.MagicMock(return_value=File("/some/path/to/project", content_type=None))) +@mock.patch( + "pipenv.utils.dependencies.unpack_url", + mock.MagicMock(return_value=File("/some/path/to/project", content_type=None)), +) @mock.patch("pipenv.utils.dependencies.find_package_name_from_directory") -def test_auth_with_only_username_variable_passed_to_pipfile(mock_find_package_name_from_directory, pipenv_instance_pypi): +def test_auth_with_only_username_variable_passed_to_pipfile( + mock_find_package_name_from_directory, pipenv_instance_pypi +): mock_find_package_name_from_directory.return_value = "myproject" with pipenv_instance_pypi() as p: p.pipenv("run shell") project = Project() requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False) - requirements_file.write("""git+https://${AUTH_USER}@github.com/user/myproject.git@main#egg=myproject""") + requirements_file.write( + """git+https://${AUTH_USER}@github.com/user/myproject.git@main#egg=myproject""" + ) requirements_file.close() import_requirements(project, r=requirements_file.name) os.unlink(requirements_file.name) - assert p.pipfile["packages"]["myproject"] == {'git': 'git+https://${AUTH_USER}@github.com/user/myproject.git', 'ref': 'main'} + assert p.pipfile["packages"]["myproject"] == { + "git": "git+https://${AUTH_USER}@github.com/user/myproject.git", + "ref": "main", + } diff --git a/tests/integration/test_install_basic.py b/tests/integration/test_install_basic.py index ee5f687850..cc16b5a6fa 100644 --- a/tests/integration/test_install_basic.py +++ b/tests/integration/test_install_basic.py @@ -92,7 +92,7 @@ def test_install_without_dev(pipenv_instance_private_pypi): @pytest.mark.basic @pytest.mark.install def test_install_with_version_req_default_operator(pipenv_instance_private_pypi): - """Ensure that running `pipenv install` work when spec is package = "X.Y.Z". """ + """Ensure that running `pipenv install` work when spec is package = "X.Y.Z".""" with pipenv_instance_private_pypi() as p: with open(p.pipfile_path, "w") as f: contents = """ @@ -163,7 +163,9 @@ def test_pinned_pipfile(pipenv_instance_pypi): @pytest.mark.install @pytest.mark.resolver @pytest.mark.backup_resolver -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Package does not work with Python 3.12") +@pytest.mark.skipif( + sys.version_info >= (3, 12), reason="Package does not work with Python 3.12" +) def test_backup_resolver(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: with open(p.pipfile_path, "w") as f: @@ -232,15 +234,10 @@ def test_bad_packages(pipenv_instance_private_pypi): @pytest.mark.install @pytest.mark.requirements def test_requirements_to_pipfile(pipenv_instance_private_pypi): - with pipenv_instance_private_pypi(pipfile=False) as p: - # Write a requirements file with open("requirements.txt", "w") as f: - f.write( - f"-i {p.index_url}\n" - "requests[socks]==2.19.1\n" - ) + f.write(f"-i {p.index_url}\nrequests[socks]==2.19.1\n") c = p.pipenv("install") assert c.returncode == 0 @@ -251,8 +248,8 @@ def test_requirements_to_pipfile(pipenv_instance_private_pypi): assert "requests" in p.pipfile["packages"] assert "extras" in p.pipfile["packages"]["requests"] assert not any( - source['url'] == 'https://private.pypi.org/simple' - for source in p.pipfile['source'] + source["url"] == "https://private.pypi.org/simple" + for source in p.pipfile["source"] ) # assert stuff in lockfile assert "requests" in p.lockfile["default"] @@ -301,8 +298,7 @@ def test_clean_on_empty_venv(pipenv_instance_pypi): @pytest.mark.basic @pytest.mark.install def test_install_does_not_extrapolate_environ(pipenv_instance_private_pypi): - """Ensure environment variables are not expanded in lock file. - """ + """Ensure environment variables are not expanded in lock file.""" with temp_environ(), pipenv_instance_private_pypi() as p: os.environ["PYPI_URL"] = p.pypi @@ -344,8 +340,7 @@ def test_editable_no_args(pipenv_instance_pypi): @pytest.mark.install @pytest.mark.virtualenv def test_install_venv_project_directory(pipenv_instance_pypi): - """Test the project functionality during virtualenv creation. - """ + """Test the project functionality during virtualenv creation.""" with pipenv_instance_pypi() as p, temp_environ(), TemporaryDirectory( prefix="pipenv-", suffix="temp_workon_home" ) as workon_home: @@ -392,7 +387,7 @@ def test_install_creates_pipfile(pipenv_instance_pypi): assert c.returncode == 0 assert os.path.isfile(p.pipfile_path) python_version = str(sys.version_info.major) + "." + str(sys.version_info.minor) - assert p.pipfile["requires"] == {'python_version': python_version} + assert p.pipfile["requires"] == {"python_version": python_version} @pytest.mark.basic @@ -404,9 +399,10 @@ def test_create_pipfile_requires_python_full_version(pipenv_instance_private_pyp c = p.pipenv(f"--python {python_full_version}") assert c.returncode == 0 assert p.pipfile["requires"] == { - 'python_full_version': python_full_version, - 'python_version': python_version - } + "python_full_version": python_full_version, + "python_version": python_version, + } + @pytest.mark.basic @pytest.mark.install @@ -415,8 +411,9 @@ def test_install_with_pipfile_including_exact_python_version(pipenv_instance_pyp valid_version = f"{sys.version_info.major}.{sys.version_info.minor}" with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: - f.write(f""" + with open(p.pipfile_path, "w") as f: + f.write( + f""" [[source]] url = "https://test.pypi.org/simple" verify_ssl = true @@ -427,7 +424,8 @@ def test_install_with_pipfile_including_exact_python_version(pipenv_instance_pyp [requires] python_version = "{valid_version}" -""") +""" + ) c = p.pipenv("install") assert c.returncode == 0 @@ -437,6 +435,7 @@ def test_install_with_pipfile_including_exact_python_version(pipenv_instance_pyp c = p.pipenv("--rm") assert c.returncode == 0 + @pytest.mark.basic @pytest.mark.install @pytest.mark.virtualenv @@ -450,8 +449,9 @@ def test_install_with_pipfile_including_invalid_python_version(pipenv_instance_p with pipenv_instance_pypi() as p: for version in invalid_versions: - with open(p.pipfile_path, 'w') as f: - f.write(f""" + with open(p.pipfile_path, "w") as f: + f.write( + f""" [[source]] url = "https://test.pypi.org/simple" verify_ssl = true @@ -462,7 +462,8 @@ def test_install_with_pipfile_including_invalid_python_version(pipenv_instance_p [requires] python_version = "{version}" -""") +""" + ) c = p.pipenv("install") assert c.returncode != 0 @@ -489,7 +490,7 @@ def test_install_package_with_dots(pipenv_instance_private_pypi): @pytest.mark.install def test_rewrite_outline_table(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "{}" @@ -502,7 +503,9 @@ def test_rewrite_outline_table(pipenv_instance_private_pypi): [packages.requests] version = "*" extras = ["socks"] - """.format(p.index_url, "{version = \"*\"}").strip() + """.format( + p.index_url, '{version = "*"}' + ).strip() f.write(contents) c = p.pipenv("install colorama") assert c.returncode == 0 @@ -518,7 +521,7 @@ def test_rewrite_outline_table(pipenv_instance_private_pypi): @pytest.mark.install def test_rewrite_outline_table_ooo(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "{}" @@ -535,7 +538,9 @@ def test_rewrite_outline_table_ooo(pipenv_instance_private_pypi): [packages.requests] version = "*" extras = ["socks"] - """.format(p.index_url, "{version = \"*\"}").strip() + """.format( + p.index_url, '{version = "*"}' + ).strip() f.write(contents) c = p.pipenv("install colorama") assert c.returncode == 0 @@ -553,7 +558,6 @@ def test_install_dev_use_default_constraints(pipenv_instance_private_pypi): # See https://github.com/pypa/pipenv/issues/4371 # See https://github.com/pypa/pipenv/issues/2987 with pipenv_instance_private_pypi() as p: - c = p.pipenv("install requests==2.14.0") assert c.returncode == 0 assert "requests" in p.lockfile["default"] @@ -578,21 +582,27 @@ def test_install_dev_use_default_constraints(pipenv_instance_private_pypi): @pytest.mark.install @pytest.mark.needs_internet def test_install_does_not_exclude_packaging(pipenv_instance_pypi): - """Ensure that running `pipenv install` doesn't exclude packaging when its required. """ + """Ensure that running `pipenv install` doesn't exclude packaging when its required.""" with pipenv_instance_pypi() as p: c = p.pipenv("install dataclasses-json") assert c.returncode == 0 - c = p.pipenv("""run python -c "from dataclasses_json import DataClassJsonMixin" """) + c = p.pipenv( + """run python -c "from dataclasses_json import DataClassJsonMixin" """ + ) assert c.returncode == 0 @pytest.mark.basic @pytest.mark.install @pytest.mark.needs_internet -@pytest.mark.skip(reason="pip 23.3 now vendors in truststore and so test assumptions invalid ") +@pytest.mark.skip( + reason="pip 23.3 now vendors in truststore and so test assumptions invalid " +) def test_install_will_supply_extra_pip_args(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv("""install -v dataclasses-json --extra-pip-args="--use-feature=truststore --proxy=test" """) + c = p.pipenv( + """install -v dataclasses-json --extra-pip-args="--use-feature=truststore --proxy=test" """ + ) assert c.returncode == 1 assert "truststore feature" in c.stdout @@ -601,7 +611,7 @@ def test_install_will_supply_extra_pip_args(pipenv_instance_pypi): @pytest.mark.install @pytest.mark.needs_internet def test_install_tarball_is_actually_installed(pipenv_instance_pypi): - """ Test case for Issue 5326""" + """Test case for Issue 5326""" with pipenv_instance_pypi() as p: with open(p.pipfile_path, "w") as f: contents = """ @@ -689,3 +699,30 @@ def test_category_not_sorted_without_directive(pipenv_instance_private_pypi): "colorama", "build", ] + + +@pytest.mark.basic +@pytest.mark.install +def test_category_sorted_with_directive_when_insalling_with_extras( + pipenv_instance_private_pypi, +): + with pipenv_instance_private_pypi() as p: + with open(p.pipfile_path, "w+") as f: + contents = """ +[pipenv] +sort_pipfile = true + +[packages] +atomicwrites = "*" +six = "*" + """.strip() + f.write(contents) + c = p.pipenv("install requests[socks]") + assert c.returncode == 0 + assert "requests" in p.pipfile["packages"] + assert "extras" in p.pipfile["packages"]["requests"] + assert list(p.pipfile["packages"].keys()) == [ + "atomicwrites", + "requests", + "six", + ] diff --git a/tests/integration/test_install_categories.py b/tests/integration/test_install_categories.py index 353b42a859..f96293c719 100644 --- a/tests/integration/test_install_categories.py +++ b/tests/integration/test_install_categories.py @@ -81,9 +81,10 @@ def test_multiple_category_install_from_requirements(pipenv_instance_private_pyp @pytest.mark.install @pytest.mark.local @pytest.mark.skipif(sys.version_info >= (3, 12), reason="test is not 3.12 compatible") -def test_multiple_category_install_proceeds_in_order_specified(pipenv_instance_private_pypi): - """Ensure -e .[extras] installs. - """ +def test_multiple_category_install_proceeds_in_order_specified( + pipenv_instance_private_pypi, +): + """Ensure -e .[extras] installs.""" with pipenv_instance_private_pypi() as p: setup_py = os.path.join(p.path, "setup.py") with open(setup_py, "w") as fh: @@ -103,18 +104,22 @@ def test_multiple_category_install_proceeds_in_order_specified(pipenv_instance_p ) """.strip() fh.write(contents) - with open(os.path.join(p.path, 'Pipfile'), 'w') as fh: - fh.write(""" + with open(os.path.join(p.path, "Pipfile"), "w") as fh: + fh.write( + """ [packages] testpipenv = {path = ".", editable = true, skip_resolver = true} [prereq] six = "*" - """.strip()) + """.strip() + ) c = p.pipenv("lock -v") assert c.returncode == 0 assert "testpipenv" in p.lockfile["default"] assert "testpipenv" not in p.lockfile["prereq"] assert "six" in p.lockfile["prereq"] - c = p.pipenv('sync --categories="prereq packages" --extra-pip-args="--no-build-isolation" -v') + c = p.pipenv( + 'sync --categories="prereq packages" --extra-pip-args="--no-build-isolation" -v' + ) assert c.returncode == 0 diff --git a/tests/integration/test_install_markers.py b/tests/integration/test_install_markers.py index 98c3ed9a9f..8d4f4bd8b8 100644 --- a/tests/integration/test_install_markers.py +++ b/tests/integration/test_install_markers.py @@ -10,9 +10,8 @@ @pytest.mark.markers def test_package_environment_markers(pipenv_instance_private_pypi): - with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "{}" @@ -23,16 +22,22 @@ def test_package_environment_markers(pipenv_instance_private_pypi): fake_package = {} [dev-packages] - """.format(p.index_url, "{version = \"*\", markers=\"os_name=='splashwear'\", index=\"testindex\"}").strip() + """.format( + p.index_url, + '{version = "*", markers="os_name==\'splashwear\'", index="testindex"}', + ).strip() f.write(contents) - c = p.pipenv('install -v') + c = p.pipenv("install -v") assert c.returncode == 0 - assert 'markers' in p.lockfile['default']['fake_package'], p.lockfile["default"] - assert p.lockfile['default']['fake_package']['markers'] == "os_name == 'splashwear'" - assert p.lockfile['default']['fake_package']['hashes'] == [ - 'sha256:1531e01a7f306f496721f425c8404f3cfd8d4933ee6daf4668fcc70059b133f3', - 'sha256:cf83dc3f6c34050d3360fbdf655b2652c56532e3028b1c95202611ba1ebdd624'] + assert "markers" in p.lockfile["default"]["fake_package"], p.lockfile["default"] + assert ( + p.lockfile["default"]["fake_package"]["markers"] == "os_name == 'splashwear'" + ) + assert p.lockfile["default"]["fake_package"]["hashes"] == [ + "sha256:1531e01a7f306f496721f425c8404f3cfd8d4933ee6daf4668fcc70059b133f3", + "sha256:cf83dc3f6c34050d3360fbdf655b2652c56532e3028b1c95202611ba1ebdd624", + ] c = p.pipenv('run python -c "import fake_package;"') assert c.returncode == 1 @@ -45,15 +50,17 @@ def test_platform_python_implementation_marker(pipenv_instance_private_pypi): incorrectly. """ with pipenv_instance_private_pypi() as p: - c = p.pipenv('install depends-on-marked-package') + c = p.pipenv("install depends-on-marked-package") assert c.returncode == 0 # depends-on-marked-package has an install_requires of # 'pytz; platform_python_implementation=="CPython"' # Verify that that marker shows up in our lockfile unaltered. - assert 'pytz' in p.lockfile['default'] - assert p.lockfile['default']['pytz'].get('markers') == \ - "platform_python_implementation == 'CPython'" + assert "pytz" in p.lockfile["default"] + assert ( + p.lockfile["default"]["pytz"].get("markers") + == "platform_python_implementation == 'CPython'" + ) @flaky @@ -61,18 +68,17 @@ def test_platform_python_implementation_marker(pipenv_instance_private_pypi): @pytest.mark.markers @pytest.mark.install def test_specific_package_environment_markers(pipenv_instance_pypi): - with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] six = {version = "*", os_name = "== 'splashwear'"} """.strip() f.write(contents) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 - assert 'markers' in p.lockfile['default']['six'] + assert "markers" in p.lockfile["default"]["six"] c = p.pipenv('run python -c "import six;"') assert c.returncode == 1 @@ -81,10 +87,9 @@ def test_specific_package_environment_markers(pipenv_instance_pypi): @flaky @pytest.mark.markers def test_top_level_overrides_environment_markers(pipenv_instance_pypi): - """Top-level environment markers should take precedence. - """ + """Top-level environment markers should take precedence.""" with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] apscheduler = "*" @@ -92,10 +97,14 @@ def test_top_level_overrides_environment_markers(pipenv_instance_pypi): """.strip() f.write(contents) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 - assert "markers" in p.lockfile['default']['funcsigs'], p.lockfile['default']['funcsigs'] - assert p.lockfile['default']['funcsigs']['markers'] == "os_name == 'splashwear'", p.lockfile['default']['funcsigs'] + assert "markers" in p.lockfile["default"]["funcsigs"], p.lockfile["default"][ + "funcsigs" + ] + assert ( + p.lockfile["default"]["funcsigs"]["markers"] == "os_name == 'splashwear'" + ), p.lockfile["default"]["funcsigs"] @flaky @@ -109,7 +118,7 @@ def test_global_overrides_environment_markers(pipenv_instance_private_pypi): also specified as an unconditional dep, its markers should be empty. """ with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] url = "{p.index_url}" @@ -122,10 +131,10 @@ def test_global_overrides_environment_markers(pipenv_instance_private_pypi): """.strip() f.write(contents) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 - assert p.lockfile['default']['funcsigs'].get('markers', '') == '' + assert p.lockfile["default"]["funcsigs"].get("markers", "") == "" @flaky @@ -140,13 +149,13 @@ def test_resolver_unique_markers(pipenv_instance_pypi): This verifies that we clean that successfully. """ with pipenv_instance_pypi() as p: - c = p.pipenv('install vcrpy==2.0.1') + c = p.pipenv("install vcrpy==2.0.1") assert c.returncode == 0 - assert 'yarl' in p.lockfile['default'] - yarl = p.lockfile['default']['yarl'] - assert 'markers' in yarl + assert "yarl" in p.lockfile["default"] + yarl = p.lockfile["default"]["yarl"] + assert "markers" in yarl # Two possible marker sets are ok here - assert yarl['markers'] in [ + assert yarl["markers"] in [ "python_version in '3.4, 3.5, 3.6'", "python_version >= '3.4'", "python_version >= '3.5'", # yarl 1.3.0 requires python 3.5.3 @@ -158,8 +167,9 @@ def test_resolver_unique_markers(pipenv_instance_pypi): @pytest.mark.needs_internet def test_environment_variable_value_does_not_change_hash(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p, temp_environ(): - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [[source]] url = 'https://${PYPI_USERNAME}:${PYPI_PASSWORD}@pypi.org/simple' verify_ssl = true @@ -167,14 +177,15 @@ def test_environment_variable_value_does_not_change_hash(pipenv_instance_private [packages] six = "*" -""") +""" + ) project = Project() - os.environ['PYPI_USERNAME'] = 'whatever' - os.environ['PYPI_PASSWORD'] = 'pass' + os.environ["PYPI_USERNAME"] = "whatever" + os.environ["PYPI_PASSWORD"] = "pass" assert project.get_lockfile_hash() is None - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 lock_hash = project.get_lockfile_hash() assert lock_hash is not None @@ -183,9 +194,9 @@ def test_environment_variable_value_does_not_change_hash(pipenv_instance_private assert c.returncode == 0 assert project.get_lockfile_hash() == project.calculate_pipfile_hash() - os.environ['PYPI_PASSWORD'] = 'pass2' + os.environ["PYPI_PASSWORD"] = "pass2" assert project.get_lockfile_hash() == project.calculate_pipfile_hash() - with open(p.pipfile_path, 'a') as f: + with open(p.pipfile_path, "a") as f: f.write('requests = "==2.14.0"\n') assert project.get_lockfile_hash() != project.calculate_pipfile_hash() diff --git a/tests/integration/test_install_misc.py b/tests/integration/test_install_misc.py index 1fb0ff50e3..b7d532b89f 100644 --- a/tests/integration/test_install_misc.py +++ b/tests/integration/test_install_misc.py @@ -10,7 +10,7 @@ def test_install_uri_with_extras(pipenv_instance_pypi): server = DEFAULT_PRIVATE_PYPI_SERVER.replace("/simple", "") file_uri = f"{server}/packages/plette/plette-0.2.2-py2.py3-none-any.whl" with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] url = "{p.index_url}" diff --git a/tests/integration/test_install_twists.py b/tests/integration/test_install_twists.py index b4db8555ee..c6e30aff30 100644 --- a/tests/integration/test_install_twists.py +++ b/tests/integration/test_install_twists.py @@ -40,8 +40,7 @@ def test_local_path_issue_6016(pipenv_instance_pypi): @pytest.mark.install @pytest.mark.local def test_local_extras_install(pipenv_instance_pypi): - """Ensure -e .[extras] installs. - """ + """Ensure -e .[extras] installs.""" with pipenv_instance_pypi() as p: setup_py = os.path.join(p.path, "setup.py") with open(setup_py, "w") as fh: @@ -62,13 +61,15 @@ def test_local_extras_install(pipenv_instance_pypi): """.strip() fh.write(contents) line = "-e .[dev]" - with open(os.path.join(p.path, 'Pipfile'), 'w') as fh: - fh.write(""" + with open(os.path.join(p.path, "Pipfile"), "w") as fh: + fh.write( + """ [packages] testpipenv = {path = ".", editable = true, extras = ["dev"]} [dev-packages] - """.strip()) + """.strip() + ) # project.write_toml({"packages": pipfile, "dev-packages": {}}) c = p.pipenv("install") assert c.returncode == 0 @@ -115,20 +116,22 @@ def helper_dependency_links_install_make_setup(pipenv_instance, deplink): @staticmethod def helper_dependency_links_install_test(pipenv_instance, deplink): - TestDirectDependencies.helper_dependency_links_install_make_setup(pipenv_instance, deplink) + TestDirectDependencies.helper_dependency_links_install_make_setup( + pipenv_instance, deplink + ) c = pipenv_instance.pipenv("install -v -e .") assert c.returncode == 0 assert "six" in pipenv_instance.lockfile["default"] - @pytest.mark.skip(reason="This test modifies os.environment which has side effects on other tests") + @pytest.mark.skip( + reason="This test modifies os.environment which has side effects on other tests" + ) def test_https_dependency_links_install(self, pipenv_instance_pypi): - """Ensure dependency_links are parsed and installed (needed for private repo dependencies). - """ + """Ensure dependency_links are parsed and installed (needed for private repo dependencies).""" with temp_environ(), pipenv_instance_pypi() as p: - os.environ["PIP_NO_BUILD_ISOLATION"] = '1' + os.environ["PIP_NO_BUILD_ISOLATION"] = "1" TestDirectDependencies.helper_dependency_links_install_test( - p, - 'six@ git+https://github.com/benjaminp/six@1.11.0' + p, "six@ git+https://github.com/benjaminp/six@1.11.0" ) @@ -177,8 +180,8 @@ def test_local_package(pipenv_instance_private_pypi, testsroot): import tarfile with tarfile.open(copy_to, "r:gz") as tgz: - def is_within_directory(directory, target): + def is_within_directory(directory, target): abs_directory = os.path.abspath(directory) abs_target = os.path.abspath(target) @@ -187,7 +190,6 @@ def is_within_directory(directory, target): return prefix == abs_directory def safe_extract(tar, path=".", members=None, *, numeric_owner=False): - for member in tar.getmembers(): member_path = os.path.join(path, member.name) if not is_within_directory(path, member_path): @@ -195,7 +197,6 @@ def safe_extract(tar, path=".", members=None, *, numeric_owner=False): tar.extractall(path, members, numeric_owner) - safe_extract(tgz, path=p.path) c = p.pipenv(f"install -e {package}") assert c.returncode == 0 @@ -253,7 +254,9 @@ def test_install_local_uri_special_character(pipenv_instance_private_pypi, tests @pytest.mark.run @pytest.mark.files @pytest.mark.install -def test_multiple_editable_packages_should_not_race(pipenv_instance_private_pypi, testsroot): +def test_multiple_editable_packages_should_not_race( + pipenv_instance_private_pypi, testsroot +): """Test for a race condition that can occur when installing multiple 'editable' packages at once, and which causes some of them to not be importable. @@ -280,12 +283,14 @@ def test_multiple_editable_packages_should_not_race(pipenv_instance_private_pypi source_path = p._pipfile.get_fixture_path(f"git/{pkg_name}/") shutil.copytree(source_path, pkg_name) - pipfile_string += f'"{pkg_name}" = {{path = "./{pkg_name}", editable = true}}\n' + pipfile_string += ( + f'"{pkg_name}" = {{path = "./{pkg_name}", editable = true}}\n' + ) - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: f.write(pipfile_string.strip()) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 c = p.pipenv('run python -c "import jinja2, six"') @@ -293,11 +298,13 @@ def test_multiple_editable_packages_should_not_race(pipenv_instance_private_pypi @pytest.mark.skipif( - os.name == 'nt' and sys.version_info[:2] == (3, 8), - reason="Seems to work on 3.8 but not via the CI" + os.name == "nt" and sys.version_info[:2] == (3, 8), + reason="Seems to work on 3.8 but not via the CI", ) @pytest.mark.outdated -def test_outdated_should_compare_postreleases_without_failing(pipenv_instance_private_pypi): +def test_outdated_should_compare_postreleases_without_failing( + pipenv_instance_private_pypi, +): with pipenv_instance_private_pypi() as p: c = p.pipenv("install ibm-db-sa-py3==0.3.0") assert c.returncode == 0 @@ -310,21 +317,26 @@ def test_outdated_should_compare_postreleases_without_failing(pipenv_instance_pr assert "out-of-date" in c.stdout -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Package does not work with Python 3.12") +@pytest.mark.skipif( + sys.version_info >= (3, 12), reason="Package does not work with Python 3.12" +) def test_install_remote_wheel_file_with_extras(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv("install fastapi[dev]@https://files.pythonhosted.org/packages/4e/1a/04887c641b67e6649bde845b9a631f73a7abfbe3afda83957e09b95d88eb/fastapi-0.95.2-py3-none-any.whl") + c = p.pipenv( + "install fastapi[dev]@https://files.pythonhosted.org/packages/4e/1a/04887c641b67e6649bde845b9a631f73a7abfbe3afda83957e09b95d88eb/fastapi-0.95.2-py3-none-any.whl" + ) assert c.returncode == 0 assert "ruff" in p.lockfile["default"] assert "pre-commit" in p.lockfile["default"] assert "uvicorn" in p.lockfile["default"] + @pytest.mark.install @pytest.mark.skip_lock @pytest.mark.needs_internet def test_install_skip_lock(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "{}" @@ -332,9 +344,11 @@ def test_install_skip_lock(pipenv_instance_private_pypi): name = "pypi" [packages] six = {} - """.format(p.index_url, '{version = "*", index = "pypi"}').strip() + """.format( + p.index_url, '{version = "*", index = "pypi"}' + ).strip() f.write(contents) - c = p.pipenv('install --skip-lock') + c = p.pipenv("install --skip-lock") assert c.returncode == 0 c = p.pipenv('run python -c "import six"') assert c.returncode == 0 diff --git a/tests/integration/test_install_uri.py b/tests/integration/test_install_uri.py index 71f89f2e26..9794c2fc76 100644 --- a/tests/integration/test_install_uri.py +++ b/tests/integration/test_install_uri.py @@ -12,13 +12,17 @@ @pytest.mark.needs_internet def test_basic_vcs_install_with_env_var(pipenv_instance_pypi): from pipenv.cli import cli - from click.testing import CliRunner # not thread safe but macos and linux will expand the env var otherwise + from click.testing import ( + CliRunner, + ) # not thread safe but macos and linux will expand the env var otherwise with pipenv_instance_pypi() as p: # edge case where normal package starts with VCS name shouldn't be flagged as vcs os.environ["GIT_HOST"] = "github.com" cli_runner = CliRunner(mix_stderr=False) - c = cli_runner.invoke(cli, "install -v git+https://${GIT_HOST}/benjaminp/six.git@1.11.0 gitdb2") + c = cli_runner.invoke( + cli, "install -v git+https://${GIT_HOST}/benjaminp/six.git@1.11.0 gitdb2" + ) assert c.exit_code == 0 assert all(package in p.pipfile["packages"] for package in ["six", "gitdb2"]) assert "git" in p.pipfile["packages"]["six"] @@ -37,9 +41,7 @@ def test_urls_work(pipenv_instance_pypi): with pipenv_instance_pypi() as p: # the library this installs is "django-cms" url = "https://github.com/lidatong/dataclasses-json/archive/refs/tags/v0.5.7.zip" - c = p.pipenv( - f"install {url}" - ) + c = p.pipenv(f"install {url}") assert c.returncode == 0 dep = list(p.pipfile["packages"].values())[0] @@ -53,7 +55,12 @@ def test_urls_work(pipenv_instance_pypi): @pytest.mark.files def test_file_urls_work(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - whl = Path(Path(__file__).resolve().parent.parent / "pypi" / "six" / "six-1.11.0-py2.py3-none-any.whl") + whl = Path( + Path(__file__).resolve().parent.parent + / "pypi" + / "six" + / "six-1.11.0-py2.py3-none-any.whl" + ) try: whl = whl.resolve() @@ -64,12 +71,11 @@ def test_file_urls_work(pipenv_instance_pypi): assert c.returncode == 0 assert "six" in p.pipfile["packages"] assert "file" in p.pipfile["packages"]["six"] - assert 'six' in p.lockfile["default"] - assert 'file' in p.lockfile["default"]["six"] + assert "six" in p.lockfile["default"] + assert "file" in p.lockfile["default"]["six"] assert "six-1.11.0-py2.py3-none-any.whl" in p.lockfile["default"]["six"]["file"] - @pytest.mark.e @pytest.mark.vcs @pytest.mark.urls @@ -90,9 +96,7 @@ def test_vcs_install(pipenv_instance_pypi): @pytest.mark.needs_internet def test_install_git_tag(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - c = p.pipenv( - "install git+https://github.com/benjaminp/six.git@1.11.0" - ) + c = p.pipenv("install git+https://github.com/benjaminp/six.git@1.11.0") assert c.returncode == 0 assert "six" in p.pipfile["packages"] assert "six" in p.lockfile["default"] @@ -108,7 +112,9 @@ def test_install_git_tag(pipenv_instance_private_pypi): @pytest.mark.index @pytest.mark.install @pytest.mark.needs_internet -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Package does not work with Python 3.12") +@pytest.mark.skipif( + sys.version_info >= (3, 12), reason="Package does not work with Python 3.12" +) def test_install_named_index_alias(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: with open(p.pipfile_path, "w") as f: @@ -137,7 +143,9 @@ def test_install_named_index_alias(pipenv_instance_private_pypi): @pytest.mark.index @pytest.mark.install @pytest.mark.needs_internet -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Package does not work with Python 3.12") +@pytest.mark.skipif( + sys.version_info >= (3, 12), reason="Package does not work with Python 3.12" +) def test_install_specifying_index_url(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: with open(p.pipfile_path, "w") as f: @@ -156,7 +164,9 @@ def test_install_specifying_index_url(pipenv_instance_private_pypi): install_search_all_sources = true """.strip() f.write(contents) - c = p.pipenv("install pipenv-test-private-package --index https://test.pypi.org/simple") + c = p.pipenv( + "install pipenv-test-private-package --index https://test.pypi.org/simple" + ) assert c.returncode == 0 pipfile = p.pipfile assert pipfile["source"][1]["url"] == "https://test.pypi.org/simple" @@ -187,9 +197,7 @@ def test_install_local_vcs_not_in_lockfile(pipenv_instance_pypi): @pytest.mark.needs_internet def test_get_vcs_refs(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - c = p.pipenv( - "install -e git+https://github.com/benjaminp/six.git@1.9.0#egg=six" - ) + c = p.pipenv("install -e git+https://github.com/benjaminp/six.git@1.9.0#egg=six") assert c.returncode == 0 assert "six" in p.pipfile["packages"] assert "six" in p.lockfile["default"] @@ -239,8 +247,13 @@ def test_vcs_entry_supersedes_non_vcs(pipenv_instance_pypi): installed_packages = ["Flask", "Jinja2"] assert all(k in p.pipfile["packages"] for k in installed_packages) assert all(k.lower() in p.lockfile["default"] for k in installed_packages) - assert all(k in p.lockfile["default"]["jinja2"] for k in ["ref", "git"]), str(p.lockfile["default"]) - assert p.lockfile["default"]["jinja2"].get("ref") == "bbdafe33ce9f47e3cbfb9415619e354349f11243" + assert all(k in p.lockfile["default"]["jinja2"] for k in ["ref", "git"]), str( + p.lockfile["default"] + ) + assert ( + p.lockfile["default"]["jinja2"].get("ref") + == "bbdafe33ce9f47e3cbfb9415619e354349f11243" + ) assert p.lockfile["default"]["jinja2"]["git"] == f"{jinja2_uri}" @@ -251,7 +264,14 @@ def test_vcs_entry_supersedes_non_vcs(pipenv_instance_pypi): def test_vcs_can_use_markers(pipenv_instance_pypi): with pipenv_instance_pypi() as p: path = p._pipfile.get_fixture_path("git/six/") - p._pipfile.install("six", {"git": f"{path.as_uri()}", "ref": "1.11.0", "markers": "sys_platform == 'linux'"}) + p._pipfile.install( + "six", + { + "git": f"{path.as_uri()}", + "ref": "1.11.0", + "markers": "sys_platform == 'linux'", + }, + ) assert "six" in p.pipfile["packages"] c = p.pipenv("install") assert c.returncode == 0 diff --git a/tests/integration/test_lock.py b/tests/integration/test_lock.py index 4d6fc33878..7f3ed3af20 100644 --- a/tests/integration/test_lock.py +++ b/tests/integration/test_lock.py @@ -11,11 +11,11 @@ @pytest.mark.lock @pytest.mark.requirements def test_lock_handle_eggs(pipenv_instance_private_pypi): - """Ensure locking works with packages providing egg formats. - """ + """Ensure locking works with packages providing egg formats.""" with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: - f.write(f""" + with open(p.pipfile_path, "w") as f: + f.write( + f""" [[source]] url = "{p.index_url}" verify_ssl = false @@ -23,11 +23,12 @@ def test_lock_handle_eggs(pipenv_instance_private_pypi): [packages] RandomWords = "*" - """) - c = p.pipenv('lock --verbose') + """ + ) + c = p.pipenv("lock --verbose") assert c.returncode == 0 - assert 'randomwords' in p.lockfile['default'] - assert p.lockfile['default']['randomwords']['version'] == '==0.2.1' + assert "randomwords" in p.lockfile["default"] + assert p.lockfile["default"]["randomwords"]["version"] == "==0.2.1" @pytest.mark.lock @@ -48,7 +49,9 @@ def test_lock_gathers_pyproject_dependencies(pipenv_instance_pypi): f.write(contents) # Write the pyproject.toml - pyproject_toml_path = os.path.join(os.path.dirname(p.pipfile_path), "pyproject.toml") + pyproject_toml_path = os.path.join( + os.path.dirname(p.pipfile_path), "pyproject.toml" + ) with open(pyproject_toml_path, "w") as f: contents = """ [build-system] @@ -69,13 +72,11 @@ def test_lock_gathers_pyproject_dependencies(pipenv_instance_pypi): assert "six" in p.lockfile["default"] - @pytest.mark.lock @pytest.mark.requirements def test_lock_requirements_file(pipenv_instance_private_pypi): - with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] urllib3 = "==1.23" @@ -88,12 +89,12 @@ def test_lock_requirements_file(pipenv_instance_private_pypi): dev_req_list = ("colorama==0.3.9",) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 - default = p.pipenv('requirements') + default = p.pipenv("requirements") assert default.returncode == 0 - dev = p.pipenv('requirements --dev-only') + dev = p.pipenv("requirements --dev-only") for req in req_list: assert req in default.stdout @@ -104,19 +105,20 @@ def test_lock_requirements_file(pipenv_instance_private_pypi): @pytest.mark.lock def test_lock_includes_hashes_for_all_platforms(pipenv_instance_private_pypi): - """ Locking should include hashes for *all* platforms, not just the - platform we're running lock on. """ + """Locking should include hashes for *all* platforms, not just the + platform we're running lock on.""" - #releases = pytest_pypi.app.packages['yarl'].releases + # releases = pytest_pypi.app.packages['yarl'].releases + releases = { + "yarl-1.3.0-cp35-cp35m-manylinux1_x86_64.whl": "3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb", + "yarl-1.3.0-cp35-cp35m-win_amd64.whl": "b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310", + "yarl-1.3.0-cp36-cp36m-manylinux1_x86_64.whl": "5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842", + "yarl-1.3.0-cp36-cp36m-win_amd64.whl": "c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4", + "yarl-1.3.0-cp37-cp37m-win_amd64.whl": "73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0", + "yarl-1.3.0.tar.gz": "024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9", + } - releases = {'yarl-1.3.0-cp35-cp35m-manylinux1_x86_64.whl': '3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb', - 'yarl-1.3.0-cp35-cp35m-win_amd64.whl': 'b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310', - 'yarl-1.3.0-cp36-cp36m-manylinux1_x86_64.whl': '5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842', - 'yarl-1.3.0-cp36-cp36m-win_amd64.whl': 'c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4', - 'yarl-1.3.0-cp37-cp37m-win_amd64.whl': '73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0', - 'yarl-1.3.0.tar.gz': '024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9', - } def get_hash(release_name): # Convert a specific filename to a hash like what would show up in a Pipfile.lock. # For example: @@ -124,7 +126,7 @@ def get_hash(release_name): return f"sha256:{releases[release_name]}" with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] url = "{p.index_url}" @@ -136,18 +138,18 @@ def get_hash(release_name): """.strip() f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 lock = p.lockfile - assert 'yarl' in lock['default'] - assert set(lock['default']['yarl']['hashes']) == { - get_hash('yarl-1.3.0-cp35-cp35m-manylinux1_x86_64.whl'), - get_hash('yarl-1.3.0-cp35-cp35m-win_amd64.whl'), - get_hash('yarl-1.3.0-cp36-cp36m-manylinux1_x86_64.whl'), - get_hash('yarl-1.3.0-cp36-cp36m-win_amd64.whl'), - get_hash('yarl-1.3.0-cp37-cp37m-win_amd64.whl'), - get_hash('yarl-1.3.0.tar.gz'), + assert "yarl" in lock["default"] + assert set(lock["default"]["yarl"]["hashes"]) == { + get_hash("yarl-1.3.0-cp35-cp35m-manylinux1_x86_64.whl"), + get_hash("yarl-1.3.0-cp35-cp35m-win_amd64.whl"), + get_hash("yarl-1.3.0-cp36-cp36m-manylinux1_x86_64.whl"), + get_hash("yarl-1.3.0-cp36-cp36m-win_amd64.whl"), + get_hash("yarl-1.3.0-cp37-cp37m-win_amd64.whl"), + get_hash("yarl-1.3.0.tar.gz"), } @@ -157,7 +159,10 @@ def test_resolve_skip_unmatched_requirements(pipenv_instance_pypi): p._pipfile.add("missing-package", {"markers": "os_name=='FakeOS'"}) c = p.pipenv("lock") assert c.returncode == 0 - assert 'Could not find a matching version of missing-package; os_name == "FakeOS"' in c.stderr + assert ( + 'Could not find a matching version of missing-package; os_name == "FakeOS"' + in c.stderr + ) @pytest.mark.lock @@ -167,38 +172,40 @@ def test_complex_lock_with_vcs_deps(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: requests_uri = p._pipfile.get_fixture_path("git/requests").as_uri() dateutil_uri = p._pipfile.get_fixture_path("git/dateutil").as_uri() - with open(p.pipfile_path, 'w') as f: - contents = """ + with open(p.pipfile_path, "w") as f: + contents = ( + """ [packages] click = "==6.7" [dev-packages] requests = {git = "%s"} - """.strip() % requests_uri + """.strip() + % requests_uri + ) f.write(contents) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 lock = p.lockfile - assert 'requests' in lock['develop'] - assert 'click' in lock['default'] + assert "requests" in lock["develop"] + assert "click" in lock["default"] - c = p.pipenv(f'run pip install -e git+{dateutil_uri}#egg=python_dateutil') + c = p.pipenv(f"run pip install -e git+{dateutil_uri}#egg=python_dateutil") assert c.returncode == 0 lock = p.lockfile - assert 'requests' in lock['develop'] - assert 'click' in lock['default'] - assert 'python_dateutil' not in lock['default'] - assert 'python_dateutil' not in lock['develop'] + assert "requests" in lock["develop"] + assert "click" in lock["default"] + assert "python_dateutil" not in lock["default"] + assert "python_dateutil" not in lock["develop"] @pytest.mark.lock @pytest.mark.requirements def test_lock_with_prereleases(pipenv_instance_private_pypi): - with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] sqlalchemy = "==1.2.0b3" @@ -208,9 +215,9 @@ def test_lock_with_prereleases(pipenv_instance_private_pypi): """.strip() f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 - assert p.lockfile['default']['sqlalchemy']['version'] == '==1.2.0b3' + assert p.lockfile["default"]["sqlalchemy"]["version"] == "==1.2.0b3" @pytest.mark.lock @@ -220,17 +227,17 @@ def test_lock_with_prereleases(pipenv_instance_private_pypi): @flaky def test_complex_deps_lock_and_install_properly(pipenv_instance_pypi): # This uses the real PyPI because Maya has too many dependencies... - with pipenv_instance_pypi() as p, open(p.pipfile_path, 'w') as f: + with pipenv_instance_pypi() as p, open(p.pipfile_path, "w") as f: contents = """ [packages] maya = "*" """.strip() f.write(contents) - c = p.pipenv('lock --verbose') + c = p.pipenv("lock --verbose") assert c.returncode == 0 - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 @@ -238,22 +245,22 @@ def test_complex_deps_lock_and_install_properly(pipenv_instance_pypi): @pytest.mark.extras def test_lock_extras_without_install(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] requests = {version = "*", extras = ["socks"]} """.strip() f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 assert "requests" in p.lockfile["default"] assert "pysocks" in p.lockfile["default"] - assert "markers" not in p.lockfile["default"]['pysocks'] + assert "markers" not in p.lockfile["default"]["pysocks"] - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 - c = p.pipenv('requirements') + c = p.pipenv("requirements") assert c.returncode == 0 assert "extra == 'socks'" not in c.stdout.strip() @@ -265,7 +272,7 @@ def test_lock_extras_without_install(pipenv_instance_private_pypi): @pytest.mark.needs_internet def test_private_index_lock_requirements(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "https://pypi.org/simple" @@ -281,7 +288,7 @@ def test_private_index_lock_requirements(pipenv_instance_private_pypi): pipenv-test-private-package = {version = "*", index = "testpypi"} """.strip() f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 @@ -290,9 +297,11 @@ def test_private_index_lock_requirements(pipenv_instance_private_pypi): @pytest.mark.install # private indexes need to be uncached for resolution @pytest.mark.requirements @pytest.mark.needs_internet -def test_private_index_lock_requirements_for_not_canonical_package(pipenv_instance_private_pypi): +def test_private_index_lock_requirements_for_not_canonical_package( + pipenv_instance_private_pypi, +): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "https://pypi.org/simple" @@ -308,16 +317,15 @@ def test_private_index_lock_requirements_for_not_canonical_package(pipenv_instan pipenv_test_private_package = {version = "*", index = "testpypi"} """.strip() f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 @pytest.mark.index @pytest.mark.install def test_lock_updated_source(pipenv_instance_private_pypi): - with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "{url}/${{MY_ENV_VAR}}" @@ -326,16 +334,18 @@ def test_lock_updated_source(pipenv_instance_private_pypi): [packages] requests = "==2.14.0" - """.strip().format(url=p.pypi) + """.strip().format( + url=p.pypi + ) f.write(contents) with temp_environ(): - os.environ['MY_ENV_VAR'] = 'simple' - c = p.pipenv('lock') + os.environ["MY_ENV_VAR"] = "simple" + c = p.pipenv("lock") assert c.returncode == 0 - assert 'requests' in p.lockfile['default'] + assert "requests" in p.lockfile["default"] - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "{url}/simple" @@ -344,12 +354,14 @@ def test_lock_updated_source(pipenv_instance_private_pypi): [packages] requests = "==2.14.0" - """.strip().format(url=p.pypi) + """.strip().format( + url=p.pypi + ) f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 - assert 'requests' in p.lockfile['default'] + assert "requests" in p.lockfile["default"] @pytest.mark.vcs @@ -358,14 +370,17 @@ def test_lock_updated_source(pipenv_instance_private_pypi): def test_lock_editable_vcs_without_install(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: requests_uri = p._pipfile.get_fixture_path("git/six").as_uri() - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [packages] six = {git = "%s", editable = true} - """.strip() % requests_uri) - c = p.pipenv('lock') + """.strip() + % requests_uri + ) + c = p.pipenv("lock") assert c.returncode == 0 - assert 'six' in p.lockfile['default'] + assert "six" in p.lockfile["default"] @pytest.mark.vcs @@ -374,15 +389,21 @@ def test_lock_editable_vcs_without_install(pipenv_instance_private_pypi): def test_lock_editable_vcs_with_ref_in_git(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: requests_uri = p._pipfile.get_fixture_path("git/requests").as_uri() - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [packages] requests = {git = "%s@883caaf", editable = true} - """.strip() % requests_uri) - c = p.pipenv('lock') + """.strip() + % requests_uri + ) + c = p.pipenv("lock") assert c.returncode == 0 - assert requests_uri in p.lockfile['default']['requests']['git'] - assert p.lockfile['default']['requests']['ref'] == '883caaf145fbe93bd0d208a6b864de9146087312' + assert requests_uri in p.lockfile["default"]["requests"]["git"] + assert ( + p.lockfile["default"]["requests"]["ref"] + == "883caaf145fbe93bd0d208a6b864de9146087312" + ) @pytest.mark.vcs @@ -392,16 +413,19 @@ def test_lock_editable_vcs_with_ref_in_git(pipenv_instance_private_pypi): def test_lock_editable_vcs_with_extras_without_install(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: requests_uri = p._pipfile.get_fixture_path("git/requests").as_uri() - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [packages] requests = {git = "%s", editable = true, extras = ["socks"]} - """.strip() % requests_uri) - c = p.pipenv('lock') + """.strip() + % requests_uri + ) + c = p.pipenv("lock") assert c.returncode == 0 - assert 'requests' in p.lockfile['default'] - assert 'idna' in p.lockfile['default'] - assert 'certifi' in p.lockfile['default'] + assert "requests" in p.lockfile["default"] + assert "idna" in p.lockfile["default"] + assert "certifi" in p.lockfile["default"] assert "socks" in p.lockfile["default"]["requests"]["extras"] assert "version" not in p.lockfile["default"]["requests"] @@ -412,16 +436,19 @@ def test_lock_editable_vcs_with_extras_without_install(pipenv_instance_private_p def test_lock_editable_vcs_with_markers_without_install(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: requests_uri = p._pipfile.get_fixture_path("git/requests").as_uri() - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [packages] requests = {git = "%s", editable = true, markers = "python_version >= '2.6'"} - """.strip() % requests_uri) - c = p.pipenv('lock') + """.strip() + % requests_uri + ) + c = p.pipenv("lock") assert c.returncode == 0 - assert 'requests' in p.lockfile['default'] - assert 'idna' in p.lockfile['default'] - assert 'certifi' in p.lockfile['default'] + assert "requests" in p.lockfile["default"] + assert "idna" in p.lockfile["default"] + assert "certifi" in p.lockfile["default"] assert c.returncode == 0 @@ -429,22 +456,22 @@ def test_lock_editable_vcs_with_markers_without_install(pipenv_instance_private_ @pytest.mark.install def test_lockfile_corrupted(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - with open(p.lockfile_path, 'w') as f: - f.write('{corrupted}') - c = p.pipenv('install') + with open(p.lockfile_path, "w") as f: + f.write("{corrupted}") + c = p.pipenv("install") assert c.returncode == 0 - assert 'Pipfile.lock is corrupted' in c.stderr - assert p.lockfile['_meta'] + assert "Pipfile.lock is corrupted" in c.stderr + assert p.lockfile["_meta"] @pytest.mark.lock def test_lockfile_with_empty_dict(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - with open(p.lockfile_path, 'w') as f: - f.write('{}') - c = p.pipenv('install') + with open(p.lockfile_path, "w") as f: + f.write("{}") + c = p.pipenv("install") assert c.returncode == 0 - assert p.lockfile['_meta'] + assert p.lockfile["_meta"] @pytest.mark.vcs @@ -454,10 +481,9 @@ def test_vcs_lock_respects_top_level_pins(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: requests_uri = p._pipfile.get_fixture_path("git/requests").as_uri() - p._pipfile.add("requests", { - "editable": True, "git": f"{requests_uri}", - "ref": "v2.18.4" - }) + p._pipfile.add( + "requests", {"editable": True, "git": f"{requests_uri}", "ref": "v2.18.4"} + ) p._pipfile.add("urllib3", "==1.21.1") c = p.pipenv("lock") assert c.returncode == 0 @@ -479,17 +505,19 @@ def test_lock_after_update_source_name(pipenv_instance_pypi): [packages] six = "*" """.strip() - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: f.write(contents) c = p.pipenv("lock") assert c.returncode == 0 assert p.lockfile["default"]["six"]["index"] == "test" - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: f.write(contents.replace('name = "test"', 'name = "custom"')) c = p.pipenv("lock --clear") assert c.returncode == 0 assert "index" in p.lockfile["default"]["six"] - assert p.lockfile["default"]["six"]["index"] == "custom", Path(p.lockfile_path).read_text() + assert p.lockfile["default"]["six"]["index"] == "custom", Path( + p.lockfile_path + ).read_text() @pytest.mark.lock @@ -509,7 +537,7 @@ def test_lock_nested_direct_url(pipenv_instance_private_pypi): [packages] test_package = "*" """.strip() - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: f.write(contents) c = p.pipenv("lock") assert c.returncode == 0 @@ -522,18 +550,25 @@ def test_lock_nested_direct_url(pipenv_instance_private_pypi): @pytest.mark.needs_internet def test_lock_nested_vcs_direct_url(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - p._pipfile.add("pep508_package", { - "git": "https://github.com/techalchemy/test-project.git", - "editable": True, "ref": "master", - "subdirectory": "parent_folder/pep508-package" - }) + p._pipfile.add( + "pep508_package", + { + "git": "https://github.com/techalchemy/test-project.git", + "editable": True, + "ref": "master", + "subdirectory": "parent_folder/pep508-package", + }, + ) c = p.pipenv("lock") assert c.returncode == 0 assert "git" in p.lockfile["default"]["pep508-package"] assert "sibling-package" in p.lockfile["default"] assert "git" in p.lockfile["default"]["sibling-package"] assert "subdirectory" in p.lockfile["default"]["sibling-package"] - assert p.lockfile["default"]["sibling-package"]["subdirectory"] == "parent_folder/sibling_package" + assert ( + p.lockfile["default"]["sibling-package"]["subdirectory"] + == "parent_folder/sibling_package" + ) assert "version" not in p.lockfile["default"]["sibling-package"] @@ -568,7 +603,7 @@ def test_default_lock_overwrite_dev_lock(pipenv_instance_pypi): @pytest.mark.needs_internet def test_pipenv_respects_package_index_restrictions(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "https://pypi.org/simple" @@ -582,21 +617,28 @@ def test_pipenv_respects_package_index_restrictions(pipenv_instance_private_pypi [packages] requests = {requirement} - """.strip().format(url=p.index_url, requirement='{version="*", index="local"}') + """.strip().format( + url=p.index_url, requirement='{version="*", index="local"}' + ) f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 - assert 'requests' in p.lockfile['default'] - assert 'idna' in p.lockfile['default'] - assert 'certifi' in p.lockfile['default'] - assert 'urllib3' in p.lockfile['default'] - assert 'chardet' in p.lockfile['default'] + assert "requests" in p.lockfile["default"] + assert "idna" in p.lockfile["default"] + assert "certifi" in p.lockfile["default"] + assert "urllib3" in p.lockfile["default"] + assert "chardet" in p.lockfile["default"] # this is the newest version we have in our private pypi (but pypi.org has 2.27.1 at present) - expected_result = {'hashes': ['sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1', - 'sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a'], - 'index': 'local', 'version': '==2.19.1'} - assert p.lockfile['default']['requests'] == expected_result + expected_result = { + "hashes": [ + "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", + "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a", + ], + "index": "local", + "version": "==2.19.1", + } + assert p.lockfile["default"]["requests"] == expected_result @pytest.mark.dev @@ -606,7 +648,7 @@ def test_dev_lock_use_default_packages_as_constraint(pipenv_instance_private_pyp # See https://github.com/pypa/pipenv/issues/4371 # See https://github.com/pypa/pipenv/issues/2987 with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] url = "{p.index_url}" @@ -650,7 +692,7 @@ def test_lock_specific_named_category(pipenv_instance_private_pypi): [prereq] six = "*" """.strip() - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: f.write(contents) c = p.pipenv("lock --categories prereq") assert c.returncode == 0 @@ -661,6 +703,7 @@ def test_lock_specific_named_category(pipenv_instance_private_pypi): assert p.lockfile["prereq"]["six"]["index"] == "test" assert p.lockfile["default"]["requests"]["index"] == "test" + def test_pinned_pipfile_no_null_markers_when_extras(pipenv_instance_pypi): with pipenv_instance_pypi() as p: with open(p.pipfile_path, "w") as f: @@ -675,13 +718,14 @@ def test_pinned_pipfile_no_null_markers_when_extras(pipenv_instance_pypi): assert "dataclasses-json" in p.lockfile["default"] assert p.lockfile["default"]["dataclasses-json"].get("markers", "") is not None + @pytest.mark.index @pytest.mark.install # private indexes need to be uncached for resolution @pytest.mark.skip_lock @pytest.mark.needs_internet def test_private_index_skip_lock(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [[source]] url = "https://pypi.org/simple" @@ -700,5 +744,5 @@ def test_private_index_skip_lock(pipenv_instance_private_pypi): install_search_all_sources = true """.strip() f.write(contents) - c = p.pipenv('install --skip-lock') + c = p.pipenv("install --skip-lock") assert c.returncode == 0 diff --git a/tests/integration/test_lockfile.py b/tests/integration/test_lockfile.py index 2617fa8839..145c291d12 100644 --- a/tests/integration/test_lockfile.py +++ b/tests/integration/test_lockfile.py @@ -21,13 +21,11 @@ def pypi_lockfile(): yield lockfile -def test_git_branch_contains_slashes( - pipenv_instance_pypi, pypi_lockfile -): +def test_git_branch_contains_slashes(pipenv_instance_pypi, pypi_lockfile): pypi_lockfile["default"]["google-api-python-client"] = { "git": "https://github.com/thehesiod/google-api-python-client.git@thehesiod/batch-retries2", "markers": "python_version >= '3.7'", - "ref": "03803c21fc13a345e978f32775b2f2fa23c8e706" + "ref": "03803c21fc13a345e978f32775b2f2fa23c8e706", } with pipenv_instance_pypi() as p: @@ -40,14 +38,16 @@ def test_git_branch_contains_slashes( pip_installable_lines = requirements.requirements_from_lockfile( deps, include_hashes=False, include_markers=True ) - assert pip_installable_lines == ["google-api-python-client@ git+https://github.com/thehesiod/google-api-python-client.git@03803c21fc13a345e978f32775b2f2fa23c8e706"] + assert pip_installable_lines == [ + "google-api-python-client@ git+https://github.com/thehesiod/google-api-python-client.git@03803c21fc13a345e978f32775b2f2fa23c8e706" + ] def test_git_branch_contains_subdirectory_fragment(pipenv_instance_pypi, pypi_lockfile): pypi_lockfile["default"]["pep508_package"] = { "git": "https://github.com/techalchemy/test-project.git@master", "subdirectory": "parent_folder/pep508-package", - "ref": "03803c21fc13a345e978f32775b2f2fa23c8e706" + "ref": "03803c21fc13a345e978f32775b2f2fa23c8e706", } with pipenv_instance_pypi() as p: @@ -60,4 +60,6 @@ def test_git_branch_contains_subdirectory_fragment(pipenv_instance_pypi, pypi_lo pip_installable_lines = requirements.requirements_from_lockfile( deps, include_hashes=False, include_markers=True ) - assert pip_installable_lines == ['pep508_package@ git+https://github.com/techalchemy/test-project.git@03803c21fc13a345e978f32775b2f2fa23c8e706#subdirectory=parent_folder/pep508-package'] + assert pip_installable_lines == [ + "pep508_package@ git+https://github.com/techalchemy/test-project.git@03803c21fc13a345e978f32775b2f2fa23c8e706#subdirectory=parent_folder/pep508-package" + ] diff --git a/tests/integration/test_pipenv.py b/tests/integration/test_pipenv.py index 3fb69abda3..e0ec23b1a0 100644 --- a/tests/integration/test_pipenv.py +++ b/tests/integration/test_pipenv.py @@ -15,9 +15,8 @@ @pytest.mark.lock @pytest.mark.deploy def test_deploy_works(pipenv_instance_pypi): - with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] dataclasses-json = "==0.5.7" @@ -27,16 +26,16 @@ def test_deploy_works(pipenv_instance_pypi): pytest = "==4.6.9" """.strip() f.write(contents) - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] dataclasses-json = "==0.5.7" """.strip() f.write(contents) - c = p.pipenv('install --deploy') + c = p.pipenv("install --deploy") assert c.returncode > 0 @@ -44,29 +43,29 @@ def test_deploy_works(pipenv_instance_pypi): @pytest.mark.lock def test_update_locks(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: - c = p.pipenv('install jdcal==1.3') + c = p.pipenv("install jdcal==1.3") assert c.returncode == 0 - assert p.lockfile['default']['jdcal']['version'] == '==1.3' + assert p.lockfile["default"]["jdcal"]["version"] == "==1.3" with open(p.pipfile_path) as fh: pipfile_contents = fh.read() - assert '==1.3' in pipfile_contents - pipfile_contents = pipfile_contents.replace('==1.3', '*') - with open(p.pipfile_path, 'w') as fh: + assert "==1.3" in pipfile_contents + pipfile_contents = pipfile_contents.replace("==1.3", "*") + with open(p.pipfile_path, "w") as fh: fh.write(pipfile_contents) - c = p.pipenv('update jdcal') + c = p.pipenv("update jdcal") assert c.returncode == 0 - assert p.lockfile['default']['jdcal']['version'] == '==1.4' - c = p.pipenv('run pip freeze') + assert p.lockfile["default"]["jdcal"]["version"] == "==1.4" + c = p.pipenv("run pip freeze") assert c.returncode == 0 lines = c.stdout.splitlines() - assert 'jdcal==1.4' in [l.strip() for l in lines] + assert "jdcal==1.4" in [l.strip() for l in lines] @pytest.mark.project @pytest.mark.proper_names def test_proper_names_unmanaged_virtualenv(pipenv_instance_pypi): with pipenv_instance_pypi(): - c = subprocess_run(['python', '-m', 'virtualenv', '.venv']) + c = subprocess_run(["python", "-m", "virtualenv", ".venv"]) assert c.returncode == 0 project = Project() assert project.proper_names == [] @@ -75,9 +74,9 @@ def test_proper_names_unmanaged_virtualenv(pipenv_instance_pypi): @pytest.mark.cli def test_directory_with_leading_dash(pipenv_instance_pypi): with temp_environ(), pipenv_instance_pypi() as p: - c = p.pipenv('run pip freeze') + c = p.pipenv("run pip freeze") assert c.returncode == 0 - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 venv_path = c.stdout.strip() assert os.path.isdir(venv_path) diff --git a/tests/integration/test_project.py b/tests/integration/test_project.py index 12ac6ca0d3..eee575294f 100644 --- a/tests/integration/test_project.py +++ b/tests/integration/test_project.py @@ -14,8 +14,9 @@ @pytest.mark.environ def test_pipfile_envvar_expansion(pipenv_instance_pypi): with pipenv_instance_pypi() as p, temp_environ(): - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [[source]] url = 'https://${TEST_HOST}/simple' verify_ssl = false @@ -23,20 +24,21 @@ def test_pipfile_envvar_expansion(pipenv_instance_pypi): [packages] pytz = "*" - """.strip()) - os.environ['TEST_HOST'] = 'localhost:5000' + """.strip() + ) + os.environ["TEST_HOST"] = "localhost:5000" project = Project() - assert project.sources[0]['url'] == 'https://localhost:5000/simple' - assert 'localhost:5000' not in str(Pipfile.load(open(p.pipfile_path))) + assert project.sources[0]["url"] == "https://localhost:5000/simple" + assert "localhost:5000" not in str(Pipfile.load(open(p.pipfile_path))) print(str(Pipfile.load(open(p.pipfile_path)))) @pytest.mark.project @pytest.mark.sources -@pytest.mark.parametrize('lock_first', [True, False]) +@pytest.mark.parametrize("lock_first", [True, False]) def test_get_source(pipenv_instance_private_pypi, lock_first): with pipenv_instance_private_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] url = "{p.index_url}" @@ -58,20 +60,17 @@ def test_get_source(pipenv_instance_private_pypi, lock_first): if lock_first: # force source to be cached - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 project = Project() - sources = [ - ['pypi', 'https://pypi.org/simple'], - ['testindex', p.index_url] - ] + sources = [["pypi", "https://pypi.org/simple"], ["testindex", p.index_url]] for src in sources: name, url = src - source = [s for s in project.pipfile_sources() if s.get('name') == name] + source = [s for s in project.pipfile_sources() if s.get("name") == name] assert source source = source[0] - assert source['name'] == name - assert source['url'] == url + assert source["name"] == name + assert source["url"] == url assert sorted(source.items()) == sorted(project.get_source(name=name).items()) assert sorted(source.items()) == sorted(project.get_source(url=url).items()) assert sorted(source.items()) == sorted(project.find_source(name).items()) @@ -80,11 +79,11 @@ def test_get_source(pipenv_instance_private_pypi, lock_first): @pytest.mark.install @pytest.mark.project -@pytest.mark.parametrize('newlines', ['\n', '\r\n']) +@pytest.mark.parametrize("newlines", ["\n", "\r\n"]) def test_maintain_file_line_endings(pipenv_instance_pypi, newlines): with pipenv_instance_pypi() as p: # Initial pipfile + lockfile generation - c = p.pipenv('install pytz') + c = p.pipenv("install pytz") assert c.returncode == 0 # Rewrite each file with parameterized newlines @@ -93,19 +92,21 @@ def test_maintain_file_line_endings(pipenv_instance_pypi, newlines): contents = f.read() # message because of https://github.com/pytest-dev/pytest/issues/3443 - with open(fn, 'w', newline=newlines) as f: + with open(fn, "w", newline=newlines) as f: f.write(contents) # Run pipenv install to programmatically rewrite - c = p.pipenv('install chardet') + c = p.pipenv("install chardet") assert c.returncode == 0 # Make sure we kept the right newlines for fn in [p.pipfile_path, p.lockfile_path]: with open(fn) as f: - f.read() # Consumes the content to detect newlines. + f.read() # Consumes the content to detect newlines. actual_newlines = f.newlines - assert actual_newlines == newlines, f'{actual_newlines!r} != {newlines!r} for {fn}' + assert ( + actual_newlines == newlines + ), f"{actual_newlines!r} != {newlines!r} for {fn}" @pytest.mark.project @@ -113,7 +114,7 @@ def test_maintain_file_line_endings(pipenv_instance_pypi, newlines): @pytest.mark.needs_internet def test_many_indexes(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] url = "{p.index_url}" @@ -137,21 +138,21 @@ def test_many_indexes(pipenv_instance_pypi): [dev-packages] """.strip() f.write(contents) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 @pytest.mark.project @pytest.mark.virtualenv @pytest.mark.skipif( - os.name == 'nt' and sys.version_info[:2] == (3, 8), - reason="Seems to work on 3.8 but not via the CI" + os.name == "nt" and sys.version_info[:2] == (3, 8), + reason="Seems to work on 3.8 but not via the CI", ) def test_run_in_virtualenv(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('run pip freeze') + c = p.pipenv("run pip freeze") assert c.returncode == 0 - assert 'Creating a virtualenv' in c.stderr + assert "Creating a virtualenv" in c.stderr project = Project() c = p.pipenv("run pip install click") assert c.returncode == 0 @@ -166,15 +167,16 @@ def test_run_in_virtualenv(pipenv_instance_pypi): assert c.returncode == 0 assert "click" in c.stdout + @pytest.mark.project @pytest.mark.sources def test_no_sources_in_pipfile(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] pytest = "*" """.strip() f.write(contents) - c = p.pipenv('install --skip-lock') + c = p.pipenv("install --skip-lock") assert c.returncode == 0 diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index 4a64a0bbb4..8be73b7cac 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -9,9 +9,9 @@ @pytest.mark.requirements def test_requirements_generates_requirements_from_lockfile(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - packages = ('requests', '2.14.0') - dev_packages = ('flask', '0.12.2') - with open(p.pipfile_path, 'w') as f: + packages = ("requests", "2.14.0") + dev_packages = ("flask", "0.12.2") + with open(p.pipfile_path, "w") as f: contents = f""" [packages] {packages[0]}= "=={packages[1]}" @@ -19,36 +19,38 @@ def test_requirements_generates_requirements_from_lockfile(pipenv_instance_pypi) {dev_packages[0]}= "=={dev_packages[1]}" """.strip() f.write(contents) - p.pipenv('lock') - c = p.pipenv('requirements') + p.pipenv("lock") + c = p.pipenv("requirements") assert c.returncode == 0 - assert f'{packages[0]}=={packages[1]}' in c.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' not in c.stdout + assert f"{packages[0]}=={packages[1]}" in c.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" not in c.stdout - d = p.pipenv('requirements --dev') + d = p.pipenv("requirements --dev") assert d.returncode == 0 - assert f'{packages[0]}=={packages[1]}' in d.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' in d.stdout + assert f"{packages[0]}=={packages[1]}" in d.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" in d.stdout - e = p.pipenv('requirements --dev-only') + e = p.pipenv("requirements --dev-only") assert e.returncode == 0 - assert f'{packages[0]}=={packages[1]}' not in e.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' in e.stdout + assert f"{packages[0]}=={packages[1]}" not in e.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" in e.stdout - e = p.pipenv('requirements --hash') + e = p.pipenv("requirements --hash") assert e.returncode == 0 - assert f'{packages[0]}=={packages[1]}' in e.stdout - for value in p.lockfile['default'].values(): - for hash in value['hashes']: - assert f' --hash={hash}' in e.stdout + assert f"{packages[0]}=={packages[1]}" in e.stdout + for value in p.lockfile["default"].values(): + for hash in value["hashes"]: + assert f" --hash={hash}" in e.stdout @pytest.mark.requirements -def test_requirements_generates_requirements_from_lockfile_multiple_sources(pipenv_instance_private_pypi): +def test_requirements_generates_requirements_from_lockfile_multiple_sources( + pipenv_instance_private_pypi, +): with pipenv_instance_private_pypi() as p: - packages = ('six', '1.12.0') - dev_packages = ('itsdangerous', '1.1.0') - with open(p.pipfile_path, 'w') as f: + packages = ("six", "1.12.0") + dev_packages = ("itsdangerous", "1.1.0") + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] name = "pypi" @@ -64,24 +66,26 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(pipe {dev_packages[0]}= "=={dev_packages[1]}" """.strip() f.write(contents) - l = p.pipenv('lock') + l = p.pipenv("lock") assert l.returncode == 0 - c = p.pipenv('requirements') + c = p.pipenv("requirements") assert c.returncode == 0 - assert '-i https://pypi.org/simple' in c.stdout - assert '--extra-index-url https://some_other_source.org' in c.stdout + assert "-i https://pypi.org/simple" in c.stdout + assert "--extra-index-url https://some_other_source.org" in c.stdout @pytest.mark.requirements -def test_requirements_generates_requirements_from_lockfile_from_categories(pipenv_instance_private_pypi): +def test_requirements_generates_requirements_from_lockfile_from_categories( + pipenv_instance_private_pypi, +): with pipenv_instance_private_pypi() as p: - packages = ('six', '1.12.0') - dev_packages = ('itsdangerous', '1.1.0') - test_packages = ('pytest', '7.1.3') - doc_packages = ('docutils', '0.19') + packages = ("six", "1.12.0") + dev_packages = ("itsdangerous", "1.1.0") + test_packages = ("pytest", "7.1.3") + doc_packages = ("docutils", "0.19") - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = f""" [[source]] name = "pypi" @@ -97,32 +101,35 @@ def test_requirements_generates_requirements_from_lockfile_from_categories(pipen {doc_packages[0]}= "=={doc_packages[1]}" """.strip() f.write(contents) - l = p.pipenv('lock') + l = p.pipenv("lock") assert l.returncode == 0 - c = p.pipenv('requirements --dev-only') + c = p.pipenv("requirements --dev-only") assert c.returncode == 0 - assert f'{packages[0]}=={packages[1]}' not in c.stdout - assert f'{test_packages[0]}=={test_packages[1]}' not in c.stdout - assert f'{doc_packages[0]}=={doc_packages[1]}' not in c.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' in c.stdout + assert f"{packages[0]}=={packages[1]}" not in c.stdout + assert f"{test_packages[0]}=={test_packages[1]}" not in c.stdout + assert f"{doc_packages[0]}=={doc_packages[1]}" not in c.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" in c.stdout d = p.pipenv('requirements --categories="test, doc"') assert d.returncode == 0 - assert f'{packages[0]}=={packages[1]}' not in d.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' not in d.stdout - assert f'{test_packages[0]}=={test_packages[1]}' in d.stdout - assert f'{doc_packages[0]}=={doc_packages[1]}' in d.stdout + assert f"{packages[0]}=={packages[1]}" not in d.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" not in d.stdout + assert f"{test_packages[0]}=={test_packages[1]}" in d.stdout + assert f"{doc_packages[0]}=={doc_packages[1]}" in d.stdout @pytest.mark.requirements def test_requirements_generates_requirements_with_from_pipfile(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - packages = ('requests', '2.31.0') - sub_packages = ('urllib3', '2.2.1') # subpackages not explicitly written in Pipfile. - dev_packages = ('flask', '0.12.2') - - with open(p.pipfile_path, 'w') as f: + packages = ("requests", "2.31.0") + sub_packages = ( + "urllib3", + "2.2.1", + ) # subpackages not explicitly written in Pipfile. + dev_packages = ("flask", "0.12.2") + + with open(p.pipfile_path, "w") as f: contents = f""" [packages] {packages[0]} = "=={packages[1]}" @@ -130,59 +137,59 @@ def test_requirements_generates_requirements_with_from_pipfile(pipenv_instance_p {dev_packages[0]} = "=={dev_packages[1]}" """.strip() f.write(contents) - p.pipenv('lock') + p.pipenv("lock") - c = p.pipenv('requirements --from-pipfile') + c = p.pipenv("requirements --from-pipfile") assert c.returncode == 0 - assert f'{packages[0]}=={packages[1]}' in c.stdout - assert f'{sub_packages[0]}=={sub_packages[1]}' not in c.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' not in c.stdout + assert f"{packages[0]}=={packages[1]}" in c.stdout + assert f"{sub_packages[0]}=={sub_packages[1]}" not in c.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" not in c.stdout - d = p.pipenv('requirements --dev --from-pipfile') + d = p.pipenv("requirements --dev --from-pipfile") assert d.returncode == 0 - assert f'{packages[0]}=={packages[1]}' in d.stdout - assert f'{sub_packages[0]}=={sub_packages[1]}' not in d.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' in d.stdout + assert f"{packages[0]}=={packages[1]}" in d.stdout + assert f"{sub_packages[0]}=={sub_packages[1]}" not in d.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" in d.stdout - e = p.pipenv('requirements --dev-only --from-pipfile') + e = p.pipenv("requirements --dev-only --from-pipfile") assert e.returncode == 0 - assert f'{packages[0]}=={packages[1]}' not in e.stdout - assert f'{sub_packages[0]}=={sub_packages[1]}' not in e.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' in e.stdout + assert f"{packages[0]}=={packages[1]}" not in e.stdout + assert f"{sub_packages[0]}=={sub_packages[1]}" not in e.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" in e.stdout - f = p.pipenv('requirements --categories=dev-packages --from-pipfile') + f = p.pipenv("requirements --categories=dev-packages --from-pipfile") assert f.returncode == 0 - assert f'{packages[0]}=={packages[1]}' not in f.stdout - assert f'{sub_packages[0]}=={sub_packages[1]}' not in f.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' in f.stdout + assert f"{packages[0]}=={packages[1]}" not in f.stdout + assert f"{sub_packages[0]}=={sub_packages[1]}" not in f.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" in f.stdout - g = p.pipenv('requirements --categories=packages,dev-packages --from-pipfile') + g = p.pipenv("requirements --categories=packages,dev-packages --from-pipfile") assert g.returncode == 0 - assert f'{packages[0]}=={packages[1]}' in g.stdout - assert f'{sub_packages[0]}=={sub_packages[1]}' not in g.stdout - assert f'{dev_packages[0]}=={dev_packages[1]}' in g.stdout + assert f"{packages[0]}=={packages[1]}" in g.stdout + assert f"{sub_packages[0]}=={sub_packages[1]}" not in g.stdout + assert f"{dev_packages[0]}=={dev_packages[1]}" in g.stdout @pytest.mark.requirements def test_requirements_with_git_requirements(pipenv_instance_pypi): - req_hash = '3264a0046e1aa3c0a813335286ebdbc651f58b13' + req_hash = "3264a0046e1aa3c0a813335286ebdbc651f58b13" lockfile = { "_meta": {"sources": []}, "default": { "dataclasses-json": { "editable": True, "git": "https://github.com/lidatong/dataclasses-json.git", - "ref": req_hash + "ref": req_hash, } }, - "develop": {} + "develop": {}, } with pipenv_instance_pypi() as p: - with open(p.lockfile_path, 'w') as f: + with open(p.lockfile_path, "w") as f: json.dump(lockfile, f) - c = p.pipenv('requirements') + c = p.pipenv("requirements") assert c.returncode == 0 assert "dataclasses-json" in c.stdout assert req_hash in c.stdout @@ -197,22 +204,22 @@ def test_requirements_markers_get_included(pipenv_instance_pypi): package: { "hashes": [ "sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6", - "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255" + "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255", ], "markers": markers, - "version": version + "version": version, } }, - "develop": {} + "develop": {}, } with pipenv_instance_pypi() as p: - with open(p.lockfile_path, 'w') as f: + with open(p.lockfile_path, "w") as f: json.dump(lockfile, f) - c = p.pipenv('requirements') + c = p.pipenv("requirements") assert c.returncode == 0 - assert f'{package}{version}; {markers}' in c.stdout + assert f"{package}{version}; {markers}" in c.stdout @pytest.mark.requirements @@ -224,20 +231,20 @@ def test_requirements_markers_get_excluded(pipenv_instance_pypi): package: { "hashes": [ "sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6", - "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255" + "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255", ], "markers": markers, - "version": version + "version": version, } }, - "develop": {} + "develop": {}, } with pipenv_instance_pypi() as p: - with open(p.lockfile_path, 'w') as f: + with open(p.lockfile_path, "w") as f: json.dump(lockfile, f) - c = p.pipenv('requirements --exclude-markers') + c = p.pipenv("requirements --exclude-markers") assert c.returncode == 0 assert markers not in c.stdout @@ -246,33 +253,35 @@ def test_requirements_markers_get_excluded(pipenv_instance_pypi): def test_requirements_hashes_get_included(pipenv_instance_pypi): package, version, markers = "werkzeug", "==2.1.2", "python_version >= '3.7'" first_hash = "sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6" - second_hash = "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255" + second_hash = ( + "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255" + ) lockfile = { "_meta": {"sources": []}, "default": { package: { - "hashes": [ - first_hash, - second_hash - ], + "hashes": [first_hash, second_hash], "markers": markers, - "version": version + "version": version, } }, - "develop": {} + "develop": {}, } with pipenv_instance_pypi() as p: - with open(p.lockfile_path, 'w') as f: + with open(p.lockfile_path, "w") as f: json.dump(lockfile, f) - c = p.pipenv('requirements --hash') + c = p.pipenv("requirements --hash") assert c.returncode == 0 - assert f'{package}{version}; {markers} --hash={first_hash} --hash={second_hash}' in c.stdout + assert ( + f"{package}{version}; {markers} --hash={first_hash} --hash={second_hash}" + in c.stdout + ) def test_requirements_generates_requirements_from_lockfile_without_env_var_expansion( - pipenv_instance_pypi, + pipenv_instance_pypi, ): lockfile = { "_meta": { @@ -292,8 +301,8 @@ def test_requirements_generates_requirements_from_lockfile_without_env_var_expan json.dump(lockfile, f) with temp_environ(): - os.environ['redacted_user'] = "example_user" - os.environ['redacted_pwd'] = "example_pwd" + os.environ["redacted_user"] = "example_user" + os.environ["redacted_pwd"] = "example_pwd" c = p.pipenv("requirements") assert c.returncode == 0 @@ -308,15 +317,10 @@ def test_requirements_generates_requirements_from_lockfile_without_env_var_expan "deps, include_hashes, include_markers, expected", [ ( - { - "django-storages": { - "version": "==1.12.3", - "extras": ["azure"] - } - }, + {"django-storages": {"version": "==1.12.3", "extras": ["azure"]}}, True, True, - ["django-storages[azure]==1.12.3"] + ["django-storages[azure]==1.12.3"], ), ( { @@ -326,23 +330,26 @@ def test_requirements_generates_requirements_from_lockfile_without_env_var_expan }, True, True, - ["https://gitlab.com/eVotUM/Cripto-py/-/archive/develop/Cripto-py-develop.zip"] + [ + "https://gitlab.com/eVotUM/Cripto-py/-/archive/develop/Cripto-py-develop.zip" + ], ), ( { "pyjwt": { "git": "https://github.com/jpadilla/pyjwt.git", "ref": "7665aa625506a11bae50b56d3e04413a3dc6fdf8", - "extras": ["crypto"] + "extras": ["crypto"], } }, True, True, - ["pyjwt[crypto]@ git+https://github.com/jpadilla/pyjwt.git@7665aa625506a11bae50b56d3e04413a3dc6fdf8"] - ) - ] + [ + "pyjwt[crypto]@ git+https://github.com/jpadilla/pyjwt.git@7665aa625506a11bae50b56d3e04413a3dc6fdf8" + ], + ), + ], ) def test_requirements_from_deps(deps, include_hashes, include_markers, expected): result = requirements_from_lockfile(deps, include_hashes, include_markers) assert result == expected - diff --git a/tests/integration/test_run.py b/tests/integration/test_run.py index 2b938aa9b9..f0f3b21250 100644 --- a/tests/integration/test_run.py +++ b/tests/integration/test_run.py @@ -9,53 +9,60 @@ @pytest.mark.run @pytest.mark.dotenv def test_env(pipenv_instance_pypi): - with pipenv_instance_pypi(pipfile=False, ) as p: + with pipenv_instance_pypi( + pipfile=False, + ) as p: with open(os.path.join(p.path, ".env"), "w") as f: f.write("HELLO=WORLD") - c = subprocess_run(['pipenv', 'run', 'python', '-c', "import os; print(os.environ['HELLO'])"], env=p.env) + c = subprocess_run( + ["pipenv", "run", "python", "-c", "import os; print(os.environ['HELLO'])"], + env=p.env, + ) assert c.returncode == 0 - assert 'WORLD' in c.stdout + assert "WORLD" in c.stdout @pytest.mark.run def test_scripts(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: - f.write(r""" + with open(p.pipfile_path, "w") as f: + f.write( + r""" [scripts] printfoo = "python -c \"print('foo')\"" notfoundscript = "randomthingtotally" appendscript = "cmd arg1" multicommand = "bash -c \"cd docs && make html\"" - """) + """ + ) if os.name == "nt": f.write('scriptwithenv = "echo %HELLO%"\n') else: f.write('scriptwithenv = "echo $HELLO"\n') - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 - c = p.pipenv('run printfoo') + c = p.pipenv("run printfoo") assert c.returncode == 0 - assert c.stdout.strip() == 'foo' + assert c.stdout.strip() == "foo" - c = p.pipenv('run notfoundscript') + c = p.pipenv("run notfoundscript") assert c.returncode != 0 - assert c.stdout == '' - if os.name != 'nt': - assert 'could not be found' in c.stderr + assert c.stdout == "" + if os.name != "nt": + assert "could not be found" in c.stderr project = Project() - script = project.build_script('multicommand') - assert script.command == 'bash' - assert script.args == ['-c', 'cd docs && make html'] + script = project.build_script("multicommand") + assert script.command == "bash" + assert script.args == ["-c", "cd docs && make html"] - script = project.build_script('appendscript', ['a', 'b']) - assert script.command == 'cmd' - assert script.args == ['arg1', 'a', 'b'] + script = project.build_script("appendscript", ["a", "b"]) + assert script.command == "cmd" + assert script.args == ["arg1", "a", "b"] with temp_environ(): - os.environ['HELLO'] = 'WORLD' + os.environ["HELLO"] = "WORLD" c = p.pipenv("run scriptwithenv") assert c.returncode == 0 if os.name != "nt": # This doesn't work on CI windows. @@ -65,30 +72,34 @@ def test_scripts(pipenv_instance_pypi): @pytest.mark.run def test_scripts_with_package_functions(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - p.pipenv('install') + p.pipenv("install") pkg_path = os.path.join(p.path, "pkg") os.makedirs(pkg_path, exist_ok=True) file_path = os.path.join(pkg_path, "mod.py") with open(file_path, "w+") as f: - f.write(""" + f.write( + """ def test_func(): print("success") def arg_func(s, i): print(f"{s.upper()}. Easy as {i}") -""") +""" + ) - with open(p.pipfile_path, 'w') as f: - f.write(r""" + with open(p.pipfile_path, "w") as f: + f.write( + r""" [scripts] pkgfunc = {call = "pkg.mod:test_func"} argfunc = {call = "pkg.mod:arg_func('abc', 123)"} - """) + """ + ) - c = p.pipenv('run pkgfunc') + c = p.pipenv("run pkgfunc") assert c.stdout.strip() == "success" - c = p.pipenv('run argfunc') + c = p.pipenv("run argfunc") assert c.stdout.strip() == "ABC. Easy as 123" @@ -96,7 +107,7 @@ def arg_func(s, i): @pytest.mark.skip_windows def test_run_with_usr_env_shebang(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - p.pipenv('install') + p.pipenv("install") script_path = os.path.join(p.path, "test_script") with open(script_path, "w") as f: f.write( @@ -114,7 +125,7 @@ def test_run_with_usr_env_shebang(pipenv_instance_pypi): @pytest.mark.run -@pytest.mark.parametrize('quiet', [True, False]) +@pytest.mark.parametrize("quiet", [True, False]) def test_scripts_resolve_dot_env_vars(quiet, pipenv_instance_pypi): with pipenv_instance_pypi() as p: with open(".env", "w") as f: @@ -130,29 +141,29 @@ def test_scripts_resolve_dot_env_vars(quiet, pipenv_instance_pypi): """.strip() f.write(contents) if quiet: - c = p.pipenv('run --quiet hello') + c = p.pipenv("run --quiet hello") else: - c = p.pipenv('run hello') + c = p.pipenv("run hello") assert c.returncode == 0 - assert 'WORLD' in c.stdout + assert "WORLD" in c.stdout @pytest.mark.run -@pytest.mark.parametrize('quiet', [True, False]) +@pytest.mark.parametrize("quiet", [True, False]) def test_pipenv_run_pip_freeze_has_expected_output(quiet, pipenv_instance_pypi): with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: + with open(p.pipfile_path, "w") as f: contents = """ [packages] requests = "==2.14.0" """.strip() f.write(contents) - c = p.pipenv('install') + c = p.pipenv("install") assert c.returncode == 0 if quiet: - c = p.pipenv('run --quiet pip freeze') + c = p.pipenv("run --quiet pip freeze") else: - c = p.pipenv('run pip freeze') + c = p.pipenv("run pip freeze") assert c.returncode == 0 - assert 'requests==2.14.0' in c.stdout + assert "requests==2.14.0" in c.stdout diff --git a/tests/integration/test_sync.py b/tests/integration/test_sync.py index 0161dbae31..0f891a4b18 100644 --- a/tests/integration/test_sync.py +++ b/tests/integration/test_sync.py @@ -7,14 +7,16 @@ @pytest.mark.sync def test_sync_error_without_lockfile(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [packages] - """.strip()) + """.strip() + ) - c = p.pipenv('sync') + c = p.pipenv("sync") assert c.returncode != 0 - assert 'Pipfile.lock not found!' in c.stderr + assert "Pipfile.lock not found!" in c.stderr @pytest.mark.sync @@ -22,9 +24,10 @@ def test_sync_error_without_lockfile(pipenv_instance_pypi): def test_mirror_lock_sync(pipenv_instance_private_pypi): with temp_environ(), pipenv_instance_private_pypi() as p: mirror_url = p.index_url - assert 'pypi.org' not in mirror_url - with open(p.pipfile_path, 'w') as f: - f.write(""" + assert "pypi.org" not in mirror_url + with open(p.pipfile_path, "w") as f: + f.write( + """ [[source]] name = "pypi" url = "https://pypi.org/simple" @@ -32,37 +35,40 @@ def test_mirror_lock_sync(pipenv_instance_private_pypi): [packages] six = "==1.12.0" - """.strip()) - c = p.pipenv(f'lock --pypi-mirror {mirror_url}') + """.strip() + ) + c = p.pipenv(f"lock --pypi-mirror {mirror_url}") assert c.returncode == 0 - c = p.pipenv(f'sync --pypi-mirror {mirror_url}') + c = p.pipenv(f"sync --pypi-mirror {mirror_url}") assert c.returncode == 0 @pytest.mark.sync @pytest.mark.lock def test_sync_should_not_lock(pipenv_instance_pypi): - """Sync should not touch the lock file, even if Pipfile is changed. - """ + """Sync should not touch the lock file, even if Pipfile is changed.""" with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [packages] - """.strip()) + """.strip() + ) # Perform initial lock. - c = p.pipenv('lock') + c = p.pipenv("lock") assert c.returncode == 0 lockfile_content = p.lockfile assert lockfile_content # Make sure sync does not trigger lockfile update. - with open(p.pipfile_path, 'w') as f: - f.write(""" + with open(p.pipfile_path, "w") as f: + f.write( + """ [packages] six = "*" - """.strip()) - c = p.pipenv('sync') + """.strip() + ) + c = p.pipenv("sync") assert c.returncode == 0 assert lockfile_content == p.lockfile - diff --git a/tests/integration/test_uninstall.py b/tests/integration/test_uninstall.py index 68a50b2f96..e78f90dc23 100644 --- a/tests/integration/test_uninstall.py +++ b/tests/integration/test_uninstall.py @@ -21,7 +21,9 @@ def test_uninstall_requests(pipenv_instance_pypi): @pytest.mark.uninstall -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Package does not work with Python 3.12") +@pytest.mark.skipif( + sys.version_info >= (3, 12), reason="Package does not work with Python 3.12" +) def test_uninstall_django(pipenv_instance_private_pypi): with pipenv_instance_private_pypi() as p: c = p.pipenv("install Django") @@ -45,10 +47,11 @@ def test_uninstall_django(pipenv_instance_private_pypi): @pytest.mark.install @pytest.mark.uninstall -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="Package does not work with Python 3.12") +@pytest.mark.skipif( + sys.version_info >= (3, 12), reason="Package does not work with Python 3.12" +) def test_mirror_uninstall(pipenv_instance_pypi): with temp_environ(), pipenv_instance_pypi() as p: - mirror_url = DEFAULT_PRIVATE_PYPI_SERVER assert "pypi.org" not in mirror_url @@ -86,7 +89,9 @@ def test_mirror_uninstall(pipenv_instance_pypi): @pytest.mark.uninstall def test_uninstall_all_local_files(pipenv_instance_private_pypi, testsroot): with pipenv_instance_private_pypi() as p: - file_uri = p._pipfile.get_fixture_path("tablib/tablib-0.12.1.tar.gz", fixtures="pypi").as_uri() + file_uri = p._pipfile.get_fixture_path( + "tablib/tablib-0.12.1.tar.gz", fixtures="pypi" + ).as_uri() c = p.pipenv(f"install {file_uri}") assert c.returncode == 0 c = p.pipenv("uninstall --all") @@ -305,6 +310,7 @@ def test_sorting_handles_str_values_and_dict_values(pipenv_instance_private_pypi "zipp", ] + @pytest.mark.install @pytest.mark.uninstall def test_category_not_sorted_without_directive(pipenv_instance_private_pypi): diff --git a/tests/integration/test_update.py b/tests/integration/test_update.py index 7b6acf5ea0..51c133db92 100644 --- a/tests/integration/test_update.py +++ b/tests/integration/test_update.py @@ -6,7 +6,7 @@ @pytest.mark.update @pytest.mark.skipif( "os.name == 'nt' and sys.version_info[:2] == (3, 8)", - reason="Seems to work on 3.8 but not via the CI" + reason="Seems to work on 3.8 but not via the CI", ) def test_update_outdated_with_outdated_package(pipenv_instance_private_pypi, cmd_option): with pipenv_instance_private_pypi() as p: diff --git a/tests/integration/test_windows.py b/tests/integration/test_windows.py index 402ce81b43..46a9434f89 100644 --- a/tests/integration/test_windows.py +++ b/tests/integration/test_windows.py @@ -7,19 +7,18 @@ from pipenv.utils.processes import subprocess_run # This module is run only on Windows. -pytestmark = pytest.mark.skipif(os.name != 'nt', reason="only relevant on windows") +pytestmark = pytest.mark.skipif(os.name != "nt", reason="only relevant on windows") @pytest.mark.project def test_case_changes_windows(pipenv_instance_pypi): - """Test project matching for case changes on Windows. - """ + """Test project matching for case changes on Windows.""" with pipenv_instance_pypi() as p: - c = p.pipenv('install pytz') + c = p.pipenv("install pytz") assert c.returncode == 0 # Canonical venv location. - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 virtualenv_location = c.stdout.strip() @@ -27,12 +26,12 @@ def test_case_changes_windows(pipenv_instance_pypi): target = p.path.upper() if target == p.path: target = p.path.lower() - os.chdir('..') + os.chdir("..") os.chdir(target) assert os.path.abspath(os.curdir) != p.path # Ensure the incorrectly-cased project can find the correct venv. - c = p.pipenv('--venv') + c = p.pipenv("--venv") assert c.returncode == 0 assert c.stdout.strip().lower() == virtualenv_location.lower() @@ -40,9 +39,8 @@ def test_case_changes_windows(pipenv_instance_pypi): @pytest.mark.files @pytest.mark.local def test_local_path_windows(pipenv_instance_pypi): - whl = ( - Path(__file__).parent.parent - .joinpath('pypi', 'six', 'six-1.11.0-py2.py3-none-any.whl') + whl = Path(__file__).parent.parent.joinpath( + "pypi", "six", "six-1.11.0-py2.py3-none-any.whl" ) try: whl = whl.resolve() @@ -56,9 +54,8 @@ def test_local_path_windows(pipenv_instance_pypi): @pytest.mark.local @pytest.mark.files def test_local_path_windows_forward_slash(pipenv_instance_pypi): - whl = ( - Path(__file__).parent.parent - .joinpath('pypi', 'six', 'six-1.11.0-py2.py3-none-any.whl') + whl = Path(__file__).parent.parent.joinpath( + "pypi", "six", "six-1.11.0-py2.py3-none-any.whl" ) try: whl = whl.resolve() @@ -70,20 +67,20 @@ def test_local_path_windows_forward_slash(pipenv_instance_pypi): @pytest.mark.skipif( - os.name == 'nt' and sys.version_info[:2] == (3, 8), - reason="Seems to work on 3.8 but not via the CI" + os.name == "nt" and sys.version_info[:2] == (3, 8), + reason="Seems to work on 3.8 but not via the CI", ) @pytest.mark.cli def test_pipenv_clean_windows(pipenv_instance_pypi): with pipenv_instance_pypi() as p: - c = p.pipenv('install dataclasses-json') + c = p.pipenv("install dataclasses-json") assert c.returncode == 0 - c = p.pipenv(f'run pip install -i {p.index_url} click') + c = p.pipenv(f"run pip install -i {p.index_url} click") assert c.returncode == 0 - c = p.pipenv('clean --dry-run') + c = p.pipenv("clean --dry-run") assert c.returncode == 0 - assert 'click' in c.stdout.strip() + assert "click" in c.stdout.strip() @pytest.mark.cli diff --git a/tests/unit/test_cmdparse.py b/tests/unit/test_cmdparse.py index 9afc0b09c8..6c14364415 100644 --- a/tests/unit/test_cmdparse.py +++ b/tests/unit/test_cmdparse.py @@ -6,54 +6,59 @@ @pytest.mark.run @pytest.mark.script def test_parse(): - script = Script.parse(['python', '-c', "print('hello')"]) - assert script.command == 'python' - assert script.args == ['-c', "print('hello')"], script + script = Script.parse(["python", "-c", "print('hello')"]) + assert script.command == "python" + assert script.args == ["-c", "print('hello')"], script @pytest.mark.run @pytest.mark.script def test_parse_error(): with pytest.raises(ScriptEmptyError) as e: - Script.parse('') + Script.parse("") assert str(e.value) == "[]" @pytest.mark.run def test_extend(): - script = Script('python', ['-c', "print('hello')"]) - script.extend(['--verbose']) - assert script.command == 'python' - assert script.args == ['-c', "print('hello')", "--verbose"], script + script = Script("python", ["-c", "print('hello')"]) + script.extend(["--verbose"]) + assert script.command == "python" + assert script.args == ["-c", "print('hello')", "--verbose"], script @pytest.mark.run @pytest.mark.script def test_cmdify(): - script = Script('python', ['-c', "print('hello world')"]) + script = Script("python", ["-c", "print('hello world')"]) cmd = script.cmdify() - assert cmd == 'python -c "print(\'hello world\')"', script + assert cmd == "python -c \"print('hello world')\"", script @pytest.mark.run @pytest.mark.script def test_cmdify_complex(): - script = Script.parse(' '.join([ - '"C:\\Program Files\\Python36\\python.exe" -c', - """ "print(\'Double quote: \\\"\')" """.strip(), - ])) - assert script.cmdify() == ' '.join([ - '"C:\\Program Files\\Python36\\python.exe"', - '-c', - """ "print(\'Double quote: \\\"\')" """.strip(), - ]), script + script = Script.parse( + " ".join( + [ + '"C:\\Program Files\\Python36\\python.exe" -c', + """ "print(\'Double quote: \\\"\')" """.strip(), + ] + ) + ) + assert script.cmdify() == " ".join( + [ + '"C:\\Program Files\\Python36\\python.exe"', + "-c", + """ "print(\'Double quote: \\\"\')" """.strip(), + ] + ), script @pytest.mark.run @pytest.mark.script def test_cmdify_quote_if_paren_in_command(): - """Ensure ONLY the command is quoted if it contains parentheses. - """ + """Ensure ONLY the command is quoted if it contains parentheses.""" script = Script.parse('"C:\\Python36(x86)\\python.exe" -c print(123)') assert script.cmdify() == '"C:\\Python36(x86)\\python.exe" -c print(123)', script @@ -61,7 +66,6 @@ def test_cmdify_quote_if_paren_in_command(): @pytest.mark.run @pytest.mark.script def test_cmdify_quote_if_carets(): - """Ensure arguments are quoted if they contain carets. - """ - script = Script('foo^bar', ['baz^rex']) + """Ensure arguments are quoted if they contain carets.""" + script = Script("foo^bar", ["baz^rex"]) assert script.cmdify() == '"foo^bar" "baz^rex"', script diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index 2702ea05eb..f857697458 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -12,24 +12,27 @@ def test_suppress_nested_venv_warning(capsys, project): # Capture the stderr of warn_in_virtualenv to test for the presence of the # courtesy notice. - project.s.PIPENV_VIRTUALENV = 'totallyrealenv' + project.s.PIPENV_VIRTUALENV = "totallyrealenv" project.s.PIPENV_VERBOSITY = -1 warn_in_virtualenv(project) output, err = capsys.readouterr() - assert 'Courtesy Notice' not in err + assert "Courtesy Notice" not in err @pytest.mark.core def test_load_dot_env_from_environment_variable_location(monkeypatch, capsys, project): - with temp_environ(), monkeypatch.context() as m, TemporaryDirectory(prefix='pipenv-', suffix='') as tempdir: + with temp_environ(), monkeypatch.context() as m, TemporaryDirectory( + prefix="pipenv-", suffix="" + ) as tempdir: if os.name == "nt": from pipenv.vendor import click + is_console = False m.setattr(click._winconsole, "_is_console", lambda x: is_console) - dotenv_path = os.path.join(tempdir, 'test.env') - key, val = 'SOME_KEY', 'some_value' - with open(dotenv_path, 'w') as f: - f.write(f'{key}={val}') + dotenv_path = os.path.join(tempdir, "test.env") + key, val = "SOME_KEY", "some_value" + with open(dotenv_path, "w") as f: + f.write(f"{key}={val}") project.s.PIPENV_DOTENV_LOCATION = str(dotenv_path) load_dot_env(project) @@ -38,15 +41,18 @@ def test_load_dot_env_from_environment_variable_location(monkeypatch, capsys, pr @pytest.mark.core def test_doesnt_load_dot_env_if_disabled(monkeypatch, capsys, project): - with temp_environ(), monkeypatch.context() as m, TemporaryDirectory(prefix='pipenv-', suffix='') as tempdir: + with temp_environ(), monkeypatch.context() as m, TemporaryDirectory( + prefix="pipenv-", suffix="" + ) as tempdir: if os.name == "nt": from pipenv.vendor import click + is_console = False m.setattr(click._winconsole, "_is_console", lambda x: is_console) - dotenv_path = os.path.join(tempdir, 'test.env') - key, val = 'SOME_KEY', 'some_value' - with open(dotenv_path, 'w') as f: - f.write(f'{key}={val}') + dotenv_path = os.path.join(tempdir, "test.env") + key, val = "SOME_KEY", "some_value" + with open(dotenv_path, "w") as f: + f.write(f"{key}={val}") project.s.PIPENV_DOTENV_LOCATION = str(dotenv_path) project.s.PIPENV_DONT_LOAD_ENV = True @@ -59,13 +65,16 @@ def test_doesnt_load_dot_env_if_disabled(monkeypatch, capsys, project): @pytest.mark.core def test_load_dot_env_warns_if_file_doesnt_exist(monkeypatch, capsys, project): - with temp_environ(), monkeypatch.context() as m, TemporaryDirectory(prefix='pipenv-', suffix='') as tempdir: + with temp_environ(), monkeypatch.context() as m, TemporaryDirectory( + prefix="pipenv-", suffix="" + ) as tempdir: if os.name == "nt": from pipenv.vendor import click + is_console = False m.setattr(click._winconsole, "_is_console", lambda x: is_console) - dotenv_path = os.path.join(tempdir, 'does-not-exist.env') + dotenv_path = os.path.join(tempdir, "does-not-exist.env") project.s.PIPENV_DOTENV_LOCATION = str(dotenv_path) load_dot_env(project) output, err = capsys.readouterr() - assert 'Warning' in err + assert "Warning" in err diff --git a/tests/unit/test_funktools.py b/tests/unit/test_funktools.py index 39c7b3ec0b..885a5274c7 100644 --- a/tests/unit/test_funktools.py +++ b/tests/unit/test_funktools.py @@ -5,19 +5,24 @@ def test_unnest(): nested_iterable = ( - 1234, (3456, 4398345, (234234)), ( - 2396, ( - 928379, 29384, ( - 293759, 2347, ( - 2098, 7987, 27599 - ) - ) - ) - ) - ) - list(unnest(nested_iterable)) == [1234, 3456, 4398345, 234234, - 2396, 928379, 29384, 293759, - 2347, 2098, 7987, 27599] + 1234, + (3456, 4398345, (234234)), + (2396, (928379, 29384, (293759, 2347, (2098, 7987, 27599)))), + ) + list(unnest(nested_iterable)) == [ + 1234, + 3456, + 4398345, + 234234, + 2396, + 928379, + 29384, + 293759, + 2347, + 2098, + 7987, + 27599, + ] @pytest.mark.parametrize( diff --git a/tests/unit/test_help.py b/tests/unit/test_help.py index 812925f759..82893f996b 100644 --- a/tests/unit/test_help.py +++ b/tests/unit/test_help.py @@ -9,7 +9,8 @@ @pytest.mark.help def test_help(): output = subprocess.check_output( - [sys.executable, '-m', 'pipenv.help'], - stderr=subprocess.STDOUT, env=os.environ.copy(), + [sys.executable, "-m", "pipenv.help"], + stderr=subprocess.STDOUT, + env=os.environ.copy(), ) assert output diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 22a96415af..73f5c6ec29 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -15,8 +15,14 @@ DEP_PIP_PAIRS = [ ({"django": ">1.10"}, {"django": "django>1.10"}), ({"Django": ">1.10"}, {"Django": "Django>1.10"}), - ({"requests": {"extras": ["socks"], "version": ">1.10"}}, {"requests": "requests[socks]>1.10"}), - ({"requests": {"extras": ["socks"], "version": "==1.10"}}, {"requests": "requests[socks]==1.10"}), + ( + {"requests": {"extras": ["socks"], "version": ">1.10"}}, + {"requests": "requests[socks]>1.10"}, + ), + ( + {"requests": {"extras": ["socks"], "version": "==1.10"}}, + {"requests": "requests[socks]==1.10"}, + ), ( { "dataclasses-json": { @@ -25,11 +31,20 @@ "editable": True, } }, - {"dataclasses-json": "dataclasses-json@ git+https://github.com/lidatong/dataclasses-json.git@v0.5.7"}, + { + "dataclasses-json": "dataclasses-json@ git+https://github.com/lidatong/dataclasses-json.git@v0.5.7" + }, ), ( - {"dataclasses-json": {"git": "https://github.com/lidatong/dataclasses-json.git", "ref": "v0.5.7"}}, - {"dataclasses-json": "dataclasses-json@ git+https://github.com/lidatong/dataclasses-json.git@v0.5.7"}, + { + "dataclasses-json": { + "git": "https://github.com/lidatong/dataclasses-json.git", + "ref": "v0.5.7", + } + }, + { + "dataclasses-json": "dataclasses-json@ git+https://github.com/lidatong/dataclasses-json.git@v0.5.7" + }, ), ( # Extras in url @@ -39,7 +54,9 @@ "extras": ["pipenv"], } }, - {"dparse": "dparse[pipenv] @ https://github.com/oz123/dparse/archive/refs/heads/master.zip"}, + { + "dparse": "dparse[pipenv] @ https://github.com/oz123/dparse/archive/refs/heads/master.zip" + }, ), ( { @@ -50,13 +67,22 @@ "editable": False, } }, - {"requests": "requests[security]@ git+https://github.com/requests/requests.git@main"}, + { + "requests": "requests[security]@ git+https://github.com/requests/requests.git@main" + }, ), ] -def mock_unpack(link, source_dir, download_dir, only_download=False, session=None, - hashes=None, progress_bar="off"): +def mock_unpack( + link, + source_dir, + download_dir, + only_download=False, + session=None, + hashes=None, + progress_bar="off", +): return @@ -95,7 +121,9 @@ def test_convert_deps_to_pip_extras_no_version(): "hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", } }, - {"FooProject": "FooProject==1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"}, + { + "FooProject": "FooProject==1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" + }, ), ( { @@ -105,7 +133,9 @@ def test_convert_deps_to_pip_extras_no_version(): "hash": "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", } }, - {"FooProject": "FooProject[stuff]==1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"}, + { + "FooProject": "FooProject[stuff]==1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" + }, ), ( { @@ -115,7 +145,9 @@ def test_convert_deps_to_pip_extras_no_version(): "extras": ["standard"], } }, - {"uvicorn": "git+https://github.com/encode/uvicorn.git@master#egg=uvicorn[standard]"}, + { + "uvicorn": "git+https://github.com/encode/uvicorn.git@master#egg=uvicorn[standard]" + }, ), ], ) @@ -146,23 +178,35 @@ def test_get_constraints_from_deps(deps, expected): assert dependencies.get_constraints_from_deps(deps) == expected -@pytest.mark.parametrize("line,result", [ - ("-i https://example.com/simple/", ("https://example.com/simple/", None, None, [])), - ("--extra-index-url=https://example.com/simple/", (None, "https://example.com/simple/", None, [])), - ("--trusted-host=example.com", (None, None, "example.com", [])), - ("# -i https://example.com/simple/", (None, None, None, [])), - ("requests # -i https://example.com/simple/", (None, None, None, ["requests"])), -]) +@pytest.mark.parametrize( + "line,result", + [ + ( + "-i https://example.com/simple/", + ("https://example.com/simple/", None, None, []), + ), + ( + "--extra-index-url=https://example.com/simple/", + (None, "https://example.com/simple/", None, []), + ), + ("--trusted-host=example.com", (None, None, "example.com", [])), + ("# -i https://example.com/simple/", (None, None, None, [])), + ("requests # -i https://example.com/simple/", (None, None, None, ["requests"])), + ], +) @pytest.mark.utils def test_parse_indexes(line, result): assert indexes.parse_indexes(line) == result -@pytest.mark.parametrize("line", [ - "-i https://example.com/simple/ --extra-index-url=https://extra.com/simple/", - "--extra-index-url https://example.com/simple/ --trusted-host=example.com", - "requests -i https://example.com/simple/", -]) +@pytest.mark.parametrize( + "line", + [ + "-i https://example.com/simple/ --extra-index-url=https://extra.com/simple/", + "--extra-index-url https://example.com/simple/ --trusted-host=example.com", + "requests -i https://example.com/simple/", + ], +) @pytest.mark.utils def test_parse_indexes_individual_lines(line): with pytest.raises(ValueError): @@ -207,6 +251,7 @@ def test_is_required_version(self, version, specified_ver, expected): @pytest.mark.vcs def test_is_vcs(self, entry, expected): from pipenv.utils.requirementslib import is_vcs + assert is_vcs(entry) is expected @pytest.mark.utils @@ -230,12 +275,13 @@ def test_python_version_from_non_python(self): ), ], ) - def test_python_version_output_variants( - self, monkeypatch, version_output, version - ): + def test_python_version_output_variants(self, monkeypatch, version_output, version): def mock_version(path): return version_output.split()[1] - monkeypatch.setattr("pipenv.vendor.pythonfinder.utils.get_python_version", mock_version) + + monkeypatch.setattr( + "pipenv.vendor.pythonfinder.utils.get_python_version", mock_version + ) assert dependencies.python_version("some/path") == version @pytest.mark.utils @@ -255,25 +301,28 @@ def test_download_file(self): os.remove(output) @pytest.mark.utils - @pytest.mark.parametrize('line, expected', [ - ("python", True), - ("python3.7", True), - ("python2.7", True), - ("python2", True), - ("python3", True), - ("pypy3", True), - ("anaconda3-5.3.0", True), - ("which", False), - ("vim", False), - ("miniconda", True), - ("micropython", True), - ("ironpython", True), - ("jython3.5", True), - ("2", True), - ("2.7", True), - ("3.7", True), - ("3", True) - ]) + @pytest.mark.parametrize( + "line, expected", + [ + ("python", True), + ("python3.7", True), + ("python2.7", True), + ("python2", True), + ("python3", True), + ("pypy3", True), + ("anaconda3-5.3.0", True), + ("which", False), + ("vim", False), + ("miniconda", True), + ("micropython", True), + ("ironpython", True), + ("jython3.5", True), + ("2", True), + ("2.7", True), + ("3.7", True), + ("3", True), + ], + ) def test_is_python_command(self, line, expected): assert shell.is_python_command(line) == expected @@ -387,7 +436,10 @@ def test_nix_normalize_drive(self, input_path, expected): ( [ {"url": "https://pypi.org/simple"}, - {"url": "https://custom.example.com:12345/simple", "verify_ssl": False}, + { + "url": "https://custom.example.com:12345/simple", + "verify_ssl": False, + }, ], [ "-i", @@ -444,10 +496,7 @@ def test_nix_normalize_drive(self, input_path, expected): ], ) def test_prepare_pip_source_args(self, sources, expected_args): - assert ( - indexes.prepare_pip_source_args(sources, pip_args=None) - == expected_args - ) + assert indexes.prepare_pip_source_args(sources, pip_args=None) == expected_args @pytest.mark.utils def test_invalid_prepare_pip_source_args(self): @@ -479,7 +528,7 @@ def mock_shutil_which(command, path=None): ("1", True), ("off", False), ("0", False), - ) + ), ) def test_env_to_bool(self, val, expected): actual = shell.env_to_bool(val) diff --git a/tests/unit/test_utils_windows_executable.py b/tests/unit/test_utils_windows_executable.py index 4236ff856e..a4ffe71bbb 100644 --- a/tests/unit/test_utils_windows_executable.py +++ b/tests/unit/test_utils_windows_executable.py @@ -8,45 +8,45 @@ # This module is run only on Windows. pytestmark = pytest.mark.skipif( - os.name != 'nt', + os.name != "nt", reason="only relevant on windows", ) @pytest.mark.utils @pytest.mark.skipif(os.name != "nt", reason="Windows test only") -@mock.patch('os.path.isfile') -@mock.patch('shutil.which') +@mock.patch("os.path.isfile") +@mock.patch("shutil.which") def test_find_windows_executable_when_not_found(mocked_which, mocked_isfile): mocked_isfile.return_value = False mocked_which.return_value = None - found = shell.find_windows_executable('fake/path', 'python') + found = shell.find_windows_executable("fake/path", "python") assert found is None assert mocked_isfile.call_count > 1 - calls = [mock.call('fake\\path\\python')] + [ - mock.call(f'fake\\path\\python{ext.lower()}') - for ext in os.environ['PATHEXT'].split(';') + calls = [mock.call("fake\\path\\python")] + [ + mock.call(f"fake\\path\\python{ext.lower()}") + for ext in os.environ["PATHEXT"].split(";") ] assert mocked_isfile.mock_calls == calls @pytest.mark.utils @pytest.mark.skipif(os.name != "nt", reason="Windows test only") -@mock.patch('os.path.isfile') -@mock.patch('shutil.which') +@mock.patch("os.path.isfile") +@mock.patch("shutil.which") def test_find_windows_executable_when_found(mocked_which, mocked_isfile): mocked_isfile.return_value = False - found_path = '/fake/known/system/path/pyenv' + found_path = "/fake/known/system/path/pyenv" mocked_which.return_value = found_path - found = shell.find_windows_executable('fake/path', 'pyenv') + found = shell.find_windows_executable("fake/path", "pyenv") assert found is found_path assert mocked_isfile.call_count > 1 - calls = [mock.call('fake\\path\\pyenv')] + [ - mock.call(f'fake\\path\\pyenv{ext.lower()}') - for ext in os.environ['PATHEXT'].split(';') + calls = [mock.call("fake\\path\\pyenv")] + [ + mock.call(f"fake\\path\\pyenv{ext.lower()}") + for ext in os.environ["PATHEXT"].split(";") ] assert mocked_isfile.mock_calls == calls diff --git a/tests/unit/test_vendor.py b/tests/unit/test_vendor.py index d6dc09e59f..cd5fa7e2db 100644 --- a/tests/unit/test_vendor.py +++ b/tests/unit/test_vendor.py @@ -10,36 +10,39 @@ from pipenv.vendor import tomlkit -@pytest.mark.parametrize('dt, content', [ - ( # Date. - datetime.date(1992, 8, 19), - '1992-08-19', - ), - ( # Naive time. - datetime.time(15, 10), - '15:10:00', - ), - ( # Aware time in UTC. - datetime.time(15, 10, tzinfo=pytz.UTC), - '15:10:00+00:00', - ), - ( # Aware local time. - datetime.time(15, 10, tzinfo=pytz.FixedOffset(8 * 60)), - '15:10:00+08:00', - ), - ( # Naive datetime. - datetime.datetime(1992, 8, 19, 15, 10), - '1992-08-19T15:10:00', - ), - ( # Aware datetime in UTC. - datetime.datetime(1992, 8, 19, 15, 10, tzinfo=pytz.UTC), - '1992-08-19T15:10:00Z', - ), - ( # Aware local datetime. - datetime.datetime(1992, 8, 19, 15, 10, tzinfo=pytz.FixedOffset(8 * 60)), - '1992-08-19T15:10:00+08:00', - ), -]) +@pytest.mark.parametrize( + "dt, content", + [ + ( # Date. + datetime.date(1992, 8, 19), + "1992-08-19", + ), + ( # Naive time. + datetime.time(15, 10), + "15:10:00", + ), + ( # Aware time in UTC. + datetime.time(15, 10, tzinfo=pytz.UTC), + "15:10:00+00:00", + ), + ( # Aware local time. + datetime.time(15, 10, tzinfo=pytz.FixedOffset(8 * 60)), + "15:10:00+08:00", + ), + ( # Naive datetime. + datetime.datetime(1992, 8, 19, 15, 10), + "1992-08-19T15:10:00", + ), + ( # Aware datetime in UTC. + datetime.datetime(1992, 8, 19, 15, 10, tzinfo=pytz.UTC), + "1992-08-19T15:10:00Z", + ), + ( # Aware local datetime. + datetime.datetime(1992, 8, 19, 15, 10, tzinfo=pytz.FixedOffset(8 * 60)), + "1992-08-19T15:10:00+08:00", + ), + ], +) def test_token_date(dt, content): item = tomlkit.item(dt) assert item.as_string() == content