Beispiel #1
0
 def __get__(self, obj, owner):
     if obj is not None:
         from xoutil.inspect import get_attr_value
         res = get_attr_value(obj, self.inner_name, Unset)
         if res is not Unset:
             return res
         elif self.init is not Unset:
             try:
                 res = self.init()
             except:
                 print('>>>', self.init, '::', type(self.init))
                 raise
             self.__set__(obj, res)
             return res
         elif self.default is not Unset:
             res = self.default
             self.__set__(obj, res)
             return res
         else:
             from xoutil.eight import typeof
             msg = "'%s' object has no attribute '%s'"
             raise AttributeError(msg % (typeof(obj).__name__,
                                         self.attr_name))
     else:
         return self
Beispiel #2
0
 def repr1(self, x, level):
     from xoutil.eight import typeof
     typename = typeof(x).__name__
     if ' ' in typename:
         parts = typename.split()
         typename = '_'.join(parts)
     if hasattr(self, 'repr_' + typename):
         return getattr(self, 'repr_' + typename)(x, level)
     else:
         return self.repr_instance(x, level)
Beispiel #3
0
 def settle_str(name, value):
     if value is not Unset:
         if isinstance(value, string_types):
             if name not in source:
                 source[name] = value
             else:
                 repeated(name)
         else:
             from xoutil.eight import typeof
             msg = 'lwraps() expecting string for "{}", {} found'
             raise TypeError(msg.format(name, typeof(value).__name__))
Beispiel #4
0
 def __get__(self, instance, owner):
     if instance is None and owner is Command:
         if not self.cache:
             self._settle_cache(Command)
             assert self.cache.pop(command_name(Command), None) is None
         return self.cache
     else:
         if instance:
             from xoutil.eight import typeof
             obj = 'Instance %s of class %s' % (id(instance),
                                                typeof(instance).__name__)
         else:
             obj = 'Class %s' % owner.__name__
         msg = 'Only allowed in class "Command"; used invalidly from "%s"!'
         raise AttributeError(msg % obj)
Beispiel #5
0
def _check_base(base):
    '''Check a base to be used in string to integer conversions.

    Return a tuple (base, table) if valid or raise an exception.

    '''
    from xoutil.eight import integer_types
    if isinstance(base, integer_types):
        table = _DEFAULT_TABLE
        if not (1 < base <= _MAX_BASE):
            raise ValueError('`base` must be between 2 and %s' % _MAX_BASE)
    elif isinstance(base, _strs):
        table = base
        base = len(table)
    else:
        from xoutil.eight import typeof
        msg = ('`base` must be an integer (base) or a string (table) with '
               'length greater or equal to 2; %s "%s" given')
        raise TypeError(msg % (typeof(base).__name__, base))
    return base, table
Beispiel #6
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__))
Beispiel #7
0
def get_attr_value(obj, name, *default):
    '''Get a named attribute from an object in a safe way.

    Similar to `getattr` but without triggering dynamic look-up via the
    descriptor protocol, `__getattr__` or `__getattribute__` by using
    `getattr_static`:func:.

    '''
    from xoutil import Undefined as _undef
    from xoutil.tools import get_default
    default = get_default(default, _undef)
    is_type = isinstance(obj, type)
    res = getattr_static(obj, name, _undef)
    if isdatadescriptor(res):
        try:
            owner = type if is_type else type(obj)
            res = res.__get__(obj, owner)
        except BaseException:
            res = _undef
    if res is _undef and not is_type:
        cls = type(obj)
        res = getattr_static(cls, name, _undef)
        if isdatadescriptor(res):
            try:
                res = res.__get__(obj, cls)
            except StandardException:
                try:
                    res = res.__get__(cls, type)
                except StandardException:
                    res = _undef
    if res is not _undef:
        return res
    elif default is not _undef:
        return default
    else:
        from xoutil.eight import typeof
        msg = "'%s' object has no attribute '%s'"
        raise AttributeError(msg % (typeof(obj).__name__, name))
