# -*- coding: utf-8 -*-
# Copyright 2017 Novo Nordisk Foundation Center for Biosustainability,
# Technical University of Denmark.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Programmatically interact with the memote test suite."""
from __future__ import absolute_import
import logging
import os
from io import open
import pytest
from jinja2 import Environment, PackageLoader, select_autoescape
from memote.suite import TEST_DIRECTORY
from memote.suite.collect import ResultCollectionPlugin
from memote.suite.reporting import (
DiffReport,
HistoryReport,
ReportConfiguration,
SnapshotReport,
)
from memote.support import validation as val
__all__ = (
"validate_model",
"test_model",
"snapshot_report",
"diff_report",
"history_report",
)
LOGGER = logging.getLogger(__name__)
[docs]def validate_model(path):
"""
Validate a model structurally and optionally store results as JSON.
Parameters
----------
path :
Path to model file.
Returns
-------
tuple
cobra.Model
The metabolic model under investigation.
tuple
A tuple reporting on the SBML level, version, and FBC package
version used (if any) in the SBML document.
dict
A simple dictionary containing a list of errors and warnings.
"""
notifications = {"warnings": [], "errors": []}
model, sbml_ver = val.load_cobra_model(path, notifications)
return model, sbml_ver, notifications
[docs]def test_model(
model,
sbml_version=None,
results=False,
pytest_args=None,
exclusive=None,
skip=None,
experimental=None,
solver_timeout=10,
):
"""
Test a model and optionally store results as JSON.
Parameters
----------
model : cobra.Model
The metabolic model under investigation.
sbml_version: tuple, optional
A tuple reporting on the level, version, and FBC use of the SBML file.
results : bool, optional
Whether to return the results in addition to the return code.
pytest_args : list, optional
Additional arguments for the pytest suite.
exclusive : iterable, optional
Names of test cases or modules to run and exclude all others. Takes
precedence over ``skip``.
skip : iterable, optional
Names of test cases or modules to skip.
solver_timeout: int, optional
Timeout in seconds to set on the mathematical optimization solver (default 10).
Returns
-------
int
The return code of the pytest suite.
memote.Result, optional
A nested dictionary structure that contains the complete test results.
"""
if pytest_args is None:
pytest_args = ["--tb", "short", TEST_DIRECTORY]
elif not any(a.startswith("--tb") for a in pytest_args):
pytest_args.extend(["--tb", "short"])
if TEST_DIRECTORY not in pytest_args:
pytest_args.append(TEST_DIRECTORY)
if "-s" not in pytest_args and LOGGER.getEffectiveLevel() <= logging.DEBUG:
# Disable pytest capturing so that the solver log output can be seen
# immediately.
pytest_args.insert(0, "-s")
model.solver.configuration.timeout = solver_timeout
# Load the experimental configuration using model information.
if experimental is not None:
experimental.load(model)
plugin = ResultCollectionPlugin(
model,
sbml_version=sbml_version,
exclusive=exclusive,
skip=skip,
experimental_config=experimental,
)
code = pytest.main(pytest_args, plugins=[plugin])
if results:
return code, plugin.results
else:
return code
[docs]def snapshot_report(result, config=None, html=True):
"""
Generate a snapshot report from a result set and configuration.
Parameters
----------
result : memote.MemoteResult
Nested dictionary structure as returned from the test suite.
config : dict, optional
The final test report configuration (default None).
html : bool, optional
Whether to render the report as full HTML or JSON (default True).
"""
if config is None:
config = ReportConfiguration.load()
report = SnapshotReport(result=result, configuration=config)
if html:
return report.render_html()
else:
return report.render_json()
[docs]def history_report(history, config=None, html=True):
"""
Test a model and save a history report.
Parameters
----------
history : memote.HistoryManager
The manager grants access to previous results.
config : dict, optional
The final test report configuration.
html : bool, optional
Whether to render the report as full HTML or JSON (default True).
"""
if config is None:
config = ReportConfiguration.load()
report = HistoryReport(history=history, configuration=config)
if html:
return report.render_html()
else:
return report.render_json()
[docs]def diff_report(diff_results, config=None, html=True):
"""
Generate a diff report from a result set and configuration.
Parameters
----------
diff_results : iterable of memote.MemoteResult
Nested dictionary structure as returned from the test suite.
config : dict, optional
The final test report configuration (default None).
html : bool, optional
Whether to render the report as full HTML or JSON (default True).
"""
if config is None:
config = ReportConfiguration.load()
report = DiffReport(diff_results=diff_results, configuration=config)
if html:
return report.render_html()
else:
return report.render_json()
def validation_report(path, notifications, filename):
"""
Generate a validation report from a notification object.
Parameters
----------
path : string
Path to model file.
notifications : dict
A simple dictionary structure containing a list of errors and warnings.
"""
env = Environment(
loader=PackageLoader("memote.suite", "templates"),
autoescape=select_autoescape(["html", "xml"]),
)
template = env.get_template("validation_template.html")
model = os.path.basename(path)
with open(filename, "w") as file_h:
file_h.write(template.render(model=model, notifications=notifications))