def test_safe_string(): from xoutil.string import safe_str from xoutil.eight import _py2 aux = lambda x: 2*x + 1 name = 'λ x: 2*x + 1' aux.__name__ = safe_str(name) delta = 1 if _py2 else 0 assert len(aux.__name__) == len(name) + delta
def wrapper(target): if isinstance(target, decorables): if isinstance(target, (staticmethod, classmethod)): target = target.__func__ for name in (mod_key, name_key, doc_key): if name in source: value = source.pop(name) if name in safes: value = safe_str(value) setattr(target, str(name), value) d = source.pop('__dict__', Unset) if d: target.__dict__.update(d) for key, value in iteritems(source): setattr(target, key, value) return target else: from xoutil.eight import typeof msg = 'Only decorate functions, not {}' raise TypeError(msg.format(typeof(target).__name__))
def copy_class(cls, meta=None, ignores=None, new_attrs=None, new_name=None): '''Copies a class definition to a new class. The returned class will have the same name, bases and module of `cls`. :param meta: If None, the `type(cls)` of the class is used to build the new class, otherwise this must be a *proper* metaclass. :param ignores: A sequence of attributes names that should not be copied to the new class. An item may be callable accepting a single argument `attr` that must return a non-null value if the the `attr` should be ignored. :param new_attrs: New attributes the class must have. These will take precedence over the attributes in the original class. :type new_attrs: dict :param new_name: The name for the copy. If not provided the name will copied. .. versionadded:: 1.4.0 .. versionchanged:: 1.7.1 The `ignores` argument must an iterable of strings or callables. Removed the glob-pattern and regular expressions as possible values. They are all possible via the callable variant. .. versionadded:: 1.7.1 The `new_name` argument. ''' from xoutil.eight import iteritems, callable from xoutil.eight._types import new_class from xoutil.eight.types import MemberDescriptorType from xoutil.string import safe_str def _get_ignored(what): if callable(what): return what else: return lambda s: s == what if not meta: meta = type(cls) if ignores: ignores = tuple(_get_ignored(i) for i in ignores) ignored = lambda name: any(ignore(name) for ignore in ignores) else: ignored = None valids = ('__class__', '__mro__', '__name__', '__weakref__', '__dict__') attrs = {name: value for name, value in iteritems(cls.__dict__) if name not in valids # Must remove member descriptors, otherwise the old's class # descriptor will override those that must be created here. if not isinstance(value, MemberDescriptorType) if ignored is None or not ignored(name)} if new_attrs: attrs.update(new_attrs) exec_body = lambda ns: ns.update(attrs) if new_name: name = safe_str(new_name) else: name = cls.__name__ result = new_class(name, cls.__bases__, {'metaclass': meta}, exec_body) return result