Skip to content

Commit

Permalink
Merge pull request #6156 from sanspareilsmyn/requirements-root-only-o…
Browse files Browse the repository at this point in the history
…ption

Add --from-pipfile subcommand to `pipenv requirements`
  • Loading branch information
matteius authored May 24, 2024
2 parents e9e5adf + 6ec19bb commit 5e63306
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 4 deletions.
1 change: 1 addition & 0 deletions news/6156.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The ``pipenv requirements`` subcommand now supports the ``--from-pipfile`` flag. When this flag is used, the requirements file will only include the packages explicitly listed in the Pipfile, excluding any sub-packages.
15 changes: 14 additions & 1 deletion pipenv/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,9 +744,21 @@ def verify(state):
default="",
help="Only add requirement of the specified categories.",
)
@option(
"--from-pipfile",
is_flag=True,
default=False,
help="Only include dependencies from Pipfile.",
)
@pass_state
def requirements(
state, dev=False, dev_only=False, hash=False, exclude_markers=False, categories=""
state,
dev=False,
dev_only=False,
hash=False,
exclude_markers=False,
categories="",
from_pipfile=False,
):
from pipenv.routines.requirements import generate_requirements

Expand All @@ -757,6 +769,7 @@ def requirements(
include_hashes=hash,
include_markers=not exclude_markers,
categories=categories,
from_pipfile=from_pipfile,
)


Expand Down
27 changes: 24 additions & 3 deletions pipenv/routines/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ def generate_requirements(
include_hashes=False,
include_markers=True,
categories="",
from_pipfile=False,
):
lockfile = project.load_lockfile(expand_env_vars=False)
pipfile_root_package_names = project.pipfile_package_names["combined"]

for i, package_index in enumerate(lockfile["_meta"]["sources"]):
prefix = "-i" if i == 0 else "--extra-index-url"
Expand All @@ -26,12 +28,31 @@ def generate_requirements(
if categories_list:
for category in categories_list:
category = get_lockfile_section_using_pipfile_category(category.strip())
deps.update(lockfile.get(category, {}))
category_deps = lockfile.get(category, {})
if from_pipfile:
category_deps = {
k: v
for k, v in category_deps.items()
if k in pipfile_root_package_names
}
deps.update(category_deps)
else:
if dev or dev_only:
deps.update(lockfile["develop"])
dev_deps = lockfile["develop"]
if from_pipfile:
dev_deps = {
k: v for k, v in dev_deps.items() if k in pipfile_root_package_names
}
deps.update(dev_deps)
if not dev_only:
deps.update(lockfile["default"])
default_deps = lockfile["default"]
if from_pipfile:
default_deps = {
k: v
for k, v in default_deps.items()
if k in pipfile_root_package_names
}
deps.update(default_deps)

pip_installable_lines = requirements_from_lockfile(
deps, include_hashes=include_hashes, include_markers=include_markers
Expand Down
48 changes: 48 additions & 0 deletions tests/integration/test_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,54 @@ def test_requirements_generates_requirements_from_lockfile_from_categories(pipen
assert f'{doc_packages[0]}=={doc_packages[1]}' in d.stdout


@pytest.mark.requirements
def test_requirements_generates_requirements_with_from_pipfile(pipenv_instance_pypi):
with pipenv_instance_pypi() as p:
packages = ('requests', '2.31.0')
sub_packages = ('urllib3', '2.2.1') # subpackages not explicitly written in Pipfile.
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('requirements --from-pipfile')
assert c.returncode == 0
assert f'{packages[0]}=={packages[1]}' in c.stdout
assert f'{sub_packages[0]}=={sub_packages[1]}' not in c.stdout
assert f'{dev_packages[0]}=={dev_packages[1]}' not in c.stdout

d = p.pipenv('requirements --dev --from-pipfile')
assert d.returncode == 0
assert f'{packages[0]}=={packages[1]}' in d.stdout
assert f'{sub_packages[0]}=={sub_packages[1]}' not in d.stdout
assert f'{dev_packages[0]}=={dev_packages[1]}' in d.stdout

e = p.pipenv('requirements --dev-only --from-pipfile')
assert e.returncode == 0
assert f'{packages[0]}=={packages[1]}' not in e.stdout
assert f'{sub_packages[0]}=={sub_packages[1]}' not in e.stdout
assert f'{dev_packages[0]}=={dev_packages[1]}' in e.stdout

f = p.pipenv('requirements --categories=dev-packages --from-pipfile')
assert f.returncode == 0
assert f'{packages[0]}=={packages[1]}' not in f.stdout
assert f'{sub_packages[0]}=={sub_packages[1]}' not in f.stdout
assert f'{dev_packages[0]}=={dev_packages[1]}' in f.stdout

g = p.pipenv('requirements --categories=packages,dev-packages --from-pipfile')
assert g.returncode == 0
assert f'{packages[0]}=={packages[1]}' in g.stdout
assert f'{sub_packages[0]}=={sub_packages[1]}' not in g.stdout
assert f'{dev_packages[0]}=={dev_packages[1]}' in g.stdout


@pytest.mark.requirements
def test_requirements_with_git_requirements(pipenv_instance_pypi):
req_hash = '3264a0046e1aa3c0a813335286ebdbc651f58b13'
Expand Down

0 comments on commit 5e63306

Please sign in to comment.