xoutil.values – coercers (or checkers) for value types

Some generic coercers (or checkers) for value types.

This module coercion function are not related in any way to deprecated old python feature, are similar to a combination of object mold/check:

  • Mold - Fit values to expected conventions.
  • Check - These functions must return nil[1] special value to specify that expected fit is not possible.
[1]We don’t use Python classic NotImplemented special value in order to obtain False if the value is not coerced (nil).

A custom coercer could be created with closures, for an example see create_int_range_coerce().

This module uses Unset value to define absent -not being specified- arguments.

Also contains sub-modules to obtain, convert and check values of common types.

New in version 1.7.0.

class xoutil.values.MetaCoercer[source]

Meta-class for coercer.

This meta-class allows that several objects are considered valid instances of coercer:

  • Functions decorated with coercer (used with its decorator facet).
  • Instances of any sub-class of custom.
  • Instances of coercer itself.

See the class declaration (coercer) for more information.

xoutil.values.callable_coerce(arg)[source]

Check if arg is a callable object.

class xoutil.values.coercer[source]

Special coercer class.

This class has several facets:

  • Pure type-checkers when a type or tuple of types are received as argument. See istype for more information.

  • Return equivalent coercer from some special values:

    • Any true value -> identity_coerce
    • Any false or empty value -> void_coerce
  • A decorator for functions; when a function is given, decorate it to become a coercer. The mark itself is not enough, functions intended to be coercers must fulfills the protocol (not to produce exception and return nil on fails). For example:

    >>> @coercer
    ... def age_coerce(arg):
    ...     res = int_coerce(arg)
    ...     return res if t(res) and 0 < arg <= 120 else nil
    
    # TODO: Change next, don't use isinstance
    >>> isinstance(age_coerce, coercer)
    True
    
xoutil.values.coercer_name(arg, join=None)[source]

Get the name of a coercer.

Parameters:
  • arg – Coercer to get the name. Also processes collections (tuple, list, or set) of coercers. Any other value is considered invalid and raises an exception.
  • join

    When a collection is used; if this argument is None a collection of names is returned, if not None then is used to join the items in a resulting string.

    For example:

    >>> coercer_name((int_coerce, float_coerce))
    ('int', 'float')
    
    >>> coercer_name((int_coerce, float_coerce), join='-')
    'int-float'
    

    To obtain pretty-print tuples, use something like:

    >>> coercer_name((int_coerce, float_coerce),
    ...              join=lambda arg: '(%s)' % ', '.join(arg))
    

This function not only works with coercers, all objects that fulfill needed protocol to get names will also be valid.

class xoutil.values.combo(*coercers)[source]

Represent a zip composition of several inner coercers.

An instance of this class is constructed from a sequence of coercers and the its purpose is coerce a sequence of values. Return a sequence [2] where each item contains the i-th element from applying the i-th coercer to the i-th value from argument sequence:

coercers -> (coercer-1, coercer-2, ... )
values -> (value-1, value-2, ... )
combo(coercers)(values) -> (coercer-1(value-1), coercer-2(value-2), ...)

If any value is coerced invalid, the function returns nil and the combo’s instance variable scope receives the duple (failed-value, failed-coercer).

The returned sequence is truncated in length to the length of the shortest sequence (coercers or arguments).

If no coercer is given, all sequences are coerced as empty.

[2]The returned sequence is of the same type as the argument sequence if possible.
class xoutil.values.compose(*args, **kwargs)[source]

Returns the composition of several inner coercers.

compose(f1, ... fn) is equivalent to f1(…(fn(arg))…)``.

If no coercer is given return identity_coerce().

Could be considered an “AND” operator with some light differences because the nature of coercers: ordering the coercers is important when some can modify (adapt) original values.

If no value results in coercers, a default coercer could be given as a keyword argument; identity_coerce is assumed if missing.

xoutil.values.create_int_range_coerce(min, max)[source]

Create a coercer to check integers between a range.

xoutil.values.create_unique_member_coerce(coerce, container)[source]

Useful to wrap member coercers when coercing containers.

See iterable and mapping.

Resulting coercer check that a member must be unique (not repeated) after it’s coerced.

For example:

>>> from xoutil.values import (mapping, create_unique_member_coerce,
...                            int_coerce, float_coerce)

>>> sample = {'1': 1, 2.0: '3', 1.0 + 0j: '4.1'}

