예제 #1
0
 def register_options(cls, register):
     super().register_options(register)
     register(
         "--imports",
         default=True,
         type=bool,
         help=("Infer a target's dependencies by parsing import statements from sources."),
     )
     register(
         "--consumed-types",
         default=True,
         type=bool,
         help=("Infer a target's dependencies by parsing consumed types from sources."),
     )
     register(
         "--third-party-imports",
         default=True,
         type=bool,
         help="Infer a target's third-party dependencies using Java import statements.",
     )
     _default_package_mapping_url = git_url(
         "src/python/pants/backend/java/dependency_inference/jvm_artifact_mappings.py"
     )
     # TODO: Move to `coursier` or a generic `jvm` subsystem.
     register(
         "--third-party-import-mapping",
         type=dict,
         help=(
             "A dictionary mapping a Java package path to a JVM artifact coordinate (GROUP:ARTIFACT) "
             "without the version. The package path may be made recursive to match symbols in subpackages "
             "by adding `.**` to the end of the package path. For example, specify `{'org.junit.**': 'junit:junit'} `"
             "to infer a dependency on junit:junit for any file importing a symbol from org.junit or its "
             f"subpackages. Pants also supplies a default package mapping ({_default_package_mapping_url})."
         ),
     )
예제 #2
0
class AvroSubsystem(JvmToolBase):
    options_scope = "java-avro"
    help = "Avro IDL compiler (https://avro.apache.org/)."

    default_version = "1.11.0"
    default_artifacts = ("org.apache.avro:avro-tools:{version}", )
    default_lockfile_resource = (
        "pants.backend.codegen.avro.java",
        "avro-tools.default.lockfile.txt",
    )
    default_lockfile_path = (
        "src/python/pants/backend/codegen/avro/java/avro-tools.default.lockfile.txt"
    )
    default_lockfile_url = git_url(default_lockfile_path)

    runtime_dependencies = TargetListOption(
        "--runtime-dependencies",
        help=lambda cls: softwrap(f"""
            A list of addresses to `jvm_artifact` targets for the runtime dependencies needed for
            generated Java code to work. For example, `['3rdparty/jvm:avro-runtime']`.
            These dependencies will be automatically added to every `avro_sources` target.
            At the very least, this option must be set to a `jvm_artifact` for the
            `org.apache.avro:avro:{cls.default_version}` runtime library.
            """),
    )
예제 #3
0
class ScalaPBSubsystem(JvmToolBase):
    options_scope = "scalapb"
    help = "The ScalaPB protocol buffer compiler (https://scalapb.github.io/)."

    default_version = "0.11.6"
    default_artifacts = ("com.thesamet.scalapb:scalapbc_2.13:{version}",)
    default_lockfile_resource = (
        "pants.backend.codegen.protobuf.scala",
        "scalapbc.default.lockfile.txt",
    )
    default_lockfile_path = (
        "src/python/pants/backend/codegen/protobuf/scala/scalapbc.default.lockfile.txt"
    )
    default_lockfile_url = git_url(default_lockfile_path)

    _jvm_plugins = StrListOption(
        "--jvm-plugins",
        help=softwrap(
            """
            A list of JVM-based `protoc` plugins to invoke when generating Scala code from protobuf files.
            The format for each plugin specifier is `NAME=ARTIFACT` where NAME is the name of the
            plugin and ARTIFACT is either the address of a `jvm_artifact` target or the colon-separated
            Maven coordinate for the plugin's jar artifact.

            For example, to invoke the fs2-grpc protoc plugin, the following option would work:
            `--scalapb-jvm-plugins=fs2=org.typelevel:fs2-grpc-codegen_2.12:2.3.1`.
            (Note: you would also need to set --scalapb-runtime-dependencies appropriately
            to include the applicable runtime libraries for your chosen protoc plugins.)
            """
        ),
    )

    @property
    def jvm_plugins(self) -> tuple[PluginArtifactSpec, ...]:
        return tuple(PluginArtifactSpec.from_str(pa_str) for pa_str in self._jvm_plugins)
예제 #4
0
class IPython(PythonToolBase):
    options_scope = "ipython"
    help = "The IPython enhanced REPL (https://ipython.org/)."

    default_version = "ipython==7.16.1"  # The last version to support Python 3.6.
    default_main = ConsoleScript("ipython")

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.subsystems",
                                 "ipython.lock")
    default_lockfile_path = "src/python/pants/backend/python/subsystems/ipython.lock"
    default_lockfile_url = git_url(default_lockfile_path)

    ignore_cwd = BoolOption(
        "--ignore-cwd",
        advanced=True,
        default=True,
        help=softwrap("""
            Whether to tell IPython not to put the CWD on the import path.

            Normally you want this to be True, so that imports come from the hermetic
            environment Pants creates.

            However IPython<7.13.0 doesn't support this option, so if you're using an earlier
            version (e.g., because you have Python 2.7 code) then you will need to set this to False,
            and you may have issues with imports from your CWD shading the hermetic environment.
            """),
    )
예제 #5
0
class Black(PythonToolBase):
    options_scope = "black"
    name = "Black"
    help = "The Black Python code formatter (https://black.readthedocs.io/)."

    default_version = "black==22.1.0"
    default_main = ConsoleScript("black")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.black", "black.lock")
    default_lockfile_path = "src/python/pants/backend/python/lint/black/black.lock"
    default_lockfile_url = git_url(default_lockfile_path)
    default_extra_requirements = ['typing-extensions>=3.10.0.0; python_version < "3.10"']

    skip = SkipOption("fmt", "lint")
    args = ArgsListOption(example="--target-version=py37 --quiet")
    export = ExportToolOption()
    config = FileOption(
        "--config",
        default=None,
        advanced=True,
        help=lambda cls: softwrap(
            f"""
            Path to a TOML config file understood by Black
            (https://github.com/psf/black#configuration-format).

            Setting this option will disable `[{cls.options_scope}].config_discovery`. Use
            this option if the config is located in a non-standard location.
            """
        ),
    )
    config_discovery = BoolOption(
        "--config-discovery",
        default=True,
        advanced=True,
        help=lambda cls: softwrap(
            f"""
            If true, Pants will include any relevant pyproject.toml config files during runs.

            Use `[{cls.options_scope}].config` instead if your config is in a
            non-standard location.
            """
        ),
    )

    def config_request(self, dirs: Iterable[str]) -> ConfigFilesRequest:
        # Refer to https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#where-black-looks-for-the-file
        # for how Black discovers config.
        candidates = {os.path.join(d, "pyproject.toml"): b"[tool.black]" for d in ("", *dirs)}
        return ConfigFilesRequest(
            specified=self.config,
            specified_option_name=f"[{self.options_scope}].config",
            discovery=self.config_discovery,
            check_content=candidates,
        )
예제 #6
0
def test_git_url(monkeypatch) -> None:
    monkeypatch.setattr(docutil, "PANTS_SEMVER", Version("1.29.0.dev0"))
    assert (
        git_url("some_file.ext") ==
        "https://github.com/pantsbuild/pants/blob/release_1.29.0.dev0/some_file.ext"
    )

    monkeypatch.setattr(docutil, "PANTS_SEMVER", Version("1.29.0rc0"))
    assert (
        git_url("some_file.ext") ==
        "https://github.com/pantsbuild/pants/blob/release_1.29.0rc0/some_file.ext"
    )

    monkeypatch.setattr(docutil, "PANTS_SEMVER", Version("1.29.0"))
    assert (
        git_url("some_file.ext") ==
        "https://github.com/pantsbuild/pants/blob/release_1.29.0/some_file.ext"
    )
예제 #7
0
class Setuptools(PythonToolRequirementsBase):
    options_scope = "setuptools"
    help = "Python setuptools, used to package `python_distribution` targets."

    default_version = "setuptools>=50.3.0,<58.0"
    default_extra_requirements = ["wheel>=0.35.1,<0.38"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.subsystems", "setuptools.lock")
    default_lockfile_path = "src/python/pants/backend/python/subsystems/setuptools.lock"
    default_lockfile_url = git_url(default_lockfile_path)
예제 #8
0
class JaxWsTools(JvmToolBase):
    options_scope = "jaxws"
    help = "The JAX-WS Import tool (https://javaee.github.io/metro-jax-ws/)"

    default_version = "2.3.5"
    default_artifacts = ("com.sun.xml.ws:jaxws-tools:{version}", )
    default_lockfile_resource = (
        "pants.backend.codegen.soap.java",
        "jaxws.default.lockfile.txt",
    )
    default_lockfile_path = "pants/backend/codegen/soap/java/jaxws.default.lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)
예제 #9
0
class DockerfileParser(PythonToolRequirementsBase):
    options_scope = "dockerfile-parser"
    help = "Used to parse Dockerfile build specs to infer their dependencies."

    default_version = "dockerfile==3.2.0"

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = (_DOCKERFILE_PACKAGE, "dockerfile.lock")
    default_lockfile_path = f"src/python/{_DOCKERFILE_PACKAGE.replace('.', '/')}/dockerfile.lock"
    default_lockfile_url = git_url(default_lockfile_path)
예제 #10
0
class TerraformHcl2Parser(PythonToolRequirementsBase):
    options_scope = "terraform-hcl2-parser"
    help = "Used to parse Terraform modules to infer their dependencies."

    default_version = "python-hcl2==3.0.5"

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.terraform", "hcl2.lock")
    default_lockfile_path = "src/python/pants/backend/terraform/hcl2.lock"
    default_lockfile_url = git_url(default_lockfile_path)
예제 #11
0
class ScroogeSubsystem(JvmToolBase):
    options_scope = "scrooge"
    help = "The Scrooge Thrift IDL compiler (https://twitter.github.io/scrooge/)."

    default_version = "21.12.0"
    default_artifacts = ("com.twitter:scrooge-generator_2.13:{version}", )
    default_lockfile_resource = (
        "pants.backend.codegen.thrift.scrooge",
        "scrooge.default.lockfile.txt",
    )
    default_lockfile_path = (
        "src/python/pants/backend/codegen/thrift/scrooge/scrooge.default.lockfile.txt"
    )
    default_lockfile_url = git_url(default_lockfile_path)
예제 #12
0
class PythonProtobufMypyPlugin(PythonToolRequirementsBase):
    options_scope = "mypy-protobuf"
    help = "Configuration of the mypy-protobuf type stub generation plugin."

    default_version = "mypy-protobuf==2.10"

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.codegen.protobuf.python",
                                 "mypy_protobuf.lock")
    default_lockfile_path = "src/python/pants/backend/codegen/protobuf/python/mypy_protobuf.lock"
    default_lockfile_url = git_url(default_lockfile_path)
예제 #13
0
class Lambdex(PythonToolBase):
    options_scope = "lambdex"
    help = "A tool for turning .pex files into Function-as-a-Service artifacts (https://github.com/pantsbuild/lambdex)."

    default_version = "lambdex==0.1.6"
    default_main = ConsoleScript("lambdex")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<3.10"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.subsystems",
                                 "lambdex.lock")
    default_lockfile_path = "src/python/pants/backend/python/subsystems/lambdex.lock"
    default_lockfile_url = git_url(default_lockfile_path)
예제 #14
0
파일: junit.py 프로젝트: codealchemy/pants
class JUnit(JvmToolBase):
    options_scope = "junit"
    name = "JUnit"
    help = "The JUnit test framework (https://junit.org)"

    default_version = "5.7.2"
    default_artifacts = (
        "org.junit.platform:junit-platform-console:1.7.2",
        "org.junit.jupiter:junit-jupiter-engine:{version}",
        "org.junit.vintage:junit-vintage-engine:{version}",
    )
    default_lockfile_resource = ("pants.jvm.test", "junit.default.lockfile.txt")
    default_lockfile_path = "src/python/pants/jvm/test/junit.default.lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)

    args = ArgsListOption(example="--disable-ansi-colors", passthrough=True)
예제 #15
0
class PyUpgrade(PythonToolBase):
    options_scope = "pyupgrade"
    help = (
        "Upgrade syntax for newer versions of the language (https://github.com/asottile/pyupgrade)."
    )

    default_version = "pyupgrade>=2.29.0,<2.30"
    default_main = ConsoleScript("pyupgrade")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.pyupgrade",
                                 "lockfile.txt")
    default_lockfile_path = "src/python/pants/backend/python/lint/pyupgrade/lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)

    @classmethod
    def register_options(cls, register):
        super().register_options(register)
        register(
            "--skip",
            type=bool,
            default=False,
            help=
            (f"Don't use pyupgrade when running `{register.bootstrap.pants_bin_name} fmt` and "
             f"`{register.bootstrap.pants_bin_name} lint`."),
        )
        register(
            "--args",
            type=list,
            default=[],
            member_type=shell_str,
            help=
            (f"Arguments to pass directly to pyupgrade, e.g. "
             f'`--{cls.options_scope}-args="--py39-plus --keep-runtime-typing"`'
             ),
        )

    @property
    def skip(self) -> bool:
        return cast(bool, self.options.skip)

    @property
    def args(self) -> tuple[str, ...]:
        return tuple(self.options.args)
예제 #16
0
class ScalafmtSubsystem(JvmToolBase):
    options_scope = "scalafmt"
    name = "scalafmt"
    help = "scalafmt (https://scalameta.org/scalafmt/)"

    default_version = "3.2.1"
    default_artifacts = ("org.scalameta:scalafmt-cli_2.13:{version}",)
    default_lockfile_resource = (
        "pants.backend.scala.lint.scalafmt",
        "scalafmt.default.lockfile.txt",
    )
    default_lockfile_path = (
        "src/python/pants/backend/scala/lint/scalafmt/scalafmt.default.lockfile.txt"
    )
    default_lockfile_url = git_url(default_lockfile_path)

    skip = SkipOption("fmt", "lint")
예제 #17
0
class SetuptoolsSCM(PythonToolBase):
    options_scope = "setuptools-scm"
    help = (
        "A tool for generating versions from VCS metadata (https://github.com/pypa/setuptools_scm)."
    )

    default_version = "setuptools-scm==6.4.2"
    default_main = EntryPoint("setuptools_scm")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.subsystems",
                                 "setuptools_scm.lock")
    default_lockfile_path = "src/python/pants/backend/python/subsystems/setuptools_scm.lock"
    default_lockfile_url = git_url(default_lockfile_path)
예제 #18
0
class Scalatest(JvmToolBase):
    options_scope = "scalatest"
    name = "Scalatest"
    help = "The Scalatest test framework (https://www.scalatest.org/)"

    default_version = "3.2.10"
    default_artifacts = ("org.scalatest:scalatest_2.13:{version}",)
    default_lockfile_resource = ("pants.backend.scala.subsystems", "scalatest.default.lockfile.txt")
    default_lockfile_path = (
        "src/python/pants/backend/scala/subsystems/scalatest.default.lockfile.txt"
    )
    default_lockfile_url = git_url(default_lockfile_path)

    args = ArgsListOption(
        example="-t $testname",
        passthrough=True,
        extra_help="See https://www.scalatest.org/user_guide/using_the_runner for supported arguments.",
    )
예제 #19
0
class Autoflake(PythonToolBase):
    options_scope = "autoflake"
    name = "Autoflake"
    help = "The Autoflake Python code formatter (https://github.com/myint/autoflake)."

    default_version = "autoflake==1.4"
    default_main = ConsoleScript("autoflake")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.autoflake", "autoflake.lock")
    default_lockfile_path = "src/python/pants/backend/python/lint/autoflake/autoflake.lock"
    default_lockfile_url = git_url(default_lockfile_path)

    skip = SkipOption("fmt", "lint")
    args = ArgsListOption(example="--target-version=py37 --quiet")
예제 #20
0
class Docformatter(PythonToolBase):
    options_scope = "docformatter"
    help = "The Python docformatter tool (https://github.com/myint/docformatter)."

    default_version = "docformatter>=1.4,<1.5"
    default_main = ConsoleScript("docformatter")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.6"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.docformatter",
                                 "lockfile.txt")
    default_lockfile_path = "src/python/pants/backend/python/lint/docformatter/lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)

    @classmethod
    def register_options(cls, register):
        super().register_options(register)
        register(
            "--skip",
            type=bool,
            default=False,
            help=
            (f"Don't use docformatter when running `{register.bootstrap.pants_bin_name} fmt` "
             f"and `{register.bootstrap.pants_bin_name} lint`."),
        )
        register(
            "--args",
            type=list,
            member_type=shell_str,
            help=
            ("Arguments to pass directly to docformatter, e.g. "
             f'`--{cls.options_scope}-args="--wrap-summaries=100 --pre-summary-newline"`.'
             ),
        )

    @property
    def skip(self) -> bool:
        return cast(bool, self.options.skip)

    @property
    def args(self) -> Tuple[str, ...]:
        return tuple(self.options.args)
예제 #21
0
class Autoflake(PythonToolBase):
    options_scope = "autoflake"
    help = "The Autoflake Python code formatter (https://github.com/myint/autoflake)."

    default_version = "autoflake==1.4"
    default_main = ConsoleScript("autoflake")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.autoflake",
                                 "lockfile.txt")
    default_lockfile_path = "src/python/pants/backend/python/lint/autoflake/lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)

    @classmethod
    def register_options(cls, register):
        super().register_options(register)
        register(
            "--skip",
            type=bool,
            default=False,
            help=
            (f"Don't use Autoflake when running `{register.bootstrap.pants_bin_name} fmt` and "
             f"`{register.bootstrap.pants_bin_name} lint`"),
        )
        register(
            "--args",
            type=list,
            member_type=shell_str,
            help=(
                "Arguments to pass directly to Autoflake, e.g. "
                f'`--{cls.options_scope}-args="--target-version=py37 --quiet"`'
            ),
        )

    @property
    def skip(self) -> bool:
        return cast(bool, self.options.skip)

    @property
    def args(self) -> tuple[str, ...]:
        return tuple(self.options.args)
예제 #22
0
class Docformatter(PythonToolBase):
    options_scope = "docformatter"
    name = "docformatter"
    help = "The Python docformatter tool (https://github.com/myint/docformatter)."

    default_version = "docformatter>=1.4,<1.5"
    default_main = ConsoleScript("docformatter")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.docformatter",
                                 "docformatter.lock")
    default_lockfile_path = "src/python/pants/backend/python/lint/docformatter/docformatter.lock"
    default_lockfile_url = git_url(default_lockfile_path)

    skip = SkipOption("fmt", "lint")
    args = ArgsListOption(example="--wrap-summaries=100 --pre-summary-newline")
예제 #23
0
class Bandit(PythonToolBase):
    options_scope = "bandit"
    name = "Bandit"
    help = "A tool for finding security issues in Python code (https://bandit.readthedocs.io)."

    # When upgrading, check if Bandit has started using PEP 517 (a `pyproject.toml` file). If so,
    # remove `setuptools` from `default_extra_requirements`.
    default_version = "bandit>=1.7.0,<1.8"
    default_extra_requirements = [
        "setuptools",
        # GitPython 3.1.20 was yanked because it breaks Python 3.8+, but Poetry's lockfile
        # generation still tries to use it. Upgrade this to the newest version once released or
        # when switching away from Poetry.
        "GitPython==3.1.18",
    ]
    default_main = ConsoleScript("bandit")

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.bandit", "bandit.lock")
    default_lockfile_path = "src/python/pants/backend/python/lint/bandit/bandit.lock"
    default_lockfile_url = git_url(default_lockfile_path)

    skip = SkipOption("lint")
    args = ArgsListOption(example="--skip B101,B308 --confidence")
    config = FileOption(
        "--config",
        default=None,
        advanced=True,
        help=(
            "Path to a Bandit YAML config file "
            "(https://bandit.readthedocs.io/en/latest/config.html)."
        ),
    )

    @property
    def config_request(self) -> ConfigFilesRequest:
        # Refer to https://bandit.readthedocs.io/en/latest/config.html. Note that there are no
        # default locations for Bandit config files.
        return ConfigFilesRequest(
            specified=self.config, specified_option_name=f"{self.options_scope}.config"
        )
예제 #24
0
class PyUpgrade(PythonToolBase):
    options_scope = "pyupgrade"
    name = "pyupgrade"
    help = (
        "Upgrade syntax for newer versions of the language (https://github.com/asottile/pyupgrade)."
    )

    default_version = "pyupgrade>=2.31.0,<2.32"
    default_main = ConsoleScript("pyupgrade")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.pyupgrade",
                                 "pyupgrade.lock")
    default_lockfile_path = "src/python/pants/backend/python/lint/pyupgrade/pyupgrade.lock"
    default_lockfile_url = git_url(default_lockfile_path)

    skip = SkipOption("fmt", "lint")
    args = ArgsListOption(example="--py39-plus --keep-runtime-typing")
예제 #25
0
class ClangFormat(PythonToolBase):
    options_scope = "clang-format"
    name = "ClangFormat"
    help = softwrap(
        """
        The clang-format utility for formatting C/C++ (and others) code
        (https://clang.llvm.org/docs/ClangFormat.html). The clang-format binaries
        are retrieved from PyPi (https://pypi.org/project/clang-format/).
        """
    )

    default_version = "clang-format==14.0.3"
    default_main = ConsoleScript("clang-format")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    skip = SkipOption("fmt", "lint")
    args = ArgsListOption(example="--version")

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.cc.lint.clangformat", "clangformat.lock")
    default_lockfile_path = "src/python/pants/backend/cc/lint/clangformat/clangformat.lock"
    default_lockfile_url = git_url(default_lockfile_path)

    export = ExportToolOption()

    def config_request(self, dirs: Iterable[str]) -> ConfigFilesRequest:
        """clang-format will use the closest configuration file to the file currently being
        formatted, so add all of them."""
        config_files = (
            ".clang-format",
            "_clang-format",
        )
        check_existence = [os.path.join(d, file) for file in config_files for d in ("", *dirs)]
        return ConfigFilesRequest(
            discovery=True,
            check_existence=check_existence,
        )
예제 #26
0
class GoogleJavaFormatSubsystem(JvmToolBase):
    options_scope = "google-java-format"
    name = "Google Java Format"
    help = "Google Java Format (https://github.com/google/google-java-format)"

    default_version = "1.13.0"
    default_artifacts = ("com.google.googlejavaformat:google-java-format:{version}",)
    default_lockfile_resource = (
        "pants.backend.java.lint.google_java_format",
        "google_java_format.default.lockfile.txt",
    )
    default_lockfile_path = "src/python/pants/backend/java/lint/google_java_format/google_java_format.default.lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)

    skip = SkipOption("fmt", "lint")
    aosp = BoolOption(
        "--aosp",
        default=False,
        help=(
            "Use AOSP style instead of Google Style (4-space indentation). "
            '("AOSP" is the Android Open Source Project.)'
        ),
    )
예제 #27
0
class CoverageSubsystem(PythonToolBase):
    options_scope = "coverage-py"
    help = "Configuration for Python test coverage measurement."

    default_version = "coverage[toml]>=5.5,<5.6"
    default_main = ConsoleScript("coverage")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.6,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.subsystems",
                                 "coverage_py_lockfile.txt")
    default_lockfile_path = "src/python/pants/backend/python/subsystems/coverage_py_lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)

    @classmethod
    def register_options(cls, register):
        super().register_options(register)
        register(
            "--filter",
            type=list,
            member_type=str,
            default=None,
            help=
            ("A list of Python modules or filesystem paths to use in the coverage report, e.g. "
             "`['helloworld_test', 'helloworld/util/dirutil'].\n\nBoth modules and directory "
             "paths are recursive: any submodules or child paths, respectively, will be "
             "included.\n\nIf you leave this off, the coverage report will include every file "
             "in the transitive closure of the address/file arguments; for example, `test ::` "
             "will include every Python file in your project, whereas "
             "`test project/app_test.py` will include `app_test.py` and any of its transitive "
             "dependencies."),
        )
        register(
            "--report",
            type=list,
            member_type=CoverageReportType,
            default=[CoverageReportType.CONSOLE],
            help="Which coverage report type(s) to emit.",
        )
        register(
            "--output-dir",
            type=str,
            default=str(PurePath("dist", "coverage", "python")),
            advanced=True,
            help=
            "Path to write the Pytest Coverage report to. Must be relative to build root.",
        )
        register(
            "--config",
            type=file_option,
            default=None,
            advanced=True,
            help=
            ("Path to an INI or TOML config file understood by coverage.py "
             "(https://coverage.readthedocs.io/en/stable/config.html).\n\n"
             f"Setting this option will disable `[{cls.options_scope}].config_discovery`. Use "
             f"this option if the config is located in a non-standard location."
             ),
        )
        register(
            "--config-discovery",
            type=bool,
            default=True,
            advanced=True,
            help=
            ("If true, Pants will include any relevant config files during runs "
             "(`.coveragerc`, `setup.cfg`, `tox.ini`, and `pyproject.toml`)."
             f"\n\nUse `[{cls.options_scope}].config` instead if your config is in a "
             f"non-standard location."),
        )
        register(
            "--global-report",
            type=bool,
            default=False,
            help=
            ("If true, Pants will generate a global coverage report.\n\nThe global report will "
             "include all Python source files in the workspace and not just those depended on "
             "by the tests that were run."),
        )
        register(
            "--fail-under",
            type=float,
            default=None,
            help=
            ("Fail if the total combined coverage percentage for all tests is less than this "
             "number.\n\nUse this instead of setting fail_under in a coverage.py config file, "
             "as the config will apply to each test separately, while you typically want this "
             "to apply to the combined coverage for all tests run."
             "\n\nNote that you must generate at least one (non-raw) coverage report for this "
             "check to trigger.\n\nNote also that if you specify a non-integral value, you must "
             "also set [report] precision properly in the coverage.py config file to make use "
             "of the decimal places. See https://coverage.readthedocs.io/en/latest/config.html ."
             ),
        )

    @property
    def filter(self) -> tuple[str, ...]:
        return tuple(self.options.filter)

    @property
    def reports(self) -> tuple[CoverageReportType, ...]:
        return tuple(self.options.report)

    @property
    def output_dir(self) -> PurePath:
        return PurePath(self.options.output_dir)

    @property
    def config(self) -> str | None:
        return cast("str | None", self.options.config)

    @property
    def config_request(self) -> ConfigFilesRequest:
        # Refer to https://coverage.readthedocs.io/en/stable/config.html.
        return ConfigFilesRequest(
            specified=self.config,
            specified_option_name=f"[{self.options_scope}].config",
            discovery=cast(bool, self.options.config_discovery),
            check_existence=[".coveragerc"],
            check_content={
                "setup.cfg": b"[coverage:",
                "tox.ini": b"[coverage:]",
                "pyproject.toml": b"[tool.coverage",
            },
        )

    @property
    def global_report(self) -> bool:
        return cast(bool, self.options.global_report)

    @property
    def fail_under(self) -> int:
        return cast(int, self.options.fail_under)
예제 #28
0
class Yapf(PythonToolBase):
    options_scope = "yapf"
    help = "A formatter for Python files (https://github.com/google/yapf)."

    default_version = "yapf==0.31.0"
    default_extra_requirements = ["toml"]
    default_main = ConsoleScript("yapf")

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.6"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.lint.yapf",
                                 "lockfile.txt")
    default_lockfile_path = "src/python/pants/backend/python/lint/yapf/lockfile.txt"
    default_lockfile_url = git_url(default_lockfile_path)

    @classmethod
    def register_options(cls, register):
        super().register_options(register)
        register(
            "--skip",
            type=bool,
            default=False,
            help=
            (f"Don't use yapf when running `{register.bootstrap.pants_bin_name} fmt` and "
             f"`{register.bootstrap.pants_bin_name} lint`."),
        )
        register(
            "--args",
            type=list,
            member_type=shell_str,
            help=
            ("Arguments to pass directly to yapf, e.g. "
             f'`--{cls.options_scope}-args="--no-local-style"`.\n\n'
             "Certain arguments, specifically `--recursive`, `--in-place`, and "
             "`--parallel`, will be ignored because Pants takes care of finding "
             "all the relevant files and running the formatting in parallel."),
        )
        register(
            "--config",
            type=file_option,
            default=None,
            advanced=True,
            help=
            ("Path to style file understood by yapf "
             "(https://github.com/google/yapf#formatting-style/).\n\n"
             f"Setting this option will disable `[{cls.options_scope}].config_discovery`. Use "
             f"this option if the config is located in a non-standard location."
             ),
        )
        register(
            "--config-discovery",
            type=bool,
            default=True,
            advanced=True,
            help=
            ("If true, Pants will include any relevant config files during "
             "runs (`.style.yapf`, `pyproject.toml`, and `setup.cfg`)."
             f"\n\nUse `[{cls.options_scope}].config` instead if your config is in a "
             f"non-standard location."),
        )

    @property
    def skip(self) -> bool:
        return cast(bool, self.options.skip)

    @property
    def args(self) -> tuple[str, ...]:
        return tuple(self.options.args)

    @property
    def config(self) -> str | None:
        return cast("str | None", self.options.config)

    def config_request(self, dirs: Iterable[str]) -> ConfigFilesRequest:
        # Refer to https://github.com/google/yapf#formatting-style.
        check_existence = []
        check_content = {}
        for d in ("", *dirs):
            check_existence.append(os.path.join(d, ".yapfignore"))
            check_content.update({
                os.path.join(d, "pyproject.toml"): b"[tool.yapf",
                os.path.join(d, "setup.cfg"): b"[yapf]",
                os.path.join(d, ".style.yapf"): b"[style]",
            })

        return ConfigFilesRequest(
            specified=self.config,
            specified_option_name=f"[{self.options_scope}].config",
            discovery=cast(bool, self.options.config_discovery),
            check_existence=check_existence,
            check_content=check_content,
        )
예제 #29
0
파일: twine.py 프로젝트: codealchemy/pants
class TwineSubsystem(PythonToolBase):
    options_scope = "twine"
    name = "Twine"
    help = "The utility for publishing Python distributions to PyPi and other Python repositories."

    default_version = "twine>=3.7.1,<3.8"
    default_main = ConsoleScript("twine")

    # This explicit dependency resolves a weird behavior in poetry, where it would include a sys
    # platform constraint on "Windows" when this was included transitively from the twine
    # requirements.
    # See: https://github.com/pantsbuild/pants/pull/13594#issuecomment-968154931
    default_extra_requirements = ["colorama>=0.4.3"]

    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.subsystems",
                                 "twine.lock")
    default_lockfile_path = "src/python/pants/backend/python/subsystems/twine.lock"
    default_lockfile_url = git_url(default_lockfile_path)

    skip = SkipOption("publish")
    args = ArgsListOption(example="--skip-existing")
    config = FileOption(
        "--config",
        default=None,
        advanced=True,
        help=lambda cls:
        ("Path to a .pypirc config file to use. "
         "(https://packaging.python.org/specifications/pypirc/)\n\n"
         f"Setting this option will disable `[{cls.options_scope}].config_discovery`. Use "
         "this option if the config is located in a non-standard location."),
    )
    config_discovery = BoolOption(
        "--config-discovery",
        default=True,
        advanced=True,
        help=lambda cls:
        ("If true, Pants will include all relevant config files during runs "
         "(`.pypirc`).\n\n"
         f"Use `[{cls.options_scope}].config` instead if your config is in a "
         "non-standard location."),
    )
    ca_certs_path = StrOption(
        "--ca-certs-path",
        advanced=True,
        default="<inherit>",
        help=
        ("Path to a file containing PEM-format CA certificates used for verifying secure "
         "connections when publishing python distributions.\n\n"
         'Uses the value from `[GLOBAL].ca_certs_path` by default. Set to `"<none>"` to '
         "not use the default CA certificate."),
    )

    def config_request(self) -> ConfigFilesRequest:
        # Refer to https://twine.readthedocs.io/en/latest/#configuration for how config files are
        # discovered.
        return ConfigFilesRequest(
            specified=self.config,
            specified_option_name=f"[{self.options_scope}].config",
            discovery=self.config_discovery,
            check_existence=[".pypirc"],
        )

    def ca_certs_digest_request(
            self, default_ca_certs_path: str | None) -> CreateDigest | None:
        ca_certs_path: str | None = self.ca_certs_path
        if ca_certs_path == "<inherit>":
            ca_certs_path = default_ca_certs_path
        if not ca_certs_path or ca_certs_path == "<none>":
            return None

        # The certs file will typically not be in the repo, so we can't digest it via a PathGlobs.
        # Instead we manually create a FileContent for it.
        ca_certs_content = Path(ca_certs_path).read_bytes()
        chrooted_ca_certs_path = os.path.basename(ca_certs_path)
        return CreateDigest((FileContent(chrooted_ca_certs_path,
                                         ca_certs_content), ))
예제 #30
0
class MyPy(PythonToolBase):
    options_scope = "mypy"
    name = "MyPy"
    help = "The MyPy Python type checker (http://mypy-lang.org/)."

    default_version = "mypy==0.910"
    default_main = ConsoleScript("mypy")

    # See `mypy/rules.py`. We only use these default constraints in some situations.
    register_interpreter_constraints = True
    default_interpreter_constraints = ["CPython>=3.7,<4"]

    register_lockfile = True
    default_lockfile_resource = ("pants.backend.python.typecheck.mypy",
                                 "mypy.lock")
    default_lockfile_path = "src/python/pants/backend/python/typecheck/mypy/mypy.lock"
    default_lockfile_url = git_url(default_lockfile_path)
    uses_requirements_from_source_plugins = True

    skip = SkipOption("check")
    args = ArgsListOption(example="--python-version 3.7 --disallow-any-expr")
    config = FileOption(
        "--config",
        default=None,
        advanced=True,
        help=lambda cls:
        ("Path to a config file understood by MyPy "
         "(https://mypy.readthedocs.io/en/stable/config_file.html).\n\n"
         f"Setting this option will disable `[{cls.options_scope}].config_discovery`. Use "
         f"this option if the config is located in a non-standard location."),
    )
    config_discovery = BoolOption(
        "--config-discovery",
        default=True,
        advanced=True,
        help=lambda cls:
        ("If true, Pants will include any relevant config files during "
         "runs (`mypy.ini`, `.mypy.ini`, and `setup.cfg`)."
         f"\n\nUse `[{cls.options_scope}].config` instead if your config is in a "
         f"non-standard location."),
    )
    _source_plugins = TargetListOption(
        "--source-plugins",
        advanced=True,
        help=
        ("An optional list of `python_sources` target addresses to load first-party "
         "plugins.\n\n"
         "You must also set `plugins = path.to.module` in your `mypy.ini`, and "
         "set the `[mypy].config` option in your `pants.toml`.\n\n"
         "To instead load third-party plugins, set the option `[mypy].extra_requirements` "
         "and set the `plugins` option in `mypy.ini`."
         "Tip: it's often helpful to define a dedicated 'resolve' via "
         "`[python].resolves` for your MyPy plugins such as 'mypy-plugins' "
         "so that the third-party requirements used by your plugin, like `mypy`, do not "
         "mix with the rest of your project. Read that option's help message for more info "
         "on resolves."),
    )
    extra_type_stubs = StrListOption(
        "--extra-type-stubs",
        advanced=True,
        help=
        ("Extra type stub requirements to install when running MyPy.\n\n"
         "Normally, type stubs can be installed as typical requirements, such as putting "
         "them in `requirements.txt` or using a `python_requirement` target."
         "Alternatively, you can use this option so that the dependencies are solely "
         "used when running MyPy and are not runtime dependencies.\n\n"
         "Expects a list of pip-style requirement strings, like "
         "`['types-requests==2.25.9']`."),
    )

    @property
    def config_request(self) -> ConfigFilesRequest:
        # Refer to https://mypy.readthedocs.io/en/stable/config_file.html.
        return ConfigFilesRequest(
            specified=self.config,
            specified_option_name=f"{self.options_scope}.config",
            discovery=self.config_discovery,
            check_existence=["mypy.ini", ".mypy.ini"],
            check_content={
                "setup.cfg": b"[mypy",
                "pyproject.toml": b"[tool.mypy"
            },
        )

    @property
    def source_plugins(self) -> UnparsedAddressInputs:
        return UnparsedAddressInputs(self._source_plugins, owning_address=None)

    def check_and_warn_if_python_version_configured(
            self, config: FileContent | None) -> bool:
        """Determine if we can dynamically set `--python-version` and warn if not."""
        configured = []
        if config and b"python_version" in config.content:
            configured.append(
                f"`python_version` in {config.path} (which is used because of either config "
                "discovery or the `[mypy].config` option)")
        if "--py2" in self.args:
            configured.append("`--py2` in the `--mypy-args` option")
        if any(arg.startswith("--python-version") for arg in self.args):
            configured.append("`--python-version` in the `--mypy-args` option")
        if configured:
            formatted_configured = " and you set ".join(configured)
            logger.warning(
                f"You set {formatted_configured}. Normally, Pants would automatically set this "
                "for you based on your code's interpreter constraints "
                f"({doc_url('python-interpreter-compatibility')}). Instead, it will "
                "use what you set.\n\n"
                "(Automatically setting the option allows Pants to partition your targets by their "
                "constraints, so that, for example, you can run MyPy on Python 2-only code and "
                "Python 3-only code at the same time. This feature may no longer work.)"
            )
        return bool(configured)