stompy-0.2.9/ 0000755 0001750 0001750 00000000000 11435373146 012422 5 ustar bsmith bsmith stompy-0.2.9/stompy.egg-info/ 0000755 0001750 0001750 00000000000 11435373146 015447 5 ustar bsmith bsmith stompy-0.2.9/stompy.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 11435373146 021515 0 ustar bsmith bsmith
stompy-0.2.9/stompy.egg-info/PKG-INFO 0000644 0001750 0001750 00000004642 11435373146 016552 0 ustar bsmith bsmith Metadata-Version: 1.0
Name: stompy
Version: 0.2.9
Summary: Implementation of the STOMP protocol in Python.
Home-page: http://bitbucket.org/benjaminws/python-stomp/
Author: Benjamin W. Smith
Author-email: benjaminwarfield@just-another.net
License: BSD
Description:
==========================================
stompy - Python STOMP client library
==========================================
This is useful for connecting to and communicating with
Apache `ActiveMQ`_ (an open source `Java Message Service`_ (JMS)
message broker) or other brokers with support for the `STOMP`_ protocol.
The majority of the methods available take a single argument; a dictionary.
This dictionary should contain the necessary bits you need
to pass to the `STOMP`_ server. It is outlined in each method
exactly what it needs to work.
For specifics on the protocol, see the `STOMP protocol specification`_.
This library is basically a Python implementation of Perls `Net::Stomp`_.
To enable the `ActiveMQ`_ Broker for `STOMP`_ add the following to the
``activemq.xml`` configuration::
See http://bitbucket.org/benjaminws/python-stomp/ for latest code.
See http://packages.python.org/stompy/ for latest documentation.
.. _`ActiveMQ`: http://activemq.apache.org/
.. _`Java Message Service`: http://java.sun.com/products/jms/
.. _`STOMP`: http://stomp.codehaus.org/
.. _`STOMP protocol specification`: http://stomp.codehaus.org/Protocol
.. _`Net::Stomp`: http://search.cpan.org/perldoc?Net::Stomp
Thanks for patches and support go out to:
Ask Solem Hoel (asksol) http://github.com/ask
Victor Ng (crankycoder) http://crankycoder.com/
Justin Azoff (justinazoff) http://www.bouncybouncy.net/
Keywords: stomp activemq jms messaging
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries
stompy-0.2.9/stompy.egg-info/top_level.txt 0000644 0001750 0001750 00000000007 11435373146 020176 0 ustar bsmith bsmith stompy
stompy-0.2.9/stompy.egg-info/SOURCES.txt 0000644 0001750 0001750 00000000350 11435373146 017331 0 ustar bsmith bsmith README
setup.cfg
setup.py
stompy/__init__.py
stompy/distmeta.py
stompy/frame.py
stompy/simple.py
stompy/stomp.py
stompy.egg-info/PKG-INFO
stompy.egg-info/SOURCES.txt
stompy.egg-info/dependency_links.txt
stompy.egg-info/top_level.txt stompy-0.2.9/PKG-INFO 0000644 0001750 0001750 00000004642 11435373146 013525 0 ustar bsmith bsmith Metadata-Version: 1.0
Name: stompy
Version: 0.2.9
Summary: Implementation of the STOMP protocol in Python.
Home-page: http://bitbucket.org/benjaminws/python-stomp/
Author: Benjamin W. Smith
Author-email: benjaminwarfield@just-another.net
License: BSD
Description:
==========================================
stompy - Python STOMP client library
==========================================
This is useful for connecting to and communicating with
Apache `ActiveMQ`_ (an open source `Java Message Service`_ (JMS)
message broker) or other brokers with support for the `STOMP`_ protocol.
The majority of the methods available take a single argument; a dictionary.
This dictionary should contain the necessary bits you need
to pass to the `STOMP`_ server. It is outlined in each method
exactly what it needs to work.
For specifics on the protocol, see the `STOMP protocol specification`_.
This library is basically a Python implementation of Perls `Net::Stomp`_.
To enable the `ActiveMQ`_ Broker for `STOMP`_ add the following to the
``activemq.xml`` configuration::
See http://bitbucket.org/benjaminws/python-stomp/ for latest code.
See http://packages.python.org/stompy/ for latest documentation.
.. _`ActiveMQ`: http://activemq.apache.org/
.. _`Java Message Service`: http://java.sun.com/products/jms/
.. _`STOMP`: http://stomp.codehaus.org/
.. _`STOMP protocol specification`: http://stomp.codehaus.org/Protocol
.. _`Net::Stomp`: http://search.cpan.org/perldoc?Net::Stomp
Thanks for patches and support go out to:
Ask Solem Hoel (asksol) http://github.com/ask
Victor Ng (crankycoder) http://crankycoder.com/
Justin Azoff (justinazoff) http://www.bouncybouncy.net/
Keywords: stomp activemq jms messaging
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries
stompy-0.2.9/setup.py 0000644 0001750 0001750 00000001515 11432420052 014120 0 ustar bsmith bsmith from setuptools import setup, find_packages
from stompy import distmeta
setup(name='stompy',
version=distmeta.__version__,
description=distmeta.__doc__,
long_description=distmeta.__long_description__,
author=distmeta.__author__,
author_email=distmeta.__contact__,
packages = ['stompy'],
license='BSD',
url=distmeta.__homepage__,
keywords='stomp activemq jms messaging',
test_suite="nose.collector",
classifiers=["Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Topic :: Software Development :: Libraries",
],
)
stompy-0.2.9/stompy/ 0000755 0001750 0001750 00000000000 11435373146 013755 5 ustar bsmith bsmith stompy-0.2.9/stompy/simple.py 0000644 0001750 0001750 00000013103 11432416543 015612 0 ustar bsmith bsmith from stompy.stomp import Stomp
from Queue import Empty
from uuid import uuid4
class TransactionError(Exception):
"""Transaction related error."""
class Client(object):
"""Simple STOMP client.
:keyword host: Hostname of the server to connect to (default:
``localhost``)
:keyword port: Port of the server to connect to (default: ``61613``)
Example
>>> from stompy.simple import Client
>>> stomp = Client()
>>> stomp.connect()
>>> stomp.put("The quick brown fox...", destination="/queue/test")
>>> stomp.subscribe("/queue/test")
>>> message = stomp.get_nowait()
>>> message.body
'The quick brown fox...'
>>> stomp.ack(message)
>>> stomp.unsubscribe("/queue/test")
>>> stomp.disconnect()
"""
Empty = Empty
def __init__(self, host="localhost", port=61613):
self.stomp = Stomp(host, port)
self._current_transaction = None
def get(self, block=True, callback=None):
"""Get message.
:keyword block: Block if necessary until an item is available.
If this is ``False``, return an item if one is immediately
available, else raise the :exc:`Empty` exception.
:keyword callback: Optional function to execute when message recieved.
:raises Empty: If ``block`` is off and no message was receied.
"""
frame = self.stomp.receive_frame(nonblocking=not block, callback=callback)
if frame is None and not block:
raise self.Empty()
return frame
def get_nowait(self):
"""Remove and return an item from the queue without blocking.
Only get an item if one is immediately available. Otherwise
raise the :exc:`Empty` exception.
See :meth:`get`.
"""
return self.get(block=False)
def put(self, item, destination, persistent=True, conf=None):
"""Put an item into the queue.
:param item: Body of the message.
:param destination: Destination queue.
:keyword persistent: Is message persistent? (store on disk).
:keyword conf: Extra headers to send to the broker.
:returns: The resulting :class:`stompy.frame.Frame` instance.
"""
persistent = "true" if persistent else "false"
conf = self._make_conf(conf, body=item, destination=destination,
persistent=persistent)
return self.stomp.send(conf)
def connect(self, username=None, password=None, clientid=None):
"""Connect to the broker.
:keyword username: Username for connection
:keyword password: Password for connection
:keyword clientid: Client identification for persistent connections
:raises :exc:`stompy.stomp.ConnectionError`:
if the connection was unsuccessful.
:raises :exc:`stompy.stomp.ConnectionTimeoutError`:
if the connection timed out.
"""
self.stomp.connect(username=username, password=password, clientid=clientid)
def disconnect(self):
"""Disconnect from the broker."""
self.stomp.disconnect()
def subscribe(self, destination, ack="auto", conf=None):
"""Subscribe to topic/queue.
:param destination: The destination queue/topic to subscribe to.
:keyword ack: How to handle acknowledgment, either
``auto`` - ack is handled by the server automatically, or
``client`` - ack is handled by the client itself by calling
:meth:`ack`.
:keyword conf: Additional headers to send with the subscribe request.
"""
conf = self._make_conf(conf, destination=destination, ack=ack)
return self.stomp.subscribe(conf)
def unsubscribe(self, destination, conf=None):
"""Unsubscribe from topic/queue previously subscribed to.
:param destination: The destination queue/topic to unsubscribe from.
:keyword conf: Additional headers to send with the unsubscribe
request.
"""
conf = self._make_conf(conf, destination=destination)
return self.stomp.unsubscribe(conf)
def begin(self, transaction):
"""Begin transaction.
Every :meth:`ack` and :meth:`send` will be affected by this
transaction and won't be real until a :meth:`commit` is issued.
To roll-back any changes since the transaction started use
:meth:`abort`.
"""
if self._current_transaction:
raise TransactionError(
"Already in transaction. Please commit or abort first!")
self._current_transaction = str(uuid4())
return self.stomp.begin({"transaction": self._current_transaction})
def commit(self, transaction):
"""Commit current transaction."""
if not self._current_transaction:
raise TransactionError("Not in transaction")
self.stomp.commit({"transaction": self._current_transaction})
self._current_transaction = None
def abort(self):
"""Roll-back current transaction."""
if not self._current_transaction:
raise TransactionError("Not in transaction")
self.stomp.abort({"transaction": self._current_transaction})
self._current_transaction = None
def ack(self, frame):
"""Acknowledge message.
:param frame: The message to acknowledge.
"""
return self.stomp.ack(frame)
def _make_conf(self, conf, **kwargs):
kwargs.update(dict(conf or {}))
if self._current_transaction:
conf["transaction"] = self._current_transaction
return kwargs
stompy-0.2.9/stompy/distmeta.py 0000644 0001750 0001750 00000003766 11435352315 016150 0 ustar bsmith bsmith """Implementation of the STOMP protocol in Python.
"""
VERSION = (0, 2, 9)
__version__ = ".".join(map(str, VERSION))
__author__ = "Benjamin W. Smith"
__contact__ = "benjaminwarfield@just-another.net"
__homepage__ = "http://bitbucket.org/benjaminws/python-stomp/"
__docformat__ = "restructuredtext"
__long_description__ = """
==========================================
stompy - Python STOMP client library
==========================================
This is useful for connecting to and communicating with
Apache `ActiveMQ`_ (an open source `Java Message Service`_ (JMS)
message broker) or other brokers with support for the `STOMP`_ protocol.
The majority of the methods available take a single argument; a dictionary.
This dictionary should contain the necessary bits you need
to pass to the `STOMP`_ server. It is outlined in each method
exactly what it needs to work.
For specifics on the protocol, see the `STOMP protocol specification`_.
This library is basically a Python implementation of Perls `Net::Stomp`_.
To enable the `ActiveMQ`_ Broker for `STOMP`_ add the following to the
``activemq.xml`` configuration::
See http://bitbucket.org/benjaminws/python-stomp/ for latest code.
See http://packages.python.org/stompy/ for latest documentation.
.. _`ActiveMQ`: http://activemq.apache.org/
.. _`Java Message Service`: http://java.sun.com/products/jms/
.. _`STOMP`: http://stomp.codehaus.org/
.. _`STOMP protocol specification`: http://stomp.codehaus.org/Protocol
.. _`Net::Stomp`: http://search.cpan.org/perldoc?Net::Stomp
Thanks for patches and support go out to:
Ask Solem Hoel (asksol) http://github.com/ask
Victor Ng (crankycoder) http://crankycoder.com/
Justin Azoff (justinazoff) http://www.bouncybouncy.net/
"""
def is_stable_release():
return bool(not VERSION[1] % 2)
def version_with_meta():
meta = "unstable"
if is_stable_release():
meta = "stable"
return "%s (%s)" % (__version__, meta)
stompy-0.2.9/stompy/__init__.py 0000644 0001750 0001750 00000000337 11432416543 016065 0 ustar bsmith bsmith from stompy.stomp import Stomp, NotConnectedError
from stompy.simple import Client, Empty, TransactionError
from stompy.distmeta import __version__
from stompy.distmeta import __doc__, __author__, __contact__, __homepage__
stompy-0.2.9/stompy/stomp.py 0000644 0001750 0001750 00000017532 11432416543 015475 0 ustar bsmith bsmith import socket
from stompy.frame import Frame
from functools import wraps
class NotConnectedError(Exception):
"""No longer connected to the STOMP server."""
class ConnectionError(socket.error):
"""Couldn't connect to the STOMP server."""
class ConnectionTimeoutError(socket.timeout):
"""Timed-out while establishing connection to the STOMP server."""
class Stomp(object):
"""STOMP Client.
:param hostname: Hostname of the STOMP server to connect to.
:param port: The port to use. (default ``61613``)
"""
ConnectionError = ConnectionError
ConnectionTimeoutError = ConnectionTimeoutError
NotConnectedError = NotConnectedError
def __init__(self, hostname, port=61613):
self.host = hostname
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._subscribed_to = {}
self._subscribed = None
self._callback = None
self.connected = None
self.frame = Frame()
def connect(self, username=None, password=None, clientid=None):
"""Connect to STOMP server.
:keyword username: Username for connection
:keyword password: Password for connection
:keyword clientid: Client identification for persistent connections
"""
try:
self.sock.connect((self.host, self.port))
self.frame.connect(self.sock, username=username, password=password, clientid=clientid)
except socket.timeout, exc:
raise self.ConnectionTimeoutError(*exc.args)
except socket.error, exc:
raise self.ConnectionError(*exc.args)
self.connected = True
def disconnect(self, conf=None):
"""Disconnect from the server."""
try:
for destination in self._subscribed_to.keys():
self.unsubscribe({"destination": destination})
self._send_command("DISCONNECT", conf)
except self.NotConnectedError:
pass
try:
self.sock.shutdown(0)
self.sock.close()
except socket.error, exc:
# likely wasn't connected
pass
self.connected = False
def send(self, conf=None):
"""Send message to STOMP server
You'll need to pass the body and any other headers your
STOMP server likes.
destination is **required**
In the case of ActiveMQ with persistence, you could do this:
>>> for i in xrange(1,1000):
... stomp.send({'destination': '/queue/foo',
... 'body': 'Testing',
... 'persistent': 'true'})
"""
headers = dict(conf)
body = headers.pop("body", "")
return self._send_command("SEND", headers, extra={"body": body},
want_receipt=True)
def _build_frame(self, *args, **kwargs):
self._connected_or_raise()
return self.frame.build_frame(*args, **kwargs)
def subscribe(self, conf=None):
"""Subscribe to a given destination
You will need to pass any headers your STOMP server likes.
destination is *required*
In the case of ActiveMQ, you could do this:
>>> stomp.subscribe({'destination':'/queue/foo',
... 'ack':'client'})
"""
destination = conf["destination"]
self._send_command("SUBSCRIBE", conf)
self._subscribed_to[destination] = True
def begin(self, conf=None):
"""Begin transaction.
You will need to pass any headers your STOMP server likes.
destination is *required*
In the case of ActiveMQ, you could do this:
>>> stomp.begin({'transaction':''})
"""
self._send_command("BEGIN", conf)
def commit(self, conf=None):
"""Commit transaction.
You will need to pass any headers your STOMP server likes.
destination is **required**
In the case of ActiveMQ, you could do this:
>>> stomp.commit({'transaction':''})
"""
self._send_command("COMMIT", conf)
def abort(self, conf=None):
"""Abort transaction.
In the case of ActiveMQ, you could do this:
>>> stomp.abort({'transaction':''})
"""
self._send_command("ABORT", conf)
def unsubscribe(self, conf=None):
"""Unsubscribe from a given destination
You will need to pass any headers your STOMP server likes.
destination is *required*
>>> stomp.unsubscribe({'destination':'/queue/foo'})
"""
destination = conf["destination"]
self._send_command("UNSUBSCRIBE", conf)
self._subscribed_to.pop(destination, None)
def ack(self, frame):
"""Acknowledge receipt of a message
:param: A :class:`stompy.frame.Frame` instance.
Example
>>> while True:
... frame = stomp.receive_frame()
... stomp.ack(frame)
"""
message_id = frame.headers.get('message-id')
self._send_command("ACK", {"message-id": message_id})
def receive_frame(self, callback=None, nonblocking=False):
"""Get a frame from the STOMP server
:keyword nonblocking: By default this function waits forever
until there is a message to be received, however, in non-blocking
mode it returns ``None`` if there is currently no message
available.
:keyword callback: Optional function to execute when message recieved.
Note that you must be subscribed to one or more destinations.
Use :meth:`subscribe` to subscribe to a topic/queue.
Example: Blocking
>>> while True:
... frame = stomp.receive_frame()
... print(frame.headers['message-id'])
... stomp.ack(frame)
Example: Non-blocking
>>> frame = stomp.recieve_frame(nonblocking=True)
>>> if frame:
... process_message(frame)
... else:
... # no messages yet.
"""
self._connected_or_raise()
self._callback = callback
message = None
if self._callback:
message = self.frame.get_message(nb=nonblocking)
self._callback(message)
return
else:
return self.frame.get_message(nb=nonblocking)
def poll(self, callback=None):
"""Alias to :meth:`receive_frame` with ``nonblocking=True``."""
return self.receive_frame(nonblocking=True, callback=callback)
def send_frame(self, frame):
"""Send a custom frame to the STOMP server
:param frame: A :class:`stompy.frame.Frame` instance.
Example
>>> from stompy import Frame
>>> frame = Frame().build_frame({
... "command": "DISCONNECT",
... "headers": {},
... })
>>> stomp.send_frame(frame)
"""
self._connected_or_raise()
frame = self.frame.send_frame(frame.as_string())
return frame
def _send_command(self, command, conf=None, extra=None, **kwargs):
conf = conf or {}
extra = extra or {}
frame_conf = {"command": command, "headers": conf}
frame_conf.update(extra)
frame = self._build_frame(frame_conf, **kwargs)
reply = self.send_frame(frame)
if kwargs.get("want_receipt", False):
return reply
return frame
def _connected_or_raise(self):
if not self.connected:
raise self.NotConnectedError("Not connected to STOMP broker.")
@property
def subscribed(self):
"""**DEPRECATED** The queue or topic currently subscribed to."""
as_list = self._subscribed_to.keys()
if not as_list:
return
return as_list[0]
stompy-0.2.9/stompy/frame.py 0000644 0001750 0001750 00000021475 11435351710 015423 0 ustar bsmith bsmith import socket
import random
from pprint import pformat
from errno import EAGAIN, EWOULDBLOCK
from Queue import Queue
from Queue import Empty as QueueEmpty
class UnknownBrokerResponseError(Exception):
"""An unexpected response was received from the broker."""
class BrokerErrorResponse(Exception):
"""Received error from the broker."""
class IntermediateMessageQueue(object):
"""Internal message queue that holds messages received by the server.
This to make sure a message isn't received instead of a command response
after issuing a receipt request.
"""
def __init__(self):
self._queue = Queue()
def put(self, frame):
"""Put a new frame onto the message queue.
:param frame: A :class:`Frame` instance.
"""
if "destination" not in frame.headers:
return
self._queue.put(frame)
def get(self, frame, nb=False):
"""Get a new frame from the message queue.
If no frame is available it try to get the next frame
from the socket.
:param frame: A :class:`Frame` instance.
:keyword nb: Non-blocking.
"""
try:
return self._queue.get_nowait()
except QueueEmpty:
return frame.parse_frame(nb=nb)
class Frame(object):
"""Build and manage a STOMP Frame.
:keyword sock: An open socket to the STOMP server.
"""
def __init__(self, sock=None):
self.command = None
self.headers = {}
self.body = None
self.session = None
self.my_name = socket.gethostbyname(socket.gethostname())
self.sock = sock
self.iqueue = IntermediateMessageQueue()
self.rqueue = Queue()
def connect(self, sock, username=None, password=None, clientid=None):
"""Connect to the STOMP server and get the session id.
:param sock: Socket object from stompy.stomp.Stomp.
:keyword username: Username for connection.
:keyword password: Password for connection.
:keyword clientid: Client identification for persistent connections
"""
self.sock = sock
headers = {}
if username and password:
headers.update({'login': username,
'passcode': password})
if clientid:
headers.update({'client-id' : clientid})
frame = self.build_frame({"command": "CONNECT", "headers": headers})
self.send_frame(frame.as_string())
# Get session from the next reply from the server.
next_frame = self.get_reply()
self.session = next_frame.headers
def build_frame(self, args, want_receipt=False):
"""Build a frame based on a :class:`dict` of arguments.
:param args: A :class:`dict` of arguments for the frame.
:keyword want_receipt: Optional argument to get a receipt from
the sever that the frame was received.
Example
>>> frame = frameobj.build_frame({"command": 'CONNECT',
"headers": {},
want_receipt=True)
"""
self.command = args.get('command')
self.headers = args.get('headers')
self.body = args.get('body')
if want_receipt:
receipt_stamp = str(random.randint(0, 10000000))
self.headers["receipt"] = "%s-%s" % (
self.session.get("session"), receipt_stamp)
return self
def as_string(self):
"""Raw string representation of this frame
Suitable for passing over a socket to the STOMP server.
Example
>>> stomp.send(frameobj.as_string())
"""
command = self.command
headers = self.headers
body = self.body
bytes_message = False
if 'bytes_message' in headers:
bytes_message = True
del headers['bytes_message']
headers['content-length'] = len(body)
headers['x-client'] = self.my_name
# Convert and append any existing headers to a string as the
# protocol describes.
headerparts = ("%s:%s\n" % (key, value)
for key, value in headers.iteritems())
# Frame is Command + Header + EOF marker.
frame = "%s\n%s\n%s\x00" % (command, "".join(headerparts), body)
return frame
def get_message(self, nb=False):
"""Get next message frame.
:keyword nb: Non-blocking: If this is set and there is no
messages currently waiting, this functions returns ``None``
instead of waiting for more data.
"""
while True:
frame = self.iqueue.get(self, nb=nb)
if not frame and nb:
return None
if frame.command == "MESSAGE":
return frame
else:
self.rqueue.put(frame)
def get_reply(self, nb=False):
"""Get command reply frame.
:keyword nb: Non-blocking: If this is set and there is no
messages currently waiting, this functions returns ``None``
instead of waiting for more data.
"""
while True:
try:
return self.rqueue.get_nowait()
except QueueEmpty:
frame = self.parse_frame(nb=nb)
if not frame and nb:
return None
if frame.command == "MESSAGE":
self.iqueue.put(frame)
else:
self.rqueue.put(frame)
def parse_frame(self, nb=False):
"""Parse data from socket
:keyword nb: Non-blocking: If this is set and there is no
messages currently waiting, this functions returns ``None``
instead of waiting for more data.
Example
>>> frameobj.parse_frame()
"""
line = self._getline(nb=nb)
if not line:
return
command = self.parse_command(line)
line = line[len(command)+1:]
headers_str, _, body = line.partition("\n\n")
if not headers_str:
raise UnknownBrokerResponseError(
"Received: (%s)" % line)
headers = self.parse_headers(headers_str)
if 'content-length' in headers:
headers['bytes_message'] = True
if command == 'ERROR':
raise BrokerErrorResponse(
"Broker Returned Error: %s" % body)
frame = Frame(self.sock)
return frame.build_frame({'command': command,
'headers': headers,
'body': body})
def parse_command(self, command_str):
"""Parse command received from the server.
:param command_str: String to parse command from
"""
command = command_str.split('\n', 1)[0]
return command
def parse_headers(self, headers_str):
"""Parse headers received from the servers and convert
to a :class:`dict`.i
:param headers_str: String to parse headers from
"""
# george:constanza\nelaine:benes
# -> {"george": "constanza", "elaine": "benes"}
return dict(line.split(":", 1) for line in headers_str.split("\n"))
def send_frame(self, frame):
"""Send frame to server, get receipt if needed.
:param frame: :class:`Frame` instance to pass across the socket
"""
self.sock.sendall(frame)
if 'receipt' in self.headers:
return self.get_reply()
def _getline(self, nb=False):
"""Get a single line from socket
:keyword nb: Non-blocking: If this is set, and there are no
messages to receive, this function returns ``None``.
"""
self.sock.setblocking(not nb)
try:
buffer = ''
partial = ''
while not buffer.endswith('\x00'):
try:
partial = self.sock.recv(1)
if not partial or partial == '':
raise UnknownBrokerResponseError('empty reply')
except socket.error, exc:
if exc[0] == EAGAIN or exc[0] == EWOULDBLOCK:
if not buffer or buffer == '\n':
raise UnknownBrokerResponseError('empty reply')
continue
buffer += partial
finally:
self.sock.setblocking(nb)
# ** Nasty Alert **
# There may be a left over newline
# RabbitMQ doesn't have a newline after \x00
# ActiveMQ does. This is a hack around that.
# http://stomp.codehaus.org/Protocol mentions
# nothing about a newline following the NULL (^@)
if buffer[:1] == '\n':
return buffer[1:-1]
return buffer[:-1]
def __repr__(self):
return "" % pformat(self.headers)
stompy-0.2.9/setup.cfg 0000644 0001750 0001750 00000000512 11435373146 014241 0 ustar bsmith bsmith [build_sphinx]
all_files = 1
build-dir = docs/build
source-dir = docs/
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
[upload_sphinx]
upload-dir = docs/build/html
[nosetests]
cover-package = stompy
verbosity = 1
with-coverage = 1
cover-erase = True
detailed-errors = 1
match = ((?:^|[b_.-])(:?[Tt]est|When|should))
stompy-0.2.9/README 0000644 0001750 0001750 00000002632 11432416543 013301 0 ustar bsmith bsmith ==========================================
stompy - Python STOMP client library
==========================================
This is useful for connecting to and communicating with
Apache `ActiveMQ`_ (an open source `Java Message Service`_ (JMS)
message broker) or other brokers with support for the `STOMP`_ protocol.
The majority of the methods available take a single argument; a dictionary.
This dictionary should contain the necessary bits you need
to pass to the `STOMP`_ server. It is outlined in each method
exactly what it needs to work.
For specifics on the protocol, see the `STOMP protocol specification`_.
This library is basically a Python implementation of Perl's `Net::Stomp`_.
To enable the `ActiveMQ`_ Broker for `STOMP`_ add the following to the
``activemq.xml`` configuration::
See http://bitbucket.org/benjaminws/python-stomp/ for latest code.
.. _`ActiveMQ`: http://activemq.apache.org/
.. _`Java Message Service`: http://java.sun.com/products/jms/
.. _`STOMP`: http://stomp.codehaus.org/
.. _`STOMP protocol specification`: http://stomp.codehaus.org/Protocol
.. _`Net::Stomp`: http://search.cpan.org/perldoc?Net::Stomp
Thanks for patches and support go out to:
Ask Solem Hoel (asksol) http://github.com/ask
Victor Ng (crankycoder) http://crankycoder.com/
Justin Azoff (justinazoff) http://www.bouncybouncy.net/