diff --git a/biosimulators_utils/_version.py b/biosimulators_utils/_version.py
index 17c53dbd..27a98350 100644
--- a/biosimulators_utils/_version.py
+++ b/biosimulators_utils/_version.py
@@ -1 +1 @@
-__version__ = '0.1.182'
+__version__ = '0.1.183'
diff --git a/biosimulators_utils/sedml/exec.py b/biosimulators_utils/sedml/exec.py
index 949a0dbf..f0209277 100644
--- a/biosimulators_utils/sedml/exec.py
+++ b/biosimulators_utils/sedml/exec.py
@@ -27,6 +27,7 @@
from lxml import etree # noqa: F401
import copy
import datetime
+import functools
import numpy
import os
import sys
@@ -51,7 +52,8 @@ def exec_sed_doc(task_executer, doc, working_dir, base_out_path, rel_out_path=No
apply_xml_model_changes=False,
log=None, indent=0, pretty_print_modified_xml_models=False,
log_level=StandardOutputErrorCapturerLevel.c,
- config=None):
+ config=None, get_value_executer=None, set_value_executer=None, preprocessed_task_executer=None,
+ reset_executer=None):
""" Execute the tasks specified in a SED document and generate the specified outputs
Args:
@@ -164,14 +166,24 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
original_model_changes = {}
temp_model_sources = []
model_etrees = {}
+ preprocessed_task = None
+
+ task_vars = get_variables_for_task(doc, task)
+ preprocessed_task_sub_executer = None
+ if preprocessed_task_executer:
+ preprocessed_task_sub_executer = functools.partial(preprocessed_task_executer,
+ task, task_vars,
+ config=config)
+
for original_model in original_models:
original_model_sources[original_model.id] = original_model.source
original_model_changes[original_model.id] = original_model.changes
- temp_model, temp_model_source, model_etree = resolve_model_and_apply_xml_changes(
+ temp_model, temp_model_source, model_etree, preprocessed_task = resolve_model_and_apply_xml_changes(
original_model, doc, working_dir,
apply_xml_model_changes=apply_xml_model_changes,
- pretty_print_modified_xml_models=pretty_print_modified_xml_models)
+ pretty_print_modified_xml_models=pretty_print_modified_xml_models,
+ set_value_executer=set_value_executer, preprocessed_task_sub_executer=preprocessed_task_sub_executer)
original_model.source = temp_model.source
original_model.changes = temp_model.changes
@@ -181,18 +193,24 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
model_etrees[original_model.id] = model_etree
- task_vars = get_variables_for_task(doc, task)
+ # The preprocessed task was not created if there was no set_value_executer, so create one now:
+ if not preprocessed_task and preprocessed_task_executer:
+ preprocessed_task = preprocessed_task_sub_executer()
# execute task
if isinstance(task, Task):
- task_var_results = exec_task(task, task_executer, task_vars, doc, log=task_log, config=config)
+ task_var_results = exec_task(task, task_executer, task_vars, doc,
+ preprocessed_task=preprocessed_task, log=task_log, config=config)
elif isinstance(task, RepeatedTask):
task_var_results = exec_repeated_task(task, task_executer, task_vars, doc,
apply_xml_model_changes=apply_xml_model_changes,
model_etrees=model_etrees,
pretty_print_modified_xml_models=pretty_print_modified_xml_models,
- config=config)
+ config=config, preprocessed_task=preprocessed_task,
+ get_value_executer=get_value_executer,
+ set_value_executer=set_value_executer,
+ reset_executer=reset_executer)
else: # pragma: no cover: already validated by :obj:`get_models_referenced_by_task`
raise NotImplementedError('Tasks of type {} are not supported.'.format(task.__class__.__name__))
@@ -363,7 +381,7 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
return report_results, log
-def exec_task(task, task_executer, task_vars, doc, log=None, config=None):
+def exec_task(task, task_executer, task_vars, doc, log=None, config=None, preprocessed_task=None):
""" Execute a basic SED task
Args:
@@ -401,7 +419,7 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
:obj:`VariableResults`: results of the variables
"""
# execute task
- task_variable_results, _ = task_executer(task, task_vars, log=log, config=config)
+ task_variable_results, _ = task_executer(task, task_vars, log=log, config=config, preprocessed_task=preprocessed_task)
# check that the expected variables were recorded
variable_results = VariableResults()
@@ -413,7 +431,8 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
def exec_repeated_task(task, task_executer, task_vars, doc, apply_xml_model_changes=False, model_etrees=None,
- pretty_print_modified_xml_models=False, config=None):
+ pretty_print_modified_xml_models=False, config=None, preprocessed_task=None, get_value_executer=None,
+ set_value_executer=None, reset_executer=None):
""" Execute a repeated SED task
Args:
@@ -451,7 +470,7 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
:obj:`VariableResults`: results of the variables
"""
# warn about inability to not reset models
- if not task.reset_model_for_each_iteration:
+ if not task.reset_model_for_each_iteration and not reset_executer:
models = get_first_last_models_executed_by_task(task)
if models[0] == models[-1]:
msg = (
@@ -462,7 +481,8 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
sub_tasks = sorted(task.sub_tasks, key=lambda sub_task: sub_task.order)
for prev_sub_task, next_sub_task in zip(sub_tasks[0:-1], sub_tasks[1:]):
- if get_first_last_models_executed_by_task(prev_sub_task.task)[-1] == get_first_last_models_executed_by_task(next_sub_task.task)[0]:
+ if get_first_last_models_executed_by_task(prev_sub_task.task)[-1] == get_first_last_models_executed_by_task(next_sub_task.task)[0] \
+ and not reset_executer:
msg = (
'Only independent execution of sub-tasks is supported. '
'Successive sub-tasks will not be executed starting from the end state of the previous sub-task.'
@@ -500,6 +520,8 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
doc = copy.deepcopy(original_doc)
task = next(task for task in doc.tasks if task.id == original_task.id)
model_etrees = copy.deepcopy(original_model_etrees)
+ if reset_executer:
+ reset_executer(preprocessed_task)
# get range values
current_range_values = {}
@@ -514,27 +536,35 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
for change in task.changes:
variable_values = {}
for variable in change.variables:
- if not apply_xml_model_changes:
+ if get_value_executer and preprocessed_task:
+ value = get_value_executer(change.model, variable, preprocessed_task)
+ variable_values[variable.id] = value
+ elif not apply_xml_model_changes:
raise NotImplementedError('Set value changes that involve variables of non-XML-encoded models are not supported.')
- variable_values[variable.id] = get_value_of_variable_model_xml_targets(variable, model_etrees)
+ else:
+ variable_values[variable.id] = get_value_of_variable_model_xml_targets(variable, model_etrees)
new_value = calc_compute_model_change_new_value(change, variable_values=variable_values, range_values=current_range_values)
- if new_value == int(new_value):
- new_value = str(int(new_value))
+
+ if set_value_executer:
+ set_value_executer(change.model, change.target, change.symbol, new_value, preprocessed_task)
else:
- new_value = str(new_value)
+ if new_value == int(new_value):
+ new_value = str(int(new_value))
+ else:
+ new_value = str(new_value)
- if change.symbol:
- raise NotImplementedError('Set value changes of symbols is not supported.')
+ if change.symbol:
+ raise NotImplementedError('Set value changes of symbols is not supported.')
- attr_change = ModelAttributeChange(target=change.target, target_namespaces=change.target_namespaces, new_value=new_value)
+ attr_change = ModelAttributeChange(target=change.target, target_namespaces=change.target_namespaces, new_value=new_value)
- if apply_xml_model_changes and is_model_language_encoded_in_xml(change.model.language):
- model = Model(changes=[attr_change])
- apply_changes_to_xml_model(model, model_etrees[change.model.id], None, None)
+ if apply_xml_model_changes and is_model_language_encoded_in_xml(change.model.language):
+ model = Model(changes=[attr_change])
+ apply_changes_to_xml_model(model, model_etrees[change.model.id], None, None)
- else:
- change.model.changes.append(attr_change)
+ else:
+ change.model.changes.append(attr_change)
# sort the sub-tasks
sub_tasks = sorted(task.sub_tasks, key=lambda sub_task: sub_task.order)
@@ -554,7 +584,7 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
standalone=False,
pretty_print=pretty_print_modified_xml_models)
- sub_task_var_results = exec_task(sub_task.task, task_executer, task_vars, doc, config=config)
+ sub_task_var_results = exec_task(sub_task.task, task_executer, task_vars, doc, config=config, preprocessed_task=preprocessed_task)
if apply_xml_model_changes and is_model_language_encoded_in_xml(model.language):
os.remove(model.source)
@@ -565,7 +595,10 @@ def exec_task(task, variables, preprocessed_task=None, log=None, config=None, **
apply_xml_model_changes=apply_xml_model_changes,
model_etrees=model_etrees,
pretty_print_modified_xml_models=pretty_print_modified_xml_models,
- config=config)
+ config=config, preprocessed_task=preprocessed_task,
+ get_value_executer=get_value_executer,
+ set_value_executer=set_value_executer,
+ reset_executer=reset_executer)
else: # pragma: no cover: already validated by :obj:`get_first_last_models_executed_by_task`
raise NotImplementedError('Tasks of type {} are not supported.'.format(sub_task.task.__class__.__name__))
diff --git a/biosimulators_utils/sedml/utils.py b/biosimulators_utils/sedml/utils.py
index ecbecdfd..7b884bed 100644
--- a/biosimulators_utils/sedml/utils.py
+++ b/biosimulators_utils/sedml/utils.py
@@ -258,10 +258,12 @@ def get_model_changes_for_task(task):
BIOMODELS_DOWNLOAD_ENDPOINT = 'https://www.ebi.ac.uk/biomodels/model/download/{}?filename={}_url.xml'
-def resolve_model_and_apply_xml_changes(model, sed_doc, working_dir,
+def resolve_model_and_apply_xml_changes(orig_model, sed_doc, working_dir,
apply_xml_model_changes=True,
save_to_file=True,
- pretty_print_modified_xml_models=False):
+ pretty_print_modified_xml_models=False,
+ set_value_executer=None,
+ preprocessed_task_sub_executer=None):
""" Resolve the source of a model and, optionally, apply XML changes to the model.
Args:
@@ -288,10 +290,13 @@ def resolve_model_and_apply_xml_changes(model, sed_doc, working_dir,
a remote source of modified
* :obj:`etree._Element`: element tree for the resolved/modified model
"""
- model = copy.deepcopy(model)
+ model = copy.deepcopy(orig_model)
+ # We need to save this because we're going to change it, then change it back.
+ orig_model_source = orig_model.source
# resolve model
temp_model_source = resolve_model(model, sed_doc, working_dir)
+ preprocessed_task = None
# apply changes to model
if apply_xml_model_changes and model.language and is_model_language_encoded_in_xml(model.language):
@@ -302,8 +307,12 @@ def resolve_model_and_apply_xml_changes(model, sed_doc, working_dir,
raise ValueError('The model could not be parsed because the model is not a valid XML document: {}'.format(str(exception)))
if model.changes:
+ # Change source here so that tasks point to actual source they can find.
+ orig_model.source = model.source
# apply changes
- apply_changes_to_xml_model(model, model_etree, sed_doc, working_dir)
+ preprocessed_task = apply_changes_to_xml_model(model, model_etree, sed_doc, working_dir,
+ set_value_executer=set_value_executer,
+ preprocessed_task_sub_executer=preprocessed_task_sub_executer)
model.changes.clear()
# write model to file
@@ -321,7 +330,9 @@ def resolve_model_and_apply_xml_changes(model, sed_doc, working_dir,
else:
model_etree = None
- return model, temp_model_source, model_etree
+ # Reset the model source, in case it matters.
+ orig_model.source = orig_model_source
+ return model, temp_model_source, model_etree, preprocessed_task
def resolve_model(model, sed_doc, working_dir):
@@ -401,7 +412,8 @@ def resolve_model(model, sed_doc, working_dir):
def apply_changes_to_xml_model(model, model_etree, sed_doc=None, working_dir=None,
variable_values=None, range_values=None,
- validate_unique_xml_targets=True):
+ validate_unique_xml_targets=True,
+ set_value_executer=None, preprocessed_task_sub_executer=None):
""" Modify an XML-encoded model according to a model change
Args:
@@ -418,29 +430,10 @@ def apply_changes_to_xml_model(model, model_etree, sed_doc=None, working_dir=Non
validate_unique_xml_targets (:obj:`bool`, optional): whether to validate the XML targets match
uniue objects
"""
- for change in model.changes:
- if isinstance(change, ModelAttributeChange):
- # get object to change
- obj_xpath, sep, attr = change.target.rpartition('/@')
- if sep != '/@':
- raise ValueError('target {} is not a valid XPath to an attribute of a model element'.format(change.target))
- objs = eval_xpath(model_etree, obj_xpath, change.target_namespaces)
- if validate_unique_xml_targets and len(objs) != 1:
- raise ValueError('xpath {} must match a single object'.format(obj_xpath))
-
- ns_prefix, _, attr = attr.rpartition(':')
- if ns_prefix:
- ns = change.target_namespaces.get(ns_prefix, None)
- if ns is None:
- raise ValueError('No namespace is defined with prefix `{}`'.format(ns_prefix))
- attr = '{{{}}}{}'.format(ns, attr)
-
- # change value
- for obj in objs:
- obj.set(attr, change.new_value)
-
- elif isinstance(change, AddElementModelChange):
+ # First pass: Must-be-XML changes:
+ for change in model.changes:
+ if isinstance(change, AddElementModelChange):
parents = eval_xpath(model_etree, change.target, change.target_namespaces)
if validate_unique_xml_targets and len(parents) != 1:
@@ -484,6 +477,51 @@ def apply_changes_to_xml_model(model, model_etree, sed_doc=None, working_dir=Non
parent = element.getparent()
parent.remove(element)
+ elif isinstance(change, ModelAttributeChange) or isinstance(change, ComputeModelChange):
+ change.model = model
+
+ else:
+ raise NotImplementedError('Change{} of type {} is not supported.'.format(
+ ' ' + change.name if change.name else '', change.__class__.__name__))
+
+ # Interlude: set up the preprocessed task, if there's a set_value_executor
+ preprocessed_task = None
+ if set_value_executer:
+ model_etree.write(model.source,
+ xml_declaration=True,
+ encoding="utf-8",
+ standalone=False,
+ pretty_print=True)
+
+ if preprocessed_task_sub_executer:
+ preprocessed_task = preprocessed_task_sub_executer()
+
+ # Second pass: changes that might need to be interpreter-based:
+ for change in model.changes:
+ if isinstance(change, ModelAttributeChange):
+ if set_value_executer:
+ set_value_executer(change.model, change.target, None, change.new_value, preprocessed_task)
+ else:
+ # get object to change
+ obj_xpath, sep, attr = change.target.rpartition('/@')
+ if sep != '/@':
+ raise NotImplementedError('target ' + change.target + ' cannot be changed by XML manipulation, as the target '
+ 'is not an attribute of a model element')
+ objs = eval_xpath(model_etree, obj_xpath, change.target_namespaces)
+ if validate_unique_xml_targets and len(objs) != 1:
+ raise ValueError('xpath {} must match a single object'.format(obj_xpath))
+
+ ns_prefix, _, attr = attr.rpartition(':')
+ if ns_prefix:
+ ns = change.target_namespaces.get(ns_prefix, None)
+ if ns is None:
+ raise ValueError('No namespace is defined with prefix `{}`'.format(ns_prefix))
+ attr = '{{{}}}{}'.format(ns, attr)
+
+ # change value
+ for obj in objs:
+ obj.set(attr, change.new_value)
+
elif isinstance(change, ComputeModelChange):
# get the values of model variables referenced by compute model changes
if variable_values is None:
@@ -499,28 +537,30 @@ def apply_changes_to_xml_model(model, model_etree, sed_doc=None, working_dir=Non
else:
new_value = str(new_value)
- # get object to change
- obj_xpath, sep, attr = change.target.rpartition('/@')
- if sep != '/@':
- raise ValueError('target {} is not a valid XPath to an attribute of a model element'.format(change.target))
- objs = eval_xpath(model_etree, obj_xpath, change.target_namespaces)
- if validate_unique_xml_targets and len(objs) != 1:
- raise ValueError('xpath {} must match a single object'.format(obj_xpath))
-
- ns_prefix, _, attr = attr.rpartition(':')
- if ns_prefix:
- ns = change.target_namespaces.get(ns_prefix, None)
- if ns is None:
- raise ValueError('No namespace is defined with prefix `{}`'.format(ns_prefix))
- attr = '{{{}}}{}'.format(ns, attr)
-
- # change value
- for obj in objs:
- obj.set(attr, new_value)
+ if set_value_executer:
+ set_value_executer(change.model, change.target, change.symbol, new_value, preprocessed_task)
+ else:
+ # get object to change
+ obj_xpath, sep, attr = change.target.rpartition('/@')
+ if sep != '/@':
+ raise NotImplementedError('target ' + change.target + ' cannot be changed by XML manipulation, as the target '
+ 'is not an attribute of a model element')
+ objs = eval_xpath(model_etree, obj_xpath, change.target_namespaces)
+ if validate_unique_xml_targets and len(objs) != 1:
+ raise ValueError('xpath {} must match a single object'.format(obj_xpath))
+
+ ns_prefix, _, attr = attr.rpartition(':')
+ if ns_prefix:
+ ns = change.target_namespaces.get(ns_prefix, None)
+ if ns is None:
+ raise ValueError('No namespace is defined with prefix `{}`'.format(ns_prefix))
+ attr = '{{{}}}{}'.format(ns, attr)
- else:
- raise NotImplementedError('Change{} of type {} is not supported.'.format(
- ' ' + change.name if change.name else '', change.__class__.__name__))
+ # change value
+ for obj in objs:
+ obj.set(attr, new_value)
+
+ return preprocessed_task
def get_values_of_variable_model_xml_targets_of_model_change(change, sed_doc, model_etrees, working_dir):
@@ -541,7 +581,7 @@ def get_values_of_variable_model_xml_targets_of_model_change(change, sed_doc, mo
for variable in change.variables:
variable_model = variable.model
if variable_model.id not in model_etrees:
- copy_variable_model, temp_model_source, variable_model_etree = resolve_model_and_apply_xml_changes(
+ copy_variable_model, temp_model_source, variable_model_etree, preprocessed_task = resolve_model_and_apply_xml_changes(
variable_model, sed_doc, working_dir,
apply_xml_model_changes=True,
save_to_file=False)
@@ -575,7 +615,8 @@ def get_value_of_variable_model_xml_targets(variable, model_etrees):
obj_xpath, sep, attr = variable.target.rpartition('/@')
if sep != '/@':
- raise ValueError('target {} is not a valid XPath to an attribute of a model element'.format(variable.target))
+ raise NotImplementedError('the value of target ' + variable.target +
+ ' cannot be obtained by examining the XML, as the target is not an attribute of a model element')
et = model_etrees[variable.model.id]
obj = eval_xpath(et, obj_xpath, variable.target_namespaces)
diff --git a/biosimulators_utils/sedml/validation.py b/biosimulators_utils/sedml/validation.py
index 29f4522f..b29953fc 100644
--- a/biosimulators_utils/sedml/validation.py
+++ b/biosimulators_utils/sedml/validation.py
@@ -1386,8 +1386,8 @@ def validate_data_generator_variables(variables, model_etrees=None, validate_tar
if not variable.id:
variable_errors.append(['Variable must have an id.'])
- if variable.model:
- variable_errors.append(['Variable should not reference a model.'])
+ # if variable.model:
+ # variable_errors.append(['Variable should not reference a model.'])
if variable.task:
task_types.add(get_task_results_shape(variable.task))
diff --git a/tests/combine/test_combine_exec.py b/tests/combine/test_combine_exec.py
index 4b25d2da..8dee88a7 100644
--- a/tests/combine/test_combine_exec.py
+++ b/tests/combine/test_combine_exec.py
@@ -383,7 +383,7 @@ def test_exec_sedml_docs_in_archive_without_log(self):
archive_filename = os.path.join(self.tmp_dir, 'archive.omex')
CombineArchiveWriter().run(archive, archive_dirname, archive_filename)
- def sed_task_executer(task, variables, log=None, config=None):
+ def sed_task_executer(task, variables, log=None, config=None, preprocessed_task=None):
if log:
log.algorithm = task.simulation.algorithm.kisao_id
log.simulator_details = {
@@ -395,7 +395,7 @@ def sed_task_executer(task, variables, log=None, config=None):
'var_2': numpy.linspace(10., 20., task.simulation.number_of_points + 1),
}), log
- def sed_task_executer_error(task, variables, log=None, config=None):
+ def sed_task_executer_error(task, variables, log=None, config=None, preprocessed_task=None):
raise ValueError('Big error')
out_dir = os.path.join(self.tmp_dir, 'outputs')
@@ -464,7 +464,7 @@ def exec_sed_doc(task_executer, filename, working_dir, base_out_dir,
indent=0, log=None, log_level=None, config=None):
return None, None
- def sed_task_executer(task, variables):
+ def sed_task_executer(task, variables, preprocessed_task=None):
pass
sed_doc_executer = functools.partial(exec_sed_doc, sed_task_executer)
diff --git a/tests/sedml/test_sedml_exec.py b/tests/sedml/test_sedml_exec.py
index 688b7e95..8613a36a 100644
--- a/tests/sedml/test_sedml_exec.py
+++ b/tests/sedml/test_sedml_exec.py
@@ -186,7 +186,7 @@ def test_successful(self):
filename = os.path.join(self.tmp_dir, 'test.sedml')
io.SedmlSimulationWriter().run(doc, filename, validate_models_with_languages=False)
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
if task.id == 'task_1_ss':
results[doc.data_generators[0].variables[0].id] = numpy.array((1., 2.))
@@ -555,7 +555,7 @@ def test_with_model_changes(self):
os.path.join(os.path.dirname(__file__), '..', 'fixtures', 'sbml-three-species.xml'),
os.path.join(working_dir, 'model1.xml'))
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
et = etree.parse(task.model.source)
results = VariableResults()
@@ -591,7 +591,7 @@ def test_warnings(self):
filename = os.path.join(self.tmp_dir, 'test.sedml')
io.SedmlSimulationWriter().run(doc, filename)
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
return VariableResults(), log
out_dir = os.path.join(self.tmp_dir, 'results')
@@ -651,7 +651,7 @@ def exec_task(task, variables, log=None, config=None):
filename = os.path.join(self.tmp_dir, 'test.sedml')
io.SedmlSimulationWriter().run(doc, filename, validate_models_with_languages=False)
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
if task.id == 'task1':
return VariableResults({'data_gen_1_var_1': numpy.array(1.)}), log
else:
@@ -720,7 +720,7 @@ def test_errors(self):
filename = os.path.join(self.tmp_dir, 'test.sedml')
io.SedmlSimulationWriter().run(doc, filename, validate_models_with_languages=False)
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
return VariableResults(), log
working_dir = os.path.dirname(filename)
@@ -786,7 +786,7 @@ def exec_task(task, variables, log=None, config=None):
],
))
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = numpy.array((1.,))
results[doc.data_generators[0].variables[1].id] = numpy.array((1.,))
@@ -827,7 +827,7 @@ def exec_task(task, variables, log=None, config=None):
)
]
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = numpy.array((1.,))
return results, log
@@ -875,7 +875,7 @@ def exec_task(task, variables, log=None, config=None):
),
]
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = numpy.array((1.,))
results[doc.data_generators[0].variables[1].id] = numpy.array((1., 2.))
@@ -947,7 +947,7 @@ def exec_task(task, variables, log=None, config=None):
),
]
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = numpy.array((1.,))
results[doc.data_generators[1].variables[0].id] = numpy.array((1., 2.))
@@ -1045,7 +1045,7 @@ def exec_task(task, variables, log=None, config=None):
),
]
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = numpy.array((1., 2.))
results[doc.data_generators[1].variables[0].id] = numpy.array((2., 3.))
@@ -1171,7 +1171,7 @@ def test_2d_plot(self):
filename = os.path.join(self.tmp_dir, 'test.sedml')
io.SedmlSimulationWriter().run(doc, filename, validate_models_with_languages=False)
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = numpy.linspace(0., 10., 10 + 1)
results[doc.data_generators[1].variables[0].id] = 2 * results[doc.data_generators[0].variables[0].id]
@@ -1274,7 +1274,7 @@ def exec_task(task, variables, log=None, config=None):
)
# error with a task
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = None
results[doc.data_generators[1].variables[0].id] = 2 * numpy.linspace(0., 10., 10 + 1)
@@ -1421,7 +1421,7 @@ def test_3d_plot(self):
filename = os.path.join(self.tmp_dir, 'test.sedml')
io.SedmlSimulationWriter().run(doc, filename, validate_models_with_languages=False)
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
x = numpy.arange(-5, 5, 0.25)
x, _ = numpy.meshgrid(x, x)
@@ -1662,7 +1662,7 @@ def test_exec_repeated_task(self):
model2.id: etree.parse(model_filename2),
}
- def task_executer(task, variables, log=None, config=None):
+ def task_executer(task, variables, log=None, config=None, preprocessed_task=None):
et = etree.parse(task.model.source)
if task.id == task1.id:
@@ -1781,7 +1781,7 @@ def test_exec_sed_doc_with_repeated_task(self):
file.write(' ')
file.write('')
- def task_executer(task, variables, log=None, config=None):
+ def task_executer(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults({
'x': numpy.linspace(10., 15., 6),
'y': numpy.linspace(20., 25., 6),
@@ -1829,7 +1829,7 @@ def test_capturer_not_available(self):
file.write(' ')
file.write('')
- def task_executer(task, variables, log=None, config=None):
+ def task_executer(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults({
'x': numpy.linspace(10., 15., 6),
})
@@ -1906,7 +1906,7 @@ def test_exec_without_log(self):
filename = os.path.join(self.tmp_dir, 'test.sedml')
io.SedmlSimulationWriter().run(doc, filename, validate_models_with_languages=False)
- def exec_task(task, variables, log=None, config=None):
+ def exec_task(task, variables, log=None, config=None, preprocessed_task=None):
results = VariableResults()
results[doc.data_generators[0].variables[0].id] = numpy.array((1., 2.))
return results, log
diff --git a/tests/sedml/test_sedml_utils.py b/tests/sedml/test_sedml_utils.py
index bb2e8eb7..10390b36 100644
--- a/tests/sedml/test_sedml_utils.py
+++ b/tests/sedml/test_sedml_utils.py
@@ -685,7 +685,7 @@ def test_errors(self):
target_namespaces={'sbml': 'http://www.sbml.org/sbml/level2/version4'},
new_value='1.9')
et = etree.parse(self.FIXTURE_FILENAME)
- with self.assertRaises(ValueError):
+ with self.assertRaises(NotImplementedError):
utils.apply_changes_to_xml_model(data_model.Model(changes=[change]), et, None, None)
change = data_model.ModelAttributeChange(
@@ -768,7 +768,7 @@ def test_apply_compute_model_change_new_value(self):
}
change.variables[0].target = "/model/parameter[@id='x']"
- with self.assertRaisesRegex(ValueError, 'not a valid XPath'):
+ with self.assertRaisesRegex(NotImplementedError, 'cannot be obtained by examining the XML'):
utils.get_value_of_variable_model_xml_targets(change.variables[0], models)
change.variables[0].target = "/model/parameter/@value"
@@ -864,7 +864,7 @@ def test_apply_compute_model_change_new_value(self):
change.target = "/model/parameter[@type='parameter']"
et = etree.parse(in_file)
- with self.assertRaisesRegex(ValueError, 'not a valid XPath to an attribute'):
+ with self.assertRaisesRegex(NotImplementedError, 'cannot be changed by XML manipulation'):
utils.apply_changes_to_xml_model(data_model.Model(changes=[change]), et, None, None, variable_values=variable_values)
with open(in_file, 'w') as file:
@@ -880,6 +880,43 @@ def test_apply_compute_model_change_new_value(self):
change.target_namespaces['qual'] = "https://qual.sbml.org"
utils.apply_changes_to_xml_model(data_model.Model(changes=[change]), et, None, None, variable_values=variable_values)
+ def test_apply_compute_model_change_new_value_only_objects(self):
+ change = data_model.ComputeModelChange(
+ target="/model/parameter[@id='p1']",
+ parameters=[
+ data_model.Parameter(id='a', value=1.5),
+ data_model.Parameter(id='b', value=2.25),
+ data_model.Parameter(id='c', value=2.),
+ ],
+ variables=[
+ data_model.Variable(id='x', model=data_model.Model(id='model_1'), target="/model/parameter[@id='x']"),
+ data_model.Variable(id='y', model=data_model.Model(id='model_2'), target="/model/parameter[@id='y']"),
+ ],
+ math='a * x + b * y',
+ )
+
+ # get values of variables
+ model_filename = os.path.join(self.tmp_dir, 'model_1.xml')
+ with open(model_filename, 'w') as file:
+ file.write('')
+ file.write('')
+ file.write('')
+ file.write('')
+ models = {
+ 'model_1': etree.parse(model_filename),
+ 'model_2': etree.parse(model_filename),
+ }
+
+ change.variables[0].target = None
+ change.variables[0].symbol = True
+
+ change.variables[0].target = "/model/parameter[@id='x']"
+ change.variables[0].symbol = None
+ with self.assertRaisesRegex(NotImplementedError, 'cannot be obtained by examining the XML'):
+ self.assertEqual(utils.get_value_of_variable_model_xml_targets(change.variables[0], models), 2.0)
+ with self.assertRaisesRegex(NotImplementedError, 'cannot be obtained by examining the XML'):
+ self.assertEqual(utils.get_value_of_variable_model_xml_targets(change.variables[1], models), 3.0)
+
def test_set_value_calc_compute_model_change_new_value(self):
change = data_model.SetValueComputeModelChange(
target="/model/parameter[@id='p1']/@value",
@@ -1521,7 +1558,7 @@ def test_resolve_model_and_apply_xml_changes_error_handling(self):
file.write('')
file.write('')
- temp_model, temp_model_source, temp_model_etree = utils.resolve_model_and_apply_xml_changes(
+ temp_model, temp_model_source, temp_model_etree, __ = utils.resolve_model_and_apply_xml_changes(
model, sed_doc, self.tmp_dir, save_to_file=False)
self.assertEqual(temp_model.source, model_filename)
@@ -1540,7 +1577,7 @@ def test_resolve_model_and_apply_xml_changes_error_handling(self):
model.language = data_model.ModelLanguage.BNGL.value
with open(model_filename, 'w') as file:
file.write('sbml')
- temp_model, temp_model_source, temp_model_etree = utils.resolve_model_and_apply_xml_changes(
+ temp_model, temp_model_source, temp_model_etree, __ = utils.resolve_model_and_apply_xml_changes(
model, sed_doc, self.tmp_dir, save_to_file=False)
self.assertEqual(temp_model.source, model_filename)
@@ -1647,3 +1684,6 @@ def test_get_task_results_shape(self):
],
)
self.assertEqual(utils.get_task_results_shape(task), (5, 1, 3, 2, 11))
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/sedml/test_sedml_validation.py b/tests/sedml/test_sedml_validation.py
index 2da94095..f4778561 100644
--- a/tests/sedml/test_sedml_validation.py
+++ b/tests/sedml/test_sedml_validation.py
@@ -234,7 +234,7 @@ def test_validate_doc(self):
],
))
errors, warnings = validation.validate_doc(doc, self.dirname)
- self.assertIn('should not reference a model', flatten_nested_list_of_strings(errors))
+ # self.assertIn('should not reference a model', flatten_nested_list_of_strings(errors))
self.assertEqual(warnings, [])
doc = data_model.SedDocument()
@@ -1210,7 +1210,7 @@ def test_validate_task(self):
data_model.Variable(task=data_model.Task(), model=data_model.Model())
]
errors, warnings = self._validate_task(task, variables)
- self.assertIn('should not reference a model', flatten_nested_list_of_strings(errors))
+ # self.assertIn('should not reference a model', flatten_nested_list_of_strings(errors))
self.assertEqual(warnings, [])
variables = [