| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- """ A universal module with functions / classes without dependencies. """
- import functools
- import re
- import os
- _sep = os.path.sep
- if os.path.altsep is not None:
- _sep += os.path.altsep
- _path_re = re.compile(r'(?:\.[^{0}]+|[{0}]__init__\.py)$'.format(re.escape(_sep)))
- del _sep
- def to_list(func):
- def wrapper(*args, **kwargs):
- return list(func(*args, **kwargs))
- return wrapper
- def to_tuple(func):
- def wrapper(*args, **kwargs):
- return tuple(func(*args, **kwargs))
- return wrapper
- def unite(iterable):
- """Turns a two dimensional array into a one dimensional."""
- return set(typ for types in iterable for typ in types)
- class UncaughtAttributeError(Exception):
- """
- Important, because `__getattr__` and `hasattr` catch AttributeErrors
- implicitly. This is really evil (mainly because of `__getattr__`).
- Therefore this class originally had to be derived from `BaseException`
- instead of `Exception`. But because I removed relevant `hasattr` from
- the code base, we can now switch back to `Exception`.
- :param base: return values of sys.exc_info().
- """
- def safe_property(func):
- return property(reraise_uncaught(func))
- def reraise_uncaught(func):
- """
- Re-throw uncaught `AttributeError`.
- Usage: Put ``@rethrow_uncaught`` in front of the function
- which does **not** suppose to raise `AttributeError`.
- AttributeError is easily get caught by `hasattr` and another
- ``except AttributeError`` clause. This becomes problem when you use
- a lot of "dynamic" attributes (e.g., using ``@property``) because you
- can't distinguish if the property does not exist for real or some code
- inside of the "dynamic" attribute through that error. In a well
- written code, such error should not exist but getting there is very
- difficult. This decorator is to help us getting there by changing
- `AttributeError` to `UncaughtAttributeError` to avoid unexpected catch.
- This helps us noticing bugs earlier and facilitates debugging.
- """
- @functools.wraps(func)
- def wrapper(*args, **kwds):
- try:
- return func(*args, **kwds)
- except AttributeError as e:
- raise UncaughtAttributeError(e) from e
- return wrapper
- class PushBackIterator:
- def __init__(self, iterator):
- self.pushes = []
- self.iterator = iterator
- self.current = None
- def push_back(self, value):
- self.pushes.append(value)
- def __iter__(self):
- return self
- def __next__(self):
- if self.pushes:
- self.current = self.pushes.pop()
- else:
- self.current = next(self.iterator)
- return self.current
|