diff --git a/AUTHORS.txt b/AUTHORS.txt index abda5916..6d22c03d 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -1,4 +1,4 @@ -Main Authors +Main Authors ============ David Halter (@davidhalter) @@ -48,5 +48,6 @@ Robin Roth (@robinro) Malte Plath (@langsamer) Anton Zub (@zabulazza) Maksim Novikov (@m-novikov) +Tobias Rzepka (@TobiasRzepka) Note: (@user) means a github user name. diff --git a/jedi/_compatibility.py b/jedi/_compatibility.py index d51356d6..1660f01e 100644 --- a/jedi/_compatibility.py +++ b/jedi/_compatibility.py @@ -2,6 +2,8 @@ To ensure compatibility from Python ``2.7`` - ``3.x``, a module has been created. Clearly there is huge need to use conforming syntax. """ +import binascii +import errno import sys import os import re @@ -446,17 +448,52 @@ if sys.version_info[:2] == (3, 3): _PICKLE_PROTOCOL = 2 +is_windows = sys.platform == 'win32' + +# The Windows shell on Python 2 consumes all control characters (below 32) and expand on +# all Python versions \n to \r\n. +# pickle starting from protocol version 1 uses binary data, which could not be escaped by +# any normal unicode encoder. Therefore, the only bytes encoder which doesn't produce +# control characters is binascii.hexlify. def pickle_load(file): - if is_py3: - return pickle.load(file, encoding='bytes') + if is_windows: + try: + data = file.readline() + data = binascii.unhexlify(data.strip()) + if is_py3: + return pickle.loads(data, encoding='bytes') + else: + return pickle.loads(data) + # Python on Windows don't throw EOF errors for pipes. So reraise them with + # the correct type, which is cought upwards. + except OSError: + raise EOFError() else: - return pickle.load(file) + if is_py3: + return pickle.load(file, encoding='bytes') + else: + return pickle.load(file) def pickle_dump(data, file): - pickle.dump(data, file, protocol=_PICKLE_PROTOCOL) + if is_windows: + try: + data = pickle.dumps(data, protocol=_PICKLE_PROTOCOL) + data = binascii.hexlify(data) + file.write(data) + file.write(b'\n') + # On Python 3.3 flush throws sometimes an error even if the two file writes + # should done it already before. This could be also computer / speed depending. + file.flush() + # Python on Windows don't throw EPIPE errors for pipes. So reraise them with + # the correct type and error number. + except OSError: + raise IOError(errno.EPIPE) + else: + pickle.dump(data, file, protocol=_PICKLE_PROTOCOL) + file.flush() try: diff --git a/jedi/evaluate/compiled/subprocess/__init__.py b/jedi/evaluate/compiled/subprocess/__init__.py index 2a20f174..6ce4f808 100644 --- a/jedi/evaluate/compiled/subprocess/__init__.py +++ b/jedi/evaluate/compiled/subprocess/__init__.py @@ -187,7 +187,6 @@ class _CompiledSubprocess(object): data = evaluator_id, function, args, kwargs try: pickle_dump(data, self._process.stdin) - self._process.stdin.flush() except (socket.error, IOError) as e: # Once Python2 will be removed we can just use `BrokenPipeError`. if e.errno != errno.EPIPE: @@ -288,7 +287,6 @@ class Listener(object): result = True, traceback.format_exc(), e pickle_dump(result, file=stdout) - stdout.flush() class AccessHandle(object):