Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5b8e60e

Browse filesBrowse files
committed
Merge tag v5.0.0 into cpython
2 parents cf54b86 + e9031b7 commit 5b8e60e
Copy full SHA for 5b8e60e

File tree

Expand file treeCollapse file tree

15 files changed

+390
-225
lines changed
Filter options
Expand file treeCollapse file tree

15 files changed

+390
-225
lines changed

‎.github/workflows/main.yml

Copy file name to clipboardExpand all lines: .github/workflows/main.yml
-44Lines changed: 0 additions & 44 deletions
This file was deleted.

‎Lib/importlib/_common.py

Copy file name to clipboardExpand all lines: Lib/importlib/_common.py
+3-6Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,15 @@ def get_resource_reader(package):
4343
# zipimport.zipimporter does not support weak references, resulting in a
4444
# TypeError. That seems terrible.
4545
spec = package.__spec__
46-
reader = getattr(spec.loader, 'get_resource_reader', None)
46+
reader = getattr(spec.loader, 'get_resource_reader', None) # type: ignore
4747
if reader is None:
4848
return None
49-
return reader(spec.name)
49+
return reader(spec.name) # type: ignore
5050

5151

5252
def resolve(cand):
5353
# type: (Package) -> types.ModuleType
54-
return (
55-
cand if isinstance(cand, types.ModuleType)
56-
else importlib.import_module(cand)
57-
)
54+
return cand if isinstance(cand, types.ModuleType) else importlib.import_module(cand)
5855

5956

6057
def get_package(package):

‎Lib/importlib/abc.py

Copy file name to clipboardExpand all lines: Lib/importlib/abc.py
+21-25Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ._abc import Loader
1515
import abc
1616
import warnings
17+
from typing import BinaryIO, Iterable, Text
1718
from typing import Protocol, runtime_checkable
1819

1920

@@ -297,49 +298,45 @@ def set_data(self, path, data):
297298

298299

299300
class ResourceReader(metaclass=abc.ABCMeta):
300-
301-
"""Abstract base class to provide resource-reading support.
302-
303-
Loaders that support resource reading are expected to implement
304-
the ``get_resource_reader(fullname)`` method and have it either return None
305-
or an object compatible with this ABC.
306-
"""
301+
"""Abstract base class for loaders to provide resource reading support."""
307302

308303
@abc.abstractmethod
309-
def open_resource(self, resource):
304+
def open_resource(self, resource: Text) -> BinaryIO:
310305
"""Return an opened, file-like object for binary reading.
311306
312-
The 'resource' argument is expected to represent only a file name
313-
and thus not contain any subdirectory components.
314-
307+
The 'resource' argument is expected to represent only a file name.
315308
If the resource cannot be found, FileNotFoundError is raised.
316309
"""
310+
# This deliberately raises FileNotFoundError instead of
311+
# NotImplementedError so that if this method is accidentally called,
312+
# it'll still do the right thing.
317313
raise FileNotFoundError
318314

319315
@abc.abstractmethod
320-
def resource_path(self, resource):
316+
def resource_path(self, resource: Text) -> Text:
321317
"""Return the file system path to the specified resource.
322318
323-
The 'resource' argument is expected to represent only a file name
324-
and thus not contain any subdirectory components.
325-
319+
The 'resource' argument is expected to represent only a file name.
326320
If the resource does not exist on the file system, raise
327321
FileNotFoundError.
328322
"""
323+
# This deliberately raises FileNotFoundError instead of
324+
# NotImplementedError so that if this method is accidentally called,
325+
# it'll still do the right thing.
329326
raise FileNotFoundError
330327

331328
@abc.abstractmethod
332-
def is_resource(self, name):
333-
"""Return True if the named 'name' is consider a resource."""
329+
def is_resource(self, path: Text) -> bool:
330+
"""Return True if the named 'path' is a resource.
331+
332+
Files are resources, directories are not.
333+
"""
334334
raise FileNotFoundError
335335

336336
@abc.abstractmethod
337-
def contents(self):
338-
"""Return an iterable of strings over the contents of the package."""
339-
return []
340-
341-
342-
_register(ResourceReader, machinery.SourceFileLoader)
337+
def contents(self) -> Iterable[str]:
338+
"""Return an iterable of entries in `package`."""
339+
raise FileNotFoundError
343340

344341

345342
@runtime_checkable
@@ -402,8 +399,7 @@ def open(self, mode='r', *args, **kwargs):
402399
"""
403400

404401
@abc.abstractproperty
405-
def name(self):
406-
# type: () -> str
402+
def name(self) -> str:
407403
"""
408404
The base name of this object without any parent references.
409405
"""

‎Lib/importlib/readers.py

Copy file name to clipboardExpand all lines: Lib/importlib/readers.py
+82Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import collections
12
import zipfile
23
import pathlib
34
from . import abc
45

56

7+
def remove_duplicates(items):
8+
return iter(collections.OrderedDict.fromkeys(items))
9+
10+
611
class FileReader(abc.TraversableResources):
712
def __init__(self, loader):
813
self.path = pathlib.Path(loader.path).parent
@@ -39,3 +44,80 @@ def is_resource(self, path):
3944

4045
def files(self):
4146
return zipfile.Path(self.archive, self.prefix)
47+
48+
49+
class MultiplexedPath(abc.Traversable):
50+
"""
51+
Given a series of Traversable objects, implement a merged
52+
version of the interface across all objects. Useful for
53+
namespace packages which may be multihomed at a single
54+
name.
55+
"""
56+
57+
def __init__(self, *paths):
58+
self._paths = list(map(pathlib.Path, remove_duplicates(paths)))
59+
if not self._paths:
60+
message = 'MultiplexedPath must contain at least one path'
61+
raise FileNotFoundError(message)
62+
if not all(path.is_dir() for path in self._paths):
63+
raise NotADirectoryError('MultiplexedPath only supports directories')
64+
65+
def iterdir(self):
66+
visited = []
67+
for path in self._paths:
68+
for file in path.iterdir():
69+
if file.name in visited:
70+
continue
71+
visited.append(file.name)
72+
yield file
73+
74+
def read_bytes(self):
75+
raise FileNotFoundError(f'{self} is not a file')
76+
77+
def read_text(self, *args, **kwargs):
78+
raise FileNotFoundError(f'{self} is not a file')
79+
80+
def is_dir(self):
81+
return True
82+
83+
def is_file(self):
84+
return False
85+
86+
def joinpath(self, child):
87+
# first try to find child in current paths
88+
for file in self.iterdir():
89+
if file.name == child:
90+
return file
91+
# if it does not exist, construct it with the first path
92+
return self._paths[0] / child
93+
94+
__truediv__ = joinpath
95+
96+
def open(self, *args, **kwargs):
97+
raise FileNotFoundError('{} is not a file'.format(self))
98+
99+
def name(self):
100+
return self._paths[0].name
101+
102+
def __repr__(self):
103+
return 'MultiplexedPath({})'.format(
104+
', '.join("'{}'".format(path) for path in self._paths)
105+
)
106+
107+
108+
class NamespaceReader(abc.TraversableResources):
109+
def __init__(self, namespace_path):
110+
if 'NamespacePath' not in str(namespace_path):
111+
raise ValueError('Invalid path')
112+
self.path = MultiplexedPath(*list(namespace_path))
113+
114+
def resource_path(self, resource):
115+
"""
116+
Return the file system path to prevent
117+
`resources.path()` from creating a temporary
118+
copy.
119+
"""
120+
return str(self.path.joinpath(resource))
121+
122+
def files(self):
123+
return self.path

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.