Skip to content

Commit

Permalink
fix logic + doctests for python 3
Browse files Browse the repository at this point in the history
  • Loading branch information
jensens committed Jul 2, 2018
1 parent 1df4f35 commit 7027ce1
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 57 deletions.
4 changes: 2 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ Breaking changes:

New features:

- Target Zope 4 (test chnages only).
- Target Zope 4 (test changes only).

Bug fixes:

- Prepare for Python 2 / 3 compatibility
[ale-rt, pbauer, MatthewWilkes]
[ale-rt, pbauer, MatthewWilkes, jensens]

- remove mention of "retina" (https://github.com/plone/Products.CMFPlone/issues/2123)
[tkimnguyen]
Expand Down
27 changes: 12 additions & 15 deletions plone/namedfile/marshaler.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from email.encoders import encode_base64
from plone.namedfile import NamedBlobFile
from plone.namedfile import NamedBlobImage
from plone.namedfile import NamedFile
Expand All @@ -14,6 +13,7 @@

import six


class BaseNamedFileFieldMarshaler(BaseFieldMarshaler):
"""Base marshaler for plone.namedfile values. Actual adapters are
registered as subclasses.
Expand All @@ -27,18 +27,20 @@ def encode(self, value, charset='utf-8', primary=False):
# never in a header
if not primary:
raise ValueError(
'File fields can only be marshaled as primary fields')
'File fields can only be marshaled as primary fields'
)
if value is None:
return None
return value.data

def decode(
self,
value,
message=None,
charset='utf-8',
contentType=None,
primary=False):
self,
value,
message=None,
charset='utf-8',
contentType=None,
primary=False,
):
filename = None
if primary and message is not None:
filename = message.get_filename(None)
Expand All @@ -48,29 +50,24 @@ def getContentType(self):
value = self._query()
if value is None:
return None
if not isinstance(value.contentType, six.text_type):
return value.contentType.decode('utf8')
return value.contentType

def getCharset(self, default='utf-8'):
return None

def postProcessMessage(self, message):
"""Encode message as base64 and set content disposition
"""
value = self._query()

if value is not None:
filename = value.filename

if filename:

message.add_header('Content-Disposition', 'attachment')
message.set_param(
'filename',
filename.encode('utf-8') if six.PY2 else filename,
header='Content-Disposition',
charset='utf-8'
)
encode_base64(message)


@adapter(Interface, INamedFileField)
Expand Down
48 changes: 26 additions & 22 deletions plone/namedfile/marshaler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ To test this, we must first load some configuration::
... </configure>
... """

>>> from six import StringIO
>>> import six
>>> from zope.configuration import xmlconfig
>>> xmlconfig.xmlconfig(StringIO(configuration))
>>> xmlconfig.xmlconfig(six.StringIO(configuration))

Next, we will create a schema with which to test the marshaler::

Expand Down Expand Up @@ -86,6 +86,7 @@ binary data into a UTF-8 string in a header::

>>> marshaler.getContentType()
'text/plain'

>>> marshaler.ascii
False

Expand All @@ -97,14 +98,15 @@ binary data into a UTF-8 string in a header::

>>> marshaler.getContentType()
'image/gif'

>>> marshaler.ascii
False

Let's try it with primary fields::

>>> marshaler = getMultiAdapter((t, ITestContent['_file']), IFieldMarshaler)
>>> bytearray(marshaler.marshal(primary=True))
bytearray(b'dummy test data')
bytearray('dummy test data')

>>> marshaler.getContentType()
'text/plain'
Expand All @@ -124,31 +126,29 @@ Let's try it with primary fields::
>>> 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.
This marshaler will also post-process a message to encode the filename in the Content-Disposition header.
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::
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)

>>> from plone.rfc822 import constructMessageFromSchema
>>> message = constructMessageFromSchema(t, ITestContent)
>>> messageBody = renderMessage(message)
>>> messageBody = message.as_string()
>>> print(messageBody)
MIME-Version: 1.0
Content-Type: text/plain
Content-Disposition: attachment; filename*="utf-8''test.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename*=utf-8''test.txt
<BLANKLINE>
ZHVtbXkgdGVzdCBkYXRh
<BLANKLINE>

