Sunday, July 25, 2010

GNUmed web client - demo available

The obligatory screenshots. Web client (rough draft) compared to the wxpython app.




Both clients are connected to the same database at the same time.
Both clients pull the documents from the document archive for the patient Kirk (primary key 12)
Both clients have identical security measures. The credentials are checked against the PG security configuration.
Both clients were coded in python (one in wxpython and one in pyjamas)

The difference is that pyjamas can compile its widgets into Javasscript. That way the user interface can be displayed in a webbrowser.

Why all this ?

You won't see wxpython on mobile devices anytime soon. If Google has its way (and they will) we will see the browser as the application platform on some sort of netbook or tablet
The current state is a good base for further development.

Best regards,
Sebastian

Monday, July 19, 2010

GNUmed electronic medical record - update for Ubuntu

The Ubuntu people are hard at work peparing the new Maverick release. Apparently Debian import freeze is in effect so the latest bugfix release (0.7.7) will not make it into Ubuntu.

I have filed a sync request at https://bugs.launchpad.net/ubuntu/+source/gnumed-client/+bug/607246

Hopefully some kind soul will take the according action. GNUmed 0.7.7 is the seventh bugfix release in the 0.7 series and we think it is pretty stable. This version will make it into Debian stable that is expected to go into feature freeze soon.

While we are working on exciting new features for the soon to be released 0.8 series of the electronic medical record we are quite happy that a stable GNUmed release will make it into Debian and Ubuntu.

GNUmed web interface - demo available

For those of you who did not follow the discussion on the technical aspects of a web interface for GNUmed here is a short summary. I have looked at many web interfaces and learned quite a bit about existing web frameworks. It turned out that none of the existing frameworks fit our needs. This is due to the fact that the web is designed to fire and forget while GNUmed wants a persisten connection to the database. Second aspect was that we wanted database access done by Postgresql itself rather then duplicating that inside a database (which seems to be industry standard).

Long story short. Luke Leighton from pyjamas came to help us and invested a substantial amount of time to get things rolling. A first working version was recently referenced in this article. All of the code that makes it work has recently been merged into the main GNUmed code repository.

If makes use of pyjamas, cjson and multitaskhttpd.

Here is how you can try it out and start improving it. This guide assumes you have GNUmed running already.

1.) Get and install lovely-jsonrpc
* wget http://lkcl.net/lovely-jsonrpc.tgz
* unpack it
* cd lovely-jsonrpc
* python setup.py install
2.) get and install cjson
* e.g. python-cjson on Debian
3.) get multitaskhttpd
* git clone git://pyjs.org/git/multitaskhttpd.git
* cd multitaskhttpd
* python proxyapp.py &
4.) get pyjamas
* git clone git://pyjamas.git.sourceforge.net/gitroot/pyjamas/pyjamas
* cd pyjamas
* python bootstrap.py
* cd bin
* put pyjsbuild into the PATH or symlink into ProxiedWeb directory of GNUmed
5.) get GNUmed from git master as tgz or a git clone. Go to gitorious for instructions.

6.) compile the pyjamas application in the GNUmed source tree
* cd ProxiedWeb
* run build.sh (make sure pyjsbuild can be be found on your system)
7.) start GNUmed like this: ./gm-from-vcs.sh --ui=web

8.) open a webbrowser and go to http://localhost:8080/ProxiedWeb/jsonrpc/output/JSONRPCExample.html

If you want to hack on it have a look at JSONRPCExample.py. It is a pyjamas application.
Enjoy.

GNUmed 0.7.7 has been released

I am happy to announce the GNUmed 0.7.7 maintenance release:

                0.7.7

        FIX: DOB could become today in certain corner cases when creating new person [thanks S.Reus]
        FIX: check_drug_interactions() failed with FreeDIAMS [thanks J.Busser]
        FIX: be more careful around changing CWD when creating document from LaTeX [thanks S.Hilbert]
        FIX: exception when save-all'ing multiple notelets [thanks S.Reus, J.Busser]
        FIX: exception when saving medication where is_long_term is true [thanks J.Busser]

                13.6 -> 13.7

        NEW: improved detection of unicode support in server encoding
        NEW: work around os.getcwd() permission problem on Mac
        FIX: even more robust gmPsql.py unicode logging [thanks E.Kuznetsov]

This release does NOT require a database upgrade.

Download your copy (it's free !):

        http://www.gnumed.de/downloads/client/0.7/
        http://www.gnumed.de/downloads/server/v13/

This is very close to what will end up in the next stable
Debian so please report bugs !

Thursday, July 15, 2010

GNUmed web interface - state of affairs

Back then there was the idea of a web interface for GNUmed. Back then there
was no clear idea of what that meant. I whipped together a few tutorial bits
of cherrpy and connected it to gmPG. This enabled us to log into the GNUmed
database and ran a few queries against the database to show there actually was
a connection. Little did I know that this was a beginning but nowhere near any
of what I wanted.

I wanted:
1.) a web client that could run concurrently to the wxpython client
2.) a web client that ran on top of gmPG2 instead of some framework's ORM
3.) role based security instead of database based security - no credentials in
a database table, period
4.) a web client that could fetch data from a backend
5.) not a web client that was no more then a number of server-side assembled
html pages.
6.) A nice looking web client without having to learn Javascript
7.) maybe more but I cannot remember

I checked loads of frameworks. But there was always a catch. The frameworks
wanted to do the work for me and they had a certain idea how to do it. Their
ideas did not neccessarly correlate with my ideas.

I ran my ideas by a couple of framework developers and Javascript toolkit
developers but none seems overly interested apart from their framework would
do what I wanted. Problems was I did not have enough skills and knowledge so
it was more a matter of trust then a fact based decision.

