diff --git a/src/python/pants/backend/python/goals/tailor.py b/src/python/pants/backend/python/goals/tailor.py index 631be695203..9fa5ebe0633 100644 --- a/src/python/pants/backend/python/goals/tailor.py +++ b/src/python/pants/backend/python/goals/tailor.py @@ -121,22 +121,41 @@ async def find_putative_targets( if python_setup.tailor_requirements_targets: # Find requirements files. - all_requirements_files = await Get( - Paths, PathGlobs, req.search_paths.path_globs("*requirements*.txt") + ( + all_requirements_files, + all_pipenv_lockfile_files, + all_pyproject_toml_contents, + ) = await MultiGet( + Get(Paths, PathGlobs, req.search_paths.path_globs("*requirements*.txt")), + Get(Paths, PathGlobs, req.search_paths.path_globs("Pipfile.lock")), + Get(DigestContents, PathGlobs, req.search_paths.path_globs("pyproject.toml")), ) - unowned_requirements_files = set(all_requirements_files.files) - set(all_owned_sources) - for req_file in unowned_requirements_files: - path, name = os.path.split(req_file) - pts.append( - PutativeTarget( - path=path, - name=name, - type_alias="python_requirements", - triggering_sources=[req_file], - owned_sources=[name], - kwargs={} if name == "requirements.txt" else {"source": name}, + + def add_req_targets(files: Iterable[str], alias: str) -> None: + unowned_files = set(files) - set(all_owned_sources) + for fp in unowned_files: + path, name = os.path.split(fp) + pts.append( + PutativeTarget( + path=path, + name=name, + type_alias=alias, + triggering_sources=[fp], + owned_sources=[name], + kwargs=( + {} + if alias != "python_requirements" or name == "requirements.txt" + else {"source": name} + ), + ) ) - ) + + add_req_targets(all_requirements_files.files, "python_requirements") + add_req_targets(all_pipenv_lockfile_files.files, "pipenv_requirements") + add_req_targets( + {fc.path for fc in all_pyproject_toml_contents if b"[tool.poetry" in fc.content}, + "poetry_requirements", + ) if python_setup.tailor_pex_binary_targets: # Find binary targets. diff --git a/src/python/pants/backend/python/goals/tailor_test.py b/src/python/pants/backend/python/goals/tailor_test.py index 2e7d5470d74..9a8204f4aab 100644 --- a/src/python/pants/backend/python/goals/tailor_test.py +++ b/src/python/pants/backend/python/goals/tailor_test.py @@ -11,6 +11,8 @@ classify_source_files, is_entry_point, ) +from pants.backend.python.macros.pipenv_requirements import PipenvRequirementsTargetGenerator +from pants.backend.python.macros.poetry_requirements import PoetryRequirementsTargetGenerator from pants.backend.python.macros.python_requirements import PythonRequirementsTargetGenerator from pants.backend.python.target_types import ( PexBinary, @@ -68,8 +70,13 @@ def test_find_putative_targets(rule_runner: RuleRunner) -> None: rule_runner.set_options(["--no-python-tailor-ignore-solitary-init-files"]) rule_runner.write_files( { + "3rdparty/Pipfile.lock": "", + "3rdparty/pyproject.toml": "[tool.poetry]", "3rdparty/requirements-test.txt": "", "already_owned/requirements.txt": "", + "already_owned/Pipfile.lock": "", + "already_owned/pyproject.toml": "[tool.poetry]", + "no_match/pyproject.toml": "# no poetry section", **{ f"src/python/foo/{fp}": "" for fp in ( @@ -92,6 +99,8 @@ def test_find_putative_targets(rule_runner: RuleRunner) -> None: AllOwnedSources( [ "already_owned/requirements.txt", + "already_owned/Pipfile.lock", + "already_owned/pyproject.toml", "src/python/foo/bar/__init__.py", "src/python/foo/bar/baz1.py", ] @@ -101,6 +110,18 @@ def test_find_putative_targets(rule_runner: RuleRunner) -> None: assert ( PutativeTargets( [ + PutativeTarget.for_target_type( + PipenvRequirementsTargetGenerator, + path="3rdparty", + name="Pipfile.lock", + triggering_sources=["3rdparty/Pipfile.lock"], + ), + PutativeTarget.for_target_type( + PoetryRequirementsTargetGenerator, + path="3rdparty", + name="pyproject.toml", + triggering_sources=["3rdparty/pyproject.toml"], + ), PutativeTarget.for_target_type( PythonRequirementsTargetGenerator, path="3rdparty", diff --git a/src/python/pants/backend/python/subsystems/setup.py b/src/python/pants/backend/python/subsystems/setup.py index 43e3ddf9033..a83831d01c0 100644 --- a/src/python/pants/backend/python/subsystems/setup.py +++ b/src/python/pants/backend/python/subsystems/setup.py @@ -432,11 +432,15 @@ class PythonSetup(Subsystem): default=True, help=softwrap( """ - If true, add `python_requirements` target generators with the `tailor` goal for - requirements files. + If true, add `python_requirements`, `poetry_requirements`, and `pipenv_requirements` + target generators with the `tailor` goal. - This matches any file with the pattern `*requirements*.txt`. You will need to manually - add `python_requirements` for different file names like `reqs.txt`. + `python_requirements` targets are added for any file that matches the pattern + `*requirements*.txt`. You will need to manually add `python_requirements` for different + file names like `reqs.txt`. + + `poetry_requirements` targets are added for `pyproject.toml` files with `[tool.poetry` + in them. """ ), advanced=True,