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 33 */.tox/*
44 tests/*
55 prepare/*
6+ */_itertools.py
67
78[report]
89show_missing = True
Original file line number Diff line number Diff line change 11v3.5.0
22======
33
4+ * #280: ``entry_points `` now only returns entry points for
5+ unique distributions (by name).
46* ``entry_points() `` now returns an ``GroupedEntryPoints ``
57 object, a tuple of all entry points but with a convenience
68 property ``groups `` and ``__getitem__ `` accessor. Further,
Original file line number Diff line number Diff line change 2121 Protocol ,
2222)
2323
24+ from ._itertools import unique_everseen
25+
2426from configparser import ConfigParser
2527from contextlib import suppress
2628from importlib import import_module
@@ -698,7 +700,10 @@ def entry_points(**params):
698700
699701 :return: EntryPoint objects for all installed packages.
700702 """
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+ )
702707 return EntryPoints (eps ).select (** params )
703708
704709
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):
8080 self .assertIn (ep .dist .name , ('distinfo-pkg' , 'egginfo-pkg' ))
8181 self .assertEqual (ep .dist .version , "1.0.0" )
8282
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+
83111 def test_entry_points_missing_name (self ):
84112 with self .assertRaises (KeyError ):
85113 entry_points (group = 'entries' )['missing' ]
Original file line number Diff line number Diff line change @@ -38,7 +38,14 @@ use_develop = False
3838deps =
3939 ipython
4040commands =
41+ python -m ' print("Simple discovery performance")'
4142 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")'
4249
4350[testenv:release]
4451skip_install = True
You can’t perform that action at this time.
0 commit comments