From 95413c1fbcc24f87f5d41c426795162b4d810626 Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Tue, 12 Jun 2018 08:45:22 +0200 Subject: [PATCH] Port implementation to DTMLDocument. --- CHANGES.rst | 3 +++ src/OFS/DTMLDocument.py | 14 +++++++++--- src/OFS/tests/test_DTMLDocument.py | 35 ++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 09dc748a82..dd8bb2747b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -14,6 +14,9 @@ https://github.com/zopefoundation/Zope/blob/4.0a6/CHANGES.rst - Add a minimum ``buildout.cfg`` suggestion in the docs for creating ``wsgi`` instances. +- Fix ZMI upload of `DTMLMethod` and `DTMLDocument` to store the DTML as a + native ``str`` on both Python versions. + 4.0b5 (2018-05-18) ------------------ diff --git a/src/OFS/DTMLDocument.py b/src/OFS/DTMLDocument.py index 2ad404f04a..02c6f0526a 100644 --- a/src/OFS/DTMLDocument.py +++ b/src/OFS/DTMLDocument.py @@ -17,7 +17,10 @@ from AccessControl.class_init import InitializeClass from DocumentTemplate.permissions import change_dtml_methods from DocumentTemplate.permissions import change_dtml_documents +from six import PY2 +from six import PY3 from six import binary_type +from six import text_type from six.moves.urllib.parse import quote from zExceptions import ResourceLockedError from zExceptions.TracebackSupplement import PathTracebackSupplement @@ -55,10 +58,15 @@ def manage_upload(self, file='', REQUEST=None): if self.wl_isLocked(): raise ResourceLockedError('This document has been locked.') - if not isinstance(file, binary_type): - if REQUEST and not file: - raise ValueError('No file specified') + if REQUEST and not file: + raise ValueError('No file specified') + + if hasattr(file, 'read'): file = file.read() + if PY3 and isinstance(file, binary_type): + file = file.decode('utf-8') + if PY2 and isinstance(file, text_type): + file = file.encode('utf-8') self.munge(file) self.ZCacheable_invalidate() diff --git a/src/OFS/tests/test_DTMLDocument.py b/src/OFS/tests/test_DTMLDocument.py index f5789847a2..3c7ef745da 100644 --- a/src/OFS/tests/test_DTMLDocument.py +++ b/src/OFS/tests/test_DTMLDocument.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +import io import unittest @@ -15,6 +17,39 @@ def test_class_conforms_to_IWriteLock(self): from OFS.interfaces import IWriteLock verifyClass(IWriteLock, self._getTargetClass()) + def test_manage_upload__bytes(self): + """It stores uploaded bytes as a native str.""" + doc = self._makeOne() + data = u'bÿtës'.encode('utf-8') + self.assertIsInstance(data, bytes) + doc.manage_upload(data) + self.assertEqual(doc.read(), 'bÿtës') + self.assertIsInstance(doc.read(), str) + + def test_manage_upload__str(self): + """It stores an uploaded str as a native str.""" + doc = self._makeOne() + data = 'bÿtës' + doc.manage_upload(data) + self.assertEqual(doc.read(), 'bÿtës') + self.assertIsInstance(doc.read(), str) + + def test_manage_upload__StringIO(self): + """It stores StringIO contents as a native str.""" + doc = self._makeOne() + data = io.StringIO(u'bÿtës') + doc.manage_upload(data) + self.assertIsInstance(doc.read(), str) + self.assertEqual(doc.read(), 'bÿtës') + + def test_manage_upload__BytesIO(self): + """It stores BytesIO contents as a native str.""" + doc = self._makeOne() + data = io.BytesIO(u'bÿtës'.encode('utf-8')) + doc.manage_upload(data) + self.assertEqual(doc.read(), 'bÿtës') + self.assertIsInstance(doc.read(), str) + class FactoryTests(unittest.TestCase):