Format: text/x-python
⬇ Download File (2.6 KB)
   1  """ A universal module with functions / classes without dependencies. """
   2  import functools
   3  import re
   4  import os
   5  
   6  
   7  _sep = os.path.sep
   8  if os.path.altsep is not None:
   9      _sep += os.path.altsep
  10  _path_re = re.compile(r'(?:\.[^{0}]+|[{0}]__init__\.py)$'.format(re.escape(_sep)))
  11  del _sep
  12  
  13  
  14  def to_list(func):
  15      def wrapper(*args, **kwargs):
  16          return list(func(*args, **kwargs))
  17      return wrapper
  18  
  19  
  20  def to_tuple(func):
  21      def wrapper(*args, **kwargs):
  22          return tuple(func(*args, **kwargs))
  23      return wrapper
  24  
  25  
  26  def unite(iterable):
  27      """Turns a two dimensional array into a one dimensional."""
  28      return set(typ for types in iterable for typ in types)
  29  
  30  
  31  class UncaughtAttributeError(Exception):
  32      """
  33      Important, because `__getattr__` and `hasattr` catch AttributeErrors
  34      implicitly. This is really evil (mainly because of `__getattr__`).
  35      Therefore this class originally had to be derived from `BaseException`
  36      instead of `Exception`.  But because I removed relevant `hasattr` from
  37      the code base, we can now switch back to `Exception`.
  38  
  39      :param base: return values of sys.exc_info().
  40      """
  41  
  42  
  43  def safe_property(func):
  44      return property(reraise_uncaught(func))
  45  
  46  
  47  def reraise_uncaught(func):
  48      """
  49      Re-throw uncaught `AttributeError`.
  50  
  51      Usage:  Put ``@rethrow_uncaught`` in front of the function
  52      which does **not** suppose to raise `AttributeError`.
  53  
  54      AttributeError is easily get caught by `hasattr` and another
  55      ``except AttributeError`` clause.  This becomes problem when you use
  56      a lot of "dynamic" attributes (e.g., using ``@property``) because you
  57      can't distinguish if the property does not exist for real or some code
  58      inside of the "dynamic" attribute through that error.  In a well
  59      written code, such error should not exist but getting there is very
  60      difficult.  This decorator is to help us getting there by changing
  61      `AttributeError` to `UncaughtAttributeError` to avoid unexpected catch.
  62      This helps us noticing bugs earlier and facilitates debugging.
  63      """
  64      @functools.wraps(func)
  65      def wrapper(*args, **kwds):
  66          try:
  67              return func(*args, **kwds)
  68          except AttributeError as e:
  69              raise UncaughtAttributeError(e) from e
  70      return wrapper
  71  
  72  
  73  class PushBackIterator:
  74      def __init__(self, iterator):
  75          self.pushes = []
  76          self.iterator = iterator
  77          self.current = None
  78  
  79      def push_back(self, value):
  80          self.pushes.append(value)
  81  
  82      def __iter__(self):
  83          return self
  84  
  85      def __next__(self):
  86          if self.pushes:
  87              self.current = self.pushes.pop()
  88          else:
  89              self.current = next(self.iterator)
  90          return self.current
  91