Permalink
Browse files

Allow reading of stdin with non-UTF-8 characters in Python 3

Fixes #67
  • Loading branch information...
SmileyChris committed Apr 30, 2015
1 parent 97635ec commit 97be1b444ac5522b6eef7c9b8e9bcc66f6cb616a
Showing with 31 additions and 10 deletions.
  1. +10 −6 qrcode/console_scripts.py
  2. +21 −4 qrcode/tests/test_script.py
View
@@ -60,7 +60,10 @@ def main(args=sys.argv[1:]):
if args:
data = args[0]
else:
- data = sys.stdin.read()
+ # Use sys.stdin.buffer if available (Python 3) avoiding
+ # UnicodeDecodeErrors.
+ stdin_buffer = getattr(sys.stdin, 'buffer', sys.stdin)
+ data = stdin_buffer.read()
if opts.optimize is None:
qr.add_data(data)
else:
@@ -73,15 +76,16 @@ def main(args=sys.argv[1:]):
img = qr.make_image(image_factory=image_factory)
sys.stdout.flush()
- if sys.version_info[0] >= 3:
- buff = sys.stdout.buffer
- else:
+ # Use sys.stdout.buffer if available (Python 3), avoiding
+ # UnicodeDecodeErrors.
+ stdout_buffer = getattr(sys.stdout, 'buffer', None)
+ if not stdout_buffer:
if sys.platform == 'win32': # pragma: no cover
import msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
- buff = sys.stdout
+ stdout_buffer = sys.stdout
- img.save(buff)
+ img.save(stdout_buffer)
if __name__ == "__main__":
@@ -1,3 +1,4 @@
+import sys
try:
import unittest2 as unittest
except ImportError:
@@ -10,6 +11,10 @@
from qrcode.console_scripts import main
+def bad_read():
+ raise UnicodeDecodeError('utf-8', b'0x80', 0, 1, 'invalid start byte')
+
+
class ScriptTest(unittest.TestCase):
@mock.patch('os.isatty', lambda *args: True)
@@ -26,11 +31,23 @@ def test_piped(self, mock_stdout):
@mock.patch('os.isatty', lambda *args: True)
@mock.patch('qrcode.main.QRCode.print_ascii')
def test_stdin(self, mock_print_ascii):
- mock_stdin = mock.Mock()
- mock_stdin.configure_mock(**{'read.return_value': 'testtext'})
- with mock.patch('sys.stdin', mock_stdin) as stdin:
+ mock_stdin = mock.Mock(sys.stdin)
+ stdin_buffer = getattr(mock_stdin, 'buffer', mock_stdin)
+ stdin_buffer.read.return_value = 'testtext'
+ with mock.patch('sys.stdin', mock_stdin):
+ main([])
+ self.assertTrue(stdin_buffer.read.called)
+ mock_print_ascii.assert_called_with(tty=True)
+
+ @unittest.skipIf(sys.version_info[0] < 3, 'Python 3')
+ @mock.patch('os.isatty', lambda *args: True)
+ @mock.patch('qrcode.main.QRCode.print_ascii')
+ def test_stdin_py3_unicodedecodeerror(self, mock_print_ascii):
+ mock_stdin = mock.Mock(sys.stdin)
+ mock_stdin.buffer.read.return_value = 'testtext'
+ mock_stdin.read.side_effect = bad_read
+ with mock.patch('sys.stdin', mock_stdin):
main([])
- self.assertTrue(stdin.read.called)
mock_print_ascii.assert_called_with(tty=True)
@mock.patch('os.isatty', lambda *args: True)

0 comments on commit 97be1b4

Please sign in to comment.