From 6460f4d8e8ca25b1141f454fa93dee433c60cfb2 Mon Sep 17 00:00:00 2001 From: Andrew Stitcher Date: Wed, 4 Dec 2013 22:19:02 +0000 Subject: QPID-5394: Fix the binding dependencies so that we no longer keep on rebuilding the python swig bindings unnecessarily git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1547933 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/cpp/bindings/qmf2/python/CMakeLists.txt | 25 +- qpid/cpp/bindings/qmf2/python/cqmf2.i | 41 +++ qpid/cpp/bindings/qmf2/python/python.i | 41 --- qpid/cpp/bindings/qmf2/ruby/CMakeLists.txt | 8 +- qpid/cpp/bindings/qpid/python/CMakeLists.txt | 18 +- qpid/cpp/bindings/qpid/python/python.i | 483 ------------------------- qpid/cpp/bindings/qpid/python/qpid_messaging.i | 483 +++++++++++++++++++++++++ qpid/cpp/bindings/qpid/ruby/CMakeLists.txt | 8 +- 8 files changed, 565 insertions(+), 542 deletions(-) create mode 100644 qpid/cpp/bindings/qmf2/python/cqmf2.i delete mode 100644 qpid/cpp/bindings/qmf2/python/python.i delete mode 100644 qpid/cpp/bindings/qpid/python/python.i create mode 100644 qpid/cpp/bindings/qpid/python/qpid_messaging.i (limited to 'qpid/cpp/bindings') diff --git a/qpid/cpp/bindings/qmf2/python/CMakeLists.txt b/qpid/cpp/bindings/qmf2/python/CMakeLists.txt index 851a33f4e4..b000937ee6 100644 --- a/qpid/cpp/bindings/qmf2/python/CMakeLists.txt +++ b/qpid/cpp/bindings/qmf2/python/CMakeLists.txt @@ -20,13 +20,25 @@ ##------------------------------------------------------ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") -swig_add_module(cqmf2_python python ${CMAKE_CURRENT_SOURCE_DIR}/python.i) -swig_link_libraries(cqmf2_python qmf2 ${PYTHON_LIBRARIES}) +# NB For python the SWIG module name must have the same name as the input .i file for CMake to generate the +# correct dependencies -set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${PYTHON_INCLUDE_PATH} -I${qpid-cpp_SOURCE_DIR}/include") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/cqmf2.i PROPERTIES + CPLUSPLUS ON + SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") + +list(APPEND SWIG_MODULE_cqmf2_EXTRA_DEPS + ${CMAKE_SOURCE_DIR}/include/qmf/qmf2.i + ${CMAKE_SOURCE_DIR}/include/qpid/swig_python_typemaps.i +) +swig_add_module(cqmf2 python ${CMAKE_CURRENT_SOURCE_DIR}/cqmf2.i) +swig_link_libraries(cqmf2 qmf2 ${PYTHON_LIBRARIES}) + +set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") +include_directories(${PYTHON_INCLUDE_PATH} + ${qpid-cpp_SOURCE_DIR}/include + ${qpid-cpp_SOURCE_DIR}/bindings) # Move source into binary dir so compiled .pyc,pyo files will be in binary dir. # NOTE: not using the file(COPY) command as it is not available in cmake 2.6 @@ -55,8 +67,7 @@ install(FILES COMPONENT ${QPID_COMPONENT_CLIENT} ) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/_cqmf2_python.so - RENAME _cqmf2.so +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/_cqmf2.so DESTINATION ${PYTHON_SITEARCH_PACKAGES} COMPONENT ${QPID_COMPONENT_CLIENT} ) diff --git a/qpid/cpp/bindings/qmf2/python/cqmf2.i b/qpid/cpp/bindings/qmf2/python/cqmf2.i new file mode 100644 index 0000000000..6b5326f8cf --- /dev/null +++ b/qpid/cpp/bindings/qmf2/python/cqmf2.i @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +%module cqmf2 +%include "std_string.i" +%include "qpid/swig_python_typemaps.i" + +/* Define the general-purpose exception handling */ +%exception { + std::string error; + Py_BEGIN_ALLOW_THREADS; + try { + $action + } catch (qpid::types::Exception& ex) { + error = ex.what(); + } + Py_END_ALLOW_THREADS; + if (!error.empty()) { + PyErr_SetString(PyExc_RuntimeError, error.c_str()); + return NULL; + } +} + +%include "qmf/qmf2.i" + diff --git a/qpid/cpp/bindings/qmf2/python/python.i b/qpid/cpp/bindings/qmf2/python/python.i deleted file mode 100644 index 6b5326f8cf..0000000000 --- a/qpid/cpp/bindings/qmf2/python/python.i +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -%module cqmf2 -%include "std_string.i" -%include "qpid/swig_python_typemaps.i" - -/* Define the general-purpose exception handling */ -%exception { - std::string error; - Py_BEGIN_ALLOW_THREADS; - try { - $action - } catch (qpid::types::Exception& ex) { - error = ex.what(); - } - Py_END_ALLOW_THREADS; - if (!error.empty()) { - PyErr_SetString(PyExc_RuntimeError, error.c_str()); - return NULL; - } -} - -%include "qmf/qmf2.i" - diff --git a/qpid/cpp/bindings/qmf2/ruby/CMakeLists.txt b/qpid/cpp/bindings/qmf2/ruby/CMakeLists.txt index 4ea61abbe8..c40480ff4a 100644 --- a/qpid/cpp/bindings/qmf2/ruby/CMakeLists.txt +++ b/qpid/cpp/bindings/qmf2/ruby/CMakeLists.txt @@ -20,7 +20,9 @@ ##------------------------------------------------------ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES + CPLUSPLUS ON + SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") if ((${CMAKE_MAJOR_VERSION} EQUAL 2) AND (${CMAKE_MINOR_VERSION} LESS 8)) set (RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_PATH}) @@ -30,6 +32,10 @@ include_directories(${RUBY_INCLUDE_DIRS} ${qpid-cpp_SOURCE_DIR}/include ${qpid-cpp_SOURCE_DIR}/bindings) +list(APPEND SWIG_MODULE_cqmf2_ruby_EXTRA_DEPS + ${CMAKE_SOURCE_DIR}/include/qmf/qmf2.i + ${CMAKE_SOURCE_DIR}/include/qpid/swig_ruby_typemaps.i +) swig_add_module(cqmf2_ruby ruby ${CMAKE_CURRENT_SOURCE_DIR}/ruby.i) swig_link_libraries(cqmf2_ruby qmf2 ${RUBY_LIBRARY}) diff --git a/qpid/cpp/bindings/qpid/python/CMakeLists.txt b/qpid/cpp/bindings/qpid/python/CMakeLists.txt index 15f9bbb9f7..56ea0e9349 100644 --- a/qpid/cpp/bindings/qpid/python/CMakeLists.txt +++ b/qpid/cpp/bindings/qpid/python/CMakeLists.txt @@ -20,15 +20,19 @@ ##------------------------------------------------------ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i - PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") -list(APPEND SWIG_MODULE_qpid_messaging_python_EXTRA_DEPS - ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/qpid/qpid.i - ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/qpid/swig_python_typemaps.i +# NB For python the SWIG module name must have the same name as the input .i file for CMake to generate the +# correct dependencies + +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/qpid_messaging.i PROPERTIES + CPLUSPLUS ON + SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") + +list(APPEND SWIG_MODULE_qpid_messaging_EXTRA_DEPS + ${CMAKE_SOURCE_DIR}/include/qpid/qpid.i + ${CMAKE_SOURCE_DIR}/include/qpid/swig_python_typemaps.i ) -swig_add_module(qpid_messaging python ${CMAKE_CURRENT_SOURCE_DIR}/python.i) +swig_add_module(qpid_messaging python ${CMAKE_CURRENT_SOURCE_DIR}/qpid_messaging.i) swig_link_libraries(qpid_messaging qpidmessaging qpidtypes ${PYTHON_LIBRARIES}) set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") diff --git a/qpid/cpp/bindings/qpid/python/python.i b/qpid/cpp/bindings/qpid/python/python.i deleted file mode 100644 index 624cee35bc..0000000000 --- a/qpid/cpp/bindings/qpid/python/python.i +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -%module qpid_messaging - -%include "std_string.i" -%include "qpid/swig_python_typemaps.i" - -/* Needed for get/setPriority methods. Surprising SWIG 1.3.40 doesn't - * convert uint8_t by default. */ -%apply unsigned char { uint8_t }; - - -/* - * Exceptions - * - * The convention below is that exceptions in _qpid_messaging.so have the same - * names as in the C++ library. They get renamed to their Python - * equivalents when brought into the Python wrapping - */ -%define QPID_EXCEPTION(exception, parent) -%{ -static PyObject* exception; -%} -%init %{ - exception = PyErr_NewException( - (char *) ("_qpid_messaging." #exception), parent, NULL); - Py_INCREF(exception); - PyModule_AddObject(m, #exception, exception); -%} -%pythoncode %{ - exception = _qpid_messaging. ## exception -%} -%enddef - - /* Python equivalents of C++ exceptions. */ - /* */ - /* Commented out lines are exceptions in the Python library, but not */ - /* in the C++ library. */ - -QPID_EXCEPTION(MessagingError, NULL) - -QPID_EXCEPTION(LinkError, MessagingError) -QPID_EXCEPTION(AddressError, LinkError) -QPID_EXCEPTION(ResolutionError, AddressError) -QPID_EXCEPTION(AssertionFailed, ResolutionError) -QPID_EXCEPTION(NotFound, ResolutionError) -QPID_EXCEPTION(InvalidOption, LinkError) -QPID_EXCEPTION(MalformedAddress, LinkError) -QPID_EXCEPTION(ReceiverError, LinkError) -QPID_EXCEPTION(FetchError, ReceiverError) -QPID_EXCEPTION(Empty, FetchError) -/* QPID_EXCEPTION(InsufficientCapacity, LinkError) */ -/* QPID_EXCEPTION(LinkClosed, LinkError) */ -QPID_EXCEPTION(SenderError, LinkError) -QPID_EXCEPTION(SendError, SenderError) -QPID_EXCEPTION(TargetCapacityExceeded, SendError) - -QPID_EXCEPTION(ConnectionError, MessagingError) -QPID_EXCEPTION(ConnectError, ConnectionError) -/* QPID_EXCEPTION(AuthenticationFailure, ConnectError) */ -/* QPID_EXCEPTION(VersionError, ConnectError) */ -/* QPID_EXCEPTION(ConnectionClosed, ConnectionError) */ -/* QPID_EXCEPTION(HeartbeartTimeout, ConnectionError) */ - -QPID_EXCEPTION(SessionError, MessagingError) -/* QPID_EXCEPTION(Detached, SessionError) */ -/* QPID_EXCEPTION(NontransactionalSession, SessionError) */ -/* QPID_EXCEPTION(ServerError, SessionError) */ -/* QPID_EXCEPTION(SessionClosed, SessionError) */ -QPID_EXCEPTION(TransactionError, SessionError) -QPID_EXCEPTION(TransactionAborted, TransactionError) -QPID_EXCEPTION(UnauthorizedAccess, SessionError) - -/* QPID_EXCEPTION(InternalError, MessagingError) */ - -%define TRANSLATE_EXCEPTION(cpp_exception, py_exception) - catch ( cpp_exception & ex) { - pExceptionType = py_exception; - error = ex.what(); - } -%enddef - -/* Define the general-purpose exception handling */ -%exception { - PyObject * pExceptionType = NULL; - std::string error; - Py_BEGIN_ALLOW_THREADS; - try { - $action - } - /* Catch and translate exceptions. */ - TRANSLATE_EXCEPTION(qpid::messaging::NoMessageAvailable, Empty) - TRANSLATE_EXCEPTION(qpid::messaging::NotFound, NotFound) - TRANSLATE_EXCEPTION(qpid::messaging::AssertionFailed, AssertionFailed) - TRANSLATE_EXCEPTION(qpid::messaging::ResolutionError, ResolutionError) - TRANSLATE_EXCEPTION(qpid::messaging::TargetCapacityExceeded, - TargetCapacityExceeded) - TRANSLATE_EXCEPTION(qpid::messaging::TransportFailure, ConnectError) - TRANSLATE_EXCEPTION(qpid::messaging::MalformedAddress, MalformedAddress) - TRANSLATE_EXCEPTION(qpid::messaging::AddressError, AddressError) - TRANSLATE_EXCEPTION(qpid::messaging::FetchError, FetchError) - TRANSLATE_EXCEPTION(qpid::messaging::ReceiverError, ReceiverError) - TRANSLATE_EXCEPTION(qpid::messaging::SendError, SendError) - TRANSLATE_EXCEPTION(qpid::messaging::SenderError, SenderError) - TRANSLATE_EXCEPTION(qpid::messaging::InvalidOptionString, InvalidOption) - TRANSLATE_EXCEPTION(qpid::messaging::LinkError, LinkError) - TRANSLATE_EXCEPTION(qpid::messaging::TransactionAborted, TransactionAborted) - TRANSLATE_EXCEPTION(qpid::messaging::TransactionError, TransactionError) - TRANSLATE_EXCEPTION(qpid::messaging::UnauthorizedAccess, UnauthorizedAccess) - TRANSLATE_EXCEPTION(qpid::messaging::SessionError, SessionError) - TRANSLATE_EXCEPTION(qpid::messaging::ConnectionError, ConnectionError) - TRANSLATE_EXCEPTION(qpid::messaging::KeyError, PyExc_KeyError) - TRANSLATE_EXCEPTION(qpid::messaging::MessagingException, MessagingError) - TRANSLATE_EXCEPTION(qpid::types::Exception, PyExc_RuntimeError) - Py_END_ALLOW_THREADS; - if (!error.empty()) { - PyErr_SetString(pExceptionType, error.c_str()); - return NULL; - } -} - - -/* This only renames the non-const version (I believe). Then again, I - * don't even know why there is a non-const version of the method. */ -%rename(opened) qpid::messaging::Connection::isOpen(); -%rename(_close) qpid::messaging::Connection::close(); -%rename(receiver) qpid::messaging::Session::createReceiver; -%rename(_sender) qpid::messaging::Session::createSender; -%rename(_acknowledge_all) qpid::messaging::Session::acknowledge(bool); -%rename(_acknowledge_msg) qpid::messaging::Session::acknowledge( - Message &, bool); - -%rename(_fetch) qpid::messaging::Receiver::fetch; -%rename(unsettled) qpid::messaging::Receiver::getUnsettled; -%rename(available) qpid::messaging::Receiver::getAvailable; - -%rename(unsettled) qpid::messaging::Sender::getUnsettled; -%rename(available) qpid::messaging::Sender::getAvailable; -%rename(_send) qpid::messaging::Sender::send; - -%rename(_getReplyTo) qpid::messaging::Message::getReplyTo; -%rename(_setReplyTo) qpid::messaging::Message::setReplyTo; -%rename(_getTtl) qpid::messaging::Message::getTtl; -%rename(_setTtl) qpid::messaging::Message::setTtl; - - -%include "qpid/qpid.i" - -%extend qpid::messaging::Connection { - %pythoncode %{ - def __init__(self, url=None, **options): - if url: - args = [str(url)] - else: - args = [] - if options: - # remove null valued options - clean_opts = {} - for k, v in options.iteritems(): - if v: - clean_opts[k] = v - args.append(clean_opts) - this = _qpid_messaging.new_Connection(*args) - try: self.this.append(this) - except: self.this = this - - def attached(self): - return self.opened() - - def close(self, timeout=None): - #timeout not supported in c++ - self._close() - %} - - /* Return a pre-existing session with the given name, if one - * exists, otherwise return a new one. (Note that if a - * pre-existing session exists, the transactional argument is - * ignored, and the returned session might not satisfy the desired - * setting. */ - qpid::messaging::Session _session(const std::string & name, - bool transactional) { - if (!name.empty()) { - try { - return self->getSession(name); - } - catch (const qpid::messaging::KeyError &) { - } - } - if (transactional) { - return self->createTransactionalSession(name); - } - else { - return self->createSession(name); - } - } - - %pythoncode %{ - def session(self, name=None, transactional=False) : - if name is None : - name = '' - return self._session(name, transactional) - %} - - %pythoncode %{ - @staticmethod - def establish(url=None, **options) : - conn = Connection(url, **options) - conn.open() - return conn - %} -} - -%extend qpid::messaging::Session { - %pythoncode %{ - def acknowledge(self, message=None, disposition=None, sync=True) : - if disposition : - raise Exception("SWIG does not support dispositions yet. Use " - "Session.reject and Session.release instead") - if message : - self._acknowledge_msg(message, sync) - else : - self._acknowledge_all(sync) - - __swig_getmethods__["connection"] = getConnection - if _newclass: connection = property(getConnection) - - def sender(self, target, **options) : - s = self._sender(target) - s._setDurable(options.get("durable")) - return s - %} -} - - -%extend qpid::messaging::Receiver { - %pythoncode %{ - def _get_source(self): - return self.getAddress().str() - - __swig_getmethods__["capacity"] = getCapacity - __swig_setmethods__["capacity"] = setCapacity - if _newclass: capacity = property(getCapacity, setCapacity) - - __swig_getmethods__["session"] = getSession - if _newclass: session = property(getSession) - - __swig_getmethods__["source"] = _get_source - if _newclass: source = property(_get_source) - %} - - %pythoncode %{ - def fetch(self, timeout=None) : - if timeout is None : - return self._fetch() - else : - # Python API uses timeouts in seconds, - # but C++ API uses milliseconds - return self._fetch(Duration(int(1000*timeout))) - %} -} - -%extend qpid::messaging::Sender { - %pythoncode %{ - def _get_target(self): - return self.getAddress().str() - - def _setDurable(self, d): - self.durable = d - - def send(self, object, sync=True) : - if isinstance(object, Message): - message = object - else: - message = Message(object) - if self.durable and message.durable is None: - message.durable = self.durable - return self._send(message, sync) - - __swig_getmethods__["capacity"] = getCapacity - __swig_setmethods__["capacity"] = setCapacity - if _newclass: capacity = property(getCapacity, setCapacity) - - __swig_getmethods__["session"] = getSession - if _newclass: session = property(getSession) - - __swig_getmethods__["target"] = _get_target - if _newclass: source = property(_get_target) - - %} -} - - -%extend qpid::messaging::Message { - %pythoncode %{ - class MessageProperties: - def __init__(self, msg): - self.msg = msg - self.properties = self.msg.getProperties() - - def __len__(self): - return self.properties.__len__() - - def __getitem__(self, key): - return self.properties[key]; - - def get(self, key): - return self.__getitem__(key) - - def __setitem__(self, key, value): - self.properties[key] = value - self.msg.setProperty(key, value) - - def set(self, key, value): - self.__setitem__(key, value) - - def __delitem__(self, key): - del self.properties[key] - self.msg.setProperties(self.properties) - - def __iter__(self): - return self.properties.iteritems() - - def __repr__(self): - return str(self.properties) - - # UNSPECIFIED was module level before, but I do not - # know how to insert python code at the top of the module. - # (A bare "%pythoncode" inserts at the end. - UNSPECIFIED=object() - def __init__(self, content=None, content_type=UNSPECIFIED, id=None, - subject=None, user_id=None, reply_to=None, - correlation_id=None, durable=None, priority=None, - ttl=None, properties=None): - this = _qpid_messaging.new_Message('') - try: self.this.append(this) - except: self.this = this - if not content is None: - self.content = content - if content_type != UNSPECIFIED : - self.content_type = content_type - if id is not None : - self.id = id - if subject is not None : - self.subject = subject - if user_id is not None : - self.user_id = user_id - if reply_to is not None : - self.reply_to = reply_to - if correlation_id is not None : - self.correlation_id = correlation_id - if durable is not None : - self.durable = durable - if priority is not None : - self.priority = priority - if ttl is not None : - self.ttl = ttl - if properties is not None : - self.setProperties(properties) - - def _get_msg_props(self): - try: - return self._msg_props - except AttributeError: - self._msg_props = Message.MessageProperties(self) - return self._msg_props - - def _get_content(self) : - obj = self.getContentObject() - if obj: - return obj - if self.content_type == "amqp/list" : - return decodeList(self) - if self.content_type == "amqp/map" : - return decodeMap(self) - return self.getContent() - def _set_content(self, content) : - if isinstance(content, str) : - self.setContent(content) - elif isinstance(content, unicode) : - if not self.content_type: self.content_type = "text/plain" - self.setContent(str(content)) - elif isinstance(content, list) or isinstance(content, dict) : - encode(content, self) - else : - self.setContentObject(content) - __swig_getmethods__["content"] = _get_content - __swig_setmethods__["content"] = _set_content - if _newclass: content = property(_get_content, _set_content) - - def _get_content_type(self) : - ct = self.getContentType() - if ct == "": return None - else: return ct - - __swig_getmethods__["content_type"] = _get_content_type - __swig_setmethods__["content_type"] = setContentType - if _newclass: content_type = property(_get_content_type, setContentType) - - __swig_getmethods__["id"] = getMessageId - __swig_setmethods__["id"] = setMessageId - if _newclass: id = property(getMessageId, setMessageId) - - __swig_getmethods__["subject"] = getSubject - __swig_setmethods__["subject"] = setSubject - if _newclass: subject = property(getSubject, setSubject) - - __swig_getmethods__["priority"] = getPriority - __swig_setmethods__["priority"] = setPriority - if _newclass: priority = property(getPriority, setPriority) - - def getTtl(self) : - return self._getTtl().getMilliseconds()/1000.0 - def setTtl(self, duration) : - self._setTtl(Duration(int(1000*duration))) - __swig_getmethods__["ttl"] = getTtl - __swig_setmethods__["ttl"] = setTtl - if _newclass: ttl = property(getTtl, setTtl) - - __swig_getmethods__["user_id"] = getUserId - __swig_setmethods__["user_id"] = setUserId - if _newclass: user_id = property(getUserId, setUserId) - - __swig_getmethods__["correlation_id"] = getCorrelationId - __swig_setmethods__["correlation_id"] = setCorrelationId - if _newclass: correlation_id = property(getCorrelationId, setCorrelationId) - - __swig_getmethods__["redelivered"] = getRedelivered - __swig_setmethods__["redelivered"] = setRedelivered - if _newclass: redelivered = property(getRedelivered, setRedelivered) - - __swig_getmethods__["durable"] = getDurable - __swig_setmethods__["durable"] = setDurable - if _newclass: durable = property(getDurable, setDurable) - - __swig_getmethods__["properties"] = _get_msg_props - if _newclass: properties = property(_get_msg_props) - - def getReplyTo(self) : - return self._getReplyTo().str() - def setReplyTo(self, address_str) : - self._setReplyTo(Address(address_str)) - __swig_getmethods__["reply_to"] = getReplyTo - __swig_setmethods__["reply_to"] = setReplyTo - if _newclass: reply_to = property(getReplyTo, setReplyTo) - - def __repr__(self): - args = [] - for name in ["id", "subject", "user_id", "reply_to", - "correlation_id", "priority", "ttl", - "durable", "redelivered", "properties", - "content_type"] : - value = getattr(self, name) - if value : args.append("%s=%r" % (name, value)) - if self.content is not None: - if args: - args.append("content=%r" % self.content) - else: - args.append(repr(self.content)) - return "Message(%s)" % ", ".join(args) - %} -} - -%pythoncode %{ -# Bring into module scope -UNSPECIFIED = Message.UNSPECIFIED -%} diff --git a/qpid/cpp/bindings/qpid/python/qpid_messaging.i b/qpid/cpp/bindings/qpid/python/qpid_messaging.i new file mode 100644 index 0000000000..624cee35bc --- /dev/null +++ b/qpid/cpp/bindings/qpid/python/qpid_messaging.i @@ -0,0 +1,483 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +%module qpid_messaging + +%include "std_string.i" +%include "qpid/swig_python_typemaps.i" + +/* Needed for get/setPriority methods. Surprising SWIG 1.3.40 doesn't + * convert uint8_t by default. */ +%apply unsigned char { uint8_t }; + + +/* + * Exceptions + * + * The convention below is that exceptions in _qpid_messaging.so have the same + * names as in the C++ library. They get renamed to their Python + * equivalents when brought into the Python wrapping + */ +%define QPID_EXCEPTION(exception, parent) +%{ +static PyObject* exception; +%} +%init %{ + exception = PyErr_NewException( + (char *) ("_qpid_messaging." #exception), parent, NULL); + Py_INCREF(exception); + PyModule_AddObject(m, #exception, exception); +%} +%pythoncode %{ + exception = _qpid_messaging. ## exception +%} +%enddef + + /* Python equivalents of C++ exceptions. */ + /* */ + /* Commented out lines are exceptions in the Python library, but not */ + /* in the C++ library. */ + +QPID_EXCEPTION(MessagingError, NULL) + +QPID_EXCEPTION(LinkError, MessagingError) +QPID_EXCEPTION(AddressError, LinkError) +QPID_EXCEPTION(ResolutionError, AddressError) +QPID_EXCEPTION(AssertionFailed, ResolutionError) +QPID_EXCEPTION(NotFound, ResolutionError) +QPID_EXCEPTION(InvalidOption, LinkError) +QPID_EXCEPTION(MalformedAddress, LinkError) +QPID_EXCEPTION(ReceiverError, LinkError) +QPID_EXCEPTION(FetchError, ReceiverError) +QPID_EXCEPTION(Empty, FetchError) +/* QPID_EXCEPTION(InsufficientCapacity, LinkError) */ +/* QPID_EXCEPTION(LinkClosed, LinkError) */ +QPID_EXCEPTION(SenderError, LinkError) +QPID_EXCEPTION(SendError, SenderError) +QPID_EXCEPTION(TargetCapacityExceeded, SendError) + +QPID_EXCEPTION(ConnectionError, MessagingError) +QPID_EXCEPTION(ConnectError, ConnectionError) +/* QPID_EXCEPTION(AuthenticationFailure, ConnectError) */ +/* QPID_EXCEPTION(VersionError, ConnectError) */ +/* QPID_EXCEPTION(ConnectionClosed, ConnectionError) */ +/* QPID_EXCEPTION(HeartbeartTimeout, ConnectionError) */ + +QPID_EXCEPTION(SessionError, MessagingError) +/* QPID_EXCEPTION(Detached, SessionError) */ +/* QPID_EXCEPTION(NontransactionalSession, SessionError) */ +/* QPID_EXCEPTION(ServerError, SessionError) */ +/* QPID_EXCEPTION(SessionClosed, SessionError) */ +QPID_EXCEPTION(TransactionError, SessionError) +QPID_EXCEPTION(TransactionAborted, TransactionError) +QPID_EXCEPTION(UnauthorizedAccess, SessionError) + +/* QPID_EXCEPTION(InternalError, MessagingError) */ + +%define TRANSLATE_EXCEPTION(cpp_exception, py_exception) + catch ( cpp_exception & ex) { + pExceptionType = py_exception; + error = ex.what(); + } +%enddef + +/* Define the general-purpose exception handling */ +%exception { + PyObject * pExceptionType = NULL; + std::string error; + Py_BEGIN_ALLOW_THREADS; + try { + $action + } + /* Catch and translate exceptions. */ + TRANSLATE_EXCEPTION(qpid::messaging::NoMessageAvailable, Empty) + TRANSLATE_EXCEPTION(qpid::messaging::NotFound, NotFound) + TRANSLATE_EXCEPTION(qpid::messaging::AssertionFailed, AssertionFailed) + TRANSLATE_EXCEPTION(qpid::messaging::ResolutionError, ResolutionError) + TRANSLATE_EXCEPTION(qpid::messaging::TargetCapacityExceeded, + TargetCapacityExceeded) + TRANSLATE_EXCEPTION(qpid::messaging::TransportFailure, ConnectError) + TRANSLATE_EXCEPTION(qpid::messaging::MalformedAddress, MalformedAddress) + TRANSLATE_EXCEPTION(qpid::messaging::AddressError, AddressError) + TRANSLATE_EXCEPTION(qpid::messaging::FetchError, FetchError) + TRANSLATE_EXCEPTION(qpid::messaging::ReceiverError, ReceiverError) + TRANSLATE_EXCEPTION(qpid::messaging::SendError, SendError) + TRANSLATE_EXCEPTION(qpid::messaging::SenderError, SenderError) + TRANSLATE_EXCEPTION(qpid::messaging::InvalidOptionString, InvalidOption) + TRANSLATE_EXCEPTION(qpid::messaging::LinkError, LinkError) + TRANSLATE_EXCEPTION(qpid::messaging::TransactionAborted, TransactionAborted) + TRANSLATE_EXCEPTION(qpid::messaging::TransactionError, TransactionError) + TRANSLATE_EXCEPTION(qpid::messaging::UnauthorizedAccess, UnauthorizedAccess) + TRANSLATE_EXCEPTION(qpid::messaging::SessionError, SessionError) + TRANSLATE_EXCEPTION(qpid::messaging::ConnectionError, ConnectionError) + TRANSLATE_EXCEPTION(qpid::messaging::KeyError, PyExc_KeyError) + TRANSLATE_EXCEPTION(qpid::messaging::MessagingException, MessagingError) + TRANSLATE_EXCEPTION(qpid::types::Exception, PyExc_RuntimeError) + Py_END_ALLOW_THREADS; + if (!error.empty()) { + PyErr_SetString(pExceptionType, error.c_str()); + return NULL; + } +} + + +/* This only renames the non-const version (I believe). Then again, I + * don't even know why there is a non-const version of the method. */ +%rename(opened) qpid::messaging::Connection::isOpen(); +%rename(_close) qpid::messaging::Connection::close(); +%rename(receiver) qpid::messaging::Session::createReceiver; +%rename(_sender) qpid::messaging::Session::createSender; +%rename(_acknowledge_all) qpid::messaging::Session::acknowledge(bool); +%rename(_acknowledge_msg) qpid::messaging::Session::acknowledge( + Message &, bool); + +%rename(_fetch) qpid::messaging::Receiver::fetch; +%rename(unsettled) qpid::messaging::Receiver::getUnsettled; +%rename(available) qpid::messaging::Receiver::getAvailable; + +%rename(unsettled) qpid::messaging::Sender::getUnsettled; +%rename(available) qpid::messaging::Sender::getAvailable; +%rename(_send) qpid::messaging::Sender::send; + +%rename(_getReplyTo) qpid::messaging::Message::getReplyTo; +%rename(_setReplyTo) qpid::messaging::Message::setReplyTo; +%rename(_getTtl) qpid::messaging::Message::getTtl; +%rename(_setTtl) qpid::messaging::Message::setTtl; + + +%include "qpid/qpid.i" + +%extend qpid::messaging::Connection { + %pythoncode %{ + def __init__(self, url=None, **options): + if url: + args = [str(url)] + else: + args = [] + if options: + # remove null valued options + clean_opts = {} + for k, v in options.iteritems(): + if v: + clean_opts[k] = v + args.append(clean_opts) + this = _qpid_messaging.new_Connection(*args) + try: self.this.append(this) + except: self.this = this + + def attached(self): + return self.opened() + + def close(self, timeout=None): + #timeout not supported in c++ + self._close() + %} + + /* Return a pre-existing session with the given name, if one + * exists, otherwise return a new one. (Note that if a + * pre-existing session exists, the transactional argument is + * ignored, and the returned session might not satisfy the desired + * setting. */ + qpid::messaging::Session _session(const std::string & name, + bool transactional) { + if (!name.empty()) { + try { + return self->getSession(name); + } + catch (const qpid::messaging::KeyError &) { + } + } + if (transactional) { + return self->createTransactionalSession(name); + } + else { + return self->createSession(name); + } + } + + %pythoncode %{ + def session(self, name=None, transactional=False) : + if name is None : + name = '' + return self._session(name, transactional) + %} + + %pythoncode %{ + @staticmethod + def establish(url=None, **options) : + conn = Connection(url, **options) + conn.open() + return conn + %} +} + +%extend qpid::messaging::Session { + %pythoncode %{ + def acknowledge(self, message=None, disposition=None, sync=True) : + if disposition : + raise Exception("SWIG does not support dispositions yet. Use " + "Session.reject and Session.release instead") + if message : + self._acknowledge_msg(message, sync) + else : + self._acknowledge_all(sync) + + __swig_getmethods__["connection"] = getConnection + if _newclass: connection = property(getConnection) + + def sender(self, target, **options) : + s = self._sender(target) + s._setDurable(options.get("durable")) + return s + %} +} + + +%extend qpid::messaging::Receiver { + %pythoncode %{ + def _get_source(self): + return self.getAddress().str() + + __swig_getmethods__["capacity"] = getCapacity + __swig_setmethods__["capacity"] = setCapacity + if _newclass: capacity = property(getCapacity, setCapacity) + + __swig_getmethods__["session"] = getSession + if _newclass: session = property(getSession) + + __swig_getmethods__["source"] = _get_source + if _newclass: source = property(_get_source) + %} + + %pythoncode %{ + def fetch(self, timeout=None) : + if timeout is None : + return self._fetch() + else : + # Python API uses timeouts in seconds, + # but C++ API uses milliseconds + return self._fetch(Duration(int(1000*timeout))) + %} +} + +%extend qpid::messaging::Sender { + %pythoncode %{ + def _get_target(self): + return self.getAddress().str() + + def _setDurable(self, d): + self.durable = d + + def send(self, object, sync=True) : + if isinstance(object, Message): + message = object + else: + message = Message(object) + if self.durable and message.durable is None: + message.durable = self.durable + return self._send(message, sync) + + __swig_getmethods__["capacity"] = getCapacity + __swig_setmethods__["capacity"] = setCapacity + if _newclass: capacity = property(getCapacity, setCapacity) + + __swig_getmethods__["session"] = getSession + if _newclass: session = property(getSession) + + __swig_getmethods__["target"] = _get_target + if _newclass: source = property(_get_target) + + %} +} + + +%extend qpid::messaging::Message { + %pythoncode %{ + class MessageProperties: + def __init__(self, msg): + self.msg = msg + self.properties = self.msg.getProperties() + + def __len__(self): + return self.properties.__len__() + + def __getitem__(self, key): + return self.properties[key]; + + def get(self, key): + return self.__getitem__(key) + + def __setitem__(self, key, value): + self.properties[key] = value + self.msg.setProperty(key, value) + + def set(self, key, value): + self.__setitem__(key, value) + + def __delitem__(self, key): + del self.properties[key] + self.msg.setProperties(self.properties) + + def __iter__(self): + return self.properties.iteritems() + + def __repr__(self): + return str(self.properties) + + # UNSPECIFIED was module level before, but I do not + # know how to insert python code at the top of the module. + # (A bare "%pythoncode" inserts at the end. + UNSPECIFIED=object() + def __init__(self, content=None, content_type=UNSPECIFIED, id=None, + subject=None, user_id=None, reply_to=None, + correlation_id=None, durable=None, priority=None, + ttl=None, properties=None): + this = _qpid_messaging.new_Message('') + try: self.this.append(this) + except: self.this = this + if not content is None: + self.content = content + if content_type != UNSPECIFIED : + self.content_type = content_type + if id is not None : + self.id = id + if subject is not None : + self.subject = subject + if user_id is not None : + self.user_id = user_id + if reply_to is not None : + self.reply_to = reply_to + if correlation_id is not None : + self.correlation_id = correlation_id + if durable is not None : + self.durable = durable + if priority is not None : + self.priority = priority + if ttl is not None : + self.ttl = ttl + if properties is not None : + self.setProperties(properties) + + def _get_msg_props(self): + try: + return self._msg_props + except AttributeError: + self._msg_props = Message.MessageProperties(self) + return self._msg_props + + def _get_content(self) : + obj = self.getContentObject() + if obj: + return obj + if self.content_type == "amqp/list" : + return decodeList(self) + if self.content_type == "amqp/map" : + return decodeMap(self) + return self.getContent() + def _set_content(self, content) : + if isinstance(content, str) : + self.setContent(content) + elif isinstance(content, unicode) : + if not self.content_type: self.content_type = "text/plain" + self.setContent(str(content)) + elif isinstance(content, list) or isinstance(content, dict) : + encode(content, self) + else : + self.setContentObject(content) + __swig_getmethods__["content"] = _get_content + __swig_setmethods__["content"] = _set_content + if _newclass: content = property(_get_content, _set_content) + + def _get_content_type(self) : + ct = self.getContentType() + if ct == "": return None + else: return ct + + __swig_getmethods__["content_type"] = _get_content_type + __swig_setmethods__["content_type"] = setContentType + if _newclass: content_type = property(_get_content_type, setContentType) + + __swig_getmethods__["id"] = getMessageId + __swig_setmethods__["id"] = setMessageId + if _newclass: id = property(getMessageId, setMessageId) + + __swig_getmethods__["subject"] = getSubject + __swig_setmethods__["subject"] = setSubject + if _newclass: subject = property(getSubject, setSubject) + + __swig_getmethods__["priority"] = getPriority + __swig_setmethods__["priority"] = setPriority + if _newclass: priority = property(getPriority, setPriority) + + def getTtl(self) : + return self._getTtl().getMilliseconds()/1000.0 + def setTtl(self, duration) : + self._setTtl(Duration(int(1000*duration))) + __swig_getmethods__["ttl"] = getTtl + __swig_setmethods__["ttl"] = setTtl + if _newclass: ttl = property(getTtl, setTtl) + + __swig_getmethods__["user_id"] = getUserId + __swig_setmethods__["user_id"] = setUserId + if _newclass: user_id = property(getUserId, setUserId) + + __swig_getmethods__["correlation_id"] = getCorrelationId + __swig_setmethods__["correlation_id"] = setCorrelationId + if _newclass: correlation_id = property(getCorrelationId, setCorrelationId) + + __swig_getmethods__["redelivered"] = getRedelivered + __swig_setmethods__["redelivered"] = setRedelivered + if _newclass: redelivered = property(getRedelivered, setRedelivered) + + __swig_getmethods__["durable"] = getDurable + __swig_setmethods__["durable"] = setDurable + if _newclass: durable = property(getDurable, setDurable) + + __swig_getmethods__["properties"] = _get_msg_props + if _newclass: properties = property(_get_msg_props) + + def getReplyTo(self) : + return self._getReplyTo().str() + def setReplyTo(self, address_str) : + self._setReplyTo(Address(address_str)) + __swig_getmethods__["reply_to"] = getReplyTo + __swig_setmethods__["reply_to"] = setReplyTo + if _newclass: reply_to = property(getReplyTo, setReplyTo) + + def __repr__(self): + args = [] + for name in ["id", "subject", "user_id", "reply_to", + "correlation_id", "priority", "ttl", + "durable", "redelivered", "properties", + "content_type"] : + value = getattr(self, name) + if value : args.append("%s=%r" % (name, value)) + if self.content is not None: + if args: + args.append("content=%r" % self.content) + else: + args.append(repr(self.content)) + return "Message(%s)" % ", ".join(args) + %} +} + +%pythoncode %{ +# Bring into module scope +UNSPECIFIED = Message.UNSPECIFIED +%} diff --git a/qpid/cpp/bindings/qpid/ruby/CMakeLists.txt b/qpid/cpp/bindings/qpid/ruby/CMakeLists.txt index 60c60445b7..f80f134366 100644 --- a/qpid/cpp/bindings/qpid/ruby/CMakeLists.txt +++ b/qpid/cpp/bindings/qpid/ruby/CMakeLists.txt @@ -29,7 +29,9 @@ set(GEM_OUTPUT_FILE ${GEM_OUTPUT_PATH}/pkg/qpid-${qpidc_version}.0.gem) ##------------------------------------------------------ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES CPLUSPLUS ON) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES + CPLUSPLUS ON + SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") if ((${CMAKE_MAJOR_VERSION} EQUAL 2) AND (${CMAKE_MINOR_VERSION} LESS 8)) set (RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_PATH}) @@ -40,8 +42,8 @@ include_directories(${RUBY_INCLUDE_DIRS} ${qpid-cpp_SOURCE_DIR}/bindings) list(APPEND SWIG_MODULE_cqpid_ruby_EXTRA_DEPS - ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/qpid/qpid.i - ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/qpid/swig_ruby_typemaps.i + ${CMAKE_SOURCE_DIR}/include/qpid/qpid.i + ${CMAKE_SOURCE_DIR}/include/qpid/swig_ruby_typemaps.i ) swig_add_module(cqpid_ruby ruby ${CMAKE_CURRENT_SOURCE_DIR}/ruby.i) swig_link_libraries(cqpid_ruby qpidmessaging qpidtypes qmf2 ${RUBY_LIBRARY}) -- cgit v1.2.1