/_unsorted/_core_new/_util/wrapper.py
Python | 213 lines | 179 code | 21 blank | 13 comment | 15 complexity | 66695de9517863865491eeb5a0e6c2f3 MD5 | raw file
Possible License(s): BSD-3-Clause
- """wrapper module
- """
- __all__ = (
- "wrapper", "wrap",
- "WrapperMeta", "Wrapper",
- "WrapperAttribute", "PassHandler",
- "MissingInstanceError", "MissingHandlerError",
- )
- from error import Error
- #################################################
- # sequence wrapper
- MAX_ITERATIONS = 2**15 # 32768
-
- class MaxIterationError(RuntimeError):
- def __init__(self, max=MAX_ITERATIONS, *args, **kwargs):
- #def __init__(self, max=MAX_ITERATIONS, *args, msg=None):
- kwargs, msg = emulate_kwonly(kwargs, (), (("msg", None),))
-
- if msg is None:
- msg = "maximum iterations reached (%s)" % max
- super(type(self), self).__init__(msg, *args)
- class SequenceWrapper(object):
- """A Sequence object that exposes the iterable as a sequence."""
- def __new__(cls, iterable, maxiter=MAX_ITERATIONS)
- if isinstance(iterable, Sequence):
- return iterable
- return super(cls, cls).__new__(cls)
- def __init__(self, iterable, maxiter=MAX_ITERATIONS):
- self.iterable = iterable
- self.maxiter = maxiter
- self._tracking = []
- def __getattr__(self, name):
- return getattr(self.iterable, name)
- def __iter__(self):
- if self.iterable is self._tracking:
- return iter(self.iterable)
- iterable = self._tracking
- for item in iterable:
- yield item
- # now get back to where we left off
- maxiter = self.maxiter
- count = 0
- for item in self.iterable: # iterator?
- if count >= maxiter:
- raise MaxIterationError(maxiter)
- yield item
- iterable.append(item)
- count += 1
- self.iterable =
- self._fixed = True
- def __len__(self):
- if hasattr(self.iterable, "__len__"):
- return len(self.iterable)
- return len(tuple(self.iterable))
- def __getitem__(self, index):
- if hasattr(self.iterable, "__getitem__"):
- return self.iterable[index]
- index -= 1
- count = 0
- for value in self.iterable:
- if count == index:
- return value
- count += 1
- raise IndexError
- def __contains__(self, value):
- ...
- def as_sequence(iterable, maxiter=MAX_ITERATIONS):
- return SequenceWrapper(iterable, maxiter)
- #################################################
- # generic wrapper class
- class MissingInstanceError(Error):
- MSG = "_WRAP_INSTANCE not set on class"
- class MissingHandlerError(Error):
- MSG = "expected a handler, found None"
- class WrapperAttribute(object):
- def __init__(self, name):
- self.name = name
- def _handler(self, cls):
- handler = cls._WRAP_HANDLERS.get(self.name)
- if handler is None:
- handler = cls._WRAP_DEFAULT_HANDLER
- if handler is None:
- raise MissingHandlerError(self.name)
- return handler(self.name)
- def __get__(self, obj, cls):
- if cls._WRAP_INSTANCE is None:
- raise MissingInstanceError(self.name)
- return self._handler(cls).__get__(obj, cls)
- #return getattr(cls._WRAP_INSTANCE, self.name)
- def __set__(self, obj, value):
- self._handler(type(obj)).__set__(obj, value)
- def __del__(self, obj):
- raise NotImplementedError
- class PassHandler(WrapperAttribute):
- def __get__(self, obj, cls):
- return getattr(cls._WRAP_INSTANCE, name)
- def __set__(self, obj, value):
- setattr(cls._WRAP_INSTANCE, name, value)
- def __del__(self, obj, cls):
- delattr(cls._WRAP_INSTANCE, name)
- class WrapperMeta(type):
- """The metaclass for the base wrapper class.
- >>> NewWrapper = WrapperMeta("NewWrapper", (list,), {})
- >>> NewWrapper = Wrapper.from_base(list, {})
- >>> class NewWrapper(list):
- ... __metaclass__ = WrapperMeta
- ...
- >>> class NewWrapper(list):
- ... __metaclass__ = WrapperMeta
- ... DEFAULT_HANDLER = PassHandler()
- ... __getitem__ = AnotherHandler()
- ...
- >>> class NewWrapper(Wrapper, list):
- ... DEFAULT_HANDLER = PassHandler()
- ... __getitem__ = AnotherHandler()
- ...
- >>> obj = NewWrapper([1,2,3,4,5])
- >>> obj = NewWrapper.from_instance([1,2,3,4,5])
- >>>
- >>> spam = [1,2,3,4,5]
- >>> spam = Wrapper.from_base(type(spam), {}).from_instance(spam)
- """
- def __new__(meta, name, bases, namespace):
- for base in bases:
- if not isinstance(base, meta):
- break
- default = namespace.pop("DEFAULT_HANDLER", None)
- handlers = namespace.pop("HANDLERS", {})
- handlers.update(namespace)
- return meta.from_base(base, handlers, default)
- @classmethod
- def from_base(meta, base, handlers, default=None):
- name = "%sWrapper" % base.__name__.capitalize()
- cls = type.__new__(meta, name, (base,), {})
- cls._WRAP_BASE = base
- cls._WRAP_HANDLERS = handlers
- cls._WRAP_DEFAULT = default
- cls._WRAP_INSTANCE = None
- for name in handlers:
- setattr(cls, name, WrapperAttribute(name))
- return cls
- def __call__(cls, *args, **kwargs):
- original = cls._WRAP_BASE(*args, **kwargs)
- return cls.from_instance(original)
- def from_instance(cls, original):
- subclass = type.__new__(type(cls), cls.__name__, (cls,), {})
- subclass._WRAP_INSTANCE = original
- obj = subclass.__new__(subclass)
- return obj
- class Wrapper(object):
- __metaclass__ = WrapperMeta
- DEFAULT_HANDLER = PassHandler
- wrapper = Wrapper.from_base
-
- def wrap(obj, names=None, attrmap=None, defaulthandler=None):
- """create an instance of a new wrapper class for this obj."""
- if names is not None and not names and not attrmap:
- raise TypeError("expected either names or attrmap")
- if attrmap is None:
- attrmap = {}
- for key, value in attrmap.items():
- if value is None:
- attrmap[key] = default_handler
- if names is None:
- names = set(dir(obj)) - set(attrmap)
- for name in names:
- if name in attrmap:
- raise TypeError("name collision between names and attrmap")
- attrmap[name] = default_handler
- try:
- cls = wrapper(type(obj), attrmap)
- except MissingHandlerError:
- if default_handler is None:
- raise TypeError("expected default_handler to be passed")
- else:
- raise
- # register abstract base classes too?
- return cls.from_instance(obj)
-