8000 ENH: restore class level attributes by un-shadowing in _setattr_cm · matplotlib/matplotlib@e6db01f · GitHub
[go: up one dir, main page]

Skip to content

Commit e6db01f

Browse files
committed
ENH: restore class level attributes by un-shadowing in _setattr_cm
1 parent 066e6ef commit e6db01f

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

lib/matplotlib/cbook/__init__.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,8 +2039,19 @@ def _setattr_cm(obj, **kwargs):
20392039
# of MethodType every time so replace them with sentinel
20402040
#
20412041
# https://docs.python.org/3/howto/descriptor.html#functions-and-methods
2042-
origs = [(attr, _ if not inspect.ismethod(_) else sentinel)
2043-
for attr, _ in origs]
2042+
def filter_restores(obj, attr, val):
2043+
if inspect.ismethod(val):
2044+
return False
2045+
2046+
if attr in obj.__dict__:
2047+
return True
2048+
2049+
if isinstance(getattr(type(obj), attr), property):
2050+
return True
2051+
return False
2052+
2053+
origs = [(attr, val if filter_restores(obj, attr, val) else sentinel)
2054+
for attr, val in origs]
20442055
try:
20452056
for attr, val in kwargs.items():
20462057
setattr(obj, attr, val)

lib/matplotlib/tests/test_cbook.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,12 @@ def test_check_shape(target, test_shape):
655655

656656
def test_setattr_cm():
657657
class A:
658+
659+
cls_level = object()
660+
override = object()
658661
def __init__(self):
659662
self.aardvark = 'aardvark'
663+
self.override = 'override'
660664
self._p = 'p'
661665

662666
def meth(self):
@@ -670,7 +674,10 @@ def prop(self):
670674
def prop(self, val):
671675
self._p = val
672676

673-
a = A()
677+
class B(A):
678+
...
679+
680+
a = B()
674681
# When you access a Python method the function is bound
675682
# to the object at access time so you get a new instance
676683
# of MethodType every time.
@@ -683,19 +690,28 @@ def prop(self, val):
683690
# and our property happens to give the same instance every time
684691
assert a.prop is a.prop
685692

693+
assert a.cls_level is A.cls_level
694+
695+
assert a.override == 'override'
696+
686697
with cbook._setattr_cm(
687698
a,
688-
aardvark='moose', meth=lambda: None, prop='b'
699+
aardvark='moose', meth=lambda: None, prop='b', cls_level='bob',
700+
override='boo'
689701
):
690702
# because we have set a lambda, it is normal attribute access
691703
# and the same every time
692704
assert a.meth is a.meth
693705
assert a.aardvark is a.aardvark
694706
assert a.aardvark == 'moose'
695707
assert a.prop == 'b'
708+
assert a.cls_level == 'bob'
709+
assert a.override == 'boo'
696710

697711
# check that we get different MethodType instances each time
698712
assert a.meth is not a.meth
699713
assert a.aardvark is a.aardvark
700714
assert a.aardvark == 'aardvark'
701715
assert a.prop is a.prop
716+
assert a.cls_level is A.cls_level
717+
assert a.override == 'override'

0 commit comments

Comments
 (0)
0