Commit eacc7441 authored by Jason Madden's avatar Jason Madden

Don't double-descriptor @staticmethod objects. Fixes #1266

parent d0aa959f
......@@ -12,6 +12,10 @@
3.7 or they will crash. Reported by Alexey Stepanov in :issue:`1260`
and pkittenis in :issue:`1261`.
- :class:`gevent.local.local` subclasses correctly supports
``@staticmethod`` functions. Reported by Brendan Powers in
:issue:`1266`.
1.3.5 (2018-07-16)
==================
......
......@@ -438,13 +438,23 @@ class local(object):
return dct[name]
if name in self._local_type_vars:
type_attr = getattr(self._local_type, name)
# It's not in the dict at all. Is it in the type?
# Not in the dictionary, but is found in the type. It could be
# a non-data descriptor still. Some descriptors, like @staticmethod,
# return objects (functions, in this case), that are *themselves*
# descriptors, which when invoked, again, would do the wrong thing.
# So we can't rely on getattr() on the type for them, we have to
# look through the MRO dicts ourself.
if name not in self._local_type_get_descriptors:
# Not a descriptor, can't execute code
return type_attr
return type(type_attr).__get__(type_attr, self, self._local_type)
# Not a descriptor, can't execute code. So all we need is
# the return value of getattr() on our type.
return getattr(self._local_type, name)
for base in self._local_type.mro():
bd = base.__dict__
if name in bd:
attr_on_type = bd[name]
result = type(attr_on_type).__get__(attr_on_type, self, self._local_type)
return result
# It wasn't in the dict and it wasn't in the type.
# So the next step is to invoke type(self)__getattr__, if it
......
......@@ -83,6 +83,20 @@ class LocalWithABC(local, Mapping):
def __len__(self):
return len(self.d)
class LocalWithStaticMethod(local):
@staticmethod
def a_staticmethod():
return 42
class LocalWithClassMethod(local):
@classmethod
def a_classmethod(cls):
return cls
class TestGeventLocal(greentest.TestCase):
# pylint:disable=attribute-defined-outside-init,blacklisted-name
......@@ -352,6 +366,14 @@ class TestGeventLocal(greentest.TestCase):
self.assertIn('a', x.d)
self.assertEqual(['a'], list(x.keys()))
def test_local_with_staticmethod(self):
x = LocalWithStaticMethod()
self.assertEqual(42, x.a_staticmethod())
def test_local_with_classmethod(self):
x = LocalWithClassMethod()
self.assertIs(LocalWithClassMethod, x.a_classmethod())
try:
from zope import interface
except ImportError:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment