1
2 __doc__ = """GNUmed general tools."""
3
4
5 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>"
6 __license__ = "GPL (details at http://www.gnu.org)"
7
8
9 import re as regex, sys, os, os.path, csv, tempfile, logging, hashlib
10 import decimal
11 import cPickle, zlib
12
13
14
15 if __name__ == '__main__':
16
17 logging.basicConfig(level = logging.DEBUG)
18 sys.path.insert(0, '../../')
19 from Gnumed.pycommon import gmI18N
20 gmI18N.activate_locale()
21 gmI18N.install_domain()
22
23 from Gnumed.pycommon import gmBorg
24
25
26 _log = logging.getLogger('gm.tools')
27
28
29 ( CAPS_NONE,
30 CAPS_FIRST,
31 CAPS_ALLCAPS,
32 CAPS_WORDS,
33 CAPS_NAMES,
34 CAPS_FIRST_ONLY
35 ) = range(6)
36
37
38 u_right_double_angle_quote = u'\u00AB'
39 u_registered_trademark = u'\u00AE'
40 u_plus_minus = u'\u00B1'
41 u_left_double_angle_quote = u'\u00BB'
42 u_one_quarter = u'\u00BC'
43 u_one_half = u'\u00BD'
44 u_three_quarters = u'\u00BE'
45 u_ellipsis = u'\u2026'
46 u_left_arrow = u'\u2190'
47 u_right_arrow = u'\u2192'
48 u_sum = u'\u2211'
49 u_corresponds_to = u'\u2258'
50 u_infinity = u'\u221E'
51 u_diameter = u'\u2300'
52 u_checkmark_crossed_out = u'\u237B'
53 u_box_horiz_single = u'\u2500'
54 u_box_horiz_4dashes = u'\u2508'
55 u_box_top_double = u'\u2550'
56 u_box_top_left_double_single = u'\u2552'
57 u_box_top_right_double_single = u'\u2555'
58 u_box_top_left_arc = u'\u256d'
59 u_box_bottom_right_arc = u'\u256f'
60 u_box_bottom_left_arc = u'\u2570'
61 u_box_horiz_light_heavy = u'\u257c'
62 u_box_horiz_heavy_light = u'\u257e'
63 u_frowning_face = u'\u2639'
64 u_smiling_face = u'\u263a'
65 u_black_heart = u'\u2665'
66 u_checkmark_thin = u'\u2713'
67 u_checkmark_thick = u'\u2714'
68 u_writing_hand = u'\u270d'
69 u_pencil_1 = u'\u270e'
70 u_pencil_2 = u'\u270f'
71 u_pencil_3 = u'\u2710'
72 u_latin_cross = u'\u271d'
73 u_replacement_character = u'\ufffd'
74
75
76
78
79 print ".========================================================"
80 print "| Unhandled exception caught !"
81 print "| Type :", t
82 print "| Value:", v
83 print "`========================================================"
84 _log.critical('unhandled exception caught', exc_info = (t,v,tb))
85 sys.__excepthook__(t,v,tb)
86
87
88
89 -def mkdir(directory=None):
90 try:
91 os.makedirs(directory)
92 except OSError, e:
93 if (e.errno == 17) and not os.path.isdir(directory):
94 raise
95 return True
96
97
99 """This class provides the following paths:
100
101 .home_dir
102 .local_base_dir
103 .working_dir
104 .user_config_dir
105 .system_config_dir
106 .system_app_data_dir
107 .tmp_dir (only readable)
108 """
109 - def __init__(self, app_name=None, wx=None):
110 """Setup pathes.
111
112 <app_name> will default to (name of the script - .py)
113 """
114 try:
115 self.already_inited
116 return
117 except AttributeError:
118 pass
119
120 self.init_paths(app_name=app_name, wx=wx)
121 self.already_inited = True
122
123
124
126
127 if wx is None:
128 _log.debug('wxPython not available')
129 _log.debug('detecting paths directly')
130
131 if app_name is None:
132 app_name, ext = os.path.splitext(os.path.basename(sys.argv[0]))
133 _log.info('app name detected as [%s]', app_name)
134 else:
135 _log.info('app name passed in as [%s]', app_name)
136
137
138 self.__home_dir = None
139
140
141
142 self.local_base_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
143
144
145 self.working_dir = os.path.abspath(os.curdir)
146
147
148
149
150 mkdir(os.path.join(self.home_dir, '.%s' % app_name))
151 self.user_config_dir = os.path.join(self.home_dir, '.%s' % app_name)
152
153
154 try:
155 self.system_config_dir = os.path.join('/etc', app_name)
156 except ValueError:
157
158 self.system_config_dir = self.user_config_dir
159
160
161 try:
162 self.system_app_data_dir = os.path.join(sys.prefix, 'share', app_name)
163 except ValueError:
164 self.system_app_data_dir = self.local_base_dir
165
166
167 try:
168 self.__tmp_dir_already_set
169 _log.debug('temp dir already set')
170 except AttributeError:
171 tmp_base = os.path.join(tempfile.gettempdir(), app_name)
172 mkdir(tmp_base)
173 _log.info('previous temp dir: %s', tempfile.gettempdir())
174 tempfile.tempdir = tmp_base
175 _log.info('intermediate temp dir: %s', tempfile.gettempdir())
176 self.tmp_dir = tempfile.mkdtemp(prefix = r'gm-')
177
178 self.__log_paths()
179 if wx is None:
180 return True
181
182
183 _log.debug('re-detecting paths with wxPython')
184
185 std_paths = wx.StandardPaths.Get()
186 _log.info('wxPython app name is [%s]', wx.GetApp().GetAppName())
187
188
189 mkdir(os.path.join(std_paths.GetUserConfigDir(), '.%s' % app_name))
190 self.user_config_dir = os.path.join(std_paths.GetUserConfigDir(), '.%s' % app_name)
191
192
193 try:
194 tmp = std_paths.GetConfigDir()
195 if not tmp.endswith(app_name):
196 tmp = os.path.join(tmp, app_name)
197 self.system_config_dir = tmp
198 except ValueError:
199
200 pass
201
202
203
204
205 if 'wxMSW' in wx.PlatformInfo:
206 _log.warning('this platform (wxMSW) sometimes returns a broken value for the system-wide application data dir')
207 else:
208 try:
209 self.system_app_data_dir = std_paths.GetDataDir()
210 except ValueError:
211 pass
212
213 self.__log_paths()
214 return True
215
217 _log.debug('sys.argv[0]: %s', sys.argv[0])
218 _log.debug('local application base dir: %s', self.local_base_dir)
219 _log.debug('current working dir: %s', self.working_dir)
220
221 _log.debug('user home dir: %s', self.home_dir)
222 _log.debug('user-specific config dir: %s', self.user_config_dir)
223 _log.debug('system-wide config dir: %s', self.system_config_dir)
224 _log.debug('system-wide application data dir: %s', self.system_app_data_dir)
225 _log.debug('temporary dir: %s', self.tmp_dir)
226
227
228
230 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
231 msg = '[%s:user_config_dir]: invalid path [%s]' % (self.__class__.__name__, path)
232 _log.error(msg)
233 raise ValueError(msg)
234 self.__user_config_dir = path
235
237 return self.__user_config_dir
238
239 user_config_dir = property(_get_user_config_dir, _set_user_config_dir)
240
242 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
243 msg = '[%s:system_config_dir]: invalid path [%s]' % (self.__class__.__name__, path)
244 _log.error(msg)
245 raise ValueError(msg)
246 self.__system_config_dir = path
247
249 return self.__system_config_dir
250
251 system_config_dir = property(_get_system_config_dir, _set_system_config_dir)
252
254 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
255 msg = '[%s:system_app_data_dir]: invalid path [%s]' % (self.__class__.__name__, path)
256 _log.error(msg)
257 raise ValueError(msg)
258 self.__system_app_data_dir = path
259
261 return self.__system_app_data_dir
262
263 system_app_data_dir = property(_get_system_app_data_dir, _set_system_app_data_dir)
264
266 raise ValueError('invalid to set home dir')
267
269 if self.__home_dir is not None:
270 return self.__home_dir
271
272 tmp = os.path.expanduser('~')
273 if tmp == '~':
274 _log.error('this platform does not expand ~ properly')
275 try:
276 tmp = os.environ['USERPROFILE']
277 except KeyError:
278 _log.error('cannot access $USERPROFILE in environment')
279
280 if not (
281 os.access(tmp, os.R_OK)
282 and
283 os.access(tmp, os.X_OK)
284 and
285 os.access(tmp, os.W_OK)
286 ):
287 msg = '[%s:home_dir]: invalid path [%s]' % (self.__class__.__name__, tmp)
288 _log.error(msg)
289 raise ValueError(msg)
290
291 self.__home_dir = tmp
292 return self.__home_dir
293
294 home_dir = property(_get_home_dir, _set_home_dir)
295
297 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
298 msg = '[%s:tmp_dir]: invalid path [%s]' % (self.__class__.__name__, path)
299 _log.error(msg)
300 raise ValueError(msg)
301 _log.debug('previous temp dir: %s', tempfile.gettempdir())
302 self.__tmp_dir = path
303 tempfile.tempdir = self.__tmp_dir
304 self.__tmp_dir_already_set = True
305
307 return self.__tmp_dir
308
309 tmp_dir = property(_get_tmp_dir, _set_tmp_dir)
310
311
312
313 -def file2md5(filename=None, return_hex=True):
314 blocksize = 2**10 * 128
315 _log.debug('md5(%s): <%s> byte blocks', filename, blocksize)
316
317 f = open(filename, 'rb')
318
319 md5 = hashlib.md5()
320 while True:
321 data = f.read(blocksize)
322 if not data:
323 break
324 md5.update(data)
325
326 _log.debug('md5(%s): %s', filename, md5.hexdigest())
327
328 if return_hex:
329 return md5.hexdigest()
330 return md5.digest()
331
333 for line in unicode_csv_data:
334 yield line.encode(encoding)
335
336
337
338
339
340 default_csv_reader_rest_key = u'list_of_values_of_unknown_fields'
341
343
344
345 try:
346 is_dict_reader = kwargs['dict']
347 del kwargs['dict']
348 if is_dict_reader is not True:
349 raise KeyError
350 kwargs['restkey'] = default_csv_reader_rest_key
351 csv_reader = csv.DictReader(unicode2charset_encoder(unicode_csv_data), dialect=dialect, **kwargs)
352 except KeyError:
353 is_dict_reader = False
354 csv_reader = csv.reader(unicode2charset_encoder(unicode_csv_data), dialect=dialect, **kwargs)
355
356 for row in csv_reader:
357
358 if is_dict_reader:
359 for key in row.keys():
360 if key == default_csv_reader_rest_key:
361 old_data = row[key]
362 new_data = []
363 for val in old_data:
364 new_data.append(unicode(val, encoding))
365 row[key] = new_data
366 if default_csv_reader_rest_key not in csv_reader.fieldnames:
367 csv_reader.fieldnames.append(default_csv_reader_rest_key)
368 else:
369 row[key] = unicode(row[key], encoding)
370 yield row
371 else:
372 yield [ unicode(cell, encoding) for cell in row ]
373
374
376 """This introduces a race condition between the file.close() and
377 actually using the filename.
378
379 The file will not exist after calling this function.
380 """
381 if tmp_dir is not None:
382 if (
383 not os.access(tmp_dir, os.F_OK)
384 or
385 not os.access(tmp_dir, os.X_OK | os.W_OK)
386 ):
387 _log.info('cannot find temporary dir [%s], using system default', tmp_dir)
388 tmp_dir = None
389
390 kwargs = {'dir': tmp_dir}
391
392 if prefix is None:
393 kwargs['prefix'] = 'gnumed-'
394 else:
395 kwargs['prefix'] = prefix
396
397 if suffix in [None, u'']:
398 kwargs['suffix'] = '.tmp'
399 else:
400 if not suffix.startswith('.'):
401 suffix = '.' + suffix
402 kwargs['suffix'] = suffix
403
404 f = tempfile.NamedTemporaryFile(**kwargs)
405 filename = f.name
406 f.close()
407
408 return filename
409
411 """Import a module from any location."""
412
413 remove_path = always_remove_path or False
414 if module_path not in sys.path:
415 _log.info('appending to sys.path: [%s]' % module_path)
416 sys.path.append(module_path)
417 remove_path = True
418
419 _log.debug('will remove import path: %s', remove_path)
420
421 if module_name.endswith('.py'):
422 module_name = module_name[:-3]
423
424 try:
425 module = __import__(module_name)
426 except StandardError:
427 _log.exception('cannot __import__() module [%s] from [%s]' % (module_name, module_path))
428 while module_path in sys.path:
429 sys.path.remove(module_path)
430 raise
431
432 _log.info('imported module [%s] as [%s]' % (module_name, module))
433 if remove_path:
434 while module_path in sys.path:
435 sys.path.remove(module_path)
436
437 return module
438
439
440
441 _kB = 1024
442 _MB = 1024 * _kB
443 _GB = 1024 * _MB
444 _TB = 1024 * _GB
445 _PB = 1024 * _TB
446
448 if size == 1:
449 return template % _('1 Byte')
450 if size < 10 * _kB:
451 return template % _('%s Bytes') % size
452 if size < _MB:
453 return template % u'%.1f kB' % (float(size) / _kB)
454 if size < _GB:
455 return template % u'%.1f MB' % (float(size) / _MB)
456 if size < _TB:
457 return template % u'%.1f GB' % (float(size) / _GB)
458 if size < _PB:
459 return template % u'%.1f TB' % (float(size) / _TB)
460 return template % u'%.1f PB' % (float(size) / _PB)
461
462 -def bool2subst(boolean=None, true_return=True, false_return=False, none_return=None):
463 if boolean is None:
464 return none_return
465 if boolean is True:
466 return true_return
467 if boolean is False:
468 return false_return
469 raise ValueError('bool2subst(): <boolean> arg must be either of True, False, None')
470
471 -def bool2str(boolean=None, true_str='True', false_str='False'):
472 return bool2subst (
473 boolean = bool(boolean),
474 true_return = true_str,
475 false_return = false_str
476 )
477
478 -def none_if(value=None, none_equivalent=None):
479 """Modelled after the SQL NULLIF function."""
480 if value == none_equivalent:
481 return None
482 return value
483
484 -def coalesce(initial=None, instead=None, template_initial=None, template_instead=None, none_equivalents=None, function_initial=None):
485 """Modelled after the SQL coalesce function.
486
487 To be used to simplify constructs like:
488
489 if initial is None (or in none_equivalents):
490 real_value = (template_instead % instead) or instead
491 else:
492 real_value = (template_initial % initial) or initial
493 print real_value
494
495 @param initial: the value to be tested for <None>
496 @type initial: any Python type, must have a __str__ method if template_initial is not None
497 @param instead: the value to be returned if <initial> is None
498 @type instead: any Python type, must have a __str__ method if template_instead is not None
499 @param template_initial: if <initial> is returned replace the value into this template, must contain one <%s>
500 @type template_initial: string or None
501 @param template_instead: if <instead> is returned replace the value into this template, must contain one <%s>
502 @type template_instead: string or None
503
504 Ideas:
505 - list of insteads: initial, [instead, template], [instead, template], [instead, template], template_initial, ...
506 """
507 if none_equivalents is None:
508 none_equivalents = [None]
509
510 if initial in none_equivalents:
511
512 if template_instead is None:
513 return instead
514
515 return template_instead % instead
516
517 if function_initial is not None:
518 funcname, args = function_initial
519 func = getattr(initial, funcname)
520 initial = func(args)
521
522 if template_initial is None:
523 return initial
524
525 try:
526 return template_initial % initial
527 except TypeError:
528 return template_initial
529
531 val = match_obj.group(0).lower()
532 if val in ['von', 'van', 'de', 'la', 'l', 'der', 'den']:
533 return val
534 buf = list(val)
535 buf[0] = buf[0].upper()
536 for part in ['mac', 'mc', 'de', 'la']:
537 if len(val) > len(part) and val[:len(part)] == part:
538 buf[len(part)] = buf[len(part)].upper()
539 return ''.join(buf)
540
542 """Capitalize the first character but leave the rest alone.
543
544 Note that we must be careful about the locale, this may
545 have issues ! However, for UTF strings it should just work.
546 """
547 if (mode is None) or (mode == CAPS_NONE):
548 return text
549
550 if mode == CAPS_FIRST:
551 if len(text) == 1:
552 return text[0].upper()
553 return text[0].upper() + text[1:]
554
555 if mode == CAPS_ALLCAPS:
556 return text.upper()
557
558 if mode == CAPS_FIRST_ONLY:
559 if len(text) == 1:
560 return text[0].upper()
561 return text[0].upper() + text[1:].lower()
562
563 if mode == CAPS_WORDS:
564 return regex.sub(ur'(\w)(\w+)', lambda x: x.group(1).upper() + x.group(2).lower(), text)
565
566 if mode == CAPS_NAMES:
567
568 return capitalize(text=text, mode=CAPS_FIRST)
569
570 print "ERROR: invalid capitalization mode: [%s], leaving input as is" % mode
571 return text
572
594
617
618 -def wrap(text=None, width=None, initial_indent=u'', subsequent_indent=u'', eol=u'\n'):
619 """A word-wrap function that preserves existing line breaks
620 and most spaces in the text. Expects that existing line
621 breaks are posix newlines (\n).
622 """
623 wrapped = initial_indent + reduce (
624 lambda line, word, width=width: '%s%s%s' % (
625 line,
626 ' \n'[(len(line) - line.rfind('\n') - 1 + len(word.split('\n',1)[0]) >= width)],
627 word
628 ),
629 text.split(' ')
630 )
631
632 if subsequent_indent != u'':
633 wrapped = (u'\n%s' % subsequent_indent).join(wrapped.split('\n'))
634
635 if eol != u'\n':
636 wrapped = wrapped.replace('\n', eol)
637
638 return wrapped
639
640 -def unwrap(text=None, max_length=None, strip_whitespace=True, remove_empty_lines=True, line_separator = u' // '):
641
642 text = text.replace(u'\r', u'')
643 lines = text.split(u'\n')
644 text = u''
645 for line in lines:
646
647 if strip_whitespace:
648 line = line.strip().strip(u'\t').strip()
649
650 if remove_empty_lines:
651 if line == u'':
652 continue
653
654 text += (u'%s%s' % (line, line_separator))
655
656 text = text.rstrip(line_separator)
657
658 if max_length is not None:
659 text = text[:max_length]
660
661 text = text.rstrip(line_separator)
662
663 return text
664
666 """check for special XML characters and transform them"""
667
668 text = text.replace(u'&', u'&')
669
670 return text
671
673 """check for special LaTeX characters and transform them"""
674
675 text = text.replace(u'\\', u'$\\backslash$')
676 text = text.replace(u'{', u'\\{')
677 text = text.replace(u'}', u'\\}')
678 text = text.replace(u'%', u'\\%')
679 text = text.replace(u'&', u'\\&')
680 text = text.replace(u'#', u'\\#')
681 text = text.replace(u'$', u'\\$')
682 text = text.replace(u'_', u'\\_')
683
684 text = text.replace(u'^', u'\\verb#^#')
685 text = text.replace('~','\\verb#~#')
686
687 return text
688
715
716
717
718
719
720 __icon_serpent = \
721 """x\xdae\x8f\xb1\x0e\x83 \x10\x86w\x9f\xe2\x92\x1blb\xf2\x07\x96\xeaH:0\xd6\
722 \xc1\x85\xd5\x98N5\xa5\xef?\xf5N\xd0\x8a\xdcA\xc2\xf7qw\x84\xdb\xfa\xb5\xcd\
723 \xd4\xda;\xc9\x1a\xc8\xb6\xcd<\xb5\xa0\x85\x1e\xeb\xbc\xbc7b!\xf6\xdeHl\x1c\
724 \x94\x073\xec<*\xf7\xbe\xf7\x99\x9d\xb21~\xe7.\xf5\x1f\x1c\xd3\xbdVlL\xc2\
725 \xcf\xf8ye\xd0\x00\x90\x0etH \x84\x80B\xaa\x8a\x88\x85\xc4(U\x9d$\xfeR;\xc5J\
726 \xa6\x01\xbbt9\xceR\xc8\x81e_$\x98\xb9\x9c\xa9\x8d,y\xa9t\xc8\xcf\x152\xe0x\
727 \xe9$\xf5\x07\x95\x0cD\x95t:\xb1\x92\xae\x9cI\xa8~\x84\x1f\xe0\xa3ec"""
728
730
731 paths = gmPaths(app_name = u'gnumed', wx = wx)
732
733 candidates = [
734 os.path.join(paths.system_app_data_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
735 os.path.join(paths.local_base_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
736 os.path.join(paths.system_app_data_dir, 'bitmaps', 'serpent.png'),
737 os.path.join(paths.local_base_dir, 'bitmaps', 'serpent.png')
738 ]
739
740 found_as = None
741 for candidate in candidates:
742 try:
743 open(candidate, 'r').close()
744 found_as = candidate
745 break
746 except IOError:
747 _log.debug('icon not found in [%s]', candidate)
748
749 if found_as is None:
750 _log.warning('no icon file found, falling back to builtin (ugly) icon')
751 icon_bmp_data = wx.BitmapFromXPMData(cPickle.loads(zlib.decompress(__icon_serpent)))
752 icon.CopyFromBitmap(icon_bmp_data)
753 else:
754 _log.debug('icon found in [%s]', found_as)
755 icon = wx.EmptyIcon()
756 try:
757 icon.LoadFile(found_as, wx.BITMAP_TYPE_ANY)
758 except AttributeError:
759 _log.exception(u"this platform doesn't support wx.Icon().LoadFile()")
760
761 return icon
762
763
764
765 if __name__ == '__main__':
766
767 if len(sys.argv) < 2:
768 sys.exit()
769
770 if sys.argv[1] != 'test':
771 sys.exit()
772
773
829
831
832 import datetime as dt
833 print coalesce(initial = dt.datetime.now(), template_initial = u'-- %s --', function_initial = ('strftime', u'%Y-%m-%d'))
834
835 print 'testing coalesce()'
836 print "------------------"
837 tests = [
838 [None, 'something other than <None>', None, None, 'something other than <None>'],
839 ['Captain', 'Mr.', '%s.'[:4], 'Mr.', 'Capt.'],
840 ['value to test', 'test 3 failed', 'template with "%s" included', None, 'template with "value to test" included'],
841 ['value to test', 'test 4 failed', 'template with value not included', None, 'template with value not included'],
842 [None, 'initial value was None', 'template_initial: %s', None, 'initial value was None'],
843 [None, 'initial value was None', 'template_initial: %%(abc)s', None, 'initial value was None']
844 ]
845 passed = True
846 for test in tests:
847 result = coalesce (
848 initial = test[0],
849 instead = test[1],
850 template_initial = test[2],
851 template_instead = test[3]
852 )
853 if result != test[4]:
854 print "ERROR"
855 print "coalesce: (%s, %s, %s, %s)" % (test[0], test[1], test[2], test[3])
856 print "expected:", test[4]
857 print "received:", result
858 passed = False
859
860 if passed:
861 print "passed"
862 else:
863 print "failed"
864 return passed
865
867 print 'testing capitalize() ...'
868 success = True
869 pairs = [
870
871 [u'Boot', u'Boot', CAPS_FIRST_ONLY],
872 [u'boot', u'Boot', CAPS_FIRST_ONLY],
873 [u'booT', u'Boot', CAPS_FIRST_ONLY],
874 [u'BoOt', u'Boot', CAPS_FIRST_ONLY],
875 [u'boots-Schau', u'Boots-Schau', CAPS_WORDS],
876 [u'boots-sChau', u'Boots-Schau', CAPS_WORDS],
877 [u'boot camp', u'Boot Camp', CAPS_WORDS],
878 [u'fahrner-Kampe', u'Fahrner-Kampe', CAPS_NAMES],
879 [u'häkkönen', u'Häkkönen', CAPS_NAMES],
880 [u'McBurney', u'McBurney', CAPS_NAMES],
881 [u'mcBurney', u'McBurney', CAPS_NAMES],
882 [u'blumberg', u'Blumberg', CAPS_NAMES],
883 [u'roVsing', u'RoVsing', CAPS_NAMES],
884 [u'Özdemir', u'Özdemir', CAPS_NAMES],
885 [u'özdemir', u'Özdemir', CAPS_NAMES],
886 ]
887 for pair in pairs:
888 result = capitalize(pair[0], pair[2])
889 if result != pair[1]:
890 success = False
891 print 'ERROR (caps mode %s): "%s" -> "%s", expected "%s"' % (pair[2], pair[0], result, pair[1])
892
893 if success:
894 print "... SUCCESS"
895
896 return success
897
899 print "testing import_module_from_directory()"
900 path = sys.argv[1]
901 name = sys.argv[2]
902 try:
903 mod = import_module_from_directory(module_path = path, module_name = name)
904 except:
905 print "module import failed, see log"
906 return False
907
908 print "module import succeeded", mod
909 print dir(mod)
910 return True
911
913 print "testing mkdir()"
914 mkdir(sys.argv[1])
915
917 print "testing gmPaths()"
918 print "-----------------"
919 paths = gmPaths(wx=None, app_name='gnumed')
920 print "user config dir:", paths.user_config_dir
921 print "system config dir:", paths.system_config_dir
922 print "local base dir:", paths.local_base_dir
923 print "system app data dir:", paths.system_app_data_dir
924 print "working directory :", paths.working_dir
925 print "temp directory :", paths.tmp_dir
926
928 print "testing none_if()"
929 print "-----------------"
930 tests = [
931 [None, None, None],
932 ['a', 'a', None],
933 ['a', 'b', 'a'],
934 ['a', None, 'a'],
935 [None, 'a', None],
936 [1, 1, None],
937 [1, 2, 1],
938 [1, None, 1],
939 [None, 1, None]
940 ]
941
942 for test in tests:
943 if none_if(value = test[0], none_equivalent = test[1]) != test[2]:
944 print 'ERROR: none_if(%s) returned [%s], expected [%s]' % (test[0], none_if(test[0], test[1]), test[2])
945
946 return True
947
949 tests = [
950 [True, 'Yes', 'Yes', 'Yes'],
951 [False, 'OK', 'not OK', 'not OK']
952 ]
953 for test in tests:
954 if bool2str(test[0], test[1], test[2]) != test[3]:
955 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])
956
957 return True
958
960
961 print bool2subst(True, 'True', 'False', 'is None')
962 print bool2subst(False, 'True', 'False', 'is None')
963 print bool2subst(None, 'True', 'False', 'is None')
964
971
973 print "testing size2str()"
974 print "------------------"
975 tests = [0, 1, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000]
976 for test in tests:
977 print size2str(test)
978
980
981 test = """
982 second line\n
983 3rd starts with tab \n
984 4th with a space \n
985
986 6th
987
988 """
989 print unwrap(text = test, max_length = 25)
990
992 test = 'line 1\nline 2\nline 3'
993
994 print "wrap 5-6-7 initial 0, subsequent 0"
995 print wrap(test, 5)
996 print
997 print wrap(test, 6)
998 print
999 print wrap(test, 7)
1000 print "-------"
1001 raw_input()
1002 print "wrap 5 initial 1-1-3, subsequent 1-3-1"
1003 print wrap(test, 5, u' ', u' ')
1004 print
1005 print wrap(test, 5, u' ', u' ')
1006 print
1007 print wrap(test, 5, u' ', u' ')
1008 print "-------"
1009 raw_input()
1010 print "wrap 6 initial 1-1-3, subsequent 1-3-1"
1011 print wrap(test, 6, u' ', u' ')
1012 print
1013 print wrap(test, 6, u' ', u' ')
1014 print
1015 print wrap(test, 6, u' ', u' ')
1016 print "-------"
1017 raw_input()
1018 print "wrap 7 initial 1-1-3, subsequent 1-3-1"
1019 print wrap(test, 7, u' ', u' ')
1020 print
1021 print wrap(test, 7, u' ', u' ')
1022 print
1023 print wrap(test, 7, u' ', u' ')
1024
1026 print '%s: %s' % (sys.argv[2], file2md5(sys.argv[2]))
1027
1028
1029
1030
1031
1032 test_gmPaths()
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044