Source code for bluecellulab.neuron_interpreter
# Copyright 2023-2024 Blue Brain Project / EPFL
# 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.
"""Module to interpret NEURON code strings."""
from __future__ import annotations
import ast
import sys
from typing import Any
from bluecellulab.exceptions import NeuronEvalError
PY39_PLUS = sys.version_info >= (3, 9)
def _recursive_evaluate(node: ast.AST, context: dict[str, Any]) -> Any:
"""A limited evaluator for evaluating NEURON code string."""
if isinstance(node, ast.Constant):
return node.value
if isinstance(node, ast.Name):
return context[node.id]
if isinstance(node, ast.Attribute):
base = _recursive_evaluate(node.value, context)
return getattr(base, node.attr)
if isinstance(node, ast.Call):
func = _recursive_evaluate(node.func, context)
args = [_recursive_evaluate(arg, context) for arg in node.args]
return func(*args)
if isinstance(node, ast.Subscript):
base = _recursive_evaluate(node.value, context)
if PY39_PLUS:
index = _recursive_evaluate(node.slice, context)
else:
index = _recursive_evaluate(node.slice.value, context) # type: ignore
return base[index]
raise NeuronEvalError("Unexpected code!")
[docs]
def eval_neuron(source: str, **context) -> Any:
"""A limited interpreter for evaluating NEURON code."""
tree = ast.parse(source)
if len(tree.body) != 1:
raise NeuronEvalError("NEURON code should be a single expression")
[node] = tree.body
if not isinstance(node, ast.Expr):
raise NeuronEvalError("NEURON code should be an expression")
return _recursive_evaluate(node.value, context)