Example #1
0
def accumulated(mass, *attrs, **kwargs):
    '''Becomes True after accumulating a given "mass".

    `mass` is the maximum allowed to accumulate.  This is usually a positive
    number.  Each value produced by the `unbounded generator` is added
    together.  Yield True when this amount to more than the given `mass`.

    If any `attrs` are provided, they will be considered attributes (or keys)
    to search inside the yielded data from the bounded function.  If no
    `attrs` are provided the whole data is accumulated, so it must allow
    addition.  The attribute to be summed is extracted with
    `~xoutil.objects.get_first_of`:func:, so only the first attribute found is
    added.

    If the keyword argument `initial` is provided the accumulator is
    initialized with that value.  By default this is 0.

    '''
    from xoutil.objects import get_first_of
    accum = kwargs.pop('initial', 0)
    if kwargs:
        raise TypeError('Invalid keyword arguments %r' % kwargs.keys())
    yield False
    while accum < mass:
        data = yield False
        accum += get_first_of(data, *attrs, default=data)
    yield True
Example #2
0
 def _get_can_new(self):
     for record in self:
         has_group = self.env['res.users'].has_group(
             'xopgi_mail_new_thread.group_new_thread')
         type = get_first_of(record, 'type', 'message_type')
         record.can_new_thread = (type not in ('notification', ) and
                                  (self._uid == SUPERUSER_ID or has_group))
Example #3
0
 def __getitem__(self, name):
     from xoutil.objects import get_first_of
     result = get_first_of(self._probes, name, default=_unset)
     if result is not _unset:
         return result
     else:
         raise KeyError(name)
Example #4
0
 def __getitem__(self, name):
     from xoutil.objects import get_first_of
     probes = tuple(c.__dict__ for c in self._target_mro)
     result = get_first_of(probes, name, default=_unset)
     if result is not _unset:
         return result
     else:
         raise KeyError(name)
Example #5
0
 def _serialize(self, data):
     """Serialize a QuerySet or anything into JSON."""
     kwargs = {}
     if not self.request.is_ajax():
         kwargs['indent'] = 2
     encoder = self.JSONEncoder(**kwargs)
     encode = get_first_of(encoder, 'iterencode', 'encode')
     return encode(data)
Example #6
0
def dict_merge(*dicts, **others):

    '''Merges several dicts into a single one.

    Merging is similar to updating a dict, but if values are non-scalars they
    are also merged is this way:

    - Any two :class:`sequences <collection.Sequence>` or :class:`sets
      <collections.Set>` are joined together.

    - Any two mappings are recursively merged.

    - Other types are just replaced like in :func:`update`.

    If for a single key two values of incompatible types are found, raise a
    TypeError.  If the values for a single key are compatible but different
    (i.e a list an a tuple) the resultant type will be the type of the first
    apparition of the key, unless for mappings which are always cast to dicts.

    No matter the types of `dicts` the result is always a dict.

    Without arguments, return the empty dict.

    '''
    from collections import Mapping, Sequence, Set
    from xoutil.eight import iteritems
    from xoutil.objects import get_first_of
    from xoutil.types import are_instances, no_instances
    if others:
        dicts = dicts + (others, )
    dicts = list(dicts)
    result = {}
    collections = (Set, Sequence)
    while dicts:
        current = dicts.pop(0)
        for key, val in iteritems(current):
            if isinstance(val, Mapping):
                val = {key: val[key] for key in val}
            value = result.setdefault(key, val)
            if value is not val:
                if are_instances(value, val, collections):
                    join = get_first_of((value, ), '__add__', '__or__')
                    if join:
                        constructor = type(value)
                        value = join(constructor(val))
                    else:
                        raise ValueError("Invalid value for key '%s'"
                                         % key)
                elif are_instances(value, val, Mapping):
                    value = dict_merge(value, val)
                elif no_instances(value, val, (Set, Sequence, Mapping)):
                    value = val
                else:
                    raise TypeError("Found incompatible values for key '%s'"
                                    % key)
                result[key] = value
    return result
Example #7
0
def smart_getattr(name, *sources, **kwargs):
    '''Gets an attr by `name` for the first source that has it.

    This is roughly that same as::

       get_first_of(sources, name, default=Unset, **kwargs)

    .. warning:: Deprecated since 1.5.1

    '''
    from xoutil.iterators import dict_update_new
    dict_update_new(kwargs, {'default': Unset})
    return get_first_of(sources, name, **kwargs)
Example #8
0
    def resolve(self, node: Node, instance, kwargs):
        resolver = getattr(node, f'resolve_{self.name}', None)
        if resolver:
            schema = Schema(resolver.__annotations__)
            kwargs = dict(kwargs, **schema.validate(kwargs))
            value = partial(resolver, instance)
        else:
            value = get_first_of(instance, self.name)

        if callable(value):
            value = value(**kwargs)

        return value
Example #9
0
    def resolve(self, node: Node, instance, kwargs):
        resolver = getattr(node, f'resolve_{self.name}', None)
        if resolver:
            kwargs = self.validate(resolver, kwargs)
            value = partial(resolver, instance)
        else:
            value = get_first_of(instance, self.name)

        all_values = getattr(value, 'all', None)
        if all_values:
            value = all_values()
        elif callable(value):
            value = value(**kwargs)

        if isinstance(value, UUID):
            value = str(value)

        return value
