util.py
Go to the documentation of this file.
00001 """Miscellaneous utility functions and classes.
00002 
00003 This module is used internally by Tornado.  It is not necessarily expected
00004 that the functions and classes defined here will be useful to other
00005 applications, but they are documented here in case they are.
00006 
00007 The one public-facing part of this module is the `Configurable` class
00008 and its `~Configurable.configure` method, which becomes a part of the
00009 interface of its subclasses, including `.AsyncHTTPClient`, `.IOLoop`,
00010 and `.Resolver`.
00011 """
00012 
00013 from __future__ import absolute_import, division, print_function, with_statement
00014 
00015 import array
00016 import inspect
00017 import os
00018 import sys
00019 import zlib
00020 
00021 
00022 try:
00023     xrange  # py2
00024 except NameError:
00025     xrange = range  # py3
00026 
00027 
00028 class ObjectDict(dict):
00029     """Makes a dictionary behave like an object, with attribute-style access.
00030     """
00031     def __getattr__(self, name):
00032         try:
00033             return self[name]
00034         except KeyError:
00035             raise AttributeError(name)
00036 
00037     def __setattr__(self, name, value):
00038         self[name] = value
00039 
00040 
00041 class GzipDecompressor(object):
00042     """Streaming gzip decompressor.
00043 
00044     The interface is like that of `zlib.decompressobj` (without some of the
00045     optional arguments, but it understands gzip headers and checksums.
00046     """
00047     def __init__(self):
00048         # Magic parameter makes zlib module understand gzip header
00049         # http://stackoverflow.com/questions/1838699/how-can-i-decompress-a-gzip-stream-with-zlib
00050         # This works on cpython and pypy, but not jython.
00051         self.decompressobj = zlib.decompressobj(16 + zlib.MAX_WBITS)
00052 
00053     def decompress(self, value, max_length=None):
00054         """Decompress a chunk, returning newly-available data.
00055 
00056         Some data may be buffered for later processing; `flush` must
00057         be called when there is no more input data to ensure that
00058         all data was processed.
00059 
00060         If ``max_length`` is given, some input data may be left over
00061         in ``unconsumed_tail``; you must retrieve this value and pass
00062         it back to a future call to `decompress` if it is not empty.
00063         """
00064         return self.decompressobj.decompress(value, max_length)
00065 
00066     @property
00067     def unconsumed_tail(self):
00068         """Returns the unconsumed portion left over
00069         """
00070         return self.decompressobj.unconsumed_tail
00071 
00072     def flush(self):
00073         """Return any remaining buffered data not yet returned by decompress.
00074 
00075         Also checks for errors such as truncated input.
00076         No other methods may be called on this object after `flush`.
00077         """
00078         return self.decompressobj.flush()
00079 
00080 
00081 def import_object(name):
00082     """Imports an object by name.
00083 
00084     import_object('x') is equivalent to 'import x'.
00085     import_object('x.y.z') is equivalent to 'from x.y import z'.
00086 
00087     >>> import tornado.escape
00088     >>> import_object('tornado.escape') is tornado.escape
00089     True
00090     >>> import_object('tornado.escape.utf8') is tornado.escape.utf8
00091     True
00092     >>> import_object('tornado') is tornado
00093     True
00094     >>> import_object('tornado.missing_module')
00095     Traceback (most recent call last):
00096         ...
00097     ImportError: No module named missing_module
00098     """
00099     if name.count('.') == 0:
00100         return __import__(name, None, None)
00101 
00102     parts = name.split('.')
00103     obj = __import__('.'.join(parts[:-1]), None, None, [parts[-1]], 0)
00104     try:
00105         return getattr(obj, parts[-1])
00106     except AttributeError:
00107         raise ImportError("No module named %s" % parts[-1])
00108 
00109 
00110 # Fake unicode literal support:  Python 3.2 doesn't have the u'' marker for
00111 # literal strings, and alternative solutions like "from __future__ import
00112 # unicode_literals" have other problems (see PEP 414).  u() can be applied
00113 # to ascii strings that include \u escapes (but they must not contain
00114 # literal non-ascii characters).
00115 if type('') is not type(b''):
00116     def u(s):
00117         return s
00118     bytes_type = bytes
00119     unicode_type = str
00120     basestring_type = str
00121 else:
00122     def u(s):
00123         return s.decode('unicode_escape')
00124     bytes_type = str
00125     unicode_type = unicode
00126     basestring_type = basestring
00127 
00128 
00129 if sys.version_info > (3,):
00130     exec("""
00131 def raise_exc_info(exc_info):
00132     raise exc_info[1].with_traceback(exc_info[2])
00133 
00134 def exec_in(code, glob, loc=None):
00135     if isinstance(code, str):
00136         code = compile(code, '<string>', 'exec', dont_inherit=True)
00137     exec(code, glob, loc)
00138 """)
00139 else:
00140     exec("""
00141 def raise_exc_info(exc_info):
00142     raise exc_info[0], exc_info[1], exc_info[2]
00143 
00144 def exec_in(code, glob, loc=None):
00145     if isinstance(code, basestring):
00146         # exec(string) inherits the caller's future imports; compile
00147         # the string first to prevent that.
00148         code = compile(code, '<string>', 'exec', dont_inherit=True)
00149     exec code in glob, loc
00150 """)
00151 
00152 
00153 def errno_from_exception(e):
00154     """Provides the errno from an Exception object.
00155 
00156     There are cases that the errno attribute was not set so we pull
00157     the errno out of the args but if someone instatiates an Exception
00158     without any args you will get a tuple error. So this function
00159     abstracts all that behavior to give you a safe way to get the
00160     errno.
00161     """
00162 
00163     if hasattr(e, 'errno'):
00164         return e.errno
00165     elif e.args:
00166         return e.args[0]
00167     else:
00168         return None
00169 
00170 
00171 class Configurable(object):
00172     """Base class for configurable interfaces.
00173 
00174     A configurable interface is an (abstract) class whose constructor
00175     acts as a factory function for one of its implementation subclasses.
00176     The implementation subclass as well as optional keyword arguments to
00177     its initializer can be set globally at runtime with `configure`.
00178 
00179     By using the constructor as the factory method, the interface
00180     looks like a normal class, `isinstance` works as usual, etc.  This
00181     pattern is most useful when the choice of implementation is likely
00182     to be a global decision (e.g. when `~select.epoll` is available,
00183     always use it instead of `~select.select`), or when a
00184     previously-monolithic class has been split into specialized
00185     subclasses.
00186 
00187     Configurable subclasses must define the class methods
00188     `configurable_base` and `configurable_default`, and use the instance
00189     method `initialize` instead of ``__init__``.
00190     """
00191     __impl_class = None
00192     __impl_kwargs = None
00193 
00194     def __new__(cls, **kwargs):
00195         base = cls.configurable_base()
00196         args = {}
00197         if cls is base:
00198             impl = cls.configured_class()
00199             if base.__impl_kwargs:
00200                 args.update(base.__impl_kwargs)
00201         else:
00202             impl = cls
00203         args.update(kwargs)
00204         instance = super(Configurable, cls).__new__(impl)
00205         # initialize vs __init__ chosen for compatiblity with AsyncHTTPClient
00206         # singleton magic.  If we get rid of that we can switch to __init__
00207         # here too.
00208         instance.initialize(**args)
00209         return instance
00210 
00211     @classmethod
00212     def configurable_base(cls):
00213         """Returns the base class of a configurable hierarchy.
00214 
00215         This will normally return the class in which it is defined.
00216         (which is *not* necessarily the same as the cls classmethod parameter).
00217         """
00218         raise NotImplementedError()
00219 
00220     @classmethod
00221     def configurable_default(cls):
00222         """Returns the implementation class to be used if none is configured."""
00223         raise NotImplementedError()
00224 
00225     def initialize(self):
00226         """Initialize a `Configurable` subclass instance.
00227 
00228         Configurable classes should use `initialize` instead of ``__init__``.
00229         """
00230 
00231     @classmethod
00232     def configure(cls, impl, **kwargs):
00233         """Sets the class to use when the base class is instantiated.
00234 
00235         Keyword arguments will be saved and added to the arguments passed
00236         to the constructor.  This can be used to set global defaults for
00237         some parameters.
00238         """
00239         base = cls.configurable_base()
00240         if isinstance(impl, (unicode_type, bytes_type)):
00241             impl = import_object(impl)
00242         if impl is not None and not issubclass(impl, cls):
00243             raise ValueError("Invalid subclass of %s" % cls)
00244         base.__impl_class = impl
00245         base.__impl_kwargs = kwargs
00246 
00247     @classmethod
00248     def configured_class(cls):
00249         """Returns the currently configured class."""
00250         base = cls.configurable_base()
00251         if cls.__impl_class is None:
00252             base.__impl_class = cls.configurable_default()
00253         return base.__impl_class
00254 
00255     @classmethod
00256     def _save_configuration(cls):
00257         base = cls.configurable_base()
00258         return (base.__impl_class, base.__impl_kwargs)
00259 
00260     @classmethod
00261     def _restore_configuration(cls, saved):
00262         base = cls.configurable_base()
00263         base.__impl_class = saved[0]
00264         base.__impl_kwargs = saved[1]
00265 
00266 
00267 class ArgReplacer(object):
00268     """Replaces one value in an ``args, kwargs`` pair.
00269 
00270     Inspects the function signature to find an argument by name
00271     whether it is passed by position or keyword.  For use in decorators
00272     and similar wrappers.
00273     """
00274     def __init__(self, func, name):
00275         self.name = name
00276         try:
00277             self.arg_pos = inspect.getargspec(func).args.index(self.name)
00278         except ValueError:
00279             # Not a positional parameter
00280             self.arg_pos = None
00281 
00282     def get_old_value(self, args, kwargs, default=None):
00283         """Returns the old value of the named argument without replacing it.
00284 
00285         Returns ``default`` if the argument is not present.
00286         """
00287         if self.arg_pos is not None and len(args) > self.arg_pos:
00288             return args[self.arg_pos]
00289         else:
00290             return kwargs.get(self.name, default)
00291 
00292     def replace(self, new_value, args, kwargs):
00293         """Replace the named argument in ``args, kwargs`` with ``new_value``.
00294 
00295         Returns ``(old_value, args, kwargs)``.  The returned ``args`` and
00296         ``kwargs`` objects may not be the same as the input objects, or
00297         the input objects may be mutated.
00298 
00299         If the named argument was not found, ``new_value`` will be added
00300         to ``kwargs`` and None will be returned as ``old_value``.
00301         """
00302         if self.arg_pos is not None and len(args) > self.arg_pos:
00303             # The arg to replace is passed positionally
00304             old_value = args[self.arg_pos]
00305             args = list(args)  # *args is normally a tuple
00306             args[self.arg_pos] = new_value
00307         else:
00308             # The arg to replace is either omitted or passed by keyword.
00309             old_value = kwargs.get(self.name)
00310             kwargs[self.name] = new_value
00311         return old_value, args, kwargs
00312 
00313 
00314 def timedelta_to_seconds(td):
00315     """Equivalent to td.total_seconds() (introduced in python 2.7)."""
00316     return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / float(10 ** 6)
00317 
00318 
00319 def _websocket_mask_python(mask, data):
00320     """Websocket masking function.
00321 
00322     `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length.
00323     Returns a `bytes` object of the same length as `data` with the mask applied
00324     as specified in section 5.3 of RFC 6455.
00325 
00326     This pure-python implementation may be replaced by an optimized version when available.
00327     """
00328     mask = array.array("B", mask)
00329     unmasked = array.array("B", data)
00330     for i in xrange(len(data)):
00331         unmasked[i] = unmasked[i] ^ mask[i % 4]
00332     if hasattr(unmasked, 'tobytes'):
00333         # tostring was deprecated in py32.  It hasn't been removed,
00334         # but since we turn on deprecation warnings in our tests
00335         # we need to use the right one.
00336         return unmasked.tobytes()
00337     else:
00338         return unmasked.tostring()
00339 
00340 if (os.environ.get('TORNADO_NO_EXTENSION') or
00341     os.environ.get('TORNADO_EXTENSION') == '0'):
00342     # These environment variables exist to make it easier to do performance
00343     # comparisons; they are not guaranteed to remain supported in the future.
00344     _websocket_mask = _websocket_mask_python
00345 else:
00346     try:
00347         from tornado.speedups import websocket_mask as _websocket_mask
00348     except ImportError:
00349         if os.environ.get('TORNADO_EXTENSION') == '1':
00350             raise
00351         _websocket_mask = _websocket_mask_python
00352 
00353 
00354 def doctests():
00355     import doctest
00356     return doctest.DocTestSuite()


rosbridge_server
Author(s): Jonathan Mace
autogenerated on Thu Jun 6 2019 21:51:51