From 29cf63e2fba97cb84d0531e84b84752aae66b32f Mon Sep 17 00:00:00 2001 From: DasaniT Date: Thu, 10 Aug 2023 16:12:36 +0330 Subject: [PATCH] Add --categories option to work with requirements txt files --- news/5722.feature.rst | 1 + pipenv/routines/install.py | 8 +++- pipenv/utils/pipfile.py | 6 ++- pipenv/utils/project.py | 2 + pipenv/utils/requirements.py | 21 +++++++-- tests/integration/test_install_categories.py | 48 +++++++++++++++++++- 6 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 news/5722.feature.rst diff --git a/news/5722.feature.rst b/news/5722.feature.rst new file mode 100644 index 0000000000..e4e835ec70 --- /dev/null +++ b/news/5722.feature.rst @@ -0,0 +1 @@ +The ``--categories`` option now works with requirements.txt file. diff --git a/pipenv/routines/install.py b/pipenv/routines/install.py index a411bfddb0..7d56bd8b5b 100644 --- a/pipenv/routines/install.py +++ b/pipenv/routines/install.py @@ -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): @@ -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) diff --git a/pipenv/utils/pipfile.py b/pipenv/utils/pipfile.py index 9029c59a3d..79b6af96e8 100644 --- a/pipenv/utils/pipfile.py +++ b/pipenv/utils/pipfile.py @@ -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. @@ -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: diff --git a/pipenv/utils/project.py b/pipenv/utils/project.py index a0cfb10f57..44fa1c95b8 100644 --- a/pipenv/utils/project.py +++ b/pipenv/utils/project.py @@ -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.""" @@ -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) diff --git a/pipenv/utils/requirements.py b/pipenv/utils/requirements.py index 3d6f816bfe..2efe2c1cf7 100644 --- a/pipenv/utils/requirements.py +++ b/pipenv/utils/requirements.py @@ -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. @@ -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. @@ -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() diff --git a/tests/integration/test_install_categories.py b/tests/integration/test_install_categories.py index 9da45b051e..5d33fdf443 100644 --- a/tests/integration/test_install_categories.py +++ b/tests/integration/test_install_categories.py @@ -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"') @@ -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