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