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
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)
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__))
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)
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
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 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))
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)