From f58d6f8478d5eecd118ed521d6c5a2f619e5f212 Mon Sep 17 00:00:00 2001 From: Samuel Gaist <samuel.gaist@idiap.ch> Date: Fri, 12 Apr 2019 17:32:57 +0200 Subject: [PATCH] [protocoltemplate] Implement ProcotolTemplate support --- beat/core/protocoltemplate.py | 123 +++++++++++++++++++++++ beat/core/schema/protocoltemplate/1.json | 58 +++++++++++ beat/core/test/test_protocoltemplate.py | 65 ++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 beat/core/protocoltemplate.py create mode 100644 beat/core/schema/protocoltemplate/1.json create mode 100644 beat/core/test/test_protocoltemplate.py diff --git a/beat/core/protocoltemplate.py b/beat/core/protocoltemplate.py new file mode 100644 index 00000000..11574f56 --- /dev/null +++ b/beat/core/protocoltemplate.py @@ -0,0 +1,123 @@ +#!/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. # +# # +################################################################################### + + +""" +================ +protocoltemplate +================ + +Validation of protocoltemplate + +Forward importing from :py:mod:`beat.backend.python.protocoltemplate`: +:py:class:`beat.backend.python.protocoltemplate.Storage` +""" + +import six + +from . import schema + +from beat.backend.python.protocoltemplate import Storage +from beat.backend.python.protocoltemplate import ( + ProtocolTemplate as BackendProtocolTemplate, +) + + +class ProtocolTemplate(BackendProtocolTemplate): + """Protocol template define the design of the database. + + + Parameters: + + prefix (str): Establishes the prefix of your installation. + + data (dict, str): The piece of data representing the protocol templates. + It must validate against the schema defined for protocol templates. If a + string is passed, it is supposed to be a valid path to protocol template + in the designated prefix area. + + dataformat_cache (:py:class:`dict`, Optional): A dictionary mapping + dataformat names to loaded dataformats. This parameter is optional and, + if passed, may greatly speed-up protocol template loading times as + dataformats that are already loaded may be re-used. If you use this + parameter, you must guarantee that the cache is refreshed as appropriate + in case the underlying dataformats change. + + + Attributes: + + name (str): The full, valid name of this protocol template + + description (str): The short description string, loaded from the JSON + file if one was set. + + documentation (str): The full-length docstring for this object. + + storage (object): A simple object that provides information about file + paths for this protocol template + + errors (list): A list containing errors found while loading this + protocol template. + + data (dict): The original data for this protocol template, as loaded by + our JSON decoder. + + """ + + def __init__(self, prefix, data, dataformat_cache=None): + super(ProtocolTemplate, self).__init__(prefix, data, dataformat_cache) + + def _load(self, data, dataformat_cache): + """Loads the database""" + + self._name = None + self.storage = None + self.dataformats = {} # preloaded dataformats + + if isinstance(data, six.string_types): # user has passed a file pointer + + self._name = data + self.storage = Storage(self.prefix, self._name) + data = self.storage.json.path + if not self.storage.json.exists(): + self.errors.append( + "Protocol template declaration file not found: %s" % data + ) + return + + # this runs basic validation, including JSON loading if required + self.data, self.errors = schema.validate("protocoltemplate", data) + if self.errors: + return # don't proceed with the rest of validation diff --git a/beat/core/schema/protocoltemplate/1.json b/beat/core/schema/protocoltemplate/1.json new file mode 100644 index 00000000..07af41a7 --- /dev/null +++ b/beat/core/schema/protocoltemplate/1.json @@ -0,0 +1,58 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Database Protocol descriptor", + "description": "This schema defines the properties of a BEAT database protocol", + + "type": "object", + + "properties": { + + "description": { "$ref": "../common/1.json#/definitions/description" }, + + "schema_version": { "const": 1 }, + + "sets": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "$ref": "#/definitions/set" } + } + + }, + + "required": [ + "schema_version", "sets" + ], + + "additionalProperties": false, + + "definitions": { + + "identifier": { + "type": "string", + "pattern": "^[a-zA-Z_][a-zA-Z0-9_-]*$" + }, + + "set": { + "type": "object", + "properties": { + "name": { "$ref": "#/definitions/identifier" }, + "outputs": { + "type": "object", + "patternProperties": { + "^[a-zA-Z_][a-zA-Z0-9_-]*$": { + "$ref": "../common/1.json#/definitions/reference" + } + }, + "minProperties": 1, + "uniqueItems": true, + "additionalProperties": false + } + }, + "required": ["name", "outputs"], + "additionalProperties": false + } + + } + +} diff --git a/beat/core/test/test_protocoltemplate.py b/beat/core/test/test_protocoltemplate.py new file mode 100644 index 00000000..526a8560 --- /dev/null +++ b/beat/core/test/test_protocoltemplate.py @@ -0,0 +1,65 @@ +#!/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 nose.tools +from ..protocoltemplate import ProtocolTemplate + +from . import prefix, tmp_prefix +from .utils import cleanup + + +def test_export(): + for protocol_name in [ + "double", + "triple", + "two_sets", + "labelled", + "different_frequencies", + ]: + yield export, f"{protocol_name}/1" + + +@nose.tools.with_setup(teardown=cleanup) +def export(protocol_name): + + obj = ProtocolTemplate(prefix, protocol_name) + nose.tools.assert_true(obj.valid, "\n * %s" % "\n * ".join(obj.errors)) + + obj.export(tmp_prefix) + + # load from tmp_prefix and validates + exported = ProtocolTemplate(tmp_prefix, protocol_name) + nose.tools.assert_true(exported.valid, "\n * %s" % "\n * ".join(exported.errors)) -- GitLab