• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 24055979590

06 Apr 2026 11:17PM UTC coverage: 52.37% (-40.5%) from 92.908%
24055979590

Pull #23225

github

web-flow
Merge 67474653c into 542ca048d
Pull Request #23225: Add --test-show-all-batch-targets to expose all targets in batched pytest

6 of 17 new or added lines in 2 files covered. (35.29%)

23030 existing lines in 605 files now uncovered.

31643 of 60422 relevant lines covered (52.37%)

1.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.21
/src/python/pants/backend/python/subsystems/pytest.py
1
# Copyright 2016 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
2✔
5

6
import os.path
2✔
7
from collections.abc import Iterable
2✔
8
from dataclasses import dataclass
2✔
9

10
from pants.backend.python.subsystems.python_tool_base import PythonToolBase
2✔
11
from pants.backend.python.target_types import (
2✔
12
    ConsoleScript,
13
    InterpreterConstraintsField,
14
    PythonResolveField,
15
    PythonTestsBatchCompatibilityTagField,
16
    PythonTestsExtraEnvVarsField,
17
    PythonTestSourceField,
18
    PythonTestsTimeoutField,
19
    PythonTestsXdistConcurrencyField,
20
    SkipPythonTestsField,
21
)
22
from pants.core.environments.target_types import EnvironmentField
2✔
23
from pants.core.goals.resolves import ExportableTool
2✔
24
from pants.core.goals.test import RuntimePackageDependenciesField, TestFieldSet
2✔
25
from pants.core.util_rules.config_files import ConfigFilesRequest
2✔
26
from pants.engine.rules import collect_rules
2✔
27
from pants.engine.target import Target
2✔
28
from pants.engine.unions import UnionRule
2✔
29
from pants.option.option_types import ArgsListOption, BoolOption, FileOption, SkipOption, StrOption
2✔
30
from pants.util.strutil import softwrap
2✔
31

32
# pants: infer-dep(pytest.lock*)
33

34

35
@dataclass(frozen=True)
2✔
36
class PythonTestFieldSet(TestFieldSet):
2✔
37
    required_fields = (PythonTestSourceField,)
2✔
38

39
    source: PythonTestSourceField
2✔
40
    interpreter_constraints: InterpreterConstraintsField
2✔
41
    timeout: PythonTestsTimeoutField
2✔
42
    runtime_package_dependencies: RuntimePackageDependenciesField
2✔
43
    extra_env_vars: PythonTestsExtraEnvVarsField
2✔
44
    xdist_concurrency: PythonTestsXdistConcurrencyField
2✔
45
    batch_compatibility_tag: PythonTestsBatchCompatibilityTagField
2✔
46
    resolve: PythonResolveField
2✔
47
    environment: EnvironmentField
2✔
48

49
    @classmethod
2✔
50
    def opt_out(cls, tgt: Target) -> bool:
2✔
UNCOV
51
        return tgt.get(SkipPythonTestsField).value
×
52

53

54
class PyTest(PythonToolBase):
2✔
55
    options_scope = "pytest"
2✔
56
    name = "Pytest"
2✔
57
    help_short = "The pytest Python test framework (https://docs.pytest.org/)."
2✔
58

59
    default_requirements = [
2✔
60
        "pytest>=7,<9,!=7.1.0,!=7.1.1",
61
        "pytest-cov>=5,<7",
62
        "pytest-xdist>=3.6.1,<4",
63
    ]
64

65
    default_main = ConsoleScript("pytest")
2✔
66

67
    default_lockfile_resource = ("pants.backend.python.subsystems", "pytest.lock")
2✔
68

69
    args = ArgsListOption(example="-k test_foo --quiet", passthrough=True)
2✔
70
    junit_family = StrOption(
2✔
71
        default="xunit2",
72
        advanced=True,
73
        help=softwrap(
74
            """
75
            The format of generated junit XML files. See
76
            https://docs.pytest.org/en/latest/reference.html#confval-junit_family.
77
            """
78
        ),
79
    )
80
    execution_slot_var = StrOption(
2✔
81
        default=None,
82
        advanced=True,
83
        help=softwrap(
84
            """
85
            If a non-empty string, the process execution slot id (an integer) will be exposed
86
            to tests under this environment variable name.
87
            """
88
        ),
89
    )
90
    config = FileOption(
2✔
91
        default=None,
92
        advanced=True,
93
        help=lambda cls: softwrap(
94
            f"""
95
            Path to a config file understood by Pytest
96
            (https://docs.pytest.org/en/latest/reference/customize.html#configuration-file-formats).
97
            Setting this option will disable `[{cls.options_scope}].config_discovery`. Use
98
            this option if the config is located in a non-standard location.
99
            """
100
        ),
101
    )
102
    config_discovery = BoolOption(
2✔
103
        default=True,
104
        advanced=True,
105
        help=lambda cls: softwrap(
106
            f"""
107
            If true, Pants will include all relevant Pytest config files (e.g. `pytest.ini`)
108
            during runs. See
109
            https://docs.pytest.org/en/stable/customize.html#finding-the-rootdir for where
110
            config files should be located for Pytest to discover them.
111

112
            Use `[{cls.options_scope}].config` instead if your config is in a
113
            non-standard location.
114
            """
115
        ),
116
    )
117
    xdist_enabled = BoolOption(
2✔
118
        default=False,
119
        advanced=False,
120
        help=softwrap(
121
            """
122
            If true, Pants will use `pytest-xdist` (https://pytest-xdist.readthedocs.io/en/latest/)
123
            to parallelize tests within each `python_test` target.
124

125
            NOTE: Enabling `pytest-xdist` can cause high-level scoped fixtures (for example `session`)
126
            to execute more than once. See the `pytest-xdist` docs for more info:
127
            https://pypi.org/project/pytest-xdist/#making-session-scoped-fixtures-execute-only-once
128
            """
129
        ),
130
    )
131
    allow_empty_test_collection = BoolOption(
2✔
132
        default=False,
133
        help=softwrap(
134
            """
135
            If true, treat pytest exit code 5 ("No tests were collected") as success.
136

137
            Pytest returns exit code 5 when no tests are collected, e.g., when all tests
138
            in a file are skipped via markers or deselected via `-k`. By default, Pants
139
            treats this as a test failure. Enable this option to instead treat it as
140
            "no tests found", which will be skipped in the test summary.
141

142
            See https://docs.pytest.org/en/stable/reference/exit-codes.html
143
            """
144
        ),
145
    )
146

147
    skip = SkipOption("test")
2✔
148

149
    def config_request(self, dirs: Iterable[str]) -> ConfigFilesRequest:
2✔
150
        # Refer to https://docs.pytest.org/en/stable/customize.html#finding-the-rootdir for how
151
        # config files are discovered.
152
        check_existence = []
2✔
153
        check_content = {}
2✔
154
        for d in ("", *dirs):
2✔
155
            check_existence.append(os.path.join(d, "pytest.ini"))
2✔
156
            check_content[os.path.join(d, "pyproject.toml")] = b"[tool.pytest.ini_options]"
2✔
157
            check_content[os.path.join(d, "tox.ini")] = b"[pytest]"
2✔
158
            check_content[os.path.join(d, "setup.cfg")] = b"[tool:pytest]"
2✔
159

160
        return ConfigFilesRequest(
2✔
161
            specified=self.config,
162
            specified_option_name=f"[{self.options_scope}].config",
163
            discovery=self.config_discovery,
164
            check_existence=check_existence,
165
            check_content=check_content,
166
        )
167

168

169
def rules():
2✔
170
    return (
2✔
171
        *collect_rules(),
172
        UnionRule(ExportableTool, PyTest),
173
    )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc