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 example:
505 function_initial = ('strftime', '%Y-%m-%d')
506
507 Ideas:
508 - list of insteads: initial, [instead, template], [instead, template], [instead, template], template_initial, ...
509 """
510 if none_equivalents is None:
511 none_equivalents = [None]
512
513 if initial in none_equivalents:
514
515 if template_instead is None:
516 return instead
517
518 return template_instead % instead
519
520 if function_initial is not None:
521 funcname, args = function_initial
522 func = getattr(initial, funcname)
523 initial = func(args)
524
525 if template_initial is None:
526 return initial
527
528 try:
529 return template_initial % initial
530 except TypeError:
531 return template_initial
532
534 val = match_obj.group(0).lower()
535 if val in ['von', 'van', 'de', 'la', 'l', 'der', 'den']:
536 return val
537 buf = list(val)
538 buf[0] = buf[0].upper()
539 for part in ['mac', 'mc', 'de', 'la']:
540 if len(val) > len(part) and val[:len(part)] == part:
541 buf[len(part)] = buf[len(part)].upper()
542 return ''.join(buf)
543
545 """Capitalize the first character but leave the rest alone.
546
547 Note that we must be careful about the locale, this may
548 have issues ! However, for UTF strings it should just work.
549 """
550 if (mode is None) or (mode == CAPS_NONE):
551 return text
552
553 if mode == CAPS_FIRST:
554 if len(text) == 1:
555 return text[0].upper()
556 return text[0].upper() + text[1:]
557
558 if mode == CAPS_ALLCAPS:
559 return text.upper()
560
561 if mode == CAPS_FIRST_ONLY:
562 if len(text) == 1:
563 return text[0].upper()
564 return text[0].upper() + text[1:].lower()
565
566 if mode == CAPS_WORDS:
567 return regex.sub(ur'(\w)(\w+)', lambda x: x.group(1).upper() + x.group(2).lower(), text)
568
569 if mode == CAPS_NAMES:
570
571 return capitalize(text=text, mode=CAPS_FIRST)
572
573 print "ERROR: invalid capitalization mode: [%s], leaving input as is" % mode
574 return text
575
597
620
621 -def wrap(text=None, width=None, initial_indent=u'', subsequent_indent=u'', eol=u'\n'):
622 """A word-wrap function that preserves existing line breaks
623 and most spaces in the text. Expects that existing line
624 breaks are posix newlines (\n).
625 """
626 wrapped = initial_indent + reduce (
627 lambda line, word, width=width: '%s%s%s' % (
628 line,
629 ' \n'[(len(line) - line.rfind('\n') - 1 + len(word.split('\n',1)[0]) >= width)],
630 word
631 ),
632 text.split(' ')
633 )
634
635 if subsequent_indent != u'':
636 wrapped = (u'\n%s' % subsequent_indent).join(wrapped.split('\n'))
637
638 if eol != u'\n':
639 wrapped = wrapped.replace('\n', eol)
640
641 return wrapped
642
643 -def unwrap(text=None, max_length=None, strip_whitespace=True, remove_empty_lines=True, line_separator = u' // '):
644
645 text = text.replace(u'\r', u'')
646 lines = text.split(u'\n')
647 text = u''
648 for line in lines:
649
650 if strip_whitespace:
651 line = line.strip().strip(u'\t').strip()
652
653 if remove_empty_lines:
654 if line == u'':
655 continue
656
657 text += (u'%s%s' % (line, line_separator))
658
659 text = text.rstrip(line_separator)
660
661 if max_length is not None:
662 text = text[:max_length]
663
664 text = text.rstrip(line_separator)
665
666 return text
667
669 """check for special XML characters and transform them"""
670
671 text = text.replace(u'&', u'&')
672
673 return text
674
676 """check for special LaTeX characters and transform them"""
677
678 text = text.replace(u'\\', u'$\\backslash$')
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 text = text.replace(u'#', u'\\#')
684 text = text.replace(u'$', u'\\$')
685 text = text.replace(u'_', u'\\_')
686
687 text = text.replace(u'^', u'\\verb#^#')
688 text = text.replace('~','\\verb#~#')
689
690 return text
691
718
719
720
721
722
723 __icon_serpent = \
724 """x\xdae\x8f\xb1\x0e\x83 \x10\x86w\x9f\xe2\x92\x1blb\xf2\x07\x96\xeaH:0\xd6\
725 \xc1\x85\xd5\x98N5\xa5\xef?\xf5N\xd0\x8a\xdcA\xc2\xf7qw\x84\xdb\xfa\xb5\xcd\
726 \xd4\xda;\xc9\x1a\xc8\xb6\xcd<\xb5\xa0\x85\x1e\xeb\xbc\xbc7b!\xf6\xdeHl\x1c\
727 \x94\x073\xec<*\xf7\xbe\xf7\x99\x9d\xb21~\xe7.\xf5\x1f\x1c\xd3\xbdVlL\xc2\
728 \xcf\xf8ye\xd0\x00\x90\x0etH \x84\x80B\xaa\x8a\x88\x85\xc4(U\x9d$\xfeR;\xc5J\
729 \xa6\x01\xbbt9\xceR\xc8\x81e_$\x98\xb9\x9c\xa9\x8d,y\xa9t\xc8\xcf\x152\xe0x\
730 \xe9$\xf5\x07\x95\x0cD\x95t:\xb1\x92\xae\x9cI\xa8~\x84\x1f\xe0\xa3ec"""
731
733
734 paths = gmPaths(app_name = u'gnumed', wx = wx)
735
736 candidates = [
737 os.path.join(paths.system_app_data_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
738 os.path.join(paths.local_base_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
739 os.path.join(paths.system_app_data_dir, 'bitmaps', 'serpent.png'),
740 os.path.join(paths.local_base_dir, 'bitmaps', 'serpent.png')
741 ]
742
743 found_as = None
744 for candidate in candidates:
745 try:
746 open(candidate, 'r').close()
747 found_as = candidate
748 break
749 except IOError:
750 _log.debug('icon not found in [%s]', candidate)
751
752 if found_as is None:
753 _log.warning('no icon file found, falling back to builtin (ugly) icon')
754 icon_bmp_data = wx.BitmapFromXPMData(cPickle.loads(zlib.decompress(__icon_serpent)))
755 icon.CopyFromBitmap(icon_bmp_data)
756 else:
757 _log.debug('icon found in [%s]', found_as)
758 icon = wx.EmptyIcon()
759 try:
760 icon.LoadFile(found_as, wx.BITMAP_TYPE_ANY)
761 except AttributeError:
762 _log.exception(u"this platform doesn't support wx.Icon().LoadFile()")
763
764 return icon
765
766
767
768 if __name__ == '__main__':
769
770 if len(sys.argv) < 2:
771 sys.exit()
772
773 if sys.argv[1] != 'test':
774 sys.exit()
775
776
834
836
837 import datetime as dt
838 print coalesce(initial = dt.datetime.now(), template_initial = u'-- %s --', function_initial = ('strftime', u'%Y-%m-%d'))
839
840 print 'testing coalesce()'
841 print "------------------"
842 tests = [
843 [None, 'something other than <None>', None, None, 'something other than <None>'],
844 ['Captain', 'Mr.', '%s.'[:4], 'Mr.', 'Capt.'],
845 ['value to test', 'test 3 failed', 'template with "%s" included', None, 'template with "value to test" included'],
846 ['value to test', 'test 4 failed', 'template with value not included', None, 'template with value not included'],
847 [None, 'initial value was None', 'template_initial: %s', None, 'initial value was None'],
848 [None, 'initial value was None', 'template_initial: %%(abc)s', None, 'initial value was None']
849 ]
850 passed = True
851 for test in tests:
852 result = coalesce (
853 initial = test[0],
854 instead = test[1],
855 template_initial = test[2],
856 template_instead = test[3]
857 )
858 if result != test[4]:
859 print "ERROR"
860 print "coalesce: (%s, %s, %s, %s)" % (test[0], test[1], test[2], test[3])
861 print "expected:", test[4]
862 print "received:", result
863 passed = False
864
865 if passed:
866 print "passed"
867 else:
868 print "failed"
869 return passed
870
872 print 'testing capitalize() ...'
873 success = True
874 pairs = [
875
876 [u'Boot', u'Boot', CAPS_FIRST_ONLY],
877 [u'boot', u'Boot', CAPS_FIRST_ONLY],
878 [u'booT', u'Boot', CAPS_FIRST_ONLY],
879 [u'BoOt', u'Boot', CAPS_FIRST_ONLY],
880 [u'boots-Schau', u'Boots-Schau', CAPS_WORDS],
881 [u'boots-sChau', u'Boots-Schau', CAPS_WORDS],
882 [u'boot camp', u'Boot Camp', CAPS_WORDS],
883 [u'fahrner-Kampe', u'Fahrner-Kampe', CAPS_NAMES],
884 [u'häkkönen', u'Häkkönen', CAPS_NAMES],
885 [u'McBurney', u'McBurney', CAPS_NAMES],
886 [u'mcBurney', u'McBurney', CAPS_NAMES],
887 [u'blumberg', u'Blumberg', CAPS_NAMES],
888 [u'roVsing', u'RoVsing', CAPS_NAMES],
889 [u'Özdemir', u'Özdemir', CAPS_NAMES],
890 [u'özdemir', u'Özdemir', CAPS_NAMES],
891 ]
892 for pair in pairs:
893 result = capitalize(pair[0], pair[2])
894 if result != pair[1]:
895 success = False
896 print 'ERROR (caps mode %s): "%s" -> "%s", expected "%s"' % (pair[2], pair[0], result, pair[1])
897
898 if success:
899 print "... SUCCESS"
900
901 return success
902
904 print "testing import_module_from_directory()"
905 path = sys.argv[1]
906 name = sys.argv[2]
907 try:
908 mod = import_module_from_directory(module_path = path, module_name = name)
909 except:
910 print "module import failed, see log"
911 return False
912
913 print "module import succeeded", mod
914 print dir(mod)
915 return True
916
918 print "testing mkdir()"
919 mkdir(sys.argv[1])
920
922 print "testing gmPaths()"
923 print "-----------------"
924 paths = gmPaths(wx=None, app_name='gnumed')
925 print "user config dir:", paths.user_config_dir
926 print "system config dir:", paths.system_config_dir
927 print "local base dir:", paths.local_base_dir
928 print "system app data dir:", paths.system_app_data_dir
929 print "working directory :", paths.working_dir
930 print "temp directory :", paths.tmp_dir
931
933 print "testing none_if()"
934 print "-----------------"
935 tests = [
936 [None, None, None],
937 ['a', 'a', None],
938 ['a', 'b', 'a'],
939 ['a', None, 'a'],
940 [None, 'a', None],
941 [1, 1, None],
942 [1, 2, 1],
943 [1, None, 1],
944 [None, 1, None]
945 ]
946
947 for test in tests:
948 if none_if(value = test[0], none_equivalent = test[1]) != test[2]:
949 print 'ERROR: none_if(%s) returned [%s], expected [%s]' % (test[0], none_if(test[0], test[1]), test[2])
950
951 return True
952
954 tests = [
955 [True, 'Yes', 'Yes', 'Yes'],
956 [False, 'OK', 'not OK', 'not OK']
957 ]
958 for test in tests:
959 if bool2str(test[0], test[1], test[2]) != test[3]:
960 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])
961
962 return True
963
965
966 print bool2subst(True, 'True', 'False', 'is None')
967 print bool2subst(False, 'True', 'False', 'is None')
968 print bool2subst(None, 'True', 'False', 'is None')
969
976
978 print "testing size2str()"
979 print "------------------"
980 tests = [0, 1, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000]
981 for test in tests:
982 print size2str(test)
983
985
986 test = """
987 second line\n
988 3rd starts with tab \n
989 4th with a space \n
990
991 6th
992
993 """
994 print unwrap(text = test, max_length = 25)
995
997 test = 'line 1\nline 2\nline 3'
998
999 print "wrap 5-6-7 initial 0, subsequent 0"
1000 print wrap(test, 5)
1001 print
1002 print wrap(test, 6)
1003 print
1004 print wrap(test, 7)
1005 print "-------"
1006 raw_input()
1007 print "wrap 5 initial 1-1-3, subsequent 1-3-1"
1008 print wrap(test, 5, u' ', u' ')
1009 print
1010 print wrap(test, 5, u' ', u' ')
1011 print
1012 print wrap(test, 5, u' ', u' ')
1013 print "-------"
1014 raw_input()
1015 print "wrap 6 initial 1-1-3, subsequent 1-3-1"
1016 print wrap(test, 6, u' ', u' ')
1017 print
1018 print wrap(test, 6, u' ', u' ')
1019 print
1020 print wrap(test, 6, u' ', u' ')
1021 print "-------"
1022 raw_input()
1023 print "wrap 7 initial 1-1-3, subsequent 1-3-1"
1024 print wrap(test, 7, u' ', u' ')
1025 print
1026 print wrap(test, 7, u' ', u' ')
1027 print
1028 print wrap(test, 7, u' ', u' ')
1029
1031 print '%s: %s' % (sys.argv[2], file2md5(sys.argv[2]))
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 test_input2decimal()
1045
1046
1047
1048
1049