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

pybuilder / pybuilder / 16613314016

30 Jul 2025 04:14AM UTC coverage: 84.008% (-0.1%) from 84.146%
16613314016

push

github

arcivanov
Release 0.13.16

2167 of 2671 branches covered (81.13%)

Branch coverage included in aggregate %.

5534 of 6496 relevant lines covered (85.19%)

36.25 hits per line

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

60.65
/src/main/python/pybuilder/python_utils.py
1
#   -*- coding: utf-8 -*-
2
#
3
#   This file is part of PyBuilder
4
#
5
#   Copyright 2011-2020 PyBuilder Team
6
#
7
#   Licensed under the Apache License, Version 2.0 (the "License");
8
#   you may not use this file except in compliance with the License.
9
#   You may obtain a copy of the License at
10
#
11
#       http://www.apache.org/licenses/LICENSE-2.0
12
#
13
#   Unless required by applicable law or agreed to in writing, software
14
#   distributed under the License is distributed on an "AS IS" BASIS,
15
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
#   See the License for the specific language governing permissions and
17
#   limitations under the License.
18

19
import os
44✔
20
import platform
44✔
21
import sys
44✔
22
import traceback
44✔
23
from collections import OrderedDict
44✔
24
from io import StringIO
44✔
25

26

27
def is_windows(platform=sys.platform, win_platforms={"win32", "cygwin", "msys"}):
44✔
28
    return platform in win_platforms
44✔
29

30

31
StringIO = StringIO
44✔
32
IS_PYPY = '__pypy__' in sys.builtin_module_names
44✔
33
IS_WIN = is_windows()
44✔
34

35

36
def raise_exception(ex, tb):
44✔
37
    raise ex.with_traceback(tb)
44✔
38

39

40
def is_string(val):
44✔
41
    return isinstance(val, str)
44✔
42

43

44
from shutil import which  # noqa: E402
44✔
45

46

47
def save_tb(ex):
44✔
48
    pass
×
49

50

51
is_string = is_string
44✔
52
makedirs = os.makedirs
44✔
53
which = which
44✔
54

55
odict = OrderedDict
44✔
56

57
_mp_get_context = None  # This will be patched at runtime
44✔
58
mp_ForkingPickler = None  # This will be patched at runtime
44✔
59
mp_log_to_stderr = None  # This will be patched at runtime
44✔
60
_mp_billiard_pyb_env = None  # This will be patched at runtime
44✔
61

62
_old_billiard_spawn_passfds = None  # This will be patched at runtime
44✔
63
_installed_tblib = False
44✔
64

65
from multiprocessing import log_to_stderr as mp_log_to_stderr, get_context as _mp_get_context  # noqa: E402
44✔
66
from multiprocessing.reduction import ForkingPickler as mp_ForkingPickler  # noqa: E402
44✔
67

68

69
def patch_mp_pyb_env(pyb_env):
44✔
70
    global _mp_billiard_pyb_env
71

72
    if not _mp_billiard_pyb_env:
44✔
73
        _mp_billiard_pyb_env = pyb_env
44✔
74

75

76
def install_tblib():
44✔
77
    global _installed_tblib
78

79
    if not _installed_tblib:
44!
80
        from pybuilder._vendor.tblib import pickling_support
44✔
81

82
        pickling_support.install()
44✔
83
        _installed_tblib = True
44✔
84

85

86
def patch_mp():
44✔
87
    install_tblib()
44✔
88

89

90
def mp_get_context(context):
44✔
91
    global _mp_get_context
92
    return _mp_get_context(context)
44✔
93

94

95
mp_ForkingPickler = mp_ForkingPickler
44✔
96
mp_log_to_stderr = mp_log_to_stderr
44✔
97
_mp_get_context = _mp_get_context
44✔
98

99

100
def _instrumented_target(q, target, *args, **kwargs):
44✔
101
    patch_mp()
×
102

103
    ex = tb = None
×
104
    try:
×
105
        send_value = (target(*args, **kwargs), None, None)
×
106
    except Exception:
×
107
        _, ex, tb = sys.exc_info()
×
108
        send_value = (None, ex, tb)
×
109

110
    try:
×
111
        q.put(send_value)
×
112
    except Exception:
×
113
        _, send_ex, send_tb = sys.exc_info()
×
114
        e_out = Exception(str(send_ex), send_tb, None if ex is None else str(ex), tb)
×
115
        q.put(e_out)
×
116

117

118
def spawn_process(target=None, args=(), kwargs={}, group=None, name=None):
44✔
119
    """
120
    Forks a child, making sure that all exceptions from the child are safely sent to the parent
121
    If a target raises an exception, the exception is re-raised in the parent process
122
    @return tuple consisting of process exit code and target's return value
123
    """
