Skip to content

Commit 9963088

Browse files
committed
Apply changes as found downstream in Python 3.10.8.
1 parent ba30e9b commit 9963088

File tree

3 files changed

+67
-14
lines changed

3 files changed

+67
-14
lines changed

Doc/library/importlib.metadata.rst

+4-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
.. versionchanged:: 3.10
1212
``importlib.metadata`` is no longer provisional.
1313

14-
**Source code:** :source:`Lib/importlib/metadata.py`
14+
**Source code:** :source:`Lib/importlib/metadata/__init__.py`
1515

1616
``importlib.metadata`` is a library that provides for access to installed
1717
package metadata. Built in part on Python's import system, this library
@@ -136,7 +136,7 @@ Inspect the resolved entry point::
136136
The ``group`` and ``name`` are arbitrary values defined by the package author
137137
and usually a client will wish to resolve all entry points for a particular
138138
group. Read `the setuptools docs
139-
<https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins>`_
139+
<https://setuptools.pypa.io/en/latest/userguide/entry_point.html>`_
140140
for more information on entry points, their definition, and usage.
141141

142142
*Compatibility Note*
@@ -255,7 +255,7 @@ function::
255255
Package distributions
256256
---------------------
257257

258-
A convience method to resolve the distribution or
258+
A convenience method to resolve the distribution or
259259
distributions (in the case of a namespace package) for top-level
260260
Python packages or modules::
261261

@@ -264,6 +264,7 @@ Python packages or modules::
264264

265265
.. versionadded:: 3.10
266266

267+
.. _distributions:
267268

268269
Distributions
269270
=============
@@ -335,6 +336,3 @@ a custom finder, return instances of this derived ``Distribution`` in the
335336
.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
336337
.. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api
337338
.. _`importlib_resources`: https://importlib-resources.readthedocs.io/en/latest/index.html
338-
339-
340-
.. rubric:: Footnotes

Lib/importlib/metadata/__init__.py

+46-8
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,21 @@ class EntryPoint(
128128
See `the packaging docs on entry points
129129
<https://packaging.python.org/specifications/entry-points/>`_
130130
for more information.
131+
132+
>>> ep = EntryPoint(
133+
... name=None, group=None, value='package.module:attr [extra1, extra2]')
134+
>>> ep.module
135+
'package.module'
136+
>>> ep.attr
137+
'attr'
138+
>>> ep.extras
139+
['extra1', 'extra2']
131140
"""
132141

133142
pattern = re.compile(
134143
r'(?P<module>[\w.]+)\s*'
135-
r'(:\s*(?P<attr>[\w.]+))?\s*'
136-
r'(?P<extras>\[.*\])?\s*$'
144+
r'(:\s*(?P<attr>[\w.]+)\s*)?'
145+
r'((?P<extras>\[.*\])\s*)?$'
137146
)
138147
"""
139148
A regular expression describing the syntax for an entry point,
@@ -176,7 +185,7 @@ def attr(self):
176185
@property
177186
def extras(self):
178187
match = self.pattern.match(self.value)
179-
return list(re.finditer(r'\w+', match.group('extras') or ''))
188+
return re.findall(r'\w+', match.group('extras') or '')
180189

181190
def _for(self, dist):
182191
self.dist = dist
@@ -200,6 +209,25 @@ def __reduce__(self):
200209
)
201210

202211
def matches(self, **params):
212+
"""
213+
EntryPoint matches the given parameters.
214+
215+
>>> ep = EntryPoint(group='foo', name='bar', value='bing:bong [extra1, extra2]')
216+
>>> ep.matches(group='foo')
217+
True
218+
>>> ep.matches(name='bar', value='bing:bong [extra1, extra2]')
219+
True
220+
>>> ep.matches(group='foo', name='other')
221+
False
222+
>>> ep.matches()
223+
True
224+
>>> ep.matches(extras=['extra1', 'extra2'])
225+
True
226+
>>> ep.matches(module='bing')
227+
True
228+
>>> ep.matches(attr='bong')
229+
True
230+
"""
203231
attrs = (getattr(self, param) for param in params)
204232
return all(map(operator.eq, params.values(), attrs))
205233

