Skip to content

Commit a184e73

Browse files
author
Scott Sanderson
committed
BUG: Fix crash when using @default with @Property.
1 parent f4140bf commit a184e73

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

interface/default.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ def non_member_attributes(defaults, members):
5252
# staticmethods can't use attributes of the interface.
5353
continue
5454

55+
elif isinstance(impl, property):
56+
impl = impl.fget
57+
5558
self_name = TypedSignature(impl).first_argument_name
5659
if self_name is None:
5760
# No parameters.
@@ -73,13 +76,20 @@ def accessed_attributes_of_local(f, local_name):
7376
The analysis performed by this function is conservative, meaning that
7477
it's not guaranteed to find **all** attributes used.
7578
"""
79+
try:
80+
instrs = dis.get_instructions(f)
81+
except TypeError:
82+
# Got a default wrapping an object that's not a python function. Be
83+
# conservative and assume this is safe.
84+
return set()
85+
7686
used = set()
7787
# Find sequences of the form: LOAD_FAST(local_name), LOAD_ATTR(<name>).
7888
# This will find all usages of the form ``local_name.<name>``.
7989
#
8090
# It will **NOT** find usages in which ``local_name`` is aliased to
8191
# another name.
82-
for first, second in sliding_window(dis.get_instructions(f), 2):
92+
for first, second in sliding_window(instrs, 2):
8393
if first.opname == 'LOAD_FAST' and first.argval == local_name:
8494
if second.opname in ('LOAD_ATTR', 'LOAD_METHOD', 'STORE_ATTR'):
8595
used.add(second.argval)

interface/tests/test_interface.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,29 @@ def method2(self):
528528
assert C().has_default() == 3
529529

530530

531+
def test_default_property():
532+
533+
class IFace(Interface): # pragma: nocover
534+
535+
@default
536+
@property
537+
def default_prop(self):
538+
return True
539+
540+
class C(implements(IFace)): # pragma: nocover
541+
pass
542+
543+
assert C().default_prop
544+
545+
class D(implements(IFace)):
546+
547+
@property
548+
def default_prop(self):
549+
return False
550+
551+
assert not D().default_prop
552+
553+
531554
def test_override_default():
532555

533556
class IFace(Interface): # pragma: nocover

0 commit comments

Comments
 (0)