Welcome to RapidSMS 0.10.0!
These release notes cover the new features in 0.10.0, as well as some backwards-incompatible-changes you’ll want to be aware of when upgrading from RapidSMS 0.9.6a or older versions. We also provide a migration guide to help you port your 0.9.6 projects and apps to 0.10.0 to take advantage of the new features.
RapidSMS 0.10.0’s focus has mostly been on decoupling the RapidSMS route process in several key places to begin processing all SMSes in normal HTTP requests. This also includes making it possible to swap the Router class that RapidSMS uses via a setting in the settings file. The key changes are as follows:
The major highlights of RapidSMS 0.10.0 are:
RapidSMS 0.10.0 supplies one built-in router, BlockingRouter. This is the default router that processes messages in real time.
We also support creation of custom router classes. All routers should extend from the BaseRouter class.
In 0.9.x, the RapidSMS router used Python’s threading module to encapsulate backends into independent threads. Using this model, backends can operate independently from one another, blocking for I/O and waiting for external service calls. Many of the original backends operated in this way. For example, rapidsms.backends.http started a HTTP server to listen on a specified port and rapidsms.backends.gsm communicated directly with a GSM modem. While this method provided RapidSMS with a routing architecture, the need for a non-threaded system grew due to the following reasons:
RapidSMS now allows you to specify the primary router class to use by defining RAPIDSMS_ROUTER in settings. This defaults to rapidsms.router.blocking.BlockingRouter, but you can change this in settings.py:
RAPIDSMS_ROUTER = 'myproject.router.MyRouter'
A new utility function, get_router, provides the ability to retrieve the settings-defined router. This helper function allows your app to remain router independent:
1 2 3 4 5 | from rapidsms.router import get_router
def send(recipient, text):
router = get_router()()
router.handle_outgoing(text, recipient.default_connection)
|
RapidSMS backends are now apps (rather than modules) in the rapidsms.backends directory. RapidSMS provides two built-in backend apps: http and kannel. We have completely removed all other backends from the RapidSMS core.
We also support creation of custom backend apps. Backend classes should extend from the classes found in rapidsms.backends.base.
MockBackendRouter is a unit test mix-in class that provides a mock backend to use with the BlockingRouter. The following example from contrib.messaging illustrates how you can test that inbound messages route to the mock backend outbox.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from django.test import TestCase
from rapidsms.tests.harness.base import MockBackendRouter
class MessagingTest(MockBackendRouter, TestCase):
def setUp(self):
self.contact = self.create_contact()
self.backend = self.create_backend({'name': 'mock'})
self.connection = self.create_connection({'backend': self.backend,
'contact': self.contact})
def test_ajax_send_view(self):
"""
Test AJAX send view with valid data
"""
data = {'text': 'hello!', 'recipients': [self.contact.id]}
response = self.client.post(reverse('send_message'), data)
self.assertEqual(response.status_code, 200)
self.assertEqual(self.outbox[0].text, data['text'])
|
Prior to 0.10.0, TestScript would instantiate the route process (with blocking backends) to allow for testing of the entire routing stack. This was a useful function, but in practice was unstable and caused tests to hang indefinitely. In 0.10.0, TestScript has been updated to work with BlockingRouter, and it functions much in the same way as before. Here’s an example testing the EchoApp:
1 2 3 4 5 6 7 8 | class EchoTest(TestScript):
apps = (EchoApp,)
def testRunScript(self):
self.runScript("""
2345678901 > echo?
2345678901 < 2345678901: echo?
""")
|
In the goal of improving the RapidSMS core, we have made a number of backwards-incompatible changes. If you have apps written against RapidSMS 0.9.6 that you need to port, see our migration guide.
RapidSMS is no longer compatible with any version of Django prior to 1.3.
RapidSMS 0.10.0 supports out-of-the-box use of django.core.staticfiles (included by default in Django 1.3.x and above). The rapidsms.urls.static_media module has been removed in favor of using this app. New projects generated using rapidsms-admin.py startproject are automatically configured to work with staticfiles. See the migration guide for more information on upgrading existing projects.
We removed several rarely-used or outdated backend packages from the core:
The rapidsms.contrib.ajax app has been removed.
Prior to 0.10.0, rapidsms.contrib.messaging contained a utility function to send a message to the Router process. This relied on the contrib.ajax‘s call_router function to pass messages to the Router via the ajax app running in the Router thread. send_message has been removed and you should now use rapidsms.router.send (see Sending Messages). Using send_message will now raise an exception:
>>> from rapidsms.contrib.messaging.utils import send_message
>>> send_message(conn, "hello?")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "../rapidsms/lib/rapidsms/contrib/messaging/utils.py", line 2, in send_message
raise DeprecationWarning("rapidsms.contrib.messaging.utils is deprecated")
DeprecationWarning: rapidsms.contrib.messaging.utils is deprecated
rapidsms.contrib.scheduler still exists, but is currently incompatible with 0.10.0. We plan to support the scheduler in the next minor RapidSMS release.