예제 #1
0
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
예제 #2
0
 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__))
예제 #3
0
파일: objects.py 프로젝트: olemis/xoutil
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