Skip to content

Commit cdb843b

Browse files
committed
Consolidate classes and functions into api module
1 parent eb107b0 commit cdb843b

File tree

5 files changed

+98
-121
lines changed

5 files changed

+98
-121
lines changed

importlib_metadata/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
Distribution, PackageNotFoundError, distribution, distributions,
33
entry_points, files, metadata, requires, version)
44

5-
# Import for installation side-effects.
6-
from . import _hooks # noqa: F401
7-
85

96
__all__ = [
107
'Distribution',

importlib_metadata/_hooks.py

Lines changed: 2 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,7 @@
1-
from __future__ import unicode_literals, absolute_import
2-
3-
import re
41
import sys
5-
import zipp
6-
import itertools
7-
8-
from .abc import DistributionFinder
9-
from .api import Distribution
10-
11-
12-
if sys.version_info >= (3,): # pragma: nocover
13-
from contextlib import suppress
14-
else: # pragma: nocover
15-
from contextlib2 import suppress # noqa
16-
from itertools import imap as map # type: ignore
17-
18-
FileNotFoundError = IOError, OSError
19-
NotADirectoryError = IOError, OSError
20-
__metaclass__ = type
212

223

23-
if sys.version_info > (3, 5): # pragma: nocover
24-
from pathlib import Path
25-
else: # pragma: nocover
26-
from pathlib2 import Path
4+
__metaclass__ = type
275

286

297
def install(cls):
@@ -32,7 +10,7 @@ def install(cls):
3210
return cls
3311

3412

35-
class NullFinder(DistributionFinder):
13+
class NullFinder:
3614
"""
3715
A "Finder" (aka "MetaClassFinder") that never finds any modules,
3816
but may find distributions.
@@ -48,68 +26,3 @@ def find_spec(*args, **kwargs):
4826
# on sys.meta_path but having no other import
4927
# system functionality), the two methods are identical.
5028
find_module = find_spec
51-
52-
53-
@install
54-
class MetadataPathFinder(NullFinder):
55-
"""A degenerate finder for distribution packages on the file system.
56-
57-
This finder supplies only a find_distributions() method for versions
58-
of Python that do not have a PathFinder find_distributions().
59-
"""
60-
search_template = r'{pattern}(-.*)?\.(dist|egg)-info'
61-
62-
def find_distributions(self, name=None, path=None):
63-
"""Return an iterable of all Distribution instances capable of
64-
loading the metadata for packages matching the name
65-
(or all names if not supplied) along the paths in the list
66-
of directories ``path`` (defaults to sys.path).
67-
"""
68-
if path is None:
69-
path = sys.path
70-
pattern = '.*' if name is None else re.escape(name)
71-
found = self._search_paths(pattern, path)
72-
return map(PathDistribution, found)
73-
74-
@classmethod
75-
def _search_paths(cls, pattern, paths):
76-
"""
77-
Find metadata directories in paths heuristically.
78-
"""
79-
return itertools.chain.from_iterable(
80-
cls._search_path(path, pattern)
81-
for path in map(cls._switch_path, paths)
82-
)
83-
84-
@staticmethod
85-
def _switch_path(path):
86-
with suppress(Exception):
87-
return zipp.Path(path)
88-
return Path(path)
89-
90-
@classmethod
91-
def _predicate(cls, pattern, root, item):
92-
return re.match(pattern, str(item.name), flags=re.IGNORECASE)
93-
94-
@classmethod
95-
def _search_path(cls, root, pattern):
96-
if not root.is_dir():
97-
return ()
98-
normalized = pattern.replace('-', '_')
99-
matcher = cls.search_template.format(pattern=normalized)
100-
return (item for item in root.iterdir()
101-
if cls._predicate(matcher, root, item))
102-
103-
104-
class PathDistribution(Distribution):
105-
def __init__(self, path):
106-
"""Construct a distribution from a path to the metadata directory."""
107-
self._path = path
108-
109-
def read_text(self, filename):
110-
with suppress(FileNotFoundError, NotADirectoryError, KeyError):
111-
return self._path.joinpath(filename).read_text(encoding='utf-8')
112-
read_text.__doc__ = Distribution.read_text.__doc__
113-
114-
def locate_file(self, path):
115-
return self._path.parent / path

importlib_metadata/abc.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

importlib_metadata/api.py

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from __future__ import absolute_import
1+
from __future__ import unicode_literals, absolute_import
22

33
import io
44
import re
55
import abc
66
import csv
77
import sys
8+
import zipp
89
import email
910
import operator
1011
import functools
@@ -13,12 +14,17 @@
1314

1415
from importlib import import_module
1516
from itertools import starmap
17+
from ._hooks import install, NullFinder
1618

1719
if sys.version_info > (3,): # pragma: nocover
1820
from configparser import ConfigParser
21+
from contextlib import suppress
1922
else: # pragma: nocover
2023
from backports.configparser import ConfigParser
2124
from itertools import imap as map # type: ignore
25+
from contextlib2 import suppress # noqa
26+
FileNotFoundError = IOError, OSError
27+
NotADirectoryError = IOError, OSError
2228

2329
if sys.version_info > (3, 5): # pragma: nocover
2430
import pathlib
@@ -31,6 +37,13 @@
3137
BaseClass = ImportError # type: ignore
3238

3339

40+
if sys.version_info >= (3,): # pragma: nocover
41+
from importlib.abc import MetaPathFinder
42+
else: # pragma: nocover
43+
class MetaPathFinder(object):
44+
__metaclass__ = abc.ABCMeta
45+
46+
3447
__metaclass__ = type
3548

3649

@@ -305,6 +318,86 @@ def parse_condition(section):
305318
yield dep + parse_condition(section)
306319

307320

321+
class DistributionFinder(MetaPathFinder):
322+
"""
323+
A MetaPathFinder capable of discovering installed distributions.
324+
"""
325+
326+
@abc.abstractmethod
327+
def find_distributions(self, name=None, path=None):
328+
"""
329+
Return an iterable of all Distribution instances capable of
330+
loading the metadata for packages matching the name
331+
(or all names if not supplied) along the paths in the list
332+
of directories ``path`` (defaults to sys.path).
333+
"""
334+
335+
336+
@install
337+
class MetadataPathFinder(NullFinder, DistributionFinder):
338+
"""A degenerate finder for distribution packages on the file system.
339+
340+
This finder supplies only a find_distributions() method for versions
341+
of Python that do not have a PathFinder find_distributions().
342+
"""
343+
search_template = r'{pattern}(-.*)?\.(dist|egg)-info'
344+
345+
def find_distributions(self, name=None, path=None):
346+
"""Return an iterable of all Distribution instances capable of
347+
loading the metadata for packages matching the name
348+
(or all names if not supplied) along the paths in the list
349+
of directories ``path`` (defaults to sys.path).
350+
"""
351+
if path is None:
352+
path = sys.path
353+
pattern = '.*' if name is None else re.escape(name)
354+
found = self._search_paths(pattern, path)
355+
return map(PathDistribution, found)
356+
357+
@classmethod
358+
def _search_paths(cls, pattern, paths):
359+
"""
360+
Find metadata directories in paths heuristically.
361+
"""
362+
return itertools.chain.from_iterable(
363+
cls._search_path(path, pattern)
364+
for path in map(cls._switch_path, paths)
365+
)
366+
367+
@staticmethod
368+
def _switch_path(path):
369+
with suppress(Exception):
370+
return zipp.Path(path)
371+
return pathlib.Path(path)
372+
373+
@classmethod
374+
def _predicate(cls, pattern, root, item):
375+
return re.match(pattern, str(item.name), flags=re.IGNORECASE)
376+
377+
@classmethod
378+
def _search_path(cls, root, pattern):
379+
if not root.is_dir():
380+
return ()
381+
normalized = pattern.replace('-', '_')
382+
matcher = cls.search_template.format(pattern=normalized)
383+
return (item for item in root.iterdir()
384+
if cls._predicate(matcher, root, item))
385+
386+
387+
class PathDistribution(Distribution):
388+
def __init__(self, path):
389+
"""Construct a distribution from a path to the metadata directory."""
390+
self._path = path
391+
392+
def read_text(self, filename):
393+
with suppress(FileNotFoundError, NotADirectoryError, KeyError):
394+
return self._path.joinpath(filename).read_text(encoding='utf-8')
395+
read_text.__doc__ = Distribution.read_text.__doc__
396+
397+
def locate_file(self, path):
398+
return self._path.parent / path
399+
400+
308401
def _email_message_from_string(text):
309402
# Work around https://bugs.python.org/issue25545 where
310403
# email.message_from_string cannot handle Unicode on Python 2.

importlib_metadata/tests/test_main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from . import fixtures
1010
from .. import (
11-
Distribution, PackageNotFoundError, _hooks, api, distributions,
11+
Distribution, PackageNotFoundError, api, distributions,
1212
entry_points, metadata, version)
1313

1414
try:
@@ -31,7 +31,7 @@ def test_for_name_does_not_exist(self):
3131

3232
def test_new_style_classes(self):
3333
self.assertIsInstance(Distribution, type)
34-
self.assertIsInstance(_hooks.MetadataPathFinder, type)
34+
self.assertIsInstance(api.MetadataPathFinder, type)
3535

3636

3737
class ImportTests(fixtures.DistInfoPkg, unittest.TestCase):

0 commit comments

Comments
 (0)