Package Gnumed :: Module gnumed |
[frames] | no frames]

# Source Code for Module Gnumed.gnumed

      1  #!/usr/bin/env python
      2
      3  __doc__ = """GNUmed client launcher.
      4
      5  This is the launcher for the GNUmed GUI client. It takes
      6  care of all the pre- and post-GUI runtime environment setup.
      7
      8  --quiet
      9   Be extra quiet and show only _real_ errors in the log.
     10  --debug
     11   Pre-set the [debug mode] checkbox in the login dialog to
     12   increase verbosity in the log file. Useful for, well, debugging :-)
     13  --slave
     14   Pre-set the [enable remote control] checkbox in the login
     15   dialog to enable the XML-RPC remote control feature.
     16  --hipaa
     17   Enable HIPAA functionality which has user impact.
     18  --profile=<file>
     19   Activate profiling and write profile data to <file>.
     20  --tool=<TOOL>
     21   Run TOOL instead of the main GUI.
     22  --text-domain=<text domain>
     23   Set this to change the name of the language file to be loaded.
     24   Note, this does not change the directory the file is searched in,
     25   only the name of the file where messages are loaded from. The
     26   standard textdomain is, of course, "gnumed.mo".
     27  --log-file=<file>
     28   Use this to change the name of the log file.
     29   See gmLog2.py to find out where the standard log file would
     30   end up.
     31  --conf-file=<file>
     32   Use configuration file <file> instead of searching for it in
     33   standard locations.
     34  --lang-gettext=<language>
     35   Explicitly set the language to use in gettext translation. The very
     36   same effect can be achieved by setting the environment variable $LANG
     37   from a launcher script.
     38  --override-schema-check
     39   Continue loading the client even if the database schema version
     40   and the client software version cannot be verified to be compatible.
     41  --skip-update-check
     42   Skip checking for client updates. This is useful during development
     43   and when the update check URL is unavailable (down).
     44  --local-import
     45   Adjust the PYTHONPATH such that GNUmed can be run from a local source tree.
     46  --ui=<ui type>
     47   Start an alternative UI. Defaults to wxPython if not specified.
     48   Currently "wxp" (wxPython) only.
     49  --wxp=<version>
     50   Explicitely request a wxPython version. Can be set to either "2" or "3".
     51   Defaults to "try 3, then 2" if not set.
     52  --version, -V
     53   Show version information.
     54  --help, -h, or -?
     55   Show this help.
     56  """
     57  #==========================================================
     58  __author__ = "H. Herb <hherb@gnumed.net>, K. Hilbert <Karsten.Hilbert@gmx.net>, I. Haywood <i.haywood@ugrad.unimelb.edu.au>"
     59  __license__ = "GPL v2 or later (details at http://www.gnu.org)"
     60
     61
     62  # standard library
     63  import sys
     64  import os
     65  import platform
     66  import faulthandler
     67  import random
     68  import logging
     69  import signal
     70  import os.path
     71  import shutil
     72  import stat
     73  import io
     74
     75
     76  # do not run as module
     77  if __name__ != "__main__":
     78          print("GNUmed startup: This is not intended to be imported as a module !")
     79          print("-----------------------------------------------------------------")
     80          print(__doc__)
     81          sys.exit(1)
     82
     83
     84  # do not run as root
     85  if os.name in ['posix'] and os.geteuid() == 0:
     86          print("""
     87  GNUmed startup: GNUmed should not be run as root.
     88  -------------------------------------------------
     89
     90  Running GNUmed as <root> can potentially put all
     91  your medical data at risk. It is strongly advised
     92  against. Please run GNUmed as a non-root user.
     93  """)
     94          sys.exit(1)
     95
     96  #----------------------------------------------------------
     97  current_client_version = '1.8.rc1'
     98  current_client_branch = '1.8'
     99
    100  _log = None
    101  _pre_log_buffer = []
    102  _cfg = None
    103  _old_sig_term = None
    104  _known_short_options = 'h?V'
    105  _known_long_options = [
    106          'debug',
    107          'slave',
    108          'skip-update-check',
    109          'profile=',
    110          'text-domain=',
    111          'log-file=',
    112          'conf-file=',
    113          'lang-gettext=',
    114          'ui=',
    115          'override-schema-check',
    116          'local-import',
    117          'help',
    118          'version',
    119          'hipaa',
    120          'wxp=',
    121          'tool='
    122  ]
    123
    124  _known_ui_types = [
    125          'web',
    126          'wxp',
    127          'chweb'
    128  ]
    129
    130  _known_tools = [
    131          'check_enc_epi_xref',
    132          'export_pat_emr_structure'
    133  ]
    134
    135
    136  import_error_sermon = """
    137  GNUmed startup: Cannot load GNUmed Python modules !
    138  ---------------------------------------------------
    139  CRITICAL ERROR: Program halted.
    140
    141  Please make sure you have:
    142
    143   1) the required third-party Python modules installed
    144   2) the GNUmed Python modules linked or installed into site-packages/
    145      (if you do not run from a CVS tree the installer should have taken care of that)
    146   3) your PYTHONPATH environment variable set up correctly
    147
    148  <sys.path> is currently set to:
    149
    150   %s
    151
    152  If you are running from a copy of the CVS tree make sure you
    153  did run gnumed/check-prerequisites.sh with good results.
    154
    155  If you still encounter errors after checking the above
    156  requirements please ask on the mailing list.
    157  """
    158
    159
    160  missing_cli_config_file = """
    161  GNUmed startup: Missing configuration file.
    162  -------------------------------------------
    163
    164  You explicitly specified a configuration file
    165  on the command line:
    166
    167          --conf-file=%s
    168
    169  The file does not exist, however.
    170  """
    171
    172
    173  no_config_files = """
    174  GNUmed startup: Missing configuration files.
    175  --------------------------------------------
    176
    177  None of the below candidate configuration
    178  files could be found:
    179
    180   %s
    181
    182  Cannot run GNUmed without any of them.
    183  """
    184
    185  #==========================================================
    186  # convenience functions
    187  #----------------------------------------------------------
    188 -def _symlink_windows(source, link_name):
    189          import ctypes
    190          csl = ctypes.windll.kernel32.CreateSymbolicLinkW
    191          csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
    192          csl.restype = ctypes.c_ubyte
    193          if os.path.isdir(source):
    194                  flags = 1
    195          else:
    196                  flags = 0
    197          ret_code = csl(link_name, source.replace('/', '\\'), flags)
    198          if ret_code == 0:
    199                  raise ctypes.WinError()
    200          return ret_code
    201
    202  #==========================================================
    203  # startup helpers
    204  #----------------------------------------------------------
    205 -def setup_fault_handler(target=None):
    206          if target is None:
    207                  faulthandler.enable()
    208                  _pre_log_buffer.append('<faulthandler> enabled, target = [console]: %s' % faulthandler)
    209                  return
    210          _pre_log_buffer.append('<faulthandler> enabled, target = [%s]: %s' % (target, faulthandler))
    211          faulthandler.enable(file = target)
    212
    213  #==========================================================
    214 -def setup_console_encoding():
    215          print_lines = []
    216          try:
    217                  sys.stdout.reconfigure(errors = 'surrogateescape')
    218                  sys.stderr.reconfigure(errors = 'surrogateescape')
    219                  _pre_log_buffer.append('stdout/stderr reconfigured to use <surrogateescape> for encoding errors')
    220                  return
    221          except AttributeError:
    222                  line = 'cannot reconfigure sys.stdout/stderr to use <errors="surrogateescape"> (needs Python 3.7+)'
    223                  _pre_log_buffer.append(line)
    224                  print_lines.append(line)
    225          try:
    226                  _pre_log_buffer.append('sys.stdout/stderr default to "${PYTHONIOENCODING}=%s"' % os.environ['PYTHONIOENCODING'])
    227                  return
    228          except KeyError:
    229                  lines = [
    230                          '${PYTHONIOENCODING} is not set up, use <PYTHONIOENCODING=utf-8:surrogateescape> in the shell (for Python < 3.7)',
    231                          'console encoding errors may occur'
    232                  ]
    233                  for line in lines:
    234                          print_lines.append(line)
    235                          _pre_log_buffer.append(line)
    236                  for line in print_lines:
    237                          print('GNUmed startup:', line)
    238
    239  #==========================================================
    240 -def setup_python_path():
    241
    242          if not '--local-import' in sys.argv:
    243                  _pre_log_buffer.append('running against systemwide install')
    244                  return
    245
    246          local_python_import_dir = os.path.dirname (
    247                  os.path.abspath(os.path.join(sys.argv[0], '..'))
    248          )
    249          print("Running from local source tree (%s) ..." % local_python_import_dir)
    250          _pre_log_buffer.append("running from local source tree: %s" % local_python_import_dir)
    251
    252          # does the path exist at all, physically ?
    253          # (*broken* links are reported as False)
    254          link_name = os.path.join(local_python_import_dir, 'Gnumed')
    255          if os.path.exists(link_name):
    256                  _pre_log_buffer.append('local module import dir symlink exists: %s' % link_name)
    257          else:
    258                  real_dir = os.path.join(local_python_import_dir, 'client')
    259                  print('Creating local module import symlink ...')
    260                  print(' real dir:', real_dir)
    261                  print('     link:', link_name)
    262                  try:
    263                          os.symlink(real_dir, link_name)
    264                  except AttributeError:
    265                          _pre_log_buffer.append('Windows does not have os.symlink(), resorting to ctypes')
    266                          result = _symlink_windows(real_dir, link_name)
    267                          _pre_log_buffer.append('ctypes.windll.kernel32.CreateSymbolicLinkW() exit code: %s', result)
    268                  _pre_log_buffer.append('created local module import dir symlink: link [%s] => dir [%s]' % (link_name, real_dir))
    269
    270          sys.path.insert(0, local_python_import_dir)
    271          _pre_log_buffer.append('sys.path with local module import base dir prepended: %s' % sys.path)
    272
    273  #==========================================================
    274 -def setup_local_repo_path():
    275
    276          local_repo_path = os.path.expanduser(os.path.join (
    277                  '~',
    278                  '.gnumed',
    279                  'local_code',
    280                  str(current_client_branch)
    281          ))
    282          local_wxGladeWidgets_path = os.path.join(local_repo_path, 'Gnumed', 'wxGladeWidgets')
    283
    284          if not os.path.exists(local_wxGladeWidgets_path):
    285                  _log.debug('[%s] not found', local_wxGladeWidgets_path)
    286                  _log.info('local wxGlade widgets repository not available')
    287                  return
    288
    289          _log.info('local wxGlade widgets repository found:')
    290          _log.info(local_wxGladeWidgets_path)
    291
    292          if not os.access(local_wxGladeWidgets_path, os.R_OK):
    293                  _log.error('invalid repo: no read access')
    294                  return
    295
    296          all_entries = os.listdir(os.path.join(local_repo_path, 'Gnumed'))
    297          _log.debug('repo base contains: %s', all_entries)
    298          all_entries.remove('wxGladeWidgets')
    299          try:
    300                  all_entries.remove('__init__.py')
    301          except ValueError:
    302                  _log.error('invalid repo: lacking __init__.py')
    303                  return
    304          try:
    305                  all_entries.remove('__init__.pyc')
    306          except ValueError:
    307                  pass
    308
    309          if len(all_entries) > 0:
    310                  _log.error('insecure repo: additional files or directories found')
    311                  return
    312
    313          # repo must be 0700 (rwx------)
    314          stat_val = os.stat(local_wxGladeWidgets_path)
    315          _log.debug('repo stat(): %s', stat_val)
    316          perms = stat.S_IMODE(stat_val.st_mode)
    317          _log.debug('repo permissions: %s (octal: %s)', perms, oct(perms))
    318          if perms != 448:                                # octal 0700
    319                  if os.name in ['nt']:
    320                          _log.warning('this platform does not support os.stat() permission checking')
    321                  else:
    322                          _log.error('insecure repo: permissions not 0600')
    323                          return
    324
    325          print("Activating local wxGlade widgets repository (%s) ..." % local_wxGladeWidgets_path)
    326          sys.path.insert(0, local_repo_path)
    327          _log.debug('sys.path with repo:')
    328          _log.debug(sys.path)
    329
    330  #==========================================================
    331 -def setup_logging():
    332          try:
    333                  from Gnumed.pycommon import gmLog2 as _gmLog2
    334          except ImportError:
    335                  print(import_error_sermon % '\n '.join(sys.path))
    336                  sys.exit(1)
    337
    338          print("Log file:", _gmLog2._logfile.name)
    339          setup_fault_handler(target = _gmLog2._logfile)
    340
    341          global gmLog2
    342          gmLog2 = _gmLog2
    343
    344          global _log
    345          _log = logging.getLogger('gm.launcher')
    346
    347  #==========================================================
    348 -def log_startup_info():
    349          global _pre_log_buffer
    350          if len(_pre_log_buffer) > 0:
    351                  _log.info('early startup log buffer:')
    352          for line in _pre_log_buffer:
    353                  _log.info(' ' + line)
    354          del _pre_log_buffer
    355          _log.info('GNUmed client version [%s] on branch [%s]', current_client_version, current_client_branch)
    356          _log.info('Platform: %s', platform.uname())
    357          _log.info(('Python %s on %s (%s)' % (sys.version, sys.platform, os.name)).replace('\n', '<\\n>'))
    358          try:
    359                  import lsb_release
    360                  _log.info('lsb_release: %s', lsb_release.get_distro_information())
    361          except ImportError:
    362                  pass
    363          _log.info('os.getcwd(): [%s]', os.getcwd())
    364          _log.info('process environment:')
    365          for key, val in os.environ.items():
    366                  _log.info(' %s: %s' % (('${%s}' % key).rjust(30),       val))
    367
    368  #==========================================================
    369 -def setup_console_exception_handler():
    370          from Gnumed.pycommon.gmTools import handle_uncaught_exception_console
    371
    372          sys.excepthook = handle_uncaught_exception_console
    373
    374  #==========================================================
    375 -def setup_cli():
    376          from Gnumed.pycommon import gmCfg2
    377
    378          global _cfg
    379          _cfg = gmCfg2.gmCfgData()
    380          _cfg.add_cli (
    381                  short_options = _known_short_options,
    382                  long_options = _known_long_options
    383          )
    384
    385          val = _cfg.get(option = '--debug', source_order = [('cli', 'return')])
    386          if val is None:
    387                  val = False
    388          _cfg.set_option (
    389                  option = 'debug',
    390                  value = val
    391          )
    392
    393          val = _cfg.get(option = '--slave', source_order = [('cli', 'return')])
    394          if val is None:
    395                  val = False
    396          _cfg.set_option (
    397                  option = 'slave',
    398                  value = val
    399          )
    400
    401          val = _cfg.get(option = '--skip-update-check', source_order = [('cli', 'return')])
    402          if val is None:
    403                  val = False
    404          _cfg.set_option (
    405                  option = 'skip-update-check',
    406                  value = val
    407          )
    408
    409          val = _cfg.get(option = '--hipaa', source_order = [('cli', 'return')])
    410          if val is None:
    411                  val = False
    412          _cfg.set_option (
    413                  option = 'hipaa',
    414                  value = val
    415          )
    416
    417          val = _cfg.get(option = '--local-import', source_order = [('cli', 'return')])
    418          if val is None:
    419                  val = False
    420          _cfg.set_option (
    421                  option = 'local-import',
    422                  value = val
    423          )
    424
    425          _cfg.set_option (
    426                  option = 'client_version',
    427                  value = current_client_version
    428          )
    429
    430          _cfg.set_option (
    431                  option = 'client_branch',
    432                  value = current_client_branch
    433          )
    434
    435  #==========================================================
    436 -def handle_sig_term(signum, frame):
    437          _log.critical('SIGTERM (SIG%s) received, shutting down ...' % signum)
    438          gmLog2.flush()
    439          print('GNUmed: SIGTERM (SIG%s) received, shutting down ...' % signum)
    440          if frame is not None:
    441                  print('%s::%s@%s' % (frame.f_code.co_filename, frame.f_code.co_name, frame.f_lineno))
    442
    443          # FIXME: need to do something useful here
    444
    445          if _old_sig_term in [None, signal.SIG_IGN]:
    446                  sys.exit(1)
    447          else:
    448                  _old_sig_term(signum, frame)
    449
    450  #----------------------------------------------------------
    451 -def setup_signal_handlers():
    452          global _old_sig_term
    453          old_sig_term = signal.signal(signal.SIGTERM, handle_sig_term)
    454
    455  #==========================================================
    456 -def setup_locale():
    457          gmI18N.activate_locale()
    458
    459          td = _cfg.get(option = '--text-domain', source_order = [('cli', 'return')])
    460          l =  _cfg.get(option = '--lang-gettext', source_order = [('cli', 'return')])
    461          gmI18N.install_domain(domain = td, language = l, prefer_local_catalog = _cfg.get(option = 'local-import'))
    462
    463  #       # make sure we re-get the default encoding
    464  #       # in case it changed
    465  #       gmLog2.set_string_encoding()
    466
    467  #==========================================================
    468 -def handle_help_request():
    469          src = [('cli', 'return')]
    470
    471          help_requested = (
    472                  _cfg.get(option = '--help', source_order = src) or
    473                  _cfg.get(option = '-h', source_order = src) or
    474                  _cfg.get(option = '-?', source_order = src)
    475          )
    476
    477          if help_requested:
    478                  print(_(
    479                          'Help requested\n'
    480                          '--------------'
    481                  ))
    482                  print(__doc__)
    483                  sys.exit(0)
    484
    485  #==========================================================
    486 -def handle_version_request():
    487          src = [('cli', 'return')]
    488
    489          version_requested = (
    490                  _cfg.get(option = '--version', source_order = src) or
    491                  _cfg.get(option = '-V', source_order = src)
    492          )
    493
    494          if version_requested:
    495
    496                  from Gnumed.pycommon.gmPG2 import map_client_branch2required_db_version, known_schema_hashes
    497
    498                  print('GNUmed version information')
    499                  print('--------------------------')
    500                  print('client     : %s on branch [%s]' % (current_client_version, current_client_branch))
    501                  print('database   : %s' % map_client_branch2required_db_version[current_client_branch])
    502                  print('schema hash: %s' % known_schema_hashes[map_client_branch2required_db_version[current_client_branch]])
    503                  sys.exit(0)
    504
    505  #==========================================================
    506 -def setup_paths_and_files():
    507          """Create needed paths in user home directory."""
    508
    509          gnumed_DIR_README_TEXT = """GNUmed Electronic Medical Record
    510
    511          %s/
    512
    513  This directory should only ever contain files which the
    514  user will come into direct contact with while using the
    515  application (say, by selecting a file from the file system,
    516  as when selecting document parts from files). You can create
    517  subdirectories here as you see fit for the purpose.
    518
    519  This directory will also serve as the default directory when
    520  GNUmed asks the user to select a directory for storing a
    521  file.
    522
    523  Any files which are NOT intended for direct user interaction
    524  but must be configured to live at a known location (say,
    525  inter-application data exchange files) should be put under
    526  the hidden directory "%s/".""" % (
    527                  os.path.expanduser(os.path.join('~', 'gnumed')),
    528                  os.path.expanduser(os.path.join('~', '.gnumed'))
    529          )
    530
    531          gmTools.mkdir(os.path.expanduser(os.path.join('~', '.gnumed', 'scripts')))
    532          gmTools.mkdir(os.path.expanduser(os.path.join('~', '.gnumed', 'spellcheck')))
    533          gmTools.mkdir(os.path.expanduser(os.path.join('~', '.gnumed', 'error_logs')))
    534          gmTools.mkdir(os.path.expanduser(os.path.join('~', 'gnumed')))
    535
    536          README = io.open(os.path.expanduser(os.path.join('~', 'gnumed', '00_README')), mode = 'wt', encoding = 'utf8')
    537          README.write(gnumed_DIR_README_TEXT)
    538          README.close()
    539
    540          # wxPython not available yet
    541          paths = gmTools.gmPaths(app_name = 'gnumed')
    542          print("Temp dir:", paths.tmp_dir)
    543
    544          # ensure there's a user-level config file
    545          io.open(os.path.expanduser(os.path.join('~', '.gnumed', 'gnumed.conf')), mode = 'a+t').close()
    546
    547          # symlink log file into temporary directory for easier debugging (everything in one place)
    548          logfile_link = os.path.join(paths.tmp_dir, 'zzz-gnumed.log')
    549          gmTools.mklink (gmLog2._logfile.name, logfile_link, overwrite = False)
    550
    551  #==========================================================
    552 -def setup_date_time():
    553          gmDateTime.init()
    554
    555  #==========================================================
    556 -def setup_cfg():
    557          """Detect and setup access to GNUmed config file.
    558
    559          Parts of this will have limited value due to
    560          wxPython not yet being available.
    561          """
    562
    563          enc = gmI18N.get_encoding()
    564          paths = gmTools.gmPaths(app_name = 'gnumed')
    565
    566          candidates = [
    567                  # the current working dir
    568                  ['workbase', os.path.join(paths.working_dir, 'gnumed.conf')],
    569                  # /etc/gnumed/
    570                  ['system', os.path.join(paths.system_config_dir, 'gnumed-client.conf')],
    571                  # ~/.gnumed/
    572                  ['user', os.path.join(paths.user_config_dir, 'gnumed.conf')],
    573                  # CVS/tgz tree .../gnumed/client/ (IOW a local installation)
    574                  ['local', os.path.join(paths.local_base_dir, 'gnumed.conf')]
    575          ]
    576          # --conf-file=
    577          explicit_fname = _cfg.get(option = '--conf-file', source_order = [('cli', 'return')])
    578          if explicit_fname is None:
    579                  candidates.append(['explicit', None])
    580          else:
    581                  candidates.append(['explicit', explicit_fname])
    582
    583          for candidate in candidates:
    584                  _cfg.add_file_source (
    585                          source = candidate[0],
    586                          file = candidate[1],
    587                          encoding = enc
    588                  )
    589
    590          # --conf-file given but does not actually exist ?
    591          if explicit_fname is not None:
    592                  if _cfg.source_files['explicit'] is None:
    593                          _log.error('--conf-file argument does not exist')
    594                          print(missing_cli_config_file % explicit_fname)
    595                          sys.exit(1)
    596
    597          # any config file found at all ?
    598          found_any_file = False
    599          for f in _cfg.source_files.values():
    600                  if f is not None:
    601                          found_any_file = True
    602                          break
    603          if not found_any_file:
    604                  _log.error('no config file found at all')
    605                  print(no_config_files % '\n '.join(candidates))
    606                  sys.exit(1)
    607
    608          # mime type handling sources
    609          fname = 'mime_type2file_extension.conf'
    610          _cfg.add_file_source (
    611                  source = 'user-mime',
    612                  file = os.path.join(paths.user_config_dir, fname),
    613                  encoding = enc
    614          )
    615          _cfg.add_file_source (
    616                  source = 'system-mime',
    617                  file = os.path.join(paths.system_config_dir, fname),
    618                  encoding = enc
    619          )
    620
    621  #==========================================================
    622 -def setup_ui_type():
    623          global ui_type
    624          ui_type = _cfg.get(option = '--ui', source_order = [('cli', 'return')])
    625          if ui_type in [True, False, None]:
    626                  ui_type = 'wxp'
    627          ui_type = ui_type.strip()
    628          if ui_type not in _known_ui_types:
    629                  _log.error('unknown UI type requested: %s', ui_type)
    630                  _log.debug('known UI types are: %s', str(_known_ui_types))
    631                  print("GNUmed startup: Unknown UI type (%s). Defaulting to wxPython client." % ui_type)
    632                  ui_type = 'wxp'
    633          _log.debug('UI type: %s', ui_type)
    634
    635  #==========================================================
    636 -def setup_backend_environment():
    637
    638          db_version = gmPG2.map_client_branch2required_db_version[current_client_branch]
    639          _log.info('client expects database version [%s]', db_version)
    640          _cfg.set_option (
    641                  option = 'database_version',
    642                  value = db_version
    643          )
    644
    645          # set up database connection timezone
    646          timezone = _cfg.get (
    647                  group = 'backend',
    648                  option = 'client timezone',
    649                  source_order = [
    650                          ('explicit', 'return'),
    651                          ('workbase', 'return'),
    652                          ('local', 'return'),
    653                          ('user', 'return'),
    654                          ('system', 'return')
    655                  ]
    656          )
    657          if timezone is not None:
    658                  gmPG2.set_default_client_timezone(timezone)
    659
    660  #==========================================================
    661 -def run_gui():
    662          gmHooks.run_hook_script(hook = 'startup-before-GUI')
    663
    664          if ui_type == 'wxp':
    665                  from Gnumed.wxpython import gmGuiMain
    666                  profile_file = _cfg.get(option = '--profile', source_order = [('cli', 'return')])
    667                  if profile_file is not None:
    668                          _log.info('writing profiling data into %s', profile_file)
    669                          import profile
    670                          profile.run('gmGuiMain.main()', profile_file)
    671                  else:
    672                          gmGuiMain.main()
    673          #elif ui_type == u'web':
    674          #       from Gnumed.proxiedpyjamas import gmWebGuiServer
    675          #       gmWebGuiServer.main()
    676          #elif ui_type == u'chweb':
    677          #       from Gnumed.CherryPy import gmGuiWeb
    678          #       gmGuiWeb.main()
    679
    680          gmHooks.run_hook_script(hook = 'shutdown-post-GUI')
    681
    682          return 0
    683
    684  #==========================================================
    685 -def run_tool():
    686          tool = _cfg.get(option = '--tool', source_order = [('cli', 'return')])
    687          if tool is None:
    688                  # not running a tool
    689                  return None
    690
    691          if tool not in _known_tools:
    692                  _log.error('unknown tool requested: %s', tool)
    693                  print('GNUmed startup: Unknown tool [%s] requested.' % tool)
    694                  print('GNUmed startup: Known tools: %s' % _known_tools)
    695                  return -1
    696
    697          print('')
    698          print('==============================================')
    699          print('Running tool: %s' % tool)
    700          print('----------------------------------------------')
    701          print('')
    702
    703          if tool == 'check_enc_epi_xref':
    704                  from Gnumed.business import gmEMRStructItems
    705                  return gmEMRStructItems.check_fk_encounter_fk_episode_x_ref()
    706
    707          if tool == 'export_pat_emr_structure':
    708                  # setup praxis
    709                  from Gnumed.business import gmPraxis
    710                  praxis = gmPraxis.gmCurrentPraxisBranch(branch = gmPraxis.get_praxis_branches()[0])
    711                  # get patient
    712                  from Gnumed.business import gmPersonSearch
    713                  pat = gmPersonSearch.ask_for_patient()
    714                  # setup exporters
    715                  from Gnumed.business import gmEMRStructItems
    716                  from Gnumed.exporters import gmTimelineExporter
    717                  from Gnumed.exporters import gmPatientExporter
    718                  while pat is not None:
    719                          print('patient:', pat['description_gender'])
    720                          # as EMR structure
    721                          fname = os.path.expanduser('~/gnumed/gm-emr_structure-%s.txt' % pat.subdir_name)
    722                          print('EMR structure:', gmEMRStructItems.export_emr_structure(patient = pat, filename = fname))
    723                          # as timeline
    724                          fname = os.path.expanduser('~/gnumed/gm-emr-%s.timeline' % pat.subdir_name)
    725                          try:
    726                                  print('EMR timeline:', gmTimelineExporter.create_timeline_file (
    727                                          patient = pat,
    728                                          filename = fname,
    729                                          include_documents = True,
    730                                          include_vaccinations = True,
    731                                          include_encounters = True
    732                                  ))
    733                          finally:
    734                                  pass
    735                          # as journal by encounter
    736                          exporter = gmPatientExporter.cEMRJournalExporter()
    737                          fname = os.path.expanduser('~/gnumed/gm-emr-journal_by_encounter-%s.txt' % pat.subdir_name)
    738                          print('EMR journal (by encounter):', exporter.save_to_file_by_encounter(patient = pat, filename = fname))
    739                          # as journal by mod time
    740                          fname = os.path.expanduser('~/gnumed/gm-emr-journal_by_mod_time-%s.txt' % pat.subdir_name)
    741                          print('EMR journal (by mod time):', exporter.save_to_file_by_mod_time(patient = pat, filename = fname))
    742                          # as statistical summary
    743                          fname = os.path.expanduser('~/gnumed/gm-emr-statistics-%s.txt' % pat.subdir_name)
    744                          output_file = io.open(fname, mode = 'wt', encoding = 'utf8', errors = 'replace')
    745                          emr = pat.emr
    746                          output_file.write(emr.format_statistics())
    747                          output_file.close()
    748                          print('EMR statistics:', fname)
    749                          # as text file
    750                          exporter = gmPatientExporter.cEmrExport(patient = pat)
    751                          fname = os.path.expanduser('~/gnumed/gm-emr-text_export-%s.txt' % pat.subdir_name)
    752                          output_file = io.open(fname, mode = 'wt', encoding = 'utf8', errors = 'replace')
    753                          exporter.set_output_file(output_file)
    754                          exporter.dump_constraints()
    755                          exporter.dump_demographic_record(True)
    756                          exporter.dump_clinical_record()
    757                          exporter.dump_med_docs()
    758                          output_file.close()
    759                          print('EMR text file:', fname)
    760                          # another patient ?
    761                          pat = gmPersonSearch.ask_for_patient()
    762
    763                  return 0
    764
    765          # tool export_patient_as (vcf, gdt, ...)
    766          #if tool == 'export_pat_demographics':
    767
    768          # should not happen (because checked against _known_tools)
    769          return -1
    770
    771  #==========================================================
    772  # shutdown helpers
    773  #----------------------------------------------------------
    774 -def shutdown_backend():
    775          gmPG2.shutdown()
    776
    777  #==========================================================
    778 -def shutdown_logging():
    779
    780  #       if _cfg.get(option = u'debug'):
    781  #               import types
    782
    783  #               def get_refcounts():
    784  #                       refcount = {}
    785  #                       # collect all classes
    786  #                       for module in sys.modules.values():
    787  #                               for sym in dir(module):
    788  #                                       obj = getattr(module, sym)
    789  #                                       if type(obj) is types.ClassType:
    790  #                                               refcount[obj] = sys.getrefcount(obj)
    791  #                       # sort by refcount
    792  #                       pairs = map(lambda x: (x[1],x[0]), refcount.items())
    793  #                       pairs.sort()
    794  #                       pairs.reverse()
    795  #                       return pairs
    796
    797  #               rcfile = io.open('./gm-refcount.lst', 'wt', encoding = 'utf8')
    798  #               for refcount, class_ in get_refcounts():
    799  #                       if not class_.__name__.startswith('wx'):
    800  #                               rcfile.write(u'%10d %s\n' % (refcount, class_.__name__))
    801  #               rcfile.close()
    802
    803          # do not choke on Windows
    804          logging.raiseExceptions = False
    805
    806  #==========================================================
    807 -def shutdown_tmp_dir():
    808
    809          tmp_dir = gmTools.gmPaths().tmp_dir
    810
    811          if _cfg.get(option = 'debug'):
    812                  _log.debug('not removing tmp dir (--debug mode): %s', tmp_dir)
    813                  return
    814
    815          _log.warning('removing tmp dir: %s', tmp_dir)
    816          shutil.rmtree(tmp_dir, True)
    817
    818  #==========================================================
    819  # main - launch the GNUmed wxPython GUI client
    820  #----------------------------------------------------------
    821
    822  random.seed()
    823
    824  # setup
    825  setup_fault_handler(target = None)
    826  setup_console_encoding()
    827  setup_python_path()
    828  setup_logging()
    829  log_startup_info()
    830  setup_console_exception_handler()
    831  setup_cli()
    832  setup_signal_handlers()
    833  setup_local_repo_path()
    834
    835  from Gnumed.pycommon import gmI18N
    836  from Gnumed.pycommon import gmTools
    837  from Gnumed.pycommon import gmDateTime
    838
    839  setup_locale()
    840  handle_help_request()
    841  handle_version_request()
    842  setup_paths_and_files()
    843  setup_date_time()
    844  setup_cfg()
    845  setup_ui_type()
    846
    847  from Gnumed.pycommon import gmPG2
    848  if ui_type in ['web']:
    849          gmPG2.auto_request_login_params = False
    850  setup_backend_environment()
    851
    852  # main
    853  exit_code = run_tool()
    854  if exit_code is None:
    855          from Gnumed.pycommon import gmHooks
    856          exit_code = run_gui()
    857
    858  # shutdown
    859  shutdown_backend()
    860  shutdown_tmp_dir()
    861  _log.info('Normally shutting down as main module.')
    862  shutdown_logging()
    863
    864  sys.exit(exit_code)
    865
    866  #==========================================================
    867