Commit f23f8ff2 authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki Committed by Jérome Perrin

py2/py3: data property is for binary, thus getData() should return bytes.

parent cb5ed562
...@@ -32,8 +32,7 @@ ...@@ -32,8 +32,7 @@
import os import os
import subprocess import subprocess
from six.moves import cStringIO as StringIO from io import BytesIO
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Acquisition import aq_base from Acquisition import aq_base
...@@ -117,7 +116,7 @@ class Image(TextConvertableMixin, File, OFSImage): ...@@ -117,7 +116,7 @@ class Image(TextConvertableMixin, File, OFSImage):
content_type, width, height = getImageInfo(self.data) content_type, width, height = getImageInfo(self.data)
if not content_type: if not content_type:
try: try:
image = PIL.Image.open(StringIO(str(self.data))) image = PIL.Image.open(BytesIO(bytes(self.data)))
except IOError: except IOError:
width = height = -1 width = height = -1
content_type = 'application/unknown' content_type = 'application/unknown'
...@@ -381,7 +380,7 @@ class Image(TextConvertableMixin, File, OFSImage): ...@@ -381,7 +380,7 @@ class Image(TextConvertableMixin, File, OFSImage):
else: else:
parameter_list.append('-') parameter_list.append('-')
data = str(self.getData()) data = bytes(self.getData())
if self.getContentType() == "image/svg+xml": if self.getContentType() == "image/svg+xml":
data = transformUrlToDataURI(data) data = transformUrlToDataURI(data)
...@@ -401,7 +400,7 @@ class Image(TextConvertableMixin, File, OFSImage): ...@@ -401,7 +400,7 @@ class Image(TextConvertableMixin, File, OFSImage):
finally: finally:
del process del process
if image: if image:
return StringIO(image) return BytesIO(image)
raise ConversionError('Image conversion failed (%s).' % err) raise ConversionError('Image conversion failed (%s).' % err)
def _getContentTypeAndImageData( def _getContentTypeAndImageData(
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
############################################################################## ##############################################################################
import re, zipfile import re, zipfile
from six.moves import cStringIO as StringIO from io import BytesIO
from warnings import warn from warnings import warn
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from OFS.Image import Pdata from OFS.Image import Pdata
...@@ -39,7 +39,7 @@ from Products.ERP5Type.Cache import CachingMethod ...@@ -39,7 +39,7 @@ from Products.ERP5Type.Cache import CachingMethod
from erp5.component.document.File import File from erp5.component.document.File import File
from erp5.component.document.Document import Document, \ from erp5.component.document.Document import Document, \
VALID_IMAGE_FORMAT_LIST, ConversionError, NotConvertedError VALID_IMAGE_FORMAT_LIST, ConversionError, NotConvertedError
from Products.ERP5Type.Utils import fill_args_from_request from Products.ERP5Type.Utils import bytes2str, fill_args_from_request, str2bytes
# Mixin Import # Mixin Import
from erp5.component.mixin.BaseConvertableFileMixin import BaseConvertableFileMixin from erp5.component.mixin.BaseConvertableFileMixin import BaseConvertableFileMixin
...@@ -199,10 +199,10 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -199,10 +199,10 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
raise NotConvertedError() raise NotConvertedError()
if format == 'text-content': if format == 'text-content':
# Extract text from the ODF file # Extract text from the ODF file
cs = cStringIO.StringIO() cs = BytesIO()
cs.write(str(self.getBaseData())) cs.write(self.getBaseData())
z = zipfile.ZipFile(cs) z = zipfile.ZipFile(cs)
s = z.read('content.xml') s = bytes2str(z.read('content.xml'))
s = self.rx_strip.sub(" ", s) # strip xml s = self.rx_strip.sub(" ", s) # strip xml
s = self.rx_compr.sub(" ", s) # compress multiple spaces s = self.rx_compr.sub(" ", s) # compress multiple spaces
cs.close() cs.close()
...@@ -211,7 +211,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -211,7 +211,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
server_proxy = DocumentConversionServerProxy(self) server_proxy = DocumentConversionServerProxy(self)
orig_format = self.getBaseContentType() orig_format = self.getBaseContentType()
generate_result = server_proxy.run_generate(self.getId(), generate_result = server_proxy.run_generate(self.getId(),
enc(str(self.getBaseData())), bytes2str(enc(bytes(self.getBaseData()))),
None, None,
format, format,
orig_format) orig_format)
...@@ -223,7 +223,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -223,7 +223,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
response_dict = generate_result response_dict = generate_result
# XXX: handle possible OOOd server failure # XXX: handle possible OOOd server failure
return response_dict['mime'], Pdata(dec(response_dict['data'])) return response_dict['mime'], Pdata(dec(str2bytes(response_dict['data'])))
# Conversion API # Conversion API
def _convert(self, format, frame=0, **kw): # pylint: disable=redefined-builtin def _convert(self, format, frame=0, **kw): # pylint: disable=redefined-builtin
...@@ -259,7 +259,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -259,7 +259,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
original_format = format original_format = format
allowed_format_list = self.getTargetFormatList() allowed_format_list = self.getTargetFormatList()
if format == 'base-data': if format == 'base-data':
return self.getBaseContentType(), str(self.getBaseData()) return self.getBaseContentType(), self.getBaseData()
if format == 'pdf': if format == 'pdf':
format_list = [x for x in allowed_format_list format_list = [x for x in allowed_format_list
if x.endswith('pdf')] if x.endswith('pdf')]
...@@ -302,8 +302,8 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -302,8 +302,8 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
if is_html: if is_html:
# Extra processing required since # Extra processing required since
# we receive a zip file # we receive a zip file
cs = cStringIO.StringIO() cs = BytesIO()
cs.write(str(data)) cs.write(data)
z = zipfile.ZipFile(cs) # A disk file would be more RAM efficient z = zipfile.ZipFile(cs) # A disk file would be more RAM efficient
for f in z.infolist(): for f in z.infolist():
fn = f.filename fn = f.filename
...@@ -325,7 +325,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -325,7 +325,7 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
# create temporary image and use it to resize accordingly # create temporary image and use it to resize accordingly
temp_image = self.portal_contributions.newContent( temp_image = self.portal_contributions.newContent(
portal_type='Image', portal_type='Image',
file=cStringIO.StringIO(), file=BytesIO(),
filename=self.getId(), filename=self.getId(),
temp_object=1) temp_object=1)
temp_image._setData(data) temp_image._setData(data)
...@@ -347,8 +347,8 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -347,8 +347,8 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
format_list = [x for x in self.getTargetFormatList() format_list = [x for x in self.getTargetFormatList()
if x.startswith('html') or x.endswith('html')] if x.startswith('html') or x.endswith('html')]
mime, data = self._getConversionFromProxyServer(format_list[0]) mime, data = self._getConversionFromProxyServer(format_list[0])
archive_file = cStringIO.StringIO() archive_file = BytesIO()
archive_file.write(str(data)) archive_file.write(data)
zip_file = zipfile.ZipFile(archive_file) zip_file = zipfile.ZipFile(archive_file)
must_close = 1 must_close = 1
else: else:
...@@ -385,13 +385,13 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -385,13 +385,13 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
server_proxy = DocumentConversionServerProxy(self) server_proxy = DocumentConversionServerProxy(self)
response_code, response_dict, response_message = server_proxy.run_convert( response_code, response_dict, response_message = server_proxy.run_convert(
self.getFilename() or self.getId(), self.getFilename() or self.getId(),
enc(str(self.getData())), bytes2str(enc(bytes(self.getData()))),
None, None,
None, None,
self.getContentType()) self.getContentType())
if response_code == 200: if response_code == 200:
# sucessfully converted document # sucessfully converted document
self._setBaseData(dec(response_dict['data'])) self._setBaseData(dec(str2bytes(response_dict['data'])))
metadata = response_dict['meta'] metadata = response_dict['meta']
self._base_metadata = metadata self._base_metadata = metadata
if metadata.get('MIMEType', None) is not None: if metadata.get('MIMEType', None) is not None:
...@@ -424,11 +424,11 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi ...@@ -424,11 +424,11 @@ class OOoDocument(OOoDocumentExtensibleTraversableMixin, BaseConvertableFileMixi
server_proxy = DocumentConversionServerProxy(self) server_proxy = DocumentConversionServerProxy(self)
response_code, response_dict, response_message = \ response_code, response_dict, response_message = \
server_proxy.run_setmetadata(self.getId(), server_proxy.run_setmetadata(self.getId(),
enc(str(self.getBaseData())), bytes2str(enc(bytes(self.getBaseData()))),
kw) kw)
if response_code == 200: if response_code == 200:
# successful meta data extraction # successful meta data extraction
self._setBaseData(dec(response_dict['data'])) self._setBaseData(dec(str2bytes(response_dict['data'])))
self.updateFileMetadata() # record in workflow history # XXX must put appropriate comments. self.updateFileMetadata() # record in workflow history # XXX must put appropriate comments.
else: else:
# Explicitly raise the exception! # Explicitly raise the exception!
......
...@@ -29,7 +29,7 @@ if context.getPortalType() in ["Presentation"]: ...@@ -29,7 +29,7 @@ if context.getPortalType() in ["Presentation"]:
portal = context.getPortalObject() portal = context.getPortalObject()
mimetype = 'text/html' mimetype = 'text/html'
content_type = context.getContentType() content_type = context.getContentType()
raw_data = portal.portal_transforms.convertToData(mimetype, str(context.getData() or ""), context=context, mimetype=content_type) raw_data = portal.portal_transforms.convertToData(mimetype, bytes(context.getData() or b""), context=context, mimetype=content_type)
if raw_data is None: if raw_data is None:
raise ValueError("Failed to convert to %r" % mimetype) raise ValueError("Failed to convert to %r" % mimetype)
if context.REQUEST is not None: if context.REQUEST is not None:
......
...@@ -727,7 +727,7 @@ class TestCRMMailIngestion(BaseTestCRM): ...@@ -727,7 +727,7 @@ class TestCRMMailIngestion(BaseTestCRM):
self.assertEqual( self.assertEqual(
'Mail Message', 'Mail Message',
self.portal.portal_contribution_registry.findPortalTypeName( self.portal.portal_contribution_registry.findPortalTypeName(
filename='postfix_mail.eml', content_type='message/rfc822', data='Test' filename='postfix_mail.eml', content_type='message/rfc822', data=b'Test'
)) ))
def test_Base_getEntityListFromFromHeader(self): def test_Base_getEntityListFromFromHeader(self):
...@@ -844,13 +844,13 @@ class TestCRMMailIngestion(BaseTestCRM): ...@@ -844,13 +844,13 @@ class TestCRMMailIngestion(BaseTestCRM):
event = self.portal.event_module.newContent( event = self.portal.event_module.newContent(
portal_type='Mail Message', portal_type='Mail Message',
destination_value=organisation, destination_value=organisation,
data='\r\n'.join(textwrap.dedent(''' data=('\r\n'.join(textwrap.dedent('''
From: Source <source@example.com> From: Source <source@example.com>
To: destination <destination@example.com> To: destination <destination@example.com>
Subject: mail subject Subject: mail subject
content content
''').splitlines()[1:])) ''').splitlines()[1:])).encode())
property_dict = event.getPropertyDictFromContent() property_dict = event.getPropertyDictFromContent()
# destination is set on the event. In this case it is kept as is. # destination is set on the event. In this case it is kept as is.
...@@ -1059,7 +1059,8 @@ class TestCRMMailIngestion(BaseTestCRM): ...@@ -1059,7 +1059,8 @@ class TestCRMMailIngestion(BaseTestCRM):
file_path = '%s/test_data/%s' % ( file_path = '%s/test_data/%s' % (
os.path.dirname(Products.ERP5.tests.__file__), os.path.dirname(Products.ERP5.tests.__file__),
filename) filename)
event.setData(open(file_path).read()) with open(file_path, 'rb') as f:
event.setData(f.read())
self.assertTrue(event.getTextContent().startswith('<')) self.assertTrue(event.getTextContent().startswith('<'))
...@@ -1811,7 +1812,7 @@ class TestCRMMailSend(BaseTestCRM): ...@@ -1811,7 +1812,7 @@ class TestCRMMailSend(BaseTestCRM):
self.assertEqual(event.getTitle(), dummy_title) self.assertEqual(event.getTitle(), dummy_title)
self.assertEqual(event.getTextContent(), dummy_content) self.assertEqual(event.getTextContent(), dummy_content)
event.setData('Subject: %s\r\n\r\n%s' % (real_title, real_content)) event.setData(('Subject: %s\r\n\r\n%s' % (real_title, real_content)).encode())
self.assertTrue(event.hasFile(), '%r has no file' % (event,)) self.assertTrue(event.hasFile(), '%r has no file' % (event,))
self.assertEqual(event.getTitle(), real_title) self.assertEqual(event.getTitle(), real_title)
self.assertEqual(event.getTextContent(), real_content) self.assertEqual(event.getTextContent(), real_content)
......
...@@ -215,7 +215,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -215,7 +215,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional):
# Set a fake file on Event and make sure no more editor is displayed # Set a fake file on Event and make sure no more editor is displayed
# and that instead a div with page CSS style appears with stripped HTML # and that instead a div with page CSS style appears with stripped HTML
event.setData('fake') event.setData(b'fake')
self.assertFalse(event.Event_view.my_text_content.get_value('editable')) self.assertFalse(event.Event_view.my_text_content.get_value('editable'))
html_text = event.view() html_text = event.view()
self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake')) self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake'))
...@@ -244,7 +244,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -244,7 +244,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional):
# Set a fake file on Event and make sure no more editor is displayed # Set a fake file on Event and make sure no more editor is displayed
# and that instead a div with page CSS style appears with stripped HTML # and that instead a div with page CSS style appears with stripped HTML
event.setData('fake') event.setData(b'fake')
self.assertFalse(event.Event_view.my_text_content.get_value('editable')) self.assertFalse(event.Event_view.my_text_content.get_value('editable'))
html_text = event.view() html_text = event.view()
self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake')) self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake'))
...@@ -272,7 +272,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -272,7 +272,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional):
# Set a fake file on Event and make sure no more editor is displayed # Set a fake file on Event and make sure no more editor is displayed
# and that instead a div with page CSS style appears with stripped HTML # and that instead a div with page CSS style appears with stripped HTML
event.setData('fake') event.setData(b'fake')
self.assertFalse(event.Event_view.my_text_content.get_value('editable')) self.assertFalse(event.Event_view.my_text_content.get_value('editable'))
html_text = event.view() html_text = event.view()
self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake')) self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake'))
...@@ -300,7 +300,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional): ...@@ -300,7 +300,7 @@ class TestEditorField(ERP5TypeTestCase, ZopeTestCase.Functional):
# Set a fake file on Event and make sure no more editor is displayed # Set a fake file on Event and make sure no more editor is displayed
# and that instead a div with page CSS style appears with stripped HTML # and that instead a div with page CSS style appears with stripped HTML
event.setData('fake') event.setData(b'fake')
self.assertFalse(event.Event_view.my_text_content.get_value('editable')) self.assertFalse(event.Event_view.my_text_content.get_value('editable'))
html_text = event.view() html_text = event.view()
self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake')) self.assertTrue(self._isReadOnlyEditor(html_text, event, 'fake'))
......
...@@ -32,13 +32,16 @@ import zope.interface ...@@ -32,13 +32,16 @@ import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.Utils import bytes2str
from erp5.component.interface.IWatermarkable import IWatermarkable from erp5.component.interface.IWatermarkable import IWatermarkable
from erp5.component.document.Image import Image from erp5.component.document.Image import Image
from erp5.component.document.Document import ConversionError from erp5.component.document.Document import ConversionError
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from zLOG import LOG, INFO, PROBLEM from zLOG import LOG, INFO, PROBLEM
import errno import errno
from StringIO import StringIO from io import BytesIO
from six.moves import range
import six
@zope.interface.implementer(IWatermarkable) @zope.interface.implementer(IWatermarkable)
class PDFDocument(Image): class PDFDocument(Image):
...@@ -90,8 +93,8 @@ class PDFDocument(Image): ...@@ -90,8 +93,8 @@ class PDFDocument(Image):
raise ValueError("watermark_data cannot not be empty") raise ValueError("watermark_data cannot not be empty")
if not self.hasData(): if not self.hasData():
raise ValueError("Cannot watermark an empty document") raise ValueError("Cannot watermark an empty document")
self_reader = PdfFileReader(StringIO(self.getData())) self_reader = PdfFileReader(BytesIO(self.getData()))
watermark_reader = PdfFileReader(StringIO(watermark_data)) watermark_reader = PdfFileReader(BytesIO(watermark_data))
watermark_page_count = watermark_reader.getNumPages() watermark_page_count = watermark_reader.getNumPages()
output = PdfFileWriter() output = PdfFileWriter()
...@@ -109,7 +112,7 @@ class PDFDocument(Image): ...@@ -109,7 +112,7 @@ class PDFDocument(Image):
self_page.mergePage(watermark_page) self_page.mergePage(watermark_page)
output.addPage(self_page) output.addPage(self_page)
outputStream = StringIO() outputStream = BytesIO()
output.write(outputStream) output.write(outputStream)
return outputStream.getvalue() return outputStream.getvalue()
...@@ -171,7 +174,7 @@ class PDFDocument(Image): ...@@ -171,7 +174,7 @@ class PDFDocument(Image):
""" """
if not self.hasData(): if not self.hasData():
return '' return ''
data = str(self.getData()) data = bytes(self.getData())
try: try:
from PyPDF2 import PdfFileReader from PyPDF2 import PdfFileReader
from PyPDF2.utils import PdfReadError from PyPDF2.utils import PdfReadError
...@@ -179,7 +182,7 @@ class PDFDocument(Image): ...@@ -179,7 +182,7 @@ class PDFDocument(Image):
pass pass
else: else:
try: try:
if PdfFileReader(StringIO(data)).isEncrypted: if PdfFileReader(BytesIO(data)).isEncrypted:
return '' return ''
except PdfReadError: except PdfReadError:
return '' return ''
...@@ -344,7 +347,7 @@ class PDFDocument(Image): ...@@ -344,7 +347,7 @@ class PDFDocument(Image):
raise raise
result = {} result = {}
for line in command_result.splitlines(): for line in bytes2str(command_result).splitlines():
item_list = line.split(':') item_list = line.split(':')
key = item_list[0].strip() key = item_list[0].strip()
value = ':'.join(item_list[1:]).strip() value = ':'.join(item_list[1:]).strip()
...@@ -360,9 +363,9 @@ class PDFDocument(Image): ...@@ -360,9 +363,9 @@ class PDFDocument(Image):
else: else:
try: try:
pdf_file = PdfFileReader(tmp) pdf_file = PdfFileReader(tmp)
for info_key, info_value in (pdf_file.getDocumentInfo() or {}).iteritems(): for info_key, info_value in six.iteritems(pdf_file.getDocumentInfo() or {}):
info_key = info_key.lstrip("/") info_key = info_key.lstrip("/")
if isinstance(info_value, unicode): if six.PY2 and isinstance(info_value, six.text_type):
info_value = info_value.encode("utf-8") info_value = info_value.encode("utf-8")
# Ignore values that cannot be pickled ( such as AAPL:Keywords ) # Ignore values that cannot be pickled ( such as AAPL:Keywords )
......
...@@ -2900,7 +2900,7 @@ return 1 ...@@ -2900,7 +2900,7 @@ return 1
document.setReference('TEST') document.setReference('TEST')
request = self.app.REQUEST request = self.app.REQUEST
download_file = document.index_html(REQUEST=request, format=None) download_file = document.index_html(REQUEST=request, format=None)
self.assertEqual(download_file, 'foo\n') self.assertEqual(download_file, b'foo\n')
document_format = None document_format = None
self.assertEqual('TEST-001-en.dummy', document.getStandardFilename( self.assertEqual('TEST-001-en.dummy', document.getStandardFilename(
document_format)) document_format))
......
...@@ -60,12 +60,12 @@ if not zip_file: ...@@ -60,12 +60,12 @@ if not zip_file:
rejectSoftwarePublication(software_publication) rejectSoftwarePublication(software_publication)
return return
from six.moves import cStringIO as StringIO from io import BytesIO
import zipfile import zipfile
from zipfile import BadZipfile from zipfile import BadZipfile
zipbuffer = StringIO() zipbuffer = BytesIO()
zipbuffer.write(str(zip_file.getData())) zipbuffer.write(bytes(zip_file.getData()))
try: try:
zip_reader = zipfile.ZipFile(zipbuffer) zip_reader = zipfile.ZipFile(zipbuffer)
except BadZipfile: except BadZipfile:
......
...@@ -181,7 +181,7 @@ class TestSimplifiedPayslipReport(ERP5TypeTestCase): ...@@ -181,7 +181,7 @@ class TestSimplifiedPayslipReport(ERP5TypeTestCase):
image_source_pdf_doc.setData(pdf_data) image_source_pdf_doc.setData(pdf_data)
self.tic() self.tic()
_, png = image_source_pdf_doc.convert("png", frame=0, quality=100) _, png = image_source_pdf_doc.convert("png", frame=0, quality=100)
self.assertImageRenderingEquals(str(png), str(expected_image.getData())) self.assertImageRenderingEquals(bytes(png), bytes(expected_image.getData()))
def test_03_payslip_holiday(self): def test_03_payslip_holiday(self):
for i in self.portal.portal_catalog( for i in self.portal.portal_catalog(
...@@ -257,5 +257,3 @@ class TestSimplifiedPayslipReport(ERP5TypeTestCase): ...@@ -257,5 +257,3 @@ class TestSimplifiedPayslipReport(ERP5TypeTestCase):
self.assertEqual(payslip_data["report_data"]["total_holiday_this_year"], 2) self.assertEqual(payslip_data["report_data"]["total_holiday_this_year"], 2)
self.assertEqual(payslip_data["report_data"]["taken_holiday"], 2) self.assertEqual(payslip_data["report_data"]["taken_holiday"], 2)
self.assertEqual(payslip_data["report_data"]["total_holiday_year_before"], 0) self.assertEqual(payslip_data["report_data"]["total_holiday_year_before"], 0)
...@@ -52,5 +52,5 @@ class ShaCacheMixin(object): ...@@ -52,5 +52,5 @@ class ShaCacheMixin(object):
} }
self.shacache_url = self.shacache.absolute_url() self.shacache_url = self.shacache.absolute_url()
self.tic() self.tic()
self.data = 'Random Content. %s' % str(random.random()) self.data = 'Random Content. %s' % str(random.random()).encode()
self.key = hashlib.sha512(self.data).hexdigest() self.key = hashlib.sha512(self.data).hexdigest()
...@@ -216,7 +216,7 @@ class TestShaDirSecurity(ShaDirMixin, ShaSecurityMixin, SecurityTestCase): ...@@ -216,7 +216,7 @@ class TestShaDirSecurity(ShaDirMixin, ShaSecurityMixin, SecurityTestCase):
data_set = self.portal.data_set_module.newContent(portal_type='Data Set') data_set = self.portal.data_set_module.newContent(portal_type='Data Set')
document = self.portal.portal_contributions.newContent( document = self.portal.portal_contributions.newContent(
filename='test.txt', filename='test.txt',
data='test content', data=b'test content',
reference='test-reference', reference='test-reference',
discover_metadata=False, discover_metadata=False,
follow_up_list=[data_set.getRelativeUrl()]) follow_up_list=[data_set.getRelativeUrl()])
......
...@@ -37,7 +37,7 @@ from erp5.component.document.Document import ConversionError ...@@ -37,7 +37,7 @@ from erp5.component.document.Document import ConversionError
from Products.ERP5Type.Base import Base, removeIContentishInterface from Products.ERP5Type.Base import Base, removeIContentishInterface
from OFS.Image import File as OFS_File from OFS.Image import File as OFS_File
from Products.ERP5Type.Utils import deprecated from Products.ERP5Type.Utils import deprecated
import six
_MARKER = object() _MARKER = object()
...@@ -67,7 +67,7 @@ class File(Document, OFS_File): ...@@ -67,7 +67,7 @@ class File(Document, OFS_File):
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default global values # Default global values
data = '' # A hack required to use OFS.Image.index_html without calling OFS.Image.__init__ data = b'' # A hack required to use OFS.Image.index_html without calling OFS.Image.__init__
# Default Properties # Default Properties
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.Base
...@@ -186,6 +186,8 @@ class File(Document, OFS_File): ...@@ -186,6 +186,8 @@ class File(Document, OFS_File):
if data is None: if data is None:
return None return None
else: else:
if six.PY3 and isinstance(data, str):
return bytes(data, self._get_encoding())
return bytes(data) return bytes(data)
# DAV Support # DAV Support
......
...@@ -33,6 +33,7 @@ from Products.ERP5Type.Message import translateString ...@@ -33,6 +33,7 @@ from Products.ERP5Type.Message import translateString
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from OFS.Image import Pdata from OFS.Image import Pdata
from io import BytesIO from io import BytesIO
import six
_MARKER = object() _MARKER = object()
class BaseConvertableFileMixin: class BaseConvertableFileMixin:
......
...@@ -37,6 +37,7 @@ from AccessControl import ClassSecurityInfo ...@@ -37,6 +37,7 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import InitializeClass from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5Type.Utils import str2bytes
from OFS.Image import Pdata, Image as OFSImage from OFS.Image import Pdata, Image as OFSImage
from DateTime import DateTime from DateTime import DateTime
...@@ -129,17 +130,20 @@ class CachedConvertableMixin: ...@@ -129,17 +130,20 @@ class CachedConvertableMixin:
conversion_md5 = None conversion_md5 = None
size = 0 size = 0
elif isinstance(data, Pdata): elif isinstance(data, Pdata):
cached_value = aq_base(data) cached_value = bytes(aq_base(data))
size = str(cached_value) # not a size but avoids a 'del' statement conversion_md5 = md5(cached_value).hexdigest()
conversion_md5 = md5(size).hexdigest() size = len(cached_value)
size = len(size)
elif isinstance(data, OFSImage): elif isinstance(data, OFSImage):
warn('Passing an OFS.Image to setConversion is deprecated', stacklevel=1) warn('Passing an OFS.Image to setConversion is deprecated', stacklevel=1)
cached_value = bytes(data)
conversion_md5 = md5(cached_value).hexdigest()
size = len(cached_value)
elif isinstance(data, bytes):
cached_value = data cached_value = data
conversion_md5 = md5(str(data.data)).hexdigest() conversion_md5 = md5(cached_value).hexdigest()
size = len(data.data) size = len(cached_value)
elif isinstance(data, six.string_types): elif isinstance(data, six.string_types):
cached_value = data cached_value = str2bytes(data)
conversion_md5 = md5(cached_value).hexdigest() conversion_md5 = md5(cached_value).hexdigest()
size = len(cached_value) size = len(cached_value)
elif isinstance(data, dict): elif isinstance(data, dict):
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
</item> </item>
<item> <item>
<key> <string>property_default</string> </key> <key> <string>property_default</string> </key>
<value> <string>python: \'\'</string> </value> <value> <string>python: b\'\'</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
</item> </item>
<item> <item>
<key> <string>property_default</string> </key> <key> <string>property_default</string> </key>
<value> <string>python: \'\'</string> </value> <value> <string>python: b\'\'</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -37,6 +37,7 @@ from Products.ERP5OOo.OOoUtils import OOoBuilder ...@@ -37,6 +37,7 @@ from Products.ERP5OOo.OOoUtils import OOoBuilder
from Products.CMFCore.exceptions import AccessControl_Unauthorized from Products.CMFCore.exceptions import AccessControl_Unauthorized
from Acquisition import Implicit, aq_base from Acquisition import Implicit, aq_base
from Products.ERP5Type.Globals import InitializeClass, DTMLFile, Persistent from Products.ERP5Type.Globals import InitializeClass, DTMLFile, Persistent
from Products.ERP5Type.Utils import bytes2str, str2bytes
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from OFS.role import RoleManager from OFS.role import RoleManager
from OFS.SimpleItem import Item from OFS.SimpleItem import Item
...@@ -290,11 +291,11 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item, PropertyManager): ...@@ -290,11 +291,11 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item, PropertyManager):
from erp5.component.document.Document import DocumentConversionServerProxy, enc, dec from erp5.component.document.Document import DocumentConversionServerProxy, enc, dec
server_proxy = DocumentConversionServerProxy(self) server_proxy = DocumentConversionServerProxy(self)
extension = guess_extension(content_type).strip('.') extension = guess_extension(content_type).strip('.')
printout = dec(server_proxy.convertFile(enc(printout), printout = dec(str2bytes(server_proxy.convertFile(bytes2str(enc(printout)),
extension, # source_format extension, # source_format
extension, # destination_format extension, # destination_format
False, # zip False, # zip
True)) # refresh True))) # refresh
# End of temporary implementation # End of temporary implementation
if not format: if not format:
if REQUEST is not None and not batch_mode: if REQUEST is not None and not batch_mode:
...@@ -317,7 +318,7 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item, PropertyManager): ...@@ -317,7 +318,7 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item, PropertyManager):
REQUEST.RESPONSE.setHeader('Content-type', mime) REQUEST.RESPONSE.setHeader('Content-type', mime)
REQUEST.RESPONSE.setHeader('Content-disposition', REQUEST.RESPONSE.setHeader('Content-disposition',
'attachment;filename="%s.%s"' % (filename, format)) 'attachment;filename="%s.%s"' % (filename, format))
return str(data) return bytes(data)
InitializeClass(FormPrintout) InitializeClass(FormPrintout)
...@@ -574,7 +575,7 @@ class ODFStrategy(Implicit): ...@@ -574,7 +575,7 @@ class ODFStrategy(Implicit):
path = image_field.get_value('default') path = image_field.get_value('default')
image_node = image_list[0] image_node = image_list[0]
image_frame = image_node.getparent() image_frame = image_node.getparent()
if path is not None: if six.PY2 and path is not None:
path = path.encode() path = path.encode()
picture = self.getPortalObject().restrictedTraverse(path) picture = self.getPortalObject().restrictedTraverse(path)
picture_data = getattr(aq_base(picture), 'data', None) picture_data = getattr(aq_base(picture), 'data', None)
...@@ -816,19 +817,20 @@ class ODFStrategy(Implicit): ...@@ -816,19 +817,20 @@ class ODFStrategy(Implicit):
\n -> line-breaks \n -> line-breaks
DateTime -> Y-m-d DateTime -> Y-m-d
""" """
assert six.PY2 # TODO-py3
if value is None: if value is None:
value = '' value = ''
translated_value = str(value)
if isinstance(value, DateTime): if isinstance(value, DateTime):
translated_value = value.strftime('%Y-%m-%d') translated_value = value.strftime('%Y-%m-%d')
elif isinstance(value, bytes):
translated_value = value.decode('utf-8')
else:
translated_value = str(value)
translated_value = escape(translated_value) translated_value = escape(translated_value)
tab_element_str = '<text:tab xmlns:text="%s"/>' % TEXT_URI tab_element_str = '<text:tab xmlns:text="%s"/>' % TEXT_URI
line_break_element_str ='<text:line-break xmlns:text="%s"/>' % TEXT_URI line_break_element_str ='<text:line-break xmlns:text="%s"/>' % TEXT_URI
translated_value = translated_value.replace('\t', tab_element_str) translated_value = translated_value.replace('\t', tab_element_str)
translated_value = translated_value.replace('\r', '') translated_value = translated_value.replace('\r', '')
translated_value = translated_value.replace('\n', line_break_element_str) translated_value = translated_value.replace('\n', line_break_element_str)
translated_value = unicode(str(translated_value),'utf-8')
# create a paragraph # create a paragraph
template = '<text:p xmlns:text="%s">%s</text:p>' template = '<text:p xmlns:text="%s">%s</text:p>'
fragment_element_tree = etree.XML(template % (TEXT_URI, translated_value)) fragment_element_tree = etree.XML(template % (TEXT_URI, translated_value))
......
...@@ -44,10 +44,11 @@ from Acquisition import aq_base ...@@ -44,10 +44,11 @@ from Acquisition import aq_base
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from .OOoUtils import OOoBuilder from .OOoUtils import OOoBuilder
from zipfile import ZipFile, ZIP_DEFLATED from zipfile import ZipFile, ZIP_DEFLATED
from six.moves import cStringIO as StringIO from io import BytesIO
import re import re
import itertools import itertools
import six import six
from Products.ERP5Type.Utils import bytes2str
try: try:
from zExceptions import ResourceLockedError from zExceptions import ResourceLockedError
...@@ -226,7 +227,7 @@ class OOoTemplate(ZopePageTemplate): ...@@ -226,7 +227,7 @@ class OOoTemplate(ZopePageTemplate):
self.OLE_documents_zipstring = None self.OLE_documents_zipstring = None
# create a zip archive and store it # create a zip archive and store it
if attached_files_list: if attached_files_list:
memory_file = StringIO() memory_file = BytesIO()
try: try:
zf = ZipFile(memory_file, mode='w', compression=ZIP_DEFLATED) zf = ZipFile(memory_file, mode='w', compression=ZIP_DEFLATED)
except RuntimeError: except RuntimeError:
...@@ -439,8 +440,8 @@ class OOoTemplate(ZopePageTemplate): ...@@ -439,8 +440,8 @@ class OOoTemplate(ZopePageTemplate):
draw_object.attrib.update({'{%s}href' % xml_doc.nsmap.get('xlink'): new_path}) draw_object.attrib.update({'{%s}href' % xml_doc.nsmap.get('xlink'): new_path})
draw_object.attrib.update(dict(office_include.attrib)) draw_object.attrib.update(dict(office_include.attrib))
office_include.getparent().replace(office_include, draw_object) office_include.getparent().replace(office_include, draw_object)
text = etree.tostring(xml_doc, encoding='utf-8', xml_declaration=True, text = bytes2str(etree.tostring(xml_doc, encoding='utf-8', xml_declaration=True,
pretty_print=False) pretty_print=False))
text = re.sub('<\s*office:include_img\s+(.*?)\s*/\s*>(?s)', replaceIncludesImg, text) text = re.sub('<\s*office:include_img\s+(.*?)\s*/\s*>(?s)', replaceIncludesImg, text)
return (text, attached_files_dict) return (text, attached_files_dict)
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import newSecurityManager
from six import StringIO
class TestFormPrintoutMixin(ERP5TypeTestCase): class TestFormPrintoutMixin(ERP5TypeTestCase):
run_all_test = 1 run_all_test = 1
...@@ -55,7 +54,7 @@ class TestFormPrintoutMixin(ERP5TypeTestCase): ...@@ -55,7 +54,7 @@ class TestFormPrintoutMixin(ERP5TypeTestCase):
'''return odf document from the printout '''return odf document from the printout
''' '''
document_file = getattr(self.portal, printout_form.template, None) document_file = getattr(self.portal, printout_form.template, None)
document_file = StringIO(document_file).read() document_file = bytes(document_file)
if document_file is not None: if document_file is not None:
return document_file return document_file
raise ValueError ('%s template not found' % printout_form.template) raise ValueError ('%s template not found' % printout_form.template)
......
...@@ -41,6 +41,7 @@ import zipfile ...@@ -41,6 +41,7 @@ import zipfile
import subprocess import subprocess
from six.moves import urllib from six.moves import urllib
from six.moves import cStringIO as StringIO from six.moves import cStringIO as StringIO
from io import BytesIO
try: try:
import lxml import lxml
...@@ -65,14 +66,14 @@ if lxml: ...@@ -65,14 +66,14 @@ if lxml:
def validate(self, odf_file_content): def validate(self, odf_file_content):
error_list = [] error_list = []
odf_file = StringIO(odf_file_content) odf_file = BytesIO(odf_file_content)
for f in ('content.xml', 'meta.xml', 'styles.xml', 'settings.xml'): for f in ('content.xml', 'meta.xml', 'styles.xml', 'settings.xml'):
error_list.extend(self._validateXML(odf_file, f)) error_list.extend(self._validateXML(odf_file, f))
return error_list return error_list
def _validateXML(self, odf_file, content_file_name): def _validateXML(self, odf_file, content_file_name):
zfd = zipfile.ZipFile(odf_file) zfd = zipfile.ZipFile(odf_file)
doc = lxml.etree.parse(StringIO(zfd.read(content_file_name))) doc = lxml.etree.parse(BytesIO(zfd.read(content_file_name)))
return [] return []
# The following is the past implementation that validates with # The following is the past implementation that validates with
# RelaxNG schema. But recent LibreOffice uses extended odf # RelaxNG schema. But recent LibreOffice uses extended odf
......
...@@ -44,6 +44,12 @@ ATTRIBUTE_PREFIX = '' ...@@ -44,6 +44,12 @@ ATTRIBUTE_PREFIX = ''
def identity(value): def identity(value):
return value return value
def asData(value):
assert not isinstance(value, six.text_type)
return value
def asFloat(value): def asFloat(value):
""" """
Return the value as a float or a type-specific default value if it fails. Return the value as a float or a type-specific default value if it fails.
...@@ -101,7 +107,7 @@ def asString(value): ...@@ -101,7 +107,7 @@ def asString(value):
if six.PY2 and isinstance(value, six.text_type): if six.PY2 and isinstance(value, six.text_type):
result = value.encode('utf-8') result = value.encode('utf-8')
elif six.PY3 and isinstance(value, bytes): elif six.PY3 and isinstance(value, bytes):
result = value.decode('utf-8') result = value.decode('utf-8', 'surrogateescape')
else: else:
result = str(value) result = str(value)
except TypeError: except TypeError:
...@@ -195,8 +201,8 @@ type_definition = { ...@@ -195,8 +201,8 @@ type_definition = {
# which intention is store large data # which intention is store large data
# such as files of BLOBs. It uses pdata # such as files of BLOBs. It uses pdata
# structure. # structure.
'data' : { 'cast' : identity, 'data' : { 'cast' : asData,
'null' : ('', 'None', None,), 'null' : (b'', b'None', None,),
'default' : None, 'default' : None,
'isList' : 0, 'isList' : 0,
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment