diff --git a/AUTHORS.txt b/AUTHORS.txt index 54bfdbe4c..b52e8ba7c 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -14,6 +14,7 @@ Ashley Manton Baptiste Mispelon Ben Darnell Ben Rosser +Berker Peksag Bernardo B. Marques Bradley Ayers Brian Rosner diff --git a/CHANGES.txt b/CHANGES.txt index 4d3f7e438..32b3ad005 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,7 @@ **1.6.0.dev1 (unreleased)** +* Fixed :issue:`1873`. Silence byte compile errors when installation succeed. + * **BACKWARD INCOMPATIBLE** Dropped support for Python 3.1. * **BACKWARD INCOMPATIBLE** Removed the bundle support which was deprecated in diff --git a/pip/util.py b/pip/util.py index 5b7192cdc..9a7ba61fe 100644 --- a/pip/util.py +++ b/pip/util.py @@ -1,3 +1,4 @@ +import contextlib import locale import re import os @@ -28,7 +29,8 @@ __all__ = ['rmtree', 'display_path', 'backup_dir', 'split_leading_dir', 'has_leading_dir', 'make_path_relative', 'normalize_path', 'renames', 'get_terminal_size', 'get_prog', - 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess'] + 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess', + 'captured_stdout'] def get_prog(): @@ -780,3 +782,31 @@ class FakeFile(object): def __iter__(self): return self._gen + + +@contextlib.contextmanager +def captured_output(stream_name): + """Return a context manager used by captured_stdout/stdin/stderr + that temporarily replaces the sys stream *stream_name* with a StringIO. + + Taken from Lib/support/__init__.py in the CPython repo. + """ + from pip._vendor.six.moves import cStringIO + orig_stdout = getattr(sys, stream_name) + setattr(sys, stream_name, cStringIO()) + try: + yield getattr(sys, stream_name) + finally: + setattr(sys, stream_name, orig_stdout) + + +def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as stdout: + print('hello') + self.assertEqual(stdout.getvalue(), 'hello\n') + + Taken from Lib/support/__init__.py in the CPython repo. + """ + return captured_output('stdout') diff --git a/pip/wheel.py b/pip/wheel.py index cfe335a44..9ed8f7393 100644 --- a/pip/wheel.py +++ b/pip/wheel.py @@ -20,7 +20,8 @@ from pip.exceptions import InvalidWheelFilename, UnsupportedWheel from pip.locations import distutils_scheme from pip.log import logger from pip import pep425tags -from pip.util import call_subprocess, normalize_path, make_path_relative +from pip.util import (call_subprocess, normalize_path, make_path_relative, + captured_stdout) from pip._vendor.distlib.scripts import ScriptMaker from pip._vendor import pkg_resources from pip._vendor.six.moves import configparser @@ -153,7 +154,11 @@ def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None, # Compile all of the pyc files that we're going to be installing if pycompile: - compileall.compile_dir(source, force=True, quiet=True) + with captured_stdout() as stdout: + compileall.compile_dir(source, force=True, quiet=True) + lines = [line for line in stdout.getvalue().splitlines() + if not line.startswith(('SyntaxError:', 'SyntaxWarning:'))] + print('\n'.join(lines)) def normpath(src, p): return make_path_relative(src, p).replace(os.path.sep, '/') diff --git a/tests/data/packages/compilewheel-1.0-py2.py3-none-any.whl b/tests/data/packages/compilewheel-1.0-py2.py3-none-any.whl new file mode 100644 index 000000000..8d82bb573 Binary files /dev/null and b/tests/data/packages/compilewheel-1.0-py2.py3-none-any.whl differ diff --git a/tests/data/src/compilewheel/setup.cfg b/tests/data/src/compilewheel/setup.cfg new file mode 100644 index 000000000..79bc67848 --- /dev/null +++ b/tests/data/src/compilewheel/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +# This flag says that the code is written to work on both Python 2 and Python +# 3. If at all possible, it is good practice to do this. If you cannot, you +# will need to generate wheels for each Python version that you support. +universal=1 diff --git a/tests/data/src/compilewheel/setup.py b/tests/data/src/compilewheel/setup.py new file mode 100644 index 000000000..46305d226 --- /dev/null +++ b/tests/data/src/compilewheel/setup.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python +from setuptools import setup, find_packages + +setup(name='compilewheel', + version='1.0', + packages=find_packages() + ) diff --git a/tests/data/src/compilewheel/simple/__init__.py b/tests/data/src/compilewheel/simple/__init__.py new file mode 100644 index 000000000..a5ec68c71 --- /dev/null +++ b/tests/data/src/compilewheel/simple/__init__.py @@ -0,0 +1,2 @@ +def spam(gen): + yield from gen diff --git a/tests/functional/test_install_wheel.py b/tests/functional/test_install_wheel.py index 6f1bd378f..1e75d068c 100644 --- a/tests/functional/test_install_wheel.py +++ b/tests/functional/test_install_wheel.py @@ -314,3 +314,9 @@ def test_install_from_wheel_uninstalls_old_version(script, data): assert dist_info_folder in result.files_created dist_info_folder = script.site_packages / 'simplewheel-1.0.dist-info' assert dist_info_folder not in result.files_created + + +def test_wheel_compile_syntax_error(script, data): + package = data.packages.join("compilewheel-1.0-py2.py3-none-any.whl") + result = script.pip('install', '--compile', package, '--no-index') + assert 'SyntaxError: ' not in result.stdout