Source code for tornado.util

"""Miscellaneous utility functions and classes.This module is used internally by Tornado. It is not necessarily expectedthat the functions and classes defined here will be useful to otherapplications, but they are documented here in case they are.The one public-facing part of this module is the `Configurable` classand its `~Configurable.configure` method, which becomes a part of theinterface of its subclasses, including `.AsyncHTTPClient`, `.IOLoop`,and `.Resolver`."""from__future__importabsolute_import,division,print_function,with_statementimportarrayimportatexitimportosimportreimportsysimportzlibPY3=sys.version_info>=(3,)ifPY3:xrange=range# inspect.getargspec() raises DeprecationWarnings in Python 3.5.# The two functions have compatible interfaces for the parts we need.ifPY3:frominspectimportgetfullargspecasgetargspecelse:frominspectimportgetargspec# Aliases for types that are spelled differently in different Python# versions. bytes_type is deprecated and no longer used in Tornado# itself but is left in case anyone outside Tornado is using it.bytes_type=bytesifPY3:unicode_type=strbasestring_type=strelse:# The names unicode and basestring don't exist in py3 so silence flake8.unicode_type=unicode# noqabasestring_type=basestring# noqatry:importtyping# noqafromtypingimportcast_ObjectDictBase=typing.Dict[str,typing.Any]exceptImportError:_ObjectDictBase=dictdefcast(typ,x):returnxelse:# More imports that are only needed in type comments.importdatetime# noqaimporttypes# noqafromtypingimportAny,AnyStr,Union,Optional,Dict,Mapping# noqafromtypingimportTuple,Match,Callable# noqaifPY3:_BaseString=strelse:_BaseString=Union[bytes,unicode_type]try:fromsysimportis_finalizingexceptImportError:# Emulate itdef_get_emulated_is_finalizing():L=[]atexit.register(lambda:L.append(None))defis_finalizing():# Not referencing any globals herereturnL!=[]returnis_finalizingis_finalizing=_get_emulated_is_finalizing()

[docs]classGzipDecompressor(object):"""Streaming gzip decompressor. The interface is like that of `zlib.decompressobj` (without some of the optional arguments, but it understands gzip headers and checksums. """def__init__(self):# Magic parameter makes zlib module understand gzip header# http://stackoverflow.com/questions/1838699/how-can-i-decompress-a-gzip-stream-with-zlib# This works on cpython and pypy, but not jython.self.decompressobj=zlib.decompressobj(16+zlib.MAX_WBITS)

[docs]defdecompress(self,value,max_length=None):# type: (bytes, Optional[int]) -> bytes"""Decompress a chunk, returning newly-available data. Some data may be buffered for later processing; `flush` must be called when there is no more input data to ensure that all data was processed. If ``max_length`` is given, some input data may be left over in ``unconsumed_tail``; you must retrieve this value and pass it back to a future call to `decompress` if it is not empty. """returnself.decompressobj.decompress(value,max_length)

[docs]defflush(self):# type: () -> bytes"""Return any remaining buffered data not yet returned by decompress. Also checks for errors such as truncated input. No other methods may be called on this object after `flush`. """returnself.decompressobj.flush()

[docs]deferrno_from_exception(e):# type: (BaseException) -> Optional[int]"""Provides the errno from an Exception object. There are cases that the errno attribute was not set so we pull the errno out of the args but if someone instantiates an Exception without any args you will get a tuple error. So this function abstracts all that behavior to give you a safe way to get the errno. """ifhasattr(e,'errno'):returne.errno# type: ignoreelife.args:returne.args[0]else:returnNone

[docs]defre_unescape(s):# type: (str) -> str"""Unescape a string escaped by `re.escape`. May raise ``ValueError`` for regular expressions which could not have been produced by `re.escape` (for example, strings containing ``\d`` cannot be unescaped). .. versionadded:: 4.4 """return_re_unescape_pattern.sub(_re_unescape_replacement,s)

[docs]classConfigurable(object):"""Base class for configurable interfaces. A configurable interface is an (abstract) class whose constructor acts as a factory function for one of its implementation subclasses. The implementation subclass as well as optional keyword arguments to its initializer can be set globally at runtime with `configure`. By using the constructor as the factory method, the interface looks like a normal class, `isinstance` works as usual, etc. This pattern is most useful when the choice of implementation is likely to be a global decision (e.g. when `~select.epoll` is available, always use it instead of `~select.select`), or when a previously-monolithic class has been split into specialized subclasses. Configurable subclasses must define the class methods `configurable_base` and `configurable_default`, and use the instance method `initialize` instead of ``__init__``. """__impl_class=None# type: type__impl_kwargs=None# type: Dict[str, Any]def__new__(cls,*args,**kwargs):base=cls.configurable_base()init_kwargs={}ifclsisbase:impl=cls.configured_class()ifbase.__impl_kwargs:init_kwargs.update(base.__impl_kwargs)else:impl=clsinit_kwargs.update(kwargs)instance=super(Configurable,cls).__new__(impl)# initialize vs __init__ chosen for compatibility with AsyncHTTPClient# singleton magic. If we get rid of that we can switch to __init__# here too.instance.initialize(*args,**init_kwargs)returninstance@classmethod

