From 0a40d75e361362be4ec266c38ebc045b5ad92695 Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Sat, 26 Mar 2022 08:52:27 +0100 Subject: [PATCH 01/12] Implements reqs command --- Pipfile | 1 + README.md | 4 +++ docs/advanced.rst | 37 ++++++++++++++++++++-- pipenv/cli/command.py | 19 ++++++++++++ tests/integration/test_reqs.py | 56 ++++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 tests/integration/test_reqs.py diff --git a/Pipfile b/Pipfile index a4888164fd..63e7506ff8 100644 --- a/Pipfile +++ b/Pipfile @@ -11,6 +11,7 @@ sphinxcontrib-spelling = "<4.3.0" [scripts] tests = "bash ./run-tests.sh" +test = "pytest -vvs" [pipenv] allow_prereleases = true diff --git a/README.md b/README.md index b0baf4f361..b14e6ab736 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,9 @@ Magic shell completions are now enabled! Use a lower-level pip command: $ pipenv run pip freeze + Generate a requirements.txt file (including dev): + $ pipenv reqs --dev > requirements.txt + Commands: check Checks for security vulnerabilities and against PEP 508 markers provided in Pipfile. @@ -199,6 +202,7 @@ Magic shell completions are now enabled! Pipfile. shell Spawns a shell within the virtualenv. sync Installs all packages specified in Pipfile.lock. + reqs Generates a requirements.txt compatible output directly from Pipfile.lock uninstall Un-installs a provided package and removes it from Pipfile. Locate the project: diff --git a/docs/advanced.rst b/docs/advanced.rst index 3d863c6f32..1484cb38ac 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -199,7 +199,7 @@ development dependencies:: py==1.4.34 pytest==3.2.3 -Finally, if you wish to generate a requirements file with only the +If you wish to generate a requirements file with only the development requirements you can do that too, using the ``--dev-only`` flag:: @@ -207,11 +207,37 @@ flag:: py==1.4.34 pytest==3.2.3 +Often, you would want to generate a requirements file based on your current +environment. However, using pipenv lock -r will still do the locking process which +could update package versions. To keep the packages as is, use the ``--keep-outdated`` +flag:: + + $ pipenv lock -r --keep-outdated + chardet==3.0.4 + requests==2.18.4 + certifi==2017.7.27.1 + idna==2.6 + urllib3==1.22 + +Note that using this approach, packages newly added to the Pipfile will still be +included in requirements.txt. If you really want to use Pipfile.lock and +Pipfile.lock only, you can generate the requirements using:: + $ pipenv reqs + chardet==3.0.4 + requests==2.18.4 + certifi==2017.7.27.1 + idna==2.6 + urllib3==1.22 + +This will bypass the locking process completely. As with other commands, +passing ``--dev`` will include both the default and development dependencies + The locked requirements are written to stdout, with shell output redirection used to write them to a file:: $ pipenv lock -r > requirements.txt $ pipenv lock -r --dev-only > dev-requirements.txt + $ pipenv reqs --dev > all-requirements.txt $ cat requirements.txt chardet==3.0.4 requests==2.18.4 @@ -221,7 +247,14 @@ used to write them to a file:: $ cat dev-requirements.txt py==1.4.34 pytest==3.2.3 - + $ cat all-requirements.txt + chardet==3.0.4 + requests==2.18.4 + certifi==2017.7.27.1 + idna==2.6 + urllib3==1.22 + py==1.4.34 + pytest==3.2.3 ☤ Detection of Security Vulnerabilities --------------------------------------- diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index c6470a6cfb..37e3f0ddb4 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -709,5 +709,24 @@ def verify(state): sys.exit(0) +@cli.command( + short_help="Generate a requirements.txt from Pipfile.lock.", + context_settings=CONTEXT_SETTINGS, +) +@option("--dev", is_flag=True, default=False, help="Also add development requirements.") +@pass_state +def reqs(state, dev=False): + lockfile = state.project.lockfile_content + for i, package_index in enumerate(lockfile['_meta']['sources']): + prefix = '-i' if i == 0 else '--extra-index-url' + echo(crayons.normal(' '.join([prefix, package_index['url']]))) + for req_name, value in lockfile['default'].items(): + echo(crayons.normal(f"{req_name}{value['version']}")) + if dev: + for req_name, value in lockfile['develop'].items(): + echo(crayons.normal(f"{req_name}{value['version']}")) + sys.exit(0) + + if __name__ == "__main__": cli() diff --git a/tests/integration/test_reqs.py b/tests/integration/test_reqs.py new file mode 100644 index 0000000000..c410c84b26 --- /dev/null +++ b/tests/integration/test_reqs.py @@ -0,0 +1,56 @@ +import pytest + + +@pytest.mark.requirements +def test_reqs_generates_requirements_from_lockfile(PipenvInstance): + with PipenvInstance(chdir=True) as p: + 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]}" + [dev-packages] + {dev_packages[0]}= "=={dev_packages[1]}" + """.strip() + f.write(contents) + p.pipenv('lock') + c = p.pipenv('reqs') + d = p.pipenv('reqs --dev') + assert c.returncode == 0 + assert d.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 d.stdout + assert f'{dev_packages[0]}=={dev_packages[1]}' in d.stdout + + +@pytest.mark.requirements +def test_reqs_generates_requirements_from_lockfile_multiple_sources(PipenvInstance): + with PipenvInstance(chdir=True) as p: + packages = ('requests', '2.14.0') + dev_packages = ('flask', '0.12.2') + with open(p.pipfile_path, 'w') as f: + contents = f""" + [[source]] + name = "pypi" + url = "https://pypi.org/simple" + verify_ssl = true + [[source]] + name = "other_source" + url = "https://some_other_source.org" + verify_ssl = true + [packages] + {packages[0]}= "=={packages[1]}" + [dev-packages] + {dev_packages[0]}= "=={dev_packages[1]}" + """.strip() + f.write(contents) + p.pipenv('lock') + c = p.pipenv('reqs') + 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 From 8111e3a2fb04eb60420c315290d1d0e852b5633e Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Sat, 26 Mar 2022 09:01:02 +0100 Subject: [PATCH 02/12] Add news document --- news/#4959.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/#4959.feature diff --git a/news/#4959.feature b/news/#4959.feature new file mode 100644 index 0000000000..a76e4c7fdd --- /dev/null +++ b/news/#4959.feature @@ -0,0 +1 @@ +Implements a `pipenv reqs` command which generates a requirements.txt compatible output without locking. \ No newline at end of file From afe90dd223f17d38a331d8159e476439ede2f012 Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Mon, 28 Mar 2022 09:36:35 +0200 Subject: [PATCH 03/12] Process comments --- README.md | 32 +++++++++---------- docs/advanced.rst | 8 ++--- news/#4959.feature | 2 +- pipenv/cli/command.py | 2 +- .../{test_reqs.py => test_requirements.py} | 10 +++--- 5 files changed, 27 insertions(+), 27 deletions(-) rename tests/integration/{test_reqs.py => test_requirements.py} (85%) diff --git a/README.md b/README.md index b14e6ab736..d467892dc3 100644 --- a/README.md +++ b/README.md @@ -186,24 +186,24 @@ Magic shell completions are now enabled! $ pipenv run pip freeze Generate a requirements.txt file (including dev): - $ pipenv reqs --dev > requirements.txt + $ pipenv requirements --dev > requirements.txt Commands: - check Checks for security vulnerabilities and against PEP 508 markers - provided in Pipfile. - clean Uninstalls all packages not specified in Pipfile.lock. - graph Displays currently–installed dependency graph information. - install Installs provided packages and adds them to Pipfile, or (if no - packages are given), installs all packages from Pipfile. - lock Generates Pipfile.lock. - open View a given module in your editor. - run Spawns a command installed into the virtualenv. - scripts Displays the shortcuts in the (optional) [scripts] section of - Pipfile. - shell Spawns a shell within the virtualenv. - sync Installs all packages specified in Pipfile.lock. - reqs Generates a requirements.txt compatible output directly from Pipfile.lock - uninstall Un-installs a provided package and removes it from Pipfile. + check Checks for security vulnerabilities and against PEP 508 markers + provided in Pipfile. + clean Uninstalls all packages not specified in Pipfile.lock. + graph Displays currently–installed dependency graph information. + install Installs provided packages and adds them to Pipfile, or (if no + packages are given), installs all packages from Pipfile. + lock Generates Pipfile.lock. + open View a given module in your editor. + run Spawns a command installed into the virtualenv. + scripts Displays the shortcuts in the (optional) [scripts] section of + Pipfile. + shell Spawns a shell within the virtualenv. + sync Installs all packages specified in Pipfile.lock. + requirements Generates a requirements.txt compatible output directly from Pipfile.lock + uninstall Un-installs a provided package and removes it from Pipfile. Locate the project: diff --git a/docs/advanced.rst b/docs/advanced.rst index 1484cb38ac..a5bda7d622 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -207,7 +207,7 @@ flag:: py==1.4.34 pytest==3.2.3 -Often, you would want to generate a requirements file based on your current +Sometimes, you would want to generate a requirements file based on your current environment. However, using pipenv lock -r will still do the locking process which could update package versions. To keep the packages as is, use the ``--keep-outdated`` flag:: @@ -222,7 +222,7 @@ flag:: Note that using this approach, packages newly added to the Pipfile will still be included in requirements.txt. If you really want to use Pipfile.lock and Pipfile.lock only, you can generate the requirements using:: - $ pipenv reqs + $ pipenv requirements chardet==3.0.4 requests==2.18.4 certifi==2017.7.27.1 @@ -230,14 +230,14 @@ Pipfile.lock only, you can generate the requirements using:: urllib3==1.22 This will bypass the locking process completely. As with other commands, -passing ``--dev`` will include both the default and development dependencies +passing ``--dev`` will include both the default and development dependencies. The locked requirements are written to stdout, with shell output redirection used to write them to a file:: $ pipenv lock -r > requirements.txt $ pipenv lock -r --dev-only > dev-requirements.txt - $ pipenv reqs --dev > all-requirements.txt + $ pipenv requirements --dev > all-requirements.txt $ cat requirements.txt chardet==3.0.4 requests==2.18.4 diff --git a/news/#4959.feature b/news/#4959.feature index a76e4c7fdd..cd7ae0e61d 100644 --- a/news/#4959.feature +++ b/news/#4959.feature @@ -1 +1 @@ -Implements a `pipenv reqs` command which generates a requirements.txt compatible output without locking. \ No newline at end of file +Implements a `pipenv requirements` command which generates a requirements.txt compatible output without locking. \ No newline at end of file diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 37e3f0ddb4..8cc25670ad 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -715,7 +715,7 @@ def verify(state): ) @option("--dev", is_flag=True, default=False, help="Also add development requirements.") @pass_state -def reqs(state, dev=False): +def requirements(state, dev=False): lockfile = state.project.lockfile_content for i, package_index in enumerate(lockfile['_meta']['sources']): prefix = '-i' if i == 0 else '--extra-index-url' diff --git a/tests/integration/test_reqs.py b/tests/integration/test_requirements.py similarity index 85% rename from tests/integration/test_reqs.py rename to tests/integration/test_requirements.py index c410c84b26..1b2f1a63c5 100644 --- a/tests/integration/test_reqs.py +++ b/tests/integration/test_requirements.py @@ -2,7 +2,7 @@ @pytest.mark.requirements -def test_reqs_generates_requirements_from_lockfile(PipenvInstance): +def test_requirements_generates_requirements_from_lockfile(PipenvInstance): with PipenvInstance(chdir=True) as p: packages = ('requests', '2.14.0') dev_packages = ('flask', '0.12.2') @@ -15,8 +15,8 @@ def test_reqs_generates_requirements_from_lockfile(PipenvInstance): """.strip() f.write(contents) p.pipenv('lock') - c = p.pipenv('reqs') - d = p.pipenv('reqs --dev') + c = p.pipenv('requirements') + d = p.pipenv('requirements --dev') assert c.returncode == 0 assert d.returncode == 0 @@ -28,7 +28,7 @@ def test_reqs_generates_requirements_from_lockfile(PipenvInstance): @pytest.mark.requirements -def test_reqs_generates_requirements_from_lockfile_multiple_sources(PipenvInstance): +def test_requirements_generates_requirements_from_lockfile_multiple_sources(PipenvInstance): with PipenvInstance(chdir=True) as p: packages = ('requests', '2.14.0') dev_packages = ('flask', '0.12.2') @@ -49,7 +49,7 @@ def test_reqs_generates_requirements_from_lockfile_multiple_sources(PipenvInstan """.strip() f.write(contents) p.pipenv('lock') - c = p.pipenv('reqs') + c = p.pipenv('requirements') assert c.returncode == 0 assert '-i https://pypi.org/simple' in c.stdout From 29ae33eeac96a6b1b8782756215430abd670fb76 Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Mon, 28 Mar 2022 09:38:45 +0200 Subject: [PATCH 04/12] Rename newsfile --- news/{#4959.feature => 4959.feature.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename news/{#4959.feature => 4959.feature.rst} (100%) diff --git a/news/#4959.feature b/news/4959.feature.rst similarity index 100% rename from news/#4959.feature rename to news/4959.feature.rst From 9345ed2d6f3084199fd935bc23d53d75bd2ac39d Mon Sep 17 00:00:00 2001 From: Imre Persoonlijk Date: Fri, 1 Apr 2022 14:27:44 +0200 Subject: [PATCH 05/12] Adds --dev-only and --hash args --- pipenv/cli/command.py | 15 ++++++++++----- tests/integration/test_requirements.py | 24 ++++++++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 8cc25670ad..5b6700a02c 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -714,17 +714,22 @@ def verify(state): context_settings=CONTEXT_SETTINGS, ) @option("--dev", is_flag=True, default=False, help="Also add development requirements.") +@option("--dev-only", is_flag=True, default=False, help="Only add development requirements.") +@option("--hash", is_flag=True, default=False, help="Add package hashes.") @pass_state -def requirements(state, dev=False): +def requirements(state, dev=False, dev_only=False, hash=False): lockfile = state.project.lockfile_content for i, package_index in enumerate(lockfile['_meta']['sources']): prefix = '-i' if i == 0 else '--extra-index-url' echo(crayons.normal(' '.join([prefix, package_index['url']]))) - for req_name, value in lockfile['default'].items(): - echo(crayons.normal(f"{req_name}{value['version']}")) - if dev: + if not dev_only: + for req_name, value in lockfile['default'].items(): + hashes = [f' \\\n --hash={h}' for h in value['hashes'] if hash] + echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) + if dev or dev_only: for req_name, value in lockfile['develop'].items(): - echo(crayons.normal(f"{req_name}{value['version']}")) + hashes = [f' \\\n --hash={h}' for h in value['hashes'] if hash] + echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) sys.exit(0) diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index 1b2f1a63c5..82cbc8c460 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -16,16 +16,27 @@ def test_requirements_generates_requirements_from_lockfile(PipenvInstance): f.write(contents) p.pipenv('lock') c = p.pipenv('requirements') - d = p.pipenv('requirements --dev') assert c.returncode == 0 - assert d.returncode == 0 - 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') + assert d.returncode == 0 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') + 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 + + 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 + @pytest.mark.requirements def test_requirements_generates_requirements_from_lockfile_multiple_sources(PipenvInstance): @@ -40,7 +51,7 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(Pipe verify_ssl = true [[source]] name = "other_source" - url = "https://some_other_source.org" + url = "https://https://$USERNAME:${{PASSWORD}}@some_other_source.org" verify_ssl = true [packages] {packages[0]}= "=={packages[1]}" @@ -48,9 +59,10 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(Pipe {dev_packages[0]}= "=={dev_packages[1]}" """.strip() f.write(contents) - p.pipenv('lock') + l = p.pipenv('lock') + assert l.returncode == 0 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 '--extra-index-url https://$USERNAME:${PASSWORD}@some_other_source.org' in c.stdout From 4439d27ce397a121d76244128ca92c59b1673072 Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Fri, 1 Apr 2022 14:59:12 +0200 Subject: [PATCH 06/12] Fix typo in 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 82cbc8c460..169d51c32a 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -51,7 +51,7 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(Pipe verify_ssl = true [[source]] name = "other_source" - url = "https://https://$USERNAME:${{PASSWORD}}@some_other_source.org" + url = "https://$USERNAME:${{PASSWORD}}@some_other_source.org" verify_ssl = true [packages] {packages[0]}= "=={packages[1]}" From 3de86808b6975be41046c073a271b2ffc548f5be Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Fri, 1 Apr 2022 15:08:28 +0200 Subject: [PATCH 07/12] Rewrite hash if..else statement --- pipenv/cli/command.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 5b6700a02c..e0b5a4a226 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -724,11 +724,17 @@ def requirements(state, dev=False, dev_only=False, hash=False): echo(crayons.normal(' '.join([prefix, package_index['url']]))) if not dev_only: for req_name, value in lockfile['default'].items(): - hashes = [f' \\\n --hash={h}' for h in value['hashes'] if hash] + if hash: + hashes = [f' \\\n --hash={h}' for h in value['hashes']] + else: + hashes = [] echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) if dev or dev_only: for req_name, value in lockfile['develop'].items(): - hashes = [f' \\\n --hash={h}' for h in value['hashes'] if hash] + if hash: + hashes = [f' \\\n --hash={h}' for h in value['hashes']] + else: + hashes = [] echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) sys.exit(0) From 7306ab51bad056e3186fd92bdc555b89b6aaa00f Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Fri, 1 Apr 2022 15:10:56 +0200 Subject: [PATCH 08/12] Fix test --- tests/integration/test_requirements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_requirements.py b/tests/integration/test_requirements.py index 169d51c32a..7eb077f57f 100644 --- a/tests/integration/test_requirements.py +++ b/tests/integration/test_requirements.py @@ -51,7 +51,7 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(Pipe verify_ssl = true [[source]] name = "other_source" - url = "https://$USERNAME:${{PASSWORD}}@some_other_source.org" + url = "https://some_other_source.org" verify_ssl = true [packages] {packages[0]}= "=={packages[1]}" @@ -65,4 +65,4 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(Pipe assert c.returncode == 0 assert '-i https://pypi.org/simple' in c.stdout - assert '--extra-index-url https://$USERNAME:${PASSWORD}@some_other_source.org' in c.stdout + assert '--extra-index-url https://some_other_source.org' in c.stdout From 54c8eef7efe9852fcc9da85281536e7304e9ac2f Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Fri, 1 Apr 2022 15:20:50 +0200 Subject: [PATCH 09/12] Readme update --- docs/advanced.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/advanced.rst b/docs/advanced.rst index a5bda7d622..745b97f40b 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -231,6 +231,8 @@ Pipfile.lock only, you can generate the requirements using:: This will bypass the locking process completely. As with other commands, passing ``--dev`` will include both the default and development dependencies. +Passing ``--dev-only`` only will include only development dependencies and ``--hash`` will +add package hashes to the output for extra security. The locked requirements are written to stdout, with shell output redirection used to write them to a file:: From 2018c791bdea2340e3b91fd420141fb5b41ec154 Mon Sep 17 00:00:00 2001 From: ImreC Date: Fri, 1 Apr 2022 15:27:34 +0200 Subject: [PATCH 10/12] Fix typo --- docs/advanced.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced.rst b/docs/advanced.rst index 745b97f40b..16b379c688 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -231,7 +231,7 @@ Pipfile.lock only, you can generate the requirements using:: This will bypass the locking process completely. As with other commands, passing ``--dev`` will include both the default and development dependencies. -Passing ``--dev-only`` only will include only development dependencies and ``--hash`` will +Passing ``--dev-only`` will include only development dependencies and ``--hash`` will add package hashes to the output for extra security. The locked requirements are written to stdout, with shell output redirection From 64e487c560832dae680a75ab840d675d6c6c2a97 Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Fri, 1 Apr 2022 17:01:37 +0200 Subject: [PATCH 11/12] Handle the case when there are no hashes --- pipenv/cli/command.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index e0b5a4a226..fdaf805fe7 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -725,14 +725,14 @@ def requirements(state, dev=False, dev_only=False, hash=False): if not dev_only: for req_name, value in lockfile['default'].items(): if hash: - hashes = [f' \\\n --hash={h}' for h in value['hashes']] + hashes = [f' \\\n --hash={h}' for h in value.get('hashes', [])] else: hashes = [] echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) if dev or dev_only: for req_name, value in lockfile['develop'].items(): if hash: - hashes = [f' \\\n --hash={h}' for h in value['hashes']] + hashes = [f' \\\n --hash={h}' for h in value.get('hashes', [])] else: hashes = [] echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) From 7fab3bfbfe989152723e21e5ba46a71a84c5f980 Mon Sep 17 00:00:00 2001 From: Imre Gelens Date: Fri, 1 Apr 2022 19:09:30 +0200 Subject: [PATCH 12/12] Linting fixes --- news/4959.feature.rst | 2 +- pipenv/cli/command.py | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/news/4959.feature.rst b/news/4959.feature.rst index cd7ae0e61d..70911ac38a 100644 --- a/news/4959.feature.rst +++ b/news/4959.feature.rst @@ -1 +1 @@ -Implements a `pipenv requirements` command which generates a requirements.txt compatible output without locking. \ No newline at end of file +Implements a ``pipenv requirements`` command which generates a requirements.txt compatible output without locking. diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 0aca915299..de90881cec 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -751,28 +751,30 @@ def verify(state): context_settings=CONTEXT_SETTINGS, ) @option("--dev", is_flag=True, default=False, help="Also add development requirements.") -@option("--dev-only", is_flag=True, default=False, help="Only add development requirements.") +@option( + "--dev-only", is_flag=True, default=False, help="Only add development requirements." +) @option("--hash", is_flag=True, default=False, help="Add package hashes.") @pass_state def requirements(state, dev=False, dev_only=False, hash=False): lockfile = state.project.lockfile_content - for i, package_index in enumerate(lockfile['_meta']['sources']): - prefix = '-i' if i == 0 else '--extra-index-url' - echo(crayons.normal(' '.join([prefix, package_index['url']]))) + for i, package_index in enumerate(lockfile["_meta"]["sources"]): + prefix = "-i" if i == 0 else "--extra-index-url" + echo(crayons.normal(" ".join([prefix, package_index["url"]]))) if not dev_only: - for req_name, value in lockfile['default'].items(): + for req_name, value in lockfile["default"].items(): if hash: - hashes = [f' \\\n --hash={h}' for h in value.get('hashes', [])] + hashes = [f" \\\n --hash={h}" for h in value.get("hashes", [])] else: hashes = [] - echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) + echo(crayons.normal("".join([req_name, value["version"], *hashes]))) if dev or dev_only: - for req_name, value in lockfile['develop'].items(): + for req_name, value in lockfile["develop"].items(): if hash: - hashes = [f' \\\n --hash={h}' for h in value.get('hashes', [])] + hashes = [f" \\\n --hash={h}" for h in value.get("hashes", [])] else: hashes = [] - echo(crayons.normal(''.join([req_name, value['version'], *hashes]))) + echo(crayons.normal("".join([req_name, value["version"], *hashes]))) sys.exit(0)