coro.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # coroutine convenience functions
  2. from BTL.reactor_magic import reactor
  3. from BTL.yielddefer import launch_coroutine
  4. from BTL.defer import wrap_task, Deferred
  5. def coro(f, *args, **kwargs):
  6. return launch_coroutine(wrap_task(reactor.callLater), f, *args, **kwargs)
  7. def coroutine(_f):
  8. """Use the following as a decorator. Ex:
  9. @coroutine
  10. def mycoro():
  11. ...
  12. yield df
  13. df.getResult()
  14. ...
  15. df = mycoro()
  16. ...
  17. Unlike the coroutine decorator in greenlet_yielddefer, this works without
  18. greenlets. This is also typically cleaner than using coro().
  19. """
  20. def replacement(*a, **kw):
  21. return launch_coroutine(wrap_task(reactor.callLater), _f, *a, **kw)
  22. return replacement
  23. def wait(n):
  24. df = Deferred()
  25. reactor.callLater(n, df.callback, 0)
  26. return df
  27. @coroutine
  28. def init_yield(clss, *args, **kwargs):
  29. """Instantiate an object of type clss and then call its asynchronous initializer
  30. (__dfinit__). The __dfinit__ returns a Deferred. When the deferred's callback is called
  31. execution resumes at init_yield and the fully initialized object is returned."""
  32. kwargs['__magic_init_yield'] = True
  33. obj = clss(*args, **kwargs) # synchronous initialization.
  34. df = obj.__dfinit__() # asynchronous (deferred) initialization.
  35. yield df
  36. df.getResult()
  37. yield obj
  38. def use_init_yield( init ):
  39. """Use this as a decorator to any class's __init__ to require that
  40. class be initialized using init_yield. This guarantees that the
  41. asynchronous initializer __dfinit__ gets called. Ex:
  42. class Foo(object):
  43. @use_init_yield
  44. def __init__( self, a, b, c):
  45. ...
  46. some_synchronous_initialization()
  47. ...
  48. def __dfinit__( self ):
  49. ...
  50. df = some_initialization()
  51. return df
  52. ...
  53. Now to instantiate an object of type Foo, we use init_yield:
  54. df = init_yield(Foo,a,b,c)
  55. yield df
  56. foo = df.getResult()
  57. If we try to instantiate Foo directly, we get an exception:
  58. foo = Foo(a,b,c) # causes an AssertionException.
  59. """
  60. def look_for_magic( *a, **kw ):
  61. assert '__magic_init_yield' in kw, "Instantiate using init_yield"
  62. del kw['__magic_init_yield']
  63. init(*a, **kw) # __init__ returns nothing.
  64. return look_for_magic