Skip to content

Commit

Permalink
Simulation validation (#246)
Browse files Browse the repository at this point in the history
* Added simulation config schema validation
* Added tests for simulation schema validation
* Add simulation validation as click command
* Update docs
* deprecated 'validate' -> 'validate-circuit'
  • Loading branch information
joni-herttuainen committed Nov 23, 2023
1 parent 9479090 commit e97429f
Show file tree
Hide file tree
Showing 13 changed files with 1,164 additions and 36 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.rst
@@ -1,6 +1,23 @@
Changelog
=========

Version v2.1.0
--------------

New Features
~~~~~~~~~~~~
- Added simulation config validation
- Added a new commandline subcommand: ``validate-simulation``
- Added an alias ``validate-circuit`` for the old ``validate`` subcommand

- deprecated ``validate``


Breaking Changes
~~~~~~~~~~~~~~~~
- Deprecated the commandline subcommand ``validate`` in favor of new ``validate-circuit`` command


Version v2.0.2
--------------

Expand Down
27 changes: 26 additions & 1 deletion README.rst
Expand Up @@ -62,7 +62,7 @@ This functionality is provided by either the cli function:

.. code-block:: shell
bluepysnap validate my/circuit/path/circuit_config.json
bluepysnap validate-circuit my/circuit/path/circuit_config.json
Or a python free function:
Expand All @@ -73,6 +73,31 @@ Or a python free function:
errors = validate("my/circuit/path/circuit_config.json")
Simulation Validation
~~~~~~~~~~~~~~~~~~~~~

Similarly to circuit validation, Blue Brain SNAP also provides a SONATA simulation validator for verifying simulation configs.

Currently, the validator only verifies that:

- all the mandatory fields are present in the config file
- all the properties in the `simulation config specification <https://sonata-extension.readthedocs.io/en/latest/sonata_simulation.html>`__ have correct data types and accepted values

This functionality is provided by either the cli function:

.. code-block:: shell
bluepysnap validate-simulation my/circuit/path/simulation_config.json
Or a python free function:

.. code-block:: python3
from bluepysnap.simulation_validation import validate
errors = validate("my/circuit/path/simulation_config.json")
Acknowledgements
----------------

Expand Down
22 changes: 3 additions & 19 deletions bluepysnap/circuit_validation.py
Expand Up @@ -5,7 +5,6 @@
import logging
from pathlib import Path

import click
import h5py
import numpy as np
import pandas as pd
Expand All @@ -15,7 +14,7 @@
from bluepysnap.exceptions import BluepySnapValidationError
from bluepysnap.morph import EXTENSIONS_MAPPING
from bluepysnap.sonata_constants import DEFAULT_EDGE_TYPE, DEFAULT_NODE_TYPE
from bluepysnap.utils import load_json
from bluepysnap.utils import load_json, print_validation_errors

L = logging.getLogger("brainbuilder")
MAX_MISSING_FILES_DISPLAY = 10
Expand Down Expand Up @@ -73,21 +72,6 @@ def _check_files(name, files):
return []


def _print_errors(errors):
"""Some fancy errors printing."""
colors = {
BluepySnapValidationError.WARNING: "yellow",
BluepySnapValidationError.FATAL: "red",
BluepySnapValidationError.INFO: "green",
}

if not errors:
print(click.style("No Error: Success.", fg=colors[BluepySnapValidationError.INFO]))

for error in errors:
print(click.style(error.level + ": ", fg=colors[error.level]) + str(error))


def _check_duplicate_populations(networks, key):
"""Check that that for key = nodes|edges, no duplicate populations names exists."""
seen = set()
Expand Down Expand Up @@ -599,7 +583,7 @@ def validate(config_file, skip_slow, only_errors=False, print_errors=True):
print_errors (bool): print errors
Returns:
list: List of errors, empty if no errors
set: set of errors, empty if no errors
"""
config = Parser.parse(load_json(config_file), str(Path(config_file).parent))
errors = schemas.validate_circuit_schema(config_file, config)
Expand All @@ -618,6 +602,6 @@ def validate(config_file, skip_slow, only_errors=False, print_errors=True):
errors = [e for e in errors if e.level == BluepySnapValidationError.FATAL]

if print_errors:
_print_errors(errors)
print_validation_errors(errors)

return set(errors)
72 changes: 60 additions & 12 deletions bluepysnap/cli.py
@@ -1,9 +1,14 @@
"""The project's command line launcher."""
import functools
import logging
import warnings

import click

from bluepysnap import circuit_validation
from bluepysnap import circuit_validation, simulation_validation
from bluepysnap.utils import Deprecate

CLICK_EXISTING_FILE = click.Path(exists=True, file_okay=True, dir_okay=False)


@click.group()
Expand All @@ -18,23 +23,66 @@ def cli(verbose):
)


def circuit_validation_params(func):
"""Small helper to have shared params."""

@click.argument("config_file", type=CLICK_EXISTING_FILE)
@click.option(
"--skip-slow/--no-skip-slow",
default=True,
help=(
"Skip slow checks; checking all edges refer to existing node ids, "
"edge indices are correct, etc"
),
)
@click.option("--only-errors", is_flag=True, help="Only print fatal errors (ignore warnings)")
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)

return wrapper


@cli.command()
@click.argument("config_file", type=click.Path(exists=True, file_okay=True, dir_okay=False))
@click.option(
"--skip-slow/--no-skip-slow",
default=True,
help=(
"Skip slow checks; checking all edges refer to existing node ids, "
"edge indices are correct, etc"
),
)
@click.option("--only-errors", is_flag=True, help="Only print fatal errors (ignore warnings)")
@circuit_validation_params
def validate(config_file, skip_slow, only_errors):
"""Validate of Sonata circuit based on config file.
"""[DEPRECATED] Validate Sonata circuit based on config file.
Args:
config_file (str): path to Sonata circuit config file
skip_slow (bool): skip slow tests
only_errors (bool): only print fatal errors
"""
with warnings.catch_warnings():
# Making sure the warning is shown
warnings.simplefilter("always", DeprecationWarning)
Deprecate.warn(
"Calling circuit validation with 'validate' is deprecated. "
"Please use 'validate-circuit' instead."
)

circuit_validation.validate(config_file, skip_slow, only_errors)


@cli.command()
@circuit_validation_params
def validate_circuit(config_file, skip_slow, only_errors):
"""Validate Sonata circuit based on config file.
Args:
config_file (str): path to Sonata circuit config file
skip_slow (bool): skip slow tests
only_errors (bool): only print fatal errors
"""
circuit_validation.validate(config_file, skip_slow, only_errors)


@cli.command()
@click.argument("config_file", type=CLICK_EXISTING_FILE)
def validate_simulation(config_file):
"""Validate Sonata simulation based on config file.
Args:
config_file (str): path to Sonata simulation config file
"""
simulation_validation.validate(config_file)
1 change: 1 addition & 0 deletions bluepysnap/schemas/__init__.py
Expand Up @@ -3,4 +3,5 @@
validate_circuit_schema,
validate_edges_schema,
validate_nodes_schema,
validate_simulation_schema,
)

0 comments on commit e97429f

Please sign in to comment.