aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharlie Denton <charlie@meshy.co.uk>2014-06-19 11:46:18 +0100
committerCharlie Denton <charlie@meshy.co.uk>2014-06-19 11:46:18 +0100
commit8e615cf00343d61e2bf3716c66888758aeb878ed (patch)
tree9f6f4ada901749eaeddb32ac75c0955a5327c2b5
parent0de693a16fa35525d3adb115bf8bf21c76581d0b (diff)
parent301bef0d6931582583a156b3195b8b13f54d2875 (diff)
downloaddjango-wkhtmltopdf-8e615cf00343d61e2bf3716c66888758aeb878ed.tar.gz
django-wkhtmltopdf-8e615cf00343d61e2bf3716c66888758aeb878ed.tar.bz2
django-wkhtmltopdf-8e615cf00343d61e2bf3716c66888758aeb878ed.zip
Merge pull request #48 from incuna/python3
Add Python3 support
-rw-r--r--.travis.yml28
-rw-r--r--CHANGELOG.md16
-rw-r--r--LICENSE2
-rw-r--r--Makefile9
-rw-r--r--README.rst9
-rwxr-xr-xbefore_script.sh12
-rwxr-xr-xrun_tests.sh6
-rw-r--r--setup.cfg2
-rw-r--r--setup.py20
-rw-r--r--test_requirements.txt1
-rw-r--r--wkhtmltopdf/__init__.py2
-rw-r--r--wkhtmltopdf/test_settings.py30
-rw-r--r--wkhtmltopdf/tests/run.py38
-rw-r--r--wkhtmltopdf/tests/test_requirements.txt1
-rw-r--r--wkhtmltopdf/tests/tests.py36
-rw-r--r--wkhtmltopdf/utils.py21
-rw-r--r--wkhtmltopdf/views.py14
17 files changed, 152 insertions, 95 deletions
diff --git a/.travis.yml b/.travis.yml
index cb3ffca..3f3dacc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,10 +2,32 @@ language: python
python:
- "2.6"
- "2.7"
-before_script:
- - "./before_script.sh"
+ - "3.3"
+ - "3.4"
+env:
+ - DJANGO="Django>=1.4,<1.5"
+ - DJANGO="Django>=1.5,<1.6"
+ - DJANGO="Django>=1.6,<1.7"
+matrix:
+ exclude:
+ - python: "3.3"
+ env: DJANGO="Django>=1.4,<1.5"
+ - python: "3.4"
+ env: DJANGO="Django>=1.4,<1.5"
+before_install:
+ - PWD=`pwd`
+ - "echo '## Installing dependencies'"
+ - "sudo apt-get update"
+ - "sudo apt-get install -y openssl build-essential xorg libssl-dev"
+ - "echo '## Downloading wkhtmltopdf 0.12.0'"
+ - "wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.0/wkhtmltox-linux-amd64_0.12.0-03c001d.tar.xz"
+ - "mkdir -p $PWD"
+ - "echo '## Extracting wkhtmltox into $PWD'"
+ - "tar xvJf wkhtmltox-linux-amd64_0.12.0-03c001d.tar.xz -C $PWD"
+ - "export WKHTMLTOPDF_CMD=$PWD/wkhtmltox/bin/wkhtmltopdf"
install:
- - pip install -r wkhtmltopdf/tests/test_requirements.txt
+ - pip install $DJANGO
+ - pip install -r test_requirements.txt
- pip install .
script:
- make test
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24f7223..780fd46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,14 +1,22 @@
Changelog for django-wkhtmltopdf
================================
+2.0.0
+-----
+
+* Support for Python 3
+* Support other Django versions
+* Use TestRunner for tests (and remove run_tests.sh)
+* Add support for Wheel packaging
+* Build the wkhtmltopdf binary in .travis.yml (and remove before_script.sh)
1.2.3
-----
-* update wkhtmltopdf binary to 0.12.0 version on before_script.sh
-* update docs to reference a wkhtmltopdf on github ( https://github.com/wkhtmltopdf/wkhtmltopdf )
-* add link to official site http://wkhtmltopdf.org/
-* move tests from Makefile to run_tests.sh
+* Update wkhtmltopdf binary to 0.12.0 version on before_script.sh
+* Update docs to reference a wkhtmltopdf on github
+* Add link to official site http://wkhtmltopdf.org/
+* Move tests from Makefile to run_tests.sh
1.2.2
diff --git a/LICENSE b/LICENSE
index fe36c19..aecebff 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012, Incuna Ltd
+Copyright (c) 2012-2014, Incuna Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Makefile b/Makefile
index 059771c..eb99a79 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,12 @@
SHELL := /bin/bash
+help:
+ @echo "Usage:"
+ @echo " make release | Release to pypi."
+ @echo " make test | Run the tests."
+
release:
- python setup.py register sdist upload
+ python setup.py register sdist bdist_wheel upload
test:
- ./run_tests.sh
+ python ./wkhtmltopdf/tests/run.py
diff --git a/README.rst b/README.rst
index 553a5da..a61a069 100644
--- a/README.rst
+++ b/README.rst
@@ -8,19 +8,20 @@ django-wkhtmltopdf
Converts html to PDF
--------------------
-Provides a thin wrapper to the wkhtmltopdf binary from https://github.com/wkhtmltopdf/wkhtmltopdf
-Get the wkhtmltopdf binaries from http://wkhtmltopdf.org/
+Provides a thin Django wrapper for the `wkhtmltopdf`_ binary.
+.. _wkhtmltopdf: http://wkhtmltopdf.org/
Requirements
------------
Install the `wkhtmltopdf`_ binary.
+
This requires libfontconfig (on Ubuntu: ``sudo aptitude install libfontconfig``).
-.. _wkhtmltopdf: http://wkhtmltopdf.org/
+.. _wkhtmltopdf: http://wkhtmltopdf.org/downloads.html
-Python 2.6
+Python 2.6+ and 3.3+ is supported.
Installation
diff --git a/before_script.sh b/before_script.sh
deleted file mode 100755
index 5c2cce8..0000000
--- a/before_script.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-WKHTMLTOX_FOLDER="`pwd`/wkhtmltox_folder"
-
-echo '## Installing dependencies'
-sudo apt-get install -y openssl build-essential xorg libssl-dev
-echo '## Downloading wkhtmltopdf 0.12.0'
-wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.0/wkhtmltox-linux-amd64_0.12.0-03c001d.tar.xz
-mkdir -p $WKHTMLTOX_FOLDER
-echo "## Extracting wkhtmltox into $WKHTMLTOX_FOLDER"
-tar xvJf wkhtmltox-linux-amd64_0.12.0-03c001d.tar.xz -C $WKHTMLTOX_FOLDER
-export WKHTMLTOPDF_CMD=$WKHTMLTOX_FOLDER/wkhtmltox/bin/wkhtmltopdf
-
diff --git a/run_tests.sh b/run_tests.sh
deleted file mode 100755
index 1cb1dd5..0000000
--- a/run_tests.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-export WKHTMLTOPDF_CMD=`pwd`/wkhtmltox_folder/wkhtmltox/bin/wkhtmltopdf;
-export PYTHONPATH=.:$$PYTHONPATH;
-
-django-admin.py test tests --settings=wkhtmltopdf.test_settings
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..2a9acf1
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal = 1
diff --git a/setup.py b/setup.py
index abc3591..876e9ef 100644
--- a/setup.py
+++ b/setup.py
@@ -8,12 +8,26 @@ setup(
packages=find_packages(),
include_package_data=True,
version=wkhtmltopdf.__version__,
- description='Converts html to PDF using http://code.google.com/p/wkhtmltopdf/.',
+ description='Converts HTML to PDF using wkhtmltopdf.',
long_description=open('README.rst').read(),
+ license='MIT',
author=wkhtmltopdf.__author__,
author_email='admin@incuna.com',
url='https://github.com/incuna/django-wkhtmltopdf',
- install_requires=['Django>=1.3'],
zip_safe=False,
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'Operating System :: OS Independent',
+ 'License :: OSI Approved :: MIT License',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Framework :: Django',
+ ],
+ keywords='django wkhtmltopdf pdf',
)
-
diff --git a/test_requirements.txt b/test_requirements.txt
new file mode 100644
index 0000000..0d4fee0
--- /dev/null
+++ b/test_requirements.txt
@@ -0,0 +1 @@
+django-discover-runner==1.0
diff --git a/wkhtmltopdf/__init__.py b/wkhtmltopdf/__init__.py
index a1663c7..537dafc 100644
--- a/wkhtmltopdf/__init__.py
+++ b/wkhtmltopdf/__init__.py
@@ -3,4 +3,4 @@ if 'DJANGO_SETTINGS_MODULE' in os.environ:
from .utils import *
__author__ = 'Incuna Ltd'
-__version__ = '1.2.3'
+__version__ = '2.0.0'
diff --git a/wkhtmltopdf/test_settings.py b/wkhtmltopdf/test_settings.py
deleted file mode 100644
index 16fb734..0000000
--- a/wkhtmltopdf/test_settings.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import os
-
-DEBUG = True
-
-DIRNAME = os.path.abspath(os.path.dirname(__file__))
-
-SECRET_KEY = 'fooooooo'
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': ':memory:',
- }
-}
-
-MEDIA_ROOT = os.path.join(DIRNAME, 'media')
-MEDIA_URL = '/media/'
-STATIC_ROOT = os.path.join(DIRNAME, 'static')
-STATIC_URL = '/static/'
-
-INSTALLED_APPS = (
- 'wkhtmltopdf.tests',
- 'wkhtmltopdf',
-)
-
-TEMPLATE_DIRS = [
- os.path.join(DIRNAME, 'testproject', 'tests', 'templates'),
-]
-
-WKHTMLTOPDF_DEBUG = DEBUG
diff --git a/wkhtmltopdf/tests/run.py b/wkhtmltopdf/tests/run.py
new file mode 100644
index 0000000..a840e68
--- /dev/null
+++ b/wkhtmltopdf/tests/run.py
@@ -0,0 +1,38 @@
+#! /usr/bin/env python
+import os
+import sys
+
+from django.conf import settings
+
+DIRNAME = os.path.abspath(os.path.dirname(__file__))
+
+
+settings.configure(
+ DEBUG=True,
+ DATABASES={
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': ':memory:',
+ }
+ },
+ INSTALLED_APPS=(
+ 'wkhtmltopdf.tests',
+ 'wkhtmltopdf',
+ ),
+ MEDIA_ROOT=os.path.join(DIRNAME, 'media'),
+ MEDIA_URL='/media/',
+ STATIC_ROOT=os.path.join(DIRNAME, 'static'),
+ STATIC_URL='/static/',
+ WKHTMLTOPDF_DEBUG=True,
+)
+
+try:
+ from django.test.runner import DiscoverRunner
+except ImportError:
+ from discover_runner.runner import DiscoverRunner
+
+
+test_runner = DiscoverRunner(verbosity=1)
+failures = test_runner.run_tests(['wkhtmltopdf'])
+if failures:
+ sys.exit(1)
diff --git a/wkhtmltopdf/tests/test_requirements.txt b/wkhtmltopdf/tests/test_requirements.txt
deleted file mode 100644
index 3999bef..0000000
--- a/wkhtmltopdf/tests/test_requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-Django==1.4.2
diff --git a/wkhtmltopdf/tests/tests.py b/wkhtmltopdf/tests/tests.py
index b007687..7365d05 100644
--- a/wkhtmltopdf/tests/tests.py
+++ b/wkhtmltopdf/tests/tests.py
@@ -8,6 +8,8 @@ import sys
from django.conf import settings
from django.test import TestCase
from django.test.client import RequestFactory
+from django.utils import six
+from django.utils.encoding import smart_str
from wkhtmltopdf.subprocess import CalledProcessError
from wkhtmltopdf.utils import (_options_to_args, make_absolute_paths,
@@ -41,15 +43,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 +65,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 +82,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 +155,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('<html>'))
self.assertTrue('<h1>{title}</h1>'.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 +181,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 +191,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)
+ title = '\0'.join(cmd_options['title'])
+ self.assertIn(six.b(title), pdf_content)
def test_pdf_template_response_to_browser(self):
self.test_pdf_template_response(show_content=True)
@@ -214,8 +216,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 +225,7 @@ class TestViews(TestCase):
self.assertEqual(response.status_code, 200)
response.render()
self.assertFalse(response.has_header('Content-Disposition'))
- self.assertTrue(response.content.startswith('<html>'))
+ self.assertTrue(response.content.startswith(b'<html>'))
# POST
request = RequestFactory().post('/')
@@ -254,8 +256,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..e34085d 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.request import pathname2url
+ from urllib.parse import urljoin
+except ImportError: # Python2
+ from urllib import pathname2url
+ from urlparse 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..2f1945d 100644
--- a/wkhtmltopdf/views.py
+++ b/wkhtmltopdf/views.py
@@ -77,12 +77,18 @@ class PDFTemplateResponse(TemplateResponse, PDFResponse):
content = smart_str(template.render(context))
content = make_absolute_paths(content)
- tempfile = NamedTemporaryFile(mode=mode, bufsize=bufsize,
- suffix=suffix, prefix=prefix,
- dir=dir, delete=delete)
+ try:
+ # Python3 has 'buffering' arg instead of 'bufsize'
+ tempfile = NamedTemporaryFile(mode=mode, buffering=bufsize,
+ suffix=suffix, prefix=prefix,
+ dir=dir, delete=delete)
+ except TypeError:
+ tempfile = NamedTemporaryFile(mode=mode, bufsize=bufsize,
+ suffix=suffix, prefix=prefix,
+ dir=dir, delete=delete)
try:
- tempfile.write(content)
+ tempfile.write(content.encode('utf-8'))
tempfile.flush()
return tempfile
except: