From 0fdacebc0f15021e08eb3a7a43831e7584883def Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 14:47:42 +0530 Subject: [PATCH 1/9] add category cmd line option --- pipenv/cli/command.py | 17 ++++++++----- tests/integration/test_requirements.py | 35 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 7e642eab..12089b22 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -1,3 +1,4 @@ +from gc import is_finalized import os import sys @@ -85,7 +86,7 @@ def cli( load_dot_env(state.project, quiet=state.quiet) - from ..core import ( + from pipenv.core import ( cleanup_virtualenv, do_clear, do_py, @@ -740,8 +741,9 @@ def verify(state): ) @option("--hash", is_flag=True, default=False, help="Add package hashes.") @option("--exclude-markers", is_flag=True, default=False, help="Exclude markers.") +@option("--category", is_flag=False, default='', help="Only add requirement of the specified category.") @pass_state -def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=False): +def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=False, category=''): from pipenv.utils.dependencies import convert_deps_to_pip @@ -753,10 +755,13 @@ def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=F deps = {} - if dev or dev_only: - deps.update(lockfile["develop"]) - if not dev_only: - deps.update(lockfile["default"]) + if category: + deps.update(lockfile.get(category, {})) + else: + if dev or dev_only: + deps.update(lockfile["develop"]) + if not dev_only: + deps.update(lockfile["default"]) pip_deps = convert_deps_to_pip( deps, diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index 3ad1e978..fa8ddf6d 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -72,6 +72,41 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(pipe assert '--extra-index-url https://some_other_source.org' in c.stdout +@pytest.mark.requirements +def test_requirements_generates_requirements_from_lockfile_from_a_category(pipenv_instance_private_pypi): + with pipenv_instance_private_pypi(chdir=True) as p: + packages = ('six', '1.12.0') + dev_packages = ('itsdangerous', '1.1.0') + test_packages = ('pytest', '7.1.3') + with open(p.pipfile_path, 'w') as f: + contents = f""" + [[source]] + name = "pypi" + url = "https://pypi.org/simple" + verify_ssl = true + [packages] + {packages[0]}= "=={packages[1]}" + [dev-packages] + {dev_packages[0]}= "=={dev_packages[1]}" + [test-packages] + {test_packages[0]}= "=={test_packages[1]}" + """.strip() + f.write(contents) + l = p.pipenv('lock') + assert l.returncode == 0 + + 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'{dev_packages[0]}=={dev_packages[1]}' in c.stdout + + d = p.pipenv('requirements --category test') + assert d.returncode == 0 + assert f'{packages[0]}=={packages[1]}' not in d.stdout + assert f'{dev_packages[0]}=={dev_packages[1]}' not in c.stdout + assert f'{test_packages[0]}=={test_packages[1]}' in d.stdout + @pytest.mark.requirements def test_requirements_with_git_requirements(pipenv_instance_pypi): req_name, req_hash = 'example-repo', 'cc858e89f19bc0dbd70983f86b811ab625dc9292' From 6a3833ac38c748932bf54aa159ef7684efd86ccc Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 14:49:35 +0530 Subject: [PATCH 2/9] Cleanup --- pipenv/cli/command.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 12089b22..a8872338 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -1,4 +1,3 @@ -from gc import is_finalized import os import sys @@ -86,7 +85,7 @@ def cli( load_dot_env(state.project, quiet=state.quiet) - from pipenv.core import ( + from ..core import ( cleanup_virtualenv, do_clear, do_py, From aa250271aad6a011843ccd44c8b387adba4bf0da Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 15:31:39 +0530 Subject: [PATCH 3/9] change category to categories --- pipenv/cli/command.py | 10 ++++++---- tests/integration/test_requirements.py | 9 +++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index a8872338..57490249 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -740,9 +740,9 @@ def verify(state): ) @option("--hash", is_flag=True, default=False, help="Add package hashes.") @option("--exclude-markers", is_flag=True, default=False, help="Exclude markers.") -@option("--category", is_flag=False, default='', help="Only add requirement of the specified category.") +@option("--categories", is_flag=False, default='', help="Only add requirement of the specified categories.") @pass_state -def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=False, category=''): +def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=False, categories=''): from pipenv.utils.dependencies import convert_deps_to_pip @@ -753,9 +753,11 @@ def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=F echo(" ".join([prefix, package_index["url"]])) deps = {} + categories_list = categories.split(',') if categories else [] - if category: - deps.update(lockfile.get(category, {})) + if categories_list: + for category in categories_list: + deps.update(lockfile.get(category, {})) else: if dev or dev_only: deps.update(lockfile["develop"]) diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index fa8ddf6d..31d9a2b0 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -73,11 +73,13 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(pipe @pytest.mark.requirements -def test_requirements_generates_requirements_from_lockfile_from_a_category(pipenv_instance_private_pypi): +def test_requirements_generates_requirements_from_lockfile_from_categories(pipenv_instance_private_pypi): with pipenv_instance_private_pypi(chdir=True) as p: packages = ('six', '1.12.0') dev_packages = ('itsdangerous', '1.1.0') test_packages = ('pytest', '7.1.3') + doc_packages = ('Sphinx', '5.3.0') + with open(p.pipfile_path, 'w') as f: contents = f""" [[source]] @@ -90,6 +92,8 @@ def test_requirements_generates_requirements_from_lockfile_from_a_category(pipen {dev_packages[0]}= "=={dev_packages[1]}" [test-packages] {test_packages[0]}= "=={test_packages[1]}" + [doc-packages] + {doc_packages[0]}= "=={doc_packages[1]}" """.strip() f.write(contents) l = p.pipenv('lock') @@ -101,11 +105,12 @@ def test_requirements_generates_requirements_from_lockfile_from_a_category(pipen assert f'{test_packages[0]}=={test_packages[1]}' not in c.stdout assert f'{dev_packages[0]}=={dev_packages[1]}' in c.stdout - d = p.pipenv('requirements --category test') + d = p.pipenv('requirements --category 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 c.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_with_git_requirements(pipenv_instance_pypi): From 4569c834e44f0fed999aaf2564d57396bb460ca3 Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 15:40:01 +0530 Subject: [PATCH 4/9] update the test --- tests/integration/test_requirements.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index 31d9a2b0..c2281074 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -90,9 +90,9 @@ def test_requirements_generates_requirements_from_lockfile_from_categories(pipen {packages[0]}= "=={packages[1]}" [dev-packages] {dev_packages[0]}= "=={dev_packages[1]}" - [test-packages] + [test] {test_packages[0]}= "=={test_packages[1]}" - [doc-packages] + [doc] {doc_packages[0]}= "=={doc_packages[1]}" """.strip() f.write(contents) @@ -105,7 +105,7 @@ def test_requirements_generates_requirements_from_lockfile_from_categories(pipen assert f'{test_packages[0]}=={test_packages[1]}' not in c.stdout assert f'{dev_packages[0]}=={dev_packages[1]}' in c.stdout - d = p.pipenv('requirements --category test,doc') + 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 c.stdout From e20763dfa1a8d823c057af37d8b8f23319225520 Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 15:50:23 +0530 Subject: [PATCH 5/9] lint fix --- pipenv/cli/command.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 57490249..9128cd8b 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -740,9 +740,16 @@ def verify(state): ) @option("--hash", is_flag=True, default=False, help="Add package hashes.") @option("--exclude-markers", is_flag=True, default=False, help="Exclude markers.") -@option("--categories", is_flag=False, default='', help="Only add requirement of the specified categories.") +@option( + "--categories", + is_flag=False, + default="", + help="Only add requirement of the specified categories.", +) @pass_state -def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=False, categories=''): +def requirements( + state, dev=False, dev_only=False, hash=False, exclude_markers=False, categories="" +): from pipenv.utils.dependencies import convert_deps_to_pip @@ -753,7 +760,7 @@ def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=F echo(" ".join([prefix, package_index["url"]])) deps = {} - categories_list = categories.split(',') if categories else [] + categories_list = categories.split(",") if categories else [] if categories_list: for category in categories_list: From f2484992de2dd102d494ee6e9e824b61b9db0df8 Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 16:09:59 +0530 Subject: [PATCH 6/9] update docs --- docs/advanced.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/advanced.rst b/docs/advanced.rst index 43847cfd..a6cf001c 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -363,6 +363,27 @@ used to write them to a file:: pytest==3.2.3 setuptools==65.4.1 ; python_version >= '3.7' +If you have multiple categories in your Pipfile and wish to generate +a requirements file for only some categories, you can do that too, +using the ``--categories`` option:: + + $ pipenv requirements --categories="tests" > requirements-tests.txt + $ pipenv requirements --categories="docs" > requirements-docs.txt + $ cat requirements-tests.txt + -i https://pypi.org/simple + attrs==22.1.0 ; python_version >= '3.5' + iniconfig==1.1.1 + packaging==21.3 ; python_version >= '3.6' + pluggy==1.0.0 ; python_version >= '3.6' + py==1.11.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' + pyparsing==3.0.9 ; python_full_version >= '3.6.8' + pytest==7.1.3 + tomli==2.0.1 ; python_version >= '3.7' + +It can be used to specify multiple categories also. + + $ pipenv requirements --categories="tests,docs" + ☤ Detection of Security Vulnerabilities --------------------------------------- From 01ba0e8c28f4a9eb4b5490f394b67de6d4242899 Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 16:54:29 +0530 Subject: [PATCH 7/9] update test --- tests/integration/test_requirements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index c2281074..dd6946c6 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -78,7 +78,7 @@ def test_requirements_generates_requirements_from_lockfile_from_categories(pipen packages = ('six', '1.12.0') dev_packages = ('itsdangerous', '1.1.0') test_packages = ('pytest', '7.1.3') - doc_packages = ('Sphinx', '5.3.0') + doc_packages = ('docutils', '0.19') with open(p.pipfile_path, 'w') as f: contents = f""" From a621facba30840a9bb0125bd4b8fcebcdf40fed9 Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sat, 22 Oct 2022 18:44:03 +0530 Subject: [PATCH 8/9] fix tests --- pipenv/cli/command.py | 1 + tests/integration/test_requirements.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 9128cd8b..d5047adc 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -764,6 +764,7 @@ def requirements( if categories_list: for category in categories_list: + category = category.strip() deps.update(lockfile.get(category, {})) else: if dev or dev_only: diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index dd6946c6..31ea8d54 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -98,17 +98,18 @@ def test_requirements_generates_requirements_from_lockfile_from_categories(pipen f.write(contents) l = p.pipenv('lock') assert l.returncode == 0 - + 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 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 c.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 From e3ea57d519eb571b4d680e642a4ee9ea802ef78f Mon Sep 17 00:00:00 2001 From: dojutsu-user Date: Sun, 23 Oct 2022 13:08:46 +0530 Subject: [PATCH 9/9] add news --- news/5431.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/5431.feature.rst diff --git a/news/5431.feature.rst b/news/5431.feature.rst new file mode 100644 index 00000000..627693cd --- /dev/null +++ b/news/5431.feature.rst @@ -0,0 +1 @@ +Add support to export requirements file for a specified set of categories.