[docs]defconfigurable_base(cls):# type: () -> Any# TODO: This class needs https://github.com/python/typing/issues/107# to be fully typeable."""Returns the base class of a configurable hierarchy. This will normally return the class in which it is defined. (which is *not* necessarily the same as the cls classmethod parameter). """raiseNotImplementedError()

@classmethod

[docs]defconfigurable_default(cls):# type: () -> type"""Returns the implementation class to be used if none is configured."""raiseNotImplementedError()

[docs]defconfigure(cls,impl,**kwargs):# type: (Any, **Any) -> None"""Sets the class to use when the base class is instantiated. Keyword arguments will be saved and added to the arguments passed to the constructor. This can be used to set global defaults for some parameters. """base=cls.configurable_base()ifisinstance(impl,(str,unicode_type)):impl=import_object(impl)ifimplisnotNoneandnotissubclass(impl,cls):raiseValueError("Invalid subclass of %s"%cls)base.__impl_class=implbase.__impl_kwargs=kwargs

[docs]classArgReplacer(object):"""Replaces one value in an ``args, kwargs`` pair. Inspects the function signature to find an argument by name whether it is passed by position or keyword. For use in decorators and similar wrappers. """def__init__(self,func,name):# type: (Callable, str) -> Noneself.name=nametry:self.arg_pos=self._getargnames(func).index(name)exceptValueError:# Not a positional parameterself.arg_pos=Nonedef_getargnames(self,func):# type: (Callable) -> List[str]try:returngetargspec(func).argsexceptTypeError:ifhasattr(func,'func_code'):# Cython-generated code has all the attributes needed# by inspect.getargspec, but the inspect module only# works with ordinary functions. Inline the portion of# getargspec that we need here. Note that for static# functions the @cython.binding(True) decorator must# be used (for methods it works out of the box).code=func.func_code# type: ignorereturncode.co_varnames[:code.co_argcount]raise

[docs]defget_old_value(self,args,kwargs,default=None):# type: (List[Any], Dict[str, Any], Any) -> Any"""Returns the old value of the named argument without replacing it. Returns ``default`` if the argument is not present. """ifself.arg_posisnotNoneandlen(args)>self.arg_pos:returnargs[self.arg_pos]else:returnkwargs.get(self.name,default)

[docs]defreplace(self,new_value,args,kwargs):# type: (Any, List[Any], Dict[str, Any]) -> Tuple[Any, List[Any], Dict[str, Any]]"""Replace the named argument in ``args, kwargs`` with ``new_value``. Returns ``(old_value, args, kwargs)``. The returned ``args`` and ``kwargs`` objects may not be the same as the input objects, or the input objects may be mutated. If the named argument was not found, ``new_value`` will be added to ``kwargs`` and None will be returned as ``old_value``. """ifself.arg_posisnotNoneandlen(args)>self.arg_pos:# The arg to replace is passed positionallyold_value=args[self.arg_pos]args=list(args)# *args is normally a tupleargs[self.arg_pos]=new_valueelse:# The arg to replace is either omitted or passed by keyword.old_value=kwargs.get(self.name)kwargs[self.name]=new_valuereturnold_value,args,kwargs

def_websocket_mask_python(mask,data):# type: (bytes, bytes) -> bytes"""Websocket masking function. `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length. Returns a `bytes` object of the same length as `data` with the mask applied as specified in section 5.3 of RFC 6455. This pure-python implementation may be replaced by an optimized version when available. """mask_arr=array.array("B",mask)unmasked_arr=array.array("B",data)foriinxrange(len(data)):unmasked_arr[i]=unmasked_arr[i]^mask_arr[i%4]ifPY3:# tostring was deprecated in py32. It hasn't been removed,# but since we turn on deprecation warnings in our tests# we need to use the right one.returnunmasked_arr.tobytes()else:returnunmasked_arr.tostring()if(os.environ.get('TORNADO_NO_EXTENSION')oros.environ.get('TORNADO_EXTENSION')=='0'):# These environment variables exist to make it easier to do performance# comparisons; they are not guaranteed to remain supported in the future._websocket_mask=_websocket_mask_pythonelse:try:fromtornado.speedupsimportwebsocket_maskas_websocket_maskexceptImportError:ifos.environ.get('TORNADO_EXTENSION')=='1':raise_websocket_mask=_websocket_mask_pythondefdoctests():importdoctestreturndoctest.DocTestSuite()