Skip to content

Commit ef7650f

Browse files
committed
Accept binary file-like input without encoding bytes again
1 parent fb86d33 commit ef7650f

3 files changed

Lines changed: 44 additions & 1 deletion

File tree

‎README.rst‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ Also you can pass an opened file:
7171
with open('file.html') as f:
7272
pdfkit.from_file(f, 'out.pdf')
7373
74+
Text streams are encoded as UTF-8. Binary streams (including ``io.BytesIO``
75+
and files opened with ``'rb'``) are passed through without changing their bytes.
76+
The caller retains ownership of the input stream.
77+
78+
7479
If you wish to further process generated PDF, you can read it to a variable:
7580

7681
.. code-block:: python

‎pdfkit/pdfkit.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ def to_pdf(self, path=None):
183183
if self.source.isString() or (self.source.isFile() and self.css):
184184
input = self.source.to_s().encode('utf-8')
185185
elif self.source.isFileObj():
186-
input = self.source.source.read().encode('utf-8')
186+
input = self.source.source.read()
187+
if isinstance(input, str):
188+
input = input.encode('utf-8')
187189
else:
188190
input = None
189191

‎tests/test_file_stream_input.py‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import io
2+
import sys
3+
import tempfile
4+
import unittest
5+
from unittest.mock import Mock, patch
6+
7+
import pdfkit
8+
9+
10+
class FileStreamInputTests(unittest.TestCase):
11+
def convert(self, stream, expected):
12+
config = pdfkit.configuration(wkhtmltopdf=sys.executable)
13+
process = Mock(returncode=0)
14+
process.communicate.return_value = (b'%PDF-test-output', b'')
15+
with patch('pdfkit.pdfkit.subprocess.Popen', return_value=process):
16+
output = pdfkit.from_file(stream, configuration=config)
17+
self.assertEqual(output, b'%PDF-test-output')
18+
process.communicate.assert_called_once_with(input=expected)
19+
self.assertFalse(stream.closed)
20+
21+
def test_binary_memory_stream(self):
22+
data = '<p>café</p>'.encode('utf-8')
23+
self.convert(io.BytesIO(data), data)
24+
25+
def test_binary_file_preserves_declared_encoding(self):
26+
data = b'<meta charset="iso-8859-1"><p>caf\xe9</p>'
27+
with tempfile.TemporaryFile('w+b') as stream:
28+
stream.write(data)
29+
stream.seek(0)
30+
self.convert(stream, data)
31+
32+
def test_text_stream_is_encoded_as_utf8(self):
33+
self.convert(io.StringIO('<p>café</p>'), '<p>café</p>'.encode('utf-8'))
34+
35+
def test_empty_binary_stream(self):
36+
self.convert(io.BytesIO(b''), b'')

0 commit comments

Comments
 (0)