util.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. """Miscellaneous utility functions and classes.
  2. This module is used internally by Tornado. It is not necessarily expected
  3. that the functions and classes defined here will be useful to other
  4. applications, but they are documented here in case they are.
  5. The one public-facing part of this module is the `Configurable` class
  6. and its `~Configurable.configure` method, which becomes a part of the
  7. interface of its subclasses, including `.AsyncHTTPClient`, `.IOLoop`,
  8. and `.Resolver`.
  9. """
  10. from __future__ import absolute_import, division, print_function, with_statement
  11. import sys
  12. # Fake unicode literal support: Python 3.2 doesn't have the u'' marker for
  13. # literal strings, and alternative solutions like "from __future__ import
  14. # unicode_literals" have other problems (see PEP 414). u() can be applied
  15. # to ascii strings that include \u escapes (but they must not contain
  16. # literal non-ascii characters).
  17. if not isinstance(b'', type('')):
  18. def u(s):
  19. return s
  20. unicode_type = str
  21. basestring_type = str
  22. else:
  23. def u(s):
  24. return s.decode('unicode_escape')
  25. # These names don't exist in py3, so use noqa comments to disable
  26. # warnings in flake8.
  27. unicode_type = unicode # noqa
  28. basestring_type = basestring # noqa
  29. def import_object(name):
  30. """Imports an object by name.
  31. import_object('x') is equivalent to 'import x'.
  32. import_object('x.y.z') is equivalent to 'from x.y import z'.
  33. >>> import tornado.escape
  34. >>> import_object('tornado.escape') is tornado.escape
  35. True
  36. >>> import_object('tornado.escape.utf8') is tornado.escape.utf8
  37. True
  38. >>> import_object('tornado') is tornado
  39. True
  40. >>> import_object('tornado.missing_module')
  41. Traceback (most recent call last):
  42. ...
  43. ImportError: No module named missing_module
  44. """
  45. if isinstance(name, unicode_type) and str is not unicode_type:
  46. # On python 2 a byte string is required.
  47. name = name.encode('utf-8')
  48. if name.count('.') == 0:
  49. return __import__(name, None, None)
  50. parts = name.split('.')
  51. obj = __import__('.'.join(parts[:-1]), None, None, [parts[-1]], 0)
  52. try:
  53. return getattr(obj, parts[-1])
  54. except AttributeError:
  55. raise ImportError("No module named %s" % parts[-1])
  56. # Deprecated alias that was used before we dropped py25 support.
  57. # Left here in case anyone outside Tornado is using it.
  58. bytes_type = bytes
  59. if sys.version_info > (3,):
  60. exec("""
  61. def raise_exc_info(exc_info):
  62. raise exc_info[1].with_traceback(exc_info[2])
  63. def exec_in(code, glob, loc=None):
  64. if isinstance(code, str):
  65. code = compile(code, '<string>', 'exec', dont_inherit=True)
  66. exec(code, glob, loc)
  67. """)
  68. else:
  69. exec("""
  70. def raise_exc_info(exc_info):
  71. raise exc_info[0], exc_info[1], exc_info[2]
  72. def exec_in(code, glob, loc=None):
  73. if isinstance(code, basestring):
  74. # exec(string) inherits the caller's future imports; compile
  75. # the string first to prevent that.
  76. code = compile(code, '<string>', 'exec', dont_inherit=True)
  77. exec code in glob, loc
  78. """)
  79. def errno_from_exception(e):
  80. """Provides the errno from an Exception object.
  81. There are cases that the errno attribute was not set so we pull
  82. the errno out of the args but if someone instantiates an Exception
  83. without any args you will get a tuple error. So this function
  84. abstracts all that behavior to give you a safe way to get the
  85. errno.
  86. """
  87. if hasattr(e, 'errno'):
  88. return e.errno
  89. elif e.args:
  90. return e.args[0]
  91. else:
  92. return None
  93. class Configurable(object):
  94. """Base class for configurable interfaces.
  95. A configurable interface is an (abstract) class whose constructor
  96. acts as a factory function for one of its implementation subclasses.
  97. The implementation subclass as well as optional keyword arguments to
  98. its initializer can be set globally at runtime with `configure`.
  99. By using the constructor as the factory method, the interface
  100. looks like a normal class, `isinstance` works as usual, etc. This
  101. pattern is most useful when the choice of implementation is likely
  102. to be a global decision (e.g. when `~select.epoll` is available,
  103. always use it instead of `~select.select`), or when a
  104. previously-monolithic class has been split into specialized
  105. subclasses.
  106. Configurable subclasses must define the class methods
  107. `configurable_base` and `configurable_default`, and use the instance
  108. method `initialize` instead of ``__init__``.
  109. """
  110. __impl_class = None
  111. __impl_kwargs = None
  112. def __new__(cls, *args, **kwargs):
  113. base = cls.configurable_base()
  114. init_kwargs = {}
  115. if cls is base:
  116. impl = cls.configured_class()
  117. if base.__impl_kwargs:
  118. init_kwargs.update(base.__impl_kwargs)
  119. else:
  120. impl = cls
  121. init_kwargs.update(kwargs)
  122. instance = super(Configurable, cls).__new__(impl)
  123. # initialize vs __init__ chosen for compatibility with AsyncHTTPClient
  124. # singleton magic. If we get rid of that we can switch to __init__
  125. # here too.
  126. instance.initialize(*args, **init_kwargs)
  127. return instance
  128. @classmethod
  129. def configurable_base(cls):
  130. """Returns the base class of a configurable hierarchy.
  131. This will normally return the class in which it is defined.
  132. (which is *not* necessarily the same as the cls classmethod parameter).
  133. """
  134. raise NotImplementedError()
  135. @classmethod
  136. def configurable_default(cls):
  137. """Returns the implementation class to be used if none is configured."""
  138. raise NotImplementedError()
  139. def initialize(self):
  140. """Initialize a `Configurable` subclass instance.
  141. Configurable classes should use `initialize` instead of ``__init__``.
  142. .. versionchanged:: 4.2
  143. Now accepts positional arguments in addition to keyword arguments.
  144. """
  145. @classmethod
  146. def configure(cls, impl, **kwargs):
  147. """Sets the class to use when the base class is instantiated.
  148. Keyword arguments will be saved and added to the arguments passed
  149. to the constructor. This can be used to set global defaults for
  150. some parameters.
  151. """
  152. base = cls.configurable_base()
  153. if isinstance(impl, (unicode_type, bytes)):
  154. impl = import_object(impl)
  155. if impl is not None and not issubclass(impl, cls):
  156. raise ValueError("Invalid subclass of %s" % cls)
  157. base.__impl_class = impl
  158. base.__impl_kwargs = kwargs
  159. @classmethod
  160. def configured_class(cls):
  161. """Returns the currently configured class."""
  162. base = cls.configurable_base()
  163. if cls.__impl_class is None:
  164. base.__impl_class = cls.configurable_default()
  165. return base.__impl_class
  166. @classmethod
  167. def _save_configuration(cls):
  168. base = cls.configurable_base()
  169. return (base.__impl_class, base.__impl_kwargs)
  170. @classmethod
  171. def _restore_configuration(cls, saved):
  172. base = cls.configurable_base()
  173. base.__impl_class = saved[0]
  174. base.__impl_kwargs = saved[1]
  175. def timedelta_to_seconds(td):
  176. """Equivalent to td.total_seconds() (introduced in python 2.7)."""
  177. return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / float(10 ** 6)