From a4ed3c8dceb7c63eb9f41eea10b9b9fb054aff6f Mon Sep 17 00:00:00 2001 From: Martin Lange <martin.lange@ufz.de> Date: Mon, 24 Oct 2022 17:31:19 +0200 Subject: [PATCH] test code of components chapter --- .../finam-book/development/adapters.rst | 22 +++++++++- .../finam-book/development/components.rst | 40 +++++++++++-------- .../finam-book/usage/coupling_scripts.rst | 7 ++-- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/docs/source/finam-book/development/adapters.rst b/docs/source/finam-book/development/adapters.rst index 62fd7e94..3686077b 100644 --- a/docs/source/finam-book/development/adapters.rst +++ b/docs/source/finam-book/development/adapters.rst @@ -31,7 +31,7 @@ which is called from downstream to request data. File ``src/scale.py``: -.. code-block:: Python +.. testcode:: scale-adapter import finam as fm @@ -45,6 +45,11 @@ File ``src/scale.py``: d = self.pull_data(time) return d * self.scale +.. testcode:: scale-adapter + :hide: + + adapter = Scale(0.5) + In :meth:`.Adapter._get_data`, we: 1. Pull the input for the requested ``time`` @@ -129,6 +134,10 @@ In :meth:`.Adapter._source_updated`, we need to store incoming data: self.old_data = None self.new_data = None + @property + def needs_push(self): + return True + def _source_updated(self, time): self.old_data = self.new_data self.new_data = (time, fm.data.strip_data(self.pull_data(time))) @@ -141,7 +150,7 @@ As the output time will differ from the input time, we need to strip the time of In :meth:`.Adapter._get_data`, we can now do the interpolation whenever data is requested from upstream. -.. code-block:: Python +.. testcode:: time-adapter import finam as fm @@ -152,6 +161,10 @@ In :meth:`.Adapter._get_data`, we can now do the interpolation whenever data is self.old_data = None self.new_data = None + @property + def needs_push(self): + return True + def _source_updated(self, time): self.old_data = self.new_data self.new_data = (time, fm.data.strip_data(self.pull_data(time))) @@ -167,6 +180,11 @@ In :meth:`.Adapter._get_data`, we can now do the interpolation whenever data is return o + dt * (n - o) +.. testcode:: time-adapter + :hide: + + adapter = TimeInterpolation() + In :meth:`.Adapter._get_data`, the following happens: 1. If only one data entry was received so far, we can't interpolate and simply return the available data. Otherwise... diff --git a/docs/source/finam-book/development/components.rst b/docs/source/finam-book/development/components.rst index 6f770bbb..712bf75c 100644 --- a/docs/source/finam-book/development/components.rst +++ b/docs/source/finam-book/development/components.rst @@ -145,9 +145,9 @@ It is called internally by the :meth:`.TimeComponent.initialize` method. # ... def _initialize(self): # <-- - self.inputs.add(name="A", grid=fm.NoGrid()) # <-- - self.inputs.add(name="B", grid=fm.NoGrid()) # <-- - self.outputs.add(name="Sum", grid=fm.NoGrid()) # <-- + self.inputs.add(name="A", time=self.time, grid=fm.NoGrid()) # <-- + self.inputs.add(name="B", time=self.time, grid=fm.NoGrid()) # <-- + self.outputs.add(name="Sum", time=self.time, grid=fm.NoGrid()) # <-- self.create_connector() # <-- @@ -196,7 +196,7 @@ After this connection phase, models can validate their state in :meth:`.TimeComp # ... def _connect(self): # <-- - self.try_connect(time=self.time, push_data={"Sum": 0}) # <-- + self.try_connect(push_data={"Sum": 0}) # <-- def _validate(self): # <-- pass # <-- @@ -227,7 +227,7 @@ For the tests, we need to set up a real coupling from here on, as the component' # a component to consume output, details not important consumer = fm.modules.debug.DebugConsumer( - inputs={"Sum": fm.Info(grid=fm.NoGrid())}, + inputs={"Sum": fm.Info(time=None, grid=fm.NoGrid())}, start=datetime(2000, 1, 1), step=timedelta(days=7) ) @@ -338,7 +338,7 @@ Final code Here is the final code of the completed component. -.. code-block:: Python +.. testcode:: import unittest from datetime import datetime, timedelta @@ -347,22 +347,22 @@ Here is the final code of the completed component. class DummyModel(fm.TimeComponent): - def __init__(self, start, step): # <-- + def __init__(self, start, step): super().__init__() - self._step = step # <-- + self._step = step self.time = start - def _initialize(self): # <-- - self.inputs.add(name="A", grid=fm.NoGrid()) # <-- - self.inputs.add(name="B", grid=fm.NoGrid()) # <-- - self.outputs.add(name="Sum", grid=fm.NoGrid()) # <-- + def _initialize(self): + self.inputs.add(name="A", time=self.time, grid=fm.NoGrid()) + self.inputs.add(name="B", time=self.time, grid=fm.NoGrid()) + self.outputs.add(name="Sum", time=self.time, grid=fm.NoGrid()) - self.create_connector() # <-- + self.create_connector() - def _connect(self): # <-- - self.try_connect(time=self.time, push_data={"Sum": 0}) # <-- + def _connect(self): + self.try_connect(push_data={"Sum": 0}) - def _validate(self): # <-- + def _validate(self): pass def _update(self): @@ -395,7 +395,7 @@ Here is the final code of the completed component. step=timedelta(days=7), ) consumer = fm.modules.debug.DebugConsumer( - inputs={"Sum": fm.Info(grid=fm.NoGrid())}, + inputs={"Sum": fm.Info(time=None, grid=fm.NoGrid())}, start=datetime(2000, 1, 1), step=timedelta(days=7), ) @@ -412,3 +412,9 @@ Here is the final code of the completed component. self.assertEqual(consumer.data, {"Sum": 0}) composition.run(t_max=datetime(2000, 12, 31)) + + TestDummy().test_dummy_model() #doctest: +ELLIPSIS + +.. testoutput:: + + ... diff --git a/docs/source/finam-book/usage/coupling_scripts.rst b/docs/source/finam-book/usage/coupling_scripts.rst index 7713beef..ae66720c 100644 --- a/docs/source/finam-book/usage/coupling_scripts.rst +++ b/docs/source/finam-book/usage/coupling_scripts.rst @@ -153,12 +153,13 @@ FINAM provides a comprehensive logging framework built on Pythons standard :mod: You can configure the base logger when creating the :class:`.Composition` as shown above: -.. code-block:: Python +.. testcode:: composition + import finam as fm import logging - comp = Composition( - modules, + comp = fm.Composition( + [], logger_name="FINAM", print_log=True, log_file=True, -- GitLab