<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ralph-heinkel.com</title><link>https://ralph-heinkel.com/</link><description>My IT site</description><atom:link href="https://ralph-heinkel.com/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2022 Ralph Heinkel </copyright><lastBuildDate>Fri, 11 Feb 2022 12:35:21 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Avoid memory leaks when caching instance methods in Python classes</title><link>https://ralph-heinkel.com/blog/avoid-memory-leaks-when-caching-instance-methods-in-python-classes/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;While working on a customer's project last week I stumbled across the problem
that caching instance method results in Python classes easily creates memory leaks,
especially in long-running processes.&lt;/p&gt;
&lt;p&gt;Although Python comes with built-in caching functionality (see &lt;code&gt;functools&lt;/code&gt; library)
and there are 3rd party caching libraries available like &lt;code&gt;cachetools&lt;/code&gt; I couldn't
find a proper solution that satified my needs. So I wrote my own, by using a very
nice function from the &lt;code&gt;cachetools&lt;/code&gt; libarary, and building a proper decorator around
it.&lt;/p&gt;
&lt;p&gt;Before using the code shown below, create a virtualenv and install the cachetools
package upfront so that you can try things out yourself:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;$ virtualenv pyenv
$ . pyenv/bin/activate
$ pip install cachetools
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let's start implementing.
A naive approach to apply caching functionality to a very simple could be:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;from cachetools import cached

mycache = {}

class MyClass:
    @cached(mycache)
    def myfunc(self, a):
        print('myfunc called with', a)
        return a * 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It uses the &lt;code&gt;cached()&lt;/code&gt; decorator from the &lt;code&gt;cachetools&lt;/code&gt; libary, and initializes it
with a dictionary instance that serves as the actual container for the caching.&lt;/p&gt;
&lt;p&gt;Now let's create an instance of &lt;code&gt;MyClass&lt;/code&gt; and call &lt;code&gt;myfunc()&lt;/code&gt; twice to see that
the cache works:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; my = MyClass()
&amp;gt;&amp;gt;&amp;gt; my.myfunc(2)
myfunc called with', 2
4
&amp;gt;&amp;gt;&amp;gt; my.myfunc(2)
4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we can see that the second call doesn't actually call into to the &lt;code&gt;myfunc()&lt;/code&gt;
function but receives the result from the previous call from the cache. So far so good.&lt;/p&gt;
&lt;p&gt;But: What happens if the &lt;code&gt;my&lt;/code&gt;-instance gets deleted (and hence garbage collected)?&lt;br&gt;
Does the cache lose its cached results from those calls above?&lt;/p&gt;
&lt;p&gt;Well, let's see. In order to prove that an object is really deleted from the Python
interpreter by garbage collection I'm applying a weak reference to the object which
I want to delete. If the weak reference returns None, the previously
referenced object has been indeed deleted.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Garbage collection doesn't necessarily happen immediately after an object
has been orphaned. Instead, the Python interpreter calls the garbage collector
at certain trigger points, so it can take a while until objects are actually
removed. However, the garbage collector can be called manually to enforce
the cleanup process, which is what we do in the following example.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let's demonstrate this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import weakref, gc
&amp;gt;&amp;gt;&amp;gt; myinst = MyClass()
&amp;gt;&amp;gt;&amp;gt; myinstref = weakref.ref(myinst)
&amp;gt;&amp;gt;&amp;gt; myinstref()
&amp;lt;__main__.MyClass object at 0x7f6565b11a30&amp;gt;
&amp;gt;&amp;gt;&amp;gt; del myinst
&amp;gt;&amp;gt;&amp;gt; gc.collect()   # enforce garbage collection
&amp;gt;&amp;gt;&amp;gt; myinstref() is None
True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, this worked. Now let's go back to the &lt;code&gt;my&lt;/code&gt;-instance created above, and also
try to remove it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; myref = weakref.ref(my)
&amp;gt;&amp;gt;&amp;gt; del my
&amp;gt;&amp;gt;&amp;gt; gc.collect()
&amp;gt;&amp;gt;&amp;gt; myref.ref()
&amp;lt;__main__.MyClass object at 0x7f6565a01c40&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hmm, this didn't work quite as expected, the &lt;code&gt;my&lt;/code&gt; instance is still alive. The reason
behind this is actually the cache. When we had called &lt;code&gt;my.myfunc(2)&lt;/code&gt; before, not only
the parameter &lt;code&gt;2&lt;/code&gt; and the result &lt;code&gt;4&lt;/code&gt; got stored in the cache, but also the reference
to &lt;code&gt;self&lt;/code&gt;, just because &lt;code&gt;self&lt;/code&gt; is part of the method signature. This can be made
visible by inspecting the cache object, which is a plain dictionary:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; mycache
{(&amp;lt;__main__.MyClass object at 0x7f6565a01c40&amp;gt;, 2): 4}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see the cache itself keeps a reference to the &lt;code&gt;my&lt;/code&gt; instance which prevents it
from being garbage collected. Now imagine you create thousands or millions of
&lt;code&gt;MyClass&lt;/code&gt; instances, and only ever make the same call &lt;code&gt;my.myfunc(2)&lt;/code&gt; to it. The
result would be a million entries in the cache for parameter &lt;code&gt;2&lt;/code&gt; and result &lt;code&gt;4&lt;/code&gt;,
just each with a reference to a different short-lived &lt;code&gt;MyClass&lt;/code&gt; instance. Voilà,
here is our memory leak.&lt;/p&gt;
&lt;p&gt;The solution is to clear the cache, and then our &lt;code&gt;my&lt;/code&gt; instance will eventually
also be garbage collected:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; cache.clear()
&amp;gt;&amp;gt;&amp;gt; gc.collect()
&amp;gt;&amp;gt;&amp;gt; myref.ref() is None
True
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Constructing a cache that frees instances when they are garbage collected&lt;/h3&gt;
&lt;p&gt;As we have seen before the &lt;code&gt;weakref&lt;/code&gt;-module provides a nice way to keep references
to objects without holding a firm grip on them. This approach can be used inside the cache
as well. Here is an implementation that I came up with, on this nice Sunday afternoon.&lt;/p&gt;
&lt;p&gt;In order to understand this implementation please make sure you are familiar with
how decorators work in general. I will only explain details which are specific
to the implemenation, not the entire principle of decorators.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;from cachetools import cachedmethod
from weakref import WeakKeyDictionary

def methodcache(cache_factory):
    def wrapped_methodcache(method):
        def get_instance_cache(self):
            try:
                instance_cache = weak_cache[self]
            except KeyError:
                instance_cache = weak_cache[self] = cache_factory()
            return instance_cache

        weak_cache = WeakKeyDictionary
        cached_method = cachedmethod(get_instance_cache)(method)
        # Attach the weak dictionary to the decorator so we can access it from outside:
        cached_method.__cache__ = weak_cache
        return cached_method

    return wrapped_methodcache


# Application:
class MyNewClass:
    @methodcache(dict)
    def myfunc(self, a):
        return a * 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The core of this decorator is the &lt;code&gt;cachetools.cachedmethod()&lt;/code&gt; function (which itself
is a decorator). It is initialized with a callback function (&lt;code&gt;get_instance_cache()&lt;/code&gt; in
this case) which is called each time the decorated method is called. It receives
a reference to the class instance (&lt;code&gt;MyNewClass()&lt;/code&gt; in the demo case above) as argument
&lt;code&gt;self&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The approach is that each decorated method will get a &lt;code&gt;WeakKeyDictionary&lt;/code&gt;-instance
attached to it. Since  &lt;code&gt;get_instance_cache()&lt;/code&gt; is defined at the same level as
the &lt;code&gt;weak_cache&lt;/code&gt; variable is assigned the &lt;code&gt;WeakKeyDictionary&lt;/code&gt;, it has access to this
weak dictionary instance. When it is called it looks up whether this weak dict has
already stored a cache for &lt;code&gt;this&lt;/code&gt;. If not, such a cache is created via the
&lt;code&gt;cache_factory()&lt;/code&gt; instance. Then the cache is returned to the &lt;code&gt;cachedmethod&lt;/code&gt; decorator
function, which itself then is responsible for doing the caching or looking up cached
values.&lt;/p&gt;
&lt;p&gt;I've to admit that this solution is not super easy to understand. but with some
experience with decorators in general and a little digging into the code I
hope everyone can profit from this solution.&lt;/p&gt;</description><category>python cache memory leak instance method</category><guid>https://ralph-heinkel.com/blog/avoid-memory-leaks-when-caching-instance-methods-in-python-classes/</guid><pubDate>Sun, 06 Feb 2022 14:32:00 GMT</pubDate></item><item><title>My website is online again</title><link>https://ralph-heinkel.com/blog/0100-my-website-is-online-again/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;Finally, after some downtime while I was working on it ... my
website &lt;a href="https://ralph-heinkel.com/blog/0100-my-website-is-online-again/ralph-heinkel.com"&gt;ralph-heinkel.com&lt;/a&gt; finally is online again.&lt;/p&gt;
&lt;p&gt;With fresh design, based on bootstrap and the 'superhero'-theme from
&lt;a href="https://ralph-heinkel.com/blog/0100-my-website-is-online-again/bootswatch.com"&gt;bootswatch.com&lt;/a&gt;, and all assembled by the static site
and blog generator &lt;a href="https://ralph-heinkel.com/blog/0100-my-website-is-online-again/getnikola.com"&gt;Nikola&lt;/a&gt;. It was quite an experience
to work with Nikola, the learning curve was a bit steeper than I had hoped,
but the result is more than rewarding. I'm really grateful for this project,
many thanks to all its contributors.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.juraforum.de"&gt;juraforum.de&lt;/a&gt; provided the (free) privacy declaration (Datenschutzerklärung).&lt;/p&gt;
&lt;p&gt;Last but not least my old blog postings got recovered, and now hopefully new ones will follow.&lt;/p&gt;
&lt;p&gt;Stay tuned ;-)&lt;/p&gt;</description><category>nikola</category><category>website</category><guid>https://ralph-heinkel.com/blog/0100-my-website-is-online-again/</guid><pubDate>Sun, 13 Jun 2021 21:17:01 GMT</pubDate></item><item><title>Repair grub2 boot after OpenSuse 12.3 update messed it up</title><link>https://ralph-heinkel.com/blog/repair-grub2-setup/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;After my OpenSuse 12.3 installation ran an automatic update on a few packages I wasn't able to
boot the system anymore. Instead I ended up in a minimal grub2 shell without any clue what to do next
in order to reboot my system again.&lt;/p&gt;
&lt;p&gt;Browsing around the internet from another computer I found that things are getting more
difficult as I had my root partition encrypted in a LUKS container. But - there is always hope
and so I eventually collected enough information from various blogs and news groups to get
my system up and running again.&lt;/p&gt;
&lt;p&gt;Here are the instructions that have worked for me.&lt;/p&gt;
&lt;h3&gt;Boot with OpenSuse 12.3 installation DVD&lt;/h3&gt;
&lt;p&gt;In order to be able to do anything I started up the installation DVD. Since I needed
to get access to my encrypted root file system the smartest way is to choose "Installation"
when the DVD provides the initial menu. Don't worry, nothing is installed yet, and it won't,
because we will jump out in time.&lt;/p&gt;
&lt;p&gt;After choosing "Installation" the system asks to confirm the EULA. Click 'Accept' to continue.
Next it will find your LUKS partition - and asks you whether you want to provide the passphrase
for decrypting it. So yes, choose decryption and enter your password.&lt;/p&gt;
&lt;p&gt;Wait until the decryption is done and the installer is waiting for new input from you. At this
point the magic stuff starts. Click Ctrl-Alt-F2 to switch to a text console. You will
be already logged in as root (the #-prompt is your friend!).&lt;/p&gt;
&lt;h3&gt;Mount your system partitions&lt;/h3&gt;
&lt;p&gt;Type the following command to see your partition setup:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# fdisk -l
[... some output omitted ...]
Device Boot         Start         End      Blocks   Id  System
/dev/sda1            2048    87472127    43735040    7  HPFS/NTFS/exFAT
/dev/sda2   *    87472128    87795711      161792   83  Linux
/dev/sda3        87795712   488396799   200300544   8e  Linux LVM
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my case partition 2 contains my boot system, partition 3 my encrypted root and home partitions.&lt;/p&gt;
&lt;p&gt;Type another command to look into the encrypted (only accessible because we did the decryption step above):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# lvscan
ACTIVE            '/dev/system/home' [100.00 GiB] inherit
ACTIVE            '/dev/system/root' [25.00 GiB] inherit
ACTIVE            '/dev/system/swap' [4.00 GiB] inherit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now lets glue together the original system with some mount commands, using the information above:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# mount /dev/system/root /mnt
# mount /dev/sda2 /mnt/boot
# mount --bind /dev /mnt/dev
# mount -o bind /sys /mnt/sys
# mount -t proc /proc /mnt/proc
# cp /proc/mounts /mnt/etc/mtab
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Change the root directory into the mounted filesystem and run grub&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# sudo chroot /mnt /bin/bash
# grub2-install /dev/sda
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;update-grub&lt;/code&gt; command mentioaned in some other blogs does not exist any longer,
so use &lt;code&gt;grub2-mkconfig&lt;/code&gt; instead to finally generate a new &lt;code&gt;grub.cfg&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# grub2-mkconfig -o /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should print a list of added partitions to your screen.&lt;/p&gt;
&lt;p&gt;Quit the chroot environment with ctrl-d and reboot your system (&lt;code&gt;reboot&lt;/code&gt; or &lt;code&gt;ctrl-alt-del&lt;/code&gt;).
Hopefully it boots up again as before.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://wiki.ubuntuusers.de/GRUB_2/Reparatur"&gt;http://wiki.ubuntuusers.de/GRUB_2/Reparatur&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fedoraproject.org/wiki/GRUB_2?rd=Grub2"&gt;https://fedoraproject.org/wiki/GRUB_2?rd=Grub2&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.gargi.org/showthread.php?4215-openSUSE-12-2-Grub2-Bootloader-wiederherstellen"&gt;http://www.gargi.org/showthread.php?4215-openSUSE-12-2-Grub2-Bootloader-wiederherstellen&lt;/a&gt;&lt;/p&gt;</description><category>grub2</category><category>linux</category><category>OpenSuse</category><guid>https://ralph-heinkel.com/blog/repair-grub2-setup/</guid><pubDate>Fri, 19 Sep 2014 11:20:00 GMT</pubDate></item><item><title>EuroPython 2014 pyRserve-slides now available online</title><link>https://ralph-heinkel.com/blog/europython2014-pyrserve-slides-online/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;After our well-attended
&lt;a href="http://www.meetup.com/HeidelbergPython/events/195639502/"&gt;Python Meetup last Wednesday in Heidelberg&lt;/a&gt;
about "Connecting Python to other programming languages for scientific computing"
I had been approached to publish the slides of my &lt;a href="https://pypi.python.org/pypi/pyRserve"&gt;pyRserve&lt;/a&gt;
talk (which has been the same as the one  I've given at EuroPython in Berlin, for those who are interested).
These are now &lt;a href="http://www.ralph-heinkel.com/download/pyRserve-talk-2014-07-24.pdf"&gt;online, so feel free to download them&lt;/a&gt;.&lt;/p&gt;</description><category>planet</category><category>pyRserve</category><category>Python</category><category>R</category><guid>https://ralph-heinkel.com/blog/europython2014-pyrserve-slides-online/</guid><pubDate>Fri, 19 Sep 2014 09:50:00 GMT</pubDate></item><item><title>pyRserve 0.8.1 released</title><link>https://ralph-heinkel.com/blog/pyRserve-0.8.1-released/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;h2&gt;About pyRserve&lt;/h2&gt;
&lt;p&gt;pyRserve is a (pure python) client for connecting Python to an R process on a remote server via TCP-IP (using Rserve).
&lt;code&gt;R&lt;/code&gt; is one of the most important and most widely spread open source statistic packages available.&lt;/p&gt;
&lt;p&gt;Through such a pyRserve connection the full power of R is available on the Python side without programming in R.
From Python variables can get set in and retrieved from R, and R-functions can be created and called remotely.
No R-related libraries need to be installed on the client side, &lt;code&gt;pip install pyRserve&lt;/code&gt; is all that needs to be
done.&lt;/p&gt;
&lt;h2&gt;Sample code&lt;/h2&gt;
&lt;p&gt;This code assumes that &lt;code&gt;Rserve&lt;/code&gt; (the part that connects the R engine to the network) already is running.
Details can be found in the pyRserve docs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import pyRserve
&amp;gt;&amp;gt;&amp;gt; conn = pyRserve.connect('Rserve.domain.com')
&amp;gt;&amp;gt;&amp;gt; conn.eval('sum( c(1.5, 4) )') # direct evaluation of a statement in R
5.5
&amp;gt;&amp;gt;&amp;gt; conn.r.myList = [1, 2, 3] # bind a Python list in R to variable 'myList'

&amp;gt;&amp;gt;&amp;gt; conn.voidEval('func1 &amp;lt;- function(v) { v*2 }')  # create a function in R
&amp;gt;&amp;gt;&amp;gt; conn.r.func1(4)                                # call the function in R
16
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Most important changes in V 0.8.x&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Support for out-of-bound messages (allows for callbacks from R to Python)
(contrib. by Philip. A.)&lt;/li&gt;
&lt;li&gt;Rserve can now be shutdown remotely (contrib. by Uwe Schmitt)&lt;/li&gt;
&lt;li&gt;Fixed bug when passing R functions as parameters to R functions&lt;/li&gt;
&lt;li&gt;Documentation errors have been fixed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Documentation and Support&lt;/h2&gt;
&lt;p&gt;The documentation for pyRserve is available at &lt;a href="http://packages.python.org/pyRserve"&gt;http://packages.python.org/pyRserve&lt;/a&gt;&lt;br&gt;
The corresponding Google news group can be found at
&lt;a href="http://groups.google.com/group/pyrserve"&gt;http://groups.google.com/group/pyrserve&lt;/a&gt;&lt;/p&gt;</description><category>planet</category><category>pyRserve</category><category>Python</category><category>R</category><guid>https://ralph-heinkel.com/blog/pyRserve-0.8.1-released/</guid><pubDate>Fri, 18 Jul 2014 08:20:00 GMT</pubDate></item><item><title>Changing selenium's default tmp directory</title><link>https://ralph-heinkel.com/blog/changing-seleniums-default-tmp-dir/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;Whenever Selenium fires up Firefox (we are still running Selenium in RC mode)
a new Firefox profile directory will be create at every startup. Usually
this directory will be created in /tmp - which is for various reasons not
always the desired location.&lt;/p&gt;
&lt;p&gt;Selenium RC itself has no configuration option to change this location as
it relies on the default value provided by java. Fortunately java provides
a command line option &lt;code&gt;-Djava.io.tmpdir&lt;/code&gt; allowing to specify a new tmp directory.&lt;/p&gt;
&lt;p&gt;So change your startup call of Selenium RC to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;java -Djava.io.tmpdir=/your/tmp/dir -jar selenium-server.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and you're all set.&lt;/p&gt;</description><category>Java</category><category>Selenium</category><guid>https://ralph-heinkel.com/blog/changing-seleniums-default-tmp-dir/</guid><pubDate>Sun, 22 Jun 2014 13:22:00 GMT</pubDate></item><item><title>Publish-Subscribe with web sockets in Python and Firefox</title><link>https://ralph-heinkel.com/blog/publish-subscribe-with-python-websockets/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;WebSockets provide a way to communicate through a bi-directional channel on a single TCP connection. This technology
is especially interesting since it allows a web server to push data to a browser (client) without having the client
to constantly poll for it. In contrast to normal HTTP requests where a new TCP connection gets opened and closed for
each request web socket connections are kept open until one party closes them. This allows for communication in both
directions, and calls can be made multiple times on the same connection.&lt;/p&gt;
&lt;p&gt;In this little article I basically combine what I found on Sylvain Hellegouarch's documentation for
&lt;a href="https://github.com/Lawouach/WebSocket-for-Python"&gt;ws4py&lt;/a&gt; (a WebSocket client and server library for Python) and
the article &lt;a href="http://www.codeproject.com/Articles/209041/HTML5-Web-Socket-in-Essence"&gt;HTML5 Web Socket in Essence&lt;/a&gt;
by Wayne Ye.&lt;/p&gt;
&lt;p&gt;More specifically the examples below shows how multiple clients subscribe via websockets to a cherrypy server through
a web socket connection.
The first of the two clients in the example below is a very lightweight client based solely on the ws4py package, the
other (javascript) implementation is supposed to run in Firefox.&lt;/p&gt;
&lt;h3&gt;The server&lt;/h3&gt;
&lt;p&gt;This example provides a minimal publishing engine implemented with cherrypy. An instance of class &lt;code&gt;WebSocketTool&lt;/code&gt; is hooked up into
cherrypy as a so-called cherrypy tool, and a web socket handler (the &lt;code&gt;Publisher&lt;/code&gt;-class) is bound
to this tool as a handler for calls to the path &lt;code&gt;/ws&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket

cherrypy.config.update({'server.socket_port': 9000})
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()

SUBSCRIBERS = set()

class Publisher(WebSocket):
    def __init__(self, *args, **kw):
        WebSocket.__init__(self, *args, **kw)
        SUBSCRIBERS.add(self)

    def closed(self, code, reason=None):
        SUBSCRIBERS.remove(self)

class Root(object):
    @cherrypy.expose
    def index(self):
        return open('ws_browser.html').read()

    @cherrypy.expose
    def ws(self):
        "Method must exist to serve as a exposed hook for the websocket"

    @cherrypy.expose
    def notify(self, msg):
        for conn in SUBSCRIBERS:
            conn.send(msg)

cherrypy.quickstart(Root(), '/', 
    config={'/ws': {'tools.websocket.on': True,
                    'tools.websocket.handler_cls': Publisher}})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only purpose of the &lt;code&gt;Root.ws()&lt;/code&gt;-method is to make this method available under &lt;code&gt;/ws&lt;/code&gt; in the web server
through the &lt;code&gt;cherrypy.expose&lt;/code&gt; decorator.
Whenever a websocket client makes a request to &lt;code&gt;/ws&lt;/code&gt; an instance of class &lt;code&gt;Publisher&lt;/code&gt; is created,
which registers itself to the global &lt;code&gt;SUBSCRIBERS&lt;/code&gt; set on &lt;code&gt;__init__()&lt;/code&gt;. When the server goes down, or the
client disconnects, its &lt;code&gt;closed()&lt;/code&gt; method is called.&lt;/p&gt;
&lt;p&gt;The only packages needed for this example are cherrypy and ws4py. Both can be easily installed via &lt;code&gt;easy_install&lt;/code&gt; or
&lt;code&gt;pip&lt;/code&gt;. Save the code above as &lt;code&gt;ws_server.py&lt;/code&gt; and start it with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python ws_server.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the server is ready to accept client connections through the web socket protocol.
As soon as one of the clients described below has subscribed to this server messages can be published by calling the
&lt;code&gt;Root.notify()&lt;/code&gt; method. Since it is exposed it is possible to call it from the command line with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl localhost:9000/notify?msg=HelloWorld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course &lt;code&gt;wget&lt;/code&gt; works as well.&lt;/p&gt;
&lt;h3&gt;A pure Python client&lt;/h3&gt;
&lt;p&gt;The Python client's code is quite short. &lt;code&gt;ws4py&lt;/code&gt; provides three sample client implementations, the threaded one has been
chosen for this example. The others are using gevent or Tornado.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from ws4py.client.threadedclient import WebSocketClient

class Subscriber(WebSocketClient):
    def handshake_ok(self):
        self._th.start()
        self._th.join()

    def received_message(self, m):
        print "=&amp;gt; %d %s" % (len(m), str(m))

if __name__ == '__main__':
    ws = Subscriber('ws://localhost:9000/ws')
    ws.connect()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The method &lt;code&gt;handshake_ok()&lt;/code&gt; has been overridden to keep the thread stored in &lt;code&gt;self._th&lt;/code&gt;
running continuously (the original implementation quits after one second). After the &lt;code&gt;Subscriber&lt;/code&gt;-class has
been instantiated it connects to the cherrypy server. Whenever the server sends a message it will be delegated
to the method &lt;code&gt;received_message()&lt;/code&gt; where it gets printed to stdout.&lt;/p&gt;
&lt;p&gt;Just store this code into a file, e.g. &lt;code&gt;ws_subscriber.py&lt;/code&gt; and start it in from a new shell. The cherrypy server
should print a message to the console that it received a web socket connection.&lt;/p&gt;
&lt;p&gt;Now again call the &lt;code&gt;notify&lt;/code&gt;-method in the server:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl localhost:9000/notify?msg=HelloWorld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the python client should print your message to the screen.&lt;/p&gt;
&lt;h3&gt;A web socket client in Firefox&lt;/h3&gt;
&lt;p&gt;This browser client uses the web socket protocol built into Firefox. The example below works for me in FF14, it failed for FF8. I'm
not sure which version of Firefox starts to support it. Safari version 5.0 also fails. IE has not been tested.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;script&amp;gt;
      var websocket = new WebSocket('ws://localhost:9000/ws');
      websocket.onopen    = function (evt) { console.log("Connected to WebSocket server."); };
      websocket.onclose   = function (evt) { console.log("Disconnected"); };
      websocket.onmessage = function (evt) { document.getElementById('msg').innerHTML = evt.data; };
      websocket.onerror   = function (evt) { console.log('Error occured: ' + evt.data); };
    &amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Websocket demo&amp;lt;/h1&amp;gt;
    Message: &amp;lt;span id="msg" /&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At load time a &lt;code&gt;Websocket&lt;/code&gt;-instance is created and event handlers are installed. The interesting one
is the &lt;code&gt;onMessage&lt;/code&gt;-handler: it is called for each message received, it copies the message into the
SPAN element and thus makes it visible.&lt;/p&gt;
&lt;p&gt;Make sure to store this html page in the same directory as the &lt;code&gt;ws_server.py&lt;/code&gt; above since we are going to open it
through cherrypy's &lt;code&gt;index&lt;/code&gt; method. For this to work it has to be named &lt;code&gt;ws_browser.html&lt;/code&gt;.
Now open Firefox and direct it to &lt;code&gt;http://localhost:9000&lt;/code&gt;. You should immediately see this page.
The SPAN element should be empty.&lt;/p&gt;
&lt;p&gt;Again repeat the &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt; command in your shell and both the python client (if it is still running) and
the SPAN element should display your "HelloWorld" message.&lt;/p&gt;</description><category>Python</category><category>Websockets</category><guid>https://ralph-heinkel.com/blog/publish-subscribe-with-python-websockets/</guid><pubDate>Sun, 22 Jul 2012 15:20:00 GMT</pubDate></item><item><title>pyRserve 0.6.0 released</title><link>https://ralph-heinkel.com/blog/pyRserve-0.6.0-released/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;While being at EuroPython in Florence the latest version of pyRserve has now been finished and is
available via pypi (&lt;code&gt;easy_install -U pyRserve&lt;/code&gt;). If you are at EuroPython, too, and want to talk about
it just come and see me.&lt;/p&gt;
&lt;h3&gt;About pyRserve&lt;/h3&gt;
&lt;p&gt;pyRserve is a (pure python) client for connecting Python to an R process on a remote server via TCP-IP (using Rserve).
&lt;code&gt;R&lt;/code&gt; is one of the most important and most widely spread open source statistic packages available.&lt;/p&gt;
&lt;p&gt;Through such a pyRserve connection the full power of R is available on the Python side without programming in R.
From Python variables can get set in and retrieved from R, and R-functions can be called remotely.
No R-related libraries need to be installed on the client side.&lt;/p&gt;
&lt;h3&gt;Sample code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import pyRserve
&amp;gt;&amp;gt;&amp;gt; conn = pyRserve.connect('servername.domain.com')
&amp;gt;&amp;gt;&amp;gt; conn.r('1+1')                # direct evaluation of a statement in R
2
&amp;gt;&amp;gt;&amp;gt; conn.r.myList = [1, 2, 3]    # bind a Python list in R to variable 'myList'

&amp;gt;&amp;gt;&amp;gt; conn.r('func1 &amp;lt;- function(v) { v*2 }') # create a function in R
&amp;gt;&amp;gt;&amp;gt; conn.r.func1(4)                        # call the function in R
16
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Most important changes in V 0.6.0&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Support for Python 3.x (therefore dropped support for Python &amp;lt;= 2.5)&lt;/li&gt;
&lt;li&gt;Support for unicode strings&lt;/li&gt;
&lt;li&gt;Suport for Fortran-style ordering of numpy arrays&lt;/li&gt;
&lt;li&gt;Elements of single-item arrays are now translated to native python data types&lt;/li&gt;
&lt;li&gt;Full support complex numbers, partial support for 64bit integers and arrays&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Documentation and Support&lt;/h3&gt;
&lt;p&gt;The documentation for pyRserve is available at &lt;a href="http://packages.python.org/pyRserve"&gt;http://packages.python.org/pyRserve&lt;/a&gt;&lt;br&gt;
The corresponding Google news group can be found at
&lt;a href="http://groups.google.com/group/pyrserve"&gt;http://groups.google.com/group/pyrserve&lt;/a&gt;&lt;/p&gt;</description><category>pyRserve</category><category>Python</category><category>R</category><guid>https://ralph-heinkel.com/blog/pyRserve-0.6.0-released/</guid><pubDate>Wed, 04 Jul 2012 17:20:00 GMT</pubDate></item><item><title>pyRserve 0.5.2 released</title><link>https://ralph-heinkel.com/blog/pyRserve-0.5.2-released/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;The latest version is now available via pypi (&lt;code&gt;easy_install -U pyRserve&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;About pyRserve&lt;/h3&gt;
&lt;p&gt;pyRserve is a (pure python) client for connecting Python to an R process on a remote server via TCP-IP (using Rserve).
Through such a connection variables can be get and set in R from Python, and also R-functions can be called remotely.
No R-related libraries need to be installed on the client side.&lt;/p&gt;
&lt;h3&gt;Sample code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from pyRserve import connect
&amp;gt;&amp;gt;&amp;gt; conn = connect('your R server')
&amp;gt;&amp;gt;&amp;gt; conn.r('1+1')                # direct evaluation of a statement
2
&amp;gt;&amp;gt;&amp;gt; conn.r.myList = [1, 2, 3]    # bind a list within R to variable 'myList'

&amp;gt;&amp;gt;&amp;gt; conn.r('func1 &amp;lt;- function(v) { v*2 }') # create a function in R
&amp;gt;&amp;gt;&amp;gt; conn.r.func1(4)                        # call the function in R
16
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Changes in V 0.5.2&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Fixed bug with 32bit integer conversion on 64bit machines. Upgrade highly recommended!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Documentation and Support&lt;/h3&gt;
&lt;p&gt;The documentation for pyRserve is available at &lt;a href="http://packages.python.org/pyRserve"&gt;http://packages.python.org/pyRserve&lt;/a&gt;&lt;br&gt;
The corresponding Google news group can be found at
&lt;a href="http://groups.google.com/group/pyrserve"&gt;http://groups.google.com/group/pyrserve&lt;/a&gt;&lt;/p&gt;</description><category>pyRserve</category><category>Python</category><category>R</category><guid>https://ralph-heinkel.com/blog/pyRserve-0.5.2-released/</guid><pubDate>Tue, 06 Dec 2011 18:22:00 GMT</pubDate></item><item><title>pyRserve 0.5.0 released</title><link>https://ralph-heinkel.com/blog/pyRserve-0.5.0-released/</link><dc:creator>Ralph Heinkel</dc:creator><description>&lt;p&gt;The latest version is now available via pypi (&lt;code&gt;easy_install -U pyRserve&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;About pyRserve&lt;/h3&gt;
&lt;p&gt;pyRServe is a library for connecting Python to an R process running under Rserve.
Through such a connection variables can be get and set in R from Python, and also R-functions can be called remotely.&lt;/p&gt;
&lt;h3&gt;Changes in V 0.5.0&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Renamed pyRserve.rconnect() to pyRserve.connect(). The former still works but shows a DeprecationWarning&lt;/li&gt;
&lt;li&gt;String evaluation should now only be executed on the namespace directly, not on the connection object anymore. The latter still works but shows a DeprecationWarning.&lt;/li&gt;
&lt;li&gt;New kw argument atomicArray=True added to pyRserve.connect() for preventing single valued arrays from being converted into atomic python data types.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Documentation and Support&lt;/h3&gt;
&lt;p&gt;The documentation for pyRserve is available at &lt;a href="http://packages.python.org/pyRserve"&gt;http://packages.python.org/pyRserve&lt;/a&gt;&lt;br&gt;
The corresponding Google news group can be found at
&lt;a href="http://groups.google.com/group/pyrserve"&gt;http://groups.google.com/group/pyrserve&lt;/a&gt;&lt;/p&gt;</description><category>pyRserve</category><category>Python</category><category>R</category><guid>https://ralph-heinkel.com/blog/pyRserve-0.5.0-released/</guid><pubDate>Wed, 12 Oct 2011 13:22:00 GMT</pubDate></item></channel></rss>