Commit 420c4d6c authored by Jason Madden's avatar Jason Madden

Simplify getting the repr for greenlet functions and return the args/kwargs in more circumstances.

parent 8a2c50e2
......@@ -88,10 +88,12 @@
- Greenlet objects now keep track of their spawning parent greenlet
and the code location that spawned them, in addition to maintaining
a "spawn tree local" mapping. Based on a proposal from PayPal and
comments by Mahmoud Hashemi and Kurt Rose. See :issue:`755`.
comments by Mahmoud Hashemi and Kurt Rose. See :issue:`755` and
:pr:`1115`.
- The :mod:`gevent.greenlet` module is now compiled with Cython to
offset any performance loss due to :issue:`755`.
offset any performance decrease due to :issue:`755`. Please open
issues for any compatibility concerns. See :pr:`1115`.
1.3a1 (2018-01-27)
==================
......
......@@ -49,12 +49,14 @@ cdef class Greenlet(greenlet):
cdef object _notifier
cdef object _start_event
cdef dict _kwargs
cdef str _formatted_info
cpdef bint has_links(self)
cpdef join(self, timeout=*)
cpdef bint ready(self)
cpdef bint successful(self)
cpdef rawlink(self, object callback)
cpdef str _formatinfo(self)
cdef bint __started_but_aborted(self)
cdef bint __start_cancelled_by_kill(self)
......
......@@ -9,7 +9,6 @@ from weakref import ref as wref
from greenlet import greenlet
from greenlet import getcurrent
from gevent._compat import PY3
from gevent._compat import PYPY
from gevent._compat import reraise
from gevent._tblib import dump_traceback
......@@ -244,6 +243,7 @@ class Greenlet(greenlet):
self._kwargs = kwargs
self.value = None
self._notifier = None
self._formatted_info = None
self._links = []
# Initial state: None.
......@@ -393,19 +393,24 @@ class Greenlet(greenlet):
result += ': ' + formatted
return result + '>'
_formatted_info = None
def _formatinfo(self):
info = self._formatted_info
if info is not None:
return info
try:
result = getfuncname(self.__dict__['_run'])
except Exception: # pylint:disable=broad-except
# Don't cache
return ''
# Are we running an arbitrary function provided to the constructor,
# or did a subclass override _run?
func = self._run
im_self = getattr(func, '__self__', None)
if im_self is self:
funcname = '_run'
elif im_self is not None:
funcname = repr(func)
else:
funcname = getattr(func, '__name__', '') or repr(func)
result = funcname
args = []
if self.args:
args = [repr(x)[:50] for x in self.args]
......@@ -672,7 +677,7 @@ class Greenlet(greenlet):
self._report_result(result)
finally:
self.__dict__.pop('_run', None)
self.args = None
self.args = ()
self._kwargs = None
def _run(self):
......@@ -880,21 +885,3 @@ def killall(greenlets, exception=GreenletExit, block=True, timeout=None):
t.cancel()
else:
loop.run_callback(_killall, greenlets, exception)
if PY3:
_meth_self = "__self__"
else:
_meth_self = "im_self"
def getfuncname(func):
if not hasattr(func, _meth_self):
try:
funcname = func.__name__
except AttributeError:
pass
else:
if funcname != '<lambda>':
return funcname
return repr(func)
......@@ -405,6 +405,8 @@ class A(object):
hexobj = re.compile('-?0x[0123456789abcdef]+L?', re.I)
class Subclass(gevent.Greenlet):
pass
class TestStr(greentest.TestCase):
......@@ -428,6 +430,17 @@ class TestStr(greentest.TestCase):
str_g = str_g.replace(__name__, 'module')
self.assertEqual(str_g, '<Greenlet at X: <bound method A.method of <module.A object at X>>>')
def test_subclass(self):
g = Subclass()
str_g = hexobj.sub('X', str(g))
str_g = str_g.replace(__name__, 'module')
self.assertEqual(str_g, '<Subclass at X: _run>')
g = Subclass(None, 'question', answer=42)
str_g = hexobj.sub('X', str(g))
str_g = str_g.replace(__name__, 'module')
self.assertEqual(str_g, "<Subclass at X: _run('question', answer=42)>")
class TestJoin(AbstractGenericWaitTestCase):
......
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