Skip to content

Commit

Permalink
Merge pull request #430 from NeuroML/feat-util-new-components
Browse files Browse the repository at this point in the history
Feat: util to create + include new components in NeuroMLDocuments
  • Loading branch information
sanjayankur31 authored Oct 23, 2024
2 parents 6632c9c + 076b077 commit 24a1b69
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 0 deletions.
75 changes: 75 additions & 0 deletions pyneuroml/utils/components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""
Utilities for creation and inclusion of new Components in models.
File: pyneuroml/utils/components.py
Copyright 2024 NeuroML contributors
"""

import logging
from typing import Optional

from lems.model.component import Component
from lems.model.model import Model

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


def add_new_component(
component_id: str,
component_type: str,
component_filename: Optional[str] = None,
**kwargs,
) -> Component:
"""Add a new component to a NeuroMLDocument.
This will create a new component with the provided id, type, and keyword
arguments and export it to a separate XML file and add that file as an
includes to the provided NeuroMLDocument object.
This is the suggested way of including new Components of new ComponentTypes
because it keeps them separate from the main model that is composed of
Components from the NeuroML schema---which can be validated. New
ComponentTypes and their Components can be used to extend NeuroML, but
since they are not yet included in the NeuroML standard, they cannot be
validated against the schema.
.. versionadded:: 1.3.13
:param nmldoc: NeuroMLDocument object to include component in
:type nmldoc: NeuroMLDocument
:param component_id: id of new Component
:type component_id: str
:param component_type: name of ComponentType that this Component is an
instance of. This must be a valid ComponentType that has been included
in the model. This function will not check this.
:type component_type: str
:param component_filename: optional file name to store the XML export of
the component in
:type component_filename: str
:param **kwargs: parameters to pass to the Component
:returns: the Component Object, and the name of the XML file it was serialised in
:rtype: tuple(Component, str)
"""
newmodel = Model()
newcomp = Component(id_=component_id, type_=component_type, **kwargs)
newmodel.add_component(newcomp)

if component_filename is None:
component_filename = f"component_{component_id}.xml"

logger.info(
f"Saving component with id '{component_id}' and type '{component_type}' to {component_filename}"
)
newmodel.export_to_file(component_filename)

logger.info(
"Component file included in NeuroML document. Note that new components will not validate against the NeuroML schema."
)
logger.info(
f"Please also remember to include {component_filename} in the LEMS simulation file"
)

return newcomp, component_filename
11 changes: 11 additions & 0 deletions tests/utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import logging
import math
import os
import pathlib as pl

import neuroml
Expand All @@ -20,6 +21,7 @@
rotate_cell,
translate_cell_to_coords,
)
from pyneuroml.utils.components import add_new_component

from .. import BaseTestCase

Expand Down Expand Up @@ -282,3 +284,12 @@ def test_translate_cell_to_coords(self):
write_neuroml2_file(
newdoc, "tests/utils/test_translation.net.nml", validate=True
)

def test_adding_new_components(self):
"""Test add_new_component method."""
new_comp, new_comp_file = add_new_component(
"newcomp", "sometype", param1="5v", param2="something"
)
self.assertIsNotNone(new_comp)
self.assertIsFile(new_comp_file)
os.unlink(new_comp_file)

0 comments on commit 24a1b69

Please sign in to comment.