plone.rfc822 marshaler ====================== This package includes a field marshaler for ``plone.rfc822``, which will be installed if that package is installed. To test this, we must first load some configuration: >>> configuration = """\ ... ... ... ... ... ... ... ... ... ... ... """ >>> from StringIO import StringIO >>> from zope.configuration import xmlconfig >>> xmlconfig.xmlconfig(StringIO(configuration)) Next, we will create a schema with which to test the marshaler >>> from zope.interface import Interface >>> from plone.namedfile import field >>> class ITestContent(Interface): ... _file = field.NamedFile() ... _image = field.NamedImage() We'll create an instance with some data, too. >>> from plone.namedfile import NamedFile, NamedImage >>> fileValue = NamedFile('dummy test data', 'text/plain', filename=u"test.txt") >>> zptlogo = ( ... 'GIF89a\x10\x00\x10\x00\xd5\x00\x00\xff\xff\xff\xff\xff\xfe\xfc\xfd\xfd' ... '\xfa\xfb\xfc\xf7\xf9\xfa\xf5\xf8\xf9\xf3\xf6\xf8\xf2\xf5\xf7\xf0\xf4\xf6' ... '\xeb\xf1\xf3\xe5\xed\xef\xde\xe8\xeb\xdc\xe6\xea\xd9\xe4\xe8\xd7\xe2\xe6' ... '\xd2\xdf\xe3\xd0\xdd\xe3\xcd\xdc\xe1\xcb\xda\xdf\xc9\xd9\xdf\xc8\xd8\xdd' ... '\xc6\xd7\xdc\xc4\xd6\xdc\xc3\xd4\xda\xc2\xd3\xd9\xc1\xd3\xd9\xc0\xd2\xd9' ... '\xbd\xd1\xd8\xbd\xd0\xd7\xbc\xcf\xd7\xbb\xcf\xd6\xbb\xce\xd5\xb9\xcd\xd4' ... '\xb6\xcc\xd4\xb6\xcb\xd3\xb5\xcb\xd2\xb4\xca\xd1\xb2\xc8\xd0\xb1\xc7\xd0' ... '\xb0\xc7\xcf\xaf\xc6\xce\xae\xc4\xce\xad\xc4\xcd\xab\xc3\xcc\xa9\xc2\xcb' ... '\xa8\xc1\xca\xa6\xc0\xc9\xa4\xbe\xc8\xa2\xbd\xc7\xa0\xbb\xc5\x9e\xba\xc4' ... '\x9b\xbf\xcc\x98\xb6\xc1\x8d\xae\xbaFgs\x00\x00\x00\x00\x00\x00\x00\x00' ... '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ... '\x00,\x00\x00\x00\x00\x10\x00\x10\x00\x00\x06z@\x80pH,\x12k\xc8$\xd2f\x04' ... '\xd4\x84\x01\x01\xe1\xf0d\x16\x9f\x80A\x01\x91\xc0ZmL\xb0\xcd\x00V\xd4' ... '\xc4a\x87z\xed\xb0-\x1a\xb3\xb8\x95\xbdf8\x1e\x11\xca,MoC$\x15\x18{' ... '\x006}m\x13\x16\x1a\x1f\x83\x85}6\x17\x1b $\x83\x00\x86\x19\x1d!%)\x8c' ... '\x866#\'+.\x8ca`\x1c`(,/1\x94B5\x19\x1e"&*-024\xacNq\xba\xbb\xb8h\xbeb' ... '\x00A\x00;' ... ) >>> imageValue = NamedImage(zptlogo, 'image/gif', filename=u'zptl\xf8go.gif') >>> from zope.interface import implements >>> class TestContent(object): ... implements(ITestContent) ... _file = None ... _image = None >>> t = TestContent() >>> t._file = fileValue >>> t._image = imageValue We can now look up and test the marshaler. >>> from zope.component import getMultiAdapter >>> from plone.rfc822.interfaces import IFieldMarshaler For the moment, fields are not marked as primary. Our marshaller will refuse to marshal a non-primary field, as it does not make much sense to encode binary data into a UTF-8 string in a header. >>> marshaler = getMultiAdapter((t, ITestContent['_file']), IFieldMarshaler) >>> marshaler.marshal() Traceback (most recent call last): ... ValueError: File fields can only be marshaled as primary fields >>> marshaler.getContentType() 'text/plain' >>> marshaler.ascii False >>> marshaler = getMultiAdapter((t, ITestContent['_image']), IFieldMarshaler) >>> marshaler.marshal() is None Traceback (most recent call last): ... ValueError: File fields can only be marshaled as primary fields >>> marshaler.getContentType() 'image/gif' >>> marshaler.ascii False Let's try it with primary fields: >>> marshaler = getMultiAdapter((t, ITestContent['_file']), IFieldMarshaler) >>> marshaler.marshal(primary=True) 'dummy test data' >>> marshaler.getContentType() 'text/plain' >>> marshaler.getCharset('utf-8') is None True >>> marshaler.ascii False >>> marshaler = getMultiAdapter((t, ITestContent['_image']), IFieldMarshaler) >>> marshaler.marshal(primary=True) == zptlogo True >>> marshaler.getContentType() 'image/gif' >>> marshaler.getCharset('utf-8') is None True >>> marshaler.ascii False This marshaler will also post-process a message to encode the filename in the Content-Disposition header, and base64-encode the payload. To illustrate that, as well as parsing of the message, let's construct a full message and look at the output. First, we need to mark one of the fields as primary. In this case, we will use the file field. The image will will now be ignored, since our marshaler refuses to encode non-primary fields. >>> from plone.rfc822.interfaces import IPrimaryField >>> from plone.rfc822 import constructMessageFromSchema >>> from plone.rfc822 import renderMessage >>> from zope.interface import alsoProvides >>> alsoProvides(ITestContent['_file'], IPrimaryField) >>> message = constructMessageFromSchema(t, ITestContent) >>> messageBody = renderMessage(message) >>> print messageBody MIME-Version: 1.0 Content-Type: text/plain Content-Disposition: attachment; filename*="utf-8''test.txt" Content-Transfer-Encoding: base64 ZHVtbXkgdGVzdCBkYXRh You can see here that we have a transfer encoding and a content disposition. Let's now use this message to construct a new object. >>> from email import message_from_string >>> inputMessage = message_from_string(messageBody) >>> newContent = TestContent() >>> from plone.rfc822 import initializeObjectFromSchema >>> initializeObjectFromSchema(newContent, ITestContent, inputMessage) >>> newContent._file.data 'dummy test data' >>> newContent._file.contentType 'text/plain' >>> newContent._file.filename u'test.txt' >>> newContent._image is None True If we have two primary fields, they will be encoded as a multipart message. >>> alsoProvides(ITestContent['_image'], IPrimaryField) >>> message = constructMessageFromSchema(t, ITestContent) >>> messageBody = renderMessage(message) >>> print messageBody # doctest: +ELLIPSIS MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============...==" --===============...== MIME-Version: 1.0 Content-Type: text/plain Content-Disposition: attachment; filename*="utf-8''test.txt" Content-Transfer-Encoding: base64 ZHVtbXkgdGVzdCBkYXRh --===============...== MIME-Version: 1.0 Content-Type: image/gif Content-Disposition: attachment; filename*="utf-8''zptl%C3%B8go.gif" Content-Transfer-Encoding: base64 R0lGODlhEAAQANUAAP///////vz9/fr7/Pf5+vX4+fP2+PL19/D09uvx8+Xt797o69zm6tnk6Nfi 5tLf49Dd483c4cva38nZ38jY3cbX3MTW3MPU2sLT2cHT2cDS2b3R2L3Q17zP17vP1rvO1bnN1LbM 1LbL07XL0rTK0bLI0LHH0LDHz6/Gzq7Ezq3EzavDzKnCy6jByqbAyaS+yKK9x6C7xZ66xJu/zJi2 wY2uukZncwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAEAAQAAAGekCAcEgsEmvIJNJm BNSEAQHh8GQWn4BBAZHAWm1MsM0AVtTEYYd67bAtGrO4lb1mOB4RyixNb0MkFRh7ADZ9bRMWGh+D hX02FxsgJIMAhhkdISUpjIY2IycrLoxhYBxgKCwvMZRCNRkeIiYqLTAyNKxOcbq7uGi+YgBBADs= --===============...==--... Of course, we will also be able to load this data from a message. >>> inputMessage = message_from_string(messageBody) >>> newContent = TestContent() >>> initializeObjectFromSchema(newContent, ITestContent, inputMessage) >>> newContent._file.data 'dummy test data' >>> newContent._file.contentType 'text/plain' >>> newContent._file.filename u'test.txt' >>> newContent._image.data == zptlogo True >>> newContent._image.contentType 'image/gif' >>> newContent._image.filename u'zptl\xf8go.gif'