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

pantsbuild / pants / 19015773527

02 Nov 2025 05:33PM UTC coverage: 17.872% (-62.4%) from 80.3%
19015773527

Pull #22816

github

web-flow
Merge a12d75757 into 6c024e162
Pull Request #22816: Update Pants internal Python to 3.14

4 of 5 new or added lines in 3 files covered. (80.0%)

28452 existing lines in 683 files now uncovered.

9831 of 55007 relevant lines covered (17.87%)

0.18 hits per line

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

68.66
/src/python/pants/testutil/python_interpreter_selection.py
1
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
1✔
5

6
import os
1✔
7
import subprocess
1✔
8
from collections.abc import Iterable
1✔
9
from functools import lru_cache
1✔
10
from unittest import skipIf
1✔
11

12
import _pytest.mark.structures
1✔
13
import pytest
1✔
14

15
from pants.backend.python.util_rules.interpreter_constraints import InterpreterConstraints
1✔
16

17
PY_2 = "2"
1✔
18
PY_3 = "3"
1✔
19

20
PY_27 = "2.7"
1✔
21
PY_36 = "3.6"
1✔
22
PY_37 = "3.7"
1✔
23
PY_38 = "3.8"
1✔
24
PY_39 = "3.9"
1✔
25
PY_310 = "3.10"
1✔
26
PY_311 = "3.11"
1✔
27
PY_312 = "3.12"
1✔
28
PY_313 = "3.13"
1✔
29
PY_314 = "3.14"
1✔
30

31

32
def has_python_version(version):
1✔
33
    """Returns `True` if the current system has the specified version of python.
34

35
    :param string version: A python version string, such as 2.7, 3.
36
    """
37
    # TODO: Tests that skip unless a python interpreter is present often need the path to that
38
    # interpreter, and so end up calling python_interpreter_path again. Find a way to streamline this.
39
    return python_interpreter_path(version) is not None
1✔
40

41

42
@lru_cache
1✔
43
def python_interpreter_path(version):
1✔
44
    """Returns the interpreter path if the current system has the specified version of python.
45

46
    :param string version: A python version string, such as 2.7, 3.
47
    :returns: the normalized path to the interpreter binary if found; otherwise `None`
48
    :rtype: string
49
    """
50
    try:
1✔
51
        command = [f"python{version}", "-c", "import sys; print(sys.executable)"]
1✔
52
        py_path = subprocess.check_output(command).decode().strip()
1✔
53
        return os.path.realpath(py_path)
1✔
UNCOV
54
    except (subprocess.CalledProcessError, FileNotFoundError):
×
UNCOV
55
        return None
×
56

57

58
def skip_unless_all_pythons_present(*versions):
1✔
59
    """A decorator that only runs the decorated test method if all of the specified pythons are
60
    present.
61

62
    :param string *versions: Python version strings, such as 2.7, 3.
63
    """
UNCOV
64
    missing_versions = [v for v in versions if not has_python_version(v)]
×
UNCOV
65
    if len(missing_versions) == 1:
×
UNCOV
66
        return skipIf(True, f"Could not find python {missing_versions[0]} on system. Skipping.")
×
UNCOV
67
    elif len(missing_versions) > 1:
×
68
        return skipIf(
×
69
            True,
70
            "Skipping due to the following missing required pythons: {}".format(
71
                ", ".join(missing_versions)
72
            ),
73
        )
74
    else:
UNCOV
75
        return skipIf(False, "All required pythons present, continuing with test!")
×
76

77

78
def skip_unless_python27_present(func):
1✔
79
    """A test skip decorator that only runs a test method if python2.7 is present."""
80
    return skip_unless_all_pythons_present(PY_27)(func)
×
81

82

83
def skip_unless_python3_present(func):
1✔
84
    """A test skip decorator that only runs a test method if python3 is present."""
85
    return skip_unless_all_pythons_present(PY_3)(func)
×
86

87

88
def skip_unless_python36_present(func):
1✔
89
    """A test skip decorator that only runs a test method if python3.6 is present."""
90
    return skip_unless_all_pythons_present(PY_36)(func)
×
91

92

93
def skip_unless_python37_present(func):
1✔
94
    """A test skip decorator that only runs a test method if python3.7 is present."""
UNCOV
95
    return skip_unless_all_pythons_present(PY_37)(func)
×
96

97

98
def skip_unless_python38_present(func):
1✔
99
    """A test skip decorator that only runs a test method if python3.8 is present."""
UNCOV
100
    return skip_unless_all_pythons_present(PY_38)(func)
×
101

102

103
def skip_unless_python39_present(func):
1✔
104
    """A test skip decorator that only runs a test method if python3.9 is present."""
UNCOV
105
    return skip_unless_all_pythons_present(PY_39)(func)
×
106

107

108
def skip_unless_python310_present(func):
1✔
109
    """A test skip decorator that only runs a test method if python3.10 is present."""
110
    return skip_unless_all_pythons_present(PY_310)(func)
×
111

112

113
def skip_unless_python311_present(func):
1✔
114
    """A test skip decorator that only runs a test method if python3.11 is present."""
115
    return skip_unless_all_pythons_present(PY_311)(func)
×
116

117

118
def skip_unless_python310_and_python311_present(func):
1✔
119
    """A test skip decorator that only runs a test method if python3.8 and python3.9 are present."""
UNCOV
120
    return skip_unless_all_pythons_present(PY_310, PY_311)(func)
×
121

122

123
def skip_unless_python27_and_python3_present(func):
1✔
124
    """A test skip decorator that only runs a test method if python2.7 and python3 are present."""
125
    return skip_unless_all_pythons_present(PY_27, PY_3)(func)
×
126

127

128
def skip_unless_python27_and_python36_present(func):
1✔
129
    """A test skip decorator that only runs a test method if python2.7 and python3.6 are present."""
130
    return skip_unless_all_pythons_present(PY_27, PY_36)(func)
×
131

132

133
def skip_unless_python38_and_python39_present(func):
1✔
134
    """A test skip decorator that only runs a test method if python3.8 and python3.9 are present."""
UNCOV
135
    return skip_unless_all_pythons_present(PY_38, PY_39)(func)
×
136

137

138
def skip_unless_python37_and_python39_present(func):
1✔
139
    """A test skip decorator that only runs a test method if python3.7 and python3.9 are present."""
140
    return skip_unless_all_pythons_present(PY_37, PY_39)(func)
×
141

142

143
def all_major_minor_python_versions(
1✔
144
    constraints: Iterable[str],
145
) -> tuple[_pytest.mark.structures.ParameterSet, ...]:
146
    """All major.minor Python versions used by the interpreter constraints.
147

148
    This is intended to be used with `@pytest.mark.parametrize()` to run a test with every relevant
149
    Python interpreter.
150
    """
151
    versions = InterpreterConstraints(constraints).partition_into_major_minor_versions(
1✔
152
        # Please update this when new stable Python versions are released to CI.
153
        interpreter_universe=["2.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
154
    )
155
    return tuple(
1✔
156
        pytest.param(
157
            version,
158
            marks=pytest.mark.skipif(
159
                not has_python_version(version),
160
                reason=f"Could not find python {version} on system. Skipping.",
161
            ),
162
        )
163
        for version in versions
164
    )
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