Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jupyter notebook fix #1443

Merged
merged 3 commits into from
Sep 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mrjob/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,4 @@
'Andrea Zonca <andrea.zonca@gmail.com>',
]

__version__ = '0.5.6'
__version__ = '0.5.7.dev0'
19 changes: 9 additions & 10 deletions mrjob/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
from mrjob.options import _alphabetize_options
from mrjob.options import _fix_custom_options
from mrjob.options import _print_help_for_groups
from mrjob.py2 import PY2
from mrjob.step import StepFailedException
from mrjob.util import log_to_null
from mrjob.util import log_to_stream
Expand Down Expand Up @@ -118,15 +117,15 @@ def error(msg):
# Make it possible to redirect stdin, stdout, and stderr, for testing
# See sandbox(), below.
#
# These should always read/write bytes, not unicode
if PY2:
self.stdin = sys.stdin
self.stdout = sys.stdout
self.stderr = sys.stderr
else:
self.stdin = sys.stdin.buffer
self.stdout = sys.stdout.buffer
self.stderr = sys.stderr.buffer
# These should always read/write bytes, not unicode. Generally,
# on Python 2, sys.std* can read and write bytes, whereas on Python 3,
# you need to use sys.std*.buffer (which doesn't exist on Python 2).
#
# However, certain Python 3 environments, such as Jupyter notebook,
# act more like Python 2. See #1441.
self.stdin = getattr(sys.stdin, 'buffer', sys.stdin)
self.stdout = getattr(sys.stdout, 'buffer', sys.stdout)
self.stderr = getattr(sys.stderr, 'buffer', sys.stderr)

@classmethod
def _usage(cls):
Expand Down
37 changes: 37 additions & 0 deletions tests/test_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from mrjob.conf import combine_envs
from mrjob.job import MRJob
from mrjob.launch import MRJobLauncher
from mrjob.py2 import PY2
from mrjob.py2 import StringIO
from mrjob.step import StepFailedException

Expand Down Expand Up @@ -352,3 +353,39 @@ def test_pass_through(self):
self.assertEqual(self.get_value(MRRunner()), None)
self.assertEqual(self.get_value(MRRunner(['-r', 'inline'])), 'inline')
self.assertEqual(self.get_value(MRRunner(['-r', 'local'])), 'local')


class StdStreamTestCase(TestCase):

def test_normal_python(self):
launcher = MRJobLauncher(args=['/path/to/script'])

if PY2:
self.assertEqual(launcher.stdin, sys.stdin)
self.assertEqual(launcher.stdout, sys.stdout)
self.assertEqual(launcher.stderr, sys.stderr)
else:
self.assertEqual(launcher.stdin, sys.stdin.buffer)
self.assertEqual(launcher.stdout, sys.stdout.buffer)
self.assertEqual(launcher.stderr, sys.stderr.buffer)

def test_python3_jupyter_notebook(self):
# regression test for #1441

# this actually works on any Python platform, since we use mocks
mock_stdin = Mock()
mock_stdin.buffer = Mock()

mock_stdout = Mock()
del mock_stdout.buffer

mock_stderr = Mock()
del mock_stderr.buffer

with patch.multiple(sys, stdin=mock_stdin,
stdout=mock_stdout, stderr=mock_stderr):
launcher = MRJobLauncher(args=['/path/to/script'])

self.assertEqual(launcher.stdin, mock_stdin.buffer)
self.assertEqual(launcher.stdout, mock_stdout)
self.assertEqual(launcher.stderr, mock_stderr)