Beispiel #8
0
    def __call__(self, args, kwargs):
        '''Consolidate in `kwargs` all actual parameters.

        :param args: The positional arguments received by the calling function.

        :param kwargs: The keyword arguments received by the calling function.

        '''
        from xoutil.eight import iteritems
        assert isinstance(args, tuple) and isinstance(kwargs, dict)

        def clean(name):
            '''If argument with name is not yet assigned.'''
            return name not in kwargs

        def settle(name, value):
            '''Settle a value if not yet assigned, raises an error if not.'''
            if clean(name):
                kwargs[str(name)] = value
            else:
                msg = 'Got multiple values for "{}" argument: "{}" and "{}"!'
                raise TypeError(msg.format(name, value, kwargs[name]))

        def solve_aliases():
            '''Solve keyword arguments that have aliases.'''
            from xoutil import Unset
            for par, ps in iteritems(self.scheme):
                for alias in ps['aliases']:
                    value = kwargs.pop(alias, Unset)
                    if value is not Unset:
                        settle(par, value)

        def check_kwargs():
            '''Check all formal keyword arguments.'''
            from xoutil.values import valid
            for key, arg in iteritems(kwargs):
                if key in self.scheme:
                    checker = self.scheme[key]['checker']
                    value = checker(arg)
                    if valid(value):
                        kwargs[str(key)] = value
                    else:
                        msg = 'Invalid argument value "{}": "{}"!'
                        raise ValueError(msg.format(key, arg))
                elif self.strict:
                    msg = 'Invalid keyword argument "{}": "{}"!'
                    raise ValueError(msg.format(key, arg))

        def solve_results():
            '''Assign default values for missing arguments.'''
            from xoutil.values import valid
            for par, ps in iteritems(self.scheme):
                if clean(par):
                    default = ps['default']
                    if valid(default):
                        kwargs[str(par)] = default
                    else:
                        msg = 'Missing required argument "{}"!'
                        raise TypeError(msg.format(par))

        def get_valid():
            '''Get the valid parameter name in current position pivot.

            Return a tuple (name, value) if valid.

            '''
            from xoutil.values import valid
            names = positions[pivot]
            i, count = 0, len(names)
            res = ()
            while not res and i < count:
                name = names[i]
                if clean(name):
                    checker = self.scheme[name]['checker']
                    value = checker(arg)
                    if valid(value):
                        res = (name, value)
                i += 1
            return res

        def get_duplicate():
            '''Get a possible all not settled valid parameter names.'''
            from xoutil.values import valid
            res = None
            pos = last_pivot
            while not res and pos < len(positions):
                names = positions[pos]
                i = 0
                while not res and i < len(names):
                    name = names[i]
                    if name not in settled:
                        checker = self.scheme[name]['checker']
                        value = checker(arg)
                        if valid(value):
                            res = name
                    i += 1
                pos += 1
            return res

        solve_aliases()
        check_kwargs()
        # Solve positional arguments
        settled = set()
        positions = self.positions
        positionals = {p for p, ps in iteritems(self.scheme) if ps['pos']}
        max_args = len({name for name in positionals if clean(name)})
        i, count = 0, len(args)
        pivot = last_pivot = 0
        if count <= max_args:
            while i < count and pivot < len(positions):
                arg = args[i]
                res = get_valid()
                if res:
                    name, value = res
                    settle(name, value)
                    settled.add(name)
                    last_pivot = pivot
                    i += 1
                else:
                    pivot += 1
            if i == count:
                solve_results()
            else:
                from xoutil.eight import typeof
                dup = get_duplicate()
                extra = 'duplicate "{}" '.format(dup) if dup else ''
                msg = ('Invalid {}argument "{}" at position "{}" of type '
                       '"{}".')
                tname = typeof(arg).__name__
                raise TypeError(msg.format(extra, arg, i, tname))
        else:
            msg = 'Expecting at most {} positional arguments ({} given)!'
            raise TypeError(msg.format(max_args, count))
    def test_basics(self):
        from xoutil.eight import typeof
        c = ChainMap()
        c['a'] = 1
        c['b'] = 2
        d = c.new_child()
        d['b'] = 20
        d['c'] = 30
        # check internal state
        self.assertEqual(d.maps, [{'b': 20, 'c': 30}, {'a': 1, 'b': 2}])
        # check items/iter/getitem
        self.assertEqual(d.items(), dict(a=1, b=20, c=30).items())
        # check len
        self.assertEqual(len(d), 3)
        # check contains
        for key in 'abc':
            self.assertIn(key, d)
        # check get
        for k, v in dict(a=1, b=20, c=30, z=100).items():
            self.assertEqual(d.get(k, 100), v)

        # unmask a value
        del d['b']
        # check internal state
        self.assertEqual(d.maps, [{'c': 30}, {'a': 1, 'b': 2}])
        # check items/iter/getitem
        self.assertEqual(d.items(), dict(a=1, b=2, c=30).items())
        # check len
        self.assertEqual(len(d), 3)
        # check contains
        for key in 'abc':
            self.assertIn(key, d)
        # check get
        for k, v in dict(a=1, b=2, c=30, z=100).items():
            self.assertEqual(d.get(k, 100), v)
        if not PY3:
            # check repr
            self.assertIn(repr(d), [
                typeof(d).__name__ + "({u'c': 30}, {u'a': 1, u'b': 2})",
                typeof(d).__name__ + "({u'c': 30}, {u'b': 2, u'a': 1})"
            ])
        else:
            # check repr
            self.assertIn(repr(d), [
                typeof(d).__name__ + "({'c': 30}, {'a': 1, 'b': 2})",
                typeof(d).__name__ + "({'c': 30}, {'b': 2, 'a': 1})"
            ])

        # check shallow copies
        for e in d.copy(), copy.copy(d):
            self.assertEqual(d, e)
            self.assertEqual(d.maps, e.maps)
            self.assertIsNot(d, e)
            self.assertIsNot(d.maps[0], e.maps[0])
            for m1, m2 in zip(d.maps[1:], e.maps[1:]):
                self.assertIs(m1, m2)

        # check deep copies
        for e in [pickle.loads(pickle.dumps(d)),
                  copy.deepcopy(d),
                  eval(repr(d))]:
            self.assertEqual(d, e)
            self.assertEqual(d.maps, e.maps)
            self.assertIsNot(d, e)
            for m1, m2 in zip(d.maps, e.maps):
                self.assertIsNot(m1, m2, e)

        f = d.new_child()
        f['b'] = 5
        self.assertEqual(f.maps, [{'b': 5}, {'c': 30}, {'a': 1, 'b': 2}])
        # check parents
        self.assertEqual(f.parents.maps, [{'c': 30}, {'a': 1, 'b': 2}])
        # find first in chain
        self.assertEqual(f['b'], 5)
        # look beyond maps[0]
        self.assertEqual(f.parents['b'], 2)