| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed exception handling widgets."""
2 # ========================================================================
3 __version__ = "$Revision: 1.17 $"
4 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>"
5 __license__ = "GPL (details at http://www.gnu.org)"
6
7 import logging, exceptions, traceback, re as regex, sys, os, shutil, datetime as pyDT, codecs
8
9
10 import wx
11
12
13 from Gnumed.business import gmSurgery
14 from Gnumed.pycommon import gmDispatcher, gmTools, gmCfg2, gmI18N, gmLog2, gmPG2
15 from Gnumed.wxpython import gmGuiHelpers
16
17
18 _log2 = logging.getLogger('gm.gui')
19 _log2.info(__version__)
20
21 _prev_excepthook = None
22 application_is_closing = False
23 #=========================================================================
27 #-------------------------------------------------------------------------
31 #-------------------------------------------------------------------------
35 #-------------------------------------------------------------------------
39 #-------------------------------------------------------------------------
43 #-------------------------------------------------------------------------
45
46 _log2.debug('unhandled exception caught:', exc_info = (t, v, tb))
47
48 # Strg-C ?
49 if t == KeyboardInterrupt:
50 print "<Ctrl-C>: Shutting down ..."
51 top_win = wx.GetApp().GetTopWindow()
52 wx.CallAfter(top_win.Close)
53 return
54
55 # careful: MSW does reference counting on Begin/End* :-(
56 try: wx.EndBusyCursor()
57 except: pass
58
59 # exception on shutdown ?
60 if application_is_closing:
61 # dead object error ?
62 if t == wx._core.PyDeadObjectError:
63 return
64 gmLog2.log_stack_trace()
65 return
66
67 # try to ignore those, they come about from async handling
68 # as Robin tells us
69 if t == wx._core.PyDeadObjectError:
70 _log2.warning('continuing and hoping for the best')
71 return
72
73 # failed import ?
74 if t == exceptions.ImportError:
75 _log2.error('module [%s] not installed', v)
76 gmGuiHelpers.gm_show_error (
77 aTitle = _('Missing GNUmed module'),
78 aMessage = _(
79 'GNUmed detected that parts of it are not\n'
80 'properly installed. The following message\n'
81 'names the missing part:\n'
82 '\n'
83 ' "%s"\n'
84 '\n'
85 'Please make sure to get the missing\n'
86 'parts installed. Otherwise some of the\n'
87 'functionality will not be accessible.'
88 ) % v
89 )
90 return
91
92 # other exceptions
93 _cfg = gmCfg2.gmCfgData()
94 if _cfg.get(option = 'debug') is False:
95 _log2.error('enabling debug mode')
96 _cfg.set_option(option = 'debug', value = True)
97 root_logger = logging.getLogger()
98 root_logger.setLevel(logging.DEBUG)
99 _log2.debug('unhandled exception caught:', exc_info = (t, v, tb))
100
101 # lost connection ?
102 try:
103 msg = gmPG2.extract_msg_from_pg_exception(exc = v)
104 except:
105 msg = u'cannot extract message from PostgreSQL exception'
106 print msg
107 print v
108
109 conn_loss_on_operational_error = (
110 (t == gmPG2.dbapi.OperationalError)
111 and
112 ('erver' in msg)
113 and
114 (('term' in msg) or ('abnorm' in msg) or ('end' in msg))
115 )
116 conn_loss_on_interface_error = (
117 (t == gmPG2.dbapi.InterfaceError)
118 and
119 ('onnect' in msg)
120 and
121 (('close' in msg) or ('end' in msg))
122 )
123 if (conn_loss_on_operational_error or conn_loss_on_interface_error):
124 _log2.error('lost connection')
125 gmLog2.log_stack_trace()
126 gmLog2.flush()
127 gmGuiHelpers.gm_show_error (
128 aTitle = _('Lost connection'),
129 aMessage = _(
130 'Since you were last working in GNUmed,\n'
131 'your database connection timed out.\n'
132 '\n'
133 'This GNUmed session is now expired.\n'
134 '\n'
135 'You will have to close this client and\n'
136 'restart a new GNUmed session.'
137 )
138 )
139 return
140
141 gmLog2.log_stack_trace()
142
143 name = os.path.basename(_logfile_name)
144 name, ext = os.path.splitext(name)
145 new_name = os.path.expanduser(os.path.join (
146 '~',
147 'gnumed',
148 'logs',
149 '%s_%s%s' % (name, pyDT.datetime.now().strftime('%Y-%m-%d_%H-%M-%S'), ext)
150 ))
151
152 dlg = cUnhandledExceptionDlg(parent = None, id = -1, exception = (t, v, tb), logfile = new_name)
153 dlg.ShowModal()
154 comment = dlg._TCTRL_comment.GetValue()
155 dlg.Destroy()
156 if (comment is not None) and (comment.strip() != u''):
157 _log2.error(u'user comment: %s', comment.strip())
158
159 _log2.warning('syncing log file for backup to [%s]', new_name)
160 gmLog2.flush()
161 shutil.copy2(_logfile_name, new_name)
162 # ------------------------------------------------------------------------
164
165 global _logfile_name
166 _logfile_name = gmLog2._logfile_name
167
168 global _local_account
169 _local_account = os.path.basename(os.path.expanduser('~'))
170
171 set_helpdesk(gmSurgery.gmCurrentPractice().helpdesk)
172 set_staff_name(_local_account)
173 set_is_public_database(False)
174 set_sender_email(None)
175 set_client_version('gmExceptionHandlingWidgets.py %s' % __version__)
176
177 gmDispatcher.connect(signal = 'application_closing', receiver = _on_application_closing)
178
179 global _prev_excepthook
180 _prev_excepthook = sys.excepthook
181 sys.excepthook = handle_uncaught_exception_wx
182
183 return True
184 # ------------------------------------------------------------------------
186 if _prev_excepthook is None:
187 sys.excepthook = sys.__excepthook__
188 return True
189 sys.excepthook = _prev_excepthook
190 return True
191 # ------------------------------------------------------------------------
193 global application_is_closing
194 # used to ignore a few exceptions, such as when the
195 # C++ object has been destroyed before the Python one
196 application_is_closing = True
197 # ========================================================================
199
200 if (comment is None) or (comment.strip() == u''):
201 comment = wx.GetTextFromUser (
202 message = _(
203 'Please enter a short note on what you\n'
204 'were about to do in GNUmed:'
205 ),
206 caption = _('Sending bug report'),
207 parent = parent
208 )
209 if comment.strip() == u'':
210 comment = u'<user did not comment on bug report>'
211
212 receivers = []
213 if helpdesk is not None:
214 receivers = regex.findall (
215 '[\S]+@[\S]+',
216 helpdesk.strip(),
217 flags = regex.UNICODE | regex.LOCALE
218 )
219 if len(receivers) == 0:
220 if _is_public_database:
221 receivers = [u'gnumed-bugs@gnu.org']
222
223 receiver_string = wx.GetTextFromUser (
224 message = _(
225 'Edit the list of email addresses to send the\n'
226 'bug report to (separate addresses by spaces).\n'
227 '\n'
228 'Note that <gnumed-bugs@gnu.org> refers to\n'
229 'the public (!) GNUmed bugs mailing list.'
230 ),
231 caption = _('Sending bug report'),
232 default_value = ','.join(receivers),
233 parent = parent
234 )
235 if receiver_string.strip() == u'':
236 return
237
238 receivers = regex.findall (
239 '[\S]+@[\S]+',
240 receiver_string,
241 flags = regex.UNICODE | regex.LOCALE
242 )
243
244 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
245 parent,
246 -1,
247 caption = _('Sending bug report'),
248 question = _(
249 'Your bug report will be sent to:\n'
250 '\n'
251 '%s\n'
252 '\n'
253 'Make sure you have reviewed the log file for potentially\n'
254 'sensitive information before sending out the bug report.\n'
255 '\n'
256 'Note that emailing the report may take a while depending\n'
257 'on the speed of your internet connection.\n'
258 ) % u'\n'.join(receivers),
259 button_defs = [
260 {'label': _('Send report'), 'tooltip': _('Yes, send the bug report.')},
261 {'label': _('Cancel'), 'tooltip': _('No, do not send the bug report.')}
262 ],
263 show_checkbox = True,
264 checkbox_msg = _('include log file in bug report')
265 )
266 dlg._CHBOX_dont_ask_again.SetValue(_is_public_database)
267 go_ahead = dlg.ShowModal()
268 if go_ahead == wx.ID_NO:
269 dlg.Destroy()
270 return
271
272 include_log = dlg._CHBOX_dont_ask_again.GetValue()
273 if not _is_public_database:
274 if include_log:
275 result = gmGuiHelpers.gm_show_question (
276 _(
277 'The database you are connected to is marked as\n'
278 '"in-production with controlled access".\n'
279 '\n'
280 'You indicated that you want to include the log\n'
281 'file in your bug report. While this is often\n'
282 'useful for debugging the log file might contain\n'
283 'bits of patient data which must not be sent out\n'
284 'without de-identification.\n'
285 '\n'
286 'Please confirm that you want to include the log !'
287 ),
288 _('Sending bug report')
289 )
290 include_log = (result is True)
291
292 if sender is None:
293 sender = _('<not supplied>')
294 else:
295 if sender.strip() == u'':
296 sender = _('<not supplied>')
297
298 msg = u"""\
299 Report sent via GNUmed's handler for unexpected exceptions.
300
301 user comment : %s
302
303 client version: %s
304
305 system account: %s
306 staff member : %s
307 sender email : %s
308
309 # enable Launchpad bug tracking
310 affects gnumed
311 tag automatic-report
312 importance medium
313
314 """ % (comment, _client_version, _local_account, _staff_name, sender)
315 if include_log:
316 _log2.error(comment)
317 _log2.warning('syncing log file for emailing')
318 gmLog2.flush()
319 attachments = [ [_logfile_name, 'text/plain', 'quoted-printable'] ]
320 else:
321 attachments = None
322
323 dlg.Destroy()
324
325 wx.BeginBusyCursor()
326 try:
327 gmTools.send_mail (
328 sender = '%s <%s>' % (_staff_name, gmTools.default_mail_sender),
329 receiver = receivers,
330 subject = u'<bug>: %s' % comment,
331 message = msg,
332 encoding = gmI18N.get_encoding(),
333 server = gmTools.default_mail_server,
334 auth = {'user': gmTools.default_mail_sender, 'password': u'gnumed-at-gmx-net'},
335 attachments = attachments
336 )
337 gmDispatcher.send(signal='statustext', msg = _('Bug report has been emailed.'))
338 except:
339 _log2.exception('cannot send bug report')
340 gmDispatcher.send(signal='statustext', msg = _('Bug report COULD NOT be emailed.'))
341 wx.EndBusyCursor()
342
343 # ========================================================================
344 from Gnumed.wxGladeWidgets import wxgUnhandledExceptionDlg
345
347
349
350 exception = kwargs['exception']
351 del kwargs['exception']
352 self.logfile = kwargs['logfile']
353 del kwargs['logfile']
354
355 wxgUnhandledExceptionDlg.wxgUnhandledExceptionDlg.__init__(self, *args, **kwargs)
356
357 if _sender_email is not None:
358 self._TCTRL_sender.SetValue(_sender_email)
359 self._TCTRL_helpdesk.SetValue(_helpdesk)
360 self._TCTRL_logfile.SetValue(self.logfile)
361 t, v, tb = exception
362 self._TCTRL_exc_type.SetValue(str(t))
363 self._TCTRL_exc_value.SetValue(str(v))
364 self._TCTRL_traceback.SetValue(''.join(traceback.format_tb(tb)))
365
366 self.Fit()
367 #------------------------------------------
378 #------------------------------------------
389
390 # comment = self._TCTRL_comment.GetValue()
391 # if (comment is None) or (comment.strip() == u''):
392 # comment = wx.GetTextFromUser (
393 # message = _(
394 # 'Please enter a short note on what you\n'
395 # 'were about to do in GNUmed:'
396 # ),
397 # caption = _('Sending bug report'),
398 # parent = self
399 # )
400 # if comment.strip() == u'':
401 # comment = u'<user did not comment on bug report>'
402 #
403 # receivers = regex.findall (
404 # '[\S]+@[\S]+',
405 # self._TCTRL_helpdesk.GetValue().strip(),
406 # flags = regex.UNICODE | regex.LOCALE
407 # )
408 # if len(receivers) == 0:
409 # if _is_public_database:
410 # receivers = [u'gnumed-bugs@gnu.org']
411 #
412 # receiver_string = wx.GetTextFromUser (
413 # message = _(
414 # 'Edit the list of email addresses to send the\n'
415 # 'bug report to (separate addresses by spaces).\n'
416 # '\n'
417 # 'Note that <gnumed-bugs@gnu.org> refers to\n'
418 # 'the public (!) GNUmed bugs mailing list.'
419 # ),
420 # caption = _('Sending bug report'),
421 # default_value = ','.join(receivers),
422 # parent = self
423 # )
424 # if receiver_string.strip() == u'':
425 # evt.Skip()
426 # return
427 #
428 # receivers = regex.findall (
429 # '[\S]+@[\S]+',
430 # receiver_string,
431 # flags = regex.UNICODE | regex.LOCALE
432 # )
433 #
434 # dlg = gmGuiHelpers.c2ButtonQuestionDlg (
435 # self,
436 # -1,
437 # caption = _('Sending bug report'),
438 # question = _(
439 # 'Your bug report will be sent to:\n'
440 # '\n'
441 # '%s\n'
442 # '\n'
443 # 'Make sure you have reviewed the log file for potentially\n'
444 # 'sensitive information before sending out the bug report.\n'
445 # '\n'
446 # 'Note that emailing the report may take a while depending\n'
447 # 'on the speed of your internet connection.\n'
448 # ) % u'\n'.join(receivers),
449 # button_defs = [
450 # {'label': _('Send report'), 'tooltip': _('Yes, send the bug report.')},
451 # {'label': _('Cancel'), 'tooltip': _('No, do not send the bug report.')}
452 # ],
453 # show_checkbox = True,
454 # checkbox_msg = _('include log file in bug report')
455 # )
456 # dlg._CHBOX_dont_ask_again.SetValue(_is_public_database)
457 # go_ahead = dlg.ShowModal()
458 # if go_ahead == wx.ID_NO:
459 # dlg.Destroy()
460 # evt.Skip()
461 # return
462 #
463 # include_log = dlg._CHBOX_dont_ask_again.GetValue()
464 # if not _is_public_database:
465 # if include_log:
466 # result = gmGuiHelpers.gm_show_question (
467 # _(
468 # 'The database you are connected to is marked as\n'
469 # '"in-production with controlled access".\n'
470 # '\n'
471 # 'You indicated that you want to include the log\n'
472 # 'file in your bug report. While this is often\n'
473 # 'useful for debugging the log file might contain\n'
474 # 'bits of patient data which must not be sent out\n'
475 # 'without de-identification.\n'
476 # '\n'
477 # 'Please confirm that you want to include the log !'
478 # ),
479 # _('Sending bug report')
480 # )
481 # include_log = (result is True)
482 #
483 # sender_email = gmTools.coalesce(self._TCTRL_sender.GetValue(), _('<not supplied>'))
484 # msg = u"""\
485 #Report sent via GNUmed's handler for unexpected exceptions.
486 #
487 #user comment : %s
488 #
489 #client version: %s
490 #
491 #system account: %s
492 #staff member : %s
493 #sender email : %s
494 #
495 # # enable Launchpad bug tracking
496 # affects gnumed
497 # tag automatic-report
498 # importance medium
499 #
500 #""" % (comment, _client_version, _local_account, _staff_name, sender_email)
501 # if include_log:
502 # _log2.error(comment)
503 # _log2.warning('syncing log file for emailing')
504 # gmLog2.flush()
505 # attachments = [ [_logfile_name, 'text/plain', 'quoted-printable'] ]
506 # else:
507 # attachments = None
508 #
509 # dlg.Destroy()
510 #
511 # wx.BeginBusyCursor()
512 # try:
513 # gmTools.send_mail (
514 # sender = '%s <%s>' % (_staff_name, gmTools.default_mail_sender),
515 # receiver = receivers,
516 # subject = u'<bug>: %s' % comment,
517 # message = msg,
518 # encoding = gmI18N.get_encoding(),
519 # server = gmTools.default_mail_server,
520 # auth = {'user': gmTools.default_mail_sender, 'password': u'gnumed-at-gmx-net'},
521 # attachments = attachments
522 # )
523 # gmDispatcher.send(signal='statustext', msg = _('Bug report has been emailed.'))
524 # except:
525 # _log2.exception('cannot send bug report')
526 # gmDispatcher.send(signal='statustext', msg = _('Bug report COULD NOT be emailed.'))
527 # wx.EndBusyCursor()
528 #
529 # evt.Skip()
530 #------------------------------------------
536 # ========================================================================
537
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Nov 29 04:05:41 2010 | http://epydoc.sourceforge.net |