argsloader.units.structure

GetItemUnit

class argsloader.units.structure.GetItemUnit(item, offset: bool = True)[source]
Overview:

Unit for getting item from list, tuple or dict object, using __getitem__.

__init__(item, offset: bool = True)[source]

Constructor of GetItemUnit.

Parameters
  • item – Item data.

  • offset – Create offset when getting item, default is True.

getitem_

argsloader.units.structure.getitem_(*items, offset: bool = True)[source]
Overview:

Getting item from list, tuple and dict, based on __getitem__.

Parameters
  • items – Items to be got, units are supported, multiple items are also supported.

  • offset – Enable offset or not, default is True.

Returns

A unit for getting item.

Examples::
  • Get item from list and tuple

>>> from argsloader.units import getitem_
>>> u = getitem_(2)
>>> u([2, 3, 5, 7, 11, 13])
5
>>> u((2, 3, 5, 7, 11, 13))
5
>>> u([2, 3])
IndexParseError: Item 2 not found in value.
  • Get item from dict

>>> u = getitem_('b')
>>> u({'a': 12, 'b': 23})
23
>>> u({'b': 24, 'bb': 233})
24
>>> u({'a': 12, 'c': 23})
KeyParseError: "Item 'b' not found in value."
  • Multiple levels

>>> u = getitem_('a', 2)
>>> u({'a': [2, 3, 5, 7], 'b': 2})
5
>>> u({'a': [2, 3], 'b': 2})
IndexParseError: Item 2 not found in value.
>>> u({'aa': [2, 3, 5, 7], 'b': 2})
KeyParseError: "Item 'a' not found in value."

Note

When getitem_() is used, the position of value will be switched to child-level. This can be seen when method argsloader.units.base.BaseUnit.call() is called. For example,

>>> from argsloader.units import getitem_, is_type
>>> u = getitem_(2) >> is_type(int)
>>> u.call([2, 3, 5.0])
argsloader.base.exception.MultipleParseError: (1 error)
  <root>.2: TypeParseError: Value type not match - int expected but float found.
>>>
>>> u = getitem_('b') >> is_type(int)
>>> u.call({'a': 12, 'b': 23.0})
argsloader.base.exception.MultipleParseError: (1 error)
  <root>.b: TypeParseError: Value type not match - int expected but float found.

But sometimes this offset should not be kept, so we can disable it. For example, in the following code, This positions of the errors are all <root> instead of <root>.2 or <root>.b.

>>> from argsloader.units import getitem_, is_type
>>> u = getitem_(2, offset=False) >> is_type(int)
>>> u.call([2, 3, 5.0])
argsloader.base.exception.MultipleParseError: (1 error)
  <root>: TypeParseError: Value type not match - int expected but float found.
>>>
>>> u = getitem_('b', offset=False) >> is_type(int)
>>> u.call({'a': 12, 'b': 23.0})
argsloader.base.exception.MultipleParseError: (1 error)
  <root>: TypeParseError: Value type not match - int expected but float found.

GetAttrUnit

class argsloader.units.structure.GetAttrUnit(attr)[source]
Overview:

Unit for getting attribute from object, using __getattr__.

__init__(attr)[source]

Constructor of GetAttrUnit.

Parameters

attr – Attribute data.

getattr_

argsloader.units.structure.getattr_(attr)argsloader.units.structure.GetAttrUnit[source]
Overview:

Getting attribute from object, based on __getattr__.

Parameters

attr – Attribute to be got, units are supported.

Returns

A unit for getting attribute.

Examples::
>>> from argsloader.units import getattr_
>>> from easydict import EasyDict
>>> u = getattr_('a')
>>> u(EasyDict({'a': 1, 'b': 2}))
1
>>>
>>> u = getattr_('__dict__')
>>> u(EasyDict({'a': 1, 'b': 2}))
{'a': 1, 'b': 2}

StructUnit

class argsloader.units.structure.StructUnit(struct_)[source]
Overview:

Unit for building structure.

