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'