Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subdirectory vcs installs are never passing the subdirectory in requirementslib which is now required by setuptools #5017

Merged
merged 11 commits into from
Mar 28, 2022
Merged
1 change: 0 additions & 1 deletion .env

This file was deleted.

1 change: 1 addition & 0 deletions news/5010.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Environment variables were not being loaded when the `--quiet` flag was set
1 change: 1 addition & 0 deletions news/5011.trivial.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adds missing unit test coverage for recent bug fixes.
4 changes: 4 additions & 0 deletions news/5019.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
It would appear that ``requirementslib`` was not fully specifying the subdirectory to ``build_pep517`` and
and when a new version of ``setuptools`` was released, the test ``test_lock_nested_vcs_direct_url``
broke indicating the Pipfile.lock no longer contained the extra dependencies that should have been resolved.
This regression affected ``pipenv>=2021.11.9`` but has been fixed by a patch to ``requirementslib``.
11 changes: 6 additions & 5 deletions pipenv/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,12 @@ def load_dot_env(project, as_dict=False, quiet=False):
)
if as_dict:
return dotenv.dotenv_values(dotenv_file)
elif os.path.isfile(dotenv_file) and not quiet:
click.echo(
crayons.normal(fix_utf8("Loading .env environment variables..."), bold=True),
err=True,
)
elif os.path.isfile(dotenv_file):
if not quiet:
click.echo(
crayons.normal(fix_utf8("Loading .env environment variables..."), bold=True),
err=True,
)
dotenv.load_dotenv(dotenv_file, override=True)
project.s.initialize()

Expand Down
11 changes: 9 additions & 2 deletions pipenv/vendor/requirementslib/models/setup_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from collections.abc import Iterable, Mapping
from functools import lru_cache, partial
from pathlib import Path
from urllib.parse import urlparse, urlunparse
from urllib.parse import parse_qs, urlparse, urlunparse
from weakref import finalize

import pipenv.vendor.attr as attr
Expand Down Expand Up @@ -1230,8 +1230,15 @@ def build_wheel(self):
)
)
need_delete = True

parsed = urlparse(str(self.ireq.link))
subdir = parse_qs(parsed.fragment).get('subdirectory', [])
if subdir:
directory = f"{self.base_dir}/{subdir[0]}"
else:
directory = self.base_dir
result = build_pep517(
self.base_dir,
directory,
self.extra_kwargs["build_dir"],
config_settings=self.pep517_config,
dist_type="wheel",
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
required = [
"pip>=18.0",
"certifi",
"setuptools>=36.2.1,<61.0.0",
"setuptools>=36.2.1",
"virtualenv-clone>=0.2.5",
"virtualenv"
]
Expand Down
30 changes: 30 additions & 0 deletions tasks/vendoring/patches/vendor/requirementslib-subdir-fix.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
diff --git a/pipenv/vendor/requirementslib/models/setup_info.py b/pipenv/vendor/requirementslib/models/setup_info.py
index 772a4d81..dc001f36 100644
--- a/pipenv/vendor/requirementslib/models/setup_info.py
+++ b/pipenv/vendor/requirementslib/models/setup_info.py
@@ -13,7 +13,7 @@ import sys
from collections.abc import Iterable, Mapping
from functools import lru_cache, partial
from pathlib import Path
-from urllib.parse import urlparse, urlunparse
+from urllib.parse import parse_qs, urlparse, urlunparse
from weakref import finalize

import pipenv.vendor.attr as attr
@@ -1230,8 +1230,15 @@ build-backend = "{1}"
)
)
need_delete = True
+
+ parsed = urlparse(str(self.ireq.link))
+ subdir = parse_qs(parsed.fragment).get('subdirectory', [])
+ if subdir:
+ directory = f"{self.base_dir}/{subdir[0]}"
+ else:
+ directory = self.base_dir
result = build_pep517(
- self.base_dir,
+ directory,
self.extra_kwargs["build_dir"],
config_settings=self.pep517_config,
dist_type="wheel",
21 changes: 0 additions & 21 deletions tests/integration/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,27 +210,6 @@ def test_scripts(PipenvInstance):
assert 'which python' in c.stdout


@pytest.mark.cli
def test_scripts_resolve_dot_env_vars(PipenvInstance):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote this test recently but technically put it in the wrong file -- relocated it in this PR and extended it's use case.

with PipenvInstance() as p:
with open(".env", "w") as f:
contents = """
HELLO=WORLD
""".strip()
f.write(contents)

with open(p.pipfile_path, "w") as f:
contents = """
[scripts]
hello = "echo $HELLO"
""".strip()
f.write(contents)
c = p.pipenv('run hello')
print(c)
print(c.stdout)
assert 'WORLD' in c.stdout


@pytest.mark.cli
def test_help(PipenvInstance):
with PipenvInstance() as p:
Expand Down
37 changes: 37 additions & 0 deletions tests/integration/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,3 +804,40 @@ def test_default_lock_overwrite_dev_lock(PipenvInstance):
assert c.returncode == 0
assert p.lockfile["default"]["click"]["version"] == "==6.7"
assert p.lockfile["develop"]["click"]["version"] == "==6.7"


@flaky
@pytest.mark.lock
@pytest.mark.install
@pytest.mark.needs_internet
def test_pipenv_respects_package_index_restrictions(PipenvInstance):
with PipenvInstance() as p:
with open(p.pipfile_path, 'w') as f:
contents = """
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[[source]]
url = "{url}/simple"
verify_ssl = true
name = "local"

[packages]
requests = {requirement}
""".strip().format(url=p.pypi, requirement='{version="*", index="local"}')
f.write(contents)

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']
# 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
45 changes: 45 additions & 0 deletions tests/integration/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,48 @@ def test_run_with_usr_env_shebang(PipenvInstance):
project = Project()
lines = [line.strip() for line in c.stdout.splitlines()]
assert all(line == project.virtualenv_location for line in lines)


@pytest.mark.run
@pytest.mark.parametrize('quiet', [True, False])
def test_scripts_resolve_dot_env_vars(quiet, PipenvInstance):
with PipenvInstance() as p:
with open(".env", "w") as f:
contents = """
HELLO_VAR=WORLD
""".strip()
f.write(contents)

with open(p.pipfile_path, "w") as f:
contents = """
[scripts]
hello = "echo $HELLO_VAR"
""".strip()
f.write(contents)
if quiet:
c = p.pipenv('run --quiet hello')
else:
c = p.pipenv('run hello')
assert c.returncode == 0
assert 'WORLD\n' == c.stdout


@pytest.mark.run
@pytest.mark.parametrize('quiet', [True, False])
def test_pipenv_run_pip_freeze_has_expected_output(quiet, PipenvInstance):
with PipenvInstance() as p:
with open(p.pipfile_path, 'w') as f:
contents = """
[packages]
requests = "==2.14.0"
""".strip()
f.write(contents)
c = p.pipenv('install')
assert c.returncode == 0

if quiet:
c = p.pipenv('run --quiet pip freeze')
else:
c = p.pipenv('run pip freeze')
assert c.returncode == 0
assert 'requests==2.14.0\n' == c.stdout