__init__(struct_)[source]

Constructor of StructUnit.

Parameters

struct – Structure data.

struct

argsloader.units.structure.struct(struct_)[source]
Overview:

Quickly build a structure, based on the given struct data.

Parameters

struct – Structure data, which should contain one or multiple units.

Returns

Structed data, which has the same structure with the given struct_.

Examples::
>>> u = struct({
...     'a': add.by(2) >> interval.LR(1, 15),
...     'b': (sub.by(3), 'this is b'),
...     'c': [233, mul.by(4)],
... })
>>> u(5)
{'a': 7, 'b': (2, 'this is b'), 'c': [233, 20]}
>>> u(10)
{'a': 12, 'b': (7, 'this is b'), 'c': [233, 40]}
>>> u(20)
ValueParseError: Value not in interval - [1, 15] expected but 22 found.

Note

Extended class of list, tuple or dict’s type will be kept. For example,

>>> from argsloader.units import struct, add, mul, sub, interval
>>> from easydict import EasyDict
>>> u = struct({
...     'a': add.by(2) >> interval.LR(1, 15),
...     'b': (sub.by(3), 'this is b'),
...     'c': EasyDict({'x': 233, 'y': mul.by(4)}),
... })
>>> u(5)
{'a': 7, 'b': (2, 'this is b'), 'c': {'x': 233, 'y': 20}}
>>> type(u(5))
<class 'dict'>
>>> type(u(5)['c'])
<class 'easydict.EasyDict'>

Note

Like the & operator, all the units will be executed, so all the errors will be recorded when method argsloader.units.base.BaseUnit.call() is used. For example,

>>> from argsloader.units import struct, add, mul, sub, interval
>>> u = struct({
...     'a': add.by(2) >> interval.LR(1, 10),
...     'b': (sub.by(3) >> interval.LR(0, 5), 'this is b'),
...     'c': [233, mul.by(4) >> interval.LR(10, 30)],
... })
>>> u.call(5)
{'a': 7, 'b': (2, 'this is b'), 'c': [233, 20]}
>>> u.call(10)
argsloader.base.exception.MultipleParseError: (3 errors)
  <root>: ValueParseError: Value not in interval - [1, 10] expected but 12 found.
  <root>: ValueParseError: Value not in interval - [0, 5] expected but 7 found.
  <root>: ValueParseError: Value not in interval - [10, 30] expected but 40 found.

Warning

If the given struct_ is not a dict, list or tuple, the return value will be a simple unit instead of StructUnit.

MappingUnit

class argsloader.units.structure.MappingUnit(f, offset: bool = True)[source]
Overview:

Unit for processing sequence-based objects.

__init__(f, offset: bool = True)[source]

Constructor of MappingUnit.

Parameters
  • f – Processor function.

  • offset – Create offset when getting item, default is True.

mapping

argsloader.units.structure.mapping(func, offset: bool = True)argsloader.units.structure.MappingUnit[source]
Overview:

Mapping items from sequence based object.

Parameters
  • func – Processor function for mapping.

  • offset – Enable offset or not, default is True.

Returns

A unit for mapping sequence based-object.

Examples::
>>> from argsloader.units import mapping, interval, add
>>> u = mapping(add.by(2) >> interval.LR(1, 10))
>>> u([2, 3, 5, 7])
[4, 5, 7, 9]
>>> u([2, 3, 5, 71, 11, 13])
ValueParseError: Value not in interval - [1, 10] expected but 73 found.

Note

All the values will be processed by the unit, so all the errors will be recorded. For example,

>>> from argsloader.units import mapping, interval, add
>>> u = mapping(add.by(2) >> interval.LR(1, 10))
>>> u.call([2, 3, 5, 7])
[4, 5, 7, 9]
>>> u.call([2, 3, 5, 71, 11, 13])
argsloader.base.exception.MultipleParseError: (3 errors)
  <root>.3: ValueParseError: Value not in interval - [1, 10] expected but 73 found.
  <root>.4: ValueParseError: Value not in interval - [1, 10] expected but 13 found.
  <root>.5: ValueParseError: Value not in interval - [1, 10] expected but 15 found.

