From 8ee8c3a8232668ba4c6873a8d292abe5dd387878 Mon Sep 17 00:00:00 2001
From: Eloy Retamino <retamino@ugr.es>
Date: Tue, 19 Nov 2019 11:50:26 +0000
Subject: [PATCH] Merged in NRRPLT-7739-remove-music (pull request #15)
[NRRPLT-7739] removed music support.
* [NRRPLT-7739] removed music support. music distributed packages kept as tar files.
* [NRRPLT-7739] small fixes
Approved-by: Ugo Albanese <ugo.albanese@santannapisa.it>
Approved-by: Manos Angelidis <angelidis@fortiss.org>
---
Makefile | 8 +-
bitbucket-pipelines.yml | 17 +-
hbp_nrp_distributed_nest/README.txt | 3 +-
hbp_nrp_music_interface/MANIFEST.in | 1 -
hbp_nrp_music_interface/README.txt | 2 -
.../hbp_nrp_music_interface/__init__.py | 8 -
.../hbp_nrp_music_interface/bibi/__init__.py | 4 -
.../bibi/bibi_music_config.py | 245 ------
.../cle/MUSICBrainLoader.py | 112 ---
.../cle/MUSICPyNNCommunicationAdapter.py | 255 ------
.../cle/MUSICPyNNControlAdapter.py | 74 --
.../hbp_nrp_music_interface/cle/__init__.py | 6 -
.../launch/MUSICBrainProcess.py | 166 ----
.../launch/MUSICCLEProcess.py | 86 --
.../launch/MUSICLauncher.py | 118 ---
.../launch/MUSICMPILauncher.py | 53 --
.../launch/__init__.py | 4 -
.../launch/host/LocalLauncher.py | 88 ---
.../launch/host/LuganoLauncher.py | 170 ----
.../launch/host/__init__.py | 3 -
.../hbp_nrp_music_interface/tests/__init__.py | 5 -
.../tests/bibi/__init__.py | 3 -
.../tests/bibi/bibi.xml | 14 -
.../tests/bibi/config.music | 16 -
.../tests/bibi/config.xml | 137 ----
.../tests/bibi/test_bibi_music_config.py | 91 ---
.../tests/cle/__init__.py | 5 -
.../tests/cle/test_brain_loader.py | 67 --
.../tests/cle/test_communication_adapter.py | 89 ---
.../tests/cle/test_control_adapter.py | 62 --
.../tests/launch/__init__.py | 3 -
.../tests/launch/host/__init__.py | 4 -
.../tests/launch/host/test_interface.py | 65 --
.../tests/launch/host/test_local.py | 105 ---
.../tests/launch/host/test_lugano.py | 129 ---
.../tests/launch/test_mpi_launcher.py | 197 -----
.../tests/launch/test_music_launcher.py | 109 ---
.../hbp_nrp_music_interface/version.py | 2 -
hbp_nrp_music_interface/requirements.txt | 3 -
.../requirements_extension_tests.txt | 3 -
hbp_nrp_music_interface/setup.py | 68 --
hbp_nrp_music_interface_deprec.tar.gz | Bin 0 -> 25324 bytes
hbp_nrp_music_xml/MANIFEST.in | 1 -
hbp_nrp_music_xml/README.txt | 5 -
.../hbp_nrp_music_xml/__init__.py | 9 -
.../hbp_nrp_music_xml/config/__init__.py | 6 -
.../hbp_nrp_music_xml/config/music_config.py | 154 ----
.../hbp_nrp_music_xml/pynn/__init__.py | 6 -
.../hbp_nrp_music_xml/pynn/cell_types.py | 58 --
.../pynn/connector_factory.py | 114 ---
.../hbp_nrp_music_xml/pynn/factory.py | 188 -----
.../hbp_nrp_music_xml/pynn/utils.py | 70 --
.../hbp_nrp_music_xml/pynn/xml_factory.py | 249 ------
.../hbp_nrp_music_xml/schema/__init__.py | 5 -
.../schema/generated/__init__.py | 5 -
.../schema/generated/music_xml.py | 743 ------------------
.../hbp_nrp_music_xml/schema/music.xsd | 108 ---
.../hbp_nrp_music_xml/tests/__init__.py | 5 -
.../tests/config/__init__.py | 5 -
.../tests/config/test_music_config.py | 75 --
.../hbp_nrp_music_xml/tests/pynn/__init__.py | 5 -
.../tests/pynn/test_factory.py | 169 ----
.../tests/pynn/test_xml_factory.py | 178 -----
.../hbp_nrp_music_xml/version.py | 2 -
hbp_nrp_music_xml/requirements.txt | 4 -
.../requirements_extension_tests.txt | 3 -
hbp_nrp_music_xml/setup.py | 71 --
hbp_nrp_music_xml_deprec.tar.gz | Bin 0 -> 19985 bytes
verify.sh | 6 +-
69 files changed, 14 insertions(+), 4830 deletions(-)
delete mode 100644 hbp_nrp_music_interface/MANIFEST.in
delete mode 100644 hbp_nrp_music_interface/README.txt
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/bibi_music_config.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICBrainLoader.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNCommunicationAdapter.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNControlAdapter.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/cle/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICCLEProcess.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICMPILauncher.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LocalLauncher.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LuganoLauncher.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/bibi.xml
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.music
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.xml
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/test_bibi_music_config.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_brain_loader.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_communication_adapter.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_control_adapter.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/__init__.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_interface.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_local.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_lugano.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_mpi_launcher.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py
delete mode 100644 hbp_nrp_music_interface/hbp_nrp_music_interface/version.py
delete mode 100644 hbp_nrp_music_interface/requirements.txt
delete mode 100644 hbp_nrp_music_interface/requirements_extension_tests.txt
delete mode 100644 hbp_nrp_music_interface/setup.py
create mode 100644 hbp_nrp_music_interface_deprec.tar.gz
delete mode 100644 hbp_nrp_music_xml/MANIFEST.in
delete mode 100644 hbp_nrp_music_xml/README.txt
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/config/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/config/music_config.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/cell_types.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/connector_factory.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/factory.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/utils.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/xml_factory.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/schema/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/music_xml.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/tests/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/test_music_config.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/__init__.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_factory.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_xml_factory.py
delete mode 100644 hbp_nrp_music_xml/hbp_nrp_music_xml/version.py
delete mode 100644 hbp_nrp_music_xml/requirements.txt
delete mode 100644 hbp_nrp_music_xml/requirements_extension_tests.txt
delete mode 100644 hbp_nrp_music_xml/setup.py
create mode 100644 hbp_nrp_music_xml_deprec.tar.gz
diff --git a/Makefile b/Makefile
index f2d4b3e..91af839 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,14 @@
#modules that have tests
-#TEST_MODULES=hbp_nrp_music_xml/hbp_nrp_music_xml hbp_nrp_music_interface/hbp_nrp_music_interface hbp_nrp_distributed_nest/hbp_nrp_distributed_nest
-# HOTFIX: as import music fails in tests (NRRPLT-6949), remove music packages from the tests
TEST_MODULES=hbp_nrp_distributed_nest/hbp_nrp_distributed_nest
#modules that are installable (ie: ones w/ setup.py)
-INSTALL_MODULES=hbp_nrp_music_xml hbp_nrp_music_interface hbp_nrp_distributed_nest
+INSTALL_MODULES=hbp_nrp_distributed_nest
#packages to cover
-#COVER_PACKAGES=hbp_nrp_music_xml hbp_nrp_music_interface hbp_nrp_distributed_nest
-# HOTFIX: as import music fails in tests (NRRPLT-6949), remove music packages from the tests
COVER_PACKAGES=hbp_nrp_distributed_nest
#documentation to build
-#DOC_MODULES=hbp_nrp_music_xml/doc hbp_nrp_music_interface/doc hbp_nrp_distributed_nest/doc
+#DOC_MODULES=hbp_nrp_distributed_nest/doc
PYTHON_PIP_VERSION?=pip==9.0.3
diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml
index 063cb87..d62b366 100644
--- a/bitbucket-pipelines.yml
+++ b/bitbucket-pipelines.yml
@@ -19,12 +19,12 @@ pipelines:
# Configure build has to be placed before make devinstall
- export VIRTUAL_ENV_PATH=$VIRTUAL_ENV
- export NRP_INSTALL_MODE=dev
- - export PYTHONPATH=hbp_nrp_music_xml:hbp_nrp_music_interface:$VIRTUAL_ENV_PATH/lib/python2.7/site-packages:$PYTHONPATH
+ - export PYTHONPATH=$VIRTUAL_ENV_PATH/lib/python2.7/site-packages:$PYTHONPATH
# Concatenate all build requirements, ensure newline in between
- - (echo; cat $HBP/ExperimentControl/hbp_nrp_excontrol/requirements.txt) >> hbp_nrp_music_interface/requirements.txt
- - (echo; cat $HBP/CLE/hbp_nrp_cle/requirements.txt) >> hbp_nrp_music_interface/requirements.txt
- - (echo; cat $HBP/ExDBackend/hbp_nrp_commons/requirements.txt) >> hbp_nrp_music_interface/requirements.txt
+ - (echo; cat $HBP/ExperimentControl/hbp_nrp_excontrol/requirements.txt) >> hbp_nrp_distributed_nest/requirements.txt
+ - (echo; cat $HBP/CLE/hbp_nrp_cle/requirements.txt) >> hbp_nrp_distributed_nest/requirements.txt
+ - (echo; cat $HBP/ExDBackend/hbp_nrp_commons/requirements.txt) >> hbp_nrp_distributed_nest/requirements.txt
# Checkout config.ini.sample from user-scripts
- cp $HBP/user-scripts/config_files/CLE/config.ini.sample $HBP/CLE/hbp_nrp_cle/hbp_nrp_cle/config.ini
@@ -34,7 +34,7 @@ pipelines:
# Generate schemas
# Egg-links have to be removed because make devinstall set them up wrongly
- - pushd $VIRTUAL_ENV_PATH/lib/python2.7/site-packages && rm -f hbp-nrp-music-interface.egg-link hbp-nrp-music-xml.egg-link hbp-nrp-distributed-nest.egg-link && popd
+ - pushd $VIRTUAL_ENV_PATH/lib/python2.7/site-packages && rm -f hbp-nrp-distributed-nest.egg-link && popd
- make devinstall # Otherwise it can't find pyxbgen
- export pyxb_version=`grep "pyxb" $HBP/ExDBackend/hbp_nrp_commons/requirements.txt`
- . $VIRTUAL_ENV_PATH/bin/activate && pip install ${pyxb_version} && pyxbgen -u $HBP/Experiments/bibi_configuration.xsd -m bibi_api_gen && pyxbgen -u $HBP/Experiments/ExDConfFile.xsd -m exp_conf_api_gen && pyxbgen -u $HBP/Models/robot_model_configuration.xsd -m robot_conf_api_gen && pyxbgen -u $HBP/Models/environment_model_configuration.xsd -m environment_conf_api_gen
@@ -43,11 +43,10 @@ pipelines:
- deactivate
# Run tests
- # HOTFIX: Exclude music packages from pylint because of NRRPLT-6949
- - export IGNORE_LINT='platform_venv|hbp_nrp_music_xml|hbp_nrp_music_interface|hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated|migrations|nest'
+ - export IGNORE_LINT='platform_venv|migrations|nest'
# Egg-links have to be removed because make devinstall set them up wrongly
- - pushd $VIRTUAL_ENV_PATH/lib/python2.7/site-packages && rm -f hbp-nrp-music-interface.egg-link hbp-nrp-music-xml.egg-link hbp-nrp-distributed-nest.egg-link && popd
- - . $VIRTUAL_ENV_PATH/bin/activate && source /opt/ros/kinetic/setup.$CURR_SHELL && echo "PYTHONPATH $PYTHONPATH" && make verify_base || { if [ -f pylint.txt ]; then echo "----------"; echo "PYLINT.TXT"; echo "----------";cat pylint.txt; fi; if [ -f pep8.txt ]; then echo "----------"; echo "PEP8.TXT"; echo "----------";cat pep8.txt; fi; exit 1; }
+ - pushd $VIRTUAL_ENV_PATH/lib/python2.7/site-packages && rm -f hbp-nrp-distributed-nest.egg-link && popd
+ - . $VIRTUAL_ENV_PATH/bin/activate && source /opt/ros/melodic/setup.$CURR_SHELL && echo "PYTHONPATH $PYTHONPATH" && make verify_base || { if [ -f pylint.txt ]; then echo "----------"; echo "PYLINT.TXT"; echo "----------";cat pylint.txt; fi; if [ -f pep8.txt ]; then echo "----------"; echo "PEP8.TXT"; echo "----------";cat pep8.txt; fi; exit 1; }
# Coverage check
- $HBP/admin-scripts/nrp_cobertura_check coverage.xml
diff --git a/hbp_nrp_distributed_nest/README.txt b/hbp_nrp_distributed_nest/README.txt
index 0fb5718..b9e05ae 100644
--- a/hbp_nrp_distributed_nest/README.txt
+++ b/hbp_nrp_distributed_nest/README.txt
@@ -1,2 +1 @@
-This package provides interfaces for standalone distributed Nest simulation without
-any MUSIC dependencies for the CLE/ExDBackend.
\ No newline at end of file
+This package provides interfaces for standalone distributed Nest simulation for the CLE/ExDBackend.
\ No newline at end of file
diff --git a/hbp_nrp_music_interface/MANIFEST.in b/hbp_nrp_music_interface/MANIFEST.in
deleted file mode 100644
index 540b720..0000000
--- a/hbp_nrp_music_interface/MANIFEST.in
+++ /dev/null
@@ -1 +0,0 @@
-include requirements.txt
\ No newline at end of file
diff --git a/hbp_nrp_music_interface/README.txt b/hbp_nrp_music_interface/README.txt
deleted file mode 100644
index 532ebdf..0000000
--- a/hbp_nrp_music_interface/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This package provides interfaces between the generic MUSIC/PyNN hbp_nrp_music_xml
-package and the CLE/ExDBackend by implementing and overriding required interfaces.
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/__init__.py
deleted file mode 100644
index c87a881..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-"""
-This package contains NRP specific implementations utilizing the MUSIC XML configuration
-and PyNN packages.
-"""
-
-from hbp_nrp_music_interface.version import VERSION as __version__ # pylint: disable=W0611
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/__init__.py
deleted file mode 100644
index 227a3db..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""
-This package contains classes to translate from a parsed BIBI specification to
-a MUSIC launch file and XML connectivity specification.
-"""
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/bibi_music_config.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/bibi_music_config.py
deleted file mode 100644
index be3a2de..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/bibi/bibi_music_config.py
+++ /dev/null
@@ -1,245 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Provdes a class to generate a MUSIC configuration from a BIBI configuration.
-"""
-
-from hbp_nrp_commons.generated import bibi_api_gen # pylint:disable=no-name-in-module
-from hbp_nrp_music_xml.schema.generated import music_xml
-from hbp_nrp_music_xml.config.music_config import Application, MusicConfigWriter, MusicConfigPort
-
-import os
-import logging
-
-logger = logging.getLogger(__name__)
-logger.setLevel(logging.DEBUG)
-
-
-class MUSICConfiguration(object):
- """
- This class offers a high-level API for assembling MUSIC configuration that contains
- ports between the Closed-Loop-Engine (CLE) and MUSIC-enabled neuro-simulators.
-
- The MUSIC configuration is assembled by converting a BIBI specification into a
- synapse/neuron specification MUSIC XML representation and also produces a formatted
- MUSIC script that can be used to launch the distributed simulation components.
- """
-
- # FIXME: [NRRPLT-4722] fudge factor for faux dynamic ports
- FAUX_DYNAMIC_FUDGE_FACTOR = 5
-
- def __init__(self, bibi):
- """
- Convert the given BIBI configuration into a MUSIC XML configuration.
-
- :param bibi: A parsed BIBI file to convert.
- """
- assert isinstance(bibi, bibi_api_gen.BIBIConfiguration)
-
- #TODO: The BIBI schema currently does not require population definitions,
- # but they are required to properly generate a BIBI->MUSIC mapping.
- # This check should be removed after the BIBI is updated and consistent
- # for Python and h5 brains.
- if bibi.brainModel.populations is None or len(bibi.brainModel.populations) == 0:
- raise Exception("This BIBI file cannot be used for multi-process simulations "
- "as it does not specify neuron populations in the brainModel "
- "section. Please contact neurorobotics@humanbrainproject.eu if "
- "you require assistance to update this file or restrict this "
- "experiment to single process mode.")
-
- self.__conf_xml = music_xml.root()
- self.__conf_script = None
-
- # construct the bidirectional xml port/synapse definitions
- for bibi_population in bibi.brainModel.populations:
- name = bibi_population.population
- width = MUSICConfiguration.get_neuron_count(bibi_population)
- music_population = self.__bibi_to_music_population(bibi_population)
-
- # FIXME: [NRRPLT-4722] Workaround for lack of dynamic MUSIC ports, allow the user
- # <fudge> the size of the population for devices (the neurons will be frozen
- # by default, which should not impact performance (too much))
- faux_w = width * MUSICConfiguration.FAUX_DYNAMIC_FUDGE_FACTOR
- self.__add_port('%s_to_brain' % name, faux_w, 'CLE', 'BRAIN', name, music_population)
- self.__add_port('%s_to_cle' % name, width, 'BRAIN', 'CLE', name, music_population)
-
- # empty dict of applications, CLE and BRAIN definitions are required
- self.__applications = {}
-
- @staticmethod
- def get_neuron_count(neurons):
- """
- Gets the amount of neurons connected
-
- :param neurons: The neuron selector
- :return: The amount of neurons as int
- """
- if isinstance(neurons, bibi_api_gen.Index):
- return 1
- elif isinstance(neurons, bibi_api_gen.Range):
- if neurons.step is None:
- return neurons.to - neurons.from_
- return (neurons.to - neurons.from_) / neurons.step
- elif isinstance(neurons, bibi_api_gen.List):
- return len(neurons.element)
- elif isinstance(neurons, bibi_api_gen.Population):
- return neurons.count
- raise Exception("Neuron Count: Don't know how to process neuron selector "
- + str(type(neurons)))
-
- def add_application(self, name, binary, args, processes):
- """
- Add a sending or receiving MUSIC application definition.
-
- :param name: The application name, currently only CLE and BRAIN are supported.
- :param binary: The binary to execute for this application.
- :param args: A list of arguments to python.
- :param processes: The number of processes to allocate for this application.
- """
- if name not in ['CLE', 'BRAIN']:
- raise Exception("Invalid application name {name} specified, must be "
- "either CLE or BRAIN.".format(name=name))
-
- if name in self.__applications:
- raise Exception("Duplicate application definition for {name}, this does not "
- "appear to be a valid request.".format(name=name))
-
- self.__applications[name] = Application(name, binary, args, int(processes))
-
- def save(self, path):
- """
- Save the MUSIC XML and application configuration files to the specified directory.
-
- :patam path: The path of the directory to save to.
- """
-
- if 'CLE' not in self.__applications or 'BRAIN' not in self.__applications:
- raise Exception('Missing CLE or BRAIN application definitions, cannote create MUSIC'
- 'configuration script!')
-
- # write the xml connectivity specification to proxy.xml
- proxy_file = os.path.join(path, 'proxy.xml')
- with open(proxy_file, 'w') as f:
- f.write(self.__conf_xml.toxml())
-
- # write the actual music launching script to cle.music
- music_file = os.path.join(path, 'cle.music')
- with open(music_file, 'w') as f:
- ports = [MusicConfigPort(p) for p in self.__conf_xml.port]
- applications = [self.__applications['CLE'], self.__applications['BRAIN']]
- self.__conf_script = MusicConfigWriter(None, applications, ports)
- self.__conf_script.write(f)
-
- @staticmethod # required to avoid "no self use" pylint error
- def __bibi_to_music_population(bibi_population):
- """
- This function converts BIBI NeuronSelector object (population specification) into
- a MUSIC-XML SynapticSelector objects. Currently only Range types are supported in
- population definitions, but this function supports all potential types.
-
- :param bibi_population: A BIBI MultiNeuronSelector object
- """
-
- def make_list_selector(iterable):
- """
- Helper function to create a list of neurons from multiple BIBI selector types.
-
- :param iterable: A list of neuron ids to add to this list selector.
- """
- neuron_list = music_xml.ListSelector()
- for element in iterable:
- neuron_list.append(element)
- return neuron_list
-
- if isinstance(bibi_population, bibi_api_gen.Range):
- neuron_slice = music_xml.SliceSelector()
- neuron_slice.start = bibi_population.from_
- neuron_slice.stop = bibi_population.to
- step = getattr(bibi_population, 'step', 1)
- if not step:
- step = 1
- neuron_slice.step = step
- return neuron_slice
-
- elif isinstance(bibi_population, bibi_api_gen.List):
- return make_list_selector(bibi_population.element)
-
- elif isinstance(bibi_population, bibi_api_gen.Population):
- return make_list_selector(list(range(0, bibi_population.count)))
-
- else:
- raise Exception("The deduction from type {} (for population declaration "
- "'{}') to the MUSIC equivalent population declaration "
- "is not implemented".format(type(bibi_population),
- bibi_population.population))
-
- def __add_port(self, name, width, sender, receiver, target, selector):
- """
- Generates a MUSIC XML spike event port for the named population with given width between
- the specified source and target.
-
- :param name: Base name of the MUSIC port (NOT the population name).
- :param width: The MUSIC port width (number of neurons to
- :param sender: The name of the producing MUSIC application (e.g. CLE, BRAIN)
- :param receiver: The name of the receiving MUSIC application (e.g. CLE, BRAIN)
- :param target: The neuron population name to connect to/from.
- :param selector: The MUSIC XML population selector (e.g. slice/etc.)
- """
-
- if sender not in ['CLE', 'BRAIN'] or receiver not in ['CLE', 'BRAIN']:
- raise Exception("Invalid sender {sender} or receiver {receiver} specified, must be "
- "either CLE or BRAIN.".format(sender=sender, receiver=receiver))
-
- port = music_xml.Port()
- port.type = music_xml.PortType.Event
- port.name = name
- port.width = width
- port.sender = music_xml.Peer(name=sender)
- port.receiver.append(music_xml.Peer(name=receiver))
-
- synapse = music_xml.SynapticConnection()
- synapse.type = music_xml.ConnectionType.one_to_one
- synapse.target = target
- synapse.selector = selector
- port.receiver[0].synapse = [synapse]
-
- logger.debug("Created MUSIC port for spike event proxy: "
- "{sender_name}.{port_name} ---/port_width:{port_width}/---> "
- "{receiver_name}.{port_name}"
- .format(sender_name=port.sender.name, port_width=port.width,
- receiver_name=port.receiver[0].name, port_name=port.name))
-
- self.__conf_xml.port.append(port)
-
- def __str__(self):
- """
- Returns the formatted MUSIC configuration script as a string.
- """
- return str(self.__conf_script)
-
- def xml(self):
- """
- Returns the XML string representation of the underlying generated configuration.
- """
- return str(self.__conf_xml.toxml())
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICBrainLoader.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICBrainLoader.py
deleted file mode 100644
index fd43c6d..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICBrainLoader.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""`
-Load a brain network's MUSIC proxies
-"""
-import pyNN.nest as sim
-import hbp_nrp_cle.tf_framework.config as tf_config
-
-from hbp_nrp_music_xml.pynn.factory import PyNNProxyFactory
-from hbp_nrp_music_xml.pynn.connector_factory import PyNNConnectorFactory
-from hbp_nrp_music_xml.pynn.xml_factory import XmlFactory
-
-import imp
-
-__brainIndex = 0
-
-
-# pylint: disable=global-statement
-def load_proxies_from_xml(xml_file, **populations):
- """
- Load neuron population proxy devices from the specified music_xml file and create a
- mapping between population names and their proxy devices. This will allow the
- communications adapter or any other components to lookup the appropriate input or
- output proxy for a given named population.
-
- :param xml_file: Path to the music_xml ile containing proxy population definitions.
- :param populations: A named list of population proxies to create
- """
-
- # ensure a Python brain module has not been loaded or set
- if tf_config.brain_root is not None:
- raise Exception("A brain module has been loaded in this process, no brain should be"
- "present when loading MUSIC proxies. Invalid configuration, aborting.")
-
- # attempt to read the XML file, abort if doesn't exist or cannot be read
- try:
- with open(xml_file, 'r') as f:
- xml = f.read()
- except IOError:
- raise Exception("Cannot create MUSIC proxy devices for simulation, unable to access "
- "XML specification file {}. Aborting!".format(xml_file))
-
- # simulator specific configuration (not through PyNN, make sure simulator is supported)
- if sim.simulator.name != "NEST":
- raise Exception("Unable to load MUSIC proxy devices for simulator {}, currently only "
- "NEST is supported. Aborting!".format(sim.simulator.name))
-
- # build proxy factories and store a dictionary of built proxies
- proxy_model_factory = PyNNProxyFactory(sim)
- connector_factory = PyNNConnectorFactory(sim)
- xml_factory = XmlFactory("CLE", connector_factory, proxy_model_factory, {})
- proxy_dict = xml_factory.create_proxies(xml)
-
- # create a surrogate python brain module in place of loading the actual brain module
- global __brainIndex
- tf_config.brain_root = imp.new_module('__brain_model{}'.format(__brainIndex))
- __brainIndex += 1
-
- # the CLE will only be able to access named proxy populations that were specified in the BIBI
- # create a population -> proxy dictionary in the tf config so that the communications adapter
- # can appropriately locate and use named input or output proxies as need
- # store a proxy population in the root brain module for each population so that the existing
- # tf framework can create population views without modification - understanding that the
- # communications adapter will replace the base proxy with the input/output population as needed
- try:
- tf_config.music_proxies = {}
-
- for p in populations:
-
- # create population views to mimic how normal neuron populations are created
- proxy_to_brain = proxy_dict['{}_to_brain'.format(p)]
- proxy_to_brain_view = sim.PopulationView(proxy_to_brain,
- slice(0, len(proxy_to_brain), None),
- label=p)
- proxy_to_cle = proxy_dict['{}_to_cle'.format(p)]
- proxy_to_cle_view = sim.PopulationView(proxy_to_cle,
- slice(0, len(proxy_to_cle), None),
- label=p)
-
- # default named proxy population, a named population for p must be in the brain_root
- # dictionary for transfer functions to create slices, but the correct population for
- # a source or sink will be properly selected in the communication adapter, so this
- # specification is arbitrary but definitely required
- tf_config.brain_root.__dict__[p] = proxy_to_brain_view
-
- # store the named proxies by direction
- tf_config.music_proxies[p] = {'source': proxy_to_brain_view, 'sink': proxy_to_cle_view}
-
- except KeyError:
- raise Exception("Could not find proxy-specification of population {} in MUSIC "
- "XML specification file: {}".format(p, xml_file))
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNCommunicationAdapter.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNCommunicationAdapter.py
deleted file mode 100644
index 6588a93..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNCommunicationAdapter.py
+++ /dev/null
@@ -1,255 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Extensions of the base CLE PyNNCommunicationAdapter to use MUSIC specific proxies
-instead of direct population access. Maxmimum code reuse and minimal duplication
-where possible.
-"""
-from hbp_nrp_cle.brainsim.pynn_nest.PyNNNestCommunicationAdapter import PyNNNestCommunicationAdapter
-import pyNN.nest as sim
-import hbp_nrp_cle.tf_framework.config as tf_config
-
-from hbp_nrp_music_interface.bibi.bibi_music_config import MUSICConfiguration
-from hbp_nrp_distributed_nest.launch.NestBrainProcess import NestBrainProcess
-
-from mpi4py import MPI
-
-import logging
-
-logger = logging.getLogger(__name__)
-
-
-class MUSICPyNNCommunicationAdapter(PyNNNestCommunicationAdapter):
- """
- Represents a MUSIC/PyNN proxy communication adapter for the neuronal simulation
- """
-
- def initialize(self):
- """
- Marks the MUSICPyNN adapter as initialized.
- """
- logger.info("MUSICPyNN communication adapter initialized")
- super(MUSICPyNNCommunicationAdapter, self).initialize()
-
- def register_spike_source(self, populations, spike_generator_type, **params):
- """
- Intercepts default PyNNNestCommunicationAdapter request and replaces specified
- population with a new set of proxy neurons for each individual TF. This is required
- to ensure weighting between the TF and target node is maintained properly as multiple
- TFs can target a single neuron and we must weight their inputs separately.
-
- This function is over-complicated due to backwards comaptibility for the single process
- CLE, it can be simplified in the future if we merge these repositories and especially
- when MUSIC supports dynamic ports.
-
- :param populations: A reference to the populations to which the spike generator
- should be connected
- :param spike_generator_type: A spike generator type (see documentation
- or a list of allowed values)
- :param params: A dictionary of configuration parameters
- :return: A communication object or a group of objects
- """
- # get the next set of free parrot neurons with real connectivity to proxy_out neuron
- proxies = self.__get_population_proxy(populations, 'source')
-
- # connect the device generator to the new proxy neurons, this will create synapses with
- # given parameters that we will need to duplicate from proxy->real neuron (parrot neurons
- # ignore their input synapses, but output synapses are respected)
- device = super(MUSICPyNNCommunicationAdapter, self). \
- register_spike_source(proxies, spike_generator_type, **params)
-
- # notify the remote brain processes that they need to setup the other side of this proxy
- self.__notify_brain_processes(populations, proxies)
-
- # return the new generator device
- return device
-
- def register_spike_sink(self, populations, spike_detector_type, **params):
- """
- Requests a communication object with the given spike detector type
- for the given set of neurons
-
- :param populations: A reference to the populations which should be connected
- to the spike detector
- :param spike_detector_type: A spike detector type (see documentation
- for a list of allowed values)
- :param params: A dictionary of configuration parameters
- :return: A Communication object or a group of objects
- """
- populations = self.__get_population_proxy(populations, 'sink')
- return super(MUSICPyNNCommunicationAdapter, self). \
- register_spike_sink(populations, spike_detector_type, **params)
-
- @staticmethod
- def __notify_brain_processes(populations, proxies):
- """
- Notify remote MPI Brain Processes that they must complete this transfer function
- connection by duplicating the parameters for this device connection with the output
- proxy neurons. This is the only way to ensure a TF is actually connected with the
- right parameters.
-
- :param populations The target population to connect to on the other side.
- :param proxies The proxy/parrot neurons that the device is actually connected to.
- """
-
- # nest is the only supported simulator in the hbp_nrp_music packages, but assert here
- # in case this changes, import here to avoid starting nest by accident earlier
- assert sim.simulator.name == "NEST", "NEST is currently required to reconfigure MUSIC ports"
- import nest
-
- # synapse details to pass to other MPI clients, the synapse parameters should all be
- # the same, but in the future a device may have variable/randomly parameterized
- # synapses so just support them now
- synapse_params = []
-
- # for each proxy/reference pair, extract input connectivity from the device, the real
- # reference output targets, and finally duplicate the input connectivity to the targets
- for p in map(int, proxies.all_cells):
-
- # the reference connection from the parrot neuron to proxy out, this contains music
- # channel information
- ref_c = nest.GetStatus(nest.GetConnections(source=[p]))[0]
- channel = ref_c['receptor']
-
- # the connection from device to parrot neuron, our desired synapse
- dev_c = nest.GetStatus(nest.GetConnections(target=[p]))[0]
- model = str(dev_c['synapse_model'])
-
- # remove specific connection information, only leave synapse params since
- # otherwise nest will complain about unused values
- for k in ['receptor', 'source', 'target', 'synapse_label', 'synapse_model', 'sizeof']:
- if k in dev_c:
- dev_c.pop(k)
-
- # override the original dummy weighted parrot->proxy synapse, we can't create a
- # new synapse because MUSIC will complain about duplicate use of music_channels
- nest.SetStatus(nest.GetConnections(source=[p]), dev_c)
-
- # store the connection parameters for remote clients
- dev_c['model'] = model
- dev_c['music_channel'] = channel
- synapse_params.append(dev_c)
-
- # population information to send to the remote MPI nodes, we can't pickle Populations
- # directly and those references wouldn't be valid on the remote nodes anyway
- label = populations.parent.label if populations.parent else populations.label
-
- # [NRRPLT-4722] workaround, if there is no population mask, then we need to use the size
- # of the proxies to target the real size of the neuron population instead of the inflated
- # proxy size
- mask = populations.mask if populations.mask else slice(0, len(proxies), 1)
-
- # propagate the synapse creation parameters to all remote notes, they will create the
- # other side of the connections for this type
- for rank in xrange(MPI.COMM_WORLD.Get_size()):
- if rank == MPI.COMM_WORLD.Get_rank():
- continue
-
- MPI.COMM_WORLD.send({'command': 'ConnectTF', 'label': label, 'mask': mask,
- 'synapses': synapse_params},
- dest=rank, tag=NestBrainProcess.MPI_MSG_TAG)
-
- def __get_population_proxy(self, population, proxy_type):
- """
- Retrieves the first <size> free proxy neurons of the specified population proxy type
- for a given population.
-
- :param population The population to find/create a proxy for.
- :param proxy_type string The type of proxy device to retrieve.
- :return: An equivalend population list or view containing proxies.
- """
- if proxy_type not in ['sink', 'source']:
- raise TypeError("Cannot retrieve unknown population proxy type: {}" % proxy_type)
-
- # lists are explicitly allowed by __register_device, support even if they are unused
- if isinstance(population, list):
- return [self.__get_population_proxy(p, proxy_type) for p in population]
-
- assert isinstance(population, sim.PopulationView)
- try:
-
- # for sinks we must use the same few neurons that are allocated at MUSIC launch
- # otherwise the frontend will not properly fill out the neuron monitor and things
- if proxy_type == 'sink':
- # top level population view with no subslicing (e.g. sensors, actors, etc.)
- if isinstance(population.parent, sim.Population):
- # tf_config.music_proxies is set in
- # hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICBrainLoader.py
- # and not in hbp_nrp_cle.tf_framework.config
- # which confuses pylint
- # pylint: disable=no-member
- return tf_config.music_proxies[population.label][proxy_type]
- # pylint: enable=no-member
-
- # otherwise, this is a view of a top level named population view
- # pylint: disable=no-member
- parent = tf_config.music_proxies[population.parent.label][proxy_type]
- # pylint: enable=no-member
- return sim.PopulationView(parent, population.mask, population.label)
-
- # [NRRPLT-4722] workaround, simply get the first <size> proxy neurons that are
- # frozen for a population, unfreeze and return them for connection, for full
- # population requests only get the real population size
- import nest
- # top level population view with no subslicing (e.g. sensors, actors, etc.)
- # pylint: disable=no-member
- if isinstance(population.parent, sim.Population):
- proxies = tf_config.music_proxies[population.label][proxy_type]
- size = proxies.size / MUSICConfiguration.FAUX_DYNAMIC_FUDGE_FACTOR
-
- # otherwise, this is a view of a top level named population view
- else:
- proxies = tf_config.music_proxies[population.parent.label][proxy_type]
- size = population.size
- # pylint: disable=no-member
- # find all of the free/frozen proxy neurons
- mask = []
- for i, p in enumerate(map(int, proxies.all_cells)):
-
- # if the neuron is frozen, unfreeze it and add to our list
- if nest.GetStatus([p], 'frozen')[0]:
- nest.SetStatus([p], 'frozen', False)
- mask.append(i)
-
- # stop looping when we have enough free neurons
- if len(mask) == size:
- break
-
- # make sure we have enough free proxy neurons
- if len(mask) != size:
- raise Exception("Not enough free proxy neurons to connect transfer functions!\n"
- "Please contact neurorobotics@humanbrainproject.eu with details of "
- "this experiment and associated BIBI file if you require support.")
-
- # return a view of the free proxy neurons for connection
- return sim.PopulationView(proxies, mask, population.label)
-
- except KeyError:
- raise Exception("Unable to locate distriuted MUSIC neuron population proxies for {}.\n"
- "This likely means that a transfer function is utilizing a neuron "
- "population that is not specified at the top of the BIBI file or is"
- "attempting to directly access the underlying \"circuit\" population."
- "Please contact neurorobotics@humanbrainproject.eu with details of "
- "this experiment and associated BIBI file if you require support."
- .format(population))
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNControlAdapter.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNControlAdapter.py
deleted file mode 100644
index 2d003a6..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/MUSICPyNNControlAdapter.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Extensions of the base CLE PyNNControlAdapter to use MUSIC specific proxies
-instead of direct population access. Maxmimum code reuse and minimal duplication
-where possible.
-"""
-from hbp_nrp_distributed_nest.cle.DistributedPyNNControlAdapter import DistributedPyNNControlAdapter
-from hbp_nrp_music_interface.cle import MUSICBrainLoader
-
-import music
-import logging
-import os
-
-logger = logging.getLogger(__name__)
-
-
-class MUSICPyNNControlAdapter(DistributedPyNNControlAdapter):
- """
- Represents a MUSIC/PyNN proxy controller object for the neuronal simulator
- """
-
- def load_brain(self, network_file, **populations):
- """
- Load MUSIC/PyNN brain proxy populations rather than loading and instantiating
- the brain - overrides functionality for both python and h5 brains.
-
- :param network_file: The path to the python file containing the network
- :param populations: A named list of populations to create
- """
- self.__load_music_brain_proxies(**populations)
-
- # load the brain source for the frontend to display, copied from parent class
- logger.info("Saving brain source")
- import hbp_nrp_cle.tf_framework.config as tf_config
- with open(network_file) as source:
- tf_config.brain_source = source.read()
-
- @staticmethod
- def __load_music_brain_proxies(**populations):
- """
- Load MUSIC proxy devices for the given brain network specification and create
- mappings from populations to input/output proxy devices.
-
- :param populations: A named list of populations to create
- """
-
- # initialize MUSIC and load proxies from the MUSIC proxy xml
- logger.info("Loading MUSIC proxy brain devices.")
- music.Setup()
- music_path = os.environ.get('NRP_MUSIC_DIRECTORY')
- proxy_file = os.path.join(music_path, 'proxy.xml')
- MUSICBrainLoader.load_proxies_from_xml(proxy_file, **populations)
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/__init__.py
deleted file mode 100644
index fb359f2..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/cle/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-This package contains an extended implementation of the CLE PyNN Brain Control Adapter
-and Brain Loader that use MUSIC proxy interfaces rather than direct access.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py
deleted file mode 100644
index 1def9d8..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-A distributed MUSIC brain process that can be launched standalone on remote hosts.
-"""
-import hbp_nrp_cle.brainsim.pynn_nest # pylint: disable=unused-import
-
-from hbp_nrp_distributed_nest.launch.NestBrainProcess import NestBrainProcess
-
-import pyNN.nest as sim
-import hbp_nrp_cle.tf_framework.config as tf_config
-
-from hbp_nrp_music_xml.pynn.factory import PyNNProxyFactory
-from hbp_nrp_music_xml.pynn.connector_factory import PyNNConnectorFactory
-from hbp_nrp_music_xml.pynn.xml_factory import XmlFactory
-
-import argparse
-import os
-import music
-
-from mpi4py import MPI
-import traceback
-
-
-class MUSICBrainProcess(NestBrainProcess):
- """
- A distributed MUSIC brain process that can be launched standalone on remote hosts.
- """
-
- def __init__(self, bibi_file, rng_seed):
- """
- Load the distributed brain and construct MUSIC proxies for communication
- to/from the CLE. Nest will automatically allocate the brain in a round-robin
- fashion under the hood, we do not need to do anything explicitly.
-
- :param bibi_file The absolute path to the BIBI file for this experiment.
- """
-
- # setup MUSIC before any brain loading attempt
- self._music_setup = music.Setup()
-
- # load the brain and set parameters
- super(MUSICBrainProcess, self).__init__(bibi_file, rng_seed)
-
- # load the MUSIC proxies for the spawned brain
- music_path = os.environ.get('NRP_MUSIC_DIRECTORY')
- proxy_file = os.path.join(music_path, 'proxy.xml')
- with open(proxy_file, 'r') as f:
- music_xml = f.read()
-
- proxy_model_factory = PyNNProxyFactory(sim)
- connector_factory = PyNNConnectorFactory(sim)
- xml_factory = XmlFactory("BRAIN",
- connector_factory,
- proxy_model_factory,
- tf_config.brain_root.__dict__)
-
- self._proxies = xml_factory.create_proxies(music_xml)
-
- def _connect_tf(self, params):
- """
- Reflect a transfer function connection made on the CLE side by connecting proxy neurons
- to real brain neurons using the same parameters and connectivity as the CLE. This is the
- only way to guarantee both sides share the same connectivity using static port allocation.
-
- :param params The connectivity/synapse parameters passed by the CLE.
- """
-
- # connections only supported during simulation construction
- if self._ready:
- raise Exception("The distributed MUSIC-Nest implementation does not dynamic TFs!")
-
- # get the population of neurons from our dictionary, we can guarantee this is a valid
- # population that has been declared in the BIBI at this point as the CLE will validate
- # before sending us the create message
- brain_pop = sim.PopulationView(tf_config.brain_root.__dict__[params['label']],
- selector=params['mask'])
-
- # get the whole population of proxy neurons for this port
- port_name = '%s_to_brain' % params['label']
- proxies = self._proxies[port_name]
-
- # this is Nest specific code, but so is the rest of the pipeline
- assert sim.simulator.name == "NEST", "Currently only NEST is supported"
- import nest
-
- # iterate through synapses and connect the specific proxy neuron (via music channel) to real
- # brain neuron with given parameters
- for synapse, brain_neuron in zip(params['synapses'], map(int, brain_pop.all_cells)):
-
- # get the proxy neuron at the channel index
- proxy = proxies[synapse['music_channel']]
- synapse.pop('music_channel')
-
- # thaw the proxy neuron so we actually get data
- nest.SetStatus([proxy], 'frozen', False)
-
- # for a source, we only need to connect the input proxy to the real neuron
- nest.Connect([proxy], [brain_neuron], syn_spec=synapse)
-
- def _delete_tf(self, params):
- """
- Currently unsupported, unable to dynamically create or destroy MUSIC ports.
- """
-
- # ignore any commands during simulation construction
- if not self._ready:
- return
-
- raise Exception("The distributed MUSIC-Nest implementation does not support TF deletion!")
-
- def _load_brain(self, params):
- """
- Currently unsupported, unable to dynamically create or destroy MUSIC ports.
- """
-
- # ignore any commands during simulation construction
- if not self._ready:
- return
-
- raise Exception("The distributed MUSIC-Nest implementation does not support brain changes!")
-
-
-if __name__ == '__main__': # pragma: no cover
-
- try:
- parser = argparse.ArgumentParser()
- parser.add_argument('--bibi-file', dest='bibi_file',
- help='the bibi file path to load', required=True)
- parser.add_argument('--rng-seed', dest='rng_seed',
- help='the global experiment RNG seed', required=True)
- args = parser.parse_args()
-
- # construct brain and proxies (expand environment variables in paths)
- brain = MUSICBrainProcess(os.path.expandvars(args.bibi_file), args.rng_seed)
-
- # run the brain until terminated, this is a blocking call
- brain.run()
-
- except Exception: # pylint: disable=broad-except
- # print the traceback which should go back to the remote logger
- traceback.print_exc()
-
- # for any failures, terminate all other brain processes and the CLE
- MPI.COMM_WORLD.Abort(-1)
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICCLEProcess.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICCLEProcess.py
deleted file mode 100644
index cb149af..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICCLEProcess.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-This module contains the CLE process logic for the simulation assembly using MUSIC
-"""
-
-import logging
-import sys
-
-from hbp_nrp_cleserver.server.CLEGazeboSimulationAssembly import CLEGazeboSimulationAssembly
-from hbp_nrp_cleserver.server.ServerConfigurations import robot_gazebo_ros_adapters
-from hbp_nrp_music_interface.cle.MUSICPyNNCommunicationAdapter import MUSICPyNNCommunicationAdapter
-from hbp_nrp_music_interface.cle.MUSICPyNNControlAdapter import MUSICPyNNControlAdapter
-
-from hbp_nrp_distributed_nest.launch.DistributedCLEProcess import launch_cle
-
-# maintain this import order and both must be done before mpi4py
-import hbp_nrp_cle.brainsim.pynn_nest # pylint: disable=unused-import
-import pyNN.nest as nestsim
-import music
-
-logger = logging.getLogger(__name__)
-
-
-class MusicCLESimulationAssembly(CLEGazeboSimulationAssembly):
- """
- Defines the assembly of a simulation using MUSIC
- """
-
- def __init__(self, sim_id, exc, bibi_model, **par):
- """
- Creates a new simulation assembly to simulate an experiment using the CLE and Gazebo
- :param sim_id: The simulation id
- :param exc: The experiment configuration
- :param bibi_model: The BIBI configuration
- """
- super(MusicCLESimulationAssembly, self).__init__(sim_id, exc, bibi_model, **par)
-
- def _create_robot_adapters(self):
- """
- Creates the adapter components for the robot side
-
- :return: A tuple of the communication and control adapter for the robot side
- """
- return robot_gazebo_ros_adapters()
-
- def _create_brain_adapters(self):
- """
- Creates the adapter components for the neural simulator
-
- :return: A tuple of the communication and control adapter for the neural simulator
- """
- logger.info('Using MUSIC configuration and adapters for CLE')
-
- # initialize music and set the CLE to use MUSIC adapters
- music.Setup()
-
- braincomm = MUSICPyNNCommunicationAdapter()
- braincontrol = MUSICPyNNControlAdapter(nestsim)
- return braincomm, braincontrol
-
-if __name__ == '__main__': # pragma: no cover
-
- # guaranteed to only be launched in one process by MUSIC, launch the CLE with defined assembly
- launch_cle(sys.argv[1:], MusicCLESimulationAssembly)
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py
deleted file mode 100644
index 5da6ead..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Setup, build, and launch a distributed MUSIC instance that will spawn the CLE and
-requested brain processes.
-"""
-from hbp_nrp_distributed_nest.launch.NestLauncher import NestLauncher
-
-from hbp_nrp_music_interface.bibi import bibi_music_config
-from hbp_nrp_music_interface.launch.MUSICMPILauncher import MUSICMPILauncher
-from hbp_nrp_music_interface.launch.host.LocalLauncher import LocalLauncher
-from hbp_nrp_music_interface.launch.host.LuganoLauncher import LuganoLauncher
-
-import os
-
-
-# This class intentionally does not inherit SimulationServer (even though it is an implementation of
-# it) in order to avoid duplicate notificators
-class MUSICLauncher(NestLauncher):
- """
- Setup, build, and launch a distributed MUSIC instance that will spawn the CLE and
- requested brain processes.
- """
-
- def __init__(self, sim_id, exc, bibi, **par):
- """
- Store all experiment configuration parameters so that they can be propagated
- to the remote hosts.
-
- :param exc: the experiment configuration
- :param bibi: the BIBI configuration.
- :param server_host Target Gazebo/brain process host (e.g. local or lugano)
- :param reservation Reservation string for cluster backend (None is a valid option)
- :param sim_id The id of the simulation/experiment to be launched.
- :param timeout The default simulation timeout (time initially allocated).
- """
- super(MUSICLauncher, self).__init__(sim_id, exc, bibi, **par)
-
- # we should call the except_hook when something goes wrong in the simulation, but currently
- # we don't
- # pylint: disable=unused-argument
- def initialize(self, environment_file, except_hook):
- """
- Construct the MUSIC launch configuration that will spawn CLE + brain processes
- on distributed hosts.
- """
-
- # extract the environment file path
- nrp_models_path = os.environ.get('NRP_MODELS_DIRECTORY').rstrip('/')
- self._env_file = environment_file.replace(nrp_models_path, '$NRP_MODELS_DIRECTORY')
-
- # create a host specific launcher
- if self._server_host == 'local':
- self._launcher = LocalLauncher()
- elif self._server_host == 'lugano':
- self._launcher = LuganoLauncher(self._exc.bibiConf.processes + 1,
- self._timeout,
- self._reservation)
- else:
- raise Exception('Unknown server host {}, cannot configure and launch MUSIC!'
- .format(self._server_host))
-
- # create launch scripts for the CLE and brain processes
- cle_launcher, brain_launcher = self._launcher.create_launch_scripts()
-
- # command line argument friendly versions of timeout and reservation arguments
- # the receiving processes must understand how to convert these back
- reservation_str = self._reservation if self._reservation else ''
- timeout_str = str(self._timeout).replace(' ', '_')
-
- # build a MUSIC configuration script with correct brain ports, launchers and arugments
- # save it to the host launcher temp directory, this is the same for every host
- music_conf = bibi_music_config.MUSICConfiguration(self._bibi)
- music_conf.add_application('CLE',
- cle_launcher,
- ['--exdconf={}'.format(self._exd_file),
- '--bibi={}'.format(self._bibi_file),
- '--environment={}'.format(self._env_file),
- '--experiment-path={}'.format(self._exp_path),
- '--gzserver-host={}'.format(self._server_host),
- '--reservation={}'.format(reservation_str),
- '--sim-id={}'.format(self._sim_id),
- '--timeout={}'.format(timeout_str),
- '--rng-seed={}'.format(self._rng_seed)],
- 1)
- music_conf.add_application('BRAIN',
- brain_launcher,
- ['--bibi-file={}'.format(self._bibi_file),
- '--rng-seed={}'.format(self._rng_seed)],
- self._exc.bibiConf.processes)
- music_conf.save(self._launcher.local_tmpdir)
-
- # construct the actual MPI launcher
- self.mpilauncher = MUSICMPILauncher('music cle.music')
-
- # build and deploy configuration
- self._build()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICMPILauncher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICMPILauncher.py
deleted file mode 100644
index 0bc240f..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICMPILauncher.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-
-"""
-Helper class to build and execute a formatted mpirun command for music in the format:
-
- mpirun -envlist <vars> -np <proc> -host <hostname/ip> -wdir <temporary work dir> <command> : ...
-
-where each of the hosts has a specific working directory with necessary config files already
-in place. Also passes environment variables required for NRP/CLE execution.
-"""
-from hbp_nrp_distributed_nest.launch.MPILauncher import MPILauncher
-
-
-class MUSICMPILauncher(MPILauncher):
- """
- Class constructs and executes the MUSIC mpi launch command.
- """
-
- def __init__(self, executable):
- super(MUSICMPILauncher, self).__init__(executable)
-
- def add_host(self, hostname, tmpdir, processes=1):
- """
- Add a target host to the mpi launch configuration with MUSIC working directory set.
-
- :param hostname The remote host name or ip.
- :param tmpdir A valid temporary directory on the remote host to launch in.
- :param processes The number of processes for this host.
- """
- self._hosts.append('-np {p} -host {h} -wdir {t} -genv NRP_MUSIC_DIRECTORY {t}'
- .format(p=processes, h=hostname, t=tmpdir))
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/__init__.py
deleted file mode 100644
index e0b1e74..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""
-This package contains classes related to launching a distributed
-MUSIC/PyNN/NEST simulation within the NRP.
-"""
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LocalLauncher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LocalLauncher.py
deleted file mode 100644
index c383c02..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LocalLauncher.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-localhost launch target configuration.
-"""
-
-from hbp_nrp_distributed_nest.launch.host.LocalLauncher import LocalLauncher as ILocalLauncher
-
-import os
-import stat
-import sys
-
-
-class LocalLauncher(ILocalLauncher):
- """
- This launch configuration targets the localhost for all processes and is suitable for local
- installs or deployed installs where the newly spawned processes can run on the same host
- as the REST backend.
- """
-
- def __init__(self):
- """
- Create a local launcher to target localhost and create a local temporary directory to
- write MUSIC configuration files.
- """
- super(LocalLauncher, self).__init__()
-
- def create_launch_scripts(self):
- """
- Create a set of launch scripts for the CLE and individual brain processes with specific
- implementations required for each host. Write the launch scripts to the temporary directory
- for this launcher.
-
- Returns a tuple (path to CLE launch script, path to BrainProcess launc script).
- """
- # create .sh launcher scripts for the CLE and brain processes
- cle_launcher = self._create_launch_script('music_cle_launcher.sh',
- 'hbp_nrp_music_interface.launch.MUSICCLEProcess')
- brain_launcher = self._create_launch_script('music_brain_launcher.sh',
- 'hbp_nrp_music_interface.launch.' +
- 'MUSICBrainProcess')
- return (cle_launcher, brain_launcher)
-
- def _create_launch_script(self, name, module):
- """
- Create an executable script in the working temporary folder to launch the specified
- Python module. These will be used by the MUSIC runtime on each of the hosts since there
- are some quirks in launching "python -m <module> with <args>" directly throug MUSIC.
-
- :param name The name for the launch script to create.
- :param module The python module to launch with this script.
- :return The absolute path to this launch script.
- """
-
- # absolute path to script in tmpdir
- path = os.path.join(self._local_tmpdir, name)
-
- # use the absolute path of the Python interpreter for our current process, this current
- # process will not be executed through uwsgi, so this will be the correct interpreter
- with open(path, 'w') as f:
- f.write('#!/bin/bash\n')
- f.write('{python} -m {module}\n'.format(python=sys.executable, module=module))
-
- os.chmod(path, stat.S_IRWXU)
-
- # return a relative path to the script, it's guaranteed to be run in the tmpdir
- return './%s' % name
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LuganoLauncher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LuganoLauncher.py
deleted file mode 100644
index 86e6032..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/LuganoLauncher.py
+++ /dev/null
@@ -1,170 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Lugano vizcluster launch target configuration.
-"""
-
-from hbp_nrp_music_interface.launch.host.LocalLauncher import LocalLauncher
-
-from hbp_nrp_commons.cluster.LuganoVizCluster import LuganoVizCluster
-
-from hbp_nrp_cle.cle import config
-
-import netifaces
-import os
-import stat
-
-
-class LuganoLauncher(LuganoVizCluster, LocalLauncher):
- """
- This launch configuration targets the Lugano vizcluster and handles brain/CLE process
- allocation and distribution. This is executed before the CLE is launched, so launching will
- immediately terminate if there are not enough cluster resources.
- """
-
- def __init__(self, processes, timeout, reservation):
- """
- Immediately attempt to allocate cluster resources for the brain processes. If this fails
- or causes Exceptions, it will be propagated up to the user appropriately.
-
- :param processes The total number of processes (brain + CLE) to reserve.
- :param timeout The simulation timeout required by the vizcluster launcher.
- :param reservation Resource reservation string to access reserved nodes.
- """
-
- # ensure both constructors are called, raise Exception if allocation fails
- try:
- super(LuganoLauncher, self).__init__(processes, 0, timeout.tzinfo, reservation)
- self._allocate_job(reuse_nodes=True) # multiple brains can run on the same node
- finally:
- LocalLauncher.__init__(self)
-
- # override hostname with allocated node, remote tmp does not exist until written
- self._hostname = self._node
- self._host_tmpdir = None
-
- def _create_launch_script(self, name, module):
- """
- Create an executable script in the working temporary folder to launch the specified
- Python module. These will be used by the MUSIC runtime on each of the hosts since there
- are some quirks in launching "python -m <module> with <args>" directly throug MUSIC.
-
- Handle specific vizcluster configuration (modules and environment).
-
- :param name The name for the launch script to create.
- :param module The python module to launch with this script.
- :return The absolute path to this launch script on the remote host.
- """
-
- # absolute path to script in local tmpdir
- path = os.path.join(self._local_tmpdir, name)
-
- # determine if we are running on a dev or staging environment
- environment = os.environ.get('ENVIRONMENT')
-
- # set the ROS master uri to use an actual IP instead of localhost
- ifaddress = netifaces.ifaddresses(config.config.get('network', 'main-interface'))
- local_ip = ifaddress[netifaces.AF_INET][0]['addr']
- ros_master_uri = os.environ.get("ROS_MASTER_URI").replace('localhost', local_ip)
-
- # create a launch script that configures the vizcluster environment properly
- with open(path, 'w') as f:
- f.write('#!/bin/bash\n')
- f.write('source /opt/rh/python27/enable\n')
-
- # set the terminal type to ensure we get the same behavior as from a backend VM
- # this is also required in the Docker images
- f.write('export TERM=linux\n')
-
- # set the environment version and any specific module versions to be used, then
- # override the environment variable to the deployed location on the remote host
- f.write('source $NRP_MUSIC_DIRECTORY/nrp-variables\n')
- f.write('export NRP_VARIABLES_PATH=$NRP_MUSIC_DIRECTORY/nrp-variables\n')
-
- # load the environment modules based on the above configuration
- proj_path = '/gpfs/bbp.cscs.ch/project/proj30/neurorobotics/%s/' % environment
- f.write('source %s/server-scripts/nrp-services-modules.sh\n' % proj_path)
-
- # set paths to models/experiments directory on gpfs
- f.write('export NRP_MODELS_DIRECTORY=%s/models\n' % proj_path)
- f.write('export NRP_EXPERIMENTS_DIRECTORY=%s/experiments\n' % proj_path)
-
- # set the PYTHONPATH to add NRP modules on gpfs
- venv_path = '%s/platform_venv/lib/python2.7/site-packages' % proj_path
- f.write('export PYTHONPATH=%s:$PYTHONPATH\n' % venv_path)
-
- # configure ROS and source the ros_venv before launching
- f.write('export ROS_MASTER_URI=%s\n' % ros_master_uri)
- f.write('source $ROS_PYTHON_VENV/bin/activate\n')
-
- # actually launch the module
- f.write('python -m {module}\n'.format(module=module))
-
- # ensure the script is executable
- os.chmod(path, stat.S_IRWXU)
-
- # return a relative path to the script, it's guaranteed to be run in the tmpdir
- return './%s' % name
-
- def deploy(self):
- """
- Copy all configuration files to a temp directory on the remote host. The remote directory
- is created here, so use it to set the launcher interface host tmpdir value.
- """
-
- # generated configuration files
- for f in os.listdir(self._local_tmpdir):
- self._copy_to_remote(os.path.join(self._local_tmpdir, f))
-
- # deploy any NRP specific variable/module version configuration
- self._copy_to_remote(os.environ.get('NRP_VARIABLES_PATH'))
-
- # set the host tmpdir, slightly different naming convention between interfaces
- self._host_tmpdir = self._tmp_dir
-
- def shutdown(self):
- """
- Shutdown by trying to kill any running processes and deleting the temporary directory on the
- remote allocated node and localhost. Both are guaranteed to exist by the constructor.
- """
-
- # try to terminate any processes running on the allocated node, they should already be
- # terminated before we get here, catch any Exceptions and ensure we cleanup below
- if self._host_tmpdir:
- try:
- # terminate any processes, remote directory will be deleted by parent cleanup
- clean_process = self._spawn_ssh_node()
- clean_process.sendline('for L in %s/*.lock ; do kill -9 `basename $L .lock`; done' %
- self._host_tmpdir)
- clean_process.terminate()
- except Exception: # pylint: disable=broad-except
- pass
- finally:
- self._host_tmpdir = None
-
- # delete the remote temp directory and deallocate the node
- LuganoVizCluster.stop(self)
-
- # cleanup any local processes and delete the remote temp directory
- LocalLauncher.shutdown(self)
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/__init__.py
deleted file mode 100644
index 51aa846..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/host/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-This package contains host specific implementations for distributed MUSIC targets.
-"""
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/__init__.py
deleted file mode 100644
index ec4a4d0..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""
-This package contains all tests for the MUSIC interface package.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/__init__.py
deleted file mode 100644
index 7366ab6..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-This package contains all tests for the MUSIC BIBI interface package.
-"""
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/bibi.xml b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/bibi.xml
deleted file mode 100644
index 7416897..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/bibi.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bibi xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.humanbrainproject.eu/SP10/2014/BIBI" xsi:schemaLocation="http://schemas.humanbrainproject.eu/SP10/2014/BIBI bibi_configuration.xsd">
- <brainModel>
- <file>fake_brain.py</file>
- <populations population="range" xsi:type="Range" from="0" to="2"/>
- <populations population="list" xsi:type="List">
- <element>3</element>
- <element>4</element>
- <element>5</element>
- </populations>
- <populations population="population" xsi:type="Population" count="10"/>
- </brainModel>
- <bodyModel>fake_model.sdf</bodyModel>
-</bibi>
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.music b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.music
deleted file mode 100644
index c3235d0..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.music
+++ /dev/null
@@ -1,16 +0,0 @@
-[CLE]
-np = 4
-binary = cle_binary
-args =
-
-[BRAIN]
-np = 2
-binary = brain_binary
-args = "--brain --args"
-
-CLE.range_to_brain -> BRAIN.range_to_brain [10]
-BRAIN.range_to_cle -> CLE.range_to_cle [2]
-CLE.list_to_brain -> BRAIN.list_to_brain [15]
-BRAIN.list_to_cle -> CLE.list_to_cle [3]
-CLE.population_to_brain -> BRAIN.population_to_brain [50]
-BRAIN.population_to_cle -> CLE.population_to_cle [10]
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.xml b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.xml
deleted file mode 100644
index 89b9261..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/config.xml
+++ /dev/null
@@ -1,137 +0,0 @@
-<?xml version="1.0"?>
-<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <port>
- <type>Event</type>
- <name>range_to_brain</name>
- <width>10</width>
- <sender>
- <name>CLE</name>
- </sender>
- <receiver>
- <name>BRAIN</name>
- <synapse>
- <target>range</target>
- <type>one_to_one</type>
- <selector xsi:type="SliceSelector">
- <start>0</start>
- <stop>2</stop>
- <step>1</step>
- </selector>
- </synapse>
- </receiver>
- </port>
- <port>
- <type>Event</type>
- <name>range_to_cle</name>
- <width>2</width>
- <sender>
- <name>BRAIN</name>
- </sender>
- <receiver>
- <name>CLE</name>
- <synapse>
- <target>range</target>
- <type>one_to_one</type>
- <selector xsi:type="SliceSelector">
- <start>0</start>
- <stop>2</stop>
- <step>1</step>
- </selector>
- </synapse>
- </receiver>
- </port>
- <port>
- <type>Event</type>
- <name>list_to_brain</name>
- <width>15</width>
- <sender>
- <name>CLE</name>
- </sender>
- <receiver>
- <name>BRAIN</name>
- <synapse>
- <target>list</target>
- <type>one_to_one</type>
- <selector xsi:type="ListSelector">
- <element>3</element>
- <element>4</element>
- <element>5</element>
- </selector>
- </synapse>
- </receiver>
- </port>
- <port>
- <type>Event</type>
- <name>list_to_cle</name>
- <width>3</width>
- <sender>
- <name>BRAIN</name>
- </sender>
- <receiver>
- <name>CLE</name>
- <synapse>
- <target>list</target>
- <type>one_to_one</type>
- <selector xsi:type="ListSelector">
- <element>3</element>
- <element>4</element>
- <element>5</element>
- </selector>
- </synapse>
- </receiver>
- </port>
- <port>
- <type>Event</type>
- <name>population_to_brain</name>
- <width>50</width>
- <sender>
- <name>CLE</name>
- </sender>
- <receiver>
- <name>BRAIN</name>
- <synapse>
- <target>population</target>
- <type>one_to_one</type>
- <selector xsi:type="ListSelector">
- <element>0</element>
- <element>1</element>
- <element>2</element>
- <element>3</element>
- <element>4</element>
- <element>5</element>
- <element>6</element>
- <element>7</element>
- <element>8</element>
- <element>9</element>
- </selector>
- </synapse>
- </receiver>
- </port>
- <port>
- <type>Event</type>
- <name>population_to_cle</name>
- <width>10</width>
- <sender>
- <name>BRAIN</name>
- </sender>
- <receiver>
- <name>CLE</name>
- <synapse>
- <target>population</target>
- <type>one_to_one</type>
- <selector xsi:type="ListSelector">
- <element>0</element>
- <element>1</element>
- <element>2</element>
- <element>3</element>
- <element>4</element>
- <element>5</element>
- <element>6</element>
- <element>7</element>
- <element>8</element>
- <element>9</element>
- </selector>
- </synapse>
- </receiver>
- </port>
-</root>
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/test_bibi_music_config.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/test_bibi_music_config.py
deleted file mode 100644
index 55bf4fc..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/bibi/test_bibi_music_config.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.bibi.bibi_music_config import MUSICConfiguration
-import hbp_nrp_commons.generated.bibi_api_gen as api
-
-from mock import Mock, patch
-import os
-
-
-class TestMusicConfiguration(unittest.TestCase):
-
- def setUp(self):
- self._path = os.path.dirname(os.path.realpath(__file__))
-
- # valid bibi with all supported population types
- bibi_file = os.path.join(self._path, "bibi.xml")
- with open(bibi_file) as f:
- self._bibi = api.CreateFromDocument(f.read())
-
- # expected xml generated
- xml_file = os.path.join(self._path, "config.xml")
- with open(xml_file) as f:
- self._xml = "".join(f.read().split())
-
- # expected script generated
- script_file = os.path.join(self._path, "config.music")
- with open(script_file) as f:
- self._script = f.read()
-
- def test_invalid_bibi(self):
- # not a BIBI file
- self.assertRaises(Exception, MUSICConfiguration, 'foo')
-
- # brain populations set to none or empty
- brain_file = "foo.py"
- empty_bibi = api.BIBIConfiguration()
- empty_bibi.brainModel = api.BrainModelWithPath(file=api.PythonFilename(brain_file),
- populations=None)
- self.assertRaises(Exception, MUSICConfiguration, empty_bibi)
- empty_bibi.brainModel = api.BrainModelWithPath(file=api.PythonFilename(brain_file),
- populations=[])
- self.assertRaises(Exception, MUSICConfiguration, empty_bibi)
-
- def test_xml(self):
- conf = MUSICConfiguration(self._bibi)
- self.assertEqual("".join(conf.xml().split()), self._xml)
-
- @patch('__builtin__.open', spec=open)
- def test_str(self, mocked_open):
- conf = MUSICConfiguration(self._bibi)
- conf.add_application('CLE', 'cle_binary', None, 4)
-
- # missing BRAIN definition
- self.assertRaises(Exception, conf.save, "")
-
- # invalid application name
- self.assertRaises(Exception, conf.add_application, 'FOO', 'bar', None, 1)
-
- # add brain, invalid if added twice
- conf.add_application('BRAIN', 'brain_binary', ['--brain', '--args'], 2)
- self.assertRaises(Exception, conf.add_application, 'BRAIN', 'bar', None, 1)
-
- # compare generated music script
- conf.save("")
- self.assertEqual(str(conf), self._script)
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/__init__.py
deleted file mode 100644
index 244bd59..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""
-This package contains all tests for the MUSIC CLE interface package.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_brain_loader.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_brain_loader.py
deleted file mode 100644
index 7b51fb9..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_brain_loader.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.cle.MUSICBrainLoader import load_proxies_from_xml
-import hbp_nrp_cle.tf_framework.config as tf_config
-import pyNN.nest as sim
-
-from mock import Mock, patch
-import os
-
-
-class TestBrainLoader(unittest.TestCase):
-
- def test_invalid_setup(self):
- tf_config.brain_root = 'foo'
- self.assertRaises(Exception, load_proxies_from_xml, 'foo.xml')
- tf_config.brain_root = None
-
- def test_invalid_xml_file(self):
- self.assertRaises(Exception, load_proxies_from_xml, 'foo.xml')
-
- @patch('__builtin__.open', spec=open)
- def test_invalid_simulator(self, mock_open):
- sim.simulator.name = 'FOO'
- self.assertRaises(Exception, load_proxies_from_xml, 'foo.xml')
- sim.simulator.name = 'NEST'
-
- @patch('__builtin__.open', spec=open)
- @patch('hbp_nrp_music_xml.pynn.xml_factory.XmlFactory.create_proxies', new=Mock(return_value={}))
- def test_proxy_dict_missing(self, mock_open):
- self.assertRaises(Exception, load_proxies_from_xml, 'foo.xml', bar='foo')
-
- @patch('__builtin__.open', spec=open)
- @patch('pyNN.nest.PopulationView', new=Mock(return_value='fake'))
- @patch('hbp_nrp_music_xml.pynn.xml_factory.XmlFactory.create_proxies',
- new=Mock(return_value={'bar_to_brain': 'foo', 'bar_to_cle': 'bar'}))
- def test_proxy_dict_valid(self, mock_open):
- tf_config.brain_root = None
- load_proxies_from_xml('foo.xml', bar='foo')
- self.assertEqual(tf_config.brain_root.__dict__['bar'], 'fake')
- self.assertEqual(tf_config.music_proxies['bar'], {'source': 'fake', 'sink': 'fake'})
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_communication_adapter.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_communication_adapter.py
deleted file mode 100644
index 14e345e..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_communication_adapter.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.cle.MUSICPyNNCommunicationAdapter import MUSICPyNNCommunicationAdapter
-
-import hbp_nrp_cle.tf_framework.config as tf_config
-
-from mock import Mock, patch
-import os
-
-
-class MockPopulation(object):
-
- def __init__(self, label):
- self.label = label
-
-
-class MockPopulationView(object):
-
- def __init__(self, parent, label, mask):
- self.parent = parent
- self.label = label
- self.mask = mask
- self.size = 0
- self.all_cells = []
-
-
-@patch('hbp_nrp_cle.brainsim.pynn_nest.PyNNNestCommunicationAdapter.PyNNNestCommunicationAdapter.initialize')
-@patch('hbp_nrp_cle.brainsim.pynn_nest.PyNNNestCommunicationAdapter.PyNNNestCommunicationAdapter.register_spike_source')
-@patch('hbp_nrp_cle.brainsim.pynn_nest.PyNNNestCommunicationAdapter.PyNNNestCommunicationAdapter.register_spike_sink')
-@patch('pyNN.nest.PopulationView', MockPopulationView)
-@patch('pyNN.nest.Population', MockPopulation)
-class TestCommunicationAdapter(unittest.TestCase):
-
- def setUp(self):
- self._adapter = MUSICPyNNCommunicationAdapter()
-
- def test_initialize(self, mock_initialize, mock_source, mock_sink):
- self._adapter.initialize()
-
- def test_invalid_population_type(self, mock_initialize, mock_source, mock_sink):
- self.assertRaises(Exception, self._adapter.register_spike_sink, 'foo', 'bar')
-
- def test_parent_population(self, mock_initialize, mock_source, mock_sink):
- pop = MockPopulationView(MockPopulation('parent'), 'population', 'mask')
- tf_config.music_proxies = {'population':{'source':pop}}
- self._adapter.register_spike_source(pop, 'foo')
-
- def test_parent_population_view(self, mock_initialize, mock_source, mock_sink):
- pop = MockPopulationView(MockPopulationView(MockPopulation('grandparent'), 'parent', 'mask'), 'population', 'mask')
- tf_config.music_proxies = {'parent':{'sink':pop}}
- self._adapter.register_spike_sink(pop, 'foo')
-
- '''
- def test_population_list(self, mock_initialize, mock_source, mock_sink):
- pop = MockPopulationView(MockPopulation('parent'), 'population', 'mask')
- tf_config.music_proxies = {'population':{'source':pop}}
- self._adapter.register_spike_source([pop, pop, pop], 'foo')
- '''
-
- def test_invalid_population(self, mock_initialize, mock_source, mock_sink):
- pop = MockPopulationView(MockPopulation('parent'), 'population', 'mask')
- tf_config.music_proxies = {}
- self.assertRaises(Exception, self._adapter.register_spike_source, pop, 'foo')
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_control_adapter.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_control_adapter.py
deleted file mode 100644
index 3d054fc..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/cle/test_control_adapter.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.cle.MUSICPyNNControlAdapter import MUSICPyNNControlAdapter
-import hbp_nrp_cle.tf_framework.config as tf_config
-
-from mock import Mock, patch, mock_open
-import os
-
-
-class MockedMUSICSetup(object):
-
- def config(self, key):
- return 'mocked.xml'
-
-
-class TestControlAdapter(unittest.TestCase):
-
- def test_missing_xml(self):
- mc = MUSICPyNNControlAdapter(Mock())
- self.assertRaises(Exception, mc.load_brain, 'foo.xml')
-
- @patch('music.Setup', name=MockedMUSICSetup())
- @patch('os.environ.get', return_value='')
- @patch('hbp_nrp_music_interface.cle.MUSICBrainLoader.load_proxies_from_xml')
- def test_valid_xml(self, mocked_setup, mocked_environ, mocked_load):
-
- m = mock_open()
- m.return_value.read.return_value = 'mock brain source'
-
- with patch('__builtin__.open', m, create=True):
- mc = MUSICPyNNControlAdapter(Mock())
- mc.load_brain('foo.xml')
-
- mocked_environ.assert_called_once_with('NRP_MUSIC_DIRECTORY')
- m.assert_called_once_with('foo.xml')
- self.assertEquals(tf_config.brain_source, 'mock brain source')
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/__init__.py
deleted file mode 100644
index 77cd9a0..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-This package contains all tests for the MUSIC interface launch package.
-"""
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/__init__.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/__init__.py
deleted file mode 100644
index d6a3227..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-"""
-This package contains all tests for the MUSIC interface launch.host package for host specific
-launch configurations.
-"""
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_interface.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_interface.py
deleted file mode 100644
index 36525a6..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_interface.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_distributed_nest.launch.host import IHostLauncher
-
-from mock import Mock, patch
-import os
-
-
-class TestHostLauncherInterface(unittest.TestCase):
-
- def setUp(self):
- self.__launcher = IHostLauncher()
-
- def test_initial_values(self):
- self.assertEqual(self.__launcher._hostname, None)
- self.assertEqual(self.__launcher._local_tmpdir, None)
- self.assertEqual(self.__launcher._host_tmpdir, None)
-
- def test_properties(self):
-
- # default values raise implementation errors
- self.assertRaises(NotImplementedError, getattr, self.__launcher, 'hostname')
- self.assertRaises(NotImplementedError, getattr, self.__launcher, 'local_tmpdir')
- self.assertRaises(NotImplementedError, getattr, self.__launcher, 'host_tmpdir')
-
- # set some values to simulate an implementation
- self.__launcher._hostname = 'foo'
- self.__launcher._local_tmpdir = 'local'
- self.__launcher._host_tmpdir = 'host'
- self.assertEqual(self.__launcher.hostname, 'foo')
- self.assertEqual(self.__launcher.local_tmpdir, 'local')
- self.assertEqual(self.__launcher.host_tmpdir, 'host')
-
- def test_functions(self):
-
- # all functions raise implementation errors in the interface
- self.assertRaises(NotImplementedError, self.__launcher.create_launch_scripts)
- self.assertRaises(NotImplementedError, self.__launcher.deploy)
- self.assertRaises(NotImplementedError, self.__launcher.shutdown)
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_local.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_local.py
deleted file mode 100644
index 0615167..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_local.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.launch.host.LocalLauncher import LocalLauncher
-
-from mock import Mock, patch, mock_open, call
-import os
-import sys
-import stat
-import signal
-
-
-class TestLocalLauncherInterface(unittest.TestCase):
-
- def setUp(self):
- with patch('tempfile.mkdtemp') as mkdtemp_mock:
- mkdtemp_mock.return_value = '/mock_tmp'
- self.__launcher = LocalLauncher()
-
- def test_properties(self):
-
- # implementation should set all property values
- self.assertEqual(self.__launcher.hostname, 'localhost')
- self.assertEqual(self.__launcher.local_tmpdir, '/mock_tmp')
- self.assertEqual(self.__launcher.host_tmpdir, '/mock_tmp')
-
- def test_create_launch_scripts(self):
-
- # ensure that the calls to create the cle and brain launch scripts are made
- def mock_creator(name, module):
- return name
-
- with patch.object(self.__launcher, '_create_launch_script', mock_creator):
- self.assertEqual(self.__launcher.create_launch_scripts(),
- ('music_cle_launcher.sh', 'music_brain_launcher.sh'))
-
- @patch('os.chmod')
- def test_internal_create_launch_script(self, mock_chmod):
-
- # mock the script open and write commands
- m = mock_open()
- with patch('__builtin__.open', m, create=True):
- self.assertEqual(self.__launcher._create_launch_script('name.sh', 'module'),
- './name.sh')
-
- # the open call
- m.assert_called_once_with('/mock_tmp/name.sh', 'w')
-
- # the write calls for the actual script
- handle = m()
- self.assertEqual(handle.write.call_args_list,
- [call('#!/bin/bash\n'),
- call('{python} -m module\n'.format(python=sys.executable))])
-
- # ensure the chmod was called to make the script executable
- mock_chmod.assert_called_once_with('/mock_tmp/name.sh', stat.S_IRWXU)
-
- def test_deploy(self):
-
- # should just call pass, exception means failure
- self.__launcher.deploy()
-
- @patch('os.path.exists', return_value=True)
- @patch('glob.iglob', return_value=['1234.lock'])
- @patch('os.kill')
- @patch('shutil.rmtree')
- def test_shutdown(self, mock_rmtree, mock_kill, mock_iglob, mock_exists):
-
- # mock the lockfile open/readline command
- m = mock_open()
- m.return_value.readline.return_value = '1234'
- with patch('__builtin__.open', m, create=True):
- self.__launcher.shutdown()
-
- # verify the rmtree is called to delete the tmpdir
- mock_rmtree.assert_called_once_with('/mock_tmp')
-
- # verify the tmp dirs are unset
- self.assertEqual(self.__launcher._local_tmpdir, None)
- self.assertEqual(self.__launcher._host_tmpdir, None)
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_lugano.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_lugano.py
deleted file mode 100644
index c548b35..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/host/test_lugano.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.launch.host.LuganoLauncher import LuganoLauncher
-
-from mock import Mock, patch, mock_open, call
-import os
-import sys
-import stat
-import signal
-import netifaces
-
-
-class TestLuganoLauncherInterface(unittest.TestCase):
-
- def setUp(self):
-
- # mock the Lugano specific calls made in the constructor
- def mock_init(self, processes, gpus, timeout, reservation):
- self._node = 'mock_node'
-
- with patch('tempfile.mkdtemp', return_value='/mock_tmp') as mkdtemp_mock,\
- patch('hbp_nrp_commons.cluster.LuganoVizCluster.LuganoVizCluster.__init__', mock_init) as init_mock,\
- patch('hbp_nrp_commons.cluster.LuganoVizCluster.LuganoVizCluster._allocate_job') as allocate_mock:
-
- self.__launcher = LuganoLauncher(4, Mock(), None)
-
- def test_properties(self):
-
- # implementation should set all property values
- self.assertEqual(self.__launcher.hostname, 'mock_node')
- self.assertEqual(self.__launcher.local_tmpdir, '/mock_tmp')
-
- @patch('hbp_nrp_cle.cle.config.config.get')
- @patch('netifaces.ifaddresses', return_value={netifaces.AF_INET: [{'addr': '1.2.3.4'}]})
- @patch('os.chmod')
- def test_internal_create_launch_script(self, mock_chmod, mock_ifaddresses, mock_config):
-
- def mock_environ_get(key):
- if key == 'ENVIRONMENT':
- return 'dev'
- elif key == 'ROS_MASTER_URI':
- return 'http://localhost:11311'
-
- # mock the script open and write commands
- m = mock_open()
- with patch('__builtin__.open', m, create=True), patch('os.environ.get', mock_environ_get):
- self.assertEqual(self.__launcher._create_launch_script('name.sh', 'module'),
- './name.sh')
-
- # the open call
- m.assert_called_once_with('/mock_tmp/name.sh', 'w')
-
- # the write calls for the actual script
- handle = m()
- self.assertEqual(handle.write.call_args_list,
- [call('#!/bin/bash\n'),
- call('source /opt/rh/python27/enable\n'),
- call('export TERM=linux\n'),
- call('source $NRP_MUSIC_DIRECTORY/nrp-variables\n'),
- call('export NRP_VARIABLES_PATH=$NRP_MUSIC_DIRECTORY/nrp-variables\n'),
- call('source /gpfs/bbp.cscs.ch/project/proj30/neurorobotics/dev//server-scripts/nrp-services-modules.sh\n'),
- call('export NRP_MODELS_DIRECTORY=/gpfs/bbp.cscs.ch/project/proj30/neurorobotics/dev//models\n'),
- call('export NRP_EXPERIMENTS_DIRECTORY=/gpfs/bbp.cscs.ch/project/proj30/neurorobotics/dev//experiments\n'),
- call('export PYTHONPATH=/gpfs/bbp.cscs.ch/project/proj30/neurorobotics/dev//platform_venv/lib/python2.7/site-packages:$PYTHONPATH\n'),
- call('export ROS_MASTER_URI=http://1.2.3.4:11311\n'),
- call('source $ROS_PYTHON_VENV/bin/activate\n'),
- call('python -m module\n')])
-
- # ensure the chmod was called to make the script executable
- mock_chmod.assert_called_once_with('/mock_tmp/name.sh', stat.S_IRWXU)
-
- def test_deploy(self):
-
- # set the remote temp dir name that is created by the copy command
- def mock_copy(self, source):
- self._tmp_dir = '/mock_remote_tmp'
-
- with patch('hbp_nrp_commons.cluster.LuganoVizCluster.LuganoVizCluster._copy_to_remote', mock_copy),\
- patch('os.listdir', return_value=['foo']):
- # should just call pass, exception means failure
- self.__launcher.deploy()
-
- # make sure the remote tmp variable is set correctly
- self.assertEqual(self.__launcher.host_tmpdir, '/mock_remote_tmp')
-
- @patch('hbp_nrp_commons.cluster.LuganoVizCluster.LuganoVizCluster._spawn_ssh_node')
- @patch('hbp_nrp_commons.cluster.LuganoVizCluster.LuganoVizCluster.stop')
- @patch('hbp_nrp_music_interface.launch.host.LocalLauncher.LocalLauncher.shutdown')
- def test_shutdown(self, mock_shutdown, mock_stop, mock_spawn):
-
- mock_ssh = Mock()
- mock_spawn.return_value = mock_ssh
-
- # ensure deploy has been called first even if the test hasn't run
- self.__launcher._host_tmpdir = '/mock_remote_tmp'
- self.__launcher.shutdown()
-
- # verify the parent class shutdowns are called
- mock_stop.assert_called_once()
- mock_shutdown.assert_called_once()
-
- # verify the tmp dirs are unset
- self.assertEqual(self.__launcher._host_tmpdir, None)
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_mpi_launcher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_mpi_launcher.py
deleted file mode 100644
index 8b55e82..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_mpi_launcher.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.launch.MUSICMPILauncher import MUSICMPILauncher
-
-from mock import Mock, patch
-import os
-import json
-
-from std_msgs.msg import String
-
-
-class MockProcessIO(object):
-
- def write(self, message):
- pass
-
- def flush(self):
- pass
-
-
-class MockProcess(object):
-
- def __init__(self, cmd, preexec_fn, stdin, env):
- self.stdin=MockProcessIO()
-
- def poll(self):
- return None
-
- def wait(self):
- return 0
-
- def kill(self):
- raise OSError('testing error')
-
-
-class MockFailedProcess(MockProcess):
-
- def poll(self):
- return 255
-
- def wait(self):
- return 255
-
-
-class TestControlAdapter(unittest.TestCase):
-
- def setUp(self):
- self.__launcher = MUSICMPILauncher('music cle.music')
-
- def test_add_hosts(self):
- self.__launcher.add_host('foo', '/tmp/foo')
- self.__launcher.add_host('bar', '/tmp/bar', 3)
- self.assertEqual(self.__launcher._hosts,
- ['-np 1 -host foo -wdir /tmp/foo -genv NRP_MUSIC_DIRECTORY /tmp/foo',
- '-np 3 -host bar -wdir /tmp/bar -genv NRP_MUSIC_DIRECTORY /tmp/bar'])
-
- @patch('os.environ.get', new=Mock(return_value='foo'))
- def test_build(self):
- self.__launcher._hosts = []
- self.assertRaises(Exception, self.__launcher.build)
-
- self.__launcher.add_host('foo', '/tmp/foo')
- self.__launcher.add_host('bar', '/tmp/bar', 3)
- self.__launcher.build()
- self.assertEqual(self.__launcher._cmd,
- 'mpirun -np 1 -host foo -wdir /tmp/foo -genv NRP_MUSIC_DIRECTORY /tmp/foo music cle.music : ' +
- '-np 3 -host bar -wdir /tmp/bar -genv NRP_MUSIC_DIRECTORY /tmp/bar music cle.music')
-
- def test_on_status(self):
-
- # reset launched flag if another test was run prior
- self.__launcher._launched = False
-
- # not a progress message, no update to launched
- msg = String()
- msg.data = json.dumps({'progress': {'task': 'Neurorobotics Closed Loop Engine'}})
- self.__launcher._on_status(msg)
- self.assertEqual(self.__launcher._launched, False)
-
- # progress completion message
- msg.data = json.dumps({'simulation': 'status'})
- self.__launcher._on_status(msg)
- self.assertEqual(self.__launcher._launched, True)
-
- @patch('rosnode.get_api_uri')
- @patch('rospy.get_master', return_value='foo')
- @patch('os.environ', return_value={})
- @patch('hbp_nrp_cle.config.config.get', return_value='mock_gzbridge_cmd')
- @patch('os.system')
- def test_check_gzbridge(self, system_mock, config_mock, environ_mock, rospy_mock, rosnode_mock):
-
- # simulate a call when uri has already been set
- self.__launcher._gazebo_master_uri = 'something'
- self.__launcher._check_gzbridge()
- self.assertEqual(rosnode_mock.call_count, 0)
- self.assertEqual(environ_mock.call_count, 0)
- self.assertEqual(system_mock.call_count, 0)
-
- # simulate node not yet started
- self.__launcher._gazebo_master_uri = None
- rosnode_mock.return_value = (-1, '', '')
- self.__launcher._check_gzbridge()
- rosnode_mock.assert_called_with('foo', '/gazebo', True)
- self.assertEqual(environ_mock.call_count, 0)
- self.assertEqual(system_mock.call_count, 0)
-
- # simulate started on localhost
- self.__launcher._gazebo_master_uri = None
- rosnode_mock.return_value = (1, '', 'http://127.0.0.1:54321')
- self.__launcher._check_gzbridge()
- rosnode_mock.assert_called_with('foo', '/gazebo', True)
- self.assertEqual(self.__launcher._gazebo_master_uri, 'http://127.0.0.1:11345')
- self.assertEqual(environ_mock.call_count, 0)
- self.assertEqual(system_mock.call_count, 0)
-
- # simulate started on remote host
- self.__launcher._gazebo_master_uri = None
- rosnode_mock.return_value = (1, '', 'http://1.2.3.4:54321')
- self.__launcher._check_gzbridge()
- rosnode_mock.assert_called_with('foo', '/gazebo', True)
- self.assertEqual(self.__launcher._gazebo_master_uri, 'http://1.2.3.4:11345')
- system_mock.assert_called_once_with('mock_gzbridge_cmd')
-
-
- @patch('rospy.Subscriber')
- def test_launch(self, rospy_mock):
-
- # unset any variables from other tests
- self.__launcher._cmd = None
- self.__launcher._launched = None
-
- # not initialized, cannot run without a command
- self.assertRaises(Exception, self.__launcher.launch)
-
- # patch gzbridge launch function to be tested separately
- with patch.object(self.__launcher, '_check_gzbridge', Mock()):
-
- # initialize with a valid process
- self.__launcher._cmd = 'foo'
- with patch('subprocess.Popen', MockProcess):
- self.__launcher._launched = True
- self.__launcher.launch()
-
- # initialize with an invalid process
- with patch('subprocess.Popen', MockFailedProcess):
- self.__launcher._launched = False
- self.assertRaises(Exception, self.__launcher.launch)
-
- def test_run(self):
-
- # not initialized or launched, failure expected
- self.__launcher._process = None
- self.__launcher._launched = False
- self.assertRaises(Exception, self.__launcher.run)
-
- # successfully launched and completed
- self.__launcher._launched = True
- self.__launcher._process = MockProcess(None, None, None, None)
- self.__launcher.run()
-
- # failed process run
- self.__launcher._process = MockFailedProcess(None, None, None, None)
- self.assertRaises(Exception, self.__launcher.run)
-
- @patch('hbp_nrp_cle.config.config.get', return_value='mock_gzbridge_cmd')
- @patch('os.system')
- def test_shutdown(self, system_mock, config_mock):
- self.__launcher._process = MockProcess(None, None, None, None)
- self.__launcher._gazebo_master_uri = 'http://1.2.3.4:11345'
- self.__launcher.shutdown()
- system_mock.assert_called_once_with('mock_gzbridge_cmd')
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py
deleted file mode 100644
index c94af48..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-
-from hbp_nrp_music_interface.launch.MUSICLauncher import MUSICLauncher
-
-from mock import Mock, patch
-import os
-
-
-class MockLocalLauncher(Mock):
-
- @property
- def hostname(self):
- return 'localhost'
-
- @property
- def local_tmpdir(self):
- return '/mock_tmpdir'
-
- @property
- def host_tmpdir(self):
- return '/mock_host_tmpdir'
-
- def create_launch_scripts(self):
- return ('cle.sh', 'brain.sh')
-
-
-class TestMUSICLauncher(unittest.TestCase):
-
- @patch('os.environ.get', return_value='')
- def setUp(self, mock_environ_get):
- exc_mock = Mock()
- exc_mock.path = 'exd_conf'
- exc_mock.dir = '/exp_path'
- exc_mock.rngSeed = 123456
- exc_mock.bibiConf.processes = 10
- bibi_mock = Mock()
- bibi_mock.path = 'bibi_file'
- self.__launcher = MUSICLauncher(1, exc_mock, bibi_mock,
- gzserver_host='local',
- reservation=None,
- timeout=None)
-
- @patch('hbp_nrp_music_interface.launch.MUSICLauncher.LocalLauncher', MockLocalLauncher)
- @patch('hbp_nrp_music_interface.launch.MUSICLauncher.bibi_music_config.MUSICConfiguration')
- @patch('hbp_nrp_music_interface.launch.MUSICLauncher.MUSICMPILauncher')
- def test_init(self, mock_mpi, mock_conf):
- # mock all of the local launcher functionality
- with patch('hbp_nrp_music_interface.launch.MUSICLauncher.os.environ.get',
- return_value='/somewhere/over/the/rainbow'):
- self.__launcher.initialize('env_file', None)
-
- # call to generate launch scripts
- self.__launcher._launcher.deploy.assert_called_once()
-
- # assert that all of the MPI configuration/launch commands were called
- self.__launcher.mpilauncher.add_host.assert_called_once_with('localhost', '/mock_host_tmpdir', 11)
- self.__launcher.mpilauncher.build.assert_called_once()
- self.__launcher.mpilauncher.launch.assert_called_once()
-
- @patch('os.system')
- def test_shutdown(self, system_mock):
-
- # mock the cleserver and launcher
- mock_cle_server = Mock()
- mock_cle_server.shutdown = Mock()
- mock_launcher = Mock()
- mock_launcher.shutdown = Mock()
-
- # set values like in init() and shutdown
- self.__launcher.mpilauncher = mock_cle_server
- self.__launcher._launcher = mock_launcher
- self.__launcher.shutdown()
-
- # make sure the mocked shutdowns are called
- mock_cle_server.shutdown.assert_called_once()
- mock_launcher.shutdown.assert_called_once()
-
- # verify the local variables are unset
- self.assertEqual(self.__launcher.mpilauncher, None)
- self.assertEqual(self.__launcher._launcher, None)
-
- # verify the ros cleanup command has been called
- system_mock.assert_called_once()
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/version.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/version.py
deleted file mode 100644
index cff3ffe..0000000
--- a/hbp_nrp_music_interface/hbp_nrp_music_interface/version.py
+++ /dev/null
@@ -1,2 +0,0 @@
-'''version string - generated by setVersion.sh'''
-VERSION = '2.3.0'
diff --git a/hbp_nrp_music_interface/requirements.txt b/hbp_nrp_music_interface/requirements.txt
deleted file mode 100644
index fb7fe6f..0000000
--- a/hbp_nrp_music_interface/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# third party requirements
-mpi4py==2.0.0
-netifaces==0.8
diff --git a/hbp_nrp_music_interface/requirements_extension_tests.txt b/hbp_nrp_music_interface/requirements_extension_tests.txt
deleted file mode 100644
index 031ce95..0000000
--- a/hbp_nrp_music_interface/requirements_extension_tests.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-#the following is required for the unit testing
-mock==1.0.1
-testfixtures==3.0.2
diff --git a/hbp_nrp_music_interface/setup.py b/hbp_nrp_music_interface/setup.py
deleted file mode 100644
index a164b22..0000000
--- a/hbp_nrp_music_interface/setup.py
+++ /dev/null
@@ -1,68 +0,0 @@
-'''setup.py'''
-
-from setuptools import setup
-
-import hbp_nrp_music_interface
-import pip
-
-from optparse import Option
-options = Option('--workaround')
-options.skip_requirements_regex = None
-reqs_file = './requirements.txt'
-if pip.__version__.startswith('10.'):
- # Versions greater or equal to 10.x don't rely on pip.req.parse_requirements
- install_reqs = list(val.strip() for val in open(reqs_file))
- reqs = install_reqs
-elif pip.__version__.startswith('1.'):
- # Versions 1.x rely on pip.req.parse_requirements
- # but don't require a "session" parameter
- from pip.req import parse_requirements # pylint:disable=no-name-in-module, import-error
- install_reqs = parse_requirements(reqs_file, options=options)
- reqs = [str(ir.req) for ir in install_reqs]
-else:
- # Versions greater than 1.x but smaller than 10.x rely on pip.req.parse_requirements
- # and requires a "session" parameter
- from pip.req import parse_requirements # pylint:disable=no-name-in-module, import-error
- from pip.download import PipSession # pylint:disable=no-name-in-module, import-error
- options.isolated_mode = False
- install_reqs = parse_requirements( # pylint:disable=unexpected-keyword-arg
- reqs_file,
- session=PipSession,
- options=options
- )
- reqs = [str(ir.req) for ir in install_reqs]
-
-# ensure we install numpy before the main list of requirements, ignore
-# failures if numpy/cython are not requirements and just proceed (future proof)
-try:
- cython_req = next(r for r in reqs if r.startswith('cython'))
- numpy_req = next(r for r in reqs if r.startswith('numpy'))
- if pip.__version__.startswith('10.'):
- import subprocess
- subprocess.check_call(
- ["python", '-m', 'pip', 'install', "--no-clean", "--user", cython_req, numpy_req]
- )
- else:
- pip.main(['install', '--no-clean', cython_req, numpy_req]) # pylint:disable=no-member
-# pylint: disable=bare-except
-except:
- pass
-
-config = {
- 'description': 'MUSIC interface support for CLE/ExDBackend for HBP SP10',
- 'author': 'HBP Neurorobotics',
- 'url': 'http://neurorobotics.net',
- 'author_email': 'neurorobotics@humanbrainproject.eu',
- 'version': hbp_nrp_music_interface.__version__,
- 'install_requires': reqs,
- 'packages': ['hbp_nrp_music_interface',
- 'hbp_nrp_music_interface.bibi',
- 'hbp_nrp_music_interface.cle',
- 'hbp_nrp_music_interface.launch',
- 'hbp_nrp_music_interface.launch.host'],
- 'scripts': [],
- 'name': 'hbp-nrp-music-interface',
- 'include_package_data': True,
-}
-
-setup(**config)
diff --git a/hbp_nrp_music_interface_deprec.tar.gz b/hbp_nrp_music_interface_deprec.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ebc23b26413abeef4eff06dbf95f40bbb0f70044
GIT binary patch
literal 25324
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%0AoYl)nlw%fNa
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
P|Fb_*{r`a>iHQLKmYL|u
literal 0
HcmV?d00001
diff --git a/hbp_nrp_music_xml/MANIFEST.in b/hbp_nrp_music_xml/MANIFEST.in
deleted file mode 100644
index 540b720..0000000
--- a/hbp_nrp_music_xml/MANIFEST.in
+++ /dev/null
@@ -1 +0,0 @@
-include requirements.txt
\ No newline at end of file
diff --git a/hbp_nrp_music_xml/README.txt b/hbp_nrp_music_xml/README.txt
deleted file mode 100644
index 4133956..0000000
--- a/hbp_nrp_music_xml/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This package provides an interface for creating and interacting with MUSIC XML configuration
-files - including reading/writing to a neuron/synapse XML format, generating a MUSIC script
-that can be used to instantiate MUSIC, and conversions to and from PyNN interfaces.
-
-This package does not depend on any other hbp_nrp dependencies and is loigically independent.
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/__init__.py
deleted file mode 100644
index 762853e..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-"""
-This package contains a XML schema and corresponding factories as well as
-utilities in order to programatically create MUSIC ports and connect them to
-PyNN populations.
-"""
-
-from hbp_nrp_music_xml.version import VERSION as __version__ # pylint: disable=W0611
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/config/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/config/__init__.py
deleted file mode 100644
index 9f1d4cc..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/config/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-This package provides a programatic interface to assemble a MUSIC-XML and
-MUSIC-config file
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/config/music_config.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/config/music_config.py
deleted file mode 100644
index a77db57..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/config/music_config.py
+++ /dev/null
@@ -1,154 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Programmatic interfaces to assemble MUSIC XML and config files.
-"""
-from hbp_nrp_music_xml.schema.generated import music_xml
-
-from ConfigParser import ConfigParser
-from types import NoneType
-import StringIO
-
-
-class Application(object):
- """
- Class to represent an application in the MUSIC context
- """
-
- def __init__(self, name, binary, args=None, num_processes=1):
- """
- :param name: A string to specify the application name
- :param binary: A string specifiying the binary to execute for this
- application process
- :param args: An ordered list of arguments for the binary.
- :param num_processes: The integer number of MPI instances for this process
- """
- assert isinstance(name, str)
- assert isinstance(binary, str)
- assert isinstance(args, (NoneType, list))
- assert isinstance(num_processes, int)
-
- self.name = name
- self.binary = binary
- self.args = '"{}"'.format(' '.join(args)) if args is not None else ''
- self.num_processes = num_processes
-
-
-class MusicConfigWriter(object):
- """
- This class helps to write a MUSIC-Config file
- """
-
- def __init__(self, header=None, applications=None, ports=None):
- """
- :param header: A dictionary object
- :param applications: A list of music_config.Application objects
- :param ports: A list of music_config.MusicConfigPort objects
- """
- assert isinstance(header, (NoneType, dict))
- assert isinstance(applications, (NoneType, list, tuple))
- assert isinstance(ports, (NoneType, list, tuple))
-
- self.header = header
- self.applications = applications
- self.ports = ports
-
- def write(self, file_handle):
- """
- Writes a string representing the MUSIC-Config to a file-like object
- :param file_handle: A file-like object
- """
- if self.header and len(self.header) > 0:
- for key, val in self.header.items():
- file_handle.write(u'{key} = "{val}"\n'.format(key=key, val=val))
- file_handle.write(u'\n')
-
- if self.applications:
- config = ConfigParser()
- for application in self.applications:
- config.add_section(application.name)
- config.set(application.name, 'np', application.num_processes)
- config.set(application.name, 'binary', application.binary)
- config.set(application.name, 'args', application.args)
-
- config.write(file_handle)
-
- if self.ports:
- for port in self.ports:
- file_handle.write(u'{port}\n'.format(port=port))
-
- def __str__(self):
- """
- Returns the MUSIC-Config as a python string
- """
-
- try:
- conf_io = StringIO.StringIO()
- self.write(conf_io)
- conf_str = conf_io.getvalue()
- except (UnicodeError, ValueError):
- raise Exception("Unable to encode MUSIC Configuration Script to String!")
- finally:
- conf_io.close()
-
- return conf_str
-
-
-class MusicConfigPort(object):
- """
- This class converts a MUSIC-XML Port object into a string
- representation in order to assemble the MUSIC config file
- """
-
- def __init__(self, music_xml_port):
- """
- :param music_xml_port: A music_xml.Port object
- """
- assert isinstance(music_xml_port, music_xml.Port)
- self.music_xml_port = music_xml_port
-
- def get_connection_strings(self):
- """
- Returns a list of port connectivity representations. The format complies
- with the format that is being used in the MUSIC-config files.
- """
- connection_strs = []
- for receiver in self.music_xml_port.receiver:
- connection_strs.append("{sender_name}.{port_name} -> "
- "{receiver_name}.{port_name} [{port_width}]".format(
- sender_name=self.music_xml_port.sender.name,
- port_name=self.music_xml_port.name,
- receiver_name=receiver.name,
- port_width=self.music_xml_port.width))
- return connection_strs
-
- def __str__(self):
- """
- Returns all connectivity representation strings as given by
- MusicConfigPort.get_connection_strings() but in a concatenated
- form. Different connectivity strings are seperated by new-line breaks.
- """
-
- connection_strs = self.get_connection_strings()
- return "\n".join(connection_strs)
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/__init__.py
deleted file mode 100644
index 679b1da..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-This package provides a programmatic interface to create MUSIC PyNN proxy devices
-from a MUSIC-XML specification.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/cell_types.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/cell_types.py
deleted file mode 100644
index 3af30bd..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/cell_types.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Provides utility functions for native cell types.
-"""
-
-__author__ = 'Martin Schulze'
-
-
-def load_cell_types(simulator):
- """
- This function provides a map containing PyNN wrappers around the simulator
- specific MUSIC proxy implementations
-
- :param simulator : The PyNN simulator (e.g. pyNN.nest)
- """
- cell_type_dict = {}
-
- if simulator.simulator.name == "NEST":
-
- music_event_out_proxy = simulator.native_cell_type('music_event_out_proxy')
- music_event_in_proxy = simulator.native_cell_type('music_event_in_proxy')
- parrot_neuron_type = simulator.native_cell_type('parrot_neuron')
-
- for model in [music_event_out_proxy, music_event_in_proxy, parrot_neuron_type]:
- model.default_initial_values = {}
- model.default_parameters = {}
-
- cell_type_dict['out'] = {'Event': music_event_out_proxy}
- cell_type_dict['in'] = {'Event': music_event_in_proxy}
- cell_type_dict['parrot'] = parrot_neuron_type
-
- else:
- raise Exception("Implementation for {simulator_name} not found"
- .format(simulator_name=simulator.name))
-
- return cell_type_dict
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/connector_factory.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/connector_factory.py
deleted file mode 100644
index cb4f47c..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/connector_factory.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-PyNN factory for PyNN projections between PyNN MUSIC proxy objects and other PyNN populations
-"""
-from hbp_nrp_music_xml.pynn.utils import desc_pynn_pop, pprint_pynn_pop, get_min_delay
-
-import logging
-
-__author__ = 'Martin Schulze'
-
-logger = logging.getLogger(__name__)
-
-
-class PyNNConnectorFactory(object):
- """
- PyNN factory for PyNN projections between PyNN MUSIC proxy objects and other PyNN populations
- """
-
- def __init__(self, simulator):
- """
- :param simulator: The PyNN simulator (e.g. pyNN.nest)
- """
- self.simulator = simulator
- self.connector_types = {'one_to_one': simulator.OneToOneConnector,
- 'all_to_all': simulator.AllToAllConnector}
-
- def create_and_connect_synapse(self, proxy, port_name, connection_rule, population_slice,
- target_population, is_output_proxy, synapse=None):
- """
- :param proxy: PyNN population that wraps the simulator specific MUSIC port implementation
- :param port_name: The name of the port
- :param connection_rule: {'one_to_one', 'all_to_all'} to connect proxy->target_population
- or target_population->proxy
- :param population_slice: Apply synapse only on subset (slice) of given target_population
- :param target_population: The target/source population
- :param is_output_proxy: A boolean which indicates whether the proxy to create represents an
- ingoing or outgoing connection
- :param synapse: Uses this PyNN synapse instead of 'StaticSynapse', default None
- """
-
- # only create default synapses to the cle ports since we will dynamically configure
- # device connectivity <-> proxies from the cle (e.g. spike generators or recorders)
- # but we need connectivity in the remote brain processes from parrot -> proxy so that
- # spikes are propagated
- if not port_name.endswith('to_cle'):
- return
-
- try:
- connector = self.connector_types[connection_rule]
- except KeyError, e:
- message = "Unsupported PyNN connector type: {connector_factory} does not support \
- '{synaptic_rule}' connectors."\
- .format(connector_factory=self.__class__, synaptic_rule=connection_rule)
- logger.error(message, exc_info=True)
- raise Exception(message)
-
- if population_slice:
- logger.debug("Applying slice {population_slice} on population {population_name}"
- .format(population_slice=population_slice,
- population_name=desc_pynn_pop(target_population)))
- target_population = self.simulator.PopulationView(target_population, population_slice)
-
- if is_output_proxy:
- presynaptic_population = target_population
- postsynaptic_population = proxy
- else:
- presynaptic_population = proxy
- postsynaptic_population = target_population
-
- direction_arrow = '-->' if not is_output_proxy else '<--'
- message = "Connecting port {port_name} {direction_arrow} PyNNPopulation \
- {postsynaptic_population}. Interface population for the proxy is\
- {presynaptic_population}"\
- .format(port_name=port_name, direction_arrow=direction_arrow,
- postsynaptic_population=desc_pynn_pop(postsynaptic_population),
- presynaptic_population=desc_pynn_pop(presynaptic_population))
- logger.debug(message)
-
- try:
- if not synapse:
- synaptic_delay = get_min_delay()
- synapse = self.simulator.StaticSynapse(weight=1.0, delay=synaptic_delay)
- self.simulator.Projection(presynaptic_population, postsynaptic_population,
- connector(), synapse)
- except Exception, e:
- logging.error(e, exc_info=True)
- logging.error('Debug information: \nStatus dictionaries of the \
- populations: \npresynaptic population: {presynaptic_population}\n\
- postsynaptic population: {postsynaptic_population}'.
- format(presynaptic_population=pprint_pynn_pop(presynaptic_population),
- postsynaptic_population=pprint_pynn_pop(postsynaptic_population)))
- raise Exception("Failure creating PyNN/MUSIC synapse: {}" % message)
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/factory.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/factory.py
deleted file mode 100644
index 080e941..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/factory.py
+++ /dev/null
@@ -1,188 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Factory class for PyNN MUSIC-proxy objects
-"""
-
-
-from hbp_nrp_music_xml.pynn.cell_types import load_cell_types
-from hbp_nrp_music_xml.pynn.utils import get_min_delay
-
-import nest
-import logging
-
-logger = logging.getLogger(__name__)
-
-__author__ = 'Martin Schulze'
-
-
-def create_proxy_via_native_cell_types(simulator, proxy_width, cell_type, port_name, proxy_type,
- acc_latency, is_output_proxy):
- """
- Creates the PyNN proxy representation of a MUSIC port
-
- :param simulator: The PyNN simulator (e.g. pyNN.nest)
- :param proxy_width: The number of proxies required to represent the port
- :param cell_type: The PyNN celltype that encapsulates the proxy mechanism of
- the underlying PyNN simulator
- :param port_name: The port name
- :param acc_latency: The maximum allowed latency in milisecond (ignored on output proxies)
- :param is_output_proxy: A boolean which indicates whether the proxy to create represents
- an ingoing or outgoing connection
- """
- assert simulator.simulator.name == "NEST", "Currently only NEST is supported"
-
- if not acc_latency:
- acc_latency = get_min_delay()
-
- proxy_label = "Port: {name}\nWidth: {width}".format(name=port_name, width=proxy_width)
- proxy = simulator.Population(proxy_width, cell_type, {}, label=proxy_label)
-
- proxy_ids = map(int, proxy.all_cells)
- nest.SetStatus(proxy_ids, 'port_name', port_name)
-
- # Acc. latency actually only matters for input ports
- if not is_output_proxy:
- nest.SetAcceptableLatency(port_name, acc_latency)
- logger.debug("Created {proxy_width} {port_direction} {port_type} proxy neurons with "
- "accLatency={port_acc_latency} for port {port_name} "
- .format(proxy_width=proxy_width, port_direction="input",
- port_type=proxy_type, port_acc_latency=acc_latency,
- port_name=port_name))
- else:
- logger.debug("Created {proxy_width} {port_direction} {port_type} proxy neurons for "
- "port {port_name}"
- .format(proxy_width=proxy_width, port_direction="output",
- port_type=proxy_type, port_name=port_name))
-
- if proxy_type == "Event" and not is_output_proxy:
- for i, proxy_id in enumerate(proxy_ids):
- nest.SetStatus([proxy_id], 'music_channel', i)
-
- return proxy
-
-
-def export_proxy(simulator, presynaptic_population, proxy, synaptic_delay=get_min_delay()):
- """
- This helper function connects a population to an output proxy.
-
- :param simulator: The PyNN simulator (e.g. pyNN.nest)
- :param presynaptic_population: A PyNN population that is to be connected to the
- desired output proxy
- :param proxy: The PyNN proxy population
- """
- assert simulator.simulator.name == "NEST", "Currently only NEST is supported"
-
- if not synaptic_delay:
- synaptic_delay = get_min_delay()
-
- presynaptic_neuron_ids = map(int, presynaptic_population.all_cells)
- proxy_ids = map(int, proxy.all_cells)
- connection_params = {'delay': synaptic_delay, 'weight': 1.0}
-
- for i, pre_id in enumerate(presynaptic_neuron_ids):
- connection_params.update(music_channel=i)
- nest.Connect([pre_id], proxy_ids, 'one_to_one', connection_params)
-
- logger.debug("Connected presynaptic population {population_name} to output proxy "
- "{proxy_name}"
- .format(population_name=presynaptic_population, proxy_name=proxy))
-
-
-class PyNNProxyFactory(object):
- """
- Factory class for PyNN MUSIC-proxy objects
- """
-
- def __init__(self, simulator, acc_latency=None, max_buffered=1):
- """
- :param simulator: The PyNN simulator (e.g. pyNN.nest)
- :param acc_latency: The maximum allowed latency in miliseconds
- :param max_buffered: TODO
- """
- assert simulator.simulator.name == "NEST", "Currently only NEST is supported"
-
- self.acc_latency = acc_latency
- self.max_buffered = max_buffered
- self.simulator = simulator
- self.cell_types = load_cell_types(simulator)
-
- def create_proxy(self, port_name, proxy_type, port_width, is_output_proxy, synaptic_delay=None):
- """
- Creates the actual PyNN MUSIC proxy object
-
- :param port_name: The name of the port
- :param proxy_type: {'Event', 'Message', 'Continuous'}
- :param port_width: The number of MUSIC connections for this port
- :param is_output_proxy: A boolean which indicates whether the proxy to create represents an
- ingoing or outgoing connection
- :param synaptic_delay: Sets the synaptic delay of the connection, defaults to simulator
- minimum synaptic delay
- """
-
- assert proxy_type == "Event", '{proxy_type} ports are currently not supported for PyNN.'\
- .format(proxy_type=proxy_type)
-
- if is_output_proxy:
- cell_type = self.cell_types['out'][proxy_type]
- # We only do need one output proxy (for spike_out_proxy and continuous_out_proxy)
- proxy_width = 1
- else:
- cell_type = self.cell_types['in'][proxy_type]
- proxy_width = port_width
-
- # Currently NEST specific, will be replaced by a MUSIC branch of PyNN
- proxy = create_proxy_via_native_cell_types(self.simulator, proxy_width, cell_type,
- port_name, proxy_type, self.acc_latency,
- is_output_proxy)
-
- if proxy_type == 'Event':
- if is_output_proxy:
- label = "Parrots for Port: {name}\nWidth: {width}"\
- .format(name=port_name, width=proxy_width)
- parrots = self.simulator.Population(port_width,
- self.cell_types['parrot'],
- {},
- label=label)
-
- export_proxy(self.simulator, parrots, proxy, synaptic_delay)
- logger.debug("Created {port_width} parrot neurons and connected it to outgoing "
- "port {port_name}"
- .format(port_width=port_width, port_name=port_name))
-
- # [NRRPLT-4722] workaround for lack of dynamic MUSIC ports, since we have many
- # more parrot neurons than required, freeze them. this means they will not be
- # updated until we explicitly thaw them during connection.
- if port_name.endswith('to_brain'):
- nest.SetStatus(map(int, parrots.all_cells), 'frozen', True)
-
- return parrots
- else:
- # [NRRPLT-4722] workaround for lack of dynamic MUSIC ports, since we have many
- # more parrot neurons than required, freeze them. this means they will not be
- # updated until we explicitly thaw them during connection.
- if port_name.endswith('to_brain'):
- nest.SetStatus(map(int, proxy.all_cells), 'frozen', True)
-
- return proxy
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/utils.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/utils.py
deleted file mode 100644
index 5999fcc..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/utils.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Common Nest/PyNN helper utility functions.
-"""
-
-import pprint
-import nest
-
-__author__ = 'Martin Schulze'
-
-pp = pprint.PrettyPrinter(indent=4)
-
-
-def desc_pynn_pop(pop):
- """
- Return a string with a high-level description of a PyNN population.
-
- :param pop: The PyNN population to describe.
- """
- return "<Type: {cell_type}, Width: {population_width}, Label: {population_label}>"\
- .format(cell_type=pop.celltype, population_width=pop.size, population_label=pop.label)
-
-
-def desc_nest_pop(ids):
- """
- Return a string with a high-level description of a Nest population.
-
- :param pop: The Nest population to describe.
- """
- return "<Model: {nest_model_name}, Width: {population_width}>"\
- .format(nest_model_name=nest.GetStatus(list(ids), 'model'),
- population_width=len(list(ids)))
-
-
-def pprint_pynn_pop(pop):
- """
- Return a string with a detailed population level description of a PyNN population.
-
- :param pop: The PyNN population to describe.
- """
- return pp.pformat(nest.GetStatus(map(int, pop.all_cells)))
-
-
-def get_min_delay():
- """
- Returns the minimum delay of the simulator.
- """
- return nest.GetKernelStatus()['min_delay']
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/xml_factory.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/xml_factory.py
deleted file mode 100644
index 340c181..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/pynn/xml_factory.py
+++ /dev/null
@@ -1,249 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-"""
-Provides a high level interface to convert a MUSIC XML file into MUSIC proxies.
-"""
-
-from hbp_nrp_music_xml.schema.generated import music_xml
-
-from collections import OrderedDict
-from prettytable import PrettyTable
-from operator import attrgetter
-
-import logging
-
-logger = logging.getLogger(__name__)
-
-__author__ = 'Martin Schulze'
-
-
-def extract_kwargs(xml_parameter_list):
- """
- Extracts keyword arguments from a music_xml.ParameterList object
-
- :param xml_parameter_list: music_xml.ParameterList object
- """
-
- if not xml_parameter_list:
- return {}
- kwargs = {}
- for elem in xml_parameter_list.orderedContent():
- kwargs[elem.value.name] = elem.value.content()
- return kwargs
-
-
-def is_application_receiver(application_name, xml_port):
- """
- Returns 'True' if the application with 'application_name' is a receiver with
- respect to the provided xml_port. Returns 'False' else
-
- :param application_name: The application name
- :param xml_port: music_xml.Port object
- """
-
- xml_receivers = xml_port.receiver
- receiver_names = map(attrgetter('name'), xml_receivers)
- if application_name in receiver_names:
- return True
- return False
-
-
-def build_port_overview_table(xml_ports, application_name):
- """
- Constructs a tabular overview in string representation for logging purposes
-
- :param xml_ports: A list of music_xml.Port objects
- :param application_name: The name of the current application (will be shown
- in the table header)
- """
-
- overview_table = PrettyTable(['Portname', 'Type', 'Width', 'Direction'])
- for xml_port in xml_ports:
- xml_sender = xml_port.sender
- direction = "Outgoing" if xml_sender.name == application_name else \
- "Ingoing"
- port_name = xml_port.name
- port_type = xml_port.type
- width = int(xml_port.width)
- if xml_sender.name == application_name or \
- is_application_receiver(application_name, xml_port):
- overview_table.add_row([port_name, port_type, width, direction])
- return overview_table
-
-
-def create_pop_slice(xml_selector):
- """
- Returns either a python-slice or a list, depending on the type of xml_selector
-
- :param xml_selector: music_xml.SelectorType
- """
- if isinstance(xml_selector, music_xml.SliceSelector):
- return slice(xml_selector.start, xml_selector.stop, xml_selector.step)
- elif isinstance(xml_selector, music_xml.ListSelector):
- elements = [x for x in xml_selector.element]
- return elements
- else:
- raise Exception("Can not convert object {xml_selector} to a "
- "slice-like object. Unknown selector type"
- .format(xml_selector=xml_selector))
-
-
-def create_selector(xml_synapse):
- """
- Returns a python-slice or list if a synaptic selector has been specified
- in the xml_synapse
-
- :param xml_synapse: music_xml.SynapticConnectionType
- """
-
- xml_selector = getattr(xml_synapse, 'selector', None)
- if xml_selector:
- selector = create_pop_slice(xml_selector)
- else:
- selector = None
- return selector
-
-
-class XmlFactory(object):
- """
- This class helps unpacking the MUSIC-XML and makes subsequent calls to the
- desired proxy/connector factories
- """
-
- def __init__(self, application_name, connector_factory, proxy_factory,
- population_dict):
- """
- :param application_name: The name of the application (process) where
- this factory is instantiated on
- :param connector_factory: A factory class to create PyNN ports
- :param proxy_factory: A factory class to create PyNN wrappers around
- simulator specific MUSIC proxy objects
- :param population_dict: A dictionary containing population names as keys
- and PyNN population objects as values. If the XML specifies synaptic
- connections between proxies and populations then this dictionary
- provides the respective mapping
- """
- self.application_name = application_name
- self.connector_factory = connector_factory
- self.proxy_factory = proxy_factory
- self.population_dict = population_dict
-
- def _get_synaptic_target_population(self, xml_synapse):
- """
- Returns the target/source population as specified in the xml_synapse
- object provided the population has been passed along with the
- population dictionary in the constructor
-
- :param xml_synapse: music_xml.SynapticConnectionType object
- """
-
- population_name = getattr(xml_synapse, 'target')
- try:
- target_population = self.population_dict[population_name]
- except KeyError:
- raise Exception("Population with dictionary key {population_name} "
- "has not been found in the provided "
- "population-dictionary."
- .format(population_name=population_name))
- return target_population
-
- def _create_and_connect_proxy(self, xml_port, xml_peer, is_output_proxy):
- """
- Creates a PyNN proxy for a specific MUSIC port and connects it to a
- source/target population as long this is specified in the
- xml_port.
-
- :param xml_port: music_xml.Port object
- :param xml_peer: music_xml.PeerType object, represents a sender or
- receiver application
- :param is_output_proxy: A boolean to indicate whether the proxy is
- inbound or outbound
- """
- port_name = xml_port.name
- port_type = xml_port.type
- width = int(xml_port.width)
-
- proxy = self.proxy_factory.create_proxy(port_name, port_type, width,
- is_output_proxy)
- xml_synapses = getattr(xml_peer, 'synapse', None)
- if not xml_synapses:
- raise Exception("No synapse connectivity specified for port {}, invalid "
- "configuration!".format(port_name))
-
- if self.population_dict and len(self.population_dict) > 0:
- for xml_synapse in xml_synapses:
- population_slice = create_selector(xml_synapse)
- connection_rule = xml_synapse.type
- synaptic_target = self._get_synaptic_target_population(xml_synapse)
- if hasattr(synaptic_target, 'mask'): # prevent duplicate slicing
- population_slice = None
- self.connector_factory.create_and_connect_synapse(proxy,
- port_name,
- connection_rule,
- population_slice,
- synaptic_target,
- is_output_proxy)
- return proxy
-
- def _assemble_proxy(self, xml_port):
- """
- Assembles and connects all PyNN proxy objects for a specific port.
- Returns a population to interface the MUSIC ports
-
- :param xml_port: music_xml.Port
- """
-
- xml_sender = xml_port.sender
- xml_receivers = xml_port.receiver
-
- if xml_sender.name == self.application_name:
- for xml_receiver in list(xml_receivers):
- return self._create_and_connect_proxy(xml_port, xml_receiver, True)
- else:
- for xml_receiver in list(xml_receivers):
- if xml_receiver.name == self.application_name:
- return self._create_and_connect_proxy(xml_port,
- xml_receiver, False)
-
- def create_proxies(self, xml_string):
- """
- This method parses, reads and creates and connects all MUSIC proxy
- objects and returns a dictionary with keys: port_name and value: PyNN
- populations that represent the MUSIC ports).
-
- :param xml_string: A raw string containing valid MUSIC-XML content
- """
-
- logger.debug("Parsing XML File")
- xml_root = music_xml.CreateFromDocument(xml_string)
- xml_ports = xml_root.port
- proxy_dict = OrderedDict()
- port_overview_table = build_port_overview_table(xml_ports,
- self.application_name)
- logger.debug("\nPort overview of application: "
- "{}\n{}".format(self.application_name, port_overview_table))
- for xml_port in xml_ports:
- proxy = self._assemble_proxy(xml_port)
- proxy_dict[xml_port.name] = proxy
- return proxy_dict
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/__init__.py
deleted file mode 100644
index 1610e00..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""
-XML Schema and generated pyxb file for MUSIC configuration file.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/__init__.py
deleted file mode 100644
index e79ff7a..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""
-Generated pyxb file for MUSIC schema.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/music_xml.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/music_xml.py
deleted file mode 100644
index b5c25e0..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated/music_xml.py
+++ /dev/null
@@ -1,743 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-# ./music_xml.py
-# -*- coding: utf-8 -*-
-# PyXB bindings for NM:e92452c8d3e28a9e27abfc9994d2007779e7f4c9
-# Generated 2016-09-16 13:06:43.146805 by PyXB version 1.2.4 using Python 2.7.6.final.0
-# Namespace AbsentNamespace0
-
-from __future__ import unicode_literals
-import pyxb
-import pyxb.binding
-import pyxb.binding.saxer
-import io
-import pyxb.utils.utility
-import pyxb.utils.domutils
-import sys
-import pyxb.utils.six as _six
-
-# Unique identifier for bindings created at the same time
-_GenerationUID = pyxb.utils.utility.UniqueIdentifier('urn:uuid:398b796a-7d06-11e6-91a7-e4b318398898')
-
-# Version of PyXB used to generate the bindings
-_PyXBVersion = '1.2.4'
-# Generated bindings are not compatible across PyXB versions
-if pyxb.__version__ != _PyXBVersion:
- raise pyxb.PyXBVersionError(_PyXBVersion)
-
-# Import bindings for namespaces imported into schema
-import pyxb.binding.datatypes
-
-# NOTE: All namespace declarations are reserved within the binding
-Namespace = pyxb.namespace.CreateAbsentNamespace()
-Namespace.configureCategories(['typeBinding', 'elementBinding'])
-
-def CreateFromDocument (xml_text, default_namespace=None, location_base=None):
- """Parse the given XML and use the document element to create a
- Python instance.
-
- @param xml_text An XML document. This should be data (Python 2
- str or Python 3 bytes), or a text (Python 2 unicode or Python 3
- str) in the L{pyxb._InputEncoding} encoding.
-
- @keyword default_namespace The L{pyxb.Namespace} instance to use as the
- default namespace where there is no default namespace in scope.
- If unspecified or C{None}, the namespace of the module containing
- this function will be used.
-
- @keyword location_base: An object to be recorded as the base of all
- L{pyxb.utils.utility.Location} instances associated with events and
- objects handled by the parser. You might pass the URI from which
- the document was obtained.
- """
-
- if pyxb.XMLStyle_saxer != pyxb._XMLStyle:
- dom = pyxb.utils.domutils.StringToDOM(xml_text)
- return CreateFromDOM(dom.documentElement, default_namespace=default_namespace)
- if default_namespace is None:
- default_namespace = Namespace.fallbackNamespace()
- saxer = pyxb.binding.saxer.make_parser(fallback_namespace=default_namespace, location_base=location_base)
- handler = saxer.getContentHandler()
- xmld = xml_text
- if isinstance(xmld, _six.text_type):
- xmld = xmld.encode(pyxb._InputEncoding)
- saxer.parse(io.BytesIO(xmld))
- instance = handler.rootObject()
- return instance
-
-def CreateFromDOM (node, default_namespace=None):
- """Create a Python instance from the given DOM node.
- The node tag must correspond to an element declaration in this module.
-
- @deprecated: Forcing use of DOM interface is unnecessary; use L{CreateFromDocument}."""
- if default_namespace is None:
- default_namespace = Namespace.fallbackNamespace()
- return pyxb.binding.basis.element.AnyCreateFromDOM(node, default_namespace)
-
-
-# Atomic simple type: PortType
-class PortType (pyxb.binding.datatypes.string, pyxb.binding.basis.enumeration_mixin):
-
- """An atomic simple type."""
-
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'PortType')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 40, 2)
- _Documentation = None
-PortType._CF_enumeration = pyxb.binding.facets.CF_enumeration(value_datatype=PortType, enum_prefix=None)
-PortType.Event = PortType._CF_enumeration.addEnumeration(unicode_value='Event', tag='Event')
-PortType.Continuous = PortType._CF_enumeration.addEnumeration(unicode_value='Continuous', tag='Continuous')
-PortType.Message = PortType._CF_enumeration.addEnumeration(unicode_value='Message', tag='Message')
-PortType._InitializeFacetMap(PortType._CF_enumeration)
-Namespace.addCategoryObject('typeBinding', 'PortType', PortType)
-
-# Atomic simple type: ConnectionType
-class ConnectionType (pyxb.binding.datatypes.string, pyxb.binding.basis.enumeration_mixin):
-
- """An atomic simple type."""
-
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'ConnectionType')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 64, 2)
- _Documentation = None
-ConnectionType._CF_enumeration = pyxb.binding.facets.CF_enumeration(value_datatype=ConnectionType, enum_prefix=None)
-ConnectionType.one_to_one = ConnectionType._CF_enumeration.addEnumeration(unicode_value='one_to_one', tag='one_to_one')
-ConnectionType.all_to_all = ConnectionType._CF_enumeration.addEnumeration(unicode_value='all_to_all', tag='all_to_all')
-ConnectionType._InitializeFacetMap(ConnectionType._CF_enumeration)
-Namespace.addCategoryObject('typeBinding', 'ConnectionType', ConnectionType)
-
-# Complex type [anonymous] with content type ELEMENT_ONLY
-class CTD_ANON (pyxb.binding.basis.complexTypeDefinition):
- """Complex type [anonymous] with content type ELEMENT_ONLY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
- _Abstract = False
- _ExpandedName = None
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 10, 4)
- _ElementMap = {}
- _AttributeMap = {}
- # Base type is pyxb.binding.datatypes.anyType
-
- # Element port uses Python identifier port
- __port = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'port'), 'port', '__AbsentNamespace0_CTD_ANON_port', True, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 12, 8), )
-
-
- port = property(__port.value, __port.set, None, None)
-
- _ElementMap.update({
- __port.name() : __port
- })
- _AttributeMap.update({
-
- })
-
-
-
-# Complex type Port with content type ELEMENT_ONLY
-class Port (pyxb.binding.basis.complexTypeDefinition):
- """Complex type Port with content type ELEMENT_ONLY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
- _Abstract = False
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'Port')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 25, 2)
- _ElementMap = {}
- _AttributeMap = {}
- # Base type is pyxb.binding.datatypes.anyType
-
- # Element type uses Python identifier type
- __type = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'type'), 'type', '__AbsentNamespace0_Port_type', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 27, 6), )
-
-
- type = property(__type.value, __type.set, None, None)
-
-
- # Element name uses Python identifier name
- __name = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'name'), 'name', '__AbsentNamespace0_Port_name', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 28, 6), )
-
-
- name = property(__name.value, __name.set, None, None)
-
-
- # Element width uses Python identifier width
- __width = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'width'), 'width', '__AbsentNamespace0_Port_width', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 29, 6), )
-
-
- width = property(__width.value, __width.set, None, None)
-
-
- # Element sender uses Python identifier sender
- __sender = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'sender'), 'sender', '__AbsentNamespace0_Port_sender', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 30, 6), )
-
-
- sender = property(__sender.value, __sender.set, None, None)
-
-
- # Element receiver uses Python identifier receiver
- __receiver = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'receiver'), 'receiver', '__AbsentNamespace0_Port_receiver', True, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 31, 6), )
-
-
- receiver = property(__receiver.value, __receiver.set, None, None)
-
- _ElementMap.update({
- __type.name() : __type,
- __name.name() : __name,
- __width.name() : __width,
- __sender.name() : __sender,
- __receiver.name() : __receiver
- })
- _AttributeMap.update({
-
- })
-Namespace.addCategoryObject('typeBinding', 'Port', Port)
-
-
-# Complex type Peer with content type ELEMENT_ONLY
-class Peer (pyxb.binding.basis.complexTypeDefinition):
- """Complex type Peer with content type ELEMENT_ONLY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
- _Abstract = False
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'Peer')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 49, 2)
- _ElementMap = {}
- _AttributeMap = {}
- # Base type is pyxb.binding.datatypes.anyType
-
- # Element name uses Python identifier name
- __name = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'name'), 'name', '__AbsentNamespace0_Peer_name', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 51, 6), )
-
-
- name = property(__name.value, __name.set, None, None)
-
-
- # Element synapse uses Python identifier synapse
- __synapse = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'synapse'), 'synapse', '__AbsentNamespace0_Peer_synapse', True, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 52, 6), )
-
-
- synapse = property(__synapse.value, __synapse.set, None, None)
-
-
- # Element parameters uses Python identifier parameters
- __parameters = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'parameters'), 'parameters', '__AbsentNamespace0_Peer_parameters', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 53, 6), )
-
-
- parameters = property(__parameters.value, __parameters.set, None, None)
-
- _ElementMap.update({
- __name.name() : __name,
- __synapse.name() : __synapse,
- __parameters.name() : __parameters
- })
- _AttributeMap.update({
-
- })
-Namespace.addCategoryObject('typeBinding', 'Peer', Peer)
-
-
-# Complex type SynapticConnection with content type ELEMENT_ONLY
-class SynapticConnection (pyxb.binding.basis.complexTypeDefinition):
- """Complex type SynapticConnection with content type ELEMENT_ONLY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
- _Abstract = False
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'SynapticConnection')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 56, 2)
- _ElementMap = {}
- _AttributeMap = {}
- # Base type is pyxb.binding.datatypes.anyType
-
- # Element target uses Python identifier target
- __target = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'target'), 'target', '__AbsentNamespace0_SynapticConnection_target', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 58, 6), )
-
-
- target = property(__target.value, __target.set, None, None)
-
-
- # Element type uses Python identifier type
- __type = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'type'), 'type', '__AbsentNamespace0_SynapticConnection_type', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 59, 6), )
-
-
- type = property(__type.value, __type.set, None, None)
-
-
- # Element selector uses Python identifier selector
- __selector = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'selector'), 'selector', '__AbsentNamespace0_SynapticConnection_selector', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 60, 6), )
-
-
- selector = property(__selector.value, __selector.set, None, None)
-
-
- # Element parameters uses Python identifier parameters
- __parameters = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'parameters'), 'parameters', '__AbsentNamespace0_SynapticConnection_parameters', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 61, 6), )
-
-
- parameters = property(__parameters.value, __parameters.set, None, None)
-
- _ElementMap.update({
- __target.name() : __target,
- __type.name() : __type,
- __selector.name() : __selector,
- __parameters.name() : __parameters
- })
- _AttributeMap.update({
-
- })
-Namespace.addCategoryObject('typeBinding', 'SynapticConnection', SynapticConnection)
-
-
-# Complex type SynapticSelector with content type EMPTY
-class SynapticSelector (pyxb.binding.basis.complexTypeDefinition):
- """Complex type SynapticSelector with content type EMPTY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_EMPTY
- _Abstract = True
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'SynapticSelector')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 72, 2)
- _ElementMap = {}
- _AttributeMap = {}
- # Base type is pyxb.binding.datatypes.anyType
- _ElementMap.update({
-
- })
- _AttributeMap.update({
-
- })
-Namespace.addCategoryObject('typeBinding', 'SynapticSelector', SynapticSelector)
-
-
-# Complex type ParameterList with content type ELEMENT_ONLY
-class ParameterList (pyxb.binding.basis.complexTypeDefinition):
- """Complex type ParameterList with content type ELEMENT_ONLY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
- _Abstract = False
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'ParameterList')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 95, 2)
- _ElementMap = {}
- _AttributeMap = {}
- # Base type is pyxb.binding.datatypes.anyType
-
- # Element parameter uses Python identifier parameter
- __parameter = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'parameter'), 'parameter', '__AbsentNamespace0_ParameterList_parameter', True, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 97, 6), )
-
-
- parameter = property(__parameter.value, __parameter.set, None, None)
-
- _ElementMap.update({
- __parameter.name() : __parameter
- })
- _AttributeMap.update({
-
- })
-Namespace.addCategoryObject('typeBinding', 'ParameterList', ParameterList)
-
-
-# Complex type Parameter with content type SIMPLE
-class Parameter (pyxb.binding.basis.complexTypeDefinition):
- """Complex type Parameter with content type SIMPLE"""
- _TypeDefinition = pyxb.binding.datatypes.string
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_SIMPLE
- _Abstract = False
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'Parameter')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 100, 2)
- _ElementMap = {}
- _AttributeMap = {}
- # Base type is pyxb.binding.datatypes.string
-
- # Attribute name uses Python identifier name
- __name = pyxb.binding.content.AttributeUse(pyxb.namespace.ExpandedName(None, 'name'), 'name', '__AbsentNamespace0_Parameter_name', pyxb.binding.datatypes.string, required=True)
- __name._DeclarationLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 103, 8)
- __name._UseLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 103, 8)
-
- name = property(__name.value, __name.set, None, None)
-
- _ElementMap.update({
-
- })
- _AttributeMap.update({
- __name.name() : __name
- })
-Namespace.addCategoryObject('typeBinding', 'Parameter', Parameter)
-
-
-# Complex type SliceSelector with content type ELEMENT_ONLY
-class SliceSelector (SynapticSelector):
- """Complex type SliceSelector with content type ELEMENT_ONLY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
- _Abstract = False
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'SliceSelector')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 73, 2)
- _ElementMap = SynapticSelector._ElementMap.copy()
- _AttributeMap = SynapticSelector._AttributeMap.copy()
- # Base type is SynapticSelector
-
- # Element start uses Python identifier start
- __start = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'start'), 'start', '__AbsentNamespace0_SliceSelector_start', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 77, 10), )
-
-
- start = property(__start.value, __start.set, None, None)
-
-
- # Element stop uses Python identifier stop
- __stop = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'stop'), 'stop', '__AbsentNamespace0_SliceSelector_stop', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 78, 10), )
-
-
- stop = property(__stop.value, __stop.set, None, None)
-
-
- # Element step uses Python identifier step
- __step = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'step'), 'step', '__AbsentNamespace0_SliceSelector_step', False, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 79, 10), )
-
-
- step = property(__step.value, __step.set, None, None)
-
- _ElementMap.update({
- __start.name() : __start,
- __stop.name() : __stop,
- __step.name() : __step
- })
- _AttributeMap.update({
-
- })
-Namespace.addCategoryObject('typeBinding', 'SliceSelector', SliceSelector)
-
-
-# Complex type ListSelector with content type ELEMENT_ONLY
-class ListSelector (SynapticSelector):
- """Complex type ListSelector with content type ELEMENT_ONLY"""
- _TypeDefinition = None
- _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
- _Abstract = False
- _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'ListSelector')
- _XSDLocation = pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 84, 2)
- _ElementMap = SynapticSelector._ElementMap.copy()
- _AttributeMap = SynapticSelector._AttributeMap.copy()
- # Base type is SynapticSelector
-
- # Element element uses Python identifier element
- __element = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'element'), 'element', '__AbsentNamespace0_ListSelector_element', True, pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 88, 10), )
-
-
- element = property(__element.value, __element.set, None, None)
-
- _ElementMap.update({
- __element.name() : __element
- })
- _AttributeMap.update({
-
- })
-Namespace.addCategoryObject('typeBinding', 'ListSelector', ListSelector)
-
-
-root = pyxb.binding.basis.element(pyxb.namespace.ExpandedName(Namespace, 'root'), CTD_ANON, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 9, 2))
-Namespace.addCategoryObject('elementBinding', root.name().localName(), root)
-
-
-
-CTD_ANON._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'port'), Port, scope=CTD_ANON, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 12, 8)))
-
-def _BuildAutomaton ():
- # Remove this helper function from the namespace after it is invoked
- global _BuildAutomaton
- del _BuildAutomaton
- import pyxb.utils.fac as fac
-
- counters = set()
- states = []
- final_update = set()
- symbol = pyxb.binding.content.ElementUse(CTD_ANON._UseForTag(pyxb.namespace.ExpandedName(None, 'port')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 12, 8))
- st_0 = fac.State(symbol, is_initial=True, final_update=final_update, is_unordered_catenation=False)
- states.append(st_0)
- transitions = []
- transitions.append(fac.Transition(st_0, [
- ]))
- st_0._set_transitionSet(transitions)
- return fac.Automaton(states, counters, False, containing_state=None)
-CTD_ANON._Automaton = _BuildAutomaton()
-
-
-
-
-Port._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'type'), PortType, scope=Port, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 27, 6)))
-
-Port._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'name'), pyxb.binding.datatypes.string, scope=Port, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 28, 6)))
-
-Port._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'width'), pyxb.binding.datatypes.positiveInteger, scope=Port, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 29, 6)))
-
-Port._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'sender'), Peer, scope=Port, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 30, 6)))
-
-Port._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'receiver'), Peer, scope=Port, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 31, 6)))
-
-def _BuildAutomaton_ ():
- # Remove this helper function from the namespace after it is invoked
- global _BuildAutomaton_
- del _BuildAutomaton_
- import pyxb.utils.fac as fac
-
- counters = set()
- states = []
- final_update = None
- symbol = pyxb.binding.content.ElementUse(Port._UseForTag(pyxb.namespace.ExpandedName(None, 'type')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 27, 6))
- st_0 = fac.State(symbol, is_initial=True, final_update=final_update, is_unordered_catenation=False)
- states.append(st_0)
- final_update = None
- symbol = pyxb.binding.content.ElementUse(Port._UseForTag(pyxb.namespace.ExpandedName(None, 'name')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 28, 6))
- st_1 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_1)
- final_update = None
- symbol = pyxb.binding.content.ElementUse(Port._UseForTag(pyxb.namespace.ExpandedName(None, 'width')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 29, 6))
- st_2 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_2)
- final_update = None
- symbol = pyxb.binding.content.ElementUse(Port._UseForTag(pyxb.namespace.ExpandedName(None, 'sender')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 30, 6))
- st_3 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_3)
- final_update = set()
- symbol = pyxb.binding.content.ElementUse(Port._UseForTag(pyxb.namespace.ExpandedName(None, 'receiver')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 31, 6))
- st_4 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_4)
- transitions = []
- transitions.append(fac.Transition(st_1, [
- ]))
- st_0._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_2, [
- ]))
- st_1._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_3, [
- ]))
- st_2._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_4, [
- ]))
- st_3._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_4, [
- ]))
- st_4._set_transitionSet(transitions)
- return fac.Automaton(states, counters, False, containing_state=None)
-Port._Automaton = _BuildAutomaton_()
-
-
-
-
-Peer._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'name'), pyxb.binding.datatypes.string, scope=Peer, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 51, 6)))
-
-Peer._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'synapse'), SynapticConnection, scope=Peer, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 52, 6)))
-
-Peer._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'parameters'), ParameterList, scope=Peer, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 53, 6)))
-
-def _BuildAutomaton_2 ():
- # Remove this helper function from the namespace after it is invoked
- global _BuildAutomaton_2
- del _BuildAutomaton_2
- import pyxb.utils.fac as fac
-
- counters = set()
- cc_0 = fac.CounterCondition(min=0, max=None, metadata=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 52, 6))
- counters.add(cc_0)
- cc_1 = fac.CounterCondition(min=0, max=1, metadata=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 53, 6))
- counters.add(cc_1)
- states = []
- final_update = set()
- symbol = pyxb.binding.content.ElementUse(Peer._UseForTag(pyxb.namespace.ExpandedName(None, 'name')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 51, 6))
- st_0 = fac.State(symbol, is_initial=True, final_update=final_update, is_unordered_catenation=False)
- states.append(st_0)
- final_update = set()
- final_update.add(fac.UpdateInstruction(cc_0, False))
- symbol = pyxb.binding.content.ElementUse(Peer._UseForTag(pyxb.namespace.ExpandedName(None, 'synapse')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 52, 6))
- st_1 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_1)
- final_update = set()
- final_update.add(fac.UpdateInstruction(cc_1, False))
- symbol = pyxb.binding.content.ElementUse(Peer._UseForTag(pyxb.namespace.ExpandedName(None, 'parameters')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 53, 6))
- st_2 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_2)
- transitions = []
- transitions.append(fac.Transition(st_1, [
- ]))
- transitions.append(fac.Transition(st_2, [
- ]))
- st_0._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_1, [
- fac.UpdateInstruction(cc_0, True) ]))
- transitions.append(fac.Transition(st_2, [
- fac.UpdateInstruction(cc_0, False) ]))
- st_1._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_2, [
- fac.UpdateInstruction(cc_1, True) ]))
- st_2._set_transitionSet(transitions)
- return fac.Automaton(states, counters, False, containing_state=None)
-Peer._Automaton = _BuildAutomaton_2()
-
-
-
-
-SynapticConnection._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'target'), pyxb.binding.datatypes.string, scope=SynapticConnection, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 58, 6)))
-
-SynapticConnection._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'type'), ConnectionType, scope=SynapticConnection, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 59, 6)))
-
-SynapticConnection._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'selector'), SynapticSelector, scope=SynapticConnection, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 60, 6)))
-
-SynapticConnection._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'parameters'), ParameterList, scope=SynapticConnection, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 61, 6)))
-
-def _BuildAutomaton_3 ():
- # Remove this helper function from the namespace after it is invoked
- global _BuildAutomaton_3
- del _BuildAutomaton_3
- import pyxb.utils.fac as fac
-
- counters = set()
- cc_0 = fac.CounterCondition(min=0, max=1, metadata=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 61, 6))
- counters.add(cc_0)
- states = []
- final_update = None
- symbol = pyxb.binding.content.ElementUse(SynapticConnection._UseForTag(pyxb.namespace.ExpandedName(None, 'target')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 58, 6))
- st_0 = fac.State(symbol, is_initial=True, final_update=final_update, is_unordered_catenation=False)
- states.append(st_0)
- final_update = None
- symbol = pyxb.binding.content.ElementUse(SynapticConnection._UseForTag(pyxb.namespace.ExpandedName(None, 'type')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 59, 6))
- st_1 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_1)
- final_update = set()
- symbol = pyxb.binding.content.ElementUse(SynapticConnection._UseForTag(pyxb.namespace.ExpandedName(None, 'selector')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 60, 6))
- st_2 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_2)
- final_update = set()
- final_update.add(fac.UpdateInstruction(cc_0, False))
- symbol = pyxb.binding.content.ElementUse(SynapticConnection._UseForTag(pyxb.namespace.ExpandedName(None, 'parameters')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 61, 6))
- st_3 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_3)
- transitions = []
- transitions.append(fac.Transition(st_1, [
- ]))
- st_0._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_2, [
- ]))
- st_1._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_3, [
- ]))
- st_2._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_3, [
- fac.UpdateInstruction(cc_0, True) ]))
- st_3._set_transitionSet(transitions)
- return fac.Automaton(states, counters, False, containing_state=None)
-SynapticConnection._Automaton = _BuildAutomaton_3()
-
-
-
-
-ParameterList._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'parameter'), Parameter, scope=ParameterList, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 97, 6)))
-
-def _BuildAutomaton_4 ():
- # Remove this helper function from the namespace after it is invoked
- global _BuildAutomaton_4
- del _BuildAutomaton_4
- import pyxb.utils.fac as fac
-
- counters = set()
- states = []
- final_update = set()
- symbol = pyxb.binding.content.ElementUse(ParameterList._UseForTag(pyxb.namespace.ExpandedName(None, 'parameter')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 97, 6))
- st_0 = fac.State(symbol, is_initial=True, final_update=final_update, is_unordered_catenation=False)
- states.append(st_0)
- transitions = []
- transitions.append(fac.Transition(st_0, [
- ]))
- st_0._set_transitionSet(transitions)
- return fac.Automaton(states, counters, False, containing_state=None)
-ParameterList._Automaton = _BuildAutomaton_4()
-
-
-
-
-SliceSelector._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'start'), pyxb.binding.datatypes.nonNegativeInteger, scope=SliceSelector, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 77, 10)))
-
-SliceSelector._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'stop'), pyxb.binding.datatypes.positiveInteger, scope=SliceSelector, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 78, 10)))
-
-SliceSelector._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'step'), pyxb.binding.datatypes.positiveInteger, scope=SliceSelector, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 79, 10)))
-
-def _BuildAutomaton_5 ():
- # Remove this helper function from the namespace after it is invoked
- global _BuildAutomaton_5
- del _BuildAutomaton_5
- import pyxb.utils.fac as fac
-
- counters = set()
- states = []
- final_update = None
- symbol = pyxb.binding.content.ElementUse(SliceSelector._UseForTag(pyxb.namespace.ExpandedName(None, 'start')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 77, 10))
- st_0 = fac.State(symbol, is_initial=True, final_update=final_update, is_unordered_catenation=False)
- states.append(st_0)
- final_update = None
- symbol = pyxb.binding.content.ElementUse(SliceSelector._UseForTag(pyxb.namespace.ExpandedName(None, 'stop')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 78, 10))
- st_1 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_1)
- final_update = set()
- symbol = pyxb.binding.content.ElementUse(SliceSelector._UseForTag(pyxb.namespace.ExpandedName(None, 'step')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 79, 10))
- st_2 = fac.State(symbol, is_initial=False, final_update=final_update, is_unordered_catenation=False)
- states.append(st_2)
- transitions = []
- transitions.append(fac.Transition(st_1, [
- ]))
- st_0._set_transitionSet(transitions)
- transitions = []
- transitions.append(fac.Transition(st_2, [
- ]))
- st_1._set_transitionSet(transitions)
- transitions = []
- st_2._set_transitionSet(transitions)
- return fac.Automaton(states, counters, False, containing_state=None)
-SliceSelector._Automaton = _BuildAutomaton_5()
-
-
-
-
-ListSelector._AddElement(pyxb.binding.basis.element(pyxb.namespace.ExpandedName(None, 'element'), pyxb.binding.datatypes.nonNegativeInteger, scope=ListSelector, location=pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 88, 10)))
-
-def _BuildAutomaton_6 ():
- # Remove this helper function from the namespace after it is invoked
- global _BuildAutomaton_6
- del _BuildAutomaton_6
- import pyxb.utils.fac as fac
-
- counters = set()
- states = []
- final_update = set()
- symbol = pyxb.binding.content.ElementUse(ListSelector._UseForTag(pyxb.namespace.ExpandedName(None, 'element')), pyxb.utils.utility.Location('/home/kenny/Desktop/HBP/BrainSimulation/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd', 88, 10))
- st_0 = fac.State(symbol, is_initial=True, final_update=final_update, is_unordered_catenation=False)
- states.append(st_0)
- transitions = []
- transitions.append(fac.Transition(st_0, [
- ]))
- st_0._set_transitionSet(transitions)
- return fac.Automaton(states, counters, False, containing_state=None)
-ListSelector._Automaton = _BuildAutomaton_6()
-
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd b/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd
deleted file mode 100644
index 5e28f13..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/schema/music.xsd
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0"?>
-<!-- MUSIC Documentation is available at: http://http://software.incf.org/software/music/home
-
- Descriptions provided inline below are from the reference documentation.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
- <!-- root element is a list of port connections between music applications -->
- <xs:element name="root">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="port" type="Port" minOccurs="1" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
-
- <!-- Communication between applications is handled by ports. Ports are named
- sources (output ports) or sinks (input ports) of data flows. The data to be
- communicated may be differently organized in process memory on the receiver
- side compared to the sender side.
-
- The width of a port, that is the number of data elements transferred in parallel
- from a cont port or the largest possible id of an event port + 1.
- -->
- <xs:complexType name="Port">
- <xs:sequence>
- <xs:element name="type" type="PortType"/>
- <xs:element name="name" type="xs:string"/>
- <xs:element name="width" type="xs:positiveInteger"/>
- <xs:element name="sender" type="Peer" minOccurs="1" maxOccurs="1"/>
- <xs:element name="receiver" type="Peer" minOccurs="1" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
-
- <!-- Each application declares its ability to produce and consume data by
- publishing ports. Ports are named by the application and provided with
- information about the datatype (continuous data, spike events, messages)
- and mapping onto different processors.
- -->
- <xs:simpleType name="PortType">
- <xs:restriction base="xs:string">
- <xs:enumeration value="Event"/>
- <xs:enumeration value="Continuous"/>
- <xs:enumeration value="Message"/>
- </xs:restriction>
- </xs:simpleType>
-
- <!-- A named peer (sender/receiver) for a port, describes the neurons/synapses to connect to/from -->
- <xs:complexType name="Peer">
- <xs:sequence>
- <xs:element name="name" type="xs:string"/>
- <xs:element name="synapse" type="SynapticConnection" minOccurs="0" maxOccurs="unbounded"/>
- <xs:element name="parameters" type="ParameterList" minOccurs="0" maxOccurs="1"/>
- </xs:sequence>
- </xs:complexType>
- <xs:complexType name="SynapticConnection">
- <xs:sequence>
- <xs:element name="target" type="xs:string"/>
- <xs:element name="type" type="ConnectionType"/>
- <xs:element name="selector" type="SynapticSelector" minOccurs="1" maxOccurs="1"/>
- <xs:element name="parameters" type="ParameterList" minOccurs="0" maxOccurs="1"/>
- </xs:sequence>
- </xs:complexType>
- <xs:simpleType name="ConnectionType">
- <xs:restriction base="xs:string">
- <xs:enumeration value="one_to_one"/>
- <xs:enumeration value="all_to_all"/>
- </xs:restriction>
- </xs:simpleType>
-
- <!-- neuron/synapse selection, similar to the abstract selectors in the BIBI -->
- <xs:complexType name="SynapticSelector" abstract="true"/>
- <xs:complexType name="SliceSelector">
- <xs:complexContent>
- <xs:extension base="SynapticSelector">
- <xs:sequence>
- <xs:element name="start" type="xs:nonNegativeInteger"/>
- <xs:element name="stop" type="xs:positiveInteger"/>
- <xs:element name="step" type="xs:positiveInteger"/>
- </xs:sequence>
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
- <xs:complexType name="ListSelector">
- <xs:complexContent>
- <xs:extension base="SynapticSelector">
- <xs:sequence>
- <xs:element name="element" type="xs:nonNegativeInteger" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
-
- <!-- A list of parameters with attribute name and key value (string) -->
- <xs:complexType name="ParameterList">
- <xs:sequence>
- <xs:element name="parameter" type="Parameter" minOccurs="1" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- <xs:complexType name="Parameter">
- <xs:simpleContent>
- <xs:extension base="xs:string">
- <xs:attribute name="name" type="xs:string" use="required"/>
- </xs:extension>
- </xs:simpleContent>
- </xs:complexType>
-
-</xs:schema>
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/__init__.py
deleted file mode 100644
index fcfe222..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""
-This package contains all tests for the MUSIC-XML package
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/__init__.py
deleted file mode 100644
index 1e62c49..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""
-This package contains all tests for the MUSIC config package.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/test_music_config.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/test_music_config.py
deleted file mode 100644
index 67d9ca1..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/config/test_music_config.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-import io
-
-from mock import patch
-import hbp_nrp_music_xml.config.music_config as config
-
-__author__ = 'Martin Schulze, Kenny Sharma'
-
-
-class MockedPortReceiver(object):
- def __init__(self, name):
- self.name = name
-
-
-class MockedXMLPort(object):
- sender = MockedPortReceiver('sender')
- name = "port"
- receiver = [MockedPortReceiver('receiver1')]
- width = 42
-
- def __str__(self):
- return 'port'
-
-
-class TestMusicConfig(unittest.TestCase):
-
- # application tests
- def test_application(self):
- ma = config.Application('foo', 'bar', ['arg1', 'arg2'], 3)
- self.assertEqual(ma.name, 'foo')
- self.assertEqual(ma.binary, 'bar')
- self.assertEqual(ma.args, '"arg1 arg2"')
- self.assertEqual(ma.num_processes, 3)
-
- # config writer tests
- def test_config_writer(self):
- header = {'foo': 'bar'}
- apps = [config.Application('foo', 'bar', None, 3)]
- projs = [MockedXMLPort()]
- mcw = config.MusicConfigWriter(header, apps, projs)
- self.assertEqual(str(mcw),
- 'foo = "bar"\n\n[foo]\nnp = 3\nbinary = bar\n' +\
- 'args = \n\nport\n')
-
- # music config port mock test
- @patch("hbp_nrp_music_xml.schema.generated.music_xml.Port", new=MockedXMLPort)
- def test_config_port(self):
- proj = config.MusicConfigPort(MockedXMLPort())
- self.assertEqual(str(proj), 'sender.port -> receiver1.port [42]')
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/__init__.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/__init__.py
deleted file mode 100644
index 30b6db4..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""
-Unit tests for the MUSIC XML -> PyNN Proxy factories.
-"""
-
-__author__ = 'Martin Schulze'
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_factory.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_factory.py
deleted file mode 100644
index 76b3464..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_factory.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-from mock import MagicMock
-
-from hbp_nrp_music_xml.pynn.factory import PyNNProxyFactory, export_proxy, create_proxy_via_native_cell_types
-from hbp_nrp_music_xml.pynn.connector_factory import PyNNConnectorFactory
-from hbp_nrp_music_xml.pynn.cell_types import load_cell_types
-from hbp_nrp_music_xml.schema.generated import music_xml
-
-import pyNN.nest as sim
-import nest
-
-__author__ = 'Martin Schulze'
-
-class TestPyNNConnectorFactory(unittest.TestCase):
-
- def test_create_and_connect_synapse(self):
- nest.ResetKernel()
- connector_factory = PyNNConnectorFactory(sim)
-
- def check_all_to_all(source_ids, target_ids):
- for target_id in target_ids:
- for source_id in source_ids:
- connections = nest.GetConnections(source=[source_id],
- target=[target_id])
- self.assertTrue(connections)
- self.assertTrue(len(connections) == 1)
-
- def check_one_to_one(source_ids, target_ids):
- for (source_id, target_id) in zip(source_ids, target_ids):
- connections = nest.GetConnections(source=[source_id],
- target=[target_id])
- self.assertTrue(connections)
- self.assertTrue(len(connections) == 1)
-
- def test_case(connection_rule, population_slice, is_output_proxy):
- sim.setup(min_delay=0.1, max_delay=20.0, threads=1)
- connection_check_func = {'all_to_all': check_all_to_all,
- 'one_to_one': check_one_to_one}
-
- if is_output_proxy:
- proxy = sim.Population(1, sim.IF_cond_alpha())
- else:
- proxy = sim.Population(10, sim.IF_cond_alpha())
-
- target_population = sim.Population(10, sim.IF_cond_alpha())
- connector_factory.create_and_connect_synapse(proxy, "test_to_cle",
- connection_rule,
- population_slice,
- target_population,
- is_output_proxy)
- connections = nest.GetConnections()
- proxy_ids = map(int, proxy.all_cells)
- target_ids = map(int, target_population.all_cells)
- if population_slice:
- target_ids = target_ids[population_slice]
- if is_output_proxy:
- connection_check_func[connection_rule](target_ids, proxy_ids)
- else:
- connection_check_func[connection_rule](proxy_ids, target_ids)
- sim.end()
- nest.ResetKernel()
-
- # Output proxy tests
- test_case('all_to_all', None, True)
- test_case('all_to_all', slice(0, 5, 1), True)
- test_case('one_to_one', None, True)
- test_case('one_to_one', slice(0, 5, 1), True)
-
- # Input proxy tests
- test_case('all_to_all', None, False)
- test_case('all_to_all', slice(0, 5, 1), False)
- test_case('one_to_one', None, False)
- test_case('one_to_one', slice(0, 5, 1), False)
- test_case('all_to_all', slice(0,11,1), False)
-
- # Invalid test cases
- with self.assertRaises(Exception):
- test_case('foo', None, False)
-
-class TestPyNNProxyFactory(unittest.TestCase):
-
- def setUp(self):
- sim.setup(min_delay=0.1, max_delay=20.0, threads=1)
- self._music_cell_types = load_cell_types(sim)
- self._music_event_in_cell = self._music_cell_types['in']['Event']
- self._music_event_out_cell = self._music_cell_types['out']['Event']
- self._parrot_cell = self._music_cell_types['parrot']
-
- def tearDown(self):
- sim.end()
- nest.ResetKernel()
-
- def test_create_proxy_via_native_cell_types(self):
-
- def setup_nest_mocks():
- # nest.SetStatus = MagicMock(return_value=False)
- nest.SetAcceptableLatency = MagicMock(return_value=False)
-
- def check_nest_calls(proxy, port_name, acc_latency, is_output_proxy):
- proxy_ids = map(int, proxy.all_cells)
- self.assertEqual(nest.GetStatus(proxy_ids, 'port_name'), (port_name,)*len(proxy_ids))
- if not is_output_proxy:
- for i, proxy_id in enumerate(proxy_ids):
- self.assertEqual(nest.GetStatus([proxy_id], 'music_channel')[0], i)
-
- set_acc_latency_call_args = nest.SetAcceptableLatency.call_args_list
- self.assertEqual(set_acc_latency_call_args[0][0][:], (port_name, acc_latency))
-
- # Input proxy test
- setup_nest_mocks()
- proxy = create_proxy_via_native_cell_types(sim, 2, self._music_event_in_cell, "test", "Event", 10.0, False)
- check_nest_calls(proxy, "test", 10.0, False)
-
- setup_nest_mocks()
- proxy = create_proxy_via_native_cell_types(sim, 2, self._music_event_in_cell, "test", "Event", None, False)
- check_nest_calls(proxy, "test", sim.get_min_delay(), False)
-
- # Output proxy test
- proxy = create_proxy_via_native_cell_types(sim, 2, self._music_event_out_cell, "test", "Event", 10.0, True)
- check_nest_calls(proxy, "test", 10.0, True)
-
- def test_export_proxy(self):
- presyn_pop = sim.Population(2, sim.IF_cond_alpha())
- proxy = create_proxy_via_native_cell_types(sim, 1, self._music_event_out_cell, "test", "Event", None, True)
- proxy_ids = map(int, proxy.all_cells)
- export_proxy(sim, presyn_pop, proxy, 3.0)
- connections = nest.GetConnections(target=proxy_ids)
- delays = nest.GetStatus(connections, 'delay')
- music_channels = nest.GetStatus(connections, 'receptor')
- self.assertTrue(delays, (3.0,)*len(proxy_ids))
- self.assertTrue(music_channels, range(len(proxy_ids)))
-
- def test_create_proxy(self):
- proxy_factory = PyNNProxyFactory(sim)
- proxy_parrots = proxy_factory.create_proxy("test", "Event", 2, True)
- self.assertEqual(proxy_parrots.celltype.nest_name['on_grid'], 'parrot_neuron')
- self.assertEqual(proxy_parrots.size, 2)
-
-
-if __name__ == "__main__":
- unittest.main()
-
-
-
-
-
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_xml_factory.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_xml_factory.py
deleted file mode 100644
index 8c70740..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/tests/pynn/test_xml_factory.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# ---LICENSE-BEGIN - DO NOT CHANGE OR MOVE THIS HEADER
-# This file is part of the Neurorobotics Platform software
-# Copyright (C) 2014,2015,2016,2017 Human Brain Project
-# https://www.humanbrainproject.eu
-#
-# The Human Brain Project is a European Commission funded project
-# in the frame of the Horizon2020 FET Flagship plan.
-# http://ec.europa.eu/programmes/horizon2020/en/h2020-section/fet-flagships
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program 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. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# ---LICENSE-END
-import unittest
-from mock import Mock, patch, MagicMock
-
-from hbp_nrp_music_xml.pynn.xml_factory import XmlFactory, create_selector, create_pop_slice
-from hbp_nrp_music_xml.pynn.xml_factory import extract_kwargs, is_application_receiver, build_port_overview_table
-from hbp_nrp_music_xml.schema.generated import music_xml
-
-import pyNN.nest as sim
-import nest
-
-__author__ = 'Martin Schulze'
-
-
-class TestPyNNXMLFactory(unittest.TestCase):
-
- def setUp(self):
- self._population_dict = {'Pop1': sim.Population(10, sim.IF_cond_alpha()),
- 'Pop2': sim.Population(5, sim.IF_cond_alpha())}
- self._connector_factory = None
- def create_proxy(port_name, proxy_type, port_width,
- is_output_proxy, synaptic_delay=None):
- if is_output_proxy:
- return sim.Population(1, sim.IF_cond_alpha())
- else:
- return sim.Population(10, sim.IF_cond_alpha())
-
- self._proxy_factory = MagicMock()
- self._proxy_factory.create_proxy = MagicMock(side_effect=create_proxy)
- self._xml_factory = XmlFactory("TestApp", self._connector_factory,
- self._proxy_factory, self._population_dict)
-
- def test_create_pop_slice(self):
- slice_selector = music_xml.SliceSelector()
- slice_selector.start = 0
- slice_selector.stop = 9
- slice_selector.step = 2
- population_slice = create_pop_slice(slice_selector)
- self.assertEqual(slice(0, 9, 2), population_slice)
-
- list_selector = music_xml.ListSelector()
- list_selector.element = [0,2,4,6]
- population_slice_list = create_pop_slice(list_selector)
- self.assertEqual([0,2,4,6], population_slice_list)
- with self.assertRaises(Exception):
- create_pop_slice(None)
-
- def test_create_selector(self):
- xml_synapse = music_xml.SynapticConnection()
- selector = create_selector(xml_synapse)
- self.assertIsNone(selector)
-
- xml_synapse.selector = music_xml.SliceSelector()
- xml_synapse.selector.start = 0
- xml_synapse.selector.stop = 9
- xml_synapse.selector.step = 1
- selector = create_selector(xml_synapse)
- self.assertEqual(selector, slice(0, 9, 1))
-
- def test_get_synaptic_target_population(self):
- xml_synapse = music_xml.SynapticConnection()
- with self.assertRaises(Exception):
- self._xml_factory._get_synaptic_target_population(xml_synapse)
-
- with self.assertRaises(Exception):
- xml_synapse.target = 'Pop3'
- self._xml_factory._get_synaptic_target_population(xml_synapse)
-
- xml_synapse.target = 'Pop1'
- self.assertEqual(self._xml_factory.
- _get_synaptic_target_population(xml_synapse),
- self._population_dict['Pop1'])
-
- def test_create_and_connect_proxy(self):
-
- def check_create_proxy_args(xml_projection, is_output_proxy):
- call_args_list = self._proxy_factory.create_proxy.call_args_list
- self.assertEqual(call_args_list[0][0][0], xml_projection.name)
- self.assertEqual(call_args_list[0][0][1], xml_projection.type)
- self.assertEqual(call_args_list[0][0][2], xml_projection.width)
- self.assertEqual(call_args_list[0][0][3], True)
-
- xml_projection = music_xml.Port()
- xml_projection.type = "Event"
- xml_projection.name = "Port1"
- xml_projection.connector = "Static"
- xml_projection.width = 10
- xml_peer = music_xml.Peer()
- xml_peer.synapse = None
- xml_peer.name = "App1"
-
- # Without synapses
- with self.assertRaises(Exception):
- proxy = self._xml_factory._create_and_connect_proxy(xml_projection,
- xml_peer, True)
-
- with self.assertRaises(Exception):
- proxy = self._xml_factory._create_and_connect_proxy(xml_projection,
- xml_peer, False)
-
- # With synapses
- xml_synapse = music_xml.SynapticConnection()
- xml_synapse.target = "Pop1"
- xml_synapse.type = "one_to_one"
- xml_projection.synapse = xml_synapse
- xml_peer.synapse = 'foo'
- self.assertRaises(Exception, self._xml_factory._create_and_connect_proxy,
- xml_projection, xml_peer, True)
-
- def test_assemble_proxy(self):
- xml_projection = music_xml.Port()
- xml_sender = music_xml.Peer()
- xml_sender.name = "Sender1"
- xml_receiver = music_xml.Peer()
- xml_receiver.name = "Receiver1"
- xml_projection.sender = xml_sender
- xml_projection.receiver = [xml_receiver, xml_sender]
- xml_factory_sender = XmlFactory("Sender1",
- self._connector_factory,
- self._proxy_factory,
- self._population_dict)
- xml_factory_receiver = XmlFactory("Receiver1",
- self._connector_factory,
- self._proxy_factory,
- self._population_dict)
- xml_factory_sender._create_and_connect_proxy = MagicMock()
- xml_factory_receiver._create_and_connect_proxy = MagicMock()
-
- self._xml_factory._assemble_proxy(xml_projection)
-
- def test_extract_kwargs(self):
- self.assertEquals(extract_kwargs(None), {})
-
- def test_application_receiver(self):
- xml_port = music_xml.Port()
- xml_port.receiver = []
- self.assertEqual(is_application_receiver('foo', xml_port), False)
-
- xml_receiver = music_xml.Peer()
- xml_receiver.name = 'foo'
- xml_port.receiver = [xml_receiver]
- self.assertEqual(is_application_receiver('foo', xml_port), True)
-
- def test_build_port_overview_table(self):
- xml_port = music_xml.Port(name='bar.port', type='Event', width=42, sender=music_xml.Peer(name='foo'))
- self.assertEqual(str(build_port_overview_table([xml_port], 'foo')),
- '+----------+-------+-------+-----------+\n' +
- '| Portname | Type | Width | Direction |\n' +
- '+----------+-------+-------+-----------+\n' +
- '| bar.port | Event | 42 | Outgoing |\n' +
- '+----------+-------+-------+-----------+')
-
-if __name__ == "__main__":
- unittest.main()
-
-
diff --git a/hbp_nrp_music_xml/hbp_nrp_music_xml/version.py b/hbp_nrp_music_xml/hbp_nrp_music_xml/version.py
deleted file mode 100644
index cff3ffe..0000000
--- a/hbp_nrp_music_xml/hbp_nrp_music_xml/version.py
+++ /dev/null
@@ -1,2 +0,0 @@
-'''version string - generated by setVersion.sh'''
-VERSION = '2.3.0'
diff --git a/hbp_nrp_music_xml/requirements.txt b/hbp_nrp_music_xml/requirements.txt
deleted file mode 100644
index bb56fe3..0000000
--- a/hbp_nrp_music_xml/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# third party requirements
-configparser==3.5.0
-prettytable==0.7.2
-pyxb==1.2.4
diff --git a/hbp_nrp_music_xml/requirements_extension_tests.txt b/hbp_nrp_music_xml/requirements_extension_tests.txt
deleted file mode 100644
index 031ce95..0000000
--- a/hbp_nrp_music_xml/requirements_extension_tests.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-#the following is required for the unit testing
-mock==1.0.1
-testfixtures==3.0.2
diff --git a/hbp_nrp_music_xml/setup.py b/hbp_nrp_music_xml/setup.py
deleted file mode 100644
index ba19ca8..0000000
--- a/hbp_nrp_music_xml/setup.py
+++ /dev/null
@@ -1,71 +0,0 @@
-'''setup.py'''
-
-from setuptools import setup
-
-import hbp_nrp_music_xml
-import pip
-
-from optparse import Option
-options = Option('--workaround')
-options.skip_requirements_regex = None
-reqs_file = './requirements.txt'
-options = Option("--workaround")
-options.skip_requirements_regex = None
-# Hack for old pip versions
-if pip.__version__.startswith('10.'):
- # Versions greater or equal to 10.x don't rely on pip.req.parse_requirements
- install_reqs = list(val.strip() for val in open(reqs_file))
- reqs = install_reqs
-elif pip.__version__.startswith('1.'):
- # Versions 1.x rely on pip.req.parse_requirements
- # but don't require a "session" parameter
- from pip.req import parse_requirements # pylint:disable=no-name-in-module, import-error
- install_reqs = parse_requirements(reqs_file, options=options)
- reqs = [str(ir.req) for ir in install_reqs]
-else:
- # Versions greater than 1.x but smaller than 10.x rely on pip.req.parse_requirements
- # and requires a "session" parameter
- from pip.req import parse_requirements # pylint:disable=no-name-in-module, import-error
- from pip.download import PipSession # pylint:disable=no-name-in-module, import-error
- options.isolated_mode = False
- install_reqs = parse_requirements( # pylint:disable=unexpected-keyword-arg
- reqs_file,
- session=PipSession,
- options=options
- )
- reqs = [str(ir.req) for ir in install_reqs]
-
-# ensure we install numpy before the main list of requirements, ignore
-# failures if numpy/cython are not requirements and just proceed (future proof)
-try:
- cython_req = next(r for r in reqs if r.startswith('cython'))
- numpy_req = next(r for r in reqs if r.startswith('numpy'))
- if pip.__version__.startswith('10.'):
- import subprocess
- subprocess.check_call(
- ["python", '-m', 'pip', 'install', "--no-clean", "--user", cython_req, numpy_req]
- )
- else:
- pip.main(['install', '--no-clean', cython_req, numpy_req]) # pylint:disable=no-member
-# pylint: disable=bare-except
-except:
- pass
-
-config = {
- 'description': 'MUSIC XML support for pyNN/NEST for HBP SP10',
- 'author': 'HBP Neurorobotics',
- 'url': 'http://neurorobotics.net',
- 'author_email': 'neurorobotics@humanbrainproject.eu',
- 'version': hbp_nrp_music_xml.__version__,
- 'install_requires': reqs,
- 'packages': ['hbp_nrp_music_xml',
- 'hbp_nrp_music_xml.config',
- 'hbp_nrp_music_xml.pynn',
- 'hbp_nrp_music_xml.schema',
- 'hbp_nrp_music_xml.schema.generated'],
- 'scripts': [],
- 'name': 'hbp-nrp-music-xml',
- 'include_package_data': True,
-}
-
-setup(**config)
diff --git a/hbp_nrp_music_xml_deprec.tar.gz b/hbp_nrp_music_xml_deprec.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..4c2fd8943ca9c6237dae4d4833a0147ab9ea7e17
GIT binary patch
literal 19985
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
literal 0
HcmV?d00001
diff --git a/verify.sh b/verify.sh
index 662e0df..ec2889c 100755
--- a/verify.sh
+++ b/verify.sh
@@ -2,10 +2,10 @@
# This script is designed for local usage.
# Ignore generated files
-# export IGNORE_LINT="platform_venv|hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated"
+# export IGNORE_LINT="platform_venv|"
-# Ignore generated and music related files
-export IGNORE_LINT='platform_venv|hbp_nrp_music_xml|hbp_nrp_music_interface|hbp_nrp_music_xml/hbp_nrp_music_xml/schema/generated|migrations|nest'
+# Ignore generated related files
+export IGNORE_LINT='platform_venv|migrations|nest'
export VIRTUAL_ENV=$NRP_VIRTUAL_ENV
# This script only runs static code analysis, the tests can be run separately using run_tests.sh
--
GitLab