Commit 0d6ff0f9 authored by Flavio TARSETTI's avatar Flavio TARSETTI

Merge branch '185_experience_environment_improvement' into 'master'

Experience environment improvement

See merge request !113
parents 52a19134 50dfd546
Pipeline #35611 passed with stages
in 14 minutes and 46 seconds
This diff is collapsed.
...@@ -39,11 +39,10 @@ from click_plugins import with_plugins ...@@ -39,11 +39,10 @@ from click_plugins import with_plugins
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
from beat.core.dock import Host
from beat.cmdline.click_helper import AliasedGroup from beat.cmdline.click_helper import AliasedGroup
from beat.cmdline.decorators import raise_on_error from beat.cmdline.decorators import raise_on_error
from beat.cmdline.decorators import verbosity_option from beat.cmdline.decorators import verbosity_option
from beat.cmdline import environments
from ..utils import setup_logger from ..utils import setup_logger
from ..utils import check_prefix_folders from ..utils import check_prefix_folders
...@@ -64,19 +63,13 @@ global logger ...@@ -64,19 +63,13 @@ global logger
logger = None logger = None
def dump_environments(environments_file_path):
logger.info("Generating environments information")
Host(images_cache=environments_file_path, raise_on_errors=False)
logger.info("Done")
def setup_environment_cache(ctx, param, value): def setup_environment_cache(ctx, param, value):
"""Click option callback to setup environment cache""" """Click option callback to setup environment cache"""
if not value: if not value:
environments = ctx.meta["environments"] environments_file_path = ctx.meta["environments"]
if not os.path.exists(environments): if not os.path.exists(environments_file_path):
dump_environments(environments) ctx.invoke(environments.list, type_="all", output=environments_file_path)
def check_prefix(prefix_path): def check_prefix(prefix_path):
...@@ -194,15 +187,22 @@ Example: ...@@ -194,15 +187,22 @@ Example:
@editor.command(epilog=ENV_REFRESH_EPILOG) @editor.command(epilog=ENV_REFRESH_EPILOG)
@click.option(
"--type",
"-t",
"type_",
type=click.Choice(["docker", "remote", "all"], case_sensitive=False),
default="all",
)
@click.pass_context @click.pass_context
@raise_on_error @raise_on_error
def refresh_env(ctx): def refresh_env(ctx, type_):
"""Update environments cache""" """Update environments cache"""
environments_file_path = ctx.meta["environments"] environments_file_path = ctx.meta["environments"]
if os.path.exists(environments_file_path): if os.path.exists(environments_file_path):
os.remove(environments_file_path) os.remove(environments_file_path)
dump_environments(environments_file_path) ctx.invoke(environments.list, type_=type_, output=environments_file_path)
@editor.group(cls=AliasedGroup) @editor.group(cls=AliasedGroup)
......
...@@ -94,8 +94,29 @@ def test_prefix(): ...@@ -94,8 +94,29 @@ def test_prefix():
env_file.write( env_file.write(
json.dumps( json.dumps(
{ {
"Test Env": {"name": "Python 2.7", "version": "1.3.0"}, "remote": [
"Another test Env": {"name": "another test", "version": "1.1.1"}, {
"name": "Python 2.7",
"version": "1.3.0",
"queues": {"queue1": {}, "queue2": {}},
},
{
"name": "Python",
"version": "2.0.0",
"queues": {
"queue_extra_long": {},
"queue_long": {},
"queue_short": {},
},
},
],
"docker": {
"Docker test env": {"name": "Pytorch", "version": "1.1.1"},
"Second Docker test env": {
"name": "Pytorch 1.0",
"version": "2.1.1",
},
},
} }
) )
) )
......
...@@ -27,7 +27,6 @@ import copy ...@@ -27,7 +27,6 @@ import copy
import pytest import pytest
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtCore import QStringListModel
from PyQt5.QtWidgets import QComboBox from PyQt5.QtWidgets import QComboBox
from PyQt5.QtWidgets import QCheckBox from PyQt5.QtWidgets import QCheckBox
...@@ -62,6 +61,7 @@ from ..widgets.experimenteditor import typed_user_property ...@@ -62,6 +61,7 @@ from ..widgets.experimenteditor import typed_user_property
from ..widgets.experimenteditor import ExperimentResources from ..widgets.experimenteditor import ExperimentResources
from ..widgets.experimenteditor import AlgorithmResourceModel from ..widgets.experimenteditor import AlgorithmResourceModel
from ..widgets.experimenteditor import QueueResourceModel
from .conftest import prefix from .conftest import prefix
from .conftest import sync_prefix from .conftest import sync_prefix
...@@ -116,6 +116,13 @@ def parameter_choice_map(prefix_path, algorithm_name): ...@@ -116,6 +116,13 @@ def parameter_choice_map(prefix_path, algorithm_name):
} }
def change_index(index):
if index > 0:
return index - 1
else:
return index + 1
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Fixtures # Fixtures
...@@ -280,6 +287,40 @@ class TestAlgorithmResourceModel: ...@@ -280,6 +287,40 @@ class TestAlgorithmResourceModel:
assert algorithm_model.rowCount() == query.value("cnt") assert algorithm_model.rowCount() == query.value("cnt")
class TestQueueResourceModel:
"""Test the model used to generate suitable algorithm selections"""
@pytest.fixture
def prefix_model(self, beat_context):
return ExperimentResources(beat_context)
def test_default(self, prefix_model):
model = QueueResourceModel()
query = QSqlQuery()
assert query.exec_("SELECT COUNT(name) AS cnt FROM queues")
query.next()
assert model.rowCount() > 0
assert model.rowCount() == query.value("cnt")
def test_types(self, prefix_model):
model = QueueResourceModel()
for type_ in ["remote", "docker"]:
model.setType(type_)
query = QSqlQuery()
assert query.exec_(
f"SELECT COUNT(name) AS cnt FROM queues WHERE env_type='{type_}'"
)
query.next()
assert model.rowCount() > 0
assert model.rowCount() == query.value("cnt")
class TestIOMapperDialog: class TestIOMapperDialog:
"""Test that the dialog used for input/output mapping works as expected""" """Test that the dialog used for input/output mapping works as expected"""
...@@ -506,7 +547,7 @@ class TestEnvironmentModel: ...@@ -506,7 +547,7 @@ class TestEnvironmentModel:
model = EnvironmentModel() model = EnvironmentModel()
model.setContext(beat_context) model.setContext(beat_context)
assert model.rowCount() == 2 assert model.rowCount() == 4
def test_visual_name(self, beat_context): def test_visual_name(self, beat_context):
model = EnvironmentModel() model = EnvironmentModel()
...@@ -728,7 +769,6 @@ class TestExecutionPropertiesEditor(PropertiesEditorTestMixin, ParameterTestMixi ...@@ -728,7 +769,6 @@ class TestExecutionPropertiesEditor(PropertiesEditorTestMixin, ParameterTestMixi
editor = self.editor_klass(test_prefix) editor = self.editor_klass(test_prefix)
editor.setAlgorithmResourceModel(algorithm_model) editor.setAlgorithmResourceModel(algorithm_model)
editor.setEnvironmentModel(environment_model) editor.setEnvironmentModel(environment_model)
editor.setQueueModel(QStringListModel(["Test"]))
return editor return editor
...@@ -745,7 +785,6 @@ class TestBlockEditor(TestExecutionPropertiesEditor): ...@@ -745,7 +785,6 @@ class TestBlockEditor(TestExecutionPropertiesEditor):
editor = self.editor_klass("block_name", test_prefix) editor = self.editor_klass("block_name", test_prefix)
editor.setEnvironmentModel(environment_model) editor.setEnvironmentModel(environment_model)
editor.setQueueModel(QStringListModel(["Test"]))
return editor return editor
...@@ -762,7 +801,6 @@ class TestAnalyzerBlockEditor(PropertiesEditorTestMixin): ...@@ -762,7 +801,6 @@ class TestAnalyzerBlockEditor(PropertiesEditorTestMixin):
editor = self.editor_klass("block_name", test_prefix) editor = self.editor_klass("block_name", test_prefix)
editor.setEnvironmentModel(environment_model) editor.setEnvironmentModel(environment_model)
editor.setQueueModel(QStringListModel(["Test"]))
return editor return editor
...@@ -779,7 +817,6 @@ class TestLoopBlockEditor(TestExecutionPropertiesEditor): ...@@ -779,7 +817,6 @@ class TestLoopBlockEditor(TestExecutionPropertiesEditor):
editor = self.editor_klass("block_name", test_prefix) editor = self.editor_klass("block_name", test_prefix)
editor.setEnvironmentModel(environment_model) editor.setEnvironmentModel(environment_model)
editor.setQueueModel(QStringListModel(["Test"]))
return editor return editor
def test_edit_environment( def test_edit_environment(
...@@ -1023,7 +1060,6 @@ class TestGlobalParametersEditor: ...@@ -1023,7 +1060,6 @@ class TestGlobalParametersEditor:
environment_model = EnvironmentModel() environment_model = EnvironmentModel()
environment_model.setContext(beat_context) environment_model.setContext(beat_context)
editor.setEnvironmentModel(environment_model) editor.setEnvironmentModel(environment_model)
editor.setQueueModel(QStringListModel(["Test", "Test2"]))
return editor return editor
@pytest.mark.parametrize( @pytest.mark.parametrize(
...@@ -1066,13 +1102,15 @@ class TestGlobalParametersEditor: ...@@ -1066,13 +1102,15 @@ class TestGlobalParametersEditor:
def test_change_environment(self, qtbot, gpe_editor, exp_globals): def test_change_environment(self, qtbot, gpe_editor, exp_globals):
gpe_editor.load(exp_globals) gpe_editor.load(exp_globals)
with qtbot.waitSignal(gpe_editor.dataChanged): with qtbot.waitSignal(gpe_editor.dataChanged):
gpe_editor.environment_combobox.setCurrentIndex(1) index = gpe_editor.environment_combobox.currentIndex()
gpe_editor.environment_combobox.setCurrentIndex(change_index(index))
assert gpe_editor.dump() != exp_globals assert gpe_editor.dump() != exp_globals
def test_change_queue(self, qtbot, gpe_editor, exp_globals): def test_change_queue(self, qtbot, gpe_editor, exp_globals):
gpe_editor.load(exp_globals) gpe_editor.load(exp_globals)
with qtbot.waitSignal(gpe_editor.dataChanged): with qtbot.waitSignal(gpe_editor.dataChanged):
gpe_editor.queue_combobox.setCurrentIndex(1) index = gpe_editor.queue_combobox.currentIndex()
gpe_editor.queue_combobox.setCurrentIndex(change_index(index))
assert gpe_editor.dump() != exp_globals assert gpe_editor.dump() != exp_globals
...@@ -1190,8 +1228,10 @@ class TestExperimentEditor: ...@@ -1190,8 +1228,10 @@ class TestExperimentEditor:
block_editor = list_widget.widget_list[0] block_editor = list_widget.widget_list[0]
properties_editor = block_editor.properties_editor properties_editor = block_editor.properties_editor
combobox = properties_editor.environment_combobox combobox = properties_editor.environment_combobox
with qtbot.waitSignal(experiment_editor.dataChanged): with qtbot.waitSignal(experiment_editor.dataChanged):
combobox.setCurrentIndex(1) index = combobox.currentIndex()
combobox.setCurrentIndex(change_index(index))
dump = experiment_editor.dump_json() dump = experiment_editor.dump_json()
assert dump != experiment_declaration assert dump != experiment_declaration
......
This diff is collapsed.
...@@ -93,9 +93,11 @@ class MainWindow(QMainWindow): ...@@ -93,9 +93,11 @@ class MainWindow(QMainWindow):
self, self,
self.tr("About"), self.tr("About"),
self.tr( self.tr(
f"{qApp.applicationName()}\n" f"{qApp.applicationName()}<br>"
f"Version: {qApp.applicationVersion()}\n" f"Version: {qApp.applicationVersion()}<br>"
"Copyright Idiap Research Institute" "Copyright Idiap Research Institute<br>"
"<a target='_blank' href='https://icons8.com/icons/set/docker'>Docker</a> icon by <a target='_blank' href='https://icons8.com'>Icons8</a>"
"<a target='_blank' href='https://icons8.com/icons/set/cloud-development'>Cloud Development</a> icon by <a target='_blank' href='https://icons8.com'>Icons8</a>"
), ),
) )
......
[buildout] [buildout]
parts = scripts templates parts = scripts
eggs = beat.editor eggs = beat.editor
develop = . develop = .
newest = false newest = false
[scripts] [scripts]
recipe = bob.buildout:scripts recipe = bob.buildout:scripts
[templates]
recipe = collective.recipe.cmd
cmds = ./bin/python conda/linkeditor.py
on_install = true
on_update = true
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''Ensures the editor JS code is available during tests'''
import os
import sys
import glob
key = '%%jsfiles%%'
scriptdir = os.path.realpath(os.path.dirname(sys.argv[0]))
try:
import pkg_resources
import beat.editorx
jsfiles = pkg_resources.resource_filename(beat.editor.__name__, 'js')
print('Running test (beat.editor import suceeded) - setting javascript path to %s' % jsfiles)
except ImportError as e:
jsfiles = os.path.realpath(os.path.join(scriptdir, '..', 'beat', 'editor',
'js'))
print('Running build (beat.editor import failed) - setting javascript path to %s' % jsfiles)
if not os.path.exists(jsfiles):
print(' Creating directory %s' % jsfiles)
os.makedirs(jsfiles)
templatedir = os.path.realpath(os.path.join(scriptdir, 'js'))
for k in glob.glob(os.path.join(templatedir, '*.template')):
output = os.path.splitext(k)[0]
print(' ** Replacing template %s -> %s' % (k, output))
with open(k, 'rt') as reader, open(output, 'wt') as writer:
for line in reader:
if key in line: line = line.replace(key, jsfiles)
writer.writelines([line])
...@@ -30,7 +30,7 @@ requirements: ...@@ -30,7 +30,7 @@ requirements:
- click - click
- click-plugins - click-plugins
- docopt - docopt
- beat.cmdline >=1.5.0b0 - beat.cmdline >=1.5.1b0
test: test:
requires: requires:
......
<!DOCTYPE RCC><RCC version="1.0"> <!DOCTYPE RCC><RCC version="1.0">
<qresource> <qresource prefix="resources">
<file>resources/remap.png</file> <file alias="remap">resources/remap.png</file>
<file alias="docker">resources/icons8-docker-50.png</file>
<file alias="remote">resources/icons8-cloud-development-50.png</file>
</qresource> </qresource>
</RCC> </RCC>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment