From 73fcb84a8e241aadb5e64cf5d6506e9836d11307 Mon Sep 17 00:00:00 2001 From: Philip ABBET <philip.abbet@idiap.ch> Date: Thu, 30 Nov 2017 15:26:16 +0100 Subject: [PATCH] [unittests] Add tests for the new algorithm APIs --- beat/backend/python/algorithm.py | 218 +++-- beat/backend/python/data_loaders.py | 13 +- beat/backend/python/loader.py | 7 +- .../prefix/algorithms/autonomous/add/1.json | 30 + .../prefix/algorithms/autonomous/add/1.py | 49 + .../prefix/algorithms/autonomous/add2/1.json | 28 + .../prefix/algorithms/autonomous/add2/1.py | 51 ++ .../prefix/algorithms/autonomous/add3/1.json | 31 + .../prefix/algorithms/autonomous/add3/1.py | 46 + .../prefix/algorithms/autonomous/echo/1.json | 21 + .../prefix/algorithms/autonomous/echo/1.py | 42 + .../algorithms/autonomous/no_prepare/1.json | 24 + .../algorithms/autonomous/no_prepare/1.py | 31 + .../algorithms/autonomous/no_setup/1.json | 24 + .../algorithms/autonomous/no_setup/1.py | 35 + .../algorithms/autonomous/parametrized/1.json | 279 ++++++ .../algorithms/autonomous/parametrized/1.py | 66 ++ .../autonomous/prepare_crash/1.json | 24 + .../prepare_crash}/1.py | 12 +- .../algorithms/autonomous/prepare_fail/1.json | 24 + .../algorithms/autonomous/prepare_fail/1.py | 34 + .../algorithms/autonomous/setup_crash/1.json | 24 + .../algorithms/autonomous/setup_crash/1.py | 35 + .../algorithms/autonomous/setup_fail/1.json | 24 + .../algorithms/autonomous/setup_fail/1.py | 34 + .../test/prefix/algorithms/legacy/add/1.json | 27 + .../test/prefix/algorithms/legacy/add/1.py | 41 + .../test/prefix/algorithms/legacy/add2/1.json | 25 + .../{two_streams__with_delay => add2}/1.py | 15 +- .../test/prefix/algorithms/legacy/echo/1.json | 18 + .../{one_stream__no_delay => echo}/1.py | 2 +- .../prefix/algorithms/legacy/no_setup/1.json | 22 + .../{two_streams__no_delay => no_setup}/1.py | 4 - .../legacy/one_stream__no_delay/1.json | 18 - .../legacy/one_stream__with_delay/1.json | 18 - .../legacy/two_streams__no_delay/1.json | 21 - .../legacy/two_streams__with_delay/1.json | 21 - .../prefix/algorithms/sequential/add/1.json | 30 + .../prefix/algorithms/sequential/add/1.py | 41 + .../prefix/algorithms/sequential/add2/1.json | 28 + .../prefix/algorithms/sequential/add2/1.py | 44 + .../prefix/algorithms/sequential/add3/1.json | 31 + .../prefix/algorithms/sequential/add3/1.py | 40 + .../prefix/algorithms/sequential/echo/1.json | 21 + .../prefix/algorithms/sequential/echo/1.py | 32 + .../algorithms/sequential/no_prepare/1.json | 24 + .../algorithms/sequential/no_prepare/1.py | 31 + .../algorithms/sequential/no_setup/1.json | 24 + .../algorithms/sequential/no_setup/1.py | 35 + .../algorithms/sequential/parametrized/1.json | 279 ++++++ .../algorithms/sequential/parametrized/1.py | 66 ++ .../sequential/prepare_crash/1.json | 24 + .../algorithms/sequential/prepare_crash/1.py | 35 + .../algorithms/sequential/prepare_fail/1.json | 24 + .../algorithms/sequential/prepare_fail/1.py | 34 + .../algorithms/sequential/setup_crash/1.json | 24 + .../algorithms/sequential/setup_crash/1.py | 35 + .../algorithms/sequential/setup_fail/1.json | 24 + .../algorithms/sequential/setup_fail/1.py | 34 + beat/backend/python/test/test_algorithm.py | 848 +++++++++++++++++- beat/backend/python/test/test_data_loaders.py | 121 ++- beat/backend/python/test/test_inputs.py | 2 +- .../python/test/test_synchronization.py | 424 --------- 63 files changed, 3171 insertions(+), 622 deletions(-) mode change 100644 => 100755 beat/backend/python/loader.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/add/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/add/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/add2/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/add2/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/add3/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/add3/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/echo/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/echo/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/prepare_crash/1.json rename beat/backend/python/test/prefix/algorithms/{legacy/one_stream__with_delay => autonomous/prepare_crash}/1.py (89%) mode change 100644 => 100755 create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/legacy/add/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/legacy/add/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/legacy/add2/1.json rename beat/backend/python/test/prefix/algorithms/legacy/{two_streams__with_delay => add2}/1.py (87%) mode change 100644 => 100755 create mode 100644 beat/backend/python/test/prefix/algorithms/legacy/echo/1.json rename beat/backend/python/test/prefix/algorithms/legacy/{one_stream__no_delay => echo}/1.py (97%) mode change 100644 => 100755 create mode 100644 beat/backend/python/test/prefix/algorithms/legacy/no_setup/1.json rename beat/backend/python/test/prefix/algorithms/legacy/{two_streams__no_delay => no_setup}/1.py (92%) delete mode 100644 beat/backend/python/test/prefix/algorithms/legacy/one_stream__no_delay/1.json delete mode 100644 beat/backend/python/test/prefix/algorithms/legacy/one_stream__with_delay/1.json delete mode 100644 beat/backend/python/test/prefix/algorithms/legacy/two_streams__no_delay/1.json delete mode 100644 beat/backend/python/test/prefix/algorithms/legacy/two_streams__with_delay/1.json create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/add/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/add/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/add2/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/add2/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/add3/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/add3/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/echo/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/echo/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.py create mode 100644 beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.json create mode 100755 beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.py delete mode 100644 beat/backend/python/test/test_synchronization.py diff --git a/beat/backend/python/algorithm.py b/beat/backend/python/algorithm.py index 607738d..ae577b2 100755 --- a/beat/backend/python/algorithm.py +++ b/beat/backend/python/algorithm.py @@ -90,15 +90,10 @@ class Runner(object): exception from the user code. Read the documention of :py:func:`run` for more details. - *args: Constructor parameters for the algorithm (normally none) - - **kwargs: Constructor parameters for the algorithm (normally none) - ''' - def __init__(self, module, obj_name, algorithm, exc=None, *args, - **kwargs): + def __init__(self, module, obj_name, algorithm, exc=None): try: class_ = getattr(module, obj_name) @@ -107,15 +102,15 @@ class Runner(object): type, value, traceback = sys.exc_info() six.reraise(exc, exc(value), traceback) else: - raise #just re-raise the user exception + raise # Just re-raise the user exception - self.obj = loader.run(class_, '__new__', exc, *args, **kwargs) + self.obj = loader.run(class_, '__new__', exc) self.name = module.__name__ self.algorithm = algorithm self.exc = exc - # if the algorithm does not have a 'setup' method, it is ready by default self.ready = not hasattr(self.obj, 'setup') + self.prepared = (self.algorithm.api_version == 1) or not hasattr(self.obj, 'prepare') def _check_parameters(self, parameters): @@ -125,7 +120,7 @@ class Runner(object): algo_parameters = self.algorithm.parameters or {} valid_keys = set(algo_parameters.keys()) - # checks the user is not trying to set an undeclared parameter + # Checks the user is not trying to set an undeclared parameter if not user_keys.issubset(valid_keys): err_keys = user_keys - valid_keys message = "parameters `%s' are not declared for algorithm `%s' - " \ @@ -150,51 +145,97 @@ class Runner(object): exc = self.exc or ValueError raise exc(message) - else: #user has not set a value, use the default + else: # User has not set a value, use the default value = algo_parameters[key]['default'] - # in the end, set the value on the dictionary to be returned + # In the end, set the value on the dictionary to be returned retval[key] = value return retval - def setup(self, parameters, *args, **kwargs): + def setup(self, parameters): '''Sets up the algorithm, only effective on the first call''' + # Only effective on the first call if self.ready: return self.ready completed_parameters = self._check_parameters(parameters) - kwargs['parameters'] = completed_parameters - self.ready = loader.run(self.obj, 'setup', self.exc, *args, **kwargs) + self.ready = loader.run(self.obj, 'setup', self.exc, completed_parameters) return self.ready - def prepare(self, parameters, *args, **kwargs): + def prepare(self, data_loaders): '''Let the algorithm process the data on the non-principal channels''' + # Only effective on the first call + if self.prepared: + return self.prepared + + # setup() must have run if not self.ready: - message = "algorithm `%s' is not yet setup" % (self.name,) exc = self.exc or RuntimeError - raise self.exc(message) + raise exc("Algorithm '%s' is not yet setup" % self.name) - if not hasattr(self.obj, 'prepare'): + # Not available in API version 1 + if self.algorithm.api_version == 1: + self.prepared = True return True - return loader.run(self.obj, 'prepare', self.exc, *args, **kwargs) + # The method is optional + if hasattr(self.obj, 'prepare'): + self.prepared = loader.run(self.obj, 'prepare', self.exc, data_loaders) + else: + self.prepared = True + return self.prepared - def process(self, *args, **kwargs): + + def process(self, inputs=None, data_loaders=None, outputs=None, output=None): '''Runs through data''' + exc = self.exc or RuntimeError + + def _check_argument(argument, name): + if argument is None: + raise exc('Missing argument: %s' % name) + + # setup() must have run if not self.ready: - message = "algorithm `%s' is not yet setup" % (self.name,) - exc = self.exc or RuntimeError - raise self.exc(message) + raise exc("Algorithm '%s' is not yet setup" % self.name) - return loader.run(self.obj, 'process', self.exc, *args, **kwargs) + # prepare() must have run + if not self.prepared: + raise exc("Algorithm '%s' is not yet prepared" % self.name) + + # Call the correct version of process() + if self.algorithm.isAnalyzer: + _check_argument(output, 'output') + outputs_to_use = output + else: + _check_argument(outputs, 'outputs') + outputs_to_use = outputs + + if self.algorithm.type == Algorithm.LEGACY: + _check_argument(inputs, 'inputs') + return loader.run(self.obj, 'process', self.exc, inputs, outputs_to_use) + + else: + _check_argument(data_loaders, 'data_loaders') + + if self.algorithm.type == Algorithm.SEQUENTIAL: + _check_argument(inputs, 'inputs') + return loader.run(self.obj, 'process', self.exc, inputs, data_loaders, + outputs_to_use) + + elif self.algorithm.type == Algorithm.AUTONOMOUS: + return loader.run(self.obj, 'process', self.exc, data_loaders, + outputs_to_use) + + else: + raise exc('Unknown algorithm type: %s' % self.algorithm.type) def __getattr__(self, key): @@ -568,6 +609,11 @@ class Algorithm(object): return value + @property + def isAnalyzer(self): + return (self.results is not None) + + @property def results(self): return self.data.get('results') @@ -601,6 +647,67 @@ class Algorithm(object): return value + @property + def description(self): + """The short description for this object""" + return self.data.get('description', None) + + + @description.setter + def description(self, value): + """Sets the short description for this object""" + self.data['description'] = value + + + @property + def documentation(self): + """The full-length description for this object""" + + if not self._name: + raise RuntimeError("algorithm has no name") + + if self.storage.doc.exists(): + return self.storage.doc.load() + return None + + + @documentation.setter + def documentation(self, value): + """Sets the full-length description for this object""" + + if not self._name: + raise RuntimeError("algorithm has no name") + + if hasattr(value, 'read'): + self.storage.doc.save(value.read()) + else: + self.storage.doc.save(value) + + + def hash(self): + """Returns the hexadecimal hash for the current algorithm""" + + if not self._name: + raise RuntimeError("algorithm has no name") + + return self.storage.hash() + + + def result_dataformat(self): + """Generates, on-the-fly, the dataformat for the result readout""" + + if not self.results: + raise TypeError("algorithm `%s' is a block algorithm, not an analyzer" \ + % (self.name)) + + format = dataformat.DataFormat(self.prefix, + dict([(k, v['type']) for k,v in self.results.items()])) + + format.name = 'analysis:' + self.name + + return format + + def uses_dict(self): """Returns the usage dictionary for all dependent modules""" @@ -665,64 +772,3 @@ class Algorithm(object): raise #just re-raise the user exception return Runner(self.__module, klass, self, exc) - - - @property - def description(self): - """The short description for this object""" - return self.data.get('description', None) - - - @description.setter - def description(self, value): - """Sets the short description for this object""" - self.data['description'] = value - - - @property - def documentation(self): - """The full-length description for this object""" - - if not self._name: - raise RuntimeError("algorithm has no name") - - if self.storage.doc.exists(): - return self.storage.doc.load() - return None - - - @documentation.setter - def documentation(self, value): - """Sets the full-length description for this object""" - - if not self._name: - raise RuntimeError("algorithm has no name") - - if hasattr(value, 'read'): - self.storage.doc.save(value.read()) - else: - self.storage.doc.save(value) - - - def hash(self): - """Returns the hexadecimal hash for the current algorithm""" - - if not self._name: - raise RuntimeError("algorithm has no name") - - return self.storage.hash() - - - def result_dataformat(self): - """Generates, on-the-fly, the dataformat for the result readout""" - - if not self.results: - raise TypeError("algorithm `%s' is a block algorithm, not an analyzer" \ - % (self.name)) - - format = dataformat.DataFormat(self.prefix, - dict([(k, v['type']) for k,v in self.results.items()])) - - format.name = 'analysis:' + self.name - - return format diff --git a/beat/backend/python/data_loaders.py b/beat/backend/python/data_loaders.py index b1953b3..ecf1a57 100755 --- a/beat/backend/python/data_loaders.py +++ b/beat/backend/python/data_loaders.py @@ -323,8 +323,8 @@ class DataLoaderList(object): if isinstance(name_or_index, six.string_types): return [x for x in self._loaders if x.channel == name_or_index][0] - elif isinstance(index, int): - return self._loaders[index] + elif isinstance(name_or_index, int): + return self._loaders[name_or_index] except: pass @@ -345,3 +345,12 @@ class DataLoaderList(object): return [ k for k in self._loaders if input_name in k.input_names() ][0] except: return None + + + def secondaries(self): + secondaries_list = DataLoaderList() + for data_loader in self._loaders: + if data_loader is not self.main_loader: + secondaries_list.add(data_loader) + + return secondaries_list diff --git a/beat/backend/python/loader.py b/beat/backend/python/loader.py old mode 100644 new mode 100755 index c0abeef..9b8efbc --- a/beat/backend/python/loader.py +++ b/beat/backend/python/loader.py @@ -69,6 +69,9 @@ def load_module(name, path, uses): return retval +#---------------------------------------------------------- + + def run(obj, method, exc=None, *args, **kwargs): '''Runs a method on the object and protects its execution @@ -96,7 +99,9 @@ def run(obj, method, exc=None, *args, **kwargs): ''' try: - if method == '__new__': return obj(*args, **kwargs) + if method == '__new__': + return obj(*args, **kwargs) + return getattr(obj, method)(*args, **kwargs) except Exception as e: if exc is not None: diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/add/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/add/1.json new file mode 100644 index 0000000..0ec3448 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/add/1.json @@ -0,0 +1,30 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "parameters": { + "sync": { + "default": "in1", + "type": "string" + } + }, + "groups": [ + { + "inputs": { + "in1": { + "type": "user/single_integer/1" + }, + "in2": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/add/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/add/1.py new file mode 100755 index 0000000..349c623 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/add/1.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + self.sync = parameters['sync'] + return True + + + def process(self, data_loaders, outputs): + data_loader = data_loaders.loaderOf('in1') + + for i in range(data_loader.count(self.sync)): + view = data_loader.view(self.sync, i) + + (data, start, end) = view[view.count() - 1] + + outputs['out'].write({ + 'value': data['in1'].value + data['in2'].value, + }, + end + ) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/add2/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/add2/1.json new file mode 100644 index 0000000..966623e --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/add2/1.json @@ -0,0 +1,28 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "in1": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + }, + { + "inputs": { + "in2": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/add2/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/add2/1.py new file mode 100755 index 0000000..2b82381 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/add2/1.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def prepare(self, data_loaders): + data_loader = data_loaders.loaderOf('in2') + + (data, start, end) = data_loader[0] + self.offset = data['in2'].value + + return True + + + def process(self, data_loaders, outputs): + data_loader = data_loaders.loaderOf('in1') + + for i in range(data_loader.count()): + (data, start, end) = data_loader[i] + + outputs['out'].write({ + 'value': data['in1'].value + self.offset, + }, + end + ) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/add3/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/add3/1.json new file mode 100644 index 0000000..cefb5e0 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/add3/1.json @@ -0,0 +1,31 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "value": { + "type": "user/single_integer/1" + }, + "offset_index": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + }, + { + "inputs": { + "offset": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/add3/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/add3/1.py new file mode 100755 index 0000000..c04edf4 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/add3/1.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def process(self, data_loaders, outputs): + values = data_loaders.loaderOf('value') + offsets = data_loaders.loaderOf('offset') + + for i in range(values.count()): + (data, start, end) = values[i] + offset_index = data['offset_index'].value + + (data2, start2, end2) = offsets[offset_index] + + outputs['out'].write({ + 'value': data['value'].value + data2['offset'].value, + }, + end + ) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/echo/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/echo/1.json new file mode 100644 index 0000000..43f7a57 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/echo/1.json @@ -0,0 +1,21 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "in": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/echo/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/echo/1.py new file mode 100755 index 0000000..d174603 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/echo/1.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def process(self, data_loaders, outputs): + data_loader = data_loaders.loaderOf('in') + + for i in range(data_loader.count()): + (data, start, end) = data_loader[i] + + outputs['out'].write({ + 'value': data['in'].value, + }, + end + ) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.json new file mode 100644 index 0000000..aff2ffc --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.py new file mode 100755 index 0000000..d370eab --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/no_prepare/1.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def process(self, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.json new file mode 100644 index 0000000..aff2ffc --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.py new file mode 100755 index 0000000..9fd8278 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/no_setup/1.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2017 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.backend.python module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + + +class Algorithm: + + def prepare(self, data_loaders): + return True + + def process(self, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.json new file mode 100644 index 0000000..76b1227 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.json @@ -0,0 +1,279 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ], + "parameters": { + "int8_value": { + "default": "5", + "type": "int8", + "description": "Some comment" + }, + "int8_range": { + "default": "6", + "range": [ + 0, + "10" + ], + "type": "int8", + "description": "Another comment" + }, + "int8_choices": { + "default": "4", + "type": "int8", + "choice": [ + "2", + "4", + "6", + "8", + "10" + ] + }, + "int16_value": { + "default": "500", + "type": "int16" + }, + "int16_range": { + "default": "300", + "type": "int16", + "range": [ + "0", + "1000" + ] + }, + "int16_choices": { + "default": "400", + "type": "int16", + "choice": [ + "200", + "400", + "600", + "800", + "1000" + ] + }, + "int16_choices2": { + "default": "400", + "type": "int16", + "choice": [ + "600", + "400" + ] + }, + "int32_value": { + "default": "500000", + "type": "int32" + }, + "int32_range": { + "default": "500000", + "type": "int32", + "range": [ + "0", + "1000000" + ] + }, + "int32_choices": { + "default": "400000", + "type": "int32", + "choice": [ + "200000", + "400000", + "600000", + "800000", + "1000000" + ] + }, + "int64_value": { + "default": "5000000000", + "type": "int64" + }, + "int64_range": { + "default": "5000000000", + "type": "int64", + "range": [ + "0", + "10000000000" + ] + }, + "int64_choices": { + "default": "4000000000", + "type": "int64", + "choice": [ + "2000000000", + "4000000000", + "6000000000", + "8000000000", + "10000000000" + ] + }, + "uint8_value": { + "default": "5", + "type": "uint8" + }, + "uint8_range": { + "default": "6", + "type": "uint8", + "range": [ + "0", + "10" + ] + }, + "uint8_choices": { + "default": "4", + "type": "uint8", + "choice": [ + "2", + "4", + "6", + "8", + "10" + ] + }, + "uint16_value": { + "default": "500", + "type": "uint16" + }, + "uint16_range": { + "default": "500", + "type": "uint16", + "range": [ + "0", + "1000" + ] + }, + "uint16_choices": { + "default": "400", + "type": "uint16", + "choice": [ + "200", + "400", + "600", + "800", + "1000" + ] + }, + "uint32_value": { + "default": "500000", + "type": "uint32" + }, + "uint32_range": { + "default": "500000", + "type": "uint32", + "range": [ + "0", + "1000000" + ] + }, + "uint32_choices": { + "default": "400000", + "type": "uint32", + "choice": [ + "200000", + "400000", + "600000", + "800000", + "1000000" + ] + }, + "uint64_value": { + "default": "5000000000", + "type": "uint64" + }, + "uint64_range": { + "default": "5000000000", + "type": "uint64", + "range": [ + "0", + "10000000000" + ] + }, + "uint64_choices": { + "default": "4000000000", + "type": "uint64", + "choice": [ + "2000000000", + "4000000000", + "6000000000", + "8000000000", + "10000000000" + ] + }, + "float32_value": { + "default": "0.0", + "type": "float32" + }, + "float32_range": { + "default": "0.0", + "type": "float32", + "range": [ + "-10.0", + "10.0" + ] + }, + "float32_choices": { + "default": "0.0", + "type": "float32", + "choice": [ + "-10.0", + "-5.0", + "0.0", + "5.0", + "10.0" + ] + }, + "float64_value": { + "default": "0.0", + "type": "float64" + }, + "float64_range": { + "default": "0.0", + "type": "float64", + "range": [ + "-100.0", + "100.0" + ] + }, + "float64_choices": { + "default": "0.0", + "type": "float64", + "choice": [ + -10.0, + -5.0, + 0.0, + 5.0, + 10.0 + ] + }, + "bool_value": { + "default": true, + "type": "bool" + }, + "string_value": { + "default": "choice1", + "type": "string", + "choice": [ + "choice1", + "choice2", + "choice3" + ] + } + } +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.py new file mode 100755 index 0000000..7d14e79 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/parametrized/1.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + self.int8_value = parameters['int8_value'] + self.int8_range = parameters['int8_range'] + self.int8_choices = parameters['int8_choices'] + self.int16_value = parameters['int16_value'] + self.int16_range = parameters['int16_range'] + self.int16_choices = parameters['int16_choices'] + self.int32_value = parameters['int32_value'] + self.int32_range = parameters['int32_range'] + self.int32_choices = parameters['int32_choices'] + self.int64_value = parameters['int64_value'] + self.int64_range = parameters['int64_range'] + self.int64_choices = parameters['int64_choices'] + self.uint8_value = parameters['uint8_value'] + self.uint8_range = parameters['uint8_range'] + self.uint8_choices = parameters['uint8_choices'] + self.uint16_value = parameters['uint16_value'] + self.uint16_range = parameters['uint16_range'] + self.uint16_choices = parameters['uint16_choices'] + self.uint32_value = parameters['uint32_value'] + self.uint32_range = parameters['uint32_range'] + self.uint32_choices = parameters['uint32_choices'] + self.uint64_value = parameters['uint64_value'] + self.uint64_range = parameters['uint64_range'] + self.uint64_choices = parameters['uint64_choices'] + self.float32_value = parameters['float32_value'] + self.float32_range = parameters['float32_range'] + self.float32_choices = parameters['float32_choices'] + self.float64_value = parameters['float64_value'] + self.float64_range = parameters['float64_range'] + self.float64_choices = parameters['float64_choices'] + self.bool_value = parameters['bool_value'] + self.string_value = parameters['string_value'] + return True + + def process(self, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/prepare_crash/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_crash/1.json new file mode 100644 index 0000000..aff2ffc --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_crash/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__with_delay/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_crash/1.py old mode 100644 new mode 100755 similarity index 89% rename from beat/backend/python/test/prefix/algorithms/legacy/one_stream__with_delay/1.py rename to beat/backend/python/test/prefix/algorithms/autonomous/prepare_crash/1.py index b5b0603..31e0108 --- a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__with_delay/1.py +++ b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_crash/1.py @@ -27,13 +27,9 @@ class Algorithm: - def __init__(self): - self.delayed = True - - def process(self, inputs, outputs): - if not(self.delayed): - outputs['out_data'].write(inputs['in_data'].data) - - self.delayed = not(self.delayed) + def prepare(self, data_loaders): + a = b + return True + def process(self, data_loaders, outputs): return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.json new file mode 100644 index 0000000..aff2ffc --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.py new file mode 100755 index 0000000..80f1093 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/prepare_fail/1.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def prepare(self, data_loaders): + return False + + def process(self, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.json new file mode 100644 index 0000000..aff2ffc --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.py new file mode 100755 index 0000000..42e46f7 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/setup_crash/1.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + a = b + return True + + def process(self, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.json b/beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.json new file mode 100644 index 0000000..aff2ffc --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "autonomous", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.py b/beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.py new file mode 100755 index 0000000..8d515da --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/autonomous/setup_fail/1.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + return False + + def process(self, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/legacy/add/1.json b/beat/backend/python/test/prefix/algorithms/legacy/add/1.json new file mode 100644 index 0000000..51ba4f2 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/legacy/add/1.json @@ -0,0 +1,27 @@ +{ + "language": "python", + "splittable": false, + "parameters": { + "sync": { + "default": "in1", + "type": "string" + } + }, + "groups": [ + { + "inputs": { + "in1": { + "type": "user/single_integer/1" + }, + "in2": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/legacy/add/1.py b/beat/backend/python/test/prefix/algorithms/legacy/add/1.py new file mode 100755 index 0000000..6715932 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/legacy/add/1.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + self.sync = parameters['sync'] + return True + + + def process(self, inputs, outputs): + if inputs[self.sync].isDataUnitDone(): + outputs['out'].write({ + 'value': inputs['in1'].data.value + inputs['in2'].data.value, + }) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/legacy/add2/1.json b/beat/backend/python/test/prefix/algorithms/legacy/add2/1.json new file mode 100644 index 0000000..20715dc --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/legacy/add2/1.json @@ -0,0 +1,25 @@ +{ + "language": "python", + "splittable": false, + "groups": [ + { + "inputs": { + "in1": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + }, + { + "inputs": { + "in2": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__with_delay/1.py b/beat/backend/python/test/prefix/algorithms/legacy/add2/1.py old mode 100644 new mode 100755 similarity index 87% rename from beat/backend/python/test/prefix/algorithms/legacy/two_streams__with_delay/1.py rename to beat/backend/python/test/prefix/algorithms/legacy/add2/1.py index 6bf327a..f177cb9 --- a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__with_delay/1.py +++ b/beat/backend/python/test/prefix/algorithms/legacy/add2/1.py @@ -28,15 +28,16 @@ class Algorithm: def __init__(self): - self.delayed = True + self.offset = None def process(self, inputs, outputs): - if not(self.delayed): - outputs['out_data'].write({ - 'value': inputs['in_data1'].data.value + \ - inputs['in_data2'].data.value - }) + if self.offset is None: + group = inputs.groupOf('in2') + group.next() + self.offset = group['in2'].data.value - self.delayed = not(self.delayed) + outputs['out'].write({ + 'value': inputs['in1'].data.value + self.offset, + }) return True diff --git a/beat/backend/python/test/prefix/algorithms/legacy/echo/1.json b/beat/backend/python/test/prefix/algorithms/legacy/echo/1.json new file mode 100644 index 0000000..bb8eb85 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/legacy/echo/1.json @@ -0,0 +1,18 @@ +{ + "language": "python", + "splittable": false, + "groups": [ + { + "inputs": { + "in": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__no_delay/1.py b/beat/backend/python/test/prefix/algorithms/legacy/echo/1.py old mode 100644 new mode 100755 similarity index 97% rename from beat/backend/python/test/prefix/algorithms/legacy/one_stream__no_delay/1.py rename to beat/backend/python/test/prefix/algorithms/legacy/echo/1.py index fe18d9e..abb54cd --- a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__no_delay/1.py +++ b/beat/backend/python/test/prefix/algorithms/legacy/echo/1.py @@ -28,5 +28,5 @@ class Algorithm: def process(self, inputs, outputs): - outputs['out_data'].write(inputs['in_data'].data) + outputs['out'].write(inputs['in'].data) return True diff --git a/beat/backend/python/test/prefix/algorithms/legacy/no_setup/1.json b/beat/backend/python/test/prefix/algorithms/legacy/no_setup/1.json new file mode 100644 index 0000000..56a6ac5 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/legacy/no_setup/1.json @@ -0,0 +1,22 @@ +{ + "schema_version": 1, + "language": "python", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__no_delay/1.py b/beat/backend/python/test/prefix/algorithms/legacy/no_setup/1.py similarity index 92% rename from beat/backend/python/test/prefix/algorithms/legacy/two_streams__no_delay/1.py rename to beat/backend/python/test/prefix/algorithms/legacy/no_setup/1.py index 148f1d3..f7f6f5b 100644 --- a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__no_delay/1.py +++ b/beat/backend/python/test/prefix/algorithms/legacy/no_setup/1.py @@ -28,8 +28,4 @@ class Algorithm: def process(self, inputs, outputs): - outputs['out_data'].write({ - 'value': inputs['in_data1'].data.value + \ - inputs['in_data2'].data.value - }) return True diff --git a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__no_delay/1.json b/beat/backend/python/test/prefix/algorithms/legacy/one_stream__no_delay/1.json deleted file mode 100644 index eefa07c..0000000 --- a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__no_delay/1.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "language": "python", - "splittable": false, - "groups": [ - { - "inputs": { - "in_data": { - "type": "user/single_integer/1" - } - }, - "outputs": { - "out_data": { - "type": "user/single_integer/1" - } - } - } - ] -} diff --git a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__with_delay/1.json b/beat/backend/python/test/prefix/algorithms/legacy/one_stream__with_delay/1.json deleted file mode 100644 index eefa07c..0000000 --- a/beat/backend/python/test/prefix/algorithms/legacy/one_stream__with_delay/1.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "language": "python", - "splittable": false, - "groups": [ - { - "inputs": { - "in_data": { - "type": "user/single_integer/1" - } - }, - "outputs": { - "out_data": { - "type": "user/single_integer/1" - } - } - } - ] -} diff --git a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__no_delay/1.json b/beat/backend/python/test/prefix/algorithms/legacy/two_streams__no_delay/1.json deleted file mode 100644 index 1a269cb..0000000 --- a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__no_delay/1.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "language": "python", - "splittable": false, - "groups": [ - { - "inputs": { - "in_data1": { - "type": "user/single_integer/1" - }, - "in_data2": { - "type": "user/single_integer/1" - } - }, - "outputs": { - "out_data": { - "type": "user/single_integer/1" - } - } - } - ] -} diff --git a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__with_delay/1.json b/beat/backend/python/test/prefix/algorithms/legacy/two_streams__with_delay/1.json deleted file mode 100644 index 1a269cb..0000000 --- a/beat/backend/python/test/prefix/algorithms/legacy/two_streams__with_delay/1.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "language": "python", - "splittable": false, - "groups": [ - { - "inputs": { - "in_data1": { - "type": "user/single_integer/1" - }, - "in_data2": { - "type": "user/single_integer/1" - } - }, - "outputs": { - "out_data": { - "type": "user/single_integer/1" - } - } - } - ] -} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/add/1.json b/beat/backend/python/test/prefix/algorithms/sequential/add/1.json new file mode 100644 index 0000000..9f4576d --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/add/1.json @@ -0,0 +1,30 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "parameters": { + "sync": { + "default": "in1", + "type": "string" + } + }, + "groups": [ + { + "inputs": { + "in1": { + "type": "user/single_integer/1" + }, + "in2": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/sequential/add/1.py b/beat/backend/python/test/prefix/algorithms/sequential/add/1.py new file mode 100755 index 0000000..a15f151 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/add/1.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + self.sync = parameters['sync'] + return True + + + def process(self, inputs, data_loaders, outputs): + if inputs[self.sync].isDataUnitDone(): + outputs['out'].write({ + 'value': inputs['in1'].data.value + inputs['in2'].data.value, + }) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/add2/1.json b/beat/backend/python/test/prefix/algorithms/sequential/add2/1.json new file mode 100644 index 0000000..69d95bf --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/add2/1.json @@ -0,0 +1,28 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "in1": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + }, + { + "inputs": { + "in2": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/sequential/add2/1.py b/beat/backend/python/test/prefix/algorithms/sequential/add2/1.py new file mode 100755 index 0000000..97e4cce --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/add2/1.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def prepare(self, data_loaders): + data_loader = data_loaders.loaderOf('in2') + + (data, start, end) = data_loader[0] + self.offset = data['in2'].value + + return True + + + def process(self, inputs, data_loaders, outputs): + outputs['out'].write({ + 'value': inputs['in1'].data.value + self.offset, + }) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/add3/1.json b/beat/backend/python/test/prefix/algorithms/sequential/add3/1.json new file mode 100644 index 0000000..a462096 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/add3/1.json @@ -0,0 +1,31 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "value": { + "type": "user/single_integer/1" + }, + "offset_index": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + }, + { + "inputs": { + "offset": { + "type": "user/single_integer/1" + } + } + } + ] +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/sequential/add3/1.py b/beat/backend/python/test/prefix/algorithms/sequential/add3/1.py new file mode 100755 index 0000000..48b1f04 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/add3/1.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def process(self, inputs, data_loaders, outputs): + offset_index = inputs['offset_index'].data.value + + data_loader = data_loaders.loaderOf('offset') + (data, start, end) = data_loader[offset_index] + + outputs['out'].write({ + 'value': inputs['value'].data.value + data['offset'].value, + }) + + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/echo/1.json b/beat/backend/python/test/prefix/algorithms/sequential/echo/1.json new file mode 100644 index 0000000..a3cdc95 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/echo/1.json @@ -0,0 +1,21 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "in": { + "type": "user/single_integer/1" + } + }, + "outputs": { + "out": { + "type": "user/single_integer/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/echo/1.py b/beat/backend/python/test/prefix/algorithms/sequential/echo/1.py new file mode 100755 index 0000000..24e904a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/echo/1.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def process(self, inputs, data_loaders, outputs): + outputs['out'].write(inputs['in'].data) + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.json b/beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.json new file mode 100644 index 0000000..b5f8d0a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.py b/beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.py new file mode 100755 index 0000000..9d1ec26 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/no_prepare/1.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def process(self, inputs, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.json b/beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.json new file mode 100644 index 0000000..b5f8d0a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.py b/beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.py new file mode 100755 index 0000000..9fd8278 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/no_setup/1.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2017 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.backend.python module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + + +class Algorithm: + + def prepare(self, data_loaders): + return True + + def process(self, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.json b/beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.json new file mode 100644 index 0000000..7041137 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.json @@ -0,0 +1,279 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ], + "parameters": { + "int8_value": { + "default": "5", + "type": "int8", + "description": "Some comment" + }, + "int8_range": { + "default": "6", + "range": [ + 0, + "10" + ], + "type": "int8", + "description": "Another comment" + }, + "int8_choices": { + "default": "4", + "type": "int8", + "choice": [ + "2", + "4", + "6", + "8", + "10" + ] + }, + "int16_value": { + "default": "500", + "type": "int16" + }, + "int16_range": { + "default": "300", + "type": "int16", + "range": [ + "0", + "1000" + ] + }, + "int16_choices": { + "default": "400", + "type": "int16", + "choice": [ + "200", + "400", + "600", + "800", + "1000" + ] + }, + "int16_choices2": { + "default": "400", + "type": "int16", + "choice": [ + "600", + "400" + ] + }, + "int32_value": { + "default": "500000", + "type": "int32" + }, + "int32_range": { + "default": "500000", + "type": "int32", + "range": [ + "0", + "1000000" + ] + }, + "int32_choices": { + "default": "400000", + "type": "int32", + "choice": [ + "200000", + "400000", + "600000", + "800000", + "1000000" + ] + }, + "int64_value": { + "default": "5000000000", + "type": "int64" + }, + "int64_range": { + "default": "5000000000", + "type": "int64", + "range": [ + "0", + "10000000000" + ] + }, + "int64_choices": { + "default": "4000000000", + "type": "int64", + "choice": [ + "2000000000", + "4000000000", + "6000000000", + "8000000000", + "10000000000" + ] + }, + "uint8_value": { + "default": "5", + "type": "uint8" + }, + "uint8_range": { + "default": "6", + "type": "uint8", + "range": [ + "0", + "10" + ] + }, + "uint8_choices": { + "default": "4", + "type": "uint8", + "choice": [ + "2", + "4", + "6", + "8", + "10" + ] + }, + "uint16_value": { + "default": "500", + "type": "uint16" + }, + "uint16_range": { + "default": "500", + "type": "uint16", + "range": [ + "0", + "1000" + ] + }, + "uint16_choices": { + "default": "400", + "type": "uint16", + "choice": [ + "200", + "400", + "600", + "800", + "1000" + ] + }, + "uint32_value": { + "default": "500000", + "type": "uint32" + }, + "uint32_range": { + "default": "500000", + "type": "uint32", + "range": [ + "0", + "1000000" + ] + }, + "uint32_choices": { + "default": "400000", + "type": "uint32", + "choice": [ + "200000", + "400000", + "600000", + "800000", + "1000000" + ] + }, + "uint64_value": { + "default": "5000000000", + "type": "uint64" + }, + "uint64_range": { + "default": "5000000000", + "type": "uint64", + "range": [ + "0", + "10000000000" + ] + }, + "uint64_choices": { + "default": "4000000000", + "type": "uint64", + "choice": [ + "2000000000", + "4000000000", + "6000000000", + "8000000000", + "10000000000" + ] + }, + "float32_value": { + "default": "0.0", + "type": "float32" + }, + "float32_range": { + "default": "0.0", + "type": "float32", + "range": [ + "-10.0", + "10.0" + ] + }, + "float32_choices": { + "default": "0.0", + "type": "float32", + "choice": [ + "-10.0", + "-5.0", + "0.0", + "5.0", + "10.0" + ] + }, + "float64_value": { + "default": "0.0", + "type": "float64" + }, + "float64_range": { + "default": "0.0", + "type": "float64", + "range": [ + "-100.0", + "100.0" + ] + }, + "float64_choices": { + "default": "0.0", + "type": "float64", + "choice": [ + -10.0, + -5.0, + 0.0, + 5.0, + 10.0 + ] + }, + "bool_value": { + "default": true, + "type": "bool" + }, + "string_value": { + "default": "choice1", + "type": "string", + "choice": [ + "choice1", + "choice2", + "choice3" + ] + } + } +} \ No newline at end of file diff --git a/beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.py b/beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.py new file mode 100755 index 0000000..544cf2a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/parametrized/1.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + self.int8_value = parameters['int8_value'] + self.int8_range = parameters['int8_range'] + self.int8_choices = parameters['int8_choices'] + self.int16_value = parameters['int16_value'] + self.int16_range = parameters['int16_range'] + self.int16_choices = parameters['int16_choices'] + self.int32_value = parameters['int32_value'] + self.int32_range = parameters['int32_range'] + self.int32_choices = parameters['int32_choices'] + self.int64_value = parameters['int64_value'] + self.int64_range = parameters['int64_range'] + self.int64_choices = parameters['int64_choices'] + self.uint8_value = parameters['uint8_value'] + self.uint8_range = parameters['uint8_range'] + self.uint8_choices = parameters['uint8_choices'] + self.uint16_value = parameters['uint16_value'] + self.uint16_range = parameters['uint16_range'] + self.uint16_choices = parameters['uint16_choices'] + self.uint32_value = parameters['uint32_value'] + self.uint32_range = parameters['uint32_range'] + self.uint32_choices = parameters['uint32_choices'] + self.uint64_value = parameters['uint64_value'] + self.uint64_range = parameters['uint64_range'] + self.uint64_choices = parameters['uint64_choices'] + self.float32_value = parameters['float32_value'] + self.float32_range = parameters['float32_range'] + self.float32_choices = parameters['float32_choices'] + self.float64_value = parameters['float64_value'] + self.float64_range = parameters['float64_range'] + self.float64_choices = parameters['float64_choices'] + self.bool_value = parameters['bool_value'] + self.string_value = parameters['string_value'] + return True + + def process(self, inputs, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.json b/beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.json new file mode 100644 index 0000000..b5f8d0a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.py b/beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.py new file mode 100755 index 0000000..774b49e --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/prepare_crash/1.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def prepare(self, data_loaders): + a = b + return True + + def process(self, inputs, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.json b/beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.json new file mode 100644 index 0000000..b5f8d0a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.py b/beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.py new file mode 100755 index 0000000..6a0f92b --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/prepare_fail/1.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def prepare(self, data_loaders): + return False + + def process(self, inputs, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.json b/beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.json new file mode 100644 index 0000000..b5f8d0a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.py b/beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.py new file mode 100755 index 0000000..20bd342 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/setup_crash/1.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + a = b + return True + + def process(self, inputs, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.json b/beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.json new file mode 100644 index 0000000..b5f8d0a --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.json @@ -0,0 +1,24 @@ +{ + "schema_version": 2, + "language": "python", + "api_version": 2, + "type": "sequential", + "splittable": false, + "groups": [ + { + "inputs": { + "images": { + "type": "user/2d_array_of_integers/1" + }, + "labels": { + "type": "user/floats/1" + } + }, + "outputs": { + "features": { + "type": "user/1d_array_of_integers/1" + } + } + } + ] +} diff --git a/beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.py b/beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.py new file mode 100755 index 0000000..e9a2814 --- /dev/null +++ b/beat/backend/python/test/prefix/algorithms/sequential/setup_fail/1.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +############################################################################### +# # +# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.core module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +class Algorithm: + + def setup(self, parameters): + return False + + def process(self, inputs, data_loaders, outputs): + return True diff --git a/beat/backend/python/test/test_algorithm.py b/beat/backend/python/test/test_algorithm.py index 6bac5b7..2d84296 100644 --- a/beat/backend/python/test/test_algorithm.py +++ b/beat/backend/python/test/test_algorithm.py @@ -26,11 +26,28 @@ ############################################################################### -import six import unittest +import six +import os +import glob +import tempfile +import numpy as np from ..algorithm import Algorithm - +from ..data_loaders import DataLoaderList +from ..data_loaders import DataLoader +from ..dataformat import DataFormat +from ..data import CachedDataSink +from ..data import CachedDataSource +from ..data import CachedFileLoader +from ..inputs import Input +from ..inputs import InputGroup +from ..inputs import InputList +from ..outputs import Output +from ..outputs import OutputList +from ..outputs import SynchronizationListener + +from .mocks import MockDataSink from . import prefix @@ -85,6 +102,7 @@ class TestLegacyAPI_Loading(unittest.TestCase): runnable = algorithm.runner() self.assertTrue(runnable.ready) #no setup + self.assertTrue(runnable.prepared) def test_load_valid_analyser(self): @@ -111,6 +129,7 @@ class TestLegacyAPI_Loading(unittest.TestCase): runnable = algorithm.runner() self.assertTrue(runnable.ready) #no setup + self.assertTrue(runnable.prepared) def test_hash(self): @@ -176,6 +195,7 @@ class TestSequentialAPI_Loading(unittest.TestCase): runnable = algorithm.runner() self.assertFalse(runnable.ready) + self.assertFalse(runnable.prepared) def test_load_valid_analyser(self): @@ -202,6 +222,7 @@ class TestSequentialAPI_Loading(unittest.TestCase): runnable = algorithm.runner() self.assertFalse(runnable.ready) + self.assertFalse(runnable.prepared) #---------------------------------------------------------- @@ -225,6 +246,7 @@ class TestAutonomousAPI_Loading(unittest.TestCase): runnable = algorithm.runner() self.assertFalse(runnable.ready) + self.assertFalse(runnable.prepared) def test_load_valid_analyser(self): @@ -251,6 +273,7 @@ class TestAutonomousAPI_Loading(unittest.TestCase): runnable = algorithm.runner() self.assertFalse(runnable.ready) + self.assertFalse(runnable.prepared) #---------------------------------------------------------- @@ -258,8 +281,13 @@ class TestAutonomousAPI_Loading(unittest.TestCase): class TestLegacyAPI_Setup(unittest.TestCase): + def __init__(self, methodName='runTest'): + super(TestLegacyAPI_Setup, self).__init__(methodName) + self.username = 'legacy' + + def test_setup_crashing_algorithm(self): - algorithm = Algorithm(prefix, 'legacy/setup_crash/1') + algorithm = Algorithm(prefix, self.username + '/setup_crash/1') self.assertTrue(algorithm.valid) runnable = algorithm.runner() @@ -270,7 +298,7 @@ class TestLegacyAPI_Setup(unittest.TestCase): def test_setup_failing_algorithm(self): - algorithm = Algorithm(prefix, 'legacy/setup_fail/1') + algorithm = Algorithm(prefix, self.username + '/setup_fail/1') self.assertTrue(algorithm.valid) runnable = algorithm.runner() @@ -280,7 +308,7 @@ class TestLegacyAPI_Setup(unittest.TestCase): def test_setup_nonparametrized_algorithm(self): - algorithm = Algorithm(prefix, 'legacy/valid_algorithm/1') + algorithm = Algorithm(prefix, self.username + '/no_setup/1') self.assertTrue(algorithm.valid) runnable = algorithm.runner() @@ -290,7 +318,7 @@ class TestLegacyAPI_Setup(unittest.TestCase): def test_setup_parametrized_algorithm_default_values(self): - algorithm = Algorithm(prefix, 'legacy/parametrized/1') + algorithm = Algorithm(prefix, self.username + '/parametrized/1') self.assertTrue(algorithm.valid) runnable = algorithm.runner() @@ -323,7 +351,7 @@ class TestLegacyAPI_Setup(unittest.TestCase): def test_setup_parametrized_algorithm_customized_values(self): - algorithm = Algorithm(prefix, 'legacy/parametrized/1') + algorithm = Algorithm(prefix, self.username + '/parametrized/1') self.assertTrue(algorithm.valid) runnable = algorithm.runner() @@ -364,7 +392,7 @@ class TestLegacyAPI_Setup(unittest.TestCase): def test_setup_parametrized_algorithm_out_of_range_value(self): - algorithm = Algorithm(prefix, 'legacy/parametrized/1') + algorithm = Algorithm(prefix, self.username + '/parametrized/1') self.assertTrue(algorithm.valid) runnable = algorithm.runner() @@ -377,7 +405,7 @@ class TestLegacyAPI_Setup(unittest.TestCase): def test_setup_parametrized_algorithm_invalid_choice_value(self): - algorithm = Algorithm(prefix, 'legacy/parametrized/1') + algorithm = Algorithm(prefix, self.username + '/parametrized/1') self.assertTrue(algorithm.valid) runnable = algorithm.runner() @@ -387,3 +415,805 @@ class TestLegacyAPI_Setup(unittest.TestCase): self.assertTrue(runnable.setup(dict( string_value='unknown', ))) + + +#---------------------------------------------------------- + + +class TestSequentialAPI_Setup(TestLegacyAPI_Setup): + + def __init__(self, methodName='runTest'): + super(TestSequentialAPI_Setup, self).__init__(methodName) + self.username = 'sequential' + + +#---------------------------------------------------------- + + +class TestAutonomousAPI_Setup(TestLegacyAPI_Setup): + + def __init__(self, methodName='runTest'): + super(TestAutonomousAPI_Setup, self).__init__(methodName) + self.username = 'sequential' + + +#---------------------------------------------------------- + + +class TestLegacyAPI_Prepare(unittest.TestCase): + + def test_always_prepared(self): + algorithm = Algorithm(prefix, 'legacy/valid_algorithm/1') + self.assertTrue(algorithm.valid) + + runnable = algorithm.runner() + self.assertTrue(runnable.prepared) + self.assertTrue(runnable.prepare(DataLoaderList())) + self.assertTrue(runnable.prepared) + + +#---------------------------------------------------------- + + +class TestSequentialAPI_Prepare(unittest.TestCase): + + def __init__(self, methodName='runTest'): + super(TestSequentialAPI_Prepare, self).__init__(methodName) + self.username = 'sequential' + + + def test_prepare_crashing_algorithm(self): + algorithm = Algorithm(prefix, self.username + '/prepare_crash/1') + self.assertTrue(algorithm.valid) + + runnable = algorithm.runner() + self.assertTrue(runnable.ready) + + self.assertFalse(runnable.prepared) + + with self.assertRaises(NameError): + runnable.prepare(DataLoaderList()) + + + def test_prepare_failing_algorithm(self): + algorithm = Algorithm(prefix, self.username + '/prepare_fail/1') + self.assertTrue(algorithm.valid) + + runnable = algorithm.runner() + self.assertTrue(runnable.ready) + + self.assertFalse(runnable.prepared) + self.assertFalse(runnable.prepare(DataLoaderList())) + self.assertFalse(runnable.prepared) + + + def test_no_preparation_algorithm(self): + algorithm = Algorithm(prefix, self.username + '/no_prepare/1') + self.assertTrue(algorithm.valid) + + runnable = algorithm.runner() + self.assertTrue(runnable.ready) + + self.assertTrue(runnable.prepared) + self.assertTrue(runnable.prepare(DataLoaderList())) + self.assertTrue(runnable.prepared) + + +#---------------------------------------------------------- + + +class TestAutonomousAPI_Prepare(TestSequentialAPI_Prepare): + + def __init__(self, methodName='runTest'): + super(TestAutonomousAPI_Prepare, self).__init__(methodName) + self.username = 'autonomous' + + +#---------------------------------------------------------- + + +class TestExecutionBase(unittest.TestCase): + + def setUp(self): + self.filenames = {} + + + def tearDown(self): + for f in self.filenames.values(): + basename, ext = os.path.splitext(f) + filenames = [f] + filenames += glob.glob(basename + '*') + for filename in filenames: + if os.path.exists(filename): + os.unlink(filename) + + + def writeData(self, input_name, indices, start_value): + testfile = tempfile.NamedTemporaryFile(prefix=__name__ + input_name, suffix='.data') + testfile.close() # preserve only the name + self.filenames[input_name] = testfile.name + + dataformat = DataFormat(prefix, 'user/single_integer/1') + self.assertTrue(dataformat.valid) + + data_sink = CachedDataSink() + self.assertTrue(data_sink.setup(self.filenames[input_name], dataformat)) + + for i in indices: + data = dataformat.type() + data.value = np.int32(start_value + i[0]) + data_sink.write(data, i[0], i[1]) + + (nb_bytes, duration) = data_sink.statistics() + self.assertTrue(nb_bytes > 0) + self.assertTrue(duration > 0) + + data_sink.close() + del data_sink + + +#---------------------------------------------------------- + + +class TestLegacyAPI_Process(TestExecutionBase): + + def create_io(self, infos): + dataformat = DataFormat(prefix, 'user/single_integer/1') + + synchronization_listener = SynchronizationListener() + + # Inputs + inputs = InputList() + + for group_name, group_inputs in infos.items(): + if len(inputs) == 0: + group = InputGroup(group_name, synchronization_listener, True) + else: + group = InputGroup(group_name, None, False) + + inputs.add(group) + + for input_name in group_inputs: + data_source = CachedDataSource() + data_source.setup(self.filenames[input_name], prefix) + group.add(Input(input_name, dataformat, data_source)) + + # Outputs + outputs = OutputList() + + data_sink = MockDataSink(dataformat) + outputs.add(Output('out', data_sink, synchronization_listener)) + + return (inputs, outputs, data_sink) + + + def test_one_group_of_one_input(self): + self.writeData('in', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + + (inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in', + ], + }) + + algorithm = Algorithm(prefix, 'legacy/echo/1') + runner = algorithm.runner() + + group = inputs.main_group + + while group.hasMoreData(): + group.restricted_access = False + group.next() + group.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + for i in range(0, 4): + self.assertEqual(data_sink.written[i].start, i) + self.assertEqual(data_sink.written[i].end, i) + self.assertEqual(data_sink.written[i].data.value, 1000 + i) + + + def test_one_group_of_two_inputs_1(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 1), (2, 3)], 2000) + + (inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'legacy/add/1') + runner = algorithm.runner() + + self.assertTrue(runner.setup({ + 'sync': 'in1', + })) + + group = inputs.main_group + + while group.hasMoreData(): + group.restricted_access = False + group.next() + group.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 3000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 3004) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3005) + + + def test_one_group_of_two_inputs_2(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 1), (2, 3)], 2000) + + (inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'legacy/add/1') + runner = algorithm.runner() + + self.assertTrue(runner.setup({ + 'sync': 'in2', + })) + + group = inputs.main_group + + while group.hasMoreData(): + group.restricted_access = False + group.next() + group.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 2) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3005) + + + def test_two_groups_of_one_input(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 3)], 2000) + + (inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + ], + 'group2': [ + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'legacy/add2/1') + runner = algorithm.runner() + + group = inputs.main_group + + while group.hasMoreData(): + group.restricted_access = False + group.next() + group.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 3000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 3002) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3003) + + +#---------------------------------------------------------- + + +class TestSequentialAPI_Process(TestExecutionBase): + + def create_io(self, infos): + dataformat = DataFormat(prefix, 'user/single_integer/1') + + synchronization_listener = SynchronizationListener() + + # Data loaders & inputs + inputs = None + data_loaders = DataLoaderList() + + for group_name, group_inputs in infos.items(): + if inputs is None: + inputs = InputGroup(group_name, synchronization_listener, True) + + for input_name in group_inputs: + data_source = CachedDataSource() + data_source.setup(self.filenames[input_name], prefix) + inputs.add(Input(input_name, dataformat, data_source)) + + else: + data_loader = DataLoader(group_name) + data_loaders.add(data_loader) + + for input_name in group_inputs: + cached_file = CachedFileLoader() + cached_file.setup(self.filenames[input_name], prefix) + data_loader.add(input_name, cached_file) + + # Outputs + outputs = OutputList() + + data_sink = MockDataSink(dataformat) + outputs.add(Output('out', data_sink, synchronization_listener)) + + return (data_loaders, inputs, outputs, data_sink) + + + def test_one_group_of_one_input(self): + self.writeData('in', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + + (data_loaders, inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in', + ], + }) + + algorithm = Algorithm(prefix, 'sequential/echo/1') + runner = algorithm.runner() + + self.assertTrue(runner.prepare(data_loaders=data_loaders)) + + while inputs.hasMoreData(): + inputs.restricted_access = False + inputs.next() + inputs.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + for i in range(0, 4): + self.assertEqual(data_sink.written[i].start, i) + self.assertEqual(data_sink.written[i].end, i) + self.assertEqual(data_sink.written[i].data.value, 1000 + i) + + + def test_one_group_of_two_inputs_1(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 1), (2, 3)], 2000) + + (data_loaders, inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'sequential/add/1') + runner = algorithm.runner() + + self.assertTrue(runner.setup({ + 'sync': 'in1', + })) + + self.assertTrue(runner.prepare(data_loaders=data_loaders)) + + while inputs.hasMoreData(): + inputs.restricted_access = False + inputs.next() + inputs.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 3000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 3004) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3005) + + + def test_one_group_of_two_inputs_2(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 1), (2, 3)], 2000) + + (data_loaders, inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'sequential/add/1') + runner = algorithm.runner() + + self.assertTrue(runner.setup({ + 'sync': 'in2', + })) + + self.assertTrue(runner.prepare(data_loaders=data_loaders)) + + while inputs.hasMoreData(): + inputs.restricted_access = False + inputs.next() + inputs.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 2) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3005) + + + def test_two_groups_of_one_input(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 3)], 2000) + + (data_loaders, inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + ], + 'group2': [ + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'sequential/add2/1') + runner = algorithm.runner() + + self.assertTrue(runner.prepare(data_loaders=data_loaders)) + + while inputs.hasMoreData(): + inputs.restricted_access = False + inputs.next() + inputs.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 3000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 3002) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3003) + + + def test_two_groups_of_related_inputs(self): + self.writeData('value', [(0, 0), (1, 1), (2, 2), (3, 3)], 0) # 0, 1, 2, 3 + self.writeData('offset_index', [(0, 0), (1, 2), (3, 3)], 0) # 0, 1, 3 + self.writeData('offset', [(0, 0), (1, 5), (6, 10), (11, 11)], 2000) # 2000, 2001, 2006, 2011 + + (data_loaders, inputs, outputs, data_sink) = self.create_io({ + 'group1': [ + 'value', + 'offset_index', + ], + 'group2': [ + 'offset', + ], + }) + + algorithm = Algorithm(prefix, 'sequential/add3/1') + runner = algorithm.runner() + + self.assertTrue(runner.prepare(data_loaders=data_loaders)) + + while inputs.hasMoreData(): + inputs.restricted_access = False + inputs.next() + inputs.restricted_access = True + self.assertTrue(runner.process(inputs=inputs, data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 2000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 2002) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 2003) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 2014) + + +#---------------------------------------------------------- + + +class TestAutonomousAPI_Process(TestExecutionBase): + + def create_io(self, infos): + dataformat = DataFormat(prefix, 'user/single_integer/1') + + # Data loaders + data_loaders = DataLoaderList() + + for group_name, group_inputs in infos.items(): + data_loader = DataLoader(group_name) + data_loaders.add(data_loader) + + for input_name in group_inputs: + cached_file = CachedFileLoader() + cached_file.setup(self.filenames[input_name], prefix) + data_loader.add(input_name, cached_file) + + # Outputs + outputs = OutputList() + + data_sink = MockDataSink(dataformat) + outputs.add(Output('out', data_sink)) + + return (data_loaders, outputs, data_sink) + + + def test_one_group_of_one_input(self): + self.writeData('in', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + + (data_loaders, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in', + ], + }) + + algorithm = Algorithm(prefix, 'autonomous/echo/1') + runner = algorithm.runner() + + self.assertTrue(runner.prepare(data_loaders=data_loaders.secondaries())) + self.assertTrue(runner.process(data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + for i in range(0, 4): + self.assertEqual(data_sink.written[i].start, i) + self.assertEqual(data_sink.written[i].end, i) + self.assertEqual(data_sink.written[i].data.value, 1000 + i) + + + def test_one_group_of_two_inputs_1(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 1), (2, 3)], 2000) + + (data_loaders, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'autonomous/add/1') + runner = algorithm.runner() + + self.assertTrue(runner.setup({ + 'sync': 'in1', + })) + + self.assertTrue(runner.prepare(data_loaders=data_loaders.secondaries())) + self.assertTrue(runner.process(data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 3000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 3004) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3005) + + + def test_one_group_of_two_inputs_2(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 1), (2, 3)], 2000) + + (data_loaders, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'autonomous/add/1') + runner = algorithm.runner() + + self.assertTrue(runner.setup({ + 'sync': 'in2', + })) + + self.assertTrue(runner.prepare(data_loaders=data_loaders.secondaries())) + self.assertTrue(runner.process(data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 2) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3005) + + + def test_two_groups_of_one_input(self): + self.writeData('in1', [(0, 0), (1, 1), (2, 2), (3, 3)], 1000) + self.writeData('in2', [(0, 3)], 2000) + + (data_loaders, outputs, data_sink) = self.create_io({ + 'group1': [ + 'in1', + ], + 'group2': [ + 'in2', + ], + }) + + algorithm = Algorithm(prefix, 'autonomous/add2/1') + runner = algorithm.runner() + + self.assertTrue(runner.prepare(data_loaders=data_loaders.secondaries())) + self.assertTrue(runner.process(data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 3000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 3001) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 3002) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 3003) + + + def test_two_groups_of_related_inputs(self): + self.writeData('value', [(0, 0), (1, 1), (2, 2), (3, 3)], 0) # 0, 1, 2, 3 + self.writeData('offset_index', [(0, 0), (1, 2), (3, 3)], 0) # 0, 1, 3 + self.writeData('offset', [(0, 0), (1, 5), (6, 10), (11, 11)], 2000) # 2000, 2001, 2006, 2011 + + (data_loaders, outputs, data_sink) = self.create_io({ + 'group1': [ + 'value', + 'offset_index', + ], + 'group2': [ + 'offset', + ], + }) + + algorithm = Algorithm(prefix, 'autonomous/add3/1') + runner = algorithm.runner() + + self.assertTrue(runner.prepare(data_loaders=data_loaders.secondaries())) + self.assertTrue(runner.process(data_loaders=data_loaders, outputs=outputs)) + + self.assertEqual(len(data_sink.written), 4) + + data_unit = data_sink.written[0] + self.assertEqual(data_unit.start, 0) + self.assertEqual(data_unit.end, 0) + self.assertEqual(data_unit.data.value, 2000) + + data_unit = data_sink.written[1] + self.assertEqual(data_unit.start, 1) + self.assertEqual(data_unit.end, 1) + self.assertEqual(data_unit.data.value, 2002) + + data_unit = data_sink.written[2] + self.assertEqual(data_unit.start, 2) + self.assertEqual(data_unit.end, 2) + self.assertEqual(data_unit.data.value, 2003) + + data_unit = data_sink.written[3] + self.assertEqual(data_unit.start, 3) + self.assertEqual(data_unit.end, 3) + self.assertEqual(data_unit.data.value, 2014) diff --git a/beat/backend/python/test/test_data_loaders.py b/beat/backend/python/test/test_data_loaders.py index b784bb7..6823fdf 100644 --- a/beat/backend/python/test/test_data_loaders.py +++ b/beat/backend/python/test/test_data_loaders.py @@ -33,6 +33,7 @@ import tempfile import numpy as np from ..data_loaders import DataLoader +from ..data_loaders import DataLoaderList from ..dataformat import DataFormat from ..data import CachedDataSink from ..data import CachedFileLoader @@ -43,7 +44,7 @@ from . import prefix #---------------------------------------------------------- -class DataLoaderTest(unittest.TestCase): +class DataLoaderBaseTest(unittest.TestCase): def setUp(self): self.filenames = {} @@ -83,6 +84,11 @@ class DataLoaderTest(unittest.TestCase): del data_sink +#---------------------------------------------------------- + + +class DataLoaderTest(DataLoaderBaseTest): + def test_creation(self): data_loader = DataLoader('channel1') @@ -647,3 +653,116 @@ class DataLoaderTest(unittest.TestCase): view = data_loader.view('input2', 2) self.assertTrue(view is None) + +#---------------------------------------------------------- + + +class DataLoaderListTest(DataLoaderBaseTest): + + def test_creation(self): + data_loaders = DataLoaderList() + + self.assertTrue(data_loaders.main_loader is None) + self.assertEqual(len(data_loaders), 0) + + + def test_list_unkown_loader_retrieval(self): + data_loaders = DataLoaderList() + self.assertTrue(data_loaders['unknown'] is None) + + + def test_list_invalid_index_retrieval(self): + data_loaders = DataLoaderList() + self.assertTrue(data_loaders[10] is None) + + + def test_list_loader_of_unknown_input_retrieval(self): + data_loaders = DataLoaderList() + self.assertTrue(data_loaders.loaderOf('unknown') is None) + + + def test_list_one_loader_one_input(self): + self.writeData('input1', [(0, 0), (1, 1), (2, 2)], 1000) + + data_loader = DataLoader('channel1') + + cached_file = CachedFileLoader() + cached_file.setup(self.filenames['input1'], prefix) + data_loader.add('input1', cached_file) + + data_loaders = DataLoaderList() + data_loaders.add(data_loader) + + self.assertEqual(data_loaders.main_loader, data_loader) + self.assertEqual(len(data_loaders), 1) + + self.assertEqual(data_loaders['channel1'], data_loader) + self.assertEqual(data_loaders[0], data_loader) + + self.assertEqual(data_loaders.loaderOf('input1'), data_loader) + + + def test_list_one_loader_two_inputs(self): + self.writeData('input1', [(0, 0), (1, 1), (2, 2)], 1000) + self.writeData('input2', [(0, 2)], 2000) + + data_loader = DataLoader('channel1') + + cached_file = CachedFileLoader() + cached_file.setup(self.filenames['input1'], prefix) + data_loader.add('input1', cached_file) + + cached_file = CachedFileLoader() + cached_file.setup(self.filenames['input2'], prefix) + data_loader.add('input2', cached_file) + + data_loaders = DataLoaderList() + data_loaders.add(data_loader) + + self.assertEqual(data_loaders.main_loader, data_loader) + self.assertEqual(len(data_loaders), 1) + + self.assertEqual(data_loaders['channel1'], data_loader) + self.assertEqual(data_loaders[0], data_loader) + + self.assertEqual(data_loaders.loaderOf('input1'), data_loader) + self.assertEqual(data_loaders.loaderOf('input2'), data_loader) + + + def test_list_two_loaders_three_inputs(self): + self.writeData('input1', [(0, 0), (1, 1), (2, 2)], 1000) + self.writeData('input2', [(0, 2)], 2000) + self.writeData('input3', [(0, 1), (2, 2)], 3000) + + data_loader1 = DataLoader('channel1') + + cached_file = CachedFileLoader() + cached_file.setup(self.filenames['input1'], prefix) + data_loader1.add('input1', cached_file) + + cached_file = CachedFileLoader() + cached_file.setup(self.filenames['input2'], prefix) + data_loader1.add('input2', cached_file) + + data_loader2 = DataLoader('channel2') + + cached_file = CachedFileLoader() + cached_file.setup(self.filenames['input3'], prefix) + data_loader2.add('input3', cached_file) + + data_loaders = DataLoaderList() + data_loaders.add(data_loader1) + data_loaders.add(data_loader2) + + self.assertEqual(data_loaders.main_loader, data_loader1) + self.assertEqual(len(data_loaders), 2) + + self.assertEqual(data_loaders['channel1'], data_loader1) + self.assertEqual(data_loaders['channel2'], data_loader2) + + self.assertEqual(data_loaders[0], data_loader1) + self.assertEqual(data_loaders[1], data_loader2) + + self.assertEqual(data_loaders.loaderOf('input1'), data_loader1) + self.assertEqual(data_loaders.loaderOf('input2'), data_loader1) + self.assertEqual(data_loaders.loaderOf('input3'), data_loader2) diff --git a/beat/backend/python/test/test_inputs.py b/beat/backend/python/test/test_inputs.py index 5d51fbd..04dc89f 100644 --- a/beat/backend/python/test/test_inputs.py +++ b/beat/backend/python/test/test_inputs.py @@ -741,7 +741,7 @@ class InputListTest(unittest.TestCase): self.assertTrue(inputs['unknown'] is None) - def test_list_group_of_unkown_input_retrieval(self): + def test_list_group_of_unknown_input_retrieval(self): inputs = InputList() self.assertTrue(inputs.groupOf('unknown') is None) diff --git a/beat/backend/python/test/test_synchronization.py b/beat/backend/python/test/test_synchronization.py deleted file mode 100644 index df592e8..0000000 --- a/beat/backend/python/test/test_synchronization.py +++ /dev/null @@ -1,424 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : - -############################################################################### -# # -# Copyright (c) 2017 Idiap Research Institute, http://www.idiap.ch/ # -# Contact: beat.support@idiap.ch # -# # -# This file is part of the beat.backend.python module of the BEAT platform. # -# # -# Commercial License Usage # -# Licensees holding valid commercial BEAT licenses may use this file in # -# accordance with the terms contained in a written agreement between you # -# and Idiap. For further information contact tto@idiap.ch # -# # -# Alternatively, this file may be used under the terms of the GNU Affero # -# Public License version 3 as published by the Free Software and appearing # -# in the file LICENSE.AGPL included in the packaging of this file. # -# The BEAT platform is distributed in the hope that it will be useful, but # -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # -# or FITNESS FOR A PARTICULAR PURPOSE. # -# # -# You should have received a copy of the GNU Affero Public License along # -# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # -# # -############################################################################### - - -import six -import numpy -import nose.tools - -from .mocks import MockDataSource, MockDataSink - -from ..inputs import Input, InputGroup, InputList -from ..outputs import Output, OutputList, SynchronizationListener -from ..dataformat import DataFormat -from ..algorithm import Algorithm - -from . import prefix - - -#---------------------------------------------------------- - - -def test_one_full_stream__no_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 6)), [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]) - group.add(Input('in_data', dataformat, data_source1)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/one_stream__no_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 6) - - for i in six.moves.range(0, 6): - nose.tools.eq_(data_sink1.written[i].start, i) # 0, 1, 2, 3, 4, 5 - nose.tools.eq_(data_sink1.written[i].end, i) # 0, 1, 2, 3, 4, 5 - nose.tools.eq_(data_sink1.written[i].data.value, i) # 0, 1, 2, 3, 4, 5 - - -#---------------------------------------------------------- - - -def test_one_delayed_stream__no_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 3)), [(0, 1), (2, 3), (4, 5)]) - group.add(Input('in_data', dataformat, data_source1)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/one_stream__no_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 3) - - for i in six.moves.range(0, 3): - nose.tools.eq_(data_sink1.written[i].start, i * 2) # 0, 2, 4 - nose.tools.eq_(data_sink1.written[i].end, i * 2 + 1) # 1, 3, 5 - nose.tools.eq_(data_sink1.written[i].data.value, i) # 0, 1, 2 - - -#---------------------------------------------------------- - - -def test_one_full_stream__with_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 6)), [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]) - group.add(Input('in_data', dataformat, data_source1)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/one_stream__with_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 3) - - for i in six.moves.range(0, 3): - nose.tools.eq_(data_sink1.written[i].start, i * 2) # 0, 2, 4 - nose.tools.eq_(data_sink1.written[i].end, i * 2 + 1) # 1, 3, 5 - nose.tools.eq_(data_sink1.written[i].data.value, i * 2 + 1) # 1, 3, 5 - - -#---------------------------------------------------------- - - -def test_one_delayed_stream__with_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 6)), [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11)]) - group.add(Input('in_data', 'single_integer', data_source1)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/one_stream__with_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 3) - - for i in six.moves.range(0, 3): - nose.tools.eq_(data_sink1.written[i].start, i * 4) # 0, 4, 8 - nose.tools.eq_(data_sink1.written[i].end, i * 4 + 3) # 3, 7, 11 - nose.tools.eq_(data_sink1.written[i].data.value, i * 2 + 1) # 1, 3, 5 - - -#---------------------------------------------------------- - - -def test_two_aligned_streams__no_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 6)), [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]) - group.add(Input('in_data1', 'single_integer', data_source1)) - - data_source2 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x * 10)), six.moves.range(0, 3)), [(0, 1), (2, 3), (4, 5)]) - group.add(Input('in_data2', 'single_integer', data_source2)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/two_streams__no_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 6) - - values = [0, 1, 12, 13, 24, 25] - - for i in six.moves.range(0, 6): - nose.tools.eq_(data_sink1.written[i].start, i) # 0, 1, 2, 3, 4, 5 - nose.tools.eq_(data_sink1.written[i].end, i) # 0, 1, 2, 3, 4, 5 - nose.tools.eq_(data_sink1.written[i].data.value, values[i]) - - -#---------------------------------------------------------- - - -def test_two_aligned_streams__with_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 6)), [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]) - group.add(Input('in_data1', 'single_integer', data_source1)) - - data_source2 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x * 10)), six.moves.range(0, 3)), [(0, 1), (2, 3), (4, 5)]) - group.add(Input('in_data2', 'single_integer', data_source2)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/two_streams__with_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 3) - - values = [1, 13, 25] - - for i in six.moves.range(0, 3): - nose.tools.eq_(data_sink1.written[i].start, i * 2) # 0, 2, 4 - nose.tools.eq_(data_sink1.written[i].end, i * 2 + 1) # 1, 3, 5 - nose.tools.eq_(data_sink1.written[i].data.value, values[i]) - - -#---------------------------------------------------------- - - -def test_two_unaligned_streams__no_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 6)), [(0, 2), (3, 5), (6, 8), (9, 11), (12, 14), (15, 17)]) - group.add(Input('in_data1', 'single_integer', data_source1)) - - data_source2 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x * 10)), six.moves.range(0, 4)), [(0, 4), (5, 9), (10, 13), (14, 17)]) - group.add(Input('in_data2', 'single_integer', data_source2)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/two_streams__no_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 9) - - starts = [0, 3, 5, 6, 9, 10, 12, 14, 15] - ends = [2, 4, 5, 8, 9, 11, 13, 14, 17] - values = [0, 1, 11, 12, 13, 23, 24, 34, 35] - - for i in six.moves.range(0, 9): - nose.tools.eq_(data_sink1.written[i].start, starts[i]) - nose.tools.eq_(data_sink1.written[i].end, ends[i]) - nose.tools.eq_(data_sink1.written[i].data.value, values[i]) - - -#---------------------------------------------------------- - - -def test_two_unaligned_streams__with_delay(): - - dataformat = DataFormat(prefix, 'user/single_integer/1') - assert dataformat.valid - - synchronization_listener = SynchronizationListener() - - # Inputs - inputs = InputList() - - group = InputGroup('channel1', synchronization_listener) - inputs.add(group) - - data_source1 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x)), six.moves.range(0, 7)), [(0, 2), (3, 5), (6, 8), (9, 11), (12, 14), (15, 17), (18, 20)]) - group.add(Input('in_data1', 'single_integer', data_source1)) - - data_source2 = MockDataSource(map(lambda x: dataformat.type(value=numpy.int32(x * 10)), six.moves.range(0, 4)), [(0, 4), (5, 9), (10, 13), (14, 20)]) - group.add(Input('in_data2', 'single_integer', data_source2)) - - # Outputs - outputs = OutputList() - - data_sink1 = MockDataSink(dataformat) - outputs.add(Output('out_data', data_sink1, synchronization_listener)) - - # Algorithm - algorithm = Algorithm(prefix, 'legacy/two_streams__with_delay/1') - assert algorithm.valid, algorithm.errors - runner = algorithm.runner() - assert runner.ready - - while group.hasMoreData(): - group.restricted_access = False - group.next() - group.restricted_access = True - runner.process(inputs, outputs) - - nose.tools.eq_(len(data_sink1.written), 5) - - starts = [0, 5, 9, 12, 15] - ends = [4, 8, 11, 14, 20] - values = [1, 12, 23, 34, 36] - - for i in six.moves.range(0, 5): - nose.tools.eq_(data_sink1.written[i].start, starts[i]) - nose.tools.eq_(data_sink1.written[i].end, ends[i]) - nose.tools.eq_(data_sink1.written[i].data.value, values[i]) -- GitLab