]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | import functools |
2 | import operator | |
3 | import itertools | |
4 | ||
5 | from .errors import OptionError | |
6 | from .extern.jaraco.text import yield_lines | |
7 | from .extern.jaraco.functools import pass_none | |
8 | from ._importlib import metadata | |
9 | from ._itertools import ensure_unique | |
10 | from .extern.more_itertools import consume | |
11 | ||
12 | ||
13 | def ensure_valid(ep): | |
14 | """ | |
15 | Exercise one of the dynamic properties to trigger | |
16 | the pattern match. | |
17 | """ | |
18 | try: | |
19 | ep.extras | |
20 | except AttributeError as ex: | |
21 | msg = ( | |
22 | f"Problems to parse {ep}.\nPlease ensure entry-point follows the spec: " | |
23 | "https://packaging.python.org/en/latest/specifications/entry-points/" | |
24 | ) | |
25 | raise OptionError(msg) from ex | |
26 | ||
27 | ||
28 | def load_group(value, group): | |
29 | """ | |
30 | Given a value of an entry point or series of entry points, | |
31 | return each as an EntryPoint. | |
32 | """ | |
33 | # normalize to a single sequence of lines | |
34 | lines = yield_lines(value) | |
35 | text = f'[{group}]\n' + '\n'.join(lines) | |
36 | return metadata.EntryPoints._from_text(text) | |
37 | ||
38 | ||
39 | def by_group_and_name(ep): | |
40 | return ep.group, ep.name | |
41 | ||
42 | ||
43 | def validate(eps: metadata.EntryPoints): | |
44 | """ | |
45 | Ensure entry points are unique by group and name and validate each. | |
46 | """ | |
47 | consume(map(ensure_valid, ensure_unique(eps, key=by_group_and_name))) | |
48 | return eps | |
49 | ||
50 | ||
51 | @functools.singledispatch | |
52 | def load(eps): | |
53 | """ | |
54 | Given a Distribution.entry_points, produce EntryPoints. | |
55 | """ | |
56 | groups = itertools.chain.from_iterable( | |
57 | load_group(value, group) | |
58 | for group, value in eps.items()) | |
59 | return validate(metadata.EntryPoints(groups)) | |
60 | ||
61 | ||
62 | @load.register(str) | |
63 | def _(eps): | |
64 | r""" | |
65 | >>> ep, = load('[console_scripts]\nfoo=bar') | |
66 | >>> ep.group | |
67 | 'console_scripts' | |
68 | >>> ep.name | |
69 | 'foo' | |
70 | >>> ep.value | |
71 | 'bar' | |
72 | """ | |
73 | return validate(metadata.EntryPoints(metadata.EntryPoints._from_text(eps))) | |
74 | ||
75 | ||
76 | load.register(type(None), lambda x: x) | |
77 | ||
78 | ||
79 | @pass_none | |
80 | def render(eps: metadata.EntryPoints): | |
81 | by_group = operator.attrgetter('group') | |
82 | groups = itertools.groupby(sorted(eps, key=by_group), by_group) | |
83 | ||
84 | return '\n'.join( | |
85 | f'[{group}]\n{render_items(items)}\n' | |
86 | for group, items in groups | |
87 | ) | |
88 | ||
89 | ||
90 | def render_items(eps): | |
91 | return '\n'.join( | |
92 | f'{ep.name} = {ep.value}' | |
93 | for ep in sorted(eps) | |
94 | ) |