Coverage for pandalone/components.py : 97%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
#! python #-*- coding: utf-8 -*- # # Copyright 2015 European Commission (JRC); # Licensed under the EUPL (the 'Licence'); # You may not use this work except in compliance with the Licence. # You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl Defines the building-blocks of a "model":
components and assemblies: See :class:`Component`, :class:`FuncComponent` and :class:`Assembly`.
paths and path-mappings (pmods): See :class:`Pmod`, :func:`pmods_from_tuples` and :class:`Pstep`.
TODO ----
1. Assembly use ComponentLoader collecting components with:
- `gatattr()` and - `filter_predicate` default to ``attr.__name__.startswith('cfunc_')``. - enforce a `disable` flag on them.
2. Component/assembly should have a stackable or common cwd?
3. Components should be easy to run without "framework". - `_build()` --> `run()` - pmods on init OR `run()`? - As ContextManager?
4. Imply a default Assembly. """
except ImportError: from mock import MagicMock # @UnusedImport
""" Encapsulates a function and its its inputs/outputs dependencies.
It should be callable, and when executed it may read/modify the data-tree given as its 1st input.
An opportunity to fix the internal-state (i.e. inputs/output/name) is when the :meth:`_build()` is invoked.
:ivar list _name: identifier :ivar list _inp: list/of/paths required on the data-tree (must not overlap with `out`) :ivar list _out: list/of/paths modified on the data-tree (must not overlap with `inp`)
Mostly defined through *cfuncs*, which provide for defining a component with a single function with a special signature, see :class:`FuncComponent`. """
def __call__(self, *agrs, **kws):
"""Invoked once before run-time and should apply `pmaps` when given."""
""" Yields a msg for each failed validation rule.
Invoke it after :meth:`_build()` component. """ # TODO: Implement Component's validation.
if False: yield # expected_attrs = ['name', 'inp', 'out'] # for attr in expected_attrs: # if not hasattr(self, attr): # yield "`%s` is unset!" % attr
""" Converts a "cfunc" into a component.
A cfunc is a function that modifies the values-tree with this signature::
cfunc_XXXX(comp, vtree)
where:
comp: the :class:`FuncComponent` associated with the cfunc
vtree: the part of the data-tree involving the values to be modified by the cfunc
It works also as a utility to developers of a cfuncs, since it is passed as their 1st arg.
The cfuncs may use :meth:`pinp` and :meth:`pout` when accessing its input and output data-tree values respectively. Note that accessing any of those attributes from outside of cfunc, would result in an error.
If a cfunc access additional values with "fixed' paths, then it has to manually add those paths into the :attr:`_inp` and :attr:`_out` lists.
Example:
This would be a fully "relocatable" cfunc::
>>> def cfunc_calc_foobar_rate(comp, value_tree): ... pi = comp.pinp() ... po = comp.pout() ... ... df = value_tree.get(pi) ... ... df[po.Acc] = df[pi.V] / df[pi.T]
To get the unmodified component-paths, use::
>>> comp = FuncComponent(cfunc_calc_foobar_rate) >>> comp._build() >>> assert list(comp._iter_validations()) == [] >>> sorted(comp._inp + comp._out) ['calc_foobar_rate/Acc', 'calc_foobar_rate/T', 'calc_foobar_rate/V']
To get the path-modified component-paths, use::
>>> from pandalone.mappings import pmods_from_tuples
>>> pmods = pmods_from_tuples([ ... ('~.*', '/A/B'), ... ]) >>> comp._build(pmods)
>>> sorted(comp.pinp()._paths()) ['/A/B/T', '/A/B/V']
>>> comp.pout()._paths() ['/A/B/Acc']
>>> sorted(comp._inp + comp._out) ['/A/B/Acc', '/A/B/T', '/A/B/V']
>>> comp._build(pmods) >>> sorted(comp._inp + comp._out) ['/A/B/Acc', '/A/B/T', '/A/B/V']
"""
# The following are initialized in _build(): # self._inp = None # self._out = None # self._pmod = None # self._pinp = None # self._pout = None
self._cfunc(self, *args, **kws)
"""The suggested :class:`Pstep` for cfunc to use to access inputs.""" _proto_or_pmod=self._pmod)
"""The suggested :class:`Pstep` for cfunc to use to access outputs.""" _proto_or_pmod=self._pmod)
"""Extracts inputs/outputs from cfunc. """
""" Example:
>>> def cfunc_f1(comp, value_tree): ... comp.pinp().A ... comp.pout().B >>> def cfunc_f2(comp, value_tree): ... comp.pinp().B ... comp.pout().C >>> ass = Assembly(FuncComponent(cfunc) for cfunc in [cfunc_f1, cfunc_f2]) >>> ass._build() >>> assert list(ass._iter_validations()) == [] >>> ass._inp ['f1/A', 'f2/B'] >>> ass._out ['f1/B', 'f2/C']
>>> from pandalone.mappings import pmods_from_tuples
>>> pmod = pmods_from_tuples([ ... ('~.*', '/root'), ... ]) >>> ass._build(pmod) >>> sorted(ass._inp + ass._out) ['/root/A', '/root/B', '/root/B', '/root/C']
"""
pass # TODO: Invoke Dispatcher with Assembly's child-components.
if __name__ == '__main__': # pragma: no cover raise NotImplementedError |