10000 Merge branch 'bugfix/97-entry-point-repr' into 'master' · python/importlib_metadata@031c7f0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 031c7f0

Browse files
committed
Merge branch 'bugfix/97-entry-point-repr' into 'master'
Fix EntryPoint.__repr__ on PyPy 2 Closes #97 See merge request python-devs/importlib_metadata!100
2 parents e226573 + 3e61dba commit 031c7f0

File tree

4 files changed

+55
-4
lines changed

4 files changed

+55
-4
lines changed

importlib_metadata/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
ModuleNotFoundError,
2828
MetaPathFinder,
2929
email_message_from_string,
30+
PyPy_repr,
3031
)
3132
from importlib import import_module
3233
from itertools import starmap
@@ -53,7 +54,9 @@ class PackageNotFoundError(ModuleNotFoundError):
5354
"""The package was not found."""
5455

5556

56-
class EntryPoint(collections.namedtuple('EntryPointBase', 'name value group')):
57+
class EntryPoint(
58+
PyPy_repr,
59+
collections.namedtuple('EntryPointBase', 'name value group')):
5760
"""An entry point as defined by Python packaging conventions.
5861
5962
See `the packaging docs on entry points

importlib_metadata/_compat.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,25 @@ def py2_message_from_string(text): # nocoverpy3
113113

114114
# https://bitbucket.org/pypy/pypy/issues/3021/ioopen-directory-leaks-a-file-descriptor
115115
PYPY_OPEN_BUG = getattr(sys, 'pypy_version_info', (9, 9, 9))[:3] <= (7, 1, 1)
116+
117+
118+
class PyPy_repr:
119+
"""
120+
Override repr for EntryPoint objects on PyPy2 to avoid __iter__ access.
121+
Ref #97.
122+
"""
123+
affected = (
124+
hasattr(sys, 'pypy_version_info') and
125+
sys.version_info < (3,)
126+
)
127+
128+
def __compat_repr__(self): # pragma: nocover
129+
def make_param(name):
130+
value = getattr(self, name)
131+
return '{name}={value!r}'.format(**locals())
132+
params = ', '.join(map(make_param, self._fields))
133+
return 'EntryPoint({params})'.format(**locals())
134+
135+
if affected: # pragma: nocover
136+
__repr__ = __compat_repr__
137+
del affected

importlib_metadata/docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ v1.1.0
77

88
* Dropped support for Python 3.4.
99
* EntryPoints are now pickleable. Closes #96.
10+
* Fixed ``repr(EntryPoint)`` on PyPy 2. Closes #97.
1011

1112
v1.0.0
1213
======

importlib_metadata/tests/test_main.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import unicode_literals
33

44
import re
5+
import json
56
import pickle
67
import textwrap
78
import unittest
@@ -193,7 +194,31 @@ def test_egg(self):
193194

194195

195196
class TestEntryPoints(unittest.TestCase):
197+
def __init__(self, *args):
198+
super(TestEntryPoints, self).__init__(*args)
199+
self.ep = importlib_metadata.EntryPoint('name', 'value', 'group')
200+
196201
def test_entry_point_pickleable(self):
197-
ep = importlib_metadata.EntryPoint('name', 'value', 'group')
198-
revived = pickle.loads(pickle.dumps(ep))
199-
assert revived == ep
202+
revived = pickle.loads(pickle.dumps(self.ep))
203+
assert revived == self.ep
204+
205+
def test_immutable(self):
206+
"""EntryPoints should be immutable"""
207+
with self.assertRaises(AttributeError):
208+
self.ep.name = 'badactor'
209+
210+
def test_repr(self):
211+
assert 'EntryPoint' in repr(self.ep)
212+
assert 'name=' in repr(self.ep)
213+
assert "'name'" in repr(self.ep)
214+
215+
def test_hashable(self):
216+
"""EntryPoints should be hashable"""
217+
hash(self.ep)
218+
219+
def test_json_dump(self):
220+
"""
221+
json should not expect to be able to dump an EntryPoint
222+
"""
223+
with self.assertRaises(Exception):
224+
json.dumps(self.ep)

0 commit comments

Comments
 (0)
0