Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit fce49b5

Browse files
committed
Adding improved error messages on dm-script errors
1 parent 3cac101 commit fce49b5

File tree

1 file changed

+153
-18
lines changed

1 file changed

+153
-18
lines changed

execdmscript/execdmscript.py

Lines changed: 153 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,63 @@ class ModuleNotFoundError(ImportError):
2323
"Microscopy Suite program.")
2424
DM = None
2525

26+
class DMScriptError(RuntimeError):
27+
"""Error in executed dm-script code."""
28+
# The doc is shown in the GMS error message. Keeping the real doc string
29+
# makes the error message very big and fills it with completely useless
30+
# information
31+
#
32+
# """This represents an error in the executed dm-script code.
33+
#
34+
# Parameters
35+
# ----------
36+
# msg : str
37+
# The text to show
38+
# script_origin : str
39+
# The name of the executed script that the error occurres in
40+
# line_in_origin : int
41+
# The line in the executed script (the `script_origin`) where the error
42+
# occurres
43+
# line_in_complete : int
44+
# The line in the compound script (including the setvars and readvars
45+
# code)
46+
# """
47+
48+
def __init__(self, msg: str, script_origin: str, line_in_origin: int,
49+
line_in_complete: int) -> None:
50+
"""
51+
Parameters
52+
----------
53+
msg : str
54+
The text to show
55+
script_origin : str
56+
The name of the executed script that the error occurres in
57+
line_in_origin : int
58+
The line in the executed script (the `script_origin`) where the error
59+
occurres
60+
line_in_complete : int
61+
The line in the compound script (including the setvars and readvars
62+
code)
63+
"""
64+
super(DMScriptError, self).__init__(msg)
65+
self.script_origin = script_origin
66+
self.line_in_origin = line_in_origin
67+
self.line_in_complete = line_in_complete
68+
self.msg = msg
69+
70+
def __str__(self) -> str:
71+
"""Get the error as a a string.
72+
73+
Returns
74+
-------
75+
str
76+
The error with (most of) the details
77+
"""
78+
79+
return ("Error in dm-script code {} in line {} (line {} in complete " +
80+
"code): {}").format(self.script_origin, self.line_in_origin,
81+
self.line_in_complete, self.msg)
82+
2683
Convertable = typing.Union[int, float, bool, str, dict, list, tuple, None]
2784

2885
_python_dm_type_map = ({
@@ -335,6 +392,7 @@ def __init__(self,
335392
self.debug = bool(debug)
336393
self.debug_file = debug_file
337394
self._slash_split_reg = re.compile("(?<!/)/(?!/)")
395+
self._script_sources = []
338396

339397
# add all setvars to the readvars to allow accessing them after the
340398
# script is executed
@@ -373,7 +431,37 @@ def __call__(self) -> bool:
373431
"because file is running in debug mode.").format(path))
374432
return True
375433
else:
376-
DM.ExecuteScriptString(dmscript)
434+
try:
435+
DM.ExecuteScriptString(dmscript)
436+
except RuntimeError as e:
437+
matches = re.match(r"Error in line ([\d]+)\s*\n(.*)", str(e))
438+
439+
if matches is not None:
440+
# there is an error in the executed script, read the line
441+
# and check in which script the error is, then calculate
442+
# the line in the script, this is better information for
443+
# the user as he/she doesn't know what code is prefixed
444+
# and suffixed
445+
line = int(matches.group(1))
446+
447+
for script_src in self._script_sources:
448+
if (script_src["start"] <= line and
449+
line <= script_src["end"]):
450+
msg = matches.group(2)
451+
src = script_src["origin-name"]
452+
l = line - script_src["start"] + 1
453+
454+
error = DMScriptError(msg, src, l, line)
455+
456+
# GMS shows the docstring in their error message,
457+
# so to offer a useful text, overwrite the docstring
458+
error.__doc__ = str(error)
459+
type(error).__doc__ = str(error)
460+
DMScriptError.__doc__ = str(error)
461+
462+
raise error from e
463+
else:
464+
raise e
377465
self._loadVariablesFromDMScript()
378466
return True
379467

@@ -428,36 +516,84 @@ def getExecDMScriptCode(self) -> str:
428516
str
429517
The code to execute
430518
"""
519+
self._script_sources = []
520+
last_pos = 1
521+
431522
dmscript = [
432523
"// This code is created automatically by concatenating files and ",
433524
"// code fragments.",
434525
"// ",
435-
"// This code is generated with the exedmscript module."
436-
"",
437-
"",
438-
self.getSetVarsDMCode()
526+
"// This code is generated with the exedmscript module.",
527+
"//",
528+
"//" + " =" * 50
439529
]
530+
new_pos = last_pos + len(dmscript) - 1
531+
self._script_sources.append({
532+
"start": last_pos,
533+
"end": new_pos,
534+
"origin-name": "<comments>",
535+
"origin-detail": None
536+
})
537+
last_pos = new_pos + 1
538+
539+
setvars_code = self.getSetVarsDMCode()
540+
dmscript.append(setvars_code)
541+
542+
new_pos = last_pos + setvars_code.count("\n")
543+
self._script_sources.append({
544+
"start": last_pos,
545+
"end": new_pos,
546+
"origin-name": "<setvars code>",
547+
"origin-detail": self.getSetVarsDMCode
548+
})
549+
last_pos = new_pos + 1
440550

441-
for kind, script in self.scripts:
551+
for i, (kind, script) in enumerate(self.scripts):
442552
if isinstance(kind, str):
443553
kind = kind.lower()
444554

445555
if kind == "file":
556+
source = script
557+
comment = "// File {}".format(escape_dm_string(source))
446558
with open(script, "r") as f:
447-
dmscript += [
448-
"// File {}".format(script),
449-
f.read(),
450-
""
451-
]
559+
code = f.read()
452560
elif kind == "script":
453-
dmscript += [
454-
"// Directly given script",
455-
script,
456-
""
457-
]
561+
source = "<inline script in parameter {}>".format(i)
562+
comment = "// Directly given script"
563+
code = script
564+
565+
dmscript.append(comment)
566+
new_pos = last_pos + comment.count("\n")
567+
self._script_sources.append({
568+
"start": last_pos,
569+
"end": new_pos,
570+
"origin-name": "<comment>",
571+
"origin-detail": None
572+
})
573+
last_pos = new_pos + 1
574+
575+
dmscript.append(code)
576+
new_pos = last_pos + code.count("\n")
577+
self._script_sources.append({
578+
"start": last_pos,
579+
"end": new_pos,
580+
"origin-name": source,
581+
"origin-detail": script
582+
})
583+
last_pos = new_pos + 1
458584

459-
dmscript.append(self.getSyncDMCode())
585+
readvars_code = self.getSyncDMCode()
586+
dmscript.append(readvars_code)
460587

588+
new_pos = last_pos + readvars_code.count("\n")
589+
self._script_sources.append({
590+
"start": last_pos,
591+
"end": new_pos ,
592+
"origin-name": "<readvars code>",
593+
"origin-type": self.getSyncDMCode
594+
})
595+
last_pos = new_pos + 1
596+
461597
return "\n".join(dmscript)
462598

463599
def getSetVarsDMCode(self) -> str:
@@ -473,7 +609,6 @@ def getSetVarsDMCode(self) -> str:
473609
return ""
474610

475611
dmscript = [
476-
"",
477612
"// Setting variables from python values"
478613
]
479614
for name, val in self.setvars.items():

0 commit comments

Comments
 (0)