Note

Like function getitem_(), the position offset is enabled in default. But we can disable it when necessary. For example, in the following code, all the errors will be marked as <root>.

>>> from argsloader.units import mapping, interval, add
>>> u = mapping(add.by(2) >> interval.LR(1, 10), offset=False)
>>> u.call([2, 3, 5, 7])
[4, 5, 7, 9]
>>> u.call([2, 3, 5, 71, 11, 13])
argsloader.base.exception.MultipleParseError: (3 errors)
  <root>: ValueParseError: Value not in interval - [1, 10] expected but 73 found.
  <root>: ValueParseError: Value not in interval - [1, 10] expected but 13 found.
  <root>: ValueParseError: Value not in interval - [1, 10] expected but 15 found.

InUnit

class argsloader.units.structure.InUnit(instance, collection)[source]
Overview:

Unit for checking if one object is in another object, using __contains__ method.

__init__(instance, collection)[source]

Constructor of InUnit.

Parameters
  • instance – Instance to be checked.

  • collection – Collection to be checked.

in_

argsloader.units.structure.in_(instance, collection)argsloader.units.structure.InUnit[source]
Overview:

Containment check, using __contains__ method.

Parameters
  • instance – Instance to be checked.

  • collection – Collection to be checked.

Returns

Unit for checking containment.

Examples::
>>> from argsloader.units import in_, add, mul, struct
>>> u = in_(add.by(2), struct([2, mul.by(2), 5]))
>>> u(0)  # 2 in [2, 0, 5]
0
>>> u(2)  # 4 in [2, 4, 5]
2
>>> u(4)  # 6 in [2, 8, 5]
KeyParseError: 'Collection should contain instance, but 6 is not included in [2, 8, 5] actually.'

isin

argsloader.units.structure.isin(collection)argsloader.units.structure.InUnit[source]
Overview:

Containment check, the same as in_(keep(), collection).

Parameters

collection – Collection to be checked.

Returns

Unit for checking containment.

Examples::
>>> from argsloader.units import isin, add, mul
>>> u = add.by(2) >> mul.by(3) >> isin([9, 0, 12])
>>> u(1)  # 9 in [9, 0, 12]
9
>>> u(2)  # 12 in [9, 0, 12]
12
>>> u(3)  # 15 in [9, 0, 12]
KeyParseError: 'Collection should contain instance, but 15 is not included in [9, 0, 12] actually.'

contains

argsloader.units.structure.contains(instance)argsloader.units.structure.InUnit[source]
Overview:

Containment check, the same as in_(instance, keep()).

Parameters

instance – Instance to be checked.

Returns

Unit for checking containment.

Examples::
>>> from argsloader.units import contains, add, mul, struct
>>> u = struct([add.by(2), mul.by(2), 10]) >> contains(8)
>>> u(4)  # 8 in [6, 8, 10]
[6, 8, 10]
>>> u(6)  # 8 in [8, 12, 10]
[8, 12, 10]
>>> u(7)  # 8 in [9, 14, 10]
KeyParseError: 'Collection should contain instance, but 8 is not included in [9, 14, 10] actually.'

cdict

argsloader.units.structure.cdict(dict_: dict)[source]
Overview:

Build a struct() unit to parse dict-based data, with some slight validations.

Parameters

dict – Dict-based metadata.

Returns

A struct() unit.

Examples::
  • Simple usage

