“stomp.py” is a Python client library for accessing messaging servers (such as ActiveMQ or JBoss Messaging) using the STOMP protocol. It can also be run as a standalone, command-line client for testing.
It was created, because I experienced strange bugs with STOMPy, and wanted an apache-licensed library.
You can download the latest version from here, or checkout from the Mercurial repository here (see this blog entry for a bit of background on the repos… only if interested).
CONTRIBUTORS
Julian Scheid (Rising Sun Pictures - http://open.rsp.com.au)
Andreas Schobel
A simple example of using stomp.py is:
import time
import sys
import stomp
class MyListener(object):
def on_error(self, headers, message):
print 'received an error %s' % message
def on_message(self, headers, message):
print 'received a message %s' % message
conn = stomp.Connection()
conn.add_listener(MyListener())
conn.start()
conn.connect()
conn.subscribe(destination='/queue/test', ack='auto')
conn.send(' '.join(sys.argv[1:]), destination='/queue/test')
time.sleep(2)
conn.disconnect()
You can also use it from the command line by running:
python stomp.py localhost 61613
or
jython stomp.py localhost 61613
Then typing commands such as:
subscribe /queue/test
send /queue/test hello world

Hello,
I have recently started learning python and am currently on a project that requires me to use stomp. I noticed that your stomp.py example was posted a while ago.
My question is, how does stomp.py compare to pyactivemq? I am downloading stomp.py but would like to get your honest opinion.
Also, do you know of any good stomp tutorials out there for python
Thank you,
Ime
To be honest, I have no experience at all with pyactivemq. This is the first I’ve seen of it.
stomp.py was a quick hack so I could experiment with activemq, but I don’t currently have any need to use activemq, thus I haven’t done any development on this code for a while. If pyactivemq is under active development, it’s probably the preferable option.
About the only advantages I can say my version has are:
1. if you remove the “import select” at the top of the file, it will run as is with Jython, I believe. (I must get around to updating it myself).
2. the code is probably easier to understand if you’re learning
Sorry but I don’t know of any stomp tutorials out there.
There’s a typo in your example code. The line:
conn.addlistener(MyListener())
should read:
conn.add_listener(MyListener())
Hmm, you’ve also changed the syntax of commands with the latest commit.
This no longer works:
conn.subscribe(’/queue/test’)
Instead, use:
conn.subscribe(destination=’/queue/test’)
Right on both counts. Julian made same changes to my original code, to tidy things up, and improve functionality/performance/etc. He warned me I needed to update the example code… and I promptly forgot.
Thanks for the update.
Any idea when you’ll have a chance to update the example code?
Now…
Fixed an initial connection problem in the stomp code (I think), and the example now works (although with intermittent errors when running with Jython).
Hi, I’ve been using stomp.py a bit lately and noticed that the latest version doesn’t seem to work with login/passcodes. Lines 315 to 318 set values into __connect_headers, but those values are never actually used.
I fixed my own copy by altering my line 406 from:
self.__send_frame_helper(’CONNECT’, ”, self.__merge_headers([headers, keyword_headers]), [ ])
to:
self.__send_frame_helper(’CONNECT’, ”, self.__merge_headers([self.__connect_headers, headers, keyword_headers]), [ ])
Hi Greg. Sorry for the delay replying, but I’ve finally applied your suggested change.
Just another quick patch/suggestion. ActiveMQ cares about the case of header names whereas stomp.py converts all header names to lower case. I fixed that in my copy of stomp.py on line 449 by just removing the .lower(). Likely this area should be revisited. Should underscores really be replaced by dashes? I couldn’t find an official grammar specification for STOMP, so, who knows?
Don’t recally seeing an official spec either. I do recall the dashes being needed for a reason… but I can’t remember the reason. So might not be a valid assumption anyway.
Hi Jason!
Your library is GREAT! I’ve been playing with it extensively, both as a standalone client for debugging and as an embedded library in my own code.
It’s pure fun
Thanks a lot!!!
PS.: I have some small improvements to suggest regarding performance. Wouldn’t you like to publish the library under SourceForge or GoogleCode? So we could collaborate…
If they’re minor changes, I’m happy to receive patches. Although, I can be a bit slow to apply said patches at times…
Hi jason,
When I use stomp.py with ActiveMQ and your simple example, I can see a TCP Connection leak with JMX.
After debugging this code, I see that the variable self.__socket is set twice.
I corrected this problem with a lock on this method :
def __attempt_connection(self):
lock.acquire(1)
try:
self.__attempt_connection_no_synchronized()
finally: lock.release()
def __attempt_connection_no_synchronized(self):
there is another problem : If the listener doesn’t have the on_disconnected method , as your sample, an AttributeError is raised.
Corrected with a simple test on this attribute :
# Notify listeners
for listener in self.__listeners:
if hasattr(listener, ‘on_disconnected’):
listener.on_disconnected()
Conctact me, if you want an unified diff.
Best regards and Thanks for your implementation
Sorry for the delay. I’ve finally integrated your suggested change…
Hi Jason,
I had some strange behaviour with the client, some message is correct dequeued but not correct managed by the listener … with your simple example too. After the patch on the method __attempt_connection proposed by Lilians AUVIGNE, everithing work correctly.
Hi Jason! Me again…
This time, a small bugfix for the error:
2008-06-14 19:14:52,028 stomp.py ERROR An unhandled exception was encountered in the stomp receiver loop
Traceback (most recent call last):
File "/opt/lwb/eventmanager/stomp.py", line 507, in __receiver_loop
self.__attempt_connection()
File "/opt/lwb/eventmanager/stomp.py", line 663, in __attempt_connection
((self.__reconnect_sleep_initial / (1.0 + self.__reconnect_sleep_increase))
OverflowError: math range error
I have two daemons using stomp.py running on different machines on a fail-over configuration.
The instance that is waiting for the availability of ActiveMQ finally dies with an overflow error
because the ’sleep_exp’ variable is being incremented even if ’sleep_duration’ is greater than
‘__reconnect_sleep_max’. This is the fix I’ve implemented:
--- stomp.py 2008-06-16 16:57:01.000000000 +0100
+++ stomp.py.new 2008-06-16 17:00:23.000000000 +0100
@@ -672,7 +672,8 @@
while self.__running and time.time() < sleep_end:
time.sleep(0.2)
- sleep_exp += 1
+ if sleep_duration < self.__reconnect_sleep_max:
+ sleep_exp += 1
finally:
lock.release()
Thanks!!!
Hi,
I try to use stomp.py to communicate with ActiveMQ, everything is working fine, except one thing :
At the CONNECT request, ActiveMQ throws a (non fatal) exception :
DEBUG Transport - Transport failed: java.io.EOFException
java.io.EOFException
at java.io.DataInputStream.readByte(DataInputStream.java:243)
at org.apache.activemq.transport.stomp.StompWireFormat.readLine(StompWireFormat.java:186)
at org.apache.activemq.transport.stomp.StompWireFormat.unmarshal(StompWireFormat.java:94)
at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:203)
at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:195)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:183)
at java.lang.Thread.run(Thread.java:595)
But the connexion is OK.
I’ve tested with a Stomp C Client, but this exception doesn’t arise.
Have you got an idea on what’s happening ?
Thanks in advance…
Hi Julien
I’m afraid my stomp client is only intermittently supported at the moment. I don’t have a requirement to use it myself, so it’s only updated when people send me patches.
Apologies,
J
Since the on_connecting() method is called before the connect() method the host and port will always be None. Is it possible to set the __current_host_and_port member object before the TCP connection is made so this value has some meaning in on_connecting()?
connect() issues a Stomp CONNECT. Not the actual socket connect. on_connecting should be called after the TCP connection.
I encountered an irregularly occurring problem with CONNECT not being issued (testing with morbidQ, on Windows).
With debug logging on, I got “An unhandled exception was encountered in the stomp receiver loop”
It would seem that the problem was caused by a socket.error being thrown during in Connection.is_connected:
def is_connected(self):
return self.__socket is not None and self.__socket.getsockname()[1] != 0
Apparently (don’t know much about sockets myself), getsockname() can fail, although there is a socket. And the exception catching in the receiver loop causes the CONNECT to be skipped in that case.
I tried changing it to:
def is_connected(self):
try:
return self.__socket is not None and self.__socket.getsockname()[1] != 0
except socket.error:
return False
And that seems to solve it.
Thanks. Applied the change.
Its not everytime you download a library from the internet and it just works without you having to tweak with the code at all. This is one of those, I tried the example and the command line. Everything just works.
Thank You