def test_copy_class(): from xoutil import Unset from xoutil.eight import _py3 from xoutil.eight.meta import metaclass from xoutil.objects import copy_class u = str if _py3 else unicode class MetaFoo(type): pass class Foo(metaclass(MetaFoo)): a = 1 b = 2 c = 3 d = 4 class Baz(Foo): e = 5 index = {k: getattr(Foo, k) for k in 'abcd'} Bar = copy_class(Foo) assert Bar.a == Foo.a and Bar.b and Bar.c and Bar.d Egg = copy_class(Foo, ignores=['b', 'c']) assert getattr(Egg, 'b', Unset) is Unset Egg = copy_class(Foo, ignores=[lambda k: index.get(k) and index.get(k) > 2]) assert Egg.a == Foo.a assert getattr(Egg, 'c', Unset) is Unset Named = copy_class(Foo, new_name='Named') assert Named.__name__ == 'Named' Named = copy_class(Foo, new_name=u('Named')) assert Named.__name__ == 'Named' import fnmatch pattern = lambda attr: fnmatch.fnmatch(attr, 'a*') Egg = copy_class(Foo, ignores=[pattern]) assert getattr(Egg, 'a', Unset) is Unset import re _pattern = re.compile('^a') pattern = lambda attr: _pattern.match(attr) Egg = copy_class(Foo, ignores=[pattern]) assert getattr(Egg, 'a', Unset) is Unset
def thesefy(target): '''Allow an object to participate in queries. Example as a wrapper:: class People(object): # ... pass query = (who for who in thesefy(People)) Example as a decorator:: @thesefy class People(object): pass query = (who for who in People) If your classes already support the iterable protocol (i.e implement ``__iter__``) this does nothing. ''' if getattr(target, '__iter__', None): return target class new_meta(type(target)): def __iter__(self): return (x for x in this if isinstance(x, self)) def next(self): raise StopIteration __next__ = next from xoutil.objects import copy_class new_class = copy_class(target, meta=new_meta) return new_class
def thesefy(target, make_subquery=True): '''Allow an object to participate in queries. Example as a wrapper:: class People: # ... pass query = (who for who in thesefy(People)) Example as a decorator:: @thesefy class People: pass query = (who for who in People) If `target` already support the iterable protocol (i.e implement ``__iter__``), return it unchanged. If `make_subquery` is True, then the query shown above will be equivalent to:: query = (who for who in (x for x in this if isinstance(x, People))) If `make_subquery` is False, `thesefy` injects an ``__iter__()`` that simply returns the same object and a ``next()`` method that immediately stops the iteration. Notice that in order to use `make_subquery` you call `thesefy`:func: as a decorator-returning function:: class Person: pass query = (x for x in thesefy(make_subquery=False)(Person)) # or simply as a decorator @thesefy(make_subquery=False) class Person: pass ''' if getattr(target, '__iter__', None): return target class new_meta(type(target)): if make_subquery: def __iter__(self): return (x for x in this if isinstance(x, self)) else: def __iter__(self): return self def next(self): raise StopIteration __next__ = next from xoutil.objects import copy_class new_class = copy_class(target, meta=new_meta) return new_class