Skip to content

Add --categories option to work with requirements txt files #5826

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

Merged
merged 1 commit into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/5722.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The ``--categories`` option now works with requirements.txt file.
8 changes: 7 additions & 1 deletion pipenv/routines/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def do_install(
skip_requirements=skip_requirements,
pypi_mirror=pypi_mirror,
site_packages=site_packages,
categories=categories,
)
# Don't attempt to install develop and default packages if Pipfile is missing
if not project.pipfile_exists and not (package_args or dev):
Expand Down Expand Up @@ -131,7 +132,12 @@ def do_install(
err=True,
)
try:
import_requirements(project, r=project.path_to(requirementstxt), dev=dev)
import_requirements(
project,
r=project.path_to(requirementstxt),
dev=dev,
categories=categories,
)
except (UnicodeDecodeError, PipError) as e:
# Don't print the temp file path if remote since it will be deleted.
req_path = requirements_url if remote else project.path_to(requirementstxt)
Expand Down
6 changes: 4 additions & 2 deletions pipenv/utils/pipfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ def find_pipfile(max_depth=3):
raise RuntimeError("No Pipfile found!")


def ensure_pipfile(project, validate=True, skip_requirements=False, system=False):
def ensure_pipfile(
project, validate=True, skip_requirements=False, system=False, categories=None
):
"""Creates a Pipfile for the project, if it doesn't exist."""

# Assert Pipfile exists.
Expand Down Expand Up @@ -81,7 +83,7 @@ def ensure_pipfile(project, validate=True, skip_requirements=False, system=False
) as st:
# Import requirements.txt.
try:
import_requirements(project)
import_requirements(project, categories=categories)
except Exception:
err.print(environments.PIPENV_SPINNER_FAIL_TEXT.format("Failed..."))
else:
Expand Down
2 changes: 2 additions & 0 deletions pipenv/utils/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def ensure_project(
skip_requirements=False,
pypi_mirror=None,
clear=False,
categories=None,
):
"""Ensures both Pipfile and virtualenv exist for the project."""

Expand Down Expand Up @@ -78,5 +79,6 @@ def ensure_project(
validate=validate,
skip_requirements=skip_requirements,
system=system,
categories=categories,
)
os.environ["PIP_PYTHON_PATH"] = project.python(system=system)
21 changes: 18 additions & 3 deletions pipenv/utils/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from pipenv.utils.pip import get_trusted_hosts


def import_requirements(project, r=None, dev=False):
def import_requirements(project, r=None, dev=False, categories=None):
# Parse requirements.txt file with Pip's parser.
# Pip requires a `PipSession` which is a subclass of requests.Session.
# Since we're not making any network calls, it's initialized to nothing.
Expand All @@ -23,6 +23,8 @@ def import_requirements(project, r=None, dev=False):
r = project.requirements_location
with open(r) as f:
contents = f.read()
if categories is None:
categories = []
indexes = []
trusted_hosts = []
# Find and add extra indexes.
Expand Down Expand Up @@ -56,9 +58,22 @@ def import_requirements(project, r=None, dev=False):
package_string = str(package.link._url)
else:
package_string = str(package.link)
project.add_package_to_pipfile(package_string, dev=dev)
if categories:
for category in categories:
project.add_package_to_pipfile(
package_string, dev=dev, category=category
)
else:
project.add_package_to_pipfile(package_string, dev=dev)
else:
project.add_package_to_pipfile(str(package.req), dev=dev)
if categories:
for category in categories:
project.add_package_to_pipfile(
str(package.req), dev=dev, category=category
)
else:
project.add_package_to_pipfile(str(package.req), dev=dev)

for index in indexes:
add_index_to_pipfile(project, index, trusted_hosts)
project.recase_pipfile()
Expand Down
48 changes: 47 additions & 1 deletion tests/integration/test_install_categories.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,29 @@ def test_basic_category_install(pipenv_instance_private_pypi):

@pytest.mark.categories
@pytest.mark.install
@pytest.mark.parametrize('categories', ["prereq other", "prereq, other"])
@pytest.mark.requirements
def test_basic_category_install_from_requirements(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"six==1.16.0")

c = p.pipenv("install --categories prereq")
assert c.returncode == 0
os.unlink("requirements.txt")
print(c.stdout)
print(c.stderr)
# assert stuff in pipfile
assert c.returncode == 0
assert "six" not in p.pipfile["packages"]
assert "six" not in p.lockfile["default"]
assert "six" in p.pipfile["prereq"]
assert "six" in p.lockfile["prereq"]


@pytest.mark.categories
@pytest.mark.install
@pytest.mark.parametrize("categories", ["prereq other", "prereq, other"])
def test_multiple_category_install(pipenv_instance_private_pypi, categories):
with pipenv_instance_private_pypi() as p:
c = p.pipenv('install six --categories="prereq other"')
Expand All @@ -31,6 +53,30 @@ def test_multiple_category_install(pipenv_instance_private_pypi, categories):
assert "six" in p.lockfile["other"]


@pytest.mark.categories
@pytest.mark.install
@pytest.mark.requirements
def test_multiple_category_install_from_requirements(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("six==1.16.0")

c = p.pipenv('install --categories="prereq other"')
assert c.returncode == 0
os.unlink("requirements.txt")
print(c.stdout)
print(c.stderr)
# assert stuff in pipfile
assert c.returncode == 0
assert "six" not in p.pipfile["packages"]
assert "six" not in p.lockfile["default"]
assert "six" in p.pipfile["prereq"]
assert "six" in p.lockfile["prereq"]
assert "six" in p.pipfile["other"]
assert "six" in p.lockfile["other"]


@pytest.mark.extras
@pytest.mark.install
@pytest.mark.local
Expand Down