Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SystemInterface abstraction #9

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Binary file modified docs/source/sim-explorer.pptx
Binary file not shown.
2 changes: 0 additions & 2 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ ignore = [
# "N816", # Variable in global scope should not be mixedCase (uncomment if you want to allow mixedCase variable names in global scope)

# Ruff lint rules considered as too strict and hence ignored
"ANN101", # Missing type annotation for `self` argument in instance methods (NOTE: also listed as deprecated by Ruff)
"ANN102", # Missing type annotation for `cls` argument in class methods (NOTE: also listed as deprecated by Ruff)
"FIX002", # Line contains TODO, consider resolving the issue
"TD003", # Missing issue link on the line following a TODO
"S101", # Use of assert detected
Expand Down
12 changes: 5 additions & 7 deletions src/sim_explorer/assertion.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# type: ignore

import ast
from typing import Any, Callable, Iterable, Iterator

Expand Down Expand Up @@ -69,7 +67,7 @@ def info(self, sym: str, typ: str = "instance") -> str | int:
elif typ == "variable": # get the generic variable name
return var
elif typ == "length": # get the number of elements
return len(self._cases_variables[var]["variables"])
return len(self._cases_variables[var]["refs"])
elif typ == "model": # get the basic (FMU) model
return self._cases_variables[var]["model"]
else:
Expand Down Expand Up @@ -250,8 +248,8 @@ def register_vars(self, variables: dict):
for key, info in variables.items():
for inst in info["instances"]:
if len(info["instances"]) == 1: # the instance is unique
self.symbol(key, len(info["variables"])) # we allow to use the 'short name' if unique
self.symbol(inst + "_" + key, len(info["variables"])) # fully qualified name can always be used
self.symbol(key, len(info["names"])) # we allow to use the 'short name' if unique
self.symbol(inst + "_" + key, len(info["names"])) # fully qualified name can always be used

def make_locals(self, loc: dict):
"""Adapt the locals with 'allowed' functions."""
Expand Down Expand Up @@ -303,7 +301,7 @@ def eval_single(self, key: str, kvargs: dict | list | tuple):
# print("kvargs", kvargs, self._syms[key], self.expr_get_symbols_functions(key))
return self._eval(locals()["_" + key], kvargs)

def eval_series(self, key: str, data: list[Any], ret: float | str | Callable | None = None):
def eval_series(self, key: str, data: list, ret: float | str | Callable | None = None):
"""Perform assertion on a (time) series.

Args:
Expand Down Expand Up @@ -336,7 +334,7 @@ def eval_series(self, key: str, data: list[Any], ret: float | str | Callable | N
_temp = self._temporal[key]["type"] if ret is None else Temporal.UNDEFINED

for row in data:
if not isinstance(row, Iterable): # can happen if the time itself is evaluated
if not isinstance(row, (tuple, list)): # can happen if the time itself is evaluated
time = row
row = [row]
elif "t" not in argnames: # the independent variable is not explicitly used in the expression
Expand Down
483 changes: 173 additions & 310 deletions src/sim_explorer/case.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/sim_explorer/cli/sim_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def main() -> None:
logger.error(f"Instantiation of {args.cases} not successfull")
return

log_msg_stub: str = f"Start sim-explorer.py with following arguments:\n" f"\t cases: \t{cases}\n"
log_msg_stub: str = f"Start sim-explorer.py with following arguments:\n\t cases: \t{cases}\n"

case: Case | None = None

Expand Down
14 changes: 8 additions & 6 deletions src/sim_explorer/json5.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ def _msg(self, pre: str, num: int = 50, pos: int | None = None) -> str:
pos = self.pos
try:
line, p = self._get_line_number(pos)
return f"Json5 read error at {line}({p}): {pre}: {self.js5[pos : pos+num]}"
return f"Json5 read error at {line}({p}): {pre}: {self.js5[pos : pos + num]}"
except Json5Error as err: # can happen when self.lines does not yet exist
return f"Json5 read error at {pos}: {pre}: {self.js5[pos : pos+num]}: {err}"
return f"Json5 read error at {pos}: {pre}: {self.js5[pos : pos + num]}: {err}"

def _lines(self):
"""Map start positions of lines and replace all newline CR-LF combinations with single newline (LF)."""
Expand Down Expand Up @@ -260,7 +260,7 @@ def _re(txt: str):
_js5 += js5[pos : pos + s1.start()]
pos += pos + s1.start()
s2 = c2.search(js5[pos:])
assert s2 is not None, f"No end of comment found for comment starting with '{js5[pos:pos+50]}'"
assert s2 is not None, f"No end of comment found for comment starting with '{js5[pos : pos + 50]}'"
comments.update({pos + s2.start(): js5[pos : pos + s2.start()]})
for p in range(pos, pos + s2.end()):
if js5[p] not in ("\r", "\n"):
Expand Down Expand Up @@ -362,7 +362,7 @@ def _key(self) -> str:
m = re.search(r":", self.js5[self.pos :])
assert m is not None, self._msg(f"Quoted key {k} found, but no ':'")
assert not len(self.js5[self.pos : self.pos + m.start()].strip()), self._msg(
f"Additional text '{self.js5[self.pos : self.pos+m.start()].strip()}' after key '{k}'"
f"Additional text '{self.js5[self.pos : self.pos + m.start()].strip()}' after key '{k}'"
)
else:
m = re.search(r"[:\}]", self.js5[self.pos :])
Expand Down Expand Up @@ -395,7 +395,7 @@ def _value(self):
v = self._object() if m.group() == "{" else self._list()
m = re.search(r"[,\}\]]", self.js5[self.pos :])
cr, cc = self._get_line_number(self.pos)
assert m is not None, self._msg(f"End of value or end of object/list '{str(v)[:50]+'..'}' expected")
assert m is not None, self._msg(f"End of value or end of object/list '{str(v)[:50] + '..'}' expected")
elif m.group() in (
"]",
"}",
Expand All @@ -404,7 +404,7 @@ def _value(self):
v = self.js5[self.pos : self.pos + m.start()].strip() if q2 < 0 else self.js5[q1 + 1 : q2 - 1]
else:
raise Json5Error(
f"Unhandled situation. Quoted: ({q1-self.pos},{q2-self.pos}), search: {m}. From pos: {self.js5[self.pos : ]}"
f"Unhandled situation. Quoted: ({q1 - self.pos},{q2 - self.pos}), search: {m}. From pos: {self.js5[self.pos :]}"
)
# save_pos = self.pos
self.pos += (
Expand All @@ -421,6 +421,8 @@ def _value(self):
elif isinstance(v, str) and not len(v): # might be empty due to trailing ','
return ""

if q2 >= 0: # explicitly quoted values are treated as strings!
return str(v)
try:
return int(v) # type: ignore
except Exception:
Expand Down
Loading
Loading