Example #10
0
File: py.py Project: mvaled/xotl.ql
 def plan(**plan_kwargs):
     # The algorithm is simple; first we "intertwine" tokens and filters
     # using a (stable) partial order: a filter comes before a token if and
     # only if neither of it's terms is bound to the token.
     #
     # The we just build several chained generators that either produce
     # (affect the vm) or filter.
     #
     from xoutil.objects import get_first_of
     from xotl.ql.expressions import _false
     parts = list(sorted_parts[:])
     vm = get_first_of((plan_kwargs, kwargs), 'vm', default={})
     # vm = plan_kwargs.get('vm', None) or kwargs.get('vm', None) or {}
     result = vmtoken(parts.pop(0), vm, query, only=only)
     while parts:
         part = parts.pop(0)
         if isinstance(part, GeneratorToken):
             result = vmtoken(part, vm, query, only=only).chain(result)
         else:
             result = vminstr(part, vm).chain(result)
     for _ in result:
         selected = select(query.selection, vm)
         if selected is not _false:
             yield selected
Example #11
0
def smart_copy(*args, **kwargs):
    '''Copies the first apparition of attributes (or keys) from `sources` to
    `target`.

    :param sources: The objects from which to extract keys or attributes.

    :param target: The object to fill.

    :param defaults: Default values for the attributes to be copied as
                     explained below. Defaults to False.

    :type defaults: Either a bool, a dictionary, an iterable or a callable.

    Every `sources` and `target` are always positional arguments. There should
    be at least one source. `target` will always be the last positional
    argument.

    If `defaults` is a dictionary or an iterable then only the names provided
    by itering over `defaults` will be copied. If `defaults` is a dictionary,
    and one of its key is not found in any of the `sources`, then the value of
    the key in the dictionary is copied to `target` unless:

    - It's the value :class:`xoutil.types.Required` or an instance of Required.

    - An exception object

    - A sequence with is first value being a subclass of Exception. In which
      case :class:`xoutil.data.adapt_exception` is used.

    In these cases a KeyError is raised if the key is not found in the
    sources.

    If `default` is an iterable and a key is not found in any of the sources,
    None is copied to `target`.

    If `defaults` is a callable then it should receive one positional
    arguments for the current `attribute name` and several keyword arguments
    (we pass ``source``) and return either True or False if the attribute
    should be copied.

    If `defaults` is False (or None) only the attributes that do not start
    with a "_" are copied, if it's True all attributes are copied.

    When `target` is not a mapping only valid Python identifiers will be
    copied.

    Each `source` is considered a mapping if it's an instance of
    `collections.Mapping` or a `MappingProxyType`.

    The `target` is considered a mapping if it's an instance of
    `collections.MutableMapping`.

    :returns: `target`.

    .. versionchanged:: 1.7.0 `defaults` is now keyword only.

    '''
    from collections import MutableMapping
    from xoutil.types import is_collection, is_mapping, Required
    from xoutil.data import adapt_exception
    from xoutil.validators.identifiers import is_valid_identifier
    defaults = kwargs.pop('defaults', False)
    if kwargs:
        raise TypeError('smart_copy does not accept a "%s" keyword argument'
                        % kwargs.keys()[0])
    sources, target = args[:-1], args[-1]
    if not sources:
        raise TypeError('smart_copy requires at least one source')
    if isinstance(target, (bool, type(None), int, float, str_base)):
        raise TypeError('target should be a mutable object, not %s' %
                        type(target))
    if isinstance(target, MutableMapping):
        def setter(key, val):
            target[key] = val
    else:
        def setter(key, val):
            if is_valid_identifier(key):
                setattr(target, key, val)
    _mapping = is_mapping(defaults)
    if _mapping or is_collection(defaults):
        for key, val in ((key, get_first_of(sources, key, default=Unset))
                         for key in defaults):
            if val is Unset:
                if _mapping:
                    val = defaults.get(key, None)
                else:
                    val = None
                exc = adapt_exception(val, key=key)
                if exc or val is Required or isinstance(val, Required):
                    raise KeyError(key)
            setter(key, val)
    else:
        keys = []
        for source in sources:
            get = smart_getter(source)
            if is_mapping(source):
                items = (name for name in source)
            else:
                items = dir(source)
            for key in items:
                private = isinstance(key, str_base) and key.startswith('_')
                if (defaults is False or defaults is None) and private:
                    copy = False
                elif callable(defaults):
                    copy = defaults(key, source=source)
                else:
                    copy = True
                if key not in keys:
                    keys.append(key)
                    if copy:
                        setter(key, get(key))
    return target
Example #12
0
def test_get_first_of():
    from xoutil.objects import get_first_of
    somedict = {"foo": "bar", "spam": "eggs"}
    assert get_first_of(somedict, "no", "foo", "spam") == 'bar'

    somedict = {"foo": "bar", "spam": "eggs"}
    assert get_first_of(somedict, "eggs") is None

    class Someobject(object):
        pass

    inst = Someobject()
    inst.foo = 'bar'
    inst.eggs = 'spam'
    assert get_first_of(inst, 'no', 'eggs', 'foo') == 'spam'
    assert get_first_of(inst, 'invalid') is None

    somedict = {"foo": "bar", "spam": "eggs"}

    class Someobject(object):
        pass

    inst = Someobject()
    inst.foo = 'bar2'
    inst.eggs = 'spam'
    assert get_first_of((somedict, inst), 'eggs') == 'spam'
    assert get_first_of((somedict, inst), 'foo') == 'bar'
    assert get_first_of((inst, somedict), 'foo') == 'bar2'
    assert get_first_of((inst, somedict), 'foobar') is None

    none = object()
    assert get_first_of((inst, somedict), 'foobar', default=none) is none
    _eggs = get_first_of(somedict, 'foo', 'spam', pred=lambda v: len(v) > 3)
    assert _eggs == 'eggs'
    _none = get_first_of(somedict, 'foo', 'spam', pred=lambda v: len(v) > 4)
    assert _none is None

    with pytest.raises(TypeError):
        get_first_of(None, anything=1)