@@ -60,51 +60,50 @@ def newsuper(typ=_SENTINEL, type_or_obj=_SENTINEL, framedepth=1):
60
60
raise RuntimeError ('super() used in a function with no args' )
61
61
62
62
try :
63
- # Get the MRO so we can crawl it.
64
- mro = type_or_obj . __mro__
65
- except ( AttributeError , RuntimeError ): # see issue #160
63
+ typ = find_owner ( type_or_obj , f . f_code )
64
+ except ( AttributeError , RuntimeError , TypeError ):
65
+ # see issues #160, #267
66
66
try :
67
- mro = type_or_obj .__class__ . __mro__
67
+ typ = find_owner ( type_or_obj .__class__ , f . f_code )
68
68
except AttributeError :
69
- raise RuntimeError ('super() used with a non-newstyle class' )
70
-
71
- # A ``for...else`` block? Yes! It's odd, but useful.
72
- # If unfamiliar with for...else, see:
73
- #
74
- # http://psung.blogspot.com/2007/12/for-else-in-python.html
75
- for typ in mro :
76
- # Find the class that owns the currently-executing method.
77
- for meth in typ .__dict__ .values ():
78
- # Drill down through any wrappers to the underlying func.
79
- # This handles e.g. classmethod() and staticmethod().
80
- try :
81
- while not isinstance (meth ,FunctionType ):
82
- if isinstance (meth , property ):
83
- # Calling __get__ on the property will invoke
84
- # user code which might throw exceptions or have
85
- # side effects
86
- meth = meth .fget
87
- else :
88
- try :
89
- meth = meth .__func__
90
- except AttributeError :
91
- meth = meth .__get__ (type_or_obj , typ )
92
- except (AttributeError , TypeError ):
93
- continue
94
- if meth .func_code is f .f_code :
95
- break # Aha! Found you.
96
- else :
97
- continue # Not found! Move onto the next class in MRO.
98
- break # Found! Break out of the search loop.
99
- else :
100
- raise RuntimeError ('super() called outside a method' )
69
+ raise RuntimeError ('super() used with an old-style class' )
70
+ except TypeError :
71
+ raise RuntimeError ('super() called outside a method' )
101
72
102
73
# Dispatch to builtin super().
103
74
if type_or_obj is not _SENTINEL :
104
75
return _builtin_super (typ , type_or_obj )
105
76
return _builtin_super (typ )
106
77
107
78
79
+ def find_owner (cls , code ):
80
+ '''Find the class that owns the currently-executing method.
81
+ '''
82
+ for typ in cls .__mro__ :
83
+ for meth in typ .__dict__ .values ():
84
+ # Drill down through any wrappers to the underlying func.
85
+ # This handles e.g. classmethod() and staticmethod().
86
+ try :
87
+ while not isinstance (meth ,FunctionType ):
88
+ if isinstance (meth , property ):
89
+ # Calling __get__ on the property will invoke
90
+ # user code which might throw exceptions or have
91
+ # side effects
92
+ meth = meth .fget
93
+ else :
94
+ try :
95
+ meth = meth .__func__
96
+ except AttributeError :
97
+ meth = meth .__get__ (cls , typ )
98
+ except (AttributeError , TypeError ):
99
+ continue
100
+ if meth .func_code is code :
101
+ return typ # Aha! Found you.
102
+ # Not found! Move onto the next class in MRO.
103
+
104
+ raise TypeError
105
+
106
+
108
107
def superm (* args , ** kwds ):
109
108
f = sys ._getframe (1 )
110
109
nm = f .f_code .co_name
0 commit comments