is your OpenShift token, not your Gihub token!
+
+
+# Local Usage
+
+Run the docker image, exposing port 5005 (because 5001 doesn't work on a Mac)
+
+```
+docker run -d -p 5005:5001 edivorce/weasyprint
+```
+
+A `POST` to port `/pdf` on port 5001 with an html body with give a response containing a PDF. The filename may be set using a query parameter, e.g.:
+
+```
+curl -X POST -d @source.html http://127.0.0.1:5005/pdf?filename=result.pdf
+```
+
+This will use the file `source.html` and return a response with `Content-Type: application/pdf` and `Content-Disposition: inline; filename=result.pdf` headers. The body of the response will be the PDF.
+
+In addition `/health` is a health check endpoint and a `GET` returns 'ok'.
diff --git a/docker-weasyprint/requirements.txt b/docker-weasyprint/requirements.txt
new file mode 100644
index 00000000..4d184ade
--- /dev/null
+++ b/docker-weasyprint/requirements.txt
@@ -0,0 +1,3 @@
+gunicorn==19.4
+WeasyPrint==0.31
+flask==0.10
diff --git a/docker-weasyprint/test.html b/docker-weasyprint/test.html
new file mode 100644
index 00000000..2a0e5359
--- /dev/null
+++ b/docker-weasyprint/test.html
@@ -0,0 +1,9 @@
+
+
+
+ Test File
+
+
+ Hello World
+
+
\ No newline at end of file
diff --git a/docker-weasyprint/test.py b/docker-weasyprint/test.py
new file mode 100644
index 00000000..2e3b1f99
--- /dev/null
+++ b/docker-weasyprint/test.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3.5
+
+import json
+import re
+import subprocess
+import unittest
+from urllib.request import Request, urlopen
+
+html_data = '''
+
+
+
+ Test File
+
+
+ Hello World
+
+
+'''
+
+
+def request_factory(path='/'):
+ url = 'http://127.0.0.1:5001%s' % path
+ headers = {
+ 'Content-Type': 'application/html'
+ }
+ return Request(url, data=html_data.encode('utf-8'), headers=headers, method='POST')
+
+
+class TestPdf(unittest.TestCase):
+
+ def setUp(self):
+ request = request_factory('/pdf?filename=sample.pdf')
+ self.response = urlopen(request)
+
+ def tearDown(self):
+ self.response.close()
+
+ def test_response_code(self):
+ self.assertEqual(self.response.getcode(), 200)
+
+ def test_headers(self):
+ headers = dict(self.response.info())
+ self.assertEqual(headers['Content-Type'], 'application/pdf')
+ self.assertEqual(headers['Content-Disposition'], 'inline;filename=sample.pdf')
+
+ def test_body(self):
+ self.assertEqual(self.response.read()[:4], b'%PDF')
+
+
+class TestMultiple(unittest.TestCase):
+
+ def setUp(self):
+ url = 'http://127.0.0.1:5001/multiple?filename=sample.pdf'
+ headers = {
+ 'Content-Type': 'application/json'
+ }
+ data = json.dumps([html_data, html_data]).encode('utf-8')
+ request = Request(url, data=data, headers=headers, method='POST')
+ self.response = urlopen(request)
+
+ def tearDown(self):
+ self.response.close()
+
+ def test_response_code(self):
+ self.assertEqual(self.response.getcode(), 200)
+
+ def test_headers(self):
+ headers = dict(self.response.info())
+ self.assertEqual(headers['Content-Type'], 'application/pdf')
+ self.assertEqual(headers['Content-Disposition'], 'inline;filename=sample.pdf')
+
+ def test_body(self):
+ data = self.response.read()
+ pages = re.findall(rb'<<\s+/Type\s+/Page\b', data, re.MULTILINE|re.DOTALL)
+ self.assertEqual(len(pages), 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/docker-weasyprint/wsgi.py b/docker-weasyprint/wsgi.py
new file mode 100644
index 00000000..cc2d0e4a
--- /dev/null
+++ b/docker-weasyprint/wsgi.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+import json
+import logging
+
+from flask import Flask, request, make_response
+from weasyprint import HTML
+
+app = Flask('pdf')
+
+@app.route('/health')
+def index():
+ return 'ok'
+
+
+@app.before_first_request
+def setup_logging():
+ logging.addLevelName(logging.DEBUG, "\033[1;36m%s\033[1;0m" % logging.getLevelName(logging.DEBUG))
+ logging.addLevelName(logging.INFO, "\033[1;32m%s\033[1;0m" % logging.getLevelName(logging.INFO))
+ logging.addLevelName(logging.WARNING, "\033[1;33m%s\033[1;0m" % logging.getLevelName(logging.WARNING))
+ logging.addLevelName(logging.ERROR, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.ERROR))
+
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter(
+ '%(asctime)s %(levelname)s: %(message)s '
+ '[in %(pathname)s:%(lineno)d]'
+ ))
+ app.logger.addHandler(handler)
+ app.logger.setLevel(logging.DEBUG)
+
+
+@app.route('/')
+def home():
+ return '''
+ PDF Generator
+ The following endpoints are available:
+
+ - POST to
/pdf?filename=myfile.pdf. The body should
+ contain html
+ - POST to
/multiple?filename=myfile.pdf. The body
+ should contain a JSON list of html strings. They will each
+ be rendered and combined into a single pdf
+
+ '''
+
+
+@app.route('/pdf', methods=['POST'])
+def generate():
+ name = request.args.get('filename', 'unnamed.pdf')
+ app.logger.info('POST /pdf?filename=%s' % name)
+ html = HTML(string=request.data)
+ pdf = html.write_pdf()
+ response = make_response(pdf)
+ response.headers['Content-Type'] = 'application/pdf'
+ response.headers['Content-Disposition'] = 'inline;filename=%s' % name
+ app.logger.info(' ==> POST /pdf?filename=%s ok' % name)
+ return response
+
+
+@app.route('/multiple', methods=['POST'])
+def multiple():
+ name = request.args.get('filename', 'unnamed.pdf')
+ app.logger.info('POST /multiple?filename=%s' % name)
+ htmls = json.loads(request.data.decode('utf-8'))
+ documents = [HTML(string=html).render() for html in htmls]
+ pdf = documents[0].copy([page for doc in documents for page in doc.pages]).write_pdf()
+ response = make_response(pdf)
+ response.headers['Content-Type'] = 'application/pdf'
+ response.headers['Content-Disposition'] = 'inline;filename=%s' % name
+ app.logger.info(' ==> POST /multiple?filename=%s ok' % name)
+ return response
+
+
+if __name__ == '__main__':
+ app.run()