@@ -23,6 +23,63 @@ class ModuleNotFoundError(ImportError):
23
23
"Microscopy Suite program." )
24
24
DM = None
25
25
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
+
26
83
Convertable = typing .Union [int , float , bool , str , dict , list , tuple , None ]
27
84
28
85
_python_dm_type_map = ({
@@ -335,6 +392,7 @@ def __init__(self,
335
392
self .debug = bool (debug )
336
393
self .debug_file = debug_file
337
394
self ._slash_split_reg = re .compile ("(?<!/)/(?!/)" )
395
+ self ._script_sources = []
338
396
339
397
# add all setvars to the readvars to allow accessing them after the
340
398
# script is executed
@@ -373,7 +431,37 @@ def __call__(self) -> bool:
373
431
"because file is running in debug mode." ).format (path ))
374
432
return True
375
433
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
377
465
self ._loadVariablesFromDMScript ()
378
466
return True
379
467
@@ -428,36 +516,84 @@ def getExecDMScriptCode(self) -> str:
428
516
str
429
517
The code to execute
430
518
"""
519
+ self ._script_sources = []
520
+ last_pos = 1
521
+
431
522
dmscript = [
432
523
"// This code is created automatically by concatenating files and " ,
433
524
"// code fragments." ,
434
525
"// " ,
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
439
529
]
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
440
550
441
- for kind , script in self .scripts :
551
+ for i , ( kind , script ) in enumerate ( self .scripts ) :
442
552
if isinstance (kind , str ):
443
553
kind = kind .lower ()
444
554
445
555
if kind == "file" :
556
+ source = script
557
+ comment = "// File {}" .format (escape_dm_string (source ))
446
558
with open (script , "r" ) as f :
447
- dmscript += [
448
- "// File {}" .format (script ),
449
- f .read (),
450
- ""
451
- ]
559
+ code = f .read ()
452
560
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
458
584
459
- dmscript .append (self .getSyncDMCode ())
585
+ readvars_code = self .getSyncDMCode ()
586
+ dmscript .append (readvars_code )
460
587
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
+
461
597
return "\n " .join (dmscript )
462
598
463
599
def getSetVarsDMCode (self ) -> str :
@@ -473,7 +609,6 @@ def getSetVarsDMCode(self) -> str:
473
609
return ""
474
610
475
611
dmscript = [
476
- "" ,
477
612
"// Setting variables from python values"
478
613
]
479
614
for name , val in self .setvars .items ():
0 commit comments