You can see here that we have a transfer encoding and a content disposition.

Expand All @@ -162,7 +162,7 @@ Let's now use this message to construct a new object::
>>> from plone.rfc822 import initializeObjectFromSchema
>>> initializeObjectFromSchema(newContent, ITestContent, inputMessage)
>>> bytearray(newContent._file.data)
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> newContent._file.contentType
'text/plain'
>>> newContent._file.filename
Expand All @@ -175,31 +175,35 @@ 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)
>>> messageBody = message.as_string()
>>> print(messageBody) # doctest: +ELLIPSIS
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="===============...=="
<BLANKLINE>
--===============...==
MIME-Version: 1.0
Content-Type: text/plain
Content-Disposition: attachment; filename*="utf-8''test.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename*=utf-8''test.txt
<BLANKLINE>
ZHVtbXkgdGVzdCBkYXRh
<BLANKLINE>
--===============...==
MIME-Version: 1.0
Content-Type: image/gif
Content-Disposition: attachment; filename*="utf-8''zptl%C3%B8go.gif"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename*=utf-8''zptl%C3%B8go.gif
<BLANKLINE>
R0lGODlhEAAQANUAAP///////vz9/fr7/Pf5+vX4+fP2+PL19/D09uvx8+Xt797o69zm6tnk6Nfi
5tLf49Dd483c4cva38nZ38jY3cbX3MTW3MPU2sLT2cHT2cDS2b3R2L3Q17zP17vP1rvO1bnN1LbM
1LbL07XL0rTK0bLI0LHH0LDHz6/Gzq7Ezq3EzavDzKnCy6jByqbAyaS+yKK9x6C7xZ66xJu/zJi2
wY2uukZncwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAEAAQAAAGekCAcEgsEmvIJNJm
BNSEAQHh8GQWn4BBAZHAWm1MsM0AVtTEYYd67bAtGrO4lb1mOB4RyixNb0MkFRh7ADZ9bRMWGh+D
hX02FxsgJIMAhhkdISUpjIY2IycrLoxhYBxgKCwvMZRCNRkeIiYqLTAyNKxOcbq7uGi+YgBBADs=
--===============...==--...
<BLANKLINE>
--===============...==--
<BLANKLINE>


Of course, we will also be able to load this data from a message::

Expand All @@ -208,7 +212,7 @@ Of course, we will also be able to load this data from a message::
>>> initializeObjectFromSchema(newContent, ITestContent, inputMessage)

>>> bytearray(newContent._file.data)
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> newContent._file.contentType
'text/plain'
>>> newContent._file.filename
Expand Down
2 changes: 1 addition & 1 deletion plone/namedfile/scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def traverse(self, name, furtherPath):
@deprecate('use property available_sizes instead')
def getAvailableSizes(self, fieldname=None):
if fieldname:
logger.warn(
logger.warning(
'fieldname was passed to deprecated getAvailableSizes, but '
'will be ignored.',
)
Expand Down
8 changes: 4 additions & 4 deletions plone/namedfile/testing.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# -*- coding: utf-8 -*-
from plone.testing import Layer
from plone.testing import publisher
from plone.testing import z2
from plone.testing import zope
from plone.testing import zca
from plone.testing import zodb
from zope.configuration import xmlconfig


class NamedFileTestLayer(Layer):

defaultBases = (z2.STARTUP, publisher.PUBLISHER_DIRECTIVES)
defaultBases = (zope.STARTUP, publisher.PUBLISHER_DIRECTIVES)

def setUp(self):
zca.pushGlobalRegistry()
Expand All @@ -33,12 +33,12 @@ def tearDown(self):

PLONE_NAMEDFILE_FIXTURE = NamedFileTestLayer()

PLONE_NAMEDFILE_INTEGRATION_TESTING = z2.IntegrationTesting(
PLONE_NAMEDFILE_INTEGRATION_TESTING = zope.IntegrationTesting(
bases=(PLONE_NAMEDFILE_FIXTURE, ),
name='plone.namedfile:NamedFileTestLayerIntegration',
)

PLONE_NAMEDFILE_FUNCTIONAL_TESTING = z2.FunctionalTesting(
PLONE_NAMEDFILE_FUNCTIONAL_TESTING = zope.FunctionalTesting(
bases=(PLONE_NAMEDFILE_FIXTURE, ),
name='plone.namedfile:NamedFileTestLayerFunctional',
)
5 changes: 4 additions & 1 deletion plone/namedfile/tests/test_doctests.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@
'utils.rst',
]


class Py23DocChecker(doctest.OutputChecker):
def check_output(self, want, got, optionflags):
if six.PY2:
got = re.sub('zExceptions.NotFound', 'NotFound', got)
got = re.sub("u'(.*?)'", "'\\1'", got)
got = re.sub('zExceptions.NotFound', 'NotFound', got)
got = re.sub(
r"WrongType: \('(.*?)', <type 'unicode'>, '(.*?)'\)",
r"zope.schema._bootstrapinterfaces.WrongType: (b'\1', <class 'str'>, '\2')", # noqa E508
got
)
if six.PY3:
got = re.sub("b'(.*?)'", "'\\1'", got)
return doctest.OutputChecker.check_output(self, want, got, optionflags)


Expand Down
2 changes: 1 addition & 1 deletion plone/namedfile/tests/test_scaling_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from plone.namedfile.scaling import ImageScaling
from plone.namedfile.testing import PLONE_NAMEDFILE_FUNCTIONAL_TESTING
from plone.namedfile.tests import getFile
from plone.testing.z2 import Browser
from plone.testing.zope import Browser
from six import BytesIO
from zope.annotation import IAttributeAnnotatable
from zope.interface import implementer
Expand Down
18 changes: 9 additions & 9 deletions plone/namedfile/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The FileContainer class creates empty objects to start with::
>>> container = FileContainer()

>>> bytearray(container.simple.data)
bytearray(b'')
bytearray('')
>>> container.simple.contentType
''
>>> container.simple.filename is None
Expand Down Expand Up @@ -75,15 +75,15 @@ will attempt to guess the filename from the file extension::

>>> container.simple = namedfile.NamedFile('dummy test data', filename=u"test.txt")
>>> bytearray(container.simple.data)
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> container.simple.contentType
'text/plain'
>>> print(container.simple.filename)
test.txt

>>> container.blob = namedfile.NamedBlobFile('dummy test data', filename=u"test.txt")
>>> bytearray(container.blob.data)
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> container.blob.contentType
'text/plain'
>>> print(container.blob.filename)
Expand Down Expand Up @@ -150,7 +150,7 @@ The filename must be set to a unicode string, not a bytestring::
>>> container.image.filename = b'foo'
Traceback (most recent call last):
...
zope.schema._bootstrapinterfaces.WrongType: (b'foo', <class 'str'>, 'filename')
zope.schema._bootstrapinterfaces.WrongType: ('foo', <class 'str'>, 'filename')


Download view
Expand All @@ -170,7 +170,7 @@ We will test this with a dummy request, faking traversal::
>>> request = TestRequest()
>>> download = Download(container, request).publishTraverse(request, 'simple')
>>> bytearray(download())
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
Expand All @@ -182,7 +182,7 @@ We will test this with a dummy request, faking traversal::
>>> download = Download(container, request).publishTraverse(request, 'blob')
>>> data = download()
>>> bytearray(hasattr(data, 'read') and data.read() or data)
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
Expand Down Expand Up @@ -231,7 +231,7 @@ We will test this with a dummy request, faking traversal::
>>> request = TestRequest()
>>> display_file = DisplayFile(container, request).publishTraverse(request, 'simple')
>>> bytearray(display_file())
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
Expand All @@ -242,7 +242,7 @@ We will test this with a dummy request, faking traversal::
>>> display_file = DisplayFile(container, request).publishTraverse(request, 'blob')
>>> data = display_file()
>>> bytearray(hasattr(data, 'read') and data.read() or data)
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
Expand Down Expand Up @@ -299,7 +299,7 @@ We will test this with a dummy request, faking traversal::
>>> request = TestRequest()
>>> download = Download(container, request)
>>> bytearray(download())
bytearray(b'dummy test data')
bytearray('dummy test data')
>>> request.response.getHeader('Content-Length')
'15'
>>> request.response.getHeader('Content-Type')
Expand Down
Loading

0 comments on commit 7027ce1

Please sign in to comment.