|
19 | 19 | # reference any injected objects! This includes not only global code but also
|
20 | 20 | # anything specified at the class level.
|
21 | 21 |
|
| 22 | +# Import builtin modules |
| 23 | +import _imp |
| 24 | +import _io |
| 25 | +import sys |
| 26 | +import _warnings |
| 27 | +import marshal |
| 28 | + |
| 29 | + |
| 30 | +_MS_WINDOWS = (sys.platform == 'win32') |
| 31 | +if _MS_WINDOWS: |
| 32 | + import nt as _os |
| 33 | + import winreg |
| 34 | +else: |
| 35 | + import posix as _os |
| 36 | + |
| 37 | + |
| 38 | +if _MS_WINDOWS: |
| 39 | + path_separators = ['\\', '/'] |
| 40 | +else: |
| 41 | + path_separators = ['/'] |
| 42 | +# Assumption made in _path_join() |
| 43 | +assert all(len(sep) == 1 for sep in path_separators) |
| 44 | +path_sep = path_separators[0] |
| 45 | +path_sep_tuple = tuple(path_separators) |
| 46 | +path_separators = ''.join(path_separators) |
| 47 | +_pathseps_with_colon = {f':{s}' for s in path_separators} |
| 48 | + |
| 49 | + |
22 | 50 | # Bootstrap-related code ######################################################
|
23 | 51 | _CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
|
24 | 52 | _CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
|
@@ -59,22 +87,49 @@ def _unpack_uint16(data):
|
59 | 87 | return int.from_bytes(data, 'little')
|
60 | 88 |
|
61 | 89 |
|
62 |
| -def _path_join(*path_parts): |
63 |
| - """Replacement for os.path.join().""" |
64 |
| - return path_sep.join([part.rstrip(path_separators) |
65 |
| - for part in path_parts if part]) |
| 90 | +if _MS_WINDOWS: |
| 91 | + def _path_join(*path_parts): |
| 92 | + """Replacement for os.path.join().""" |
| 93 | + if not path_parts: |
| 94 | + return "" |
| 95 | + if len(path_parts) == 1: |
| 96 | + return path_parts[0] |
| 97 | + root = "" |
| 98 | + path = [] |
| 99 | + for new_root, tail in map(_os._path_splitroot, path_parts): |
| 100 | + if new_root.startswith(path_sep_tuple) or new_root.endswith(path_sep_tuple): |
| 101 | + root = new_root.rstrip(path_separators) or root |
| 102 | + path = [path_sep + tail] |
| 103 | + elif new_root.endswith(':'): |
| 104 | + if root.casefold() != new_root.casefold(): |
| 105 | + # Drive relative paths have to be resolved by the OS, so we reset the |
| 106 | + # tail but do not add a path_sep prefix. |
| 107 | + root = new_root |
| 108 | + path = [tail] |
| 109 | + else: |
| 110 | + path.append(tail) |
| 111 | + else: |
| 112 | + root = new_root or root |
| 113 | + path.append(tail) |
| 114 | + path = [p.rstrip(path_separators) for p in path if p] |
| 115 | + if len(path) == 1 and not path[0]: |
| 116 | + # Avoid losing the root's trailing separator when joining with nothing |
| 117 | + return root + path_sep |
| 118 | + return root + path_sep.join(path) |
| 119 | + |
| 120 | +else: |
| 121 | + def _path_join(*path_parts): |
| 122 | + """Replacement for os.path.join().""" |
| 123 | + return path_sep.join([part.rstrip(path_separators) |
| 124 | + for part in path_parts if part]) |
66 | 125 |
|
67 | 126 |
|
68 | 127 | def _path_split(path):
|
69 | 128 | """Replacement for os.path.split()."""
|
70 |
| - if len(path_separators) == 1: |
71 |
| - front, _, tail = path.rpartition(path_sep) |
72 |
| - return front, tail |
73 |
| - for x in reversed(path): |
74 |
| - if x in path_separators: |
75 |
| - front, tail = path.rsplit(x, maxsplit=1) |
76 |
| - return front, tail |
77 |
| - return '', path |
| 129 | + i = max(path.rfind(p) for p in path_separators) |
| 130 | + if i < 0: |
| 131 | + return '', path |
| 132 | + return path[:i], path[i + 1:] |
78 | 133 |
|
79 | 134 |
|
80 | 135 | def _path_stat(path):
|
@@ -108,13 +163,18 @@ def _path_isdir(path):
|
108 | 163 | return _path_is_mode_type(path, 0o040000)
|
109 | 164 |
|
110 | 165 |
|
111 |
| -def _path_isabs(path): |
112 |
| - """Replacement for os.path.isabs. |
| 166 | +if _MS_WINDOWS: |
| 167 | + def _path_isabs(path): |
| 168 | + """Replacement for os.path.isabs.""" |
| 169 | + if not path: |
| 170 | + return False |
| 171 | + root = _os._path_splitroot(path)[0].replace('/', '\\') |
| 172 | + return len(root) > 1 and (root.startswith('\\\\') or root.endswith('\\')) |
113 | 173 |
|
114 |
| - Considers a Windows drive-relative path (no drive, but starts with slash) to |
115 |
| - still be "absolute". |
116 |
| - """ |
117 |
| - return path.startswith(path_separators) or path[1:3] in _pathseps_with_colon |
| 174 | +else: |
| 175 | + def _path_isabs(path): |
| 176 | + """Replacement for os.path.isabs.""" |
| 177 | + return path.startswith(path_separators) |
118 | 178 |
|
119 | 179 |
|
120 | 180 | def _write_atomic(path, data, mode=0o666):
|
@@ -658,6 +718,11 @@ def spec_from_file_location(name, location=None, *, loader=None,
|
658 | 718 | pass
|
659 | 719 | else:
|
660 | 720 | location = _os.fspath(location)
|
| 721 | + if not _path_isabs(location): |
| 722 | + try: |
| 723 | + location = _path_join(_os.getcwd(), location) |
| 724 | + except OSError: |
| 725 | + pass |
661 | 726 |
|
662 | 727 | # If the location is on the filesystem, but doesn't actually exist,
|
663 | 728 | # we could return None here, indicating that the location is not
|
@@ -1408,6 +1473,8 @@ def __init__(self, path, *loader_details):
|
1408 | 1473 | self._loaders = loaders
|
1409 | 1474 | # Base (directory) path
|
1410 | 1475 | self.path = path or '.'
|
| 1476 | + if not _path_isabs(self.path): |
| 1477 | + self.path = _path_join(_os.getcwd(), self.path) |
1411 | 1478 | self._path_mtime = -1
|
1412 | 1479 | self._path_cache = set()
|
1413 | 1480 | self._relaxed_path_cache = set()
|
@@ -1470,7 +1537,10 @@ def find_spec(self, fullname, target=None):
|
1470 | 1537 | is_namespace = _path_isdir(base_path)
|
1471 | 1538 | # Check for a file w/ a proper suffix exists.
|
1472 | 1539 | for suffix, loader_class in self._loaders:
|
1473 |
| - full_path = _path_join(self.path, tail_module + suffix) |
| 1540 | + try: |
| 1541 | + full_path = _path_join(self.path, tail_module + suffix) |
| 1542 | + except ValueError: |
| 1543 | + return None |
1474 | 1544 | _bootstrap._verbose_message('trying {}', full_path, verbosity=2)
|
1475 | 1545 | if cache_module + suffix in cache:
|
1476 | 1546 | if _path_isfile(full_path):
|
|
0 commit comments