I always came across pyjamas. It seemed to partly fit the bill as it would let
em write python instead of Javascript. I ran my ideas by Luke Leighton after
seeing a message on python-announce mailing list.

That changes quite a few things. First he told me what I did not know about
the web. Most of the stuff was obvious for a web developer. I learned that the
web is stateless and unlike in a desktop application it is quite a bit of work
to make a client and a server process holding a unique persistent database
connection. Luke published quite a bit of code in easy to digest chunks so I
was able to follow along.

In the end here is what he solved for GNUmed.

The code:
1.) allows a browser (web client) to hold a persistent database connection to
the GNUmed backend even if the user closes the browser. The client will
reconnect to its unique connection when it is restarted.

2.) talks to the GNUmed database through the GNUmed middleware. No ORM or
stuff needed.

3.) demonstrated how two simultaneous connections (clients) talk to the
database without getting in each other's way or stealing each other's data
(which is common if you don't take care of it)

4.) provides a pyjamas application which will let a user log in and run
database queries.

5.) runs without interfering with other wxpython clients

6.) shows nicely how to use JSON-RPC to talk to client side frameworks. This
even lets Javascript framework warriors write their own client in Javascript
without having to do any database stuff.

The problems Luke solved were to do with turning HTTP connections,
which are ordinarily stateless, into permanent stateful connections.
He achieved this by:

* creating a special non-blocking HTTP proxy that does HTTP 1.1 with
"keep-alives", even if the browser does not.

* creating a modified version of python's SimpleHTTPServer that always
responds with "Connection: keep-alive", for GET and POST queries, even
on HTTP errors.

* inserting a session cookie into the HTTP stream, which the
non-blocking HTTP proxy looks out for, and uses to match the incoming
HTTP request with the corresponding outgoing connection.

in this way, browsers appear to be connected to the same persistent
back-end process, which is kept open and alive on behalf of the
browser, by the special proxy. as long as the back-end process
doesn't crash (or deliberately exit after a timeout) and as long as
the user does not clear the browser's cache, the user will always be
connected to the exact same back-end web server process.
What we have now is an excellent starting point to develop a web client for
GNUmed. Users have the option to run the wxpyton client or web client or both
at the same time. The big benefit of all client talking to the backend through
a common server side middleware is that in case of backend changes or
middleware changes all client continue to work without having to port all
changes to all clients.

Buyer beware: This is proof of concept code. It shows the concept works. Not
more. No less.



Rock on.

Sebastian

Wednesday, July 07, 2010

GNUmed plugin development - how to access the current patient

Chances are you want to access the data of the currently active patient in your plugin. There is an app for that (TM) . I mean there are some convenience functions for that. This is called middleware. No matter if the database ever changes. The way to access the data is abstracted and will remain stable.
from Gnumed.business import gmPerson

pat = gmPerson.gmCurrentPatient()
text = patient['firstnames']
text = patient['lastnames']
text = patient['dob']
text = patient['gender']
This should be pretty self explainatory. For convenience use patient['dob'].isoformat() for a string representation of the datetime object.

To work with the patient's emr you can access it like this:

emr = pat.get_emr()
Let's say you want to get the current episode and if none create one.

                if episode is None:
                        all_epis = emr.get_episodes()
                        # FIXME: what to do here ? probably create dummy episode
                        if len(all_epis) == 0:
                                episode = emr.add_episode(episode_name = _('Cardiac echo exam'), is_open = False)
                        else:
                                dlg = gmEMRStructWidgets.cEpisodeListSelectorDlg(parent = parent, id = -1, episodes = all_epis)
                                dlg.SetTitle(_('Select the episode under which to file the document ...'))
                                btn_pressed = dlg.ShowModal()
                                episode = dlg.get_selected_item_data(only_one = True)
                                dlg.Destroy()

                                if (btn_pressed == wx.ID_CANCEL) or (episode is None):
                                        if unlock_patient:
                                                pat.locked = False
                                        return None

Thursday, July 01, 2010

GNUmed plugin development - easy testing of plugin

Developing a plugin is no magic. We have received a report by a university student that he was able to get a plugin developed and running from the documentation we provide. He intentionally does not ask any questions but tries to dig through the documentation (blog, wiki, source code comments) to find out how everything plays together.

In one of the last articles it was demonstrated how to display a plugin. While it is nice to see your plugin in GNUmed often you don't want to start up all of GNUmed just to test your plugin.

Python comes with batteries included. Each client plugin can be started standalone through a helper called pywidgettester. This is implemented in the ExamplePlugin aleready.

Just start the plugin like this
cd ./client/wxpython/gui
python gmExamplePlugin.py
It will ask for the server it should connect to, the database it should connect to, the username and the password. Once it has connected it lets you search for a patient. Then it will display this:



These lines in a plugin make this possible
#================================================================
# MAIN
#----------------------------------------------------------------
if __name__ == '__main__':

        # GNUmed
        from Gnumed.business import gmPerson
        from Gnumed.wxpython import gmPatSearchWidgets

        _log.info("starting template plugin...")

        try:
                # obtain patient
                patient = gmPerson.ask_for_patient()
                if patient is None:
                        print "None patient. Exiting gracefully..."
                        sys.exit(0)
                gmPatSearchWidgets.set_active_patient(patient=patient)

                # display the plugin standalone
                application = wx.wx.PyWidgetTester(size = (800,600))
                widgets = gmExamplePluginWidgets.cExamplePluginPnl(application.frame, -1)

                application.frame.Show(True)
                application.MainLoop()

Happy coding