Packages for the 0.6 release candidates are ready for testing. If you want a stable EMR choose GNUmed 0.5.2 instead of 0.6 series. Go to software.opensuse.org or use this link. Please report any issues you encounter.
Sebastian
This blog deals with the Free and Open Source Software GNUmed. It is essentially a software package for medical professionals looking for a patient management solution.
Packages for the 0.6 release candidates are ready for testing. If you want a stable EMR choose GNUmed 0.5.2 instead of 0.6 series. Go to software.opensuse.org or use this link. Please report any issues you encounter.
Sebastian
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Hi all,
I am looking for a voluteer to write up non-technical about GNUmed. If you can spare a minute please write a page or so that can be distributed to press and press-alike people.
Background: I was talking to the openSUSE guys about including it into the distribution and writing about it in the suse blogs.
They asked me to provide some non-technical information on GNUmed.
I believe this document should include:
- GNUmed is an electronic medical record program
- Targeted at medical offices - not hospitals
- aimed at record keeping - not billing
- talk about some features
- talk about use cases
- who creates it and why
- what is desired for the future
Any help is really appreciated. I believe GNUmed's current feature set is big enough to raise awareness that GNUmed can be used in certain settings today.
Sebastian
GNUmed Live CD 0.5.1 is available from
http://www.gnumed.de/downloads/live-cd/gnumed-live-0.5.1.is
Sebastian
A new experiment.
Follow GNUmed on identi.ca
http://identi.ca/releasedude
Sebastian
Hi all,
GNUmed EMR Live CD is available for download from
http://www.gnumed.de/downloads/live-cd/gnumed-live-0.5.0.iso
(md5sum 9af2a609b80a92109643c53b904896c1 gnumed-live-0.5.0.iso)
It includes a fully configured and bootstraped local database.
One can use this CD to testdrive the GNUmed EMR without installing anything or the need for an internet connection.
BTW. Thanks Andreas for the quick fixes to the GNUmed packages.
Take care,
Sebastian
pat = gmPerson.gmCurrentPatient()This returns a list of cMedDoc objects which can be parsed like that:
doc_folder = pat.get_document_folder()
docs = doc_folder.get_documents()
for doc in docs:doc_folder.get_documents() returns elements ordered by clin_when so the first element is the newest one I am looking for.
doc['comment'] = ... etc.
for doc in docs:To construct the line
if doc['type'] == 'cardiac device checkup report':
selected_docs.append(doc)
if not len(selected_docs) == 0:
# since get_documents() is sorted I simply get the first one as the most recent one
# for now assume that the xml file provide the cardiac device context.
# that pretty much means logical connection of leads and generator is provided in the xml
xml = selected_docs[0].get_parts()[0].export_to_file()
tree = etree.parse(xml)
DevicesDisplayed = gmDevices.device_status_as_text(tree)
for line in DevicesDisplayed:
text = text + line
else:
_log.info('There are no device checkup reports in the database')
text = _('There are no device checkup reports in the database')
xml = selected_docs[0].get_parts()[0].export_to_file()one has to take a good look at the file gmMedDoc.py in /business. Using that code it is now possible to get the XML from the database and display the current device status.
def __init__(self, *args, **kwargs):The next step is to get rid of saving to a file and reading from that. Another issue is to get refresh going when entering new data.
# check if report types exist in db, if not create them
dtype = gmMedDoc.create_document_type('cardiac device checkup report')
dtype.set_translation(_('cardiac device checkup report'))
python GNUmedDeviceParserElementTree.pyand observe the following output:
-------------------------------------------------------------Now what you see here has been parsed from the XML. No more fake input. Next step is to first replace all hardcoded English strings with gettext-equivalents so translators can have a go at them. To achieve that we will take a look at other plugins that already have that feature.
Device(ICD): St. Jude Medical Atlas DR (active) Battery: St. Jude Medical (St. Jude Medical) Implanted: 23.03.2002
RA-lead in RA-position: Medtronic Sprint XL (active,no comment on lead) Implanted: 23.04.2009
last check: 23.04.2004 Sensing: 7mV Threshold 1.4mV Impedance: 300 Ohm
RV-lead in RV-position: Medtronic Sprint fidelis (inactive,no comment on lead) Implanted: 23.04.2009
last check: 23.04.2009" Sensing: 7mV Threshold 1.4mV Impedance: 300 Ohm
LV-lead in LV-position: St. Jude QuickSite XL (active,no comment on LV lead) Implanted: 23.04.2009
last check: 23.03.2004 Sensing: 7mV Threshold 1.4mV Impedance: 300 Ohm
import loggingAll of the above but the second and third line were added to the top of the parser. To tell gettext where to replace I marked them like this:
from Gnumed.wxpython import gmPlugin, gmMeasurementWidgets
from Gnumed.pycommon import gmI18N
_log = logging.getLogger('gm.ui')
_log.info(__version__)
_('this is a string that needs a translation') vs. 'this is a string that needs a translation'So the _() construct identifies the strings to gettext. The following lines were added to the main section.
from Gnumed.pycommon import gmI18NRunning the parser now displayes the same result even after all 'I am a string' occurences having been replaced by _('I am a string'). The next part will try to get the parser connected to gmCardiacDevicePlugin and get this plugin displayed in GNUmed. Once this has been accomplished the XML needs to be read from the database instead of a file.
gmI18N.activate_locale()
gmI18N.install_domain()
cvs add GNUmed6.xml GNUmedDeviceParserElementTree.pyand
Enter passphrase for key '/home/basti/.ssh/id_rsa':
cvs add: scheduling file `GNUmed6.xml' for addition
cvs add: scheduling file `GNUmedDeviceParserElementTree.py' for addition
cvs add: use `cvs commit' to add these files permanently
cvs commit GNUmed6.xml GNUmedDeviceParserElementTree.pyWhen you update your CVS tree you get my work located in the folder gnumed/gnumed/test-area/shilbert
Enter passphrase for key '/home/basti/.ssh/id_rsa':
/sources/gnumed/gnumed/gnumed/test-area/shilbert/GNUmed6.xml,v <-- GNUmed6.xml
initial revision: 1.1
/sources/gnumed/gnumed/gnumed/test-area/shilbert/GNUmedDeviceParserElementTree.py,v <-- GNUmedDeviceParserElementTree.py
initial revision: 1.1
python GNUmedDeviceParserElementTree.pyReading the XML file GNUmed6.xml it will output this:
The file has the following devices: <Element CardicacDevice at b7bfb20c>:
The device has the following parts: <Element DevicePart at b7bfb18c>
hey we are dealing with a generator here:-)
('St. Jude Medical', 'Atlas DR', 'active')
<?xml version="1.0" encoding="UTF-8"?>This is a simplified version. It lacks the actual measurements. Next step is to learn how to transfer that XML to a human readable form so I can display it in the left upper section of the plugin.
<!-- New document created with EditiX at Wed Apr 29 15:37:23 CEST 2009 -->
<CardicacDevices>
<DevicePart type="generator">
<class>AID</class>
<type>generator</type>
<isactive>yes</isactive>
<dateofimplant></dateofimplant>
<dateofexplant></dateofexplant>
<isexplanted>no</isexplanted>
<comment></comment>
<implantsite>subpectoral</implantsite>
<implantregion>right subclavian</implantregion>
<GeneratorPart type="CPU" >
<manufacturer>SJM</manufacturer>
<model></model>
<serial></serial>
</GeneratorPart>
<GeneratorPart type="Battery">
<manufacturer></manufacturer>
<serial></serial>
</GeneratorPart>
</DevicePart>
<DevicePart type="lead">
<manufacturer> </manufacturer>
<model></model>
<polarity></polarity>
<serial></serial>
<isactive>yes</isactive>
<hasYconnector>yes</hasYconnector>
<dateofimplant></dateofimplant>
<dateofexplant></dateofexplant>
<isexplanted> no</isexplanted>
<leadposition>RV</leadposition>
<leadslot>RA</leadslot>
<comment></comment>
<connectedtodevice>aid</connectedtodevice>
<connectedtodevice>RVlead</connectedtodevice>
</DevicePart>
</CardicacDevices>
class wxgCardiacDevicePluginPnl(wx.ScrolledWindow):The import statements to my wxgCardiacDevicePluginPnl.py. It now actually shows up in GNUmed. Horray. But it crashes when trying to load data. this should be easy to fix.
def __init__(self, *args, **kwds):
from Gnumed.wxpython.gmNarrativeWidgets import cSoapNoteInputNotebook
from Gnumed.wxpython.gmDateTimeInput import cFuzzyTimestampInput
from Gnumed.wxpython.gmEMRStructWidgets import cEncounterTypePhraseWheel
from Gnumed.wxpython import gmListWidgets
# begin wxGlade: wxgCardiacDevicePluginPnl.__init__
gm.gui (/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmExceptionHandlingWidgets.py::handle_uncaught_exception_wx() #49): unhandled exception caught:That is no surprise since I decided to put the class cCardiacDeviceMeasurementsPnl into gmMeasurementWidgets.py and did not copy all stuff from gmSoapWidgets. What I effectively missed is to copy all the needed functions like _populate_with_data().
Traceback (most recent call last):
File "/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmHorstSpace.py", line 231, in _on_notebook_page_changed
new_page.receive_focus()
File "/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmPlugin.py", line 183, in receive_focus
self._widget.repopulate_ui()
File "/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmRegetMixin.py", line 128, in repopulate_ui
self.__repopulate_ui()
File "/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmRegetMixin.py", line 66, in __repopulate_ui
self._data_stale = not self._populate_with_data()
File "/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmRegetMixin.py", line 79, in _populate_with_data
raise NotImplementedError, "[%s] _populate_with_data() not implemented" % self.__class__.__name__
NotImplementedError: [cCardiacDeviceMeasurementsPnl] _populate_with_data() not implemented
class gmCardiacDevicePlugin(gmPlugin.cNotebookPlugin):in gmCardiacDevicePlugin.py tells me that in the case of the Document archive plugin we borrowed from the class cSelectablySortedDocTreePnl is located in the file gmMedDocWidgets. The name implies that this is a collection of classes of medical document widgets. The device parameters are essentially measurements.
def GetWidget (self, parent):
self._widget = gmMedDocWidgets.cSelectablySortedDocTreePnl(parent, -1)
return self._widget
#================================================================
class cCardiacDeviceMeasurementsPnl(wxgCardiacDevicePluginPnl.wxgCardiacDevicePluginPnl, gmRegetMixin.cRegetOnPaintMixin):
"""Panel holding a number of widgets to manage implanted cardiac devices. Used as notebook page."""
def __init__(self, *args, **kwargs):
wxgCardiacDevicePluginPnl.wxgCardiacDevicePluginPnl.__init__(self, *args, **kwargs)
gmRegetMixin.cRegetOnPaintMixin.__init__(self)
self.__init_ui()
self.__register_interests()
#--------------------------------------------------------
# event handling
#--------------------------------------------------------
from Gnumed.wxGladeWidgets import wxgMeasurementsPnl, wxgMeasurementsReviewDlg
from Gnumed.wxGladeWidgets import wxgMeasurementEditAreaPnl
from Gnumed.wxGladeWidgets import wxgCardiacDevicePluginPnl
class gmCardiacDevicePlugin(gmPlugin.cNotebookPlugin):
def GetWidget (self, parent):
self._widget = gmMeasurementWidgets.cCardiacDeviceMeasurementsPnl(parent, -1)
return self._widget
from Gnumed.wxpython import gmMeasurementWidgets, gmPlugininstead of
from Gnumed.wxpython import gmMedDocWidgets, gmPlugin, images_Archive_pluginIf you followed the above steps you might notice that the plugin throws many errors in the file gnumed.log. This file can be viewed directly from within GNUmed. It does not show up. The reason is simple. I use a complex set of widgets that are scattered across the files gmMeasurementWidgets and gmNarrativeWidgets.
Traceback (most recent call last):This is due to the fact that the class name and the file name (gmCardiacDevicePlugin) due not match. Open the file and change the class name.
File "/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmHorstSpace.py", line 121, in __load_plugins
plugin = gmPlugin.instantiate_plugin('gui', curr_plugin)
File "/home/basti/sources/gnumed/gnumed/Gnumed/wxpython/gmPlugin.py", line 333, in instantiate_plugin
plugin_class = module_from_package.__dict__[plugin_name]
KeyError: u'gmCardiacDevicePlugin'
class gmCardiacDevicePlugin(gmPlugin.cNotebookPlugin):The section 'Menu Info' is responsible for the name of the plugin in the GNUmed menu. I changed it like this and while we are at it the notebook tab name as well.
"""Plugin to encapsulate document tree."""
tab_name = _("Documents")
def name (self):
return gmCardiacDevicePlugin.tab_name
class gmCardiacDevicePlugin(gmPlugin.cNotebookPlugin):
"""Plugin to encapsulate document tree."""
tab_name = _("Cardiac Device")
def name (self):
return gmCardiacDevicePlugin.tab_name
#--------------------------------------------------------
def GetWidget (self, parent):
self._widget = gmMedDocWidgets.cSelectablySortedDocTreePnl(parent, -1)
return self._widget
#--------------------------------------------------------
def MenuInfo (self):
return ('tools', _('Show &cardiac devices'))