Skip to content

Commit

Permalink
Merge pull request #31 from Kozea/new-flask
Browse files Browse the repository at this point in the history
Support recent Flask, WeasyPrint and Python versions
  • Loading branch information
liZe authored Oct 3, 2023
2 parents 0280f34 + b3428d1 commit e88b37f
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 43 deletions.
38 changes: 19 additions & 19 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,39 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.8']
exclude:
# Wheels missing for this configuration
- os: macos-latest
python-version: pypy-3.8
python-version: ['3.12']
include:
- os: ubuntu-latest
python-version: '3.8'
- os: ubuntu-latest
python-version: 'pypy-3.8'
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install DejaVu and Ghostscript (Ubuntu)
- name: Install Ghostscript (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get update -y && sudo apt-get install fonts-dejavu ghostscript -y
- name: Install DejaVu, Pango and Ghostscript (MacOS)
run: sudo apt-get update -y && sudo apt-get install ghostscript -y
- name: Install Pango and Ghostscript (MacOS)
if: matrix.os == 'macos-latest'
run: |
rm /usr/local/bin/2to3
brew update
brew tap homebrew/cask-fonts
brew install --cask font-dejavu
brew install pango ghostscript
- name: Install DejaVu, Pango and Ghostscript (Windows)
- name: Install Pango and Ghostscript (Windows)
if: matrix.os == 'windows-latest'
run: |
C:\msys64\usr\bin\bash -lc 'pacman -S mingw-w64-x86_64-ttf-dejavu mingw-w64-x86_64-pango mingw-w64-x86_64-ghostscript mingw-w64-x86_64-wget --noconfirm'
C:\msys64\usr\bin\bash -lc 'wget https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-harfbuzz-4.3.0-1-any.pkg.tar.zst'
C:\msys64\usr\bin\bash -lc 'pacman -U --noconfirm mingw-w64-x86_64-harfbuzz-4.3.0-1-any.pkg.tar.zst'
xcopy "C:\msys64\mingw64\share\fonts\TTF" "C:\Users\runneradmin\.fonts" /e /i
C:\msys64\usr\bin\bash -lc 'pacman -S mingw-w64-x86_64-pango mingw-w64-x86_64-ghostscript --noconfirm'
echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH
rm C:\msys64\mingw64\bin\python.exe
- name: Upgrade pip and setuptools
run: python -m pip install --upgrade pip setuptools
- name: Install tests’ requirements
run: python -m pip install .[test]
run: python -m pip install .[test] pytest-xdist
- name: Launch tests
run: python -m pytest
run: python -m pytest -n auto
- name: Check coding style
run: python -m flake8
- name: Check imports order
run: python -m isort . --check --diff
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Flask-WeasyPrint generates PDF files out of your Flask website thanks to
WeasyPrint.

* Free software: BSD license
* For Python 3.7+, tested on CPython and PyPy
* For Python 3.8+, tested on CPython and PyPy
* Documentation: https://doc.courtbouillon.org/flask-weasyprint
* Changelog: https://github.com/Kozea/Flask-WeasyPrint/releases
* Code, issues, tests: https://github.com/Kozea/Flask-WeasyPrint
Expand Down
13 changes: 8 additions & 5 deletions flask_weasyprint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def accept(url):

def dispatch(url_string):
if isinstance(url_string, bytes):
url_string = url_string.decode('utf8')
url_string = url_string.decode()
url = urlsplit(url_string)
url_port = url.port
if (url.scheme, url_port) in DEFAULT_PORTS:
Expand Down Expand Up @@ -107,12 +107,13 @@ def flask_url_fetcher(url):
server_name = EnvironBuilder(
path, base_url=base_url).server_name
for cookie_key, cookie_value in request.cookies.items():
client.set_cookie(server_name, cookie_key, cookie_value)
client.set_cookie(
cookie_key, cookie_value, domain=server_name)
response = client.get(path, base_url=base_url)
if response.status_code == 200:
return {
'string': response.data, 'mime_type': response.mimetype,
'encoding': response.charset, 'redirected_url': url}
'encoding': 'utf-8', 'redirected_url': url}
# The test client can follow redirects, but do it ourselves
# to get access to the redirected URL.
elif response.status_code in (301, 302, 303, 305, 307, 308):
Expand Down Expand Up @@ -167,7 +168,7 @@ def CSS(*args, **kwargs):


