Skip to content
Snippets Groups Projects
Commit 55e82fa5 authored by Samuel GAIST's avatar Samuel GAIST
Browse files

[algorithm] Split LOOP_USER in autonomous and sequential types

This will give the developer the choice of how
they want their loop user to work.
parent 2a846868
Branches
Tags
1 merge request!55New loop user types
......@@ -214,7 +214,10 @@ class Runner(object):
# The method is optional
if hasattr(self.obj, "prepare"):
if self.algorithm.type in [Algorithm.AUTONOMOUS, Algorithm.LOOP_USER]:
if self.algorithm.type in [
Algorithm.AUTONOMOUS,
Algorithm.AUTONOMOUS_LOOP_USER,
]:
self.prepared = loader.run(
self.obj, "prepare", self.exc, data_loaders.secondaries()
)
......@@ -264,35 +267,40 @@ class Runner(object):
else:
_check_argument(data_loaders, "data_loaders")
if self.algorithm.type == Algorithm.SEQUENTIAL:
if self.algorithm.is_sequential:
_check_argument(inputs, "inputs")
return loader.run(
self.obj, "process", self.exc, inputs, data_loaders, outputs_to_use
)
run_args = [
self.obj,
"process",
self.exc,
inputs,
data_loaders,
outputs_to_use,
]
elif self.algorithm.is_autonomous:
run_args = [self.obj, "process", self.exc, data_loaders, outputs_to_use]
has_loop_arg = utils.has_argument(self.obj.process, "loop_channel")
if loop_channel is not None:
if has_loop_arg:
run_args.append(loop_channel)
else:
raise exc(
"Algorithm '%s' is not a valid loop enabled algorithm"
% self.name
)
elif has_loop_arg:
else:
raise exc("Unknown algorithm type: %s" % self.algorithm.type)
has_loop_arg = utils.has_argument(self.obj.process, "loop_channel")
if loop_channel is not None:
if has_loop_arg:
run_args.append(loop_channel)
else:
raise exc(
"Algorithm '%s' is a loop enabled algorithm but no loop_channel given"
"Algorithm '%s' is not a valid loop enabled algorithm"
% self.name
)
elif has_loop_arg:
raise exc(
"Algorithm '%s' is a loop enabled algorithm but no loop_channel given"
% self.name
)
return loader.run(*run_args)
else:
raise exc("Unknown algorithm type: %s" % self.algorithm.type)
return loader.run(*run_args)
def validate(self, result):
"""Validates the given results"""
......@@ -404,7 +412,8 @@ class Algorithm(object):
SEQUENTIAL = "sequential"
AUTONOMOUS = "autonomous"
LOOP = "loop"
LOOP_USER = "loop_user"
SEQUENTIAL_LOOP_USER = "sequential_loop_user"
AUTONOMOUS_LOOP_USER = "autonomous_loop_user"
def __init__(self, prefix, name, dataformat_cache=None, library_cache=None):
......@@ -672,7 +681,16 @@ class Algorithm(object):
@property
def is_autonomous(self):
""" Returns whether the algorithm is in the autonomous category"""
return self.type in [Algorithm.AUTONOMOUS, Algorithm.LOOP_USER, Algorithm.LOOP]
return self.type in [
Algorithm.AUTONOMOUS,
Algorithm.AUTONOMOUS_LOOP_USER,
Algorithm.LOOP,
]
@property
def is_sequential(self):
""" Returns whether the algorithm is in the sequential category"""
return self.type in [Algorithm.SEQUENTIAL, Algorithm.SEQUENTIAL_LOOP_USER]
@language.setter
def language(self, value):
......
......@@ -2,7 +2,7 @@
"schema_version": 3,
"language": "python",
"api_version": 2,
"type": "loop_user",
"type": "autonomous_loop_user",
"splittable": false,
"groups": [
{
......
{
"schema_version": 3,
"language": "python",
"api_version": 2,
"type": "sequential_loop_user",
"splittable": false,
"groups": [
{
"inputs": {
"in": {
"type": "user/single_integer/1"
}
},
"outputs": {
"out": {
"type": "user/single_integer/1"
}
},
"loop": {
"request": {
"type": "user/single_integer/1"
},
"answer": {
"type": "user/single_integer/1"
}
}
}
]
}
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###################################################################################
# #
# Copyright (c) 2019 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions are met: #
# #
# 1. Redistributions of source code must retain the above copyright notice, this #
# list of conditions and the following disclaimer. #
# #
# 2. Redistributions in binary form must reproduce the above copyright notice, #
# this list of conditions and the following disclaimer in the documentation #
# and/or other materials provided with the distribution. #
# #
# 3. Neither the name of the copyright holder nor the names of its contributors #
# may be used to endorse or promote products derived from this software without #
# specific prior written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE #
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL #
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER #
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, #
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE #
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #
# #
###################################################################################
import numpy as np
class Algorithm:
def process(self, inputs, data_loaders, outputs, loop_channel):
cnt = 10
is_valid, _ = loop_channel.validate({"value": np.int32(cnt)})
while not is_valid:
cnt = cnt - 1
is_valid, _ = loop_channel.validate({"value": np.int32(cnt)})
value = inputs["in"].data.value
new_value = value + cnt
outputs["out"].write({"value": np.int32(new_value)})
return True
Test documentation
......@@ -234,6 +234,24 @@ class TestSequentialAPI_Loading(unittest.TestCase):
self.assertFalse(runnable.ready)
self.assertFalse(runnable.prepared)
def test_load_valid_loop_user(self):
algorithm = Algorithm(prefix, "sequential/loop_user/1")
self.assertEqual(algorithm.name, "sequential/loop_user/1")
self.assertTrue(algorithm.valid)
self.assertFalse(algorithm.errors)
self.assertFalse(algorithm.results) # it is not an analyzer
self.assertFalse(algorithm.parameters) # does not contain parameters
self.assertTrue(algorithm.input_map)
self.assertTrue(algorithm.output_map)
self.assertEqual(algorithm.schema_version, 3)
self.assertEqual(algorithm.api_version, 2)
self.assertEqual(algorithm.type, Algorithm.SEQUENTIAL_LOOP_USER)
runnable = algorithm.runner()
self.assertTrue(runnable.ready)
self.assertTrue(runnable.prepared)
# ----------------------------------------------------------
......@@ -285,6 +303,24 @@ class TestAutonomousAPI_Loading(unittest.TestCase):
self.assertFalse(runnable.ready)
self.assertFalse(runnable.prepared)
def test_load_valid_loop_user(self):
algorithm = Algorithm(prefix, "autonomous/loop_user/1")
self.assertEqual(algorithm.name, "autonomous/loop_user/1")
self.assertTrue(algorithm.valid)
self.assertFalse(algorithm.errors)
self.assertFalse(algorithm.results) # it is not an analyzer
self.assertFalse(algorithm.parameters) # does not contain parameters
self.assertTrue(algorithm.input_map)
self.assertTrue(algorithm.output_map)
self.assertEqual(algorithm.schema_version, 3)
self.assertEqual(algorithm.api_version, 2)
self.assertEqual(algorithm.type, Algorithm.AUTONOMOUS_LOOP_USER)
runnable = algorithm.runner()
self.assertTrue(runnable.ready)
self.assertTrue(runnable.prepared)
# ----------------------------------------------------------
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment