diff --git a/README.rst b/README.rst index 2822f0c..9444856 100644 --- a/README.rst +++ b/README.rst @@ -71,6 +71,11 @@ Also you can pass an opened file: with open('file.html') as f: pdfkit.from_file(f, 'out.pdf') +Text streams are encoded as UTF-8. Binary streams (including ``io.BytesIO`` +and files opened with ``'rb'``) are passed through without changing their bytes. +The caller retains ownership of the input stream. + + If you wish to further process generated PDF, you can read it to a variable: .. code-block:: python diff --git a/pdfkit/pdfkit.py b/pdfkit/pdfkit.py index 88b3c92..7ebe4eb 100644 --- a/pdfkit/pdfkit.py +++ b/pdfkit/pdfkit.py @@ -183,7 +183,9 @@ def to_pdf(self, path=None): if self.source.isString() or (self.source.isFile() and self.css): input = self.source.to_s().encode('utf-8') elif self.source.isFileObj(): - input = self.source.source.read().encode('utf-8') + input = self.source.source.read() + if isinstance(input, str): + input = input.encode('utf-8') else: input = None diff --git a/tests/test_file_stream_input.py b/tests/test_file_stream_input.py new file mode 100644 index 0000000..e9856ce --- /dev/null +++ b/tests/test_file_stream_input.py @@ -0,0 +1,36 @@ +import io +import sys +import tempfile +import unittest +from unittest.mock import Mock, patch + +import pdfkit + + +class FileStreamInputTests(unittest.TestCase): + def convert(self, stream, expected): + config = pdfkit.configuration(wkhtmltopdf=sys.executable) + process = Mock(returncode=0) + process.communicate.return_value = (b'%PDF-test-output', b'') + with patch('pdfkit.pdfkit.subprocess.Popen', return_value=process): + output = pdfkit.from_file(stream, configuration=config) + self.assertEqual(output, b'%PDF-test-output') + process.communicate.assert_called_once_with(input=expected) + self.assertFalse(stream.closed) + + def test_binary_memory_stream(self): + data = '

café

'.encode('utf-8') + self.convert(io.BytesIO(data), data) + + def test_binary_file_preserves_declared_encoding(self): + data = b'

caf\xe9

' + with tempfile.TemporaryFile('w+b') as stream: + stream.write(data) + stream.seek(0) + self.convert(stream, data) + + def test_text_stream_is_encoded_as_utf8(self): + self.convert(io.StringIO('

café

'), '

café

'.encode('utf-8')) + + def test_empty_binary_stream(self): + self.convert(io.BytesIO(b''), b'')