utils

class anyblok_wms_base.utils.NonZero[source]

Marker to mean any unspecified non zero value.

>>> str(NonZero())
'NONZERO'
>>> bool(NonZero())
True
>>> NonZero() == 2
True
>>> NonZero() == 0
False
>>> NonZero() != 0
True
>>> NonZero() != 2
False
>>> try: NonZero() == 'abc'
... except ValueError: print('ok')
ok

We don’t implement __repr__ because with reloads and the like, one can have subtle bugs with constants, and in that case, the default repr() including the object id (memory address with CPython) is really useful.

For these subtle bugs reasons, it’s probably better to test with isinstance rather than with is on a constant.

anyblok_wms_base.utils.dict_merge(first, second, list_merge=None)[source]

Deep merging of two Python objects

if both parameters are dict or set instances, they get merged, recursively for dicts. Lists can be merged according to the specified list_merge. Otherwise the value of first is returned.

Parameters:
  • first – the one having precedence.
  • list_merge

    controls list merging. If first and second are lists, this is a pair whose first element specifies what to do of lists at top level, with possible values:

    • None: first is returned
    • 'zip': return the list obtained by merging elements of the first list with those of the second, in order.
    • 'append': elements of first are added in order at the end of second.
    • 'prepend': elements of first are inserted in order at the beginning of second.
    • 'set': a set is built from elements of first and second.

    The second element of list_merge is then for recursing: a dict whose keys are list indexes or the '*' wildcard and values are to be passed as list_merge below. The second element can also be None, behaving like an empty dict.

    If first and second are dicts, then list_merge is directly the dict for recursion, and its keys are those of first and second.

No attempt is made to merge tuples (could be done later)

Examples and tests

We’ll need pretty printing to compare dicts:

>>> from pprint import pprint

First order merging:

>>> pprint(dict_merge(dict(a=1), dict(b=2)))
{'a': 1, 'b': 2}

Recursion:

>>> pprint(dict_merge(dict(a=1, deep=dict(k='foo')),
...                   dict(a=2, deep=dict(k='bar', other=3))))
{'a': 1, 'deep': {'k': 'foo', 'other': 3}}
>>> pprint(dict_merge([dict(a=1, b=2), dict(a=3)],
...                   [dict(b=5), dict(b=6)],
...                   list_merge=('zip', None)))
[{'a': 1, 'b': 2}, {'a': 3, 'b': 6}]
>>> pprint(dict_merge(dict(tozip=[dict(a=1, b=2), dict(a=3)], x=[1]),
...                   dict(tozip=[dict(b=5), dict(b=6)], x=[2]),
...                   list_merge=dict(tozip=('zip', None))))
{'tozip': [{'a': 1, 'b': 2}, {'a': 3, 'b': 6}], 'x': [1]}
>>> pprint(dict_merge(dict(tozip=[dict(a=1, b=2), dict(a=3)], x=[1]),
...                   dict(tozip=[dict(b=5), dict(b=6)], x=[2]),
...                   list_merge={'tozip': ('zip', None),
...                               '*': ('set', None),
...                               }))
{'tozip': [{'a': 1, 'b': 2}, {'a': 3, 'b': 6}], 'x': {1, 2}}

Sets:

>>> s = dict_merge({'a', 'c'}, {'a', 'b'})
>>> type(s)
<class 'set'>
>>> sorted(s)
['a', 'b', 'c']

Lists:

>>> dict_merge(['a'], ['b'])
['a']
>>> dict_merge(['a'], ['b'], list_merge=(None, None))
['a']
>>> dict_merge(['a'], ['b'], list_merge=('append', None))
['b', 'a']
>>> dict_merge(['a'], ['b'], list_merge=('prepend', None))
['a', 'b']
>>> s = dict_merge(['a', 'b'], ['a', 'c'], list_merge=('set', None))
>>> type(s)
<class 'set'>
>>> sorted(s)
['a', 'b', 'c']

Recursion inside a zip:

>>> dict_merge([dict(x='a'), dict(y=[1]), {}],
...            [dict(x='b'), dict(y=[2]), dict(x=1)],
...            list_merge=('zip',
...                        {1: {'y': ('append', None)}}))
[{'x': 'a'}, {'y': [2, 1]}, {'x': 1}]

Wildcards in list_merge for lists:

>>> dict_merge([dict(y=['a']), dict(y=[1]), {}],
...            [dict(y=['b']), dict(y=[2]), dict(y=3)],
...            list_merge=('zip',
...                        {'*': {'y': ('append', None)}}))
[{'y': ['b', 'a']}, {'y': [2, 1]}, {'y': 3}]

Non dict values:

>>> dict_merge(1, 2)
1
>>> dict_merge(dict(a=1), 'foo')
{'a': 1}
>>> dict_merge('foo', dict(a=1))
'foo'
anyblok_wms_base.utils.min_upper_bounds(inputs)[source]

Return the smallest of the given inputs, each thought as an upper bound.

Parameters:untils – an iterable of comparable values or None

To thinking about the inputs as some upper bounds translates as the convention that None means +infinity.

>>> min_upper_bounds([2, 1, None])
1
>>> min_upper_bounds([None, None]) is None
True
>>> min_upper_bounds(x for x in [2, 5, 3])
2