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 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_down_left_arrow = u'\u21B5'
47 u_left_arrow = u'\u2190'
48 u_right_arrow = u'\u2192'
49 u_sum = u'\u2211'
50 u_corresponds_to = u'\u2258'
51 u_infinity = u'\u221E'
52 u_diameter = u'\u2300'
53 u_checkmark_crossed_out = u'\u237B'
54 u_box_horiz_single = u'\u2500'
55 u_box_horiz_4dashes = u'\u2508'
56 u_box_top_double = u'\u2550'
57 u_box_top_left_double_single = u'\u2552'
58 u_box_top_right_double_single = u'\u2555'
59 u_box_top_left_arc = u'\u256d'
60 u_box_bottom_right_arc = u'\u256f'
61 u_box_bottom_left_arc = u'\u2570'
62 u_box_horiz_light_heavy = u'\u257c'
63 u_box_horiz_heavy_light = u'\u257e'
64 u_skull_and_crossbones = u'\u2620'
65 u_frowning_face = u'\u2639'
66 u_smiling_face = u'\u263a'
67 u_black_heart = u'\u2665'
68 u_checkmark_thin = u'\u2713'
69 u_checkmark_thick = u'\u2714'
70 u_writing_hand = u'\u270d'
71 u_pencil_1 = u'\u270e'
72 u_pencil_2 = u'\u270f'
73 u_pencil_3 = u'\u2710'
74 u_latin_cross = u'\u271d'
75 u_replacement_character = u'\ufffd'
76 u_link_symbol = u'\u1f517'
77
78
80
81 print ".========================================================"
82 print "| Unhandled exception caught !"
83 print "| Type :", t
84 print "| Value:", v
85 print "`========================================================"
86 _log.critical('unhandled exception caught', exc_info = (t,v,tb))
87 sys.__excepthook__(t,v,tb)
88
89
90
91 -def mkdir(directory=None):
92 try:
93 os.makedirs(directory)
94 except OSError, e:
95 if (e.errno == 17) and not os.path.isdir(directory):
96 raise
97 return True
98
99
101 """This class provides the following paths:
102
103 .home_dir
104 .local_base_dir
105 .working_dir
106 .user_config_dir
107 .system_config_dir
108 .system_app_data_dir
109 .tmp_dir (readonly)
110 """
111 - def __init__(self, app_name=None, wx=None):
112 """Setup pathes.
113
114 <app_name> will default to (name of the script - .py)
115 """
116 try:
117 self.already_inited
118 return
119 except AttributeError:
120 pass
121
122 self.init_paths(app_name=app_name, wx=wx)
123 self.already_inited = True
124
125
126
128
129 if wx is None:
130 _log.debug('wxPython not available')
131 _log.debug('detecting paths directly')
132
133 if app_name is None:
134 app_name, ext = os.path.splitext(os.path.basename(sys.argv[0]))
135 _log.info('app name detected as [%s]', app_name)
136 else:
137 _log.info('app name passed in as [%s]', app_name)
138
139
140 self.__home_dir = None
141
142
143
144 self.local_base_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
145
146
147 self.working_dir = os.path.abspath(os.curdir)
148
149
150
151
152 mkdir(os.path.join(self.home_dir, '.%s' % app_name))
153 self.user_config_dir = os.path.join(self.home_dir, '.%s' % app_name)
154
155
156 try:
157 self.system_config_dir = os.path.join('/etc', app_name)
158 except ValueError:
159
160 self.system_config_dir = self.user_config_dir
161
162
163 try:
164 self.system_app_data_dir = os.path.join(sys.prefix, 'share', app_name)
165 except ValueError:
166 self.system_app_data_dir = self.local_base_dir
167
168
169 try:
170 self.__tmp_dir_already_set
171 _log.debug('temp dir already set')
172 except AttributeError:
173 tmp_base = os.path.join(tempfile.gettempdir(), app_name)
174 mkdir(tmp_base)
175 _log.info('previous temp dir: %s', tempfile.gettempdir())
176 tempfile.tempdir = tmp_base
177 _log.info('intermediate temp dir: %s', tempfile.gettempdir())
178 self.tmp_dir = tempfile.mkdtemp(prefix = r'gm-')
179
180 self.__log_paths()
181 if wx is None:
182 return True
183
184
185 _log.debug('re-detecting paths with wxPython')
186
187 std_paths = wx.StandardPaths.Get()
188 _log.info('wxPython app name is [%s]', wx.GetApp().GetAppName())
189
190
191 mkdir(os.path.join(std_paths.GetUserConfigDir(), '.%s' % app_name))
192 self.user_config_dir = os.path.join(std_paths.GetUserConfigDir(), '.%s' % app_name)
193
194
195 try:
196 tmp = std_paths.GetConfigDir()
197 if not tmp.endswith(app_name):
198 tmp = os.path.join(tmp, app_name)
199 self.system_config_dir = tmp
200 except ValueError:
201
202 pass
203
204
205
206
207 if 'wxMSW' in wx.PlatformInfo:
208 _log.warning('this platform (wxMSW) sometimes returns a broken value for the system-wide application data dir')
209 else:
210 try:
211 self.system_app_data_dir = std_paths.GetDataDir()
212 except ValueError:
213 pass
214
215 self.__log_paths()
216 return True
217
219 _log.debug('sys.argv[0]: %s', sys.argv[0])
220 _log.debug('local application base dir: %s', self.local_base_dir)
221 _log.debug('current working dir: %s', self.working_dir)
222
223 _log.debug('user home dir: %s', self.home_dir)
224 _log.debug('user-specific config dir: %s', self.user_config_dir)
225 _log.debug('system-wide config dir: %s', self.system_config_dir)
226 _log.debug('system-wide application data dir: %s', self.system_app_data_dir)
227 _log.debug('temporary dir: %s', self.tmp_dir)
228
229
230
232 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
233 msg = '[%s:user_config_dir]: invalid path [%s]' % (self.__class__.__name__, path)
234 _log.error(msg)
235 raise ValueError(msg)
236 self.__user_config_dir = path
237
239 return self.__user_config_dir
240
241 user_config_dir = property(_get_user_config_dir, _set_user_config_dir)
242
244 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
245 msg = '[%s:system_config_dir]: invalid path [%s]' % (self.__class__.__name__, path)
246 _log.error(msg)
247 raise ValueError(msg)
248 self.__system_config_dir = path
249
251 return self.__system_config_dir
252
253 system_config_dir = property(_get_system_config_dir, _set_system_config_dir)
254
256 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
257 msg = '[%s:system_app_data_dir]: invalid path [%s]' % (self.__class__.__name__, path)
258 _log.error(msg)
259 raise ValueError(msg)
260 self.__system_app_data_dir = path
261
263 return self.__system_app_data_dir
264
265 system_app_data_dir = property(_get_system_app_data_dir, _set_system_app_data_dir)
266
268 raise ValueError('invalid to set home dir')
269
271 if self.__home_dir is not None:
272 return self.__home_dir
273
274 tmp = os.path.expanduser('~')
275 if tmp == '~':
276 _log.error('this platform does not expand ~ properly')
277 try:
278 tmp = os.environ['USERPROFILE']
279 except KeyError:
280 _log.error('cannot access $USERPROFILE in environment')
281
282 if not (
283 os.access(tmp, os.R_OK)
284 and
285 os.access(tmp, os.X_OK)
286 and
287 os.access(tmp, os.W_OK)
288 ):
289 msg = '[%s:home_dir]: invalid path [%s]' % (self.__class__.__name__, tmp)
290 _log.error(msg)
291 raise ValueError(msg)
292
293 self.__home_dir = tmp
294 return self.__home_dir
295
296 home_dir = property(_get_home_dir, _set_home_dir)
297
299 if not (os.access(path, os.R_OK) and os.access(path, os.X_OK)):
300 msg = '[%s:tmp_dir]: invalid path [%s]' % (self.__class__.__name__, path)
301 _log.error(msg)
302 raise ValueError(msg)
303 _log.debug('previous temp dir: %s', tempfile.gettempdir())
304 self.__tmp_dir = path
305 tempfile.tempdir = self.__tmp_dir
306 self.__tmp_dir_already_set = True
307
309 return self.__tmp_dir
310
311 tmp_dir = property(_get_tmp_dir, _set_tmp_dir)
312
313
314
315 -def file2md5(filename=None, return_hex=True):
316 blocksize = 2**10 * 128
317 _log.debug('md5(%s): <%s> byte blocks', filename, blocksize)
318
319 f = open(filename, 'rb')
320
321 md5 = hashlib.md5()
322 while True:
323 data = f.read(blocksize)
324 if not data:
325 break
326 md5.update(data)
327
328 _log.debug('md5(%s): %s', filename, md5.hexdigest())
329
330 if return_hex:
331 return md5.hexdigest()
332 return md5.digest()
333
335 for line in unicode_csv_data:
336 yield line.encode(encoding)
337
338
339
340
341
342 default_csv_reader_rest_key = u'list_of_values_of_unknown_fields'
343
345
346
347 try:
348 is_dict_reader = kwargs['dict']
349 del kwargs['dict']
350 if is_dict_reader is not True:
351 raise KeyError
352 kwargs['restkey'] = default_csv_reader_rest_key
353 csv_reader = csv.DictReader(unicode2charset_encoder(unicode_csv_data), dialect=dialect, **kwargs)
354 except KeyError:
355 is_dict_reader = False
356 csv_reader = csv.reader(unicode2charset_encoder(unicode_csv_data), dialect=dialect, **kwargs)
357
358 for row in csv_reader:
359
360 if is_dict_reader:
361 for key in row.keys():
362 if key == default_csv_reader_rest_key:
363 old_data = row[key]
364 new_data = []
365 for val in old_data:
366 new_data.append(unicode(val, encoding))
367 row[key] = new_data
368 if default_csv_reader_rest_key not in csv_reader.fieldnames:
369 csv_reader.fieldnames.append(default_csv_reader_rest_key)
370 else:
371 row[key] = unicode(row[key], encoding)
372 yield row
373 else:
374 yield [ unicode(cell, encoding) for cell in row ]
375
376
378 """This introduces a race condition between the file.close() and
379 actually using the filename.
380
381 The file will not exist after calling this function.
382 """
383 if tmp_dir is not None:
384 if (
385 not os.access(tmp_dir, os.F_OK)
386 or
387 not os.access(tmp_dir, os.X_OK | os.W_OK)
388 ):
389 _log.info('cannot find temporary dir [%s], using system default', tmp_dir)
390 tmp_dir = None
391
392 kwargs = {'dir': tmp_dir}
393
394 if prefix is None:
395 kwargs['prefix'] = 'gnumed-'
396 else:
397 kwargs['prefix'] = prefix
398
399 if suffix in [None, u'']:
400 kwargs['suffix'] = '.tmp'
401 else:
402 if not suffix.startswith('.'):
403 suffix = '.' + suffix
404 kwargs['suffix'] = suffix
405
406 f = tempfile.NamedTemporaryFile(**kwargs)
407 filename = f.name
408 f.close()
409
410 return filename
411
413 """Import a module from any location."""
414
415 remove_path = always_remove_path or False
416 if module_path not in sys.path:
417 _log.info('appending to sys.path: [%s]' % module_path)
418 sys.path.append(module_path)
419 remove_path = True
420
421 _log.debug('will remove import path: %s', remove_path)
422
423 if module_name.endswith('.py'):
424 module_name = module_name[:-3]
425
426 try:
427 module = __import__(module_name)
428 except StandardError:
429 _log.exception('cannot __import__() module [%s] from [%s]' % (module_name, module_path))
430 while module_path in sys.path:
431 sys.path.remove(module_path)
432 raise
433
434 _log.info('imported module [%s] as [%s]' % (module_name, module))
435 if remove_path:
436 while module_path in sys.path:
437 sys.path.remove(module_path)
438
439 return module
440
441
442
443 _kB = 1024
444 _MB = 1024 * _kB
445 _GB = 1024 * _MB
446 _TB = 1024 * _GB
447 _PB = 1024 * _TB
448
450 if size == 1:
451 return template % _('1 Byte')
452 if size < 10 * _kB:
453 return template % _('%s Bytes') % size
454 if size < _MB:
455 return template % u'%.1f kB' % (float(size) / _kB)
456 if size < _GB:
457 return template % u'%.1f MB' % (float(size) / _MB)
458 if size < _TB:
459 return template % u'%.1f GB' % (float(size) / _GB)
460 if size < _PB:
461 return template % u'%.1f TB' % (float(size) / _TB)
462 return template % u'%.1f PB' % (float(size) / _PB)
463
464 -def bool2subst(boolean=None, true_return=True, false_return=False, none_return=None):
465 if boolean is None:
466 return none_return
467 if boolean is True:
468 return true_return
469 if boolean is False:
470 return false_return
471 raise ValueError('bool2subst(): <boolean> arg must be either of True, False, None')
472
473 -def bool2str(boolean=None, true_str='True', false_str='False'):
474 return bool2subst (
475 boolean = bool(boolean),
476 true_return = true_str,
477 false_return = false_str
478 )
479
480 -def none_if(value=None, none_equivalent=None, strip_string=False):
481 """Modelled after the SQL NULLIF function."""
482 if value is None:
483 return None
484 if strip_string:
485 stripped = value.strip()
486 else:
487 stripped = value
488 if stripped == none_equivalent:
489 return None
490 return value
491
492 -def coalesce(initial=None, instead=None, template_initial=None, template_instead=None, none_equivalents=None, function_initial=None):
493 """Modelled after the SQL coalesce function.
494
495 To be used to simplify constructs like:
496
497 if initial is None (or in none_equivalents):
498 real_value = (template_instead % instead) or instead
499 else:
500 real_value = (template_initial % initial) or initial
501 print real_value
502
503 @param initial: the value to be tested for <None>
504 @type initial: any Python type, must have a __str__ method if template_initial is not None
505 @param instead: the value to be returned if <initial> is None
506 @type instead: any Python type, must have a __str__ method if template_instead is not None
507 @param template_initial: if <initial> is returned replace the value into this template, must contain one <%s>
508 @type template_initial: string or None
509 @param template_instead: if <instead> is returned replace the value into this template, must contain one <%s>
510 @type template_instead: string or None
511
512 example:
513 function_initial = ('strftime', '%Y-%m-%d')
514
515 Ideas:
516 - list of insteads: initial, [instead, template], [instead, template], [instead, template], template_initial, ...
517 """
518 if none_equivalents is None:
519 none_equivalents = [None]
520
521 if initial in none_equivalents:
522
523 if template_instead is None:
524 return instead
525
526 return template_instead % instead
527
528 if function_initial is not None:
529 funcname, args = function_initial
530 func = getattr(initial, funcname)
531 initial = func(args)
532
533 if template_initial is None:
534 return initial
535
536 try:
537 return template_initial % initial
538 except TypeError:
539 return template_initial
540
542 val = match_obj.group(0).lower()
543 if val in ['von', 'van', 'de', 'la', 'l', 'der', 'den']:
544 return val
545 buf = list(val)
546 buf[0] = buf[0].upper()
547 for part in ['mac', 'mc', 'de', 'la']:
548 if len(val) > len(part) and val[:len(part)] == part:
549 buf[len(part)] = buf[len(part)].upper()
550 return ''.join(buf)
551
553 """Capitalize the first character but leave the rest alone.
554
555 Note that we must be careful about the locale, this may
556 have issues ! However, for UTF strings it should just work.
557 """
558 if (mode is None) or (mode == CAPS_NONE):
559 return text
560
561 if mode == CAPS_FIRST:
562 if len(text) == 1:
563 return text[0].upper()
564 return text[0].upper() + text[1:]
565
566 if mode == CAPS_ALLCAPS:
567 return text.upper()
568
569 if mode == CAPS_FIRST_ONLY:
570 if len(text) == 1:
571 return text[0].upper()
572 return text[0].upper() + text[1:].lower()
573
574 if mode == CAPS_WORDS:
575 return regex.sub(ur'(\w)(\w+)', lambda x: x.group(1).upper() + x.group(2).lower(), text)
576
577 if mode == CAPS_NAMES:
578
579 return capitalize(text=text, mode=CAPS_FIRST)
580
581 print "ERROR: invalid capitalization mode: [%s], leaving input as is" % mode
582 return text
583
605
631
633 return_join = False
634 if lines is None:
635 return_join = True
636 lines = eol.split(text)
637
638 while True:
639 if lines[0].strip(eol).strip() != u'':
640 break
641 lines = lines[1:]
642
643 if return_join:
644 return eol.join(lines)
645
646 return lines
647
649 return_join = False
650 if lines is None:
651 return_join = True
652 lines = eol.split(text)
653
654 while True:
655 if lines[-1].strip(eol).strip() != u'':
656 break
657 lines = lines[:-1]
658
659 if return_join:
660 return eol.join(lines)
661
662 return lines
663
664 -def wrap(text=None, width=None, initial_indent=u'', subsequent_indent=u'', eol=u'\n'):
665 """A word-wrap function that preserves existing line breaks
666 and most spaces in the text. Expects that existing line
667 breaks are posix newlines (\n).
668 """
669 wrapped = initial_indent + reduce (
670 lambda line, word, width=width: '%s%s%s' % (
671 line,
672 ' \n'[(len(line) - line.rfind('\n') - 1 + len(word.split('\n',1)[0]) >= width)],
673 word
674 ),
675 text.split(' ')
676 )
677
678 if subsequent_indent != u'':
679 wrapped = (u'\n%s' % subsequent_indent).join(wrapped.split('\n'))
680
681 if eol != u'\n':
682 wrapped = wrapped.replace('\n', eol)
683
684 return wrapped
685
686 -def unwrap(text=None, max_length=None, strip_whitespace=True, remove_empty_lines=True, line_separator = u' // '):
687
688 text = text.replace(u'\r', u'')
689 lines = text.split(u'\n')
690 text = u''
691 for line in lines:
692
693 if strip_whitespace:
694 line = line.strip().strip(u'\t').strip()
695
696 if remove_empty_lines:
697 if line == u'':
698 continue
699
700 text += (u'%s%s' % (line, line_separator))
701
702 text = text.rstrip(line_separator)
703
704 if max_length is not None:
705 text = text[:max_length]
706
707 text = text.rstrip(line_separator)
708
709 return text
710
712 """check for special XML characters and transform them"""
713
714 text = text.replace(u'&', u'&')
715
716 return text
717
719 """check for special LaTeX characters and transform them"""
720
721 text = text.replace(u'\\', u'$\\backslash$')
722 text = text.replace(u'{', u'\\{')
723 text = text.replace(u'}', u'\\}')
724 text = text.replace(u'%', u'\\%')
725 text = text.replace(u'&', u'\\&')
726 text = text.replace(u'#', u'\\#')
727 text = text.replace(u'$', u'\\$')
728 text = text.replace(u'_', u'\\_')
729
730 text = text.replace(u'^', u'\\verb#^#')
731 text = text.replace('~','\\verb#~#')
732
733 return text
734
761
762
763
764
765
766 __icon_serpent = \
767 """x\xdae\x8f\xb1\x0e\x83 \x10\x86w\x9f\xe2\x92\x1blb\xf2\x07\x96\xeaH:0\xd6\
768 \xc1\x85\xd5\x98N5\xa5\xef?\xf5N\xd0\x8a\xdcA\xc2\xf7qw\x84\xdb\xfa\xb5\xcd\
769 \xd4\xda;\xc9\x1a\xc8\xb6\xcd<\xb5\xa0\x85\x1e\xeb\xbc\xbc7b!\xf6\xdeHl\x1c\
770 \x94\x073\xec<*\xf7\xbe\xf7\x99\x9d\xb21~\xe7.\xf5\x1f\x1c\xd3\xbdVlL\xc2\
771 \xcf\xf8ye\xd0\x00\x90\x0etH \x84\x80B\xaa\x8a\x88\x85\xc4(U\x9d$\xfeR;\xc5J\
772 \xa6\x01\xbbt9\xceR\xc8\x81e_$\x98\xb9\x9c\xa9\x8d,y\xa9t\xc8\xcf\x152\xe0x\
773 \xe9$\xf5\x07\x95\x0cD\x95t:\xb1\x92\xae\x9cI\xa8~\x84\x1f\xe0\xa3ec"""
774
776
777 paths = gmPaths(app_name = u'gnumed', wx = wx)
778
779 candidates = [
780 os.path.join(paths.system_app_data_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
781 os.path.join(paths.local_base_dir, 'bitmaps', 'gm_icon-serpent_and_gnu.png'),
782 os.path.join(paths.system_app_data_dir, 'bitmaps', 'serpent.png'),
783 os.path.join(paths.local_base_dir, 'bitmaps', 'serpent.png')
784 ]
785
786 found_as = None
787 for candidate in candidates:
788 try:
789 open(candidate, 'r').close()
790 found_as = candidate
791 break
792 except IOError:
793 _log.debug('icon not found in [%s]', candidate)
794
795 if found_as is None:
796 _log.warning('no icon file found, falling back to builtin (ugly) icon')
797 icon_bmp_data = wx.BitmapFromXPMData(cPickle.loads(zlib.decompress(__icon_serpent)))
798 icon.CopyFromBitmap(icon_bmp_data)
799 else:
800 _log.debug('icon found in [%s]', found_as)
801 icon = wx.EmptyIcon()
802 try:
803 icon.LoadFile(found_as, wx.BITMAP_TYPE_ANY)
804 except AttributeError:
805 _log.exception(u"this platform doesn't support wx.Icon().LoadFile()")
806
807 return icon
808
809
810
811 if __name__ == '__main__':
812
813 if len(sys.argv) < 2:
814 sys.exit()
815
816 if sys.argv[1] != 'test':
817 sys.exit()
818
819
877
882
884
885 import datetime as dt
886 print coalesce(initial = dt.datetime.now(), template_initial = u'-- %s --', function_initial = ('strftime', u'%Y-%m-%d'))
887
888 print 'testing coalesce()'
889 print "------------------"
890 tests = [
891 [None, 'something other than <None>', None, None, 'something other than <None>'],
892 ['Captain', 'Mr.', '%s.'[:4], 'Mr.', 'Capt.'],
893 ['value to test', 'test 3 failed', 'template with "%s" included', None, 'template with "value to test" included'],
894 ['value to test', 'test 4 failed', 'template with value not included', None, 'template with value not included'],
895 [None, 'initial value was None', 'template_initial: %s', None, 'initial value was None'],
896 [None, 'initial value was None', 'template_initial: %%(abc)s', None, 'initial value was None']
897 ]
898 passed = True
899 for test in tests:
900 result = coalesce (
901 initial = test[0],
902 instead = test[1],
903 template_initial = test[2],
904 template_instead = test[3]
905 )
906 if result != test[4]:
907 print "ERROR"
908 print "coalesce: (%s, %s, %s, %s)" % (test[0], test[1], test[2], test[3])
909 print "expected:", test[4]
910 print "received:", result
911 passed = False
912
913 if passed:
914 print "passed"
915 else:
916 print "failed"
917 return passed
918
920 print 'testing capitalize() ...'
921 success = True
922 pairs = [
923
924 [u'Boot', u'Boot', CAPS_FIRST_ONLY],
925 [u'boot', u'Boot', CAPS_FIRST_ONLY],
926 [u'booT', u'Boot', CAPS_FIRST_ONLY],
927 [u'BoOt', u'Boot', CAPS_FIRST_ONLY],
928 [u'boots-Schau', u'Boots-Schau', CAPS_WORDS],
929 [u'boots-sChau', u'Boots-Schau', CAPS_WORDS],
930 [u'boot camp', u'Boot Camp', CAPS_WORDS],
931 [u'fahrner-Kampe', u'Fahrner-Kampe', CAPS_NAMES],
932 [u'häkkönen', u'Häkkönen', CAPS_NAMES],
933 [u'McBurney', u'McBurney', CAPS_NAMES],
934 [u'mcBurney', u'McBurney', CAPS_NAMES],
935 [u'blumberg', u'Blumberg', CAPS_NAMES],
936 [u'roVsing', u'RoVsing', CAPS_NAMES],
937 [u'Özdemir', u'Özdemir', CAPS_NAMES],
938 [u'özdemir', u'Özdemir', CAPS_NAMES],
939 ]
940 for pair in pairs:
941 result = capitalize(pair[0], pair[2])
942 if result != pair[1]:
943 success = False
944 print 'ERROR (caps mode %s): "%s" -> "%s", expected "%s"' % (pair[2], pair[0], result, pair[1])
945
946 if success:
947 print "... SUCCESS"
948
949 return success
950
952 print "testing import_module_from_directory()"
953 path = sys.argv[1]
954 name = sys.argv[2]
955 try:
956 mod = import_module_from_directory(module_path = path, module_name = name)
957 except:
958 print "module import failed, see log"
959 return False
960
961 print "module import succeeded", mod
962 print dir(mod)
963 return True
964
966 print "testing mkdir()"
967 mkdir(sys.argv[1])
968
970 print "testing gmPaths()"
971 print "-----------------"
972 paths = gmPaths(wx=None, app_name='gnumed')
973 print "user config dir:", paths.user_config_dir
974 print "system config dir:", paths.system_config_dir
975 print "local base dir:", paths.local_base_dir
976 print "system app data dir:", paths.system_app_data_dir
977 print "working directory :", paths.working_dir
978 print "temp directory :", paths.tmp_dir
979
981 print "testing none_if()"
982 print "-----------------"
983 tests = [
984 [None, None, None],
985 ['a', 'a', None],
986 ['a', 'b', 'a'],
987 ['a', None, 'a'],
988 [None, 'a', None],
989 [1, 1, None],
990 [1, 2, 1],
991 [1, None, 1],
992 [None, 1, None]
993 ]
994
995 for test in tests:
996 if none_if(value = test[0], none_equivalent = test[1]) != test[2]:
997 print 'ERROR: none_if(%s) returned [%s], expected [%s]' % (test[0], none_if(test[0], test[1]), test[2])
998
999 return True
1000
1002 tests = [
1003 [True, 'Yes', 'Yes', 'Yes'],
1004 [False, 'OK', 'not OK', 'not OK']
1005 ]
1006 for test in tests:
1007 if bool2str(test[0], test[1], test[2]) != test[3]:
1008 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])
1009
1010 return True
1011
1013
1014 print bool2subst(True, 'True', 'False', 'is None')
1015 print bool2subst(False, 'True', 'False', 'is None')
1016 print bool2subst(None, 'True', 'False', 'is None')
1017
1024
1026 print "testing size2str()"
1027 print "------------------"
1028 tests = [0, 1, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000]
1029 for test in tests:
1030 print size2str(test)
1031
1033
1034 test = """
1035 second line\n
1036 3rd starts with tab \n
1037 4th with a space \n
1038
1039 6th
1040
1041 """
1042 print unwrap(text = test, max_length = 25)
1043
1045 test = 'line 1\nline 2\nline 3'
1046
1047 print "wrap 5-6-7 initial 0, subsequent 0"
1048 print wrap(test, 5)
1049 print
1050 print wrap(test, 6)
1051 print
1052 print wrap(test, 7)
1053 print "-------"
1054 raw_input()
1055 print "wrap 5 initial 1-1-3, subsequent 1-3-1"
1056 print wrap(test, 5, u' ', u' ')
1057 print
1058 print wrap(test, 5, u' ', u' ')
1059 print
1060 print wrap(test, 5, u' ', u' ')
1061 print "-------"
1062 raw_input()
1063 print "wrap 6 initial 1-1-3, subsequent 1-3-1"
1064 print wrap(test, 6, u' ', u' ')
1065 print
1066 print wrap(test, 6, u' ', u' ')
1067 print
1068 print wrap(test, 6, u' ', u' ')
1069 print "-------"
1070 raw_input()
1071 print "wrap 7 initial 1-1-3, subsequent 1-3-1"
1072 print wrap(test, 7, u' ', u' ')
1073 print
1074 print wrap(test, 7, u' ', u' ')
1075 print
1076 print wrap(test, 7, u' ', u' ')
1077
1079 print '%s: %s' % (sys.argv[2], file2md5(sys.argv[2]))
1080
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099 test_unicode()
1100
1101
1102