Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don't worry, you can still create the pull request.
  • 2 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
Commits on Mar 14, 2012
@johnpaulett Use unicode internally. Receiver now must implement getCodec.
Speak byte strings with source system, but use unicode internally and
pass unicode messages to the receiver implementation.

Previously, for high-order cp1252 encoded messages, the ACK's
hl7.parse() was causing the server to permanently stop ACK'ing as
soon as it received the such a message.
1165b07
@johnpaulett Documentation for 0.0.3 release. 6e2a89c
View
8 docs/changelog.rst
@@ -2,6 +2,14 @@
Change Log
==========
+0.0.3 - March 2012
+==================
+
+* Convert to unicode. As soon as a message string is assembled, decode into
+ unicode, using the codec specified by the implementation of
+ ``IHL7Receiver.getCodec()`. When writing an ACK, the message is re-encoded
+ into that codec.
+
0.0.2 - September 2011
======================
View
2  setup.py
@@ -2,7 +2,7 @@
setup(
name='twisted-hl7',
- version='0.0.2',
+ version='0.0.3',
author='John Paulett',
author_email = 'john@paulett.org',
url = 'http://twisted-hl7.readthedocs.org',
View
9 tests/test_ack.py
@@ -21,3 +21,12 @@ def test_ae(self):
expected = 'MSH|^~\\&|GHH OE|BLDG4|GHH LAB|ELAB-3|200202150930||ACK^001|CNTRL-3456|P|2.4\rMSA|AE|CNTRL-3456'
self.assertEqual(expected, result)
+
+ def test_unicode(self):
+ # ACK takes and returns unicode. The Factory is responsible for
+ # decoding/encoding
+ message = unicode(HL7_MESSAGE).replace(u'BLDG4', u'x\u201ay')
+ result = ACK(message)
+
+ expected = u'MSH|^~\\&|GHH OE|x\u201ay|GHH LAB|ELAB-3|200202150930||ACK^001|CNTRL-3456|P|2.4\rMSA|AA|CNTRL-3456'
+ self.assertEqual(expected, result)
View
14 tests/test_mllp.py
@@ -22,6 +22,9 @@ def handleMessage(self, message):
self.messages.append(message)
return defer.succeed(ACK(message, self.ack_code))
+ def getCodec(self):
+ return 'cp1252'
+
class MinimalLowerLayerProtocolTest(TestCase):
def setUp(self):
self.receiver = CaptureReceiver()
@@ -46,3 +49,14 @@ def testUncaughtError(self):
self.assertEqual(self.protocol.transport.write.call_args[0][0],
'\x0b' + EXPECTED_ACK.format('AR') + '\x1c\x0d')
+
+ def testParseMessageUnicode(self):
+ message = HL7_MESSAGE.replace('BLDG4', 'x\x82y')
+ self.protocol.dataReceived('\x0b' + message + '\x1c\x0d')
+
+ expected_message = unicode(HL7_MESSAGE).replace(u'BLDG4', u'x\u201ay')
+ self.assertEqual(self.receiver.messages, [expected_message])
+
+ expected_ack = EXPECTED_ACK.replace('BLDG4', 'x\x82y')
+ self.assertEqual(self.protocol.transport.write.call_args[0][0],
+ '\x0b' + expected_ack.format('AA') + '\x1c\x0d')
View
4 twistedhl7/ack.py
@@ -1,6 +1,6 @@
from hl7 import parse
-_ACK_TEMPLATE = 'MSH|^~\\&|{send_app}|{send_fac}|{recv_app}|{recv_fac}|{dttm}||ACK^001|{msgid}|P|{version}\rMSA|{ack_code}|{msgid}'
+_ACK_TEMPLATE = u'MSH|^~\\&|{send_app}|{send_fac}|{recv_app}|{recv_fac}|{dttm}||ACK^001|{msgid}|P|{version}\rMSA|{ack_code}|{msgid}'
def ACK(original_message, ack_code='AA'):
@@ -18,6 +18,8 @@ def ACK(original_message, ack_code='AA'):
-
"""
+ # hl7.parse requires the message is unicode already or can be easily
+ # converted via unicode()
msh = parse(original_message).segment('MSH')
# easy-access function to make sure unicode is always called
View
31 twistedhl7/mllp.py
@@ -6,6 +6,7 @@ class IHL7Receiver(Interface):
# set error handling code
# set system name
# set 2.9.2.1 validation
+
def prepareMessage(original):
# default to not modifying the message
return original
@@ -13,7 +14,8 @@ def prepareMessage(original):
def handleMessage(message):
"""Clients should implement ``handleMessage``, which takes a ``message``
argument, that is an unparsed HL7 message (the MLLP wrapping around the
- HL7 message will be removed).
+ HL7 message will be removed). The message will be in unicode, using
+ the codec from get_codec() to decode the message.
The implementation, if non-blocking, may directly return the ack/nack
message or can return the ack/nack within a
@@ -24,6 +26,13 @@ def handleMessage(message):
loop from being blocked.
"""
+ def getCodec():
+ """Clients should return the codec name, used when decoding into unicode
+
+ http://docs.python.org/library/codecs.html#standard-encodings
+ """
+ return None
+
class MinimalLowerLayerProtocol(protocol.Protocol):
"""
Minimal Lower-Layer Protocol (MLLP) takes the form:
@@ -59,6 +68,11 @@ def onSuccess(message):
# only pass messages with data
if len(message) > 0:
+ # convert into unicode (ACK's call to hl7.parse will explode if
+ # it receives a non-ASCII byte string, so we just convert to
+ # unicode here
+ message = self.factory.decode(message)
+
# error callback (defined here, since error depends on
# current message). rejects the message
def onError(err):
@@ -72,6 +86,8 @@ def onError(err):
d.addErrback(onError)
def writeMessage(self, message):
+ # convert back to a byte string
+ message = self.factory.encode(message)
# wrap message in payload container
self.transport.write(
self.start_block + message + self.end_block + self.carriage_return
@@ -82,9 +98,22 @@ class MLLPFactory(protocol.ServerFactory):
def __init__(self, receiver):
self.receiver = receiver
+ self.encoding = receiver.getCodec()
# set server name
def handleMessage(self, message):
# IHL7Receiver allows implementations to return a Deferred or the
# result, so ensure we return a Deferred here
return defer.maybeDeferred(self.receiver.handleMessage, message)
+
+ def decode(self, value):
+ # turn value into unicode using the receiver's declared codec
+ if self.encoding and isinstance(value, str):
+ return value.decode(self.encoding)
+ return unicode(value)
+
+ def encode(self, value):
+ # turn value into unicode using the receiver's declared codec
+ if self.encoding and isinstance(value, unicode):
+ return value.encode(self.encoding)
+ return unicode(value)

No commit comments for this range

Something went wrong with that request. Please try again.