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

pybuilder / pybuilder / 22815788768

08 Mar 2026 06:40AM UTC coverage: 82.899% (+0.4%) from 82.478%
22815788768

push

github

web-flow
Update supported Python versions in README (#937)

Add CPython 3.14, update PyPy versions to 3.9, 3.10, 3.11

1388 of 1840 branches covered (75.43%)

Branch coverage included in aggregate %.

5510 of 6481 relevant lines covered (85.02%)

38.73 hits per line

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

73.33
/src/main/python/pybuilder/extern/__init__.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 sys
47✔
20
from importlib import import_module
47✔
21
from importlib.abc import Loader, MetaPathFinder
47✔
22
from importlib.util import spec_from_loader
47✔
23

24
import pybuilder._vendor
47✔
25

26

27
class VendorImporter(Loader, MetaPathFinder):
47✔
28
    """
29
    A PEP 302 meta path importer for finding optionally-vendored
30
    or otherwise naturally-installed packages from root_name.
31
    """
32

33
    def __init__(self, root_name, vendored_names, vendor_pkg):
47✔
34
        self.root_name = root_name
47✔
35
        self.vendored_names = set(vendored_names)
47✔
36
        self.vendor_pkg = vendor_pkg
47✔
37
        self._in_flight_imports = set()
47✔
38

39
    @property
47✔
40
    def search_path(self):
47✔
41
        """
42
        Search first the vendor package then as a natural package.
43
        """
44
        yield self.vendor_pkg + "."
47✔
45

46
    def find_module(self, fullname, path=None):
47✔
47
        """
48
        Return self when fullname starts with root_name and the
49
        target module is one vendored through this importer.
50
        """
51
        root, base, target = fullname.partition(self.root_name + ".")
×
52
        if root == fullname and not base and not target:
×
53
            root = None
×
54
            target = fullname
×
55
        if root:
×
56
            return
×
57
        if not any(map(target.startswith, self.vendored_names)):
×
58
            return
×
59
        return self
×
60

61
    def load_module(self, fullname):
47✔
62
        """
63
        Iterate over the search path to locate and load fullname.
64
        """
65
        root, base, target = fullname.partition(self.root_name + ".")
47✔
66
        if root == fullname and not base and not target:
47!
67
            root = None
47✔
68
            target = fullname
47✔
69
        for prefix in self.search_path:
47!
70
            extant = prefix + target
47✔
71
            if extant not in self._in_flight_imports:
47✔
72
                self._in_flight_imports.add(extant)
47✔
73
                try:
47✔
74
                    mod = import_module(extant)
47✔
75
                finally:
76
                    self._in_flight_imports.remove(extant)
47✔
77
            if extant in sys.modules:
47!
78
                mod = sys.modules[extant]
47✔
79
                sys.modules[fullname] = mod
47✔
80
                return mod
47✔
81
        else:
82
            raise ImportError(
×
83
                "The '{target}' package is required; "
84
                "normally this is bundled with this package so if you get "
85
                "this warning, consult the packager of your "
86
                "distribution.".format(**locals())
87
            )
88

89
    def find_spec(self, fullname, path=None, target=None):
47✔
90
        """Return a module spec for vendored names."""
91
        return (
47✔
92
            spec_from_loader(fullname, self)
93
            if self._module_matches_namespace(fullname) else None
94
        )
95

96
    def _module_matches_namespace(self, fullname):
47✔
97
        """Figure out if the target module is vendored."""
98
        root, base, target = fullname.partition(self.root_name + '.')
47✔
99
        if root == fullname and not base and not target:
47!
100
            root = None
47✔
101
            target = fullname
47✔
102
        return not root and any(map(target.startswith, self.vendored_names))
47✔
103

104
    def _find_distributions(self, context):
47✔
105
        context.path.insert(0, pybuilder._vendor.__file__[:-len("__init__.py") - 1])
47✔
106
        return []
47✔
107

108
    # https://github.com/pybuilder/pybuilder/issues/807
109
    if sys.version_info[:2] == (3, 8):
47!
110
        def find_distributions(self, context):
×
111
            return iter(self._find_distributions(context))
×
112
    else:
113
        find_distributions = _find_distributions
47✔
114

115
    def install(self):
47✔
116
        """
117
        Install this importer into sys.meta_path if not already present.
118
        """
119
        if self not in sys.meta_path:
47!
120
            sys.meta_path.insert(0, self)
47✔
121

122
            for pkg in self.vendored_names:
47✔
123
                for p in list(sys.modules):
47✔
124
                    if p == pkg or p.startswith(pkg + "."):
47✔
125
                        sys.modules.pop(p, None)
23✔
126

127

128
VendorImporter(__name__, pybuilder._vendor.__names__, pybuilder._vendor.__package__).install()
47✔
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