File tree Expand file tree Collapse file tree 6 files changed +63
-1
lines changed Expand file tree Collapse file tree 6 files changed +63
-1
lines changed Original file line number Diff line number Diff line change 3
3
*/.tox/*
4
4
tests/*
5
5
prepare/*
6
+ */_itertools.py
6
7
7
8
[report]
8
9
show_missing = True
Original file line number Diff line number Diff line change 1
1
v3.5.0
2
2
======
3
3
4
+ * #280: ``entry_points `` now only returns entry points for
5
+ unique distributions (by name).
4
6
* ``entry_points() `` now returns an ``GroupedEntryPoints ``
5
7
object, a tuple of all entry points but with a convenience
6
8
property ``groups `` and ``__getitem__ `` accessor. Further,
Original file line number Diff line number Diff line change 21
21
Protocol ,
22
22
)
23
23
24
+ from ._itertools import unique_everseen
25
+
24
26
from configparser import ConfigParser
25
27
from contextlib import suppress
26
28
from importlib import import_module
@@ -698,7 +700,10 @@ def entry_points(**params):
698
700
699
701
:return: EntryPoint objects for all installed packages.
700
702
"""
701
- eps = itertools .chain .from_iterable (dist .entry_points for dist in distributions ())
703
+ unique = functools .partial (unique_everseen , key = operator .attrgetter ('name' ))
704
+ eps = itertools .chain .from_iterable (
705
+ dist .entry_points for dist in unique (distributions ())
706
+ )
702
707
return EntryPoints (eps ).select (** params )
703
708
704
709
Original file line number Diff line number Diff line change
1
+ from itertools import filterfalse
2
+
3
+
4
+ def unique_everseen (iterable , key = None ):
5
+ "List unique elements, preserving order. Remember all elements ever seen."
6
+ # unique_everseen('AAAABBBCCDAABBB') --> A B C D
7
+ # unique_everseen('ABBCcAD', str.lower) --> A B C D
8
+ seen = set ()
9
+ seen_add = seen .add
10
+ if key is None :
11
+ for element in filterfalse (seen .__contains__ , iterable ):
12
+ seen_add (element )
13
+ yield element
14
+ else :
15
+ for element in iterable :
16
+ k = key (element )
17
+ if k not in seen :
18
+ seen_add (k )
19
+ yield element
Original file line number Diff line number Diff line change @@ -80,6 +80,34 @@ def test_entry_points_distribution(self):
80
80
self .assertIn (ep .dist .name , ('distinfo-pkg' , 'egginfo-pkg' ))
81
81
self .assertEqual (ep .dist .version , "1.0.0" )
82
82
83
+ def test_entry_points_unique_packages (self ):
84
+ """
85
+ Entry points should only be exposed for the first package
86
+ on sys.path with a given name.
87
+ """
88
+ alt_site_dir = self .fixtures .enter_context (fixtures .tempdir ())
89
+ self .fixtures .enter_context (self .add_sys_path (alt_site_dir ))
90
+ alt_pkg = {
91
+ "distinfo_pkg-1.1.0.dist-info" : {
92
+ "METADATA" : """
93
+ Name: distinfo-pkg
94
+ Version: 1.1.0
95
+ """ ,
96
+ "entry_points.txt" : """
97
+ [entries]
98
+ main = mod:altmain
99
+ """ ,
100
+ },
101
+ }
102
+ fixtures .build_files (alt_pkg , alt_site_dir )
103
+ entries = entry_points (group = 'entries' )
104
+ assert not any (
105
+ ep .dist .name == 'distinfo-pkg' and ep .dist .version == '1.0.0'
106
+ for ep in entries
107
+ )
108
+ # ns:sub doesn't exist in alt_pkg
109
+ assert 'ns:sub' not in entries
110
+
83
111
def test_entry_points_missing_name (self ):
84
112
with self .assertRaises (KeyError ):
85
113
entry_points (group = 'entries' )['missing' ]
Original file line number Diff line number Diff line change @@ -38,7 +38,14 @@ use_develop = False
38
38
deps =
39
39
ipython
40
40
commands =
41
+ python -m ' print("Simple discovery performance")'
41
42
python -m timeit -s ' import importlib_metadata' -- ' importlib_metadata.distribution("ipython")'
43
+ python -m ' print("Entry point discovery performance")'
44
+ python -m timeit -s ' import importlib_metadata' -- ' importlib_metadata.entry_points()'
45
+ python -c ' print("Cached lookup performance")'
46
+ python -m timeit -s ' import importlib_metadata; importlib_metadata.distribution("ipython")' -- ' importlib_metadata.distribution("ipython")'
47
+ python -c ' print("Uncached lookup performance")'
48
+ python -m timeit -s ' import importlib, importlib_metadata' -- ' importlib.invalidate_caches(); importlib_metadata.distribution("ipython")'
42
49
43
50
[testenv:release]
44
51
skip_install = True
You can’t perform that action at this time.
0 commit comments