def render_pdf(html, stylesheets=None, download_filename=None,
automatic_download=True):
automatic_download=True, **options):
"""Render a PDF to a response with the correct ``Content-Type`` header.
:param html:
Expand All @@ -181,14 +182,16 @@ def render_pdf(html, stylesheets=None, download_filename=None,
If provided, the ``Content-Disposition`` header is set so that most
web browser will show the "Save as…" dialog with the value as the
default filename.
:param **options:
Named properties given to :class:`weasyprint.HTML.write_pdf`.
:param bool automatic_download:
If :obj:`True`, the browser will automatic download file.
:returns: a :class:`flask.Response` object.
"""
if not hasattr(html, 'write_pdf'):
html = HTML(html)
pdf = html.write_pdf(stylesheets=stylesheets)
pdf = html.write_pdf(stylesheets=stylesheets, **options)
response = current_app.response_class(pdf, mimetype='application/pdf')
if download_filename:
response.headers.add(
Expand Down
13 changes: 5 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ requires-python = '>=3.7'
readme = {file = 'README.rst', content-type = 'text/x-rst'}
license = {file = 'LICENSE'}
dependencies = [
'flask >=2.0.0',
'weasyprint >=43.0',
'flask >=2.3.0',
'weasyprint >=53.0',
]
classifiers = [
'Development Status :: 5 - Production/Stable',
Expand All @@ -24,10 +24,11 @@ classifiers = [
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
Expand All @@ -45,15 +46,11 @@ Donation = 'https://opencollective.com/courtbouillon'

[project.optional-dependencies]
doc = ['sphinx', 'sphinx_rtd_theme']
# TODO: remove the flake8 dependency when https://github.com/tholo/pytest-flake8/issues/87 is fixed
test = ['pytest', 'pytest-xdist', 'pytest-flake8', 'pytest-isort', 'pytest-cov', 'coverage[toml]', 'flake8 <5']
test = ['pytest', 'isort', 'flake8']

[tool.flit.sdist]
exclude = ['.*']

[tool.pytest.ini_options]
addopts = '--isort --flake8 --numprocesses=auto'

[tool.coverage.run]
branch = true
include = ['tests/*', 'flask_weasyprint/*']
Expand Down
6 changes: 5 additions & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Demonstration and testing application for Flask-WeasyPrint."""

from flask import Flask, abort, redirect, render_template, request, url_for
from weasyprint import __version__ as weasyprint_version

# Disable the Flask’s default static file handling. (See below.)
app = Flask(__name__, static_folder=None)
Expand Down Expand Up @@ -48,7 +49,10 @@ def graph():

@app.route('/foo.pdf')
def document_pdf():
return render_pdf(url_for('index'))
if int(weasyprint_version.split('.')[0]) >= 59:
return render_pdf(url_for('index'), uncompressed_pdf=True)
else:
return render_pdf(url_for('index'))

# End of code specific to Flask-WeasyPrint.

Expand Down
22 changes: 13 additions & 9 deletions tests/test_flask_weasyprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from flask import Flask, json, jsonify, redirect, request
from flask_weasyprint import CSS, HTML, make_url_fetcher, render_pdf
from weasyprint import __version__ as weasyprint_version
from werkzeug.test import ClientRedirectError

from . import app, document_html
Expand Down Expand Up @@ -57,19 +58,22 @@ def test_pdf(url, filename, automatic, cookie):
if url.endswith('.pdf'):
client = app.test_client()
if cookie:
client.set_cookie('', 'cookie', cookie)
client.set_cookie('cookie', cookie)
response = client.get('/foo.pdf')
else:
with app.test_request_context('/foo/'):
response = render_pdf(
HTML(string=document_html()),
download_filename=filename,
automatic_download=automatic)
options = {
'download_filename': filename,
'automatic_download': automatic,
}
if int(weasyprint_version.split('.')[0]) >= 59:
options['uncompressed_pdf'] = True
response = render_pdf(HTML(string=document_html()), **options)
assert response.status_code == 200
assert response.mimetype == 'application/pdf'
assert response.data.startswith(b'%PDF')
if cookie:
assert cookie.encode('utf8') in response.data
assert cookie.encode() in response.data
assert b'/URI (https://courtbouillon.org/)' in response.data
disposition = response.headers.get('Content-Disposition')
if filename:
Expand Down Expand Up @@ -115,7 +119,7 @@ def test_dispatcher():
@app.route('/<path:path>')
@app.route('/<path:path>', subdomain='<subdomain>')
def catchall(subdomain='', path=None):
query_string = request.query_string.decode('utf8')
query_string = request.query_string.decode()
app = [subdomain, request.script_root, request.path, query_string]
return jsonify(app=app)

Expand Down Expand Up @@ -202,11 +206,11 @@ def assert_dummy(url):

@pytest.mark.parametrize('url', (
'http://example.net/Unïĉodé/pass !',
'http://example.net/Unïĉodé/pass !'.encode('utf8'),
'http://example.net/Unïĉodé/pass !'.encode(),
'http://example.net/foo%20bar/p%61ss%C2%A0!',
b'http://example.net/foo%20bar/p%61ss%C2%A0!',
))
def test_funky_urls(url):
with app.test_request_context(base_url='http://example.net/'):
fetcher = make_url_fetcher()
assert fetcher(url)['string'] == 'pass !'.encode('utf8')
assert fetcher(url)['string'] == 'pass !'.encode()

0 comments on commit e88b37f

Please sign in to comment.