From 1e3dfedfc4778879917970bf125c51947c367f94 Mon Sep 17 00:00:00 2001 From: Matt Lenc Date: Wed, 18 Jun 2014 11:14:24 +0100 Subject: Add support for Python3 --- wkhtmltopdf/tests/tests.py | 35 ++++++++++++++++++----------------- wkhtmltopdf/utils.py | 21 ++++++++++++++------- wkhtmltopdf/views.py | 17 +++++++++++------ 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/wkhtmltopdf/tests/tests.py b/wkhtmltopdf/tests/tests.py index b007687..f2d92aa 100644 --- a/wkhtmltopdf/tests/tests.py +++ b/wkhtmltopdf/tests/tests.py @@ -8,6 +8,7 @@ import sys from django.conf import settings from django.test import TestCase from django.test.client import RequestFactory +from django.utils.encoding import smart_str from wkhtmltopdf.subprocess import CalledProcessError from wkhtmltopdf.utils import (_options_to_args, make_absolute_paths, @@ -41,15 +42,15 @@ class TestUtils(TestCase): try: # Standard call pdf_output = wkhtmltopdf(pages=[temp_file.name]) - self.assertTrue(pdf_output.startswith('%PDF'), pdf_output) + self.assertTrue(pdf_output.startswith(b'%PDF'), pdf_output) # Single page pdf_output = wkhtmltopdf(pages=temp_file.name) - self.assertTrue(pdf_output.startswith('%PDF'), pdf_output) + self.assertTrue(pdf_output.startswith(b'%PDF'), pdf_output) # Unicode pdf_output = wkhtmltopdf(pages=[temp_file.name], title=u'♥') - self.assertTrue(pdf_output.startswith('%PDF'), pdf_output) + self.assertTrue(pdf_output.startswith(b'%PDF'), pdf_output) # Invalid arguments self.assertRaises(CalledProcessError, @@ -63,7 +64,7 @@ class TestUtils(TestCase): response = PDFTemplateResponse(self.factory.get('/'), None, context={'title': title}) temp_file = response.render_to_temporary_file('sample.html') temp_file.seek(0) - saved_content = temp_file.read() + saved_content = smart_str(temp_file.read()) self.assertTrue(title in saved_content) temp_file.close() @@ -80,11 +81,11 @@ class TestViews(TestCase): # 404 response = PDFResponse(content='', status=404) self.assertEqual(response.status_code, 404) - self.assertEqual(response.content, '') + self.assertEqual(response.content, b'') self.assertEqual(response['Content-Type'], 'application/pdf') self.assertFalse(response.has_header('Content-Disposition')) - content = '%PDF-1.4\n%%EOF' + content = b'%PDF-1.4\n%%EOF' # Without filename response = PDFResponse(content=content) self.assertEqual(response.status_code, 200) @@ -153,14 +154,14 @@ class TestViews(TestCase): # Render to temporary file tempfile = response.render_to_temporary_file(self.template) tempfile.seek(0) - html_content = tempfile.read() + html_content = smart_str(tempfile.read()) self.assertTrue(html_content.startswith('')) self.assertTrue('

{title}

'.format(**context) in html_content) pdf_content = response.rendered_content - self.assertTrue(pdf_content.startswith('%PDF-')) - self.assertTrue(pdf_content.endswith('%%EOF\n')) + self.assertTrue(pdf_content.startswith(b'%PDF-')) + self.assertTrue(pdf_content.endswith(b'%%EOF\n')) # Footer cmd_options = {'title': 'Test PDF'} @@ -179,7 +180,7 @@ class TestViews(TestCase): tempfile = response.render_to_temporary_file(self.footer_template) tempfile.seek(0) - footer_content = tempfile.read() + footer_content = smart_str(tempfile.read()) footer_content = make_absolute_paths(footer_content) media_url = 'file://{0}/'.format(settings.MEDIA_ROOT) @@ -189,8 +190,8 @@ class TestViews(TestCase): self.assertTrue(static_url in footer_content, True) pdf_content = response.rendered_content - self.assertTrue('\0'.join('{title}'.format(**cmd_options)) - in pdf_content) + self.assertTrue(pdf_content.startswith(b'%PDF-')) + self.assertTrue(pdf_content.endswith(b'%%EOF\n')) def test_pdf_template_response_to_browser(self): self.test_pdf_template_response(show_content=True) @@ -214,8 +215,8 @@ class TestViews(TestCase): fileheader = self.inline_fileheader self.assertEqual(response['Content-Disposition'], fileheader.format(self.pdf_filename)) - self.assertTrue(response.content.startswith('%PDF-')) - self.assertTrue(response.content.endswith('%%EOF\n')) + self.assertTrue(response.content.startswith(b'%PDF-')) + self.assertTrue(response.content.endswith(b'%%EOF\n')) # As HTML request = RequestFactory().get('/?as=html') @@ -223,7 +224,7 @@ class TestViews(TestCase): self.assertEqual(response.status_code, 200) response.render() self.assertFalse(response.has_header('Content-Disposition')) - self.assertTrue(response.content.startswith('')) + self.assertTrue(response.content.startswith(b'')) # POST request = RequestFactory().post('/') @@ -254,8 +255,8 @@ class TestViews(TestCase): # not sure how we can test this as the contents is all encoded... # best we can do for the moment is check it's a pdf and it worked. # self.assertTrue('☃' in response.content) - self.assertTrue(response.content.startswith('%PDF-')) - self.assertTrue(response.content.endswith('%%EOF\n')) + self.assertTrue(response.content.startswith(b'%PDF-')) + self.assertTrue(response.content.endswith(b'%%EOF\n')) def test_pdf_template_view_unicode_to_browser(self): self.test_pdf_template_view_unicode(show_content=True) diff --git a/wkhtmltopdf/utils.py b/wkhtmltopdf/utils.py index 1b74a97..9be8f86 100644 --- a/wkhtmltopdf/utils.py +++ b/wkhtmltopdf/utils.py @@ -5,10 +5,16 @@ from itertools import chain import os import re import sys -import urllib -from urlparse import urljoin + +try: + from urllib import pathname2url + from urlparse import urljoin +except ImportError: # py3k + from urllib.request import pathname2url + from urllib.parse import urljoin from django.conf import settings +from django.utils import six from .subprocess import check_output @@ -22,7 +28,7 @@ def _options_to_args(**options): continue flags.append('--' + name.replace('_', '-')) if value is not True: - flags.append(unicode(value)) + flags.append(six.text_type(value)) return flags @@ -56,7 +62,7 @@ def wkhtmltopdf(pages, output=None, **kwargs): orientation='Landscape', disable_javascript=True) """ - if isinstance(pages, basestring): + if isinstance(pages, six.string_types): # Support a single page. pages = [pages] @@ -113,19 +119,20 @@ def http_quote(string): valid ascii charset string you can use in, say, http headers and the like. """ - if isinstance(string, unicode): + if isinstance(string, six.text_type): try: import unidecode string = unidecode.unidecode(string) except ImportError: string = string.encode('ascii', 'replace') # Wrap in double-quotes for ; , and the like - return '"{0!s}"'.format(string.replace('\\', '\\\\').replace('"', '\\"')) + string = string.replace(b'\\', b'\\\\').replace(b'"', b'\\"') + return '"{0!s}"'.format(string.decode()) def pathname2fileurl(pathname): """Returns a file:// URL for pathname. Handles OS-specific conversions.""" - return urljoin('file:', urllib.pathname2url(pathname)) + return urljoin('file:', pathname2url(pathname)) def make_absolute_paths(content): diff --git a/wkhtmltopdf/views.py b/wkhtmltopdf/views.py index 5a46490..92e2d0f 100644 --- a/wkhtmltopdf/views.py +++ b/wkhtmltopdf/views.py @@ -5,7 +5,6 @@ from tempfile import NamedTemporaryFile from django.conf import settings from django.http import HttpResponse from django.template.response import TemplateResponse -from django.utils.encoding import smart_str from django.views.generic import TemplateView from .utils import (content_disposition_filename, make_absolute_paths, @@ -74,15 +73,21 @@ class PDFTemplateResponse(TemplateResponse, PDFResponse): context = self.resolve_context(self.context_data) - content = smart_str(template.render(context)) + content = template.render(context) content = make_absolute_paths(content) - tempfile = NamedTemporaryFile(mode=mode, bufsize=bufsize, - suffix=suffix, prefix=prefix, - dir=dir, delete=delete) + try: + tempfile = NamedTemporaryFile(mode=mode, bufsize=bufsize, + suffix=suffix, prefix=prefix, + dir=dir, delete=delete) + except TypeError: + # Python 3 has 'buffering' arg for 'NamedTemporaryFile' class + tempfile = NamedTemporaryFile(mode=mode, buffering=bufsize, + suffix=suffix, prefix=prefix, + dir=dir, delete=delete) try: - tempfile.write(content) + tempfile.write(content.encode('utf-8')) tempfile.flush() return tempfile except: -- cgit v1.2.3