Skip to content

Commit f75478e

Browse files
v3.2.4 (#1329)
- CMX: improved logging - CMX: improved error handling (show module path and line number)
2 parents 71e1720 + c7bd26b commit f75478e

File tree

6 files changed

+139
-17
lines changed

6 files changed

+139
-17
lines changed

cm/CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## V3.2.4
2+
- CMX: improved logging
3+
- CMX: improved error handling (show module path and line number)
4+
15
## V3.2.3
26
- added --new_branch to `cm pull repo` and `cm checkout repo`
37
- fixed a bug in `cm show repo` (removed dependency on cm4mlops

cm/cmind/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
#
33
# Written by Grigori Fursin
44

5-
__version__ = "3.2.3"
5+
__version__ = "3.2.4"
66

77
from cmind.core import access
88
from cmind.core import x
99
from cmind.core import error
10+
from cmind.core import errorx
1011
from cmind.core import halt
1112
from cmind.core import CM

cm/cmind/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def runx(argv = None):
8484
r = cm.x(argv, out='con')
8585

8686
if r['return']>0 and (cm.output is None or cm.output == 'con'):
87-
cm.error(r)
87+
cm.errorx(r)
8888

8989
sys.exit(r['return'])
9090

cm/cmind/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def __init__(self, config_file = None):
3737
"flag_help2": "help",
3838

3939
"error_prefix": "CM error:",
40+
"error_prefix2": "CMX detected an issue",
4041
"info_cli": "cm {action} {automation} {artifact(s)} {flags} @input.yaml @input.json",
4142
"info_clix": "cmx {action} {automation} {artifact(s)} {CMX control flags (-)} {CMX automation flags (--)}",
4243

cm/cmind/core.py

Lines changed: 127 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,116 @@ def error(self, r):
140140

141141
return r
142142

143+
############################################################
144+
def errorx(self, r):
145+
"""
146+
If r['return']>0: print CM error and raise error if in debugging mode
147+
148+
Args:
149+
r (dict): output from CM function with "return" and "error"
150+
151+
Returns:
152+
(dict): r
153+
154+
"""
155+
156+
import os
157+
158+
if r['return']>0:
159+
if self.debug:
160+
raise Exception(r['error'])
161+
162+
module_path = r.get('module_path', '')
163+
lineno = r.get('lineno', '')
164+
165+
message = ''
166+
167+
if not self.logger == None or (module_path != '' and lineno != ''):
168+
call_stack = self.state.get('call_stack', [])
169+
170+
if not self.logger == None:
171+
172+
self.log(f"x error call stack: {call_stack}", "debug")
173+
self.log(f"x error: {r}", "debug")
174+
175+
sys.stderr.write('='*60 + '\n')
176+
177+
if not self.logger == None:
178+
sys.stderr.write('CMX call stack:\n')
179+
180+
for cs in call_stack:
181+
sys.stderr.write(f' * {cs}\n')
182+
183+
message += '\n'
184+
else:
185+
message += '\n'
186+
187+
message += self.cfg['error_prefix2']
188+
189+
if module_path != '' and lineno !='':
190+
message += f' in {module_path} ({lineno}):\n\n'
191+
else:
192+
message += ': '
193+
194+
message += r['error'] + '\n'
195+
196+
sys.stderr.write(message)
197+
198+
return r
199+
200+
############################################################
201+
def prepare_error(self, returncode, error):
202+
"""
203+
Prepare error dictionary with the module and line number of an error
204+
205+
Args:
206+
returncode (int): CMX returncode
207+
error (str): error message
208+
209+
Returns:
210+
(dict): r
211+
return (int)
212+
error (str)
213+
module_path (str): path to module
214+
lineno (int): line number
215+
216+
"""
217+
218+
from inspect import getframeinfo, stack
219+
220+
caller = getframeinfo(stack()[1][0])
221+
222+
return {'return': returncode,
223+
'error': error,
224+
'module_path': caller.filename,
225+
'lineno': caller.lineno}
226+
227+
############################################################
228+
def embed_error(self, r):
229+
"""
230+
Embed module and line number to an error
231+
232+
Args:
233+
r (dict): CM return dict
234+
235+
Returns:
236+
(dict): r
237+
return (int)
238+
error (str)
239+
module_path (str): path to module
240+
lineno (int): line number
241+
242+
"""
243+
244+
from inspect import getframeinfo, stack
245+
246+
caller = getframeinfo(stack()[1][0])
247+
248+
r['module_path'] = caller.filename
249+
r['lineno'] = caller.lineno
250+
251+
return r
252+
143253
############################################################
144254
def halt(self, r):
145255
"""
@@ -849,18 +959,6 @@ def x(self, i, out = None):
849959
meta = r)
850960

851961
if r['return'] >0:
852-
if r['return'] > 32:
853-
print ('')
854-
print ('CM Error Call Stack:')
855-
856-
call_stack = self.state['call_stack']
857-
858-
for cs in call_stack:
859-
print (f' {cs}')
860-
861-
self.log(f"x error call stack: {call_stack}", "debug")
862-
self.log(f"x error: {r}", "debug")
863-
864962
if use_raise:
865963
raise Exception(r['error'])
866964

@@ -1518,6 +1616,23 @@ def error(i):
15181616

15191617
return cm.error(i)
15201618

1619+
############################################################
1620+
def errorx(i):
1621+
"""
1622+
Automatically initialize CM and print error if needed
1623+
without the need to initialize and customize CM class.
1624+
Useful for Python automation scripts.
1625+
1626+
See CM.error function for more details.
1627+
"""
1628+
1629+
global cm
1630+
1631+
if cm is None:
1632+
cm=CM()
1633+
1634+
return cm.errorx(i)
1635+
15211636
############################################################
15221637
def halt(i):
15231638
"""

cm/cmind/utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,7 +1928,7 @@ def convert_dictionary(d, key, sub = True):
19281928
return dd
19291929

19301930
##############################################################################
1931-
def test_input(i, module):
1931+
def test_input(i):
19321932
"""
19331933
Test if input has keys and report them as error
19341934
"""
@@ -1939,9 +1939,10 @@ def test_input(i, module):
19391939
unknown_keys = i.keys()
19401940
unknown_keys_str = ', '.join(unknown_keys)
19411941

1942+
x = '' if len(unknown_keys) == 1 else 's'
1943+
19421944
r = {'return': 1,
1943-
'error': 'unknown input key(s) "{}" in module {}'.format(unknown_keys_str, module),
1944-
'module': module,
1945+
'error': f'unknown input key{x}: {unknown_keys_str}',
19451946
'unknown_keys': unknown_keys,
19461947
'unknown_keys_str': unknown_keys_str}
19471948

0 commit comments

Comments
 (0)