Skip to content

Commit 717e71e

Browse files
committed
Cherry-adapt from #16934
1 parent a607b02 commit 717e71e

6 files changed

+129
-13
lines changed

src/python/pants/backend/python/goals/lockfile.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -272,15 +272,18 @@ async def setup_user_lockfile_requests(
272272

273273
@dataclass(frozen=True)
274274
class PythonSyntheticLockfileTargetsRequest(SyntheticTargetsRequest):
275-
path: str = "" # Indicate that all targets are provided with a single request.
275+
path: str = SyntheticTargetsRequest.SINGLE_REQUEST_FOR_ALL_TARGETS
276276

277277

278278
@rule
279279
async def python_lockfile_synthetic_targets(
280280
request: PythonSyntheticLockfileTargetsRequest,
281281
python_setup: PythonSetup,
282282
) -> SyntheticAddressMaps:
283-
if not python_setup.enable_resolves:
283+
if (
284+
not python_setup.enable_resolves
285+
or request.path != SyntheticTargetsRequest.SINGLE_REQUEST_FOR_ALL_TARGETS
286+
):
284287
return SyntheticAddressMaps()
285288

286289
resolves = [

src/python/pants/backend/python/macros/pipenv_requirements.py

+15-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
TypeStubsModuleMappingField,
1414
)
1515
from pants.backend.python.pip_requirement import PipRequirement
16+
from pants.backend.python.subsystems.setup import PythonSetup
1617
from pants.backend.python.target_types import (
1718
PythonRequirementModulesField,
1819
PythonRequirementResolveField,
@@ -70,7 +71,9 @@ class GenerateFromPipenvRequirementsRequest(GenerateTargetsRequest):
7071
# TODO(#10655): differentiate between Pipfile vs. Pipfile.lock.
7172
@rule(desc="Generate `python_requirement` targets from Pipfile.lock", level=LogLevel.DEBUG)
7273
async def generate_from_pipenv_requirement(
73-
request: GenerateFromPipenvRequirementsRequest, union_membership: UnionMembership
74+
request: GenerateFromPipenvRequirementsRequest,
75+
union_membership: UnionMembership,
76+
python_setup: PythonSetup,
7477
) -> GeneratedTargets:
7578
generator = request.generator
7679
lock_rel_path = generator[PipenvSourceField].value
@@ -90,6 +93,15 @@ async def generate_from_pipenv_requirement(
9093
union_membership,
9194
)
9295

96+
req_deps = [file_tgt.address.spec]
97+
98+
resolve = request.template.get(
99+
PythonRequirementResolveField.alias, python_setup.default_resolve
100+
)
101+
lockfile = python_setup.resolves.get(resolve) if python_setup.enable_resolves else None
102+
if lockfile:
103+
req_deps.append(f"{lockfile}:{resolve}")
104+
93105
digest_contents = await Get(
94106
DigestContents,
95107
PathGlobs(
@@ -106,9 +118,7 @@ def generate_tgt(parsed_req: PipRequirement) -> PythonRequirementTarget:
106118
normalized_proj_name = canonicalize_project_name(parsed_req.project_name)
107119
tgt_overrides = overrides.pop(normalized_proj_name, {})
108120
if Dependencies.alias in tgt_overrides:
109-
tgt_overrides[Dependencies.alias] = list(tgt_overrides[Dependencies.alias]) + [
110-
file_tgt.address.spec
111-
]
121+
tgt_overrides[Dependencies.alias] = list(tgt_overrides[Dependencies.alias]) + req_deps
112122

113123
return PythonRequirementTarget(
114124
{
@@ -120,7 +130,7 @@ def generate_tgt(parsed_req: PipRequirement) -> PythonRequirementTarget:
120130
),
121131
# This may get overridden by `tgt_overrides`, which will have already added in
122132
# the file tgt.
123-
Dependencies.alias: [file_tgt.address.spec],
133+
Dependencies.alias: req_deps,
124134
**tgt_overrides,
125135
},
126136
request.template_address.create_generated(parsed_req.project_name),

src/python/pants/backend/python/macros/pipenv_requirements_test.py

+44-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ def assert_pipenv_requirements(
4848

4949

5050
def test_pipfile_lock(rule_runner: RuleRunner) -> None:
51-
"""This tests that we correctly create a new python_requirement_library for each entry in a
52-
Pipfile.lock file.
51+
"""This tests that we correctly create a new python_requirement for each entry in a Pipfile.lock
52+
file.
5353
5454
Edge cases:
5555
@@ -89,3 +89,45 @@ def test_pipfile_lock(rule_runner: RuleRunner) -> None:
8989
TargetGeneratorSourcesHelperTarget({"source": "Pipfile.lock"}, file_addr),
9090
},
9191
)
92+
93+
94+
def test_pipfile_lockfile_dependency(rule_runner: RuleRunner) -> None:
95+
"""This tests that we adds a dependency on the lockfile for the resolve for each generated
96+
python_requirement."""
97+
rule_runner.set_options(["--python-enable-resolves"])
98+
file_addr = Address("", target_name="reqs", relative_file_path="Pipfile.lock")
99+
lock_addr = Address(
100+
"3rdparty/python", target_name="python-default", relative_file_path="default.lock"
101+
)
102+
assert_pipenv_requirements(
103+
rule_runner,
104+
"pipenv_requirements(name='reqs', module_mapping={'ansicolors': ['colors']})",
105+
{
106+
"default": {"ansicolors": {"version": ">=1.18.0"}},
107+
"develop": {
108+
"cachetools": {
109+
"markers": "python_version ~= '3.5'",
110+
"version": "==4.1.1",
111+
"extras": ["ring", "mongo"],
112+
}
113+
},
114+
},
115+
expected_targets={
116+
PythonRequirementTarget(
117+
{
118+
"requirements": ["ansicolors>=1.18.0"],
119+
"modules": ["colors"],
120+
"dependencies": [file_addr.spec, lock_addr.spec],
121+
},
122+
Address("", target_name="reqs", generated_name="ansicolors"),
123+
),
124+
PythonRequirementTarget(
125+
{
126+
"requirements": ["cachetools[ring, mongo]==4.1.1;python_version ~= '3.5'"],
127+
"dependencies": [file_addr.spec, lock_addr.spec],
128+
},
129+
Address("", target_name="reqs", generated_name="cachetools"),
130+
),
131+
TargetGeneratorSourcesHelperTarget({"source": file_addr.filename}, file_addr),
132+
},
133+
)

src/python/pants/backend/python/macros/poetry_requirements.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
TypeStubsModuleMappingField,
2222
)
2323
from pants.backend.python.pip_requirement import PipRequirement
24+
from pants.backend.python.subsystems.setup import PythonSetup
2425
from pants.backend.python.target_types import (
2526
PythonRequirementModulesField,
2627
PythonRequirementResolveField,
@@ -457,6 +458,7 @@ async def generate_from_python_requirement(
457458
request: GenerateFromPoetryRequirementsRequest,
458459
build_root: BuildRoot,
459460
union_membership: UnionMembership,
461+
python_setup: PythonSetup,
460462
) -> GeneratedTargets:
461463
generator = request.generator
462464
pyproject_rel_path = generator[PoetryRequirementsSourceField].value
@@ -476,6 +478,15 @@ async def generate_from_python_requirement(
476478
union_membership,
477479
)
478480

481+
req_deps = [file_tgt.address.spec]
482+
483+
resolve = request.template.get(
484+
PythonRequirementResolveField.alias, python_setup.default_resolve
485+
)
486+
lockfile = python_setup.resolves.get(resolve) if python_setup.enable_resolves else None
487+
if lockfile:
488+
req_deps.append(f"{lockfile}:{resolve}")
489+
479490
digest_contents = await Get(
480491
DigestContents,
481492
PathGlobs(
@@ -500,9 +511,7 @@ def generate_tgt(parsed_req: PipRequirement) -> PythonRequirementTarget:
500511
normalized_proj_name = canonicalize_project_name(parsed_req.project_name)
501512
tgt_overrides = overrides.pop(normalized_proj_name, {})
502513
if Dependencies.alias in tgt_overrides:
503-
tgt_overrides[Dependencies.alias] = list(tgt_overrides[Dependencies.alias]) + [
504-
file_tgt.address.spec
505-
]
514+
tgt_overrides[Dependencies.alias] = list(tgt_overrides[Dependencies.alias]) + req_deps
506515

507516
return PythonRequirementTarget(
508517
{
@@ -514,7 +523,7 @@ def generate_tgt(parsed_req: PipRequirement) -> PythonRequirementTarget:
514523
),
515524
# This may get overridden by `tgt_overrides`, which will have already added in
516525
# the file tgt.
517-
Dependencies.alias: [file_tgt.address.spec],
526+
Dependencies.alias: req_deps,
518527
**tgt_overrides,
519528
},
520529
request.template_address.create_generated(parsed_req.project_name),

src/python/pants/backend/python/macros/poetry_requirements_test.py

+29
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,35 @@ def test_source_override(rule_runner: RuleRunner) -> None:
555555
)
556556

557557

558+
def test_lockfile_dependency(rule_runner: RuleRunner) -> None:
559+
rule_runner.set_options(["--python-enable-resolves"])
560+
file_addr = Address("", target_name="reqs", relative_file_path="pyproject.toml")
561+
lock_addr = Address(
562+
"3rdparty/python", target_name="python-default", relative_file_path="default.lock"
563+
)
564+
assert_poetry_requirements(
565+
rule_runner,
566+
"poetry_requirements(name='reqs')",
567+
dedent(
568+
"""\
569+
[tool.poetry.dependencies]
570+
ansicolors = ">=1.18.0"
571+
[tool.poetry.dev-dependencies]
572+
"""
573+
),
574+
expected_targets={
575+
PythonRequirementTarget(
576+
{
577+
"dependencies": [file_addr.spec, lock_addr.spec],
578+
"requirements": ["ansicolors>=1.18.0"],
579+
},
580+
address=Address("", target_name="reqs", generated_name="ansicolors"),
581+
),
582+
TargetGeneratorSourcesHelperTarget({"source": file_addr.filename}, file_addr),
583+
},
584+
)
585+
586+
558587
def test_non_pep440_error(rule_runner: RuleRunner) -> None:
559588
with engine_error(contains='Failed to parse requirement foo = "~r62b" in pyproject.toml'):
560589
assert_poetry_requirements(

src/python/pants/backend/python/macros/python_requirements_test.py

+23
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,26 @@ def test_source_override(rule_runner: RuleRunner) -> None:
191191
TargetGeneratorSourcesHelperTarget({"source": "subdir/requirements.txt"}, file_addr),
192192
},
193193
)
194+
195+
196+
def test_lockfile_dependency(rule_runner: RuleRunner) -> None:
197+
rule_runner.set_options(["--python-enable-resolves"])
198+
reqs_addr = Address("", target_name="reqs", relative_file_path="requirements.txt")
199+
lock_addr = Address(
200+
"3rdparty/python", target_name="python-default", relative_file_path="default.lock"
201+
)
202+
assert_python_requirements(
203+
rule_runner,
204+
"python_requirements(name='reqs')",
205+
"ansicolors>=1.18.0",
206+
expected_targets={
207+
PythonRequirementTarget(
208+
{
209+
"requirements": ["ansicolors>=1.18.0"],
210+
"dependencies": [reqs_addr.spec, lock_addr.spec],
211+
},
212+
Address("", target_name="reqs", generated_name="ansicolors"),
213+
),
214+
TargetGeneratorSourcesHelperTarget({"source": reqs_addr.filename}, reqs_addr),
215+
},
216+
)

0 commit comments

Comments
 (0)