Skip to content

Commit 01cf7b4

Browse files
committed
Extract Sectioned for parsing entry points
1 parent 4e28868 commit 01cf7b4

File tree

1 file changed

+64
-10
lines changed

1 file changed

+64
-10
lines changed

importlib_metadata/__init__.py

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import email
88
import pathlib
99
import operator
10+
import textwrap
1011
import functools
1112
import itertools
1213
import posixpath
@@ -55,6 +56,60 @@ def name(self):
5556
return name
5657

5758

59+
class Sectioned:
60+
"""
61+
A simple entry point config parser for performance
62+
63+
>>> res = Sectioned.get_sections(Sectioned._sample)
64+
>>> sec, values = next(res)
65+
>>> sec
66+
'sec1'
67+
>>> [(key, value) for key, value in values]
68+
[('a', '1'), ('b', '2')]
69+
>>> sec, values = next(res)
70+
>>> sec
71+
'sec2'
72+
>>> [(key, value) for key, value in values]
73+
[('a', '2')]
74+
>>> list(res)
75+
[]
76+
"""
77+
78+
_sample = textwrap.dedent(
79+
"""
80+
[sec1]
81+
a = 1
82+
b = 2
83+
84+
[sec2]
85+
a = 2
86+
"""
87+
).lstrip()
88+
89+
def __init__(self):
90+
self.section = None
91+
92+
def __call__(self, line):
93+
if line.startswith('[') and line.endswith(']'):
94+
# new section
95+
self.section = line.strip('[]')
96+
return
97+
return self.section
98+
99+
@classmethod
100+
def get_sections(cls, text):
101+
lines = filter(None, map(str.strip, text.splitlines()))
102+
return (
103+
(section, map(cls.parse_value, values))
104+
for section, values in itertools.groupby(lines, cls())
105+
if section is not None
106+
)
107+
108+
@staticmethod
109+
def parse_value(line):
110+
return map(str.strip, line.split("=", 1))
111+
112+
58113
class EntryPoint(
59114
PyPy_repr, collections.namedtuple('EntryPointBase', 'name value group')
60115
):
@@ -115,16 +170,15 @@ def extras(self):
115170

116171
@classmethod
117172
def _from_text(cls, text):
118-
# A hand-rolled parser is much faster than ConfigParser.
119-
if not text:
120-
return
121-
group = None
122-
for line in filter(None, map(str.strip, text.splitlines())):
123-
if line.startswith("["):
124-
group = line[1:-1]
125-
else:
126-
name, value = map(str.strip, line.split("=", 1))
127-
yield cls(name, value, group)
173+
return itertools.starmap(cls, cls._parse_groups(text or ''))
174+
175+
@staticmethod
176+
def _parse_groups(text):
177+
return (
178+
(name, value, section)
179+
for section, values in Sectioned.get_sections(text)
180+
for name, value in values
181+
)
128182

129183
@classmethod
130184
def _from_text_for(cls, text, dist):

0 commit comments

Comments
 (0)