@@ -236,6 +264,8 @@ class DeprecatedList(list):
236264
1
237265
"""
238266

267+
__slots__ = ()
268+
239269
_warn = functools.partial(
240270
warnings.warn,
241271
"EntryPoints list interface is deprecated. Cast to list if needed.",
@@ -648,7 +678,7 @@ def _read_dist_info_reqs(self):
648678

649679
def _read_egg_info_reqs(self):
650680
source = self.read_text('requires.txt')
651-
return source and self._deps_from_requires_text(source)
681+
return None if source is None else self._deps_from_requires_text(source)
652682

653683
@classmethod
654684
def _deps_from_requires_text(cls, source):
@@ -669,16 +699,25 @@ def _convert_egg_info_reqs_to_simple_reqs(sections):
669699
def make_condition(name):
670700
return name and f'extra == "{name}"'
671701

672-
def parse_condition(section):
702+
def quoted_marker(section):
673703
section = section or ''
674704
extra, sep, markers = section.partition(':')
675705
if extra and markers:
676706
markers = f'({markers})'
677707
conditions = list(filter(None, [markers, make_condition(extra)]))
678708
return '; ' + ' and '.join(conditions) if conditions else ''
679709

710+
def url_req_space(req):
711+
"""
712+
PEP 508 requires a space between the url_spec and the quoted_marker.
713+
Ref python/importlib_metadata#357.
714+
"""
715+
# '@' is uniquely indicative of a url_req.
716+
return ' ' * ('@' in req)
717+
680718
for section in sections:
681-
yield section.value + parse_condition(section.name)
719+
space = url_req_space(section.value)
720+
yield section.value + space + quoted_marker(section.name)
682721

683722

684723
class DistributionFinder(MetaPathFinder):
@@ -741,14 +780,13 @@ def __new__(cls, root):
741780

742781
def __init__(self, root):
743782
self.root = root
744-
self.base = os.path.basename(self.root).lower()
745783

746784
def joinpath(self, child):
747785
return pathlib.Path(self.root, child)
748786

749787
def children(self):
750788
with suppress(Exception):
751-
return os.listdir(self.root or '')
789+
return os.listdir(self.root or '.')
752790
with suppress(Exception):
753791
return self.zip_children()
754792
return []

Lib/test/test_importlib/test_metadata_api.py

+17
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ def test_entry_points_groups_get(self):
172172
entry_points().get('entries', 'default') == entry_points()['entries']
173173
entry_points().get('missing', ()) == ()
174174

175+
def test_entry_points_allows_no_attributes(self):
176+
ep = entry_points().select(group='entries', name='main')
177+
with self.assertRaises(AttributeError):
178+
ep.foo = 4
179+
175180
def test_metadata_for_this_package(self):
176181
md = metadata('egginfo-pkg')
177182
assert md['author'] == 'Steven Ma'
@@ -217,6 +222,16 @@ def test_requires_egg_info(self):
217222
assert len(deps) == 2
218223
assert any(dep == 'wheel >= 1.0; python_version >= "2.7"' for dep in deps)
219224

225+
def test_requires_egg_info_empty(self):
226+
fixtures.build_files(
227+
{
228+
'requires.txt': '',
229+
},
230+
self.site_dir.joinpath('egginfo_pkg.egg-info'),
231+
)
232+
deps = requires('egginfo-pkg')
233+
assert deps == []
234+
220235
def test_requires_dist_info(self):
221236
deps = requires('distinfo-pkg')
222237
assert len(deps) == 2
@@ -235,6 +250,7 @@ def test_more_complex_deps_requires_text(self):
235250
236251
[extra1]
237252
dep4
253+
dep6@ git+https://example.com/python/[email protected]
238254
239255
[extra2:python_version < "3"]
240256
dep5
@@ -247,6 +263,7 @@ def test_more_complex_deps_requires_text(self):
247263
'dep3; python_version < "3"',
248264
'dep4; extra == "extra1"',
249265
'dep5; (python_version < "3") and extra == "extra2"',
266+
'dep6@ git+https://example.com/python/[email protected] ; extra == "extra1"',
250267
]
251268
# It's important that the environment marker expression be
252269
# wrapped in parentheses to avoid the following 'and' binding more

0 commit comments

Comments
 (0)