>>> from argsloader.units import cdict, cvalue, is_type, crequired, add, interval, number
>>> u = cdict({
...     'a': cvalue(1, number()),  # default value with validation
...     'b': crequired(),  # required value
...     'c': {
...         'x': cvalue(4, is_type(int) >> add.by(10)),
...         'y': cvalue(crequired(), is_type(int) & interval.LR(0, 10)),
...         'z': 5,  # simple default value
...     },
... })
>>> u.call({'a': 5, 'b': 10, 'c': {'x': 7, 'y': 9}})
{'a': 5, 'b': 10, 'c': {'x': 17, 'y': 9, 'z': 5}}
>>> u.call({'a': '0xff', 'b': -2, 'c': {'y': 4}})
{'a': 255, 'b': -2, 'c': {'x': 14, 'y': 4, 'z': 5}}
>>> u.call({'a': '0b101011', 'c': {'x': 6.0, 'y': 100.0}})
argsloader.base.exception.MultipleParseError: (4 errors)
  <root>: KeyParseError: Item 'b' not found in value.
  <root>.c.x: TypeParseError: Value type not match - int expected but float found.
  <root>.c.y: TypeParseError: Value type not match - int expected but float found.
  <root>.c.y: ValueParseError: Value not in interval - [0, 10] expected but 100.0 found.
  • Keep the original type

>>> from easydict import EasyDict
>>> from argsloader.units import cdict, cvalue, number
>>> u = cdict(EasyDict({
...     'a': cvalue(1, number()),
...     'b': crequired(),
... }))
>>> u.call({'a': '0xff', 'b': -2})
{'a': 255, 'b': -2}
>>> isinstance(u.call({'a': '0xff', 'b': -2}), EasyDict)
True
  • Nested usage

>>> from argsloader.units import cdict, cvalue, is_type, crequired, add, interval, number
>>> u = cdict({
...     'a': cvalue(1, number()),
...     'b': crequired(),
...     'c': cdict({  # inner cdict can be used
...         'x': cvalue(4, is_type(int) >> add.by(10)),
...         'y': cvalue(crequired(), is_type(int) & interval.LR(0, 10)),
...         'z': 5,
...     }),
... })
>>> u.call({'a': 5, 'b': 10, 'c': {'x': 7, 'y': 9}})
{'a': 5, 'b': 10, 'c': {'x': 17, 'y': 9, 'z': 5}}
>>> u.call({'a': '0xff', 'b': -2, 'c': {'y': 4}})
{'a': 255, 'b': -2, 'c': {'x': 14, 'y': 4, 'z': 5}}
>>> u.call({'a': '0b101011', 'c': {'x': 6.0, 'y': 100.0}})
argsloader.base.exception.MultipleParseError: (4 errors)
  <root>: KeyParseError: Item 'b' not found in value.
  <root>.c.x: TypeParseError: Value type not match - int expected but float found.
  <root>.c.y: TypeParseError: Value type not match - int expected but float found.
  <root>.c.y: ValueParseError: Value not in interval - [0, 10] expected but 100.0 found.

Warning

Attention that the value items which not appeared in the dict_ value will be ignored. This means the parsing result of function cdict() will have exactly the same structure as dict_. For example

>>> from easydict import EasyDict
>>> from argsloader.units import cdict, cvalue, number
>>> u = cdict(EasyDict({
...     'a': cvalue(1, number()),
...     'b': crequired(),
... }))
>>> u.call({'a': '0xff', 'b': -2, 'z': 174})  # z is ignored
{'a': 255, 'b': -2}

cfree

argsloader.units.structure.cfree(unit)[source]
Overview:

Processing values freely in cdict().

cvalue

argsloader.units.structure.cvalue(default_, ucheck=<SingletonMark 'CVALUE_UNIT_KEEP'>) → argsloader.units.structure._CDefaultValidation[source]
Overview:

Get a value validation mark which means this value item has a default value and some validations.

See cdict().

Parameters
  • default – Default value of this item.

  • ucheck – Check unit for this item, default means just do not do any validation.

Note

The validation will be processed after item’s getting and default value’s applying. This means the given default_ will be processed by ucheck as well.

Warning

Do not use unit object in default_ parameter, which will be processed with argsloader.units.base.raw(). Some unexpected result will be caused due to this misuse.

crequired

argsloader.units.structure.crequired()[source]
Overview:

Get a mark which means this value is required.

See cdict().