124
    ctx = mp_get_context("spawn")
×
125

126
    q = ctx.SimpleQueue()
×
127
    p = ctx.Process(group=group, target=_instrumented_target, name=name, args=[q, target] + list(args), kwargs=kwargs)
×
128
    p.start()
×
129
    result = q.get()
×
130
    p.join()
×
131
    if isinstance(result, tuple):
×
132
        if result[1]:
×
133
            raise_exception(result[1], result[2])
×
134
        return p.exitcode, result[0]
×
135
    else:
136
        msg = "Fatal error occurred in the forked process %s: %s" % (p, result.args[0])
×
137
        if result.args[2]:
×
138
            chained_message = "This error masked the send error '%s':\n%s" % (
×
139
                result.args[2], "".join(traceback.format_tb(result.args[3])))
140
            msg += "\n" + chained_message
×
141
        ex = Exception(msg)
×
142
        raise_exception(ex, result.args[1])
×
143

144

145
def prepend_env_to_path(python_env, sys_path):
44✔
146
    """type: (PythonEnv, List(str)) -> None
147
    Prepend venv directories to sys.path-like collection
148
    """
149
    for path in reversed(python_env.site_paths):
44✔
150
        if path not in sys_path:
44✔
151
            sys_path.insert(0, path)
44✔
152

153

154
def add_env_to_path(python_env, sys_path):
44✔
155
    """type: (PythonEnv, List(str)) -> None
156
    Adds venv directories to sys.path-like collection
157
    """
158
    for path in python_env.site_paths:
×
159
        if path not in sys_path:
×
160
            sys_path.append(path)
×
161

162

163
from glob import glob, iglob, escape  # noqa: E402
44✔
164

165
from os import symlink  # noqa: E402
44✔
166

167
symlink = symlink
44✔
168

169
sys_executable_suffix = sys.executable[len(sys.exec_prefix) + 1:]
44✔
170

171
python_specific_dir_name = "%s-%s" % (platform.python_implementation().lower(),
44✔
172
                                      ".".join(str(f) for f in sys.version_info))
173

174
_, _venv_python_exename = os.path.split(os.path.abspath(getattr(sys, "_base_executable", sys.executable)))
44✔
175

176
try:
44✔
177
    from imp import load_source
44✔
178
except ImportError:
16✔
179
    from importlib import machinery as importlib_machinery
16✔
180
    from importlib import util as importlib_util
16✔
181
    from importlib._bootstrap import _exec as importlib_exec
16✔
182
    from importlib._bootstrap import _load as importlib_load
16✔
183

184

185
    class _HackedGetData:
16✔
186

187
        """Compatibility support for 'file' arguments of various load_*()
188
        functions."""
189

190
        def __init__(self, fullname, path, file=None):
16✔
191
            super().__init__(fullname, path)
16✔
192
            self.file = file
16✔
193

194
        def get_data(self, path):
16✔
195
            """Gross hack to contort loader to deal w/ load_*()'s bad API."""
196
            if self.file and path == self.path:
16!
197
                # The contract of get_data() requires us to return bytes. Reopen the
198
                # file in binary mode if needed.
199
                if not self.file.closed:
×
200
                    file = self.file
×
201
                    if 'b' not in file.mode:
×
202
                        file.close()
×
203
                if self.file.closed:
×
204
                    self.file = file = open(self.path, 'rb')
×
205

206
                with file:
×
207
                    return file.read()
×
208
            else:
209
                return super().get_data(path)
16✔
210

211

212
    class _LoadSourceCompatibility(_HackedGetData, importlib_machinery.SourceFileLoader):
16✔
213

214
        """Compatibility support for implementing load_source()."""
215

216

217
    def load_source(name, pathname, file=None):
16✔
218
        loader = _LoadSourceCompatibility(name, pathname, file)
16✔
219
        spec = importlib_util.spec_from_file_location(name, pathname, loader=loader)
16✔
220
        if name in sys.modules:
16✔
221
            module = importlib_exec(spec, sys.modules[name])
16✔
222
        else:
223
            module = importlib_load(spec)
16✔
224
        # To allow reloading to potentially work, use a non-hacked loader which
225
        # won't rely on a now-closed file object.
226
        module.__loader__ = importlib_machinery.SourceFileLoader(name, pathname)
16✔
227
        module.__spec__.loader = module.__loader__
16✔
228
        return module
16✔
229

230
__all__ = ["glob", "iglob", "escape"]
44✔
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