1
2 __doc__ = """GNUmed general tools."""
3
4
5 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>"
6 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
7
8
9 import re as regex, sys, os, os.path, csv, tempfile, logging, hashlib
10 import platform
11 import subprocess
12 import decimal
13 import cPickle, zlib
14 import xml.sax.saxutils as xml_tools
15
16
17
18 if __name__ == '__main__':
19
20 logging.basicConfig(level = logging.DEBUG)
21 sys.path.insert(0, '../../')
22 from Gnumed.pycommon import gmI18N
23 gmI18N.activate_locale()
24 gmI18N.install_domain()
25
26 from Gnumed.pycommon import gmBorg
27
28
29 _log = logging.getLogger('gm.tools')
30
31
32 ( CAPS_NONE,
33 CAPS_FIRST,
34 CAPS_ALLCAPS,
35 CAPS_WORDS,
36 CAPS_NAMES,
37 CAPS_FIRST_ONLY
38 ) = range(6)
39
40
41 u_currency_pound = u'\u00A3'
42 u_currency_sign = u'\u00A4'
43 u_currency_yen = u'\u00A5'
44 u_right_double_angle_quote = u'\u00AB'
45 u_registered_trademark = u'\u00AE'
46 u_plus_minus = u'\u00B1'
47 u_left_double_angle_quote = u'\u00BB'
48 u_one_quarter = u'\u00BC'
49 u_one_half = u'\u00BD'
50 u_three_quarters = u'\u00BE'
51 u_multiply = u'\u00D7'
52 u_triangular_bullet = u'\u2023'
53 u_ellipsis = u'\u2026'
54 u_euro = u'\u20AC'
55 u_numero = u'\u2116'
56 u_down_left_arrow = u'\u21B5'
57 u_left_arrow = u'\u2190'
58 u_right_arrow = u'\u2192'
59 u_left_arrow_with_tail = u'\u21a2'
60 u_sum = u'\u2211'
61 u_almost_equal_to = u'\u2248'
62 u_corresponds_to = u'\u2258'
63 u_infinity = u'\u221E'
64 u_diameter = u'\u2300'
65 u_checkmark_crossed_out = u'\u237B'
66 u_box_horiz_single = u'\u2500'
67 u_box_horiz_4dashes = u'\u2508'
68 u_box_top_double = u'\u2550'
69 u_box_top_left_double_single = u'\u2552'
70 u_box_top_right_double_single = u'\u2555'
71 u_box_top_left_arc = u'\u256d'
72 u_box_bottom_right_arc = u'\u256f'
73 u_box_bottom_left_arc = u'\u2570'
74 u_box_horiz_light_heavy = u'\u257c'
75 u_box_horiz_heavy_light = u'\u257e'
76 u_skull_and_crossbones = u'\u2620'
77 u_frowning_face = u'\u2639'
78 u_smiling_face = u'\u263a'
79 u_black_heart = u'\u2665'
80 u_checkmark_thin = u'\u2713'
81 u_checkmark_thick = u'\u2714'
82 u_writing_hand = u'\u270d'
83 u_pencil_1 = u'\u270e'
84 u_pencil_2 = u'\u270f'
85 u_pencil_3 = u'\u2710'
86 u_latin_cross = u'\u271d'
87 u_kanji_yen = u'\u5186'
88 u_replacement_character = u'\ufffd'
89 u_link_symbol = u'\u1f517'
90
91
93
94 print ".========================================================"
95 print "| Unhandled exception caught !"
96 print "| Type :", t
97 print "| Value:", v
98 print "`========================================================"
99 _log.critical('unhandled exception caught', exc_info = (t,v,tb))
100 sys.__excepthook__(t,v,tb)
101
102
103
104 -def mkdir(directory=None):
105 try:
106 os.makedirs(directory)
107 except OSError, e:
108 if (e.errno == 17) and not os.path.isdir(directory):
109 raise
110 return True
111
112
114 """This class provides the following paths:
115
116 .home_dir
117 .local_base_dir
118 .working_dir
119 .user_config_dir
120 .system_config_dir
121 .system_app_data_dir
122 .tmp_dir (readonly)
123 """
124 - def __init__(self, app_name=None, wx=None):
125 """Setup pathes.
126
127 <app_name> will default to (name of the script - .py)
128 """
129 try:
130 self.already_inited
131 return
132 except AttributeError:
133 pass
134
135 self.init_paths(app_name=app_name, wx=wx)
136 self.already_inited = True
137
138
139
141
142 if wx is None:
143 _log.debug('wxPython not available')
144 _log.debug('detecting paths directly')
145
146 if app_name is None:
147 app_name, ext = os.path.splitext(os.path.basename(sys.argv[0]))
148 _log.info('app name detected as [%s]', app_name)
149 else:
150 _log.info('app name passed in as [%s]', app_name)
151
152
153 self.__home_dir = None
154
155
156 if getattr(sys, 'frozen', False):
157 _log.info('frozen app, installed into temporary path')
158
159
160
161
162
163
164
165
166
167 self.local_base_dir = os.path.dirname(sys.executable)
168 else:
169 self.local_base_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
170
171
172 self.working_dir = os.path.abspath(os.curdir)
173
174
175 mkdir(os.path.join(self.home_dir, '.%s' % app_name))
176 self.user_config_dir = os.path.join(self.home_dir, '.%s' % app_name)
177
178
179 try:
180 self.system_config_dir = os.path.join('/etc', app_name)
181 except ValueError:
182
183 self.system_config_dir = self.user_config_dir
184
185
186 try:
187 self.system_app_data_dir = os.path.join(sys.prefix, 'share', app_name)
188 except ValueError:
189 self.system_app_data_dir = self.local_base_dir
190
191
192 try:
193 self.__tmp_dir_already_set
194 _log.debug('temp dir already set')
195 except AttributeError:
196 tmp_base = os.path.join(tempfile.gettempdir(), app_name)
197 mkdir(tmp_base)
198 _log.info('previous temp dir: %s', tempfile.gettempdir())
199 tempfile.tempdir = tmp_base
200 _log.info('intermediate temp dir: %s', tempfile.gettempdir())
201 self.tmp_dir = tempfile.mkdtemp(prefix = r'gm-')
202
203 self.__log_paths()
204 if wx is None:
205 return True
206
207
208 _log.debug('re-detecting paths with wxPython')
209
210 std_paths = wx.StandardPaths.Get()
211 _log.info('wxPython app name is [%s]', wx.GetApp().GetAppName())
212
213
214 mkdir(os.path.join(std_paths.GetUserConfigDir(), '.%s' % app_name))
215 self.user_config_dir = os.path.join(std_paths.GetUserConfigDir(), '.%s' % app_name)
216
217
218 try:
219 tmp = std_paths.GetConfigDir()
220 if not tmp.endswith(app_name):
221 tmp = os.path.join(tmp, app_name)
222 self.system_config_dir = tmp
223 except ValueError:
224
225 pass
226
227
228
229
230 if 'wxMSW' in wx.PlatformInfo:
231 _log.warning('this platform (wxMSW) sometimes returns a broken value for the system-wide application data dir')
232 else:
233 try:
234 self.system_app_data_dir = std_paths.GetDataDir()
235 except ValueError:
236 pass
237
238 self.__log_paths()
239 return True
240
242 _log.debug('sys.argv[0]: %s', sys.argv[0])
243 _log.debug('sys.executable: %s', sys.executable)
244 _log.debug('sys._MEIPASS: %s', getattr(sys, '_MEIPASS', '<not found>'))
245 _log.debug('os.environ["_MEIPASS2"]: %s', os.environ.get('_MEIPASS2', '<not found>'))
246 _log.debug('__file__ : %s', __file__)
247 _log.debug('local application base dir: %s', self.local_base_dir)
248 _log.debug('current working dir: %s', self.working_dir)
249 _log.debug('user home dir: %s', self.home_dir)
250 _log.debug('user-specific config dir: %s', self.user_config_dir)
251 _log.debug('system-wide config dir: %s', self.system_config_dir)
252 _log.debug('system-wide application data dir: %s', self.system_app_data_dir)
253 _log.debug('temporary dir: %s', self.tmp_dir)
254
255
256
258 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
259 msg = '[%s:user_config_dir]: invalid path [%s]' % (self.__class__.__name__, path)
260 _log.error(msg)
261 raise ValueError(msg)
262 self.__user_config_dir = path
263
265 return self.__user_config_dir
266
267 user_config_dir = property(_get_user_config_dir, _set_user_config_dir)
268
270 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
271 msg = '[%s:system_config_dir]: invalid path [%s]' % (self.__class__.__name__, path)
272 _log.error(msg)
273 raise ValueError(msg)
274 self.__system_config_dir = path
275
277 return self.__system_config_dir
278
279 system_config_dir = property(_get_system_config_dir, _set_system_config_dir)
280
282 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
283 msg = '[%s:system_app_data_dir]: invalid path [%s]' % (self.__class__.__name__, path)
284 _log.error(msg)
285 raise ValueError(msg)
286 self.__system_app_data_dir = path
287
289 return self.__system_app_data_dir
290
291 system_app_data_dir = property(_get_system_app_data_dir, _set_system_app_data_dir)
292
294 raise ValueError('invalid to set home dir')
295
297 if self.__home_dir is not None:
298 return self.__home_dir
299
300 tmp = os.path.expanduser('~')
301 if tmp == '~':
302 _log.error('this platform does not expand ~ properly')
303 try:
304 tmp = os.environ['USERPROFILE']
305 except KeyError:
306 _log.error('cannot access $USERPROFILE in environment')
307
308 if not (
309 os.access(tmp, os.R_OK)
310 and
311 os.access(tmp, os.X_OK)
312 and
313 os.access(tmp, os.W_OK)
314 ):
315 msg = '[%s:home_dir]: invalid path [%s]' % (self.__class__.__name__, tmp)
316 _log.error(msg)
317 raise ValueError(msg)
318
319 self.__home_dir = tmp
320 return self.__home_dir
321
322 home_dir = property(_get_home_dir, _set_home_dir)
323
325 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
326 msg = '[%s:tmp_dir]: invalid path [%s]' % (self.__class__.__name__, path)
327 _log.error(msg)
328 raise ValueError(msg)
329 _log.debug('previous temp dir: %s', tempfile.gettempdir())
330 self.__tmp_dir = path
331 tempfile.tempdir = self.__tmp_dir
332 self.__tmp_dir_already_set = True
333
335 return self.__tmp_dir
336
337 tmp_dir = property(_get_tmp_dir, _set_tmp_dir)
338
339
340
342
343 if platform.system() == 'Windows':
344 exec_name = 'gpg.exe'
345 else:
346 exec_name = 'gpg'
347
348 tmp, fname = os.path.split(filename)
349 basename, tmp = os.path.splitext(fname)
350 filename_decrypted = get_unique_filename(prefix = '%s-decrypted-' % basename)
351
352 args = [exec_name, '--verbose', '--batch', '--yes', '--passphrase-fd', '0', '--output', filename_decrypted, '--decrypt', filename]
353 _log.debug('GnuPG args: %s' % str(args))
354
355 try:
356 gpg = subprocess.Popen (
357 args = args,
358 stdin = subprocess.PIPE,
359 stdout = subprocess.PIPE,
360 stderr = subprocess.PIPE,
361 close_fds = False
362 )
363 except (OSError, ValueError, subprocess.CalledProcessError):
364 _log.exception('there was a problem executing gpg')
365 gmDispatcher.send(signal = u'statustext', msg = _('Error running GnuPG. Cannot decrypt data.'), beep = True)
366 return
367
368 out, error = gpg.communicate(passphrase)
369 _log.debug('gpg returned [%s]', gpg.returncode)
370 if gpg.returncode != 0:
371 _log.debug('GnuPG STDOUT:\n%s', out)
372 _log.debug('GnuPG STDERR:\n%s', error)
373 return None
374
375 return filename_decrypted
376
377 -def file2md5(filename=None, return_hex=True):
378 blocksize = 2**10 * 128
379 _log.debug('md5(%s): <%s> byte blocks', filename, blocksize)
380
381 f = open(filename, 'rb')
382
383 md5 = hashlib.md5()
384 while True:
385 data = f.read(blocksize)
386 if not data:
387 break
388 md5.update(data)
389
390 _log.debug('md5(%s): %s', filename, md5.hexdigest())
391
392 if return_hex:
393 return md5.hexdigest()
394 return md5.digest()
395
397 for line in unicode_csv_data:
398 yield line.encode(encoding)
399
400
401
402
403
404 default_csv_reader_rest_key = u'list_of_values_of_unknown_fields'
405
407
408
409 try:
410 is_dict_reader = kwargs['dict']
411 del kwargs['dict']
412 if is_dict_reader is not True:
413 raise KeyError
414 kwargs['restkey'] = default_csv_reader_rest_key
415 csv_reader = csv.DictReader(unicode2charset_encoder(unicode_csv_data), dialect=dialect, **kwargs)
416 except KeyError:
417 is_dict_reader = False
418 csv_reader = csv.reader(unicode2charset_encoder(unicode_csv_data), dialect=dialect, **kwargs)
419
420 for row in csv_reader:
421
422 if is_dict_reader:
423 for key in row.keys():
424 if key == default_csv_reader_rest_key:
425 old_data = row[key]
426 new_data = []
427 for val in old_data:
428 new_data.append(unicode(val, encoding))
429 row[key] = new_data
430 if default_csv_reader_rest_key not in csv_reader.fieldnames:
431 csv_reader.fieldnames.append(default_csv_reader_rest_key)
432 else:
433 row[key] = unicode(row[key], encoding)
434 yield row
435 else:
436 yield [ unicode(cell, encoding) for cell in row ]
437
438
439
441 return os.path.splitext(os.path.basename(filename))[0]
442
443
445 """This introduces a race condition between the file.close() and
446 actually using the filename.
447
448 The file will NOT exist after calling this function.
449 """
450 if tmp_dir is not None:
451 if (
452 not os.access(tmp_dir, os.F_OK)
453 or
454 not os.access(tmp_dir, os.X_OK | os.W_OK)
455 ):
456 _log.warning('cannot find temporary dir [%s], using system default', tmp_dir)
457 tmp_dir = None
458
459 kwargs = {'dir': tmp_dir}
460
461 if prefix is None:
462 kwargs['prefix'] = 'gnumed-'
463 else:
464 kwargs['prefix'] = prefix
465
466 if suffix in [None, u'']:
467 kwargs['suffix'] = '.tmp'
468 else:
469 if not suffix.startswith('.'):
470 suffix = '.' + suffix
471 kwargs['suffix'] = suffix
472
473 f = tempfile.NamedTemporaryFile(**kwargs)
474 filename = f.name
475 f.close()
476
477 return filename
478
480 """Import a module from any location."""
481
482 remove_path = always_remove_path or False
483 if module_path not in sys.path:
484 _log.info('appending to sys.path: [%s]' % module_path)
485 sys.path.append(module_path)
486 remove_path = True
487
488 _log.debug('will remove import path: %s', remove_path)
489
490 if module_name.endswith('.py'):
491 module_name = module_name[:-3]
492
493 try:
494 module = __import__(module_name)
495 except StandardError:
496 _log.exception('cannot __import__() module [%s] from [%s]' % (module_name, module_path))
497 while module_path in sys.path:
498 sys.path.remove(module_path)
499 raise
500
501 _log.info('imported module [%s] as [%s]' % (module_name, module))
502 if remove_path:
503 while module_path in sys.path:
504 sys.path.remove(module_path)
505
506 return module
507
508
509
510 _kB = 1024
511 _MB = 1024 * _kB
512 _GB = 1024 * _MB
513 _TB = 1024 * _GB
514 _PB = 1024 * _TB
515
517 if size == 1:
518 return template % _('1 Byte')
519 if size < 10 * _kB:
520 return template % _('%s Bytes') % size
521 if size < _MB:
522 return template % u'%.1f kB' % (float(size) / _kB)
523 if size < _GB:
524 return template % u'%.1f MB' % (float(size) / _MB)
525 if size < _TB:
526 return template % u'%.1f GB' % (float(size) / _GB)
527 if size < _PB:
528 return template % u'%.1f TB' % (float(size) / _TB)
529 return template % u'%.1f PB' % (float(size) / _PB)
530
531 -def bool2subst(boolean=None, true_return=True, false_return=False, none_return=None):
532 if boolean is None:
533 return none_return
534 if boolean:
535 return true_return
536 if not boolean:
537 return false_return
538 raise ValueError('bool2subst(): <boolean> arg must be either of True, False, None')
539
540 -def bool2str(boolean=None, true_str='True', false_str='False'):
541 return bool2subst (
542 boolean = bool(boolean),
543 true_return = true_str,
544 false_return = false_str
545 )
546
547 -def none_if(value=None, none_equivalent=None, strip_string=False):
548 """Modelled after the SQL NULLIF function."""
549 if value is None:
550 return None
551 if strip_string:
552 stripped = value.strip()
553 else:
554 stripped = value
555 if stripped == none_equivalent:
556 return None
557 return value
558
559 -def coalesce(initial=None, instead=None, template_initial=None, template_instead=None, none_equivalents=None, function_initial=None):
560 """Modelled after the SQL coalesce function.
561
562 To be used to simplify constructs like:
563
564 if initial is None (or in none_equivalents):
565 real_value = (template_instead % instead) or instead
566 else:
567 real_value = (template_initial % initial) or initial
568 print real_value
569
570 @param initial: the value to be tested for <None>
571 @type initial: any Python type, must have a __str__ method if template_initial is not None
572 @param instead: the value to be returned if <initial> is None
573 @type instead: any Python type, must have a __str__ method if template_instead is not None
574 @param template_initial: if <initial> is returned replace the value into this template, must contain one <%s>
575 @type template_initial: string or None
576 @param template_instead: if <instead> is returned replace the value into this template, must contain one <%s>
577 @type template_instead: string or None
578
579 example:
580 function_initial = ('strftime', '%Y-%m-%d')
581
582 Ideas:
583 - list of insteads: initial, [instead, template], [instead, template], [instead, template], template_initial, ...
584 """
585 if none_equivalents is None:
586 none_equivalents = [None]
587
588 if initial in none_equivalents:
589
590 if template_instead is None:
591 return instead
592
593 return template_instead % instead
594
595 if function_initial is not None:
596 funcname, args = function_initial
597 func = getattr(initial, funcname)
598 initial = func(args)
599
600 if template_initial is None:
601 return initial
602
603 try:
604 return template_initial % initial
605 except TypeError:
606 return template_initial
607
609 val = match_obj.group(0).lower()
610 if val in ['von', 'van', 'de', 'la', 'l', 'der', 'den']:
611 return val
612 buf = list(val)
613 buf[0] = buf[0].upper()
614 for part in ['mac', 'mc', 'de', 'la']:
615 if len(val) > len(part) and val[:len(part)] == part:
616 buf[len(part)] = buf[len(part)].upper()
617 return ''.join(buf)
618
620 """Capitalize the first character but leave the rest alone.
621
622 Note that we must be careful about the locale, this may
623 have issues ! However, for UTF strings it should just work.
624 """
625 if (mode is None) or (mode == CAPS_NONE):
626 return text
627
628 if len(text) == 0:
629 return text
630
631 if mode == CAPS_FIRST:
632 if len(text) == 1:
633 return text[0].upper()
634 return text[0].upper() + text[1:]
635
636 if mode == CAPS_ALLCAPS:
637 return text.upper()
638
639 if mode == CAPS_FIRST_ONLY:
640 if len(text) == 1:
641 return text[0].upper()
642 return text[0].upper() + text[1:].lower()
643
644 if mode == CAPS_WORDS:
645 return regex.sub(ur'(\w)(\w+)', lambda x: x.group(1).upper() + x.group(2).lower(), text)
646
647 if mode == CAPS_NAMES:
648
649 return capitalize(text=text, mode=CAPS_FIRST)
650
651 print "ERROR: invalid capitalization mode: [%s], leaving input as is" % mode
652 return text
653
675
701
703 if lines is None:
704 lines = text.split(eol)
705
706 while True:
707 if lines[0].strip(eol).strip() != u'':
708 break
709 lines = lines[1:]
710
711 if return_list:
712 return lines
713
714 return eol.join(lines)
715
717 if lines is None:
718 lines = text.split(eol)
719
720 while True:
721 if lines[-1].strip(eol).strip() != u'':
722 break
723 lines = lines[:-1]
724
725 if return_list:
726 return lines
727
728 return eol.join(lines)
729
730 -def wrap(text=None, width=None, initial_indent=u'', subsequent_indent=u'', eol=u'\n'):
731 """A word-wrap function that preserves existing line breaks
732 and most spaces in the text. Expects that existing line
733 breaks are posix newlines (\n).
734 """
735 if width is None:
736 return text
737 wrapped = initial_indent + reduce (
738 lambda line, word, width=width: '%s%s%s' % (
739 line,
740 ' \n'[(len(line) - line.rfind('\n') - 1 + len(word.split('\n',1)[0]) >= width)],
741 word
742 ),
743 text.split(' ')
744 )
745
746 if subsequent_indent != u'':
747 wrapped = (u'\n%s' % subsequent_indent).join(wrapped.split('\n'))
748
749 if eol != u'\n':
750 wrapped = wrapped.replace('\n', eol)
751
752 return wrapped
753
754 -def unwrap(text=None, max_length=None, strip_whitespace=True, remove_empty_lines=True, line_separator = u' // '):
755
756 text = text.replace(u'\r', u'')
757 lines = text.split(u'\n')
758 text = u''
759 for line in lines:
760
761 if strip_whitespace:
762 line = line.strip().strip(u'\t').strip()
763
764 if remove_empty_lines:
765 if line == u'':
766 continue
767
768 text += (u'%s%s' % (line, line_separator))
769
770 text = text.rstrip(line_separator)
771
772 if max_length is not None:
773 text = text[:max_length]
774
775 text = text.rstrip(line_separator)
776
777 return text
778
780 """check for special XML characters and transform them"""
781 return xml_tools.escape(text)
782
784 """check for special TeX characters and transform them"""
785
786 text = text.replace(u'\\', u'\\textbackslash')
787 text = text.replace(u'^', u'\\textasciicircum')
788 text = text.replace('~','\\textasciitilde')
789
790 text = text.replace(u'{', u'\\{')
791 text = text.replace(u'}', u'\\}')
792 text = text.replace(u'%', u'\\%')
793 text = text.replace(u'&', u'\\&')
794 text = text.replace(u'#', u'\\#')
795 text = text.replace(u'$', u'\\$')
796 text = text.replace(u'_', u'\\_')
797
798 if replace_known_unicode:
799
800 text = text.replace(u_euro, u'\\EUR')
801
802 return text
803
808
835
836
837
838
839
840 __icon_serpent = \
841 """x\xdae\x8f\xb1\x0e\x83 \x10\x86w\x9f\xe2\x92\x1blb\xf2\x07\x96\xeaH:0\xd6\
842 \xc1\x85\xd5\x98N5\xa5\xef?\xf5N\xd0\x8a\xdcA\xc2\xf7qw\x84\xdb\xfa\xb5\xcd\
843 \xd4\xda;\xc9\x1a\xc8\xb6\xcd<\xb5\xa0\x85\x1e\xeb\xbc\xbc7b!\xf6\xdeHl\x1c\
844 \x94\x073\xec<*\xf7\xbe\xf7\x99\x9d\xb21~\xe7.\xf5\x1f\x1c\xd3\xbdVlL\xc2\
845 \xcf\xf8ye\xd0\x00\x90\x0etH \x84\x80B\xaa\x8a\x88\x85\xc4(U\x9d$\xfeR;\xc5J\
846 \xa6\x01\xbbt9\xceR\xc8\x81e_$\x98\xb9\x9c\xa9\x8d,y\xa9t\xc8\xcf\x152\xe0x\
847 \xe9$\xf5\x07\x95\x0cD\x95t:\xb1\x92\xae\x9cI\xa8~\x84\x1f\xe0\xa3ec"""
848
850
851 paths = gmPaths(app_name = u'gnumed', wx = wx)
852
853 candidates = [
854 os.path.join(paths.system_app_data_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
855 os.path.join(paths.local_base_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
856 os.path.join(paths.system_app_data_dir, 'bitmaps', 'serpent.png'),
857 os.path.join(paths.local_base_dir, 'bitmaps', 'serpent.png')
858 ]
859
860 found_as = None
861 for candidate in candidates:
862 try:
863 open(candidate, 'r').close()
864 found_as = candidate
865 break
866 except IOError:
867 _log.debug('icon not found in [%s]', candidate)
868
869 if found_as is None:
870 _log.warning('no icon file found, falling back to builtin (ugly) icon')
871 icon_bmp_data = wx.BitmapFromXPMData(cPickle.loads(zlib.decompress(__icon_serpent)))
872 icon.CopyFromBitmap(icon_bmp_data)
873 else:
874 _log.debug('icon found in [%s]', found_as)
875 icon = wx.EmptyIcon()
876 try:
877 icon.LoadFile(found_as, wx.BITMAP_TYPE_ANY)
878 except AttributeError:
879 _log.exception(u"this platform doesn't support wx.Icon().LoadFile()")
880
881 return icon
882
883
884
885 if __name__ == '__main__':
886
887 if len(sys.argv) < 2:
888 sys.exit()
889
890 if sys.argv[1] != 'test':
891 sys.exit()
892
893
951
956
958
959 import datetime as dt
960 print coalesce(initial = dt.datetime.now(), template_initial = u'-- %s --', function_initial = ('strftime', u'%Y-%m-%d'))
961
962 print 'testing coalesce()'
963 print "------------------"
964 tests = [
965 [None, 'something other than <None>', None, None, 'something other than <None>'],
966 ['Captain', 'Mr.', '%s.'[:4], 'Mr.', 'Capt.'],
967 ['value to test', 'test 3 failed', 'template with "%s" included', None, 'template with "value to test" included'],
968 ['value to test', 'test 4 failed', 'template with value not included', None, 'template with value not included'],
969 [None, 'initial value was None', 'template_initial: %s', None, 'initial value was None'],
970 [None, 'initial value was None', 'template_initial: %%(abc)s', None, 'initial value was None']
971 ]
972 passed = True
973 for test in tests:
974 result = coalesce (
975 initial = test[0],
976 instead = test[1],
977 template_initial = test[2],
978 template_instead = test[3]
979 )
980 if result != test[4]:
981 print "ERROR"
982 print "coalesce: (%s, %s, %s, %s)" % (test[0], test[1], test[2], test[3])
983 print "expected:", test[4]
984 print "received:", result
985 passed = False
986
987 if passed:
988 print "passed"
989 else:
990 print "failed"
991 return passed
992
994 print 'testing capitalize() ...'
995 success = True
996 pairs = [
997
998 [u'Boot', u'Boot', CAPS_FIRST_ONLY],
999 [u'boot', u'Boot', CAPS_FIRST_ONLY],
1000 [u'booT', u'Boot', CAPS_FIRST_ONLY],
1001 [u'BoOt', u'Boot', CAPS_FIRST_ONLY],
1002 [u'boots-Schau', u'Boots-Schau', CAPS_WORDS],
1003 [u'boots-sChau', u'Boots-Schau', CAPS_WORDS],
1004 [u'boot camp', u'Boot Camp', CAPS_WORDS],
1005 [u'fahrner-Kampe', u'Fahrner-Kampe', CAPS_NAMES],
1006 [u'häkkönen', u'Häkkönen', CAPS_NAMES],
1007 [u'McBurney', u'McBurney', CAPS_NAMES],
1008 [u'mcBurney', u'McBurney', CAPS_NAMES],
1009 [u'blumberg', u'Blumberg', CAPS_NAMES],
1010 [u'roVsing', u'RoVsing', CAPS_NAMES],
1011 [u'Özdemir', u'Özdemir', CAPS_NAMES],
1012 [u'özdemir', u'Özdemir', CAPS_NAMES],
1013 ]
1014 for pair in pairs:
1015 result = capitalize(pair[0], pair[2])
1016 if result != pair[1]:
1017 success = False
1018 print 'ERROR (caps mode %s): "%s" -> "%s", expected "%s"' % (pair[2], pair[0], result, pair[1])
1019
1020 if success:
1021 print "... SUCCESS"
1022
1023 return success
1024
1026 print "testing import_module_from_directory()"
1027 path = sys.argv[1]
1028 name = sys.argv[2]
1029 try:
1030 mod = import_module_from_directory(module_path = path, module_name = name)
1031 except:
1032 print "module import failed, see log"
1033 return False
1034
1035 print "module import succeeded", mod
1036 print dir(mod)
1037 return True
1038
1040 print "testing mkdir()"
1041 mkdir(sys.argv[1])
1042
1044 print "testing gmPaths()"
1045 print "-----------------"
1046 paths = gmPaths(wx=None, app_name='gnumed')
1047 print "user config dir:", paths.user_config_dir
1048 print "system config dir:", paths.system_config_dir
1049 print "local base dir:", paths.local_base_dir
1050 print "system app data dir:", paths.system_app_data_dir
1051 print "working directory :", paths.working_dir
1052 print "temp directory :", paths.tmp_dir
1053
1055 print "testing none_if()"
1056 print "-----------------"
1057 tests = [
1058 [None, None, None],
1059 ['a', 'a', None],
1060 ['a', 'b', 'a'],
1061 ['a', None, 'a'],
1062 [None, 'a', None],
1063 [1, 1, None],
1064 [1, 2, 1],
1065 [1, None, 1],
1066 [None, 1, None]
1067 ]
1068
1069 for test in tests:
1070 if none_if(value = test[0], none_equivalent = test[1]) != test[2]:
1071 print 'ERROR: none_if(%s) returned [%s], expected [%s]' % (test[0], none_if(test[0], test[1]), test[2])
1072
1073 return True
1074
1076 tests = [
1077 [True, 'Yes', 'Yes', 'Yes'],
1078 [False, 'OK', 'not OK', 'not OK']
1079 ]
1080 for test in tests:
1081 if bool2str(test[0], test[1], test[2]) != test[3]:
1082 print 'ERROR: bool2str(%s, %s, %s) returned [%s], expected [%s]' % (test[0], test[1], test[2], bool2str(test[0], test[1], test[2]), test[3])
1083
1084 return True
1085
1087
1088 print bool2subst(True, 'True', 'False', 'is None')
1089 print bool2subst(False, 'True', 'False', 'is None')
1090 print bool2subst(None, 'True', 'False', 'is None')
1091
1098
1100 print "testing size2str()"
1101 print "------------------"
1102 tests = [0, 1, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000]
1103 for test in tests:
1104 print size2str(test)
1105
1107
1108 test = """
1109 second line\n
1110 3rd starts with tab \n
1111 4th with a space \n
1112
1113 6th
1114
1115 """
1116 print unwrap(text = test, max_length = 25)
1117
1119 test = 'line 1\nline 2\nline 3'
1120
1121 print "wrap 5-6-7 initial 0, subsequent 0"
1122 print wrap(test, 5)
1123 print
1124 print wrap(test, 6)
1125 print
1126 print wrap(test, 7)
1127 print "-------"
1128 raw_input()
1129 print "wrap 5 initial 1-1-3, subsequent 1-3-1"
1130 print wrap(test, 5, u' ', u' ')
1131 print
1132 print wrap(test, 5, u' ', u' ')
1133 print
1134 print wrap(test, 5, u' ', u' ')
1135 print "-------"
1136 raw_input()
1137 print "wrap 6 initial 1-1-3, subsequent 1-3-1"
1138 print wrap(test, 6, u' ', u' ')
1139 print
1140 print wrap(test, 6, u' ', u' ')
1141 print
1142 print wrap(test, 6, u' ', u' ')
1143 print "-------"
1144 raw_input()
1145 print "wrap 7 initial 1-1-3, subsequent 1-3-1"
1146 print wrap(test, 7, u' ', u' ')
1147 print
1148 print wrap(test, 7, u' ', u' ')
1149 print
1150 print wrap(test, 7, u' ', u' ')
1151
1153 print '%s: %s' % (sys.argv[2], file2md5(sys.argv[2]))
1154
1157
1162
1164 fname = gpg_decrypt_file(filename = sys.argv[2], passphrase = sys.argv[3])
1165 if fname is not None:
1166 print "successfully decrypted:", fname
1167
1169 tests = [
1170 u'one line, no embedded line breaks ',
1171 u'one line\nwith embedded\nline\nbreaks\n '
1172 ]
1173 for test in tests:
1174 print 'as list:'
1175 print strip_trailing_empty_lines(text = test, eol=u'\n', return_list = True)
1176 print 'as string:'
1177 print u'>>>%s<<<' % strip_trailing_empty_lines(text = test, eol=u'\n', return_list = False)
1178 tests = [
1179 ['list', 'without', 'empty', 'trailing', 'lines'],
1180 ['list', 'with', 'empty', 'trailing', 'lines', '', ' ', '']
1181 ]
1182 for test in tests:
1183 print 'as list:'
1184 print strip_trailing_empty_lines(lines = test, eol = u'\n', return_list = True)
1185 print 'as string:'
1186 print strip_trailing_empty_lines(lines = test, eol = u'\n', return_list = False)
1187
1189 tests = [
1190 r'abc.exe',
1191 r'\abc.exe',
1192 r'c:\abc.exe',
1193 r'c:\d\abc.exe',
1194 r'/home/ncq/tmp.txt',
1195 r'~/tmp.txt',
1196 r'./tmp.txt',
1197 r'./.././tmp.txt',
1198 r'tmp.txt'
1199 ]
1200 for t in tests:
1201 print "[%s] -> [%s]" % (t, fname_stem(t))
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222 test_fname_stem()
1223
1224
1225