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

pantsbuild / pants / 27118289758

08 Jun 2026 05:40AM UTC coverage: 92.786% (-0.005%) from 92.791%
27118289758

push

github

web-flow
Fix uv support under remote caching/execution. (#23403)

As explained in #23344, a remote cache hit on the process that
creates the uv venv will cause venv creation to be skipped,
and pex will not find that venv locally.

With this change uv venv creation and the pex invocation that
uses it run under the same `Process`, ensuring that they are
always run together or cached together.

This fixes not only the remote caching issue but also a
similar issue with remote execution, when we aren't
guaranteed to run the two processes on the same machine.

13 of 13 new or added lines in 2 files covered. (100.0%)

8 existing lines in 4 files now uncovered.

93104 of 100343 relevant lines covered (92.79%)

3.69 hits per line

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

67.14
/src/python/pants/util/osutil.py
1
# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
11✔
5

6
import errno
11✔
7
import getpass
11✔
8
import logging
11✔
9
import os
11✔
10
import platform
11✔
11
import posix
11✔
12
from functools import reduce
11✔
13

14
logger = logging.getLogger(__name__)
11✔
15

16

17
def _compute_cpu_count() -> int:
11✔
18
    # We use `sched_getaffinity()` to get the number of cores available to the process, rather than
19
    # the raw number of cores. This sometimes helps for containers to accurately report their # of
20
    # cores, rather than the host's.
21
    sched_getaffinity = getattr(os, "sched_getaffinity", None)
11✔
22
    if sched_getaffinity:
11✔
23
        return len(sched_getaffinity(0))
11✔
UNCOV
24
    cpu_count = os.cpu_count()
×
UNCOV
25
    if cpu_count:
×
UNCOV
26
        return cpu_count
×
27
    return 2
×
28

29

30
CPU_COUNT = _compute_cpu_count()
11✔
31

32

33
OS_ALIASES = {
11✔
34
    "macos": {"macos", "darwin", "macosx", "mac os x", "mac"},
35
    "linux": {"linux", "linux2"},
36
}
37

38
ARCH_ALIASES = {
11✔
39
    "x86_64": {"x86_64", "x86-64", "amd64"},
40
    "arm64": {"arm64", "aarch64"},
41
}
42

43
Pid = int
11✔
44

45

46
def get_arch_name(uname_result: posix.uname_result | None = None) -> str:
11✔
47
    """
48
    :API: public
49
    """
50
    if uname_result is None:
11✔
51
        uname_result = os.uname()
11✔
52
    return uname_result.machine.lower()
11✔
53

54

55
def get_os_name(uname_result: posix.uname_result | None = None) -> str:
11✔
56
    """
57
    :API: public
58
    """
59
    if uname_result is None:
11✔
60
        uname_result = os.uname()
11✔
61
    return uname_result.sysname.lower()
11✔
62

63

64
def normalize_arch_name(arch_name: str) -> str:
11✔
65
    """
66
    :API: public
67
    """
68
    return _normalize(arch_name, ARCH_ALIASES, "architecture")
11✔
69

70

71
def normalize_os_name(os_name: str) -> str:
11✔
72
    """
73
    :API: public
74
    """
75
    return _normalize(os_name, OS_ALIASES, "operating system")
11✔
76

77

78
def _normalize(name: str, aliases: dict[str, set[str]], warning_hint: str) -> str:
11✔
79
    for proper_name, alias_set in aliases.items():
11✔
80
        if name in alias_set:
11✔
81
            return proper_name
11✔
82
    else:
83
        logger.warning(
1✔
84
            "Unknown {hint} name: {bad}, known names are: {known}".format(
85
                hint=warning_hint, bad=name, known=", ".join(sorted(_values(aliases)))
86
            )
87
        )
88
        return name
1✔
89

90

91
def get_normalized_os_name() -> str:
11✔
92
    return normalize_os_name(get_os_name())
11✔
93

94

95
def get_normalized_arch_name() -> str:
11✔
96
    return normalize_arch_name(get_arch_name())
11✔
97

98

99
def macos_major_version() -> None | int:
11✔
100
    if not hasattr(platform, "mac_ver"):
×
101
        return None
×
102

103
    version = platform.mac_ver()[0]
×
104
    if not version:
×
105
        return None
×
106

107
    return int(version.split(".", 1)[0])
×
108

109

110
def is_macos_big_sur() -> bool:
11✔
111
    return macos_major_version() == 11
×
112

113

114
def getuser() -> str:
11✔
115
    try:
1✔
116
        return getpass.getuser()
1✔
117
    except KeyError:
×
118
        # Work when running with a uid not associated with a user,
119
        # e.g., in a docker container with a host uid.
120
        return str(os.getuid())
×
121

122

123
def _values(aliases: dict[str, set[str]]) -> set[str]:
11✔
124
    return reduce(set.union, aliases.values())
1✔
125

126

127
# From kill(2) on OSX 10.13:
128
#     [EINVAL]           Sig is not a valid, supported signal number.
129
#
130
#     [EPERM]            The sending process is not the super-user and its effective user id does not match the effective user-id of the receiving process.  When signaling a process group, this error is returned if
131
#                        any members of the group could not be signaled.
132
#
133
#     [ESRCH]            No process or process group can be found corresponding to that specified by pid.
134
#
135
#     [ESRCH]            The process id was given as 0, but the sending process does not have a process group.
136
def safe_kill(pid: Pid, signum: int) -> None:
11✔
137
    """Kill a process with the specified signal, catching nonfatal errors."""
138
    assert isinstance(pid, Pid)
×
139
    assert isinstance(signum, int)
×
140
    try:
×
141
        os.kill(pid, signum)
×
142
    except OSError as e:
×
143
        if e.errno in [errno.ESRCH, errno.EPERM]:
×
144
            pass
×
145
        elif e.errno == errno.EINVAL:
×
146
            raise ValueError(f"Invalid signal number {signum}: {e}", e)
×
147
        else:
148
            raise
×
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