Hi, I am trying to build packages for 3rd-party re...
# plugins
p
Hi, I am trying to build packages for 3rd-party repos that use setup.py. But, they have build-time dependencies. I could package them using manually created
pyproject.toml
like:
Copy code
[build-system]
requires = ["setuptools", "wheel", "torch==2.5.1+cu121"]
build-backend = "setuptools.build_meta"
defining them as
resource
and adding as a dependency to
python_distribution
. Now, I would like to generate this
pyproject.toml
using a custom target that takes the build-time dependencies as an argument, and use this generated resource as dependency to
python_distribution
. For example, using a
BUILD
like this:
Copy code
pyproject_build_config(
    name = "pyproject",
    build_requirements = [
        "setuptools",
        "wheel",
        "torch==2.5.1+cu121",
    ],
)

python_distribution(
    name = "pytorch3d",
    dependencies = [
        ":pytorch3d-source",
        ":pyproject",
    ],
    generate_setup = False,
    provides = python_artifact(),
    sdist = False,
)
However, I am unsure how to get the plugin correctly. This is what I have so far, but this doesn't seem work (although there's no error either):
Copy code
# register.py
from pants.core.target_types import ResourceSourceField, ResourceTarget
from pants.engine.fs import CreateDigest, Digest, FileContent
from pants.engine.rules import Get, rule
from pants.engine.target import (
    COMMON_TARGET_FIELDS,
    GeneratedSources,
    GenerateSourcesRequest,
    StringSequenceField,
)


class PyprojectBuildConfigRequirements(StringSequenceField):
    alias = "build_requirements"
    help = "List of requirements to build the package"


class PyprojectBuildConfigTarget(ResourceTarget):
    alias = "pyproject_build_config"
    core_fields = (*COMMON_TARGET_FIELDS, PyprojectBuildConfigRequirements)
    help = "Generate PEP-517/518 compliant pyproject.toml for setup.py-based builds"


class GeneratePyprojectBuildConfigRequest(GenerateSourcesRequest):
    input = PyprojectBuildConfigTarget  # This is the resource target type that we handle.


@rule
async def generate_pyproject_build_config(target: PyprojectBuildConfigRequirements) -> GeneratedSources:
    # Dynamically create content for the resource.
    build_requirements = target[PyprojectBuildConfigRequirements].value
    dependencies_list = ",".join((f'"{b}"' for b in build_requirements))
    content = f"""
[build-system]
requires = [{dependencies_list}]
build-backend = "setuptools.build_meta"
"""
    file_name = "pyproject.toml"

    # Create the file as a digest.
    digest = await Get(Digest, CreateDigest([FileContent(file_name, content.encode())]))

    # Return the generated sources.
    return GeneratedSources(digest)


def target_types():
    return [PyprojectBuildConfigTarget]


def rules():
    return [generate_pyproject_build_config]
What should I do?
b
Sorry for the trouble! A few extra questions: 1. When you say "doesn't work" can you be any more specific? For instance: what goal(s) are you running? What are you expecting to see? What are you seeing instead? 2. Can you share your
pants.toml
too?
p
I am running
pants package :pytorch3d
, but the build fails because it can't find
torch
during import, which is imported by
setup.py
in
:pytorch3d-source
. If I manually create
pyproject.toml
and add it as a
resource
, then
torch
is available for import and the package builds.
pants.toml
Copy code
[GLOBAL]
pants_version = "2.23.0"
backend_packages = [
    "pants.backend.build_files.fmt.buildifier",
    "pants.backend.python",
    "pants.backend.python.lint.isort",
    "pants.backend.python.lint.black",
    "pants.backend.python.lint.pylint",
    "pants.backend.python.typecheck.mypy",
    "pants.backend.docker",
    "pants.backend.experimental.adhoc",
    "pants.backend.experimental.debian",
    "pants.backend.shell",
    "pants.backend.shell.lint.shellcheck",
    "pants.backend.shell.lint.shfmt"
]
# plugins = ["hdrhistogram"]
process_execution_local_parallelism = 8
process_execution_local_enable_nailgun = false
cache_content_behavior = "defer"
print_stacktrace = true
build_file_prelude_globs = ["tools/macros.py"]

[environments-preview.names]
default = "//:local"

[subprocess-environment]
env_vars.add = [
    "DOCKER_HOST",
    "DOCKER_DRIVER",
    "DOCKER_TLS_CERTDIR",
    "DOCKER_TLS_VERIFY",
    "TESTCONTAINERS_RYUK_DISABLED",
    "EGL_PLATFORM"
]

[source]
root_patterns = ["/"]

[python]
interpreter_constraints = ["CPython>=3.11,<3.12"]
enable_resolves = true
default_resolve = "root"

[python.resolves]
root = "dependencies/root.lock"
Here are the
BUILD
and
pyproject.toml
that works:
BUILD
pyproject.toml
All I want is to generate the
pyproject.toml
file automatically given a list of build-time dependencies (e.g.,
["setuptools", "wheel", "torch==2.5.1+cu121"]
). So, I thought I could use a custom target like:
Copy code
pyproject_build_config(
    name = "pyproject",
    build_requirements = [
        "setuptools",
        "wheel",
        "torch==2.5.1+cu121",
    ],
)
and make that available as a
resource
to the
python_distribution
target in place of the manual
pyproject.toml
resource
.
For now, I am doing this:
Copy code
shell_command(
    name = "pyproject",
    command = "echo -e '[build-system]\nrequires = [{}]\nbuild-backend = \"setuptools.build_meta\"' > pyproject.toml".format(",".join(f'"{v}"' for v in ["setuptools", "wheel", "torch==2.5.1+cu121"])),
    output_files = ["pyproject.toml"],
    tools = ["echo"],
    workdir = "./",
)
which gets ugly when I try to templatize
"torch==2.5.1+cu121"
. I guess I could write a macro to wrap the shell_command...
b
Sorry, I'm pretty unfamiliar with this part of Pants, so I don't know what's best. A macro/function/loop to templatise what you need might indeed be good enough?