>>> dc = mapping(int_coerce, float_coerce)
>>> dc(dict(sample))
{1: 1.0, 2: 3.0}

>>> dc = mapping(create_unique_member_coerce(int_coerce), float_coerce)
>>> dc(dict(sample))
nil
class xoutil.values.custom(*args, **kwargs)[source]

Base class for any custom coercer.

The field inner stores an internal data used for the custom coercer; could be a callable, an inner coercer, or a tuple of inner checkers if more than one is needed, …

The field scope stores the exit (not regular) condition: the value that fails or -if needed- a tuple with (exit-value, exit-coercer) or (error-value, error). The exit condition is not always a failure, for example in some it is the one that is valid among other inner coercers. To understand better this think on (AND, OR) operators a chain of ANDs exits with the first failure and a chains of ORs exits with the first success.

All custom coercers are callable (must redefine __call__()) receiving one argument that must be coerced. For example:

>>> def foobar(*args):
...     coerce = pargs(int_coerce)
...     return coerce(args)

This class has two protected fields (_str_join and _repr_join) that are used to call coercer_name() in __str__() and __repr__() special methods.

classmethod flatten(obj, avoid=Unset)[source]

Flatten a coercer set.

Parameters:obj – Could be a coercer representing other inner coercers, or a tuple or list containing coercers.
xoutil.values.file_coerce(arg)[source]

Check if arg is a file-like object.

xoutil.values.float_coerce(arg)[source]

Check if arg is a valid float.

Other types are checked (string, int, complex).

xoutil.values.full_identifier_coerce(arg)[source]

Check if arg is a valid dotted Python identifier.

See identifier_coerce() for what “validity” means.

xoutil.values.identifier_coerce(arg)[source]

Check if arg is a valid Python identifier.

Note

Only Python 2’s version of valid identifier. This means that some Python 3 valid identifiers are not considered valid. This helps to keep things working the same in Python 2 and 3.

xoutil.values.identity_coerce(arg)[source]

Leaves unchanged the passed argument arg.

xoutil.values.int_coerce(arg)[source]

Check if arg is a valid integer.

Other types are checked (string, float, complex).

class xoutil.values.istype(*args, **kwargs)[source]

Pure type-checker.

It’s constructed from an argument valid for types_tuple_coerce() coercer.

For example:

>>> int_coerce = istype(int)

>>> int_coerce(1)
1

>>> int_coerce('1')
nil

>>> number_coerce = istype((int, float, complex))

>>> number_coerce(1.25)
1.25

>>> number_coerce('1.25')
nil
class xoutil.values.iterable(member_coerce, outer_coerce=True)[source]

Create a inner coercer that coerces an iterable member a member.

See constructor for more information.

Return a list, or the same type of source iterable argument if possible.

For example:

>>> from xoutil.values import (iterable, int_coerce,
...                            create_unique_member_coerce)

>>> sample = {'1', 1, '1.0'}

>>> sc = iterable(int_coerce)
>>> sc(set(sample)) == {1}
True

See mapping for more details of this problem. The equivalent safe example is:

>>> member_coerce = create_unique_member_coerce(int_coerce, sample)
>>> sc = iterable(member_coerce)
>>> sc(set(sample))
nil

when executed coerces arg (an iterable) member a member using member_coercer. If any member coercion fails, the full execution also fails.

There are three types of results when an instance is executed: (1) iterables that are coerced without modifications, (2) the modified ones but conserving its type, and (3) those that are returned in a list.

class xoutil.values.logical(*args, **kwds)[source]

Represent Common Lisp two special values t and nil.

Include redefinition of __call__() to check values with special semantic:

  • When called as t(arg), check if arg is not nil returning a logical true: the same argument if arg is nil or a true boolean value, else return t. That means that False or 0 are valid true values for Common Lisp but not for Python.
  • When called as nil(arg), check if arg is nil returning t or nil if not.

Constructor could receive a valid name (‘nil’ or ‘t’) or any other boolean instance.

class xoutil.values.mapping(*args, **kwargs)[source]

Create a coercer to check dictionaries.

Receives two coercers, one for keys and one for values.

For example:

>>> from xoutil.values import (mapping, int_coerce, float_coerce,
...                            create_unique_member_coerce)

>>> sample = {'1': 1, 2.0: '3', 1.0 + 0j: '4.1'}

>>> dc = mapping(int_coerce, float_coerce)
>>> dc(dict(sample)) == {1: 1.0, 2: 3.0}
True

When coercing containers it’s probable that members become repeated after coercing them. This could be not desirable (mainly in sets and dictionaries). In those cases use create_unique_member_coerce() to wrap member coercer. For example:

>>> key_coerce = create_unique_member_coerce(int_coerce, sample)
>>> dc = mapping(key_coerce, float_coerce)
>>> dc(dict(sample))
nil

Above problem is because it’s the same integer (same hash) coerced versions of '1' and 1.0+0j.

This problem of objects of different types that have the same hash is a problem to use a example as below:

>>> {1: int, 1.0: float, 1+0j: complex} == {1: complex}
True
xoutil.values.names_coerce(arg)[source]

Check arg as a tuple of valid object names (identifiers).

If only one string is given, is returned as the only member of the resulting tuple.

xoutil.values.number_coerce(arg)[source]

Check if arg is a valid number (integer or float).

Types that are checked (string, int, float, complex).

class xoutil.values.pargs(arg_coerce)[source]

Create a inner coercer that check variable argument passing.

Created coercer closure must always receives an argument that is an valid iterable with all members coerced properly with the argument of this outer creator function.

If the inner closure argument has only a member and this one is not properly coerced but it’s an iterabled with all members that coerced well, this member will be the assumed iterable instead the original argument.

In the following example:

>>> from xoutil.values import (iterable, int_coerce)

>>> def foobar(*args):
...     coerce = iterable(int_coerce)
...     return coerce(args)

>>> args = (1, 2.0, '3.0')
>>> foobar(*args)
(1, 2, 3)

>>> foobar(args)
nil

An example using pargs

>>> from xoutil.values import (pargs, int_coerce)

>>> def foobar(*args):
...     # Below, "coercer" receives the returned "inner"
...     coerce = pargs(int_coerce)
...     return coerce(args)

>>> args = (1, 2.0, '3.0')
>>> foobar(*args)
(1, 2, 3)

>>> foobar(args)
(1, 2, 3)

The second form is an example of the real utility of this coercer closure: if by error a sequence is passed as it to a function that expect a variable number of argument, this coercer fixes it.

Instance variable scope stores the last processed invalid argument.

When executed, usually arg is a tuple received by a function as *args form.

When executed, returns a tuple, or the same type of source iterable argument if possible.

See xoutil.params for a more specialized and full function arguments conformer.

See combo for a combined coercer that validate each member with a separate member coercer.

xoutil.values.positive_int_coerce(arg)[source]

Check if arg is a valid positive integer.

class xoutil.values.safe(func)[source]

Uses a function (or callable) in a safe way.

Receives a coercer that expects only one argument and returns another value.

If the returned value is a boolean (maybe the coercer is a predicate), it’s converted to a logical instance.

The wrapped coercer is called in a safe way (inside try/except); if an exception is raised the coercer returns nil and the error is saved in the instance attribute scope.

xoutil.values.sized_coerce(arg)[source]

Return a valid sized iterable from arg.

If arg is iterable but not sized, is converted to a list. For example:

>>> sized_coerce(i for i in range(1, 10, 2))
[1, 3, 5, 7, 9]

>>> s = {1, 2, 3}
>>> sized_coerce(s) is s
True
class xoutil.values.some(*args, **kwargs)[source]

Represent OR composition of several inner coercers.

compose(f1, ... fn) is equivalent to f1(arg) or f2(arg) … fn(arg)`` in the sense “the first not nil”.

If no coercer is given return void_coerce().

xoutil.values.type_coerce(arg)[source]

Check if arg is a valid type.

class xoutil.values.typecast(*args, **kwargs)[source]

A type-caster.

It’s constructed from an argument valid for types_tuple_coerce() coercer. Similar to istype but try to convert the value if needed.

For example:

>>> int_cast = typecast(int)

>>> int_cast('1')
1

>>> int_cast('1x')
nil
xoutil.values.types_tuple_coerce(arg)[source]

Check if arg is valid for isinstance or issubclass 2nd argument.

Type checkers are any class, a type or tuple of types. For example:

>>> types_tuple_coerce(object) == (object,)
True

>>> types_tuple_coerce((int, float)) == (int, float)
true

>>> types_tuple_coerce('not-a-type') is nil
True

See type_coerce for more information.

xoutil.values.void_coerce(arg)[source]

Always nil.

Contents: