'get_child_watcher', 'set_child_watcher',
]
+import functools
+import inspect
import subprocess
import threading
import socket
+import sys
+
+
+_PY34 = sys.version_info >= (3, 4)
+
+def _get_function_source(func):
+ if _PY34:
+ func = inspect.unwrap(func)
+ elif hasattr(func, '__wrapped__'):
+ func = func.__wrapped__
+ if inspect.isfunction(func):
+ code = func.__code__
+ return (code.co_filename, code.co_firstlineno)
+ if isinstance(func, functools.partial):
+ return _get_function_source(func.func)
+ if _PY34 and isinstance(func, functools.partialmethod):
+ return _get_function_source(func.func)
+ return None
class Handle:
self._cancelled = False
def __repr__(self):
- res = 'Handle({}, {})'.format(self._callback, self._args)
+ cb_repr = getattr(self._callback, '__qualname__', None)
+ if not cb_repr:
+ cb_repr = str(self._callback)
+
+ source = _get_function_source(self._callback)
+ if source:
+ cb_repr += ' at %s:%s' % source
+
+ res = 'Handle({}, {})'.format(cb_repr, self._args)
if self._cancelled:
res += '<cancelled>'
return res
import io
import os
import platform
+import re
import signal
import socket
try:
return asyncio.SelectorEventLoop(selectors.SelectSelector())
+def noop():
+ pass
+
+
class HandleTests(unittest.TestCase):
+ def setUp(self):
+ self.loop = None
+
def test_handle(self):
def callback(*args):
return args
args = ()
- h = asyncio.Handle(callback, args, mock.Mock())
+ h = asyncio.Handle(callback, args, self.loop)
self.assertIs(h._callback, callback)
self.assertIs(h._args, args)
self.assertFalse(h._cancelled)
- r = repr(h)
- self.assertTrue(r.startswith(
- 'Handle('
- '<function HandleTests.test_handle.<locals>.callback'))
- self.assertTrue(r.endswith('())'))
-
h.cancel()
self.assertTrue(h._cancelled)
- r = repr(h)
- self.assertTrue(r.startswith(
- 'Handle('
- '<function HandleTests.test_handle.<locals>.callback'))
- self.assertTrue(r.endswith('())<cancelled>'), r)
-
def test_handle_from_handle(self):
def callback(*args):
return args
- m_loop = object()
- h1 = asyncio.Handle(callback, (), loop=m_loop)
+ h1 = asyncio.Handle(callback, (), loop=self.loop)
self.assertRaises(
- AssertionError, asyncio.Handle, h1, (), m_loop)
+ AssertionError, asyncio.Handle, h1, (), self.loop)
def test_callback_with_exception(self):
def callback():
raise ValueError()
- m_loop = mock.Mock()
- m_loop.call_exception_handler = mock.Mock()
+ self.loop = mock.Mock()
+ self.loop.call_exception_handler = mock.Mock()
- h = asyncio.Handle(callback, (), m_loop)
+ h = asyncio.Handle(callback, (), self.loop)
h._run()
- m_loop.call_exception_handler.assert_called_with({
+ self.loop.call_exception_handler.assert_called_with({
'message': test_utils.MockPattern('Exception in callback.*'),
'exception': mock.ANY,
'handle': h
def test_handle_weakref(self):
wd = weakref.WeakValueDictionary()
- h = asyncio.Handle(lambda: None, (), object())
+ h = asyncio.Handle(lambda: None, (), self.loop)
wd['h'] = h # Would fail without __weakref__ slot.
+ def test_repr(self):
+ # simple function
+ h = asyncio.Handle(noop, (), self.loop)
+ src = test_utils.get_function_source(noop)
+ self.assertEqual(repr(h),
+ 'Handle(noop at %s:%s, ())' % src)
+
+ # cancelled handle
+ h.cancel()
+ self.assertEqual(repr(h),
+ 'Handle(noop at %s:%s, ())<cancelled>' % src)
+
+ # decorated function
+ cb = asyncio.coroutine(noop)
+ h = asyncio.Handle(cb, (), self.loop)
+ self.assertEqual(repr(h),
+ 'Handle(noop at %s:%s, ())' % src)
+
+ # partial function
+ cb = functools.partial(noop)
+ h = asyncio.Handle(cb, (), self.loop)
+ filename, lineno = src
+ regex = (r'^Handle\(functools.partial\('
+ r'<function noop .*>\) at %s:%s, '
+ r'\(\)\)$' % (re.escape(filename), lineno))
+ self.assertRegex(repr(h), regex)
+
+ # partial method
+ if sys.version_info >= (3, 4):
+ method = HandleTests.test_repr
+ cb = functools.partialmethod(method)
+ src = test_utils.get_function_source(method)
+ h = asyncio.Handle(cb, (), self.loop)
+
+ filename, lineno = src
+ regex = (r'^Handle\(functools.partialmethod\('
+ r'<function HandleTests.test_repr .*>, , \) at %s:%s, '
+ r'\(\)\)$' % (re.escape(filename), lineno))
+ self.assertRegex(repr(h), regex)
+
+
class TimerTests(unittest.TestCase):
yield from []
return 'abc'
+ filename, lineno = test_utils.get_function_source(notmuch)
+ src = "%s:%s" % (filename, lineno)
+
t = asyncio.Task(notmuch(), loop=self.loop)
t.add_done_callback(Dummy())
- self.assertEqual(repr(t), 'Task(<notmuch>)<PENDING, [Dummy()]>')
+ self.assertEqual(repr(t),
+ 'Task(<notmuch at %s>)<PENDING, [Dummy()]>' % src)
+
t.cancel() # Does not take immediate effect!
- self.assertEqual(repr(t), 'Task(<notmuch>)<CANCELLING, [Dummy()]>')
+ self.assertEqual(repr(t),
+ 'Task(<notmuch at %s>)<CANCELLING, [Dummy()]>' % src)
self.assertRaises(asyncio.CancelledError,
self.loop.run_until_complete, t)
- self.assertEqual(repr(t), 'Task(<notmuch>)<CANCELLED>')
+ self.assertEqual(repr(t),
+ 'Task(<notmuch done at %s>)<CANCELLED>' % filename)
+
t = asyncio.Task(notmuch(), loop=self.loop)
self.loop.run_until_complete(t)
- self.assertEqual(repr(t), "Task(<notmuch>)<result='abc'>")
+ self.assertEqual(repr(t),
+ "Task(<notmuch done at %s>)<result='abc'>" % filename)
def test_task_repr_custom(self):
@asyncio.coroutine
- def coro():
+ def notmuch():
pass
class T(asyncio.Future):
def __repr__(self):
return super().__repr__()
- gen = coro()
+ gen = notmuch()
t = MyTask(gen, loop=self.loop)
- self.assertEqual(repr(t), 'T[](<coro>)')
- gen.close()
+ filename = gen.gi_code.co_filename
+ lineno = gen.gi_frame.f_lineno
+ # FIXME: check for the name "coro" instead of "notmuch" because
+ # @asyncio.coroutine drops the name of the wrapped function:
+ # http://bugs.python.org/issue21205
+ self.assertEqual(repr(t), 'T[](<coro at %s:%s>)' % (filename, lineno))
def test_task_basics(self):
@asyncio.coroutine