[med-svn] [gnumed-server] 01/06: Imported Upstream version 20.8
Andreas Tille
tille at debian.org
Wed Dec 16 15:43:26 UTC 2015
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository gnumed-server.
commit 324056f7a32aa22556a630add3fa2ca54dbce543
Author: Andreas Tille <tille at debian.org>
Date: Tue Nov 10 08:10:59 2015 +0100
Imported Upstream version 20.8
---
server/doc/schema/gnumed-entire_schema.html | 2 +-
server/pycommon/gmBackendListener.py | 4 +-
server/pycommon/gmBorg.py | 43 +-------
server/pycommon/gmBusinessDBObject.py | 27 +++--
server/pycommon/gmNull.py | 108 ++++++++-----------
server/pycommon/gmPG2.py | 7 +-
server/pycommon/gmTools.py | 116 +++++++++++++++++++--
.../v19-v20/dynamic/v20-release_notes-dynamic.sql | 15 ++-
8 files changed, 185 insertions(+), 137 deletions(-)
diff --git a/server/doc/schema/gnumed-entire_schema.html b/server/doc/schema/gnumed-entire_schema.html
index 3e7c538..ac003b1 100644
--- a/server/doc/schema/gnumed-entire_schema.html
+++ b/server/doc/schema/gnumed-entire_schema.html
@@ -112,7 +112,7 @@
<body>
<!-- Primary Index -->
- <p><br><br>Dumped on 2015-07-08</p>
+ <p><br><br>Dumped on 2015-10-11</p>
<h1><a name="index">Index of database - gnumed_v20</a></h1>
<ul>
diff --git a/server/pycommon/gmBackendListener.py b/server/pycommon/gmBackendListener.py
index ca9fac5..665f029 100644
--- a/server/pycommon/gmBackendListener.py
+++ b/server/pycommon/gmBackendListener.py
@@ -57,7 +57,7 @@ class gmBackendListener(gmBorg.cBorg):
self._conn = conn
self.backend_pid = self._conn.get_backend_pid()
- _log.debug('connection has backend PID [%s]', self.backend_pid)
+ _log.debug('notification listener connection has backend PID [%s]', self.backend_pid)
self._conn.set_isolation_level(0) # autocommit mode = psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT
self._cursor = self._conn.cursor()
try:
@@ -217,7 +217,7 @@ class gmBackendListener(gmBorg.cBorg):
self.__notifications_received += 1
if self.debug:
print notification
- _log.debug('#%s: %s', self.__notifications_received, notification)
+ _log.debug('#%s: %s (first param is PID of sending backend)', self.__notifications_received, notification)
# decode payload
payload = notification.payload.split(u'::')
operation = None
diff --git a/server/pycommon/gmBorg.py b/server/pycommon/gmBorg.py
index 37132c2..76864b2 100644
--- a/server/pycommon/gmBorg.py
+++ b/server/pycommon/gmBorg.py
@@ -1,10 +1,8 @@
#===================================================
# Thanks to Python Patterns !
# ---------------------------
-# $Id: gmBorg.py,v 1.7 2009-05-08 07:58:35 ncq Exp $
-__version__ = "$Revision: 1.7 $"
__author__ = "Karsten.Hilbert at gmx.net"
-__license__ = "GPL"
+__license__ = "GPL v2 or later"
#===================================================
class cBorg(object):
@@ -12,7 +10,7 @@ class cBorg(object):
- mixin this class with your class' ancestors to borg it
- - there may be many instances of this - PER CHILD CLASS - but they all share state
+ - there may be many _instances_ of this - PER CHILD CLASS - but they all share _state_
"""
_instances = {}
@@ -22,6 +20,7 @@ class cBorg(object):
#cBorg._instances[cls] = object.__new__(cls, *args, **kargs)
cBorg._instances[cls] = object.__new__(cls)
return cBorg._instances[cls]
+
#===================================================
if __name__ == '__main__':
@@ -57,39 +56,3 @@ if __name__ == '__main__':
print c3.x
#===================================================
-# $Log: gmBorg.py,v $
-# Revision 1.7 2009-05-08 07:58:35 ncq
-# - __new__ doesn't take args anymore
-#
-# Revision 1.6 2008/05/21 13:57:57 ncq
-# - remove old borg
-#
-# Revision 1.5 2007/10/23 21:23:30 ncq
-# - cleanup
-#
-# Revision 1.4 2007/09/24 22:05:23 ncq
-# - improved docs
-#
-# Revision 1.3 2007/05/11 14:14:59 ncq
-# - make borg per-sublcass
-#
-# Revision 1.2 2007/05/07 12:30:05 ncq
-# - make cBorg an object child so properties work on it
-#
-# Revision 1.1 2004/02/25 09:30:13 ncq
-# - moved here from python-common
-#
-# Revision 1.3 2003/12/29 16:21:51 uid66147
-# - spelling fix
-#
-# Revision 1.2 2003/11/17 10:56:35 sjtan
-#
-# synced and commiting.
-#
-# Revision 1.1 2003/10/23 06:02:38 sjtan
-#
-# manual edit areas modelled after r.terry's specs.
-#
-# Revision 1.1 2003/04/02 16:07:55 ncq
-# - first version
-#
diff --git a/server/pycommon/gmBusinessDBObject.py b/server/pycommon/gmBusinessDBObject.py
index 7aadbde..19589f9 100644
--- a/server/pycommon/gmBusinessDBObject.py
+++ b/server/pycommon/gmBusinessDBObject.py
@@ -141,7 +141,9 @@ if __name__ == '__main__':
from Gnumed.pycommon import gmExceptions
from Gnumed.pycommon import gmPG2
from Gnumed.pycommon.gmDateTime import pydt_strftime
-from Gnumed.pycommon.gmTools import tex_escape_string, xetex_escape_string
+from Gnumed.pycommon.gmTools import tex_escape_string, xetex_escape_string, compare_dict_likes
+from Gnumed.pycommon.gmTools import xetex_escape_string
+from Gnumed.pycommon.gmTools import compare_dict_likes
_log = logging.getLogger('gm.db')
@@ -483,7 +485,7 @@ def delete_xxx(pk_XXX=None):
#--------------------------------------------------------
def fields_as_dict(self, date_format='%Y %b %d %H:%M', none_string=u'', escape_style=None, bool_strings=None):
if bool_strings is None:
- bools = {True: u'true', False: u'false'}
+ bools = {True: u'True', False: u'False'}
else:
bools = {True: bool_strings[0], False: bool_strings[1]}
data = {}
@@ -501,6 +503,9 @@ def delete_xxx(pk_XXX=None):
continue
if isinstance(val, datetime.datetime):
+ if date_format is None:
+ data[field] = val
+ continue
data[field] = pydt_strftime(val, format = date_format, encoding = 'utf8')
if escape_style in [u'latex', u'tex']:
data[field] = tex_escape_string(data[field])
@@ -534,10 +539,11 @@ def delete_xxx(pk_XXX=None):
"""Fetch field values from backend.
"""
if self._is_modified:
+ compare_dict_likes(self.original_payload, self.fields_as_dict(date_format = None, none_string = None), u'original payload', u'modified payload')
if ignore_changes:
_log.critical('[%s:%s]: loosing payload changes' % (self.__class__.__name__, self.pk_obj))
- _log.debug('original: %s' % self.original_payload)
- _log.debug('modified: %s' % self._payload)
+ #_log.debug('original: %s' % self.original_payload)
+ #_log.debug('modified: %s' % self._payload)
else:
_log.critical('[%s:%s]: cannot reload, payload changed' % (self.__class__.__name__, self.pk_obj))
return False
@@ -604,10 +610,11 @@ def delete_xxx(pk_XXX=None):
if len(rows) == 0:
return (False, (u'cannot update row', _('[%s:%s]: row not updated (nothing returned), row in use ?') % (self.__class__.__name__, self.pk_obj)))
- # update cached values from should-be-first-and-only result
- # row of last query,
+ # update cached values from should-be-first-and-only
+ # result row of last query,
# update all fields returned such that computed
- # columns see their new values
+ # columns see their new values (given they are
+ # returned by the query)
row = rows[0]
for key in idx:
try:
@@ -621,10 +628,14 @@ def delete_xxx(pk_XXX=None):
_log.error(args)
raise
+ # only at conn.commit() time will data actually
+ # get committed (and thusly trigger based notifications
+ # be sent out), so reset the local modification flag
+ # right before that
+ self._is_modified = False
conn.commit()
close_conn()
- self._is_modified = False
# update to new "original" payload
self.original_payload = {}
for field in self._idx.keys():
diff --git a/server/pycommon/gmNull.py b/server/pycommon/gmNull.py
index 1ac21e9..2bc48a3 100644
--- a/server/pycommon/gmNull.py
+++ b/server/pycommon/gmNull.py
@@ -35,19 +35,19 @@ combinations of these words: Null, object, design and pattern.
Dinu C. Gherman,
August 2001
-For modifications see CVS changelog below.
-
Karsten Hilbert
July 2004
"""
#==============================================================
-# $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/pycommon/gmNull.py,v $
-__version__ = "$Revision: 1.6 $"
-__author__ = "Dinu C. Gherman"
+__author__ = "Dinu C. Gherman, Karsten Hilbert"
__license__ = "GPL v2 or later (details at http://www.gnu.org)"
+import logging
+
+_log = logging.getLogger('cNull')
+
#==============================================================
-class cNull:
+class cNull(object):
"""A class for implementing Null objects.
This class ignores all parameters passed when constructing or
@@ -61,69 +61,67 @@ class cNull:
on the environment and, hence, these special methods are not
provided here.
"""
- _warn = 0
-
# object constructing
-
def __init__(self, *args, **kwargs):
"Ignore parameters."
- try:
- cNull._warn = kwargs['warn']
- except KeyError:
- pass
- return None
+ _log.debug(u'args: %s', args)
+ _log.debug(u'kwargs: %s', kwargs)
# object calling
-
def __call__(self, *args, **kwargs):
"Ignore method calls."
- if cNull._warn:
- print "cNull.__call__()"
+ _log.debug(u'args: %s', args)
+ _log.debug(u'kwargs: %s', kwargs)
return self
# attribute handling
-
- def __getattr__(self, mname):
+ def __getattr__(self, attribute):
"Ignore attribute requests."
- if cNull._warn:
- print "cNull.__getattr__()"
+ _log.debug(u'%s.%s', self, attribute)
return self
- def __setattr__(self, name, value):
+ def __setattr__(self, attribute, value):
"Ignore attribute setting."
- if cNull._warn:
- print "cNull.__setattr__()"
+ _log.debug(u'%s.%s = %s', self, attribute, value)
return self
- def __delattr__(self, name):
+ def __delattr__(self, attribute):
"Ignore deleting attributes."
- if cNull._warn:
- print "cNull.__delattr__()"
+ _log.debug(u'%s.%s', self, attribute)
return self
- # misc.
+ # item handling
+ def __getitem__(self, item):
+ "Ignore item requests."
+ _log.debug(u'%s[%s]', self, item)
+ return self
+
+ def __setitem__(self, item, value):
+ "Ignore item setting."
+ _log.debug(u'%s[%s] = %s', self, item, value)
+ return self
+ def __delitem__(self, item):
+ "Ignore deleting items."
+ _log.debug(u'%s[%s]', self, item)
+ return self
+
+ # misc.
def __repr__(self):
"Return a string representation."
- if cNull._warn:
- print "cNull.__repr__()"
return "<cNull instance @ %s>" % id(self)
def __str__(self):
"Convert to a string and return it."
- if cNull._warn:
- print "cNull.__str__()"
- return "cNull instance"
+ return 'cNull instance'
def __nonzero__(self):
- if cNull._warn:
- print "cNull.__nonzero__()"
+ _log.debug(u'returns 0')
return 0
-
+
def __len__(self):
- if cNull._warn:
- print "cNull.__len__()"
- return 0
+ _log.debug(u'0')
+ return 0
#==============================================================
def test():
@@ -133,7 +131,7 @@ def test():
n = cNull()
n = cNull('value')
- n = cNull('value', param='value', warn=1)
+ n = cNull('value', param='value')
n()
n('value')
@@ -154,6 +152,10 @@ def test():
n.attr1 = 'value'
n.attr1.attr2 = 'value'
+ n['1']
+ n['2'] = '123'
+ del n['3']
+
del n.attr1
del n.attr1.attr2.attr3
@@ -167,29 +169,7 @@ def test():
print "Null object == 1"
else:
print "Null object != 1"
-#--------------------------------------------------------------
-if __name__ == '__main__':
- test()
#==============================================================
-# $Log: gmNull.py,v $
-# Revision 1.6 2005-06-28 14:12:55 cfmoro
-# Integration in space fixes
-#
-# Revision 1.5 2004/12/22 08:40:01 ncq
-# - make output more obvious
-#
-# Revision 1.4 2004/11/24 15:49:11 ncq
-# - use 0/1 not False/True so we can run on older pythons
-#
-# Revision 1.3 2004/08/20 08:38:47 ncq
-# - robustify while working on allowing inactive patient after search
-#
-# Revision 1.2 2004/07/21 07:51:47 ncq
-# - tabified
-# - __nonzero__ added
-# - if keyword argument 'warn' is True: warn on use of Null class
-#
-# Revision 1.1 2004/07/06 00:08:31 ncq
-# - null design pattern from python cookbook
-#
+if __name__ == '__main__':
+ test()
diff --git a/server/pycommon/gmPG2.py b/server/pycommon/gmPG2.py
index da71465..4e9317b 100644
--- a/server/pycommon/gmPG2.py
+++ b/server/pycommon/gmPG2.py
@@ -353,7 +353,7 @@ where
curs.execute(cmd, args)
rows = curs.fetchall()
if len(rows) > 0:
- result = rows[0][0]
+ result = rows[0]['name']
_log.debug(u'[%s] maps to [%s]', timezone, result)
except:
_log.exception(u'cannot expand timezone abbreviation [%s]', timezone)
@@ -1603,6 +1603,7 @@ def get_raw_connection(dsn=None, verbose=False, readonly=True):
try:
conn = dbapi.connect(dsn=dsn, connection_factory=psycopg2.extras.DictConnection)
+ #conn = dbapi.connect(dsn=dsn, cursor_factory=psycopg2.extras.RealDictCursor)
except dbapi.OperationalError, e:
t, v, tb = sys.exc_info()
@@ -1930,7 +1931,7 @@ def _log_PG_settings(curs=None):
_log.error(u'cannot log PG settings (>>>show all<<< did not return rows)')
return False
for setting in settings:
- _log.debug(u'PG option [%s]: %s', setting[0], setting[1])
+ _log.debug(u'PG option [%s]: %s', setting['name'], setting['setting'])
try:
curs.execute(u'select pg_available_extensions()')
@@ -1942,7 +1943,7 @@ def _log_PG_settings(curs=None):
_log.error(u'no PG extensions available')
return False
for ext in extensions:
- _log.debug(u'PG extension: %s', ext[0])
+ _log.debug(u'PG extension: %s', ext['pg_available_extensions'])
return True
#========================================================================
diff --git a/server/pycommon/gmTools.py b/server/pycommon/gmTools.py
index 263330a..de090ee 100644
--- a/server/pycommon/gmTools.py
+++ b/server/pycommon/gmTools.py
@@ -6,13 +6,21 @@ __author__ = "K. Hilbert <Karsten.Hilbert at gmx.net>"
__license__ = "GPL v2 or later (details at http://www.gnu.org)"
# std libs
-import re as regex, sys, os, os.path, csv, tempfile, logging, hashlib
+import sys
+import os
+import os.path
+import csv
+import tempfile
+import logging
+import hashlib
import platform
import subprocess
import decimal
import getpass
-import cPickle, zlib
+import re as regex
import xml.sax.saxutils as xml_tools
+# old:
+import cPickle, zlib
# GNUmed libs
@@ -95,6 +103,12 @@ u_kanji_yen = u'\u5186' # Yen kanji
u_replacement_character = u'\ufffd'
u_link_symbol = u'\u1f517'
+_kB = 1024
+_MB = 1024 * _kB
+_GB = 1024 * _MB
+_TB = 1024 * _GB
+_PB = 1024 * _TB
+
#===========================================================================
def handle_uncaught_exception_console(t, v, tb):
@@ -105,6 +119,7 @@ def handle_uncaught_exception_console(t, v, tb):
print "`========================================================"
_log.critical('unhandled exception caught', exc_info = (t,v,tb))
sys.__excepthook__(t,v,tb)
+
#===========================================================================
# path level operations
#---------------------------------------------------------------------------
@@ -358,6 +373,7 @@ class gmPaths(gmBorg.cBorg):
return self.__tmp_dir
tmp_dir = property(_get_tmp_dir, _set_tmp_dir)
+
#===========================================================================
# file related tools
#---------------------------------------------------------------------------
@@ -396,6 +412,7 @@ def gpg_decrypt_file(filename=None, passphrase=None):
return None
return filename_decrypted
+
#---------------------------------------------------------------------------
def file2md5(filename=None, return_hex=True):
blocksize = 2**10 * 128 # 128k, since md5 uses 128 byte blocks
@@ -415,6 +432,26 @@ def file2md5(filename=None, return_hex=True):
if return_hex:
return md5.hexdigest()
return md5.digest()
+
+#---------------------------------------------------------------------------
+def file2chunked_md5(filename=None, chunk_size=500*_MB):
+ _log.debug('chunked_md5(%s, chunk_size=%s bytes)', filename, chunk_size)
+ md5_concat = u''
+ f = open(filename, 'rb')
+ while True:
+ md5 = hashlib.md5()
+ data = f.read(chunk_size)
+ if not data:
+ break
+ md5.update(data)
+ md5_concat += md5.hexdigest()
+ f.close()
+ md5 = hashlib.md5()
+ md5.update(md5_concat)
+ hex_digest = md5.hexdigest()
+ _log.debug('md5("%s"): %s', md5_concat, hex_digest)
+ return hex_digest
+
#---------------------------------------------------------------------------
def unicode2charset_encoder(unicode_csv_data, encoding='utf-8'):
for line in unicode_csv_data:
@@ -498,6 +535,7 @@ def get_unique_filename(prefix=None, suffix=None, tmp_dir=None):
f.close()
return filename
+
#===========================================================================
def import_module_from_directory(module_path=None, module_name=None, always_remove_path=False):
"""Import a module from any location."""
@@ -529,15 +567,10 @@ def import_module_from_directory(module_path=None, module_name=None, always_remo
sys.path.remove(module_path)
return module
+
#===========================================================================
# text related tools
#---------------------------------------------------------------------------
-_kB = 1024
-_MB = 1024 * _kB
-_GB = 1024 * _MB
-_TB = 1024 * _GB
-_PB = 1024 * _TB
-#---------------------------------------------------------------------------
def size2str(size=0, template=u'%s'):
if size == 1:
return template % _('1 Byte')
@@ -856,6 +889,44 @@ def html_escape_string(text=None):
return "".join(__html_escape_table.get(char, char) for char in text)
#---------------------------------------------------------------------------
+#---------------------------------------------------------------------------
+def compare_dict_likes(d1, d2, title1=None, title2=None):
+ _log.info('comparing dict-likes: %s[%s] vs %s[%s]', coalesce(title1, u'', u'"%s" '), type(d1), coalesce(title2, u'', u'"%s" '), type(d2))
+ k1 = frozenset(d1)
+ k2 = frozenset(d2)
+ different = False
+ if len(k1) != len(k2):
+ _log.info('different number of keys: %s vs %s', len(k1), len(k2))
+ different = True
+ for key in k1:
+ if key in k2:
+ if type(d1[key]) != type(d2[key]):
+ _log.info(u'%25.25s: type(dict1) = %s = >>>%s<<<' % (key, type(d1[key]), d1[key]))
+ _log.info(u'%25.25s type(dict2) = %s = >>>%s<<<' % (u'', type(d2[key]), d2[key]))
+ different = True
+ continue
+ if d1[key] == d2[key]:
+ _log.info(u'%25.25s: both = >>>%s<<<' % (key, d1[key]))
+ else:
+ _log.info(u'%25.25s: dict1 = >>>%s<<<' % (key, d1[key]))
+ _log.info(u'%25.25s dict2 = >>>%s<<<' % (u'', d2[key]))
+ different = True
+ else:
+ _log.info(u'%25.25s: %50.50s | <MISSING>' % (key, u'>>>%s<<<' % d1[key]))
+ different = True
+ for key in k2:
+ if key in k1:
+ continue
+ _log.info(u'%25.25s: %50.50s | %.50s' % (key, u'<MISSING>', u'>>>%s<<<' % d2[key]))
+ different = True
+ if different:
+ _log.info('dict-likes appear to be different from each other')
+ return False
+ _log.info('dict-likes appear equal to each other')
+ return True
+
+#---------------------------------------------------------------------------
+#---------------------------------------------------------------------------
def prompted_input(prompt=None, default=None):
"""Obtains entry from standard input.
@@ -1200,7 +1271,8 @@ second line\n
print wrap(test, 7, u' ', u' ')
#-----------------------------------------------------------------------
def test_md5():
- print '%s: %s' % (sys.argv[2], file2md5(sys.argv[2]))
+ print 'md5 %s: %s' % (sys.argv[2], file2md5(sys.argv[2]))
+ print 'chunked md5 %s: %s' % (sys.argv[2], file2chunked_md5(sys.argv[2]))
#-----------------------------------------------------------------------
def test_unicode():
print u_link_symbol * 10
@@ -1259,6 +1331,27 @@ second line\n
def test_dir_is_empty():
print sys.argv[2], 'empty:', dir_is_empty(sys.argv[2])
#-----------------------------------------------------------------------
+ def test_compare_dicts():
+ d1 = {}
+ d2 = {}
+ d1[1] = 1
+ d1[2] = 2
+ d1[3] = 3
+ # 4
+ d1[5] = 5
+
+ d2[1] = 1
+ d2[2] = None
+ # 3
+ d2[4] = 4
+
+ compare_dict_likes(d1, d2)
+
+ d1 = {1: 1, 2: 2}
+ d2 = {1: 1, 2: 2}
+
+ compare_dict_likes(d1, d2, 'same1', 'same2')
+ #-----------------------------------------------------------------------
#test_coalesce()
#test_capitalize()
#test_import_module()
@@ -1273,13 +1366,14 @@ second line\n
#test_input2decimal()
#test_input2int()
#test_unwrap()
- #test_md5()
+ test_md5()
#test_unicode()
#test_xml_escape()
#test_gpg_decrypt()
#test_strip_trailing_empty_lines()
#test_fname_stem()
- test_tex_escape()
+ #test_tex_escape()
#test_dir_is_empty()
+ #test_compare_dicts()
#===========================================================================
diff --git a/server/sql/v19-v20/dynamic/v20-release_notes-dynamic.sql b/server/sql/v19-v20/dynamic/v20-release_notes-dynamic.sql
index 92ae3d2..96b5817 100644
--- a/server/sql/v19-v20/dynamic/v20-release_notes-dynamic.sql
+++ b/server/sql/v19-v20/dynamic/v20-release_notes-dynamic.sql
@@ -17,19 +17,18 @@ INSERT INTO dem.message_inbox (
) VALUES (
(select pk from dem.staff where db_user = 'any-doc'),
(select pk_type from dem.v_inbox_item_type where type = 'memo' and category = 'administrative'),
- 'Release Notes for GNUmed 1.5.6 (database v20.6)',
- 'GNUmed 1.5.6 Release Notes:
+ 'Release Notes for GNUmed 1.5.8 (database v20.8)',
+ 'GNUmed 1.5.8 Release Notes:
- 1.5.6
+ 1.5.8
-FIX: exception on removing temporary config file [thanks Vaibhav]
-FIX: exception on importing duplicate file into export area
-FIX: exception on merging patients under wxPython 3 [thanks max]
+FIX: SQL formatting when retrieving clinical narrative [thanks Marc]
+FIX: strange case of "curr_pat is None" in top panel [thanks Marc]
- 20.6
+ 20.8
no changes
');
-- --------------------------------------------------------------
-select gm.log_script_insertion('v20-release_notes-dynamic.sql', '20.6');
+select gm.log_script_insertion('v20-release_notes-dynamic.sql', '20.8');
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/gnumed-server.git
More information about the debian-med-commit
mailing list