Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb37b584

Browse files
authored
Add --no-lock flag to 'pipenv requirements' command (#6496)
Adds a new --no-lock flag that generates requirements using versionspecifiers from the Pipfile instead of locked versions from Pipfile.lock.This is useful for Python libraries that need flexible version constraints(like '>=1.0', '*') rather than strictly pinned versions (like '==1.2.3')for their install_requires.Examples: # Pipfile has: requests = ">=2.0" pipenv requirements --no-lock # Output: requests>=2.0 # Pipfile has: flask = "*" pipenv requirements --no-lock # Output: flaskThe --no-lock flag implies --from-pipfile since only direct dependenciesmake sense without the lockfile.Fixes#5482
1 parent4aa8431 commitb37b584

File tree

3 files changed

+211
-2
lines changed

3 files changed

+211
-2
lines changed

‎pipenv/cli/command.py‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,14 @@ def verify(state):
988988
"--from-pipfile",
989989
is_flag=True,
990990
default=False,
991-
help="Only include dependencies from Pipfile.",
991+
help="Only include dependencies from Pipfile (excludes transitive deps).",
992+
)
993+
@option(
994+
"--no-lock",
995+
is_flag=True,
996+
default=False,
997+
help="Use version specifiers from Pipfile instead of locked versions. "
998+
"Useful for generating flexible requirements for libraries.",
992999
)
9931000
@pass_state
9941001
defrequirements(
@@ -999,9 +1006,14 @@ def requirements(
9991006
exclude_markers=False,
10001007
categories="",
10011008
from_pipfile=False,
1009+
no_lock=False,
10021010
):
10031011
frompipenv.routines.requirementsimportgenerate_requirements
10041012

1013+
# --no-lock implies --from-pipfile (only direct deps make sense without lock)
1014+
ifno_lock:
1015+
from_pipfile=True
1016+
10051017
generate_requirements(
10061018
project=state.project,
10071019
dev=dev,
@@ -1010,6 +1022,7 @@ def requirements(
10101022
include_markers=notexclude_markers,
10111023
categories=categories,
10121024
from_pipfile=from_pipfile,
1025+
no_lock=no_lock,
10131026
)
10141027

10151028

‎pipenv/routines/requirements.py‎

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
importsys
33

44
frompipenv.utils.dependenciesimportget_lockfile_section_using_pipfile_category
5-
frompipenv.utils.requirementsimportrequirements_from_lockfile
5+
frompipenv.utils.requirementsimport (
6+
requirements_from_lockfile,
7+
requirements_from_pipfile,
8+
)
69

710

811
defgenerate_requirements(
@@ -13,7 +16,19 @@ def generate_requirements(
1316
include_markers=True,
1417
categories="",
1518
from_pipfile=False,
19+
no_lock=False,
1620
):
21+
# If --no-lock, generate from Pipfile directly without using lockfile versions
22+
ifno_lock:
23+
_generate_requirements_from_pipfile(
24+
project=project,
25+
dev=dev,
26+
dev_only=dev_only,
27+
include_markers=include_markers,
28+
categories=categories,
29+
)
30+
return
31+
1732
lockfile=project.load_lockfile(expand_env_vars=False)
1833
pipfile_package_names=project.pipfile_package_names
1934

@@ -69,3 +84,51 @@ def generate_requirements(
6984
print(line)# Use print instead of console.print
7085

7186
sys.exit(0)
87+
88+
89+
def_generate_requirements_from_pipfile(
90+
project,
91+
dev=False,
92+
dev_only=False,
93+
include_markers=True,
94+
categories="",
95+
):
96+
"""Generate requirements directly from Pipfile using flexible version specifiers.
97+
98+
This is useful for libraries that need looser version constraints than
99+
the strictly pinned versions in Pipfile.lock.
100+
"""
101+
parsed_pipfile=project.parsed_pipfile
102+
103+
# Print index URLs from Pipfile sources
104+
sources=parsed_pipfile.get("source", [])
105+
fori,sourceinenumerate(sources):
106+
url=source.get("url","")
107+
ifurl:
108+
prefix="-i"ifi==0else"--extra-index-url"
109+
print(f"{prefix}{url}")
110+
111+
deps= {}
112+
categories_list=re.split(r", *| ",categories)ifcategorieselse []
113+
114+
ifcategories_list:
115+
forcategoryincategories_list:
116+
category_deps=project.get_pipfile_section(category.strip())
117+
deps.update(category_deps)
118+
else:
119+
ifdevordev_only:
120+
dev_deps=project.get_pipfile_section("dev-packages")
121+
deps.update(dev_deps)
122+
ifnotdev_only:
123+
default_deps=project.get_pipfile_section("packages")
124+
deps.update(default_deps)
125+
126+
pip_installable_lines=requirements_from_pipfile(
127+
deps,include_markers=include_markers
128+
)
129+
130+
# Print each requirement on its own line
131+
forlineinpip_installable_lines:
132+
print(line)
133+
134+
sys.exit(0)

‎pipenv/utils/requirements.py‎

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,136 @@ def requirements_from_lockfile(deps, include_hashes=True, include_markers=True):
254254

255255
# pip_packages contains the pip-installable lines
256256
returnpip_packages
257+
258+
259+
defrequirement_from_pipfile(package_name,package_spec,include_markers=True):
260+
"""Convert a Pipfile package entry to a pip requirements line.
261+
262+
Uses the version specifiers from the Pipfile (like "*", ">=1.0") rather than
263+
locked versions. This is useful for generating requirements for libraries
264+
that need more flexible version constraints.
265+
266+
Args:
267+
package_name: The package name
268+
package_spec: The package specification from Pipfile (str or dict)
269+
include_markers: Whether to include environment markers
270+
271+
Returns:
272+
A pip-installable requirement line
273+
"""
274+
frompipenv.utils.dependenciesimportis_editable_path,is_star
275+
276+
# Handle simple string specifications like "*", ">=1.0", "==1.0"
277+
ifisinstance(package_spec,str):
278+
ifis_star(package_spec):
279+
returnpackage_name
280+
elifpackage_spec.startswith(("==",">=","<=",">","<","~=","!=")):
281+
returnf"{package_name}{package_spec}"
282+
else:
283+
# Assume it's a version without operator, default to ==
284+
returnf"{package_name}=={package_spec}"
285+
286+
# Handle dict specifications
287+
ifnotisinstance(package_spec,dict):
288+
returnpackage_name
289+
290+
# Handle VCS dependencies
291+
forvcs_typein ["git","hg","svn","bzr"]:
292+
ifvcs_typeinpackage_spec:
293+
vcs_url=package_spec[vcs_type]
294+
ref=package_spec.get("ref","")
295+
subdirectory=package_spec.get("subdirectory","")
296+
extras= (
297+
"[{}]".format(",".join(package_spec.get("extras", [])))
298+
if"extras"inpackage_spec
299+
else""
300+
)
301+
302+
# Build the VCS URL
303+
ref_str=f"@{ref}"ifrefandf"@{ref}"notinvcs_urlelse""
304+
egg_fragment=f"#egg={package_name}"if"#egg="notinvcs_urlelse""
305+
306+
if (
307+
is_editable_path(vcs_url)
308+
or"file://"invcs_url
309+
orpackage_spec.get("editable",False)
310+
):
311+
line=f"-e{vcs_type}+{vcs_url}{ref_str}{egg_fragment}{extras}"
312+
ifsubdirectory:
313+
line+=f"&subdirectory={subdirectory}"
314+
else:
315+
line=f"{package_name}{extras} @{vcs_type}+{vcs_url}{ref_str}"
316+
ifsubdirectory:
317+
line+=f"#subdirectory={subdirectory}"
318+
returnline
319+
320+
# Handle file/path dependencies
321+
forkeyin ["file","path"]:
322+
ifkeyinpackage_spec:
323+
path=package_spec[key]
324+
parts= []
325+
ifpackage_spec.get("editable")andis_editable_path(path):
326+
parts.append("-e")
327+
parts.append(path)
328+
329+
ifinclude_markers:
330+
if"markers"inpackage_specandpackage_spec["markers"]:
331+
parts.append(f";{package_spec['markers']}")
332+
return" ".join(parts)
333+
334+
# Handle standard version specifications
335+
version=package_spec.get("version","")
336+
extras= (
337+
"[{}]".format(",".join(package_spec.get("extras", [])))
338+
if"extras"inpackage_spec
339+
else""
340+
)
341+
342+
# Process version
343+
ifis_star(version):
344+
version_str=""
345+
elifversion.startswith(("==",">=","<=",">","<","~=","!=")):
346+
version_str=version
347+
elifversion:
348+
version_str=f"=={version}"
349+
else:
350+
version_str=""
351+
352+
# Process markers
353+
markers=""
354+
ifinclude_markers:
355+
# Handle sys_platform and other common markers
356+
marker_parts= []
357+
if"markers"inpackage_specandpackage_spec["markers"]:
358+
marker_parts.append(package_spec["markers"])
359+
if"sys_platform"inpackage_specandpackage_spec["sys_platform"]:
360+
marker_parts.append(f"sys_platform{package_spec['sys_platform']}")
361+
362+
ifmarker_parts:
363+
markers="; "+" and ".join(marker_parts)
364+
365+
returnf"{package_name}{extras}{version_str}{markers}"
366+
367+
368+
defrequirements_from_pipfile(deps,include_markers=True):
369+
"""Convert Pipfile dependencies to pip requirements lines.
370+
371+
Uses the version specifiers from the Pipfile rather than locked versions.
372+
373+
Args:
374+
deps: Dictionary of package names to specifications from Pipfile
375+
include_markers: Whether to include environment markers
376+
377+
Returns:
378+
List of pip-installable requirement lines
379+
"""
380+
pip_packages= []
381+
382+
forpackage_name,package_specindeps.items():
383+
pip_package=requirement_from_pipfile(
384+
package_name,package_spec,include_markers
385+
)
386+
ifpip_package:
387+
pip_packages.append(pip_package)
388+
389+
returnpip_packages

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp