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

pantsbuild / pants / 20438429929

22 Dec 2025 04:55PM UTC coverage: 80.287% (+0.003%) from 80.284%
20438429929

Pull #22934

github

web-flow
Merge b49c09e21 into 06f105be8
Pull Request #22934: feat(go): add multi-module support to golangci-lint plugin and upgrade to v2

37 of 62 new or added lines in 3 files covered. (59.68%)

183 existing lines in 9 files now uncovered.

78528 of 97809 relevant lines covered (80.29%)

3.36 hits per line

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

85.71
/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
9✔
5

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

10
from pants.backend.python.subsystems.python_tool_base import PythonToolBase
9✔
11
from pants.backend.python.target_types import (
9✔
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
9✔
23
from pants.core.goals.resolves import ExportableTool
9✔
24
from pants.core.goals.test import RuntimePackageDependenciesField, TestFieldSet
9✔
25
from pants.core.util_rules.config_files import ConfigFilesRequest
9✔
26
from pants.engine.rules import collect_rules
9✔
27
from pants.engine.target import Target
9✔
28
from pants.engine.unions import UnionRule
9✔
29
from pants.option.option_types import ArgsListOption, BoolOption, FileOption, SkipOption, StrOption
9✔
30
from pants.util.strutil import softwrap
9✔
31

32

33
@dataclass(frozen=True)
9✔
34
class PythonTestFieldSet(TestFieldSet):
9✔
35
    required_fields = (PythonTestSourceField,)
9✔
36

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

47
    @classmethod
9✔
48
    def opt_out(cls, tgt: Target) -> bool:
9✔
49
        return tgt.get(SkipPythonTestsField).value
1✔
50

51

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

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

63
    default_main = ConsoleScript("pytest")
9✔
64

65
    default_lockfile_resource = ("pants.backend.python.subsystems", "pytest.lock")
9✔
66

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

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

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

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

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

145
    skip = SkipOption("test")
9✔
146

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

UNCOV
158
        return ConfigFilesRequest(
×
159
            specified=self.config,
160
            specified_option_name=f"[{self.options_scope}].config",
161
            discovery=self.config_discovery,
162
            check_existence=check_existence,
163
            check_content=check_content,
164
        )
165

166

167
def rules():
9✔
168
    return (
7✔
169
        *collect_rules(),
170
        UnionRule(ExportableTool, PyTest),
171
    )
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

© 2025 Coveralls, Inc