def venv_setup(): # First just set up a blank virtualenv, this'll bypass the # bootstrap when we're actually testing for speed if not Path('venv').exists(): requirements('') venv_update() install_coverage() # Now the actual requirements we'll install requirements('\n'.join(( 'project_with_c', 'pure_python_package==0.2.1', 'slow_python_package==0.1.0', 'dependant_package', 'many_versions_package>=2,<3', '' ))) yield expected = '\n'.join(( 'dependant-package==1', 'implicit-dependency==1', 'many-versions-package==2.1', 'project-with-c==0.1.0', 'pure-python-package==0.2.1', 'slow-python-package==0.1.0', 'venv-update==%s' % __version__, '' )) assert pip_freeze() == expected
def test_conflicting_reqs(tmpdir): tmpdir.chdir() T.requirements(''' dependant_package conflicting_package ''') with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) err = T.strip_pip_warnings(err) assert err == ( "conflicting-package 1 has requirement many-versions-package<2, but you'll " 'have many-versions-package 3 which is incompatible.\n' # TODO: do we still need to append our own error? 'Error: version conflict: many-versions-package 3 (venv/{}) ' '<-> many-versions-package<2 ' '(from conflicting_package->-r requirements.txt (line 3))\n'.format( PYTHON_LIB, )) out = T.uncolor(out) assert_something_went_wrong(out) assert_venv_marked_invalid(tmpdir.join('venv'))
def test_multiple_issues(tmpdir): # Make it a bit worse. The output should show all three issues. tmpdir.chdir() T.requirements('flake8==2.2.5') T.venv_update() T.run('./virtualenv_run/bin/pip', 'uninstall', '--yes', 'pyflakes') T.requirements(''' # flake8 2.2.5 requires mccabe>=0.2.1 and pep8>=1.5.7, so this isn't satisfiable flake8==2.2.5 mccabe==0.2 pep8==1.0 ''') with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) assert err == '' out = T.uncolor(out) assert ''' Cleaning up... Error: version conflict: mccabe 0.2 <-> mccabe>=0.2.1 (from flake8==2.2.5 (from -r requirements.txt (line 3))) Error: version conflict: pep8 1.0 <-> pep8>=1.5.7 (from flake8==2.2.5 (from -r requirements.txt (line 3))) Error: unmet dependency: pyflakes>=0.8.1 (from flake8==2.2.5 (from -r requirements.txt (line 3))) Something went wrong! Sending 'virtualenv_run' back in time, so make knows it's invalid. ''' in out
def it_gives_the_same_python_version_as_we_started_with(tmpdir): other_python = OtherPython() with tmpdir.as_cwd(): requirements('') # first simulate some unrelated use of venv-update # this guards against statefulness in the venv-update scratch dir venv_update('unrelated_venv', '--', '--version') run('virtualenv', '--python', other_python.interpreter, 'venv') initial_version = assert_python_version(other_python.version_prefix) venv_update_symlink_pwd() out, err = run('./venv/bin/python', 'venv_update.py') assert err == '' out = uncolor(out) assert out.startswith('''\ > virtualenv Keeping valid virtualenv from previous run. > venv/bin/python -m pip.__main__ install pip-faster==%s ''' % __version__) final_version = assert_python_version(other_python.version_prefix) assert final_version == initial_version
def test_bad_symlink_can_be_fixed(tmpdir): """If the symlink at ~/.config/venv-update/$version/venv-update is wrong, we should be able to fix it and keep going. https://github.com/Yelp/pip-faster/issues/98 """ tmpdir.chdir() scratch_dir = tmpdir.join( 'home', '.cache').ensure_dir('venv-update').ensure_dir(__version__) symlink = scratch_dir.join('venv-update') # run a trivial venv-update to populate the cache and create a proper symlink assert not symlink.exists() requirements('') venv_update() assert symlink.exists() # break the symlink by hand (in real life, this can happen if mounting # things into Docker containers, for example) symlink.remove() symlink.mksymlinkto('/nonexist') assert not symlink.exists() # a simple venv-update should install packages and fix the symlink enable_coverage(tmpdir) requirements('pure-python-package') venv_update() assert '\npure-python-package==0.2.0\n' in pip_freeze() assert symlink.exists()
def test_package_name_normalization(tmpdir): with tmpdir.as_cwd(): enable_coverage() requirements('WEIRD_cAsing-packAge') venv_update() assert '\nweird-CASING-pACKage==' in pip_freeze()
def test_override_requirements_file(tmpdir): tmpdir.chdir() enable_coverage() requirements('') Path('.').join('requirements-bootstrap.txt').write('''\ venv-update==%s pure_python_package ''' % __version__) out, err = venv_update( 'bootstrap-deps=', '-r', 'requirements-bootstrap.txt', ) err = strip_pip_warnings(err) # pip>=10 doesn't complain about installing an empty requirements file. assert err == '' out = uncolor(out) # installing venv-update may downgrade / upgrade pip out = re.sub(' pip-[0-9.]+ ', ' ', out) assert '\n> pip install -r requirements-bootstrap.txt\n' in out assert ( '\nSuccessfully installed pure-python-package-0.2.1 venv-update-%s' % __version__ ) in out assert '\n Successfully uninstalled pure-python-package-0.2.1\n' in out expected = '\n'.join(( 'venv-update==' + __version__, '' )) assert pip_freeze() == expected
def test_cant_wheel_package(tmpdir): with tmpdir.as_cwd(): enable_coverage() install_coverage() requirements('cant-wheel-package\npure-python-package') out, err = venv_update() err = strip_pip_warnings(err) assert err == '' out = uncolor(out) # for unknown reasons, py27 has an extra line with four spaces in this output, where py26 does not. out = out.replace('\n \n', '\n') assert ''' ---------------------------------------- Failed building wheel for cant-wheel-package Running setup.py bdist_wheel for pure-python-package Destination directory: %s/home/.cache/pip-faster/wheelhouse''' % tmpdir + ''' SLOW!! no wheel found after building (couldn't be wheeled?): cant-wheel-package==0.1.0 Installing collected packages: cant-wheel-package, pure-python-package Running setup.py install for cant-wheel-package Could not find .egg-info directory in install record for cant-wheel-package (from -r requirements.txt (line 1)) Successfully installed cant-wheel-package pure-python-package Cleaning up... ''' in out # noqa assert pip_freeze().startswith('cant-wheel-package==0.1.0\n')
def test_symlink_is_relative(tmpdir): """We want to be able to mount ~/.cache/venv-update in different locations safely, so the symlink must be relative. https://github.com/Yelp/pip-faster/issues/101 """ tmpdir.chdir() scratch_dir = tmpdir.join('home', '.cache').ensure_dir('venv-update').ensure_dir(__version__) symlink = scratch_dir.join('venv-update') # run a trivial venv-update to populate the cache and create a proper symlink assert not symlink.exists() requirements('') venv_update() # it should be a valid, relative symlink assert symlink.exists() assert not symlink.readlink().startswith('/') # and if we move the entire scratch directory, the symlink should still be valid # (this is what we really care about) scratch_dir.move(tmpdir.join('derp')) symlink = tmpdir.join('derp', 'venv-update') assert symlink.exists()
def test_conflicting_reqs(tmpdir): tmpdir.chdir() T.requirements(''' dependant_package conflicting_package ''') with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) err = T.strip_pip_warnings(err) assert err == '' out = T.uncolor(out) assert ( ''' Cleaning up... Error: version conflict: many-versions-package 3 (venv/%s)''' ''' <-> many-versions-package<2 (from conflicting-package->-r requirements.txt (line 3)) Storing debug log for failure in %s/home/.pip/pip.log Something went wrong! Sending 'venv' back in time, so make knows it's invalid. ''' % (PYTHON_LIB, tmpdir)) in out assert_venv_marked_invalid(tmpdir.join('venv'))
def test_override_requirements_file(tmpdir): tmpdir.chdir() enable_coverage() requirements('') Path('.').ensure_dir('requirements.d').join('venv-update.txt').write('''\ venv-update==%s pure_python_package ''' % __version__) out, err = venv_update() err = strip_pip_warnings(err) assert err == '' out = uncolor(out) assert ( '\n> pip install --find-links=file://%s/home/.cache/pip-faster/wheelhouse -r requirements.d/venv-update.txt\n' % tmpdir ) in out assert ( '\nSuccessfully installed pip-1.5.6 pure-python-package-0.2.0 venv-update-%s' % __version__ ) in out assert '\n Successfully uninstalled pure-python-package\n' in out expected = '\n'.join(( 'venv-update==%s' % __version__, 'wheel==0.29.0', '' )) assert pip_freeze() == expected
def venv_setup(): # First just set up a blank virtualenv, this'll bypass the # bootstrap when we're actually testing for speed if not Path('venv').exists(): requirements('') venv_update() install_coverage() # Now the actual requirements we'll install requirements('\n'.join( ('project_with_c', 'pure_python_package==0.2.1', 'slow_python_package==0.1.0', 'dependant_package', 'many_versions_package>=2,<3', ''))) yield expected = '\n'.join( ('appdirs==1.4.3', 'dependant-package==1', 'implicit-dependency==1', 'many-versions-package==2.1', 'packaging==16.8', 'pip==9.0.1', 'project-with-c==0.1.0', 'pure-python-package==0.2.1', 'pyparsing==2.2.0', 'setuptools==35.0.2', 'six==1.10.0', 'slow-python-package==0.1.0', 'venv-update==%s' % __version__, 'wheel==0.29.0', '')) assert pip_freeze() == expected
def test_cant_wheel_package(tmpdir): with tmpdir.as_cwd(): enable_coverage(tmpdir) requirements('cant-wheel-package\npure-python-package') out, err = venv_update() assert err == '' out = uncolor(out) # for unknown reasons, py27 has an extra line with four spaces in this output, where py26 does not. out = out.replace('\n \n', '\n') assert ''' ---------------------------------------- Failed building wheel for cant-wheel-package Running setup.py bdist_wheel for pure-python-package Destination directory: %s/home/.cache/pip-faster/wheelhouse''' % tmpdir + ''' SLOW!! no wheel found after building (couldn't be wheeled?): cant-wheel-package (from -r requirements.txt (line 1)) Installing collected packages: cant-wheel-package, pure-python-package Running setup.py install for cant-wheel-package Could not find .egg-info directory in install record for cant-wheel-package (from -r requirements.txt (line 1)) Successfully installed cant-wheel-package pure-python-package Cleaning up... > pip uninstall --yes coverage coverage-enable-subprocess ''' in out # noqa assert pip_freeze().startswith('cant-wheel-package==0.1.0\n')
def flake8_newer(): requirements('''\ flake8==2.2.5 # we expect 0.8.1 pyflakes<=0.8.1 # simply to prevent these from drifting: mccabe<=0.3 pep8<=1.5.7 -r %s/requirements.d/coverage.txt ''' % TOP) venv_update() assert pip_freeze() == '\n'.join(( 'appdirs==1.4.3', 'coverage==4.4.1', 'coverage-enable-subprocess==1.0', 'flake8==2.2.5', 'mccabe==0.3', 'packaging==16.8', 'pep8==1.5.7', 'pip==9.0.1', 'pyflakes==0.8.1', 'pyparsing==2.2.0', 'setuptools==35.0.2', 'six==1.10.0', 'venv-update==' + __version__, 'wheel==0.29.0', '' ))
def test_package_name_normalization(tmpdir): with tmpdir.as_cwd(): enable_coverage(tmpdir) requirements('WEIRD_cAsing-packAge') venv_update() assert '\nweird-CASING-pACKage==' in pip_freeze()
def test_override_requirements_file(tmpdir): tmpdir.chdir() requirements('') Path('.').ensure_dir('requirements.d').join('venv-update.txt').write('''\ pip-faster==%s pure_python_package ''' % __version__) out, err = venv_update() err = strip_pip_warnings(err) assert err == '' out = uncolor(out) assert ' '.join(( '\n> venv/bin/python -m pip.__main__ install', '-r requirements.d/venv-update.txt\n', )) in out expected = ('\nSuccessfully installed pip-1.5.6 pip-faster-%s pure-python-package-0.2.0 virtualenv-1.11.6' % __version__) assert expected in out assert '\n Successfully uninstalled pure-python-package\n' in out expected = '\n'.join(( 'pip-faster==%s' % __version__, 'virtualenv==1.11.6', 'wheel==0.29.0', '' )) assert pip_freeze() == expected
def flake8_older(): requirements('''\ flake8==2.0 # last pyflakes release before 0.8 was 0.7.3 pyflakes<0.8 # simply to prevent these from drifting: mccabe<=0.3 pep8<=1.5.7 -r %s/requirements.d/coverage.txt ''' % TOP) venv_update() assert pip_freeze() == '\n'.join(( 'coverage==4.0.3', 'coverage-enable-subprocess==0', 'flake8==2.0', 'mccabe==0.3', 'pep8==1.5.7', 'pip-faster==' + __version__, 'pyflakes==0.7.3', 'virtualenv==1.11.6', 'wheel==0.29.0', '' ))
def flake8_newer(): requirements('''\ flake8==2.2.5 # we expect 0.8.1 pyflakes<=0.8.1 # simply to prevent these from drifting: mccabe<=0.3 pep8<=1.5.7 -r %s/requirements.d/coverage.txt ''' % TOP) venv_update() assert pip_freeze() == '\n'.join(( 'coverage==4.0.3', 'coverage-enable-subprocess==0', 'flake8==2.2.5', 'mccabe==0.3', 'pep8==1.5.7', 'pip-faster==' + __version__, 'pyflakes==0.8.1', 'virtualenv==1.11.6', 'wheel==0.29.0', '' ))
def it_gives_the_same_python_version_as_we_started_with(tmpdir): other_python = OtherPython() with tmpdir.as_cwd(): requirements('') # first simulate some unrelated use of venv-update # this guards against statefulness in the venv-update scratch dir venv_update('venv=', 'unrelated_venv', 'pip-command=', 'true') run('virtualenv', '--python', other_python.interpreter, 'venv') initial_version = assert_python_version(other_python.version_prefix) venv_update_symlink_pwd() out, err = run('./venv/bin/python', 'venv_update.py') err = strip_pip_warnings(err) assert err == '' out = uncolor(out) assert out.startswith('''\ > virtualenv venv Keeping valid virtualenv from previous run. > rm -rf venv/local > pip install venv-update=={} '''.format(__version__)) final_version = assert_python_version(other_python.version_prefix) assert final_version == initial_version
def test_conflicting_reqs(tmpdir): tmpdir.chdir() T.requirements(''' dependant_package conflicting_package ''') with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) err = T.strip_pip_warnings(err) assert err == ( "conflicting-package 1 has requirement many-versions-package<2, but you'll " 'have many-versions-package 3 which is incompatible.\n' # TODO: do we still need to append our own error? 'Error: version conflict: many-versions-package 3 (venv/{}) ' '<-> many-versions-package<2 ' '(from conflicting_package->-r requirements.txt (line 3))\n'.format( PYTHON_LIB, ) ) out = T.uncolor(out) assert_something_went_wrong(out) assert_venv_marked_invalid(tmpdir.join('venv'))
def test_conflicting_reqs(tmpdir): tmpdir.chdir() T.requirements(''' dependant_package conflicting_package ''') with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) err = T.strip_pip_warnings(err) assert err == '' out = T.uncolor(out) assert ( ''' Cleaning up... Error: version conflict: many-versions-package 3 (venv/%s)''' ''' <-> many-versions-package<2 (from conflicting-package->-r requirements.txt (line 3)) Storing debug log for failure in %s/home/.pip/pip.log Something went wrong! Sending 'venv' back in time, so make knows it's invalid. ''' % (PYTHON_LIB, tmpdir) ) in out assert_venv_marked_invalid(tmpdir.join('venv'))
def test_symlink_is_relative(tmpdir): """We want to be able to mount ~/.cache/venv-update in different locations safely, so the symlink must be relative. https://github.com/Yelp/pip-faster/issues/101 """ tmpdir.chdir() scratch_dir = tmpdir.join( 'home', '.cache').ensure_dir('venv-update').ensure_dir(__version__) symlink = scratch_dir.join('venv-update') # run a trivial venv-update to populate the cache and create a proper symlink assert not symlink.exists() requirements('') venv_update() # it should be a valid, relative symlink assert symlink.exists() assert not symlink.readlink().startswith('/') # and if we move the entire scratch directory, the symlink should still be valid # (this is what we really care about) scratch_dir.move(tmpdir.join('derp')) symlink = tmpdir.join('derp', 'venv-update') assert symlink.exists()
def test_conflicting_reqs(tmpdir): tmpdir.chdir() T.requirements(''' # flake8 2.2.5 requires mccabe>=0.2.1, so this isn't satisfiable flake8==2.2.5 mccabe==0.2 ''') with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) assert err == '' out = T.uncolor(out) assert ( ''' Cleaning up... Error: version conflict: mccabe 0.2 (virtualenv_run/%s)''' ''' <-> mccabe>=0.2.1 (from flake8==2.2.5 (from -r requirements.txt (line 3))) Something went wrong! Sending 'virtualenv_run' back in time, so make knows it's invalid. ''' % PYTHON_LIB ) in out
def test_bad_symlink_can_be_fixed(tmpdir): """If the symlink at ~/.config/venv-update/$version/venv-update is wrong, we should be able to fix it and keep going. https://github.com/Yelp/pip-faster/issues/98 """ tmpdir.chdir() scratch_dir = tmpdir.join('home', '.cache').ensure_dir('venv-update').ensure_dir(__version__) symlink = scratch_dir.join('venv-update') # run a trivial venv-update to populate the cache and create a proper symlink assert not symlink.exists() requirements('') venv_update() assert symlink.exists() # break the symlink by hand (in real life, this can happen if mounting # things into Docker containers, for example) symlink.remove() symlink.mksymlinkto('/nonexist') assert not symlink.exists() # a simple venv-update should install packages and fix the symlink enable_coverage(tmpdir) requirements('pure-python-package') venv_update() assert '\npure-python-package==0.2.0\n' in pip_freeze() assert symlink.exists()
def test_update_while_active(tmpdir): tmpdir.chdir() enable_coverage() requirements('') venv_update() assert 'project-with-c' not in pip_freeze() # An arbitrary small package: project_with_c requirements('project_with_c') venv_update_symlink_pwd() out, err = run( 'sh', '-c', '. venv/bin/activate && python venv_update.py venv= venv --python=venv/bin/python' ) out = uncolor(out) err = strip_pip_warnings(err) assert err == '' assert out.startswith('''\ > virtualenv venv --python=venv/bin/python Keeping valid virtualenv from previous run. ''') assert 'project-with-c' in pip_freeze()
def it_installs_stuff_with_dash_e_without_wheeling(tmpdir): venv = tmpdir.join('venv') install_coverage(venv) pip = venv.join('bin/pip').strpath run(pip, 'install', 'venv-update==' + __version__) # Install a package from git with no extra dependencies in editable mode. # # We need to install a package from VCS instead of the filesystem because # otherwise we aren't testing that editable requirements aren't wheeled # (and instead might just be testing that local paths aren't wheeled). requirements( '-e git+git://github.com/Yelp/dumb-init.git@87545be699a13d0fd31f67199b7782ebd446437e#egg=dumb-init' ) # noqa run(str(venv.join('bin/pip-faster')), 'install', '-r', 'requirements.txt') frozen_requirements = pip_freeze(str(venv)).split('\n') assert set(frozen_requirements) == { '-e git://github.com/Yelp/dumb-init.git@87545be699a13d0fd31f67199b7782ebd446437e#egg=dumb_init', # noqa 'coverage-enable-subprocess==1.0', 'coverage==ANY', 'venv-update==' + __version__, '', } # we shouldn't wheel things installed editable assert not tuple(cached_wheels(tmpdir))
def test_override_requirements_file(tmpdir): tmpdir.chdir() enable_coverage() requirements('') Path('.').join('requirements-bootstrap.txt').write('''\ venv-update==%s pure_python_package ''' % __version__) out, err = venv_update( 'bootstrap-deps=', '-r', 'requirements-bootstrap.txt', ) err = strip_pip_warnings(err) # pip>=10 doesn't complain about installing an empty requirements file. assert err == '' out = uncolor(out) assert '\n> pip install -r requirements-bootstrap.txt\n' in out assert ( '\nSuccessfully installed pure-python-package-0.2.1 venv-update-%s' % __version__ ) in out assert '\n Successfully uninstalled pure-python-package-0.2.1\n' in out expected = '\n'.join(( 'venv-update==' + __version__, '' )) assert pip_freeze() == expected
def test_update_invalidated_while_active(tmpdir): tmpdir.chdir() enable_coverage() requirements('') venv_update() assert 'project-with-c' not in pip_freeze() # An arbitrary small package: project_with_c requirements('project-with-c') venv_update_symlink_pwd() out, err = run( 'sh', '-c', '. venv/bin/activate && python venv_update.py venv= --system-site-packages venv' ) err = strip_pip_warnings(err) assert err == '' out = uncolor(out) assert out.startswith('''\ > virtualenv --system-site-packages venv Removing invalidated virtualenv. (system-site-packages changed, to True) ''') assert 'project-with-c' in pip_freeze()
def it_installs_stuff_with_dash_e_without_wheeling(tmpdir): venv = tmpdir.join('venv') install_coverage(venv) pip = venv.join('bin/pip').strpath run(pip, 'install', 'venv-update==' + __version__) # Install a package from git with no extra dependencies in editable mode. # # We need to install a package from VCS instead of the filesystem because # otherwise we aren't testing that editable requirements aren't wheeled # (and instead might just be testing that local paths aren't wheeled). requirements('-e git+git://github.com/Yelp/dumb-init.git@87545be699a13d0fd31f67199b7782ebd446437e#egg=dumb-init') # noqa run(str(venv.join('bin/pip-faster')), 'install', '-r', 'requirements.txt') frozen_requirements = pip_freeze(str(venv)).split('\n') assert set(frozen_requirements) == { '-e git://github.com/Yelp/dumb-init.git@87545be699a13d0fd31f67199b7782ebd446437e#egg=dumb_init', # noqa 'coverage-enable-subprocess==1.0', 'coverage==ANY', 'venv-update==' + __version__, '', } # we shouldn't wheel things installed editable assert not tuple(cached_wheels(tmpdir))
def test_args_backward(tmpdir): tmpdir.chdir() enable_coverage() requirements('') with pytest.raises(CalledProcessError) as excinfo: venv_update('venv=', 'requirements.txt') # py26 doesn't have a consistent exit code: # http://bugs.python.org/issue15033 assert excinfo.value.returncode != 0 out, err = excinfo.value.result err = strip_coverage_warnings(err) err = strip_pip_warnings(err) assert err == '' out = uncolor(out) assert out.rsplit('\n', 4)[-4:] == [ '> virtualenv requirements.txt', 'ERROR: File already exists and is not a directory.', 'Please provide a different path or delete the file.', '', ] assert Path('requirements.txt').isfile() assert Path('requirements.txt').read() == '' assert not Path('myvenv').exists()
def test_override_requirements_file(tmpdir): tmpdir.chdir() enable_coverage() requirements('') Path('.').join('requirements-bootstrap.txt').write('''\ venv-update==%s pure_python_package ''' % __version__) out, err = venv_update( 'bootstrap-deps=', '-r', 'requirements-bootstrap.txt', ) err = strip_pip_warnings(err) assert err == ('You must give at least one requirement to install ' '(see "pip help install")\n') out = uncolor(out) assert '\n> pip install -r requirements-bootstrap.txt\n' in out assert ( '\nSuccessfully installed pure-python-package-0.2.1 venv-update-%s' % __version__) in out assert '\n Successfully uninstalled pure-python-package-0.2.1\n' in out expected = '\n'.join( ('appdirs==1.4.0', 'packaging==16.8', 'pip==9.0.1', 'pyparsing==2.1.10', 'setuptools==34.1.1', 'six==1.10.0', 'venv-update==' + __version__, 'wheel==0.29.0', '')) assert pip_freeze() == expected
def test_multiple_issues(tmpdir): # Make it a bit worse. The output should show all three issues. tmpdir.chdir() T.requirements('flake8==2.2.5') T.venv_update() T.run('./virtualenv_run/bin/pip', 'uninstall', '--yes', 'pyflakes') T.requirements(''' # flake8 2.2.5 requires mccabe>=0.2.1 and pep8>=1.5.7, so this isn't satisfiable flake8==2.2.5 mccabe==0.2 pep8==1.0 ''') with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) assert err == '' out = T.uncolor(out) assert ( ''' Cleaning up... Error: version conflict: mccabe 0.2 (virtualenv_run/%s)''' ''' <-> mccabe>=0.2.1 (from flake8==2.2.5 (from -r requirements.txt (line 3))) Error: version conflict: pep8 1.0 (virtualenv_run/%s) ''' '''<-> pep8>=1.5.7 (from flake8==2.2.5 (from -r requirements.txt (line 3))) Error: unmet dependency: pyflakes>=0.8.1 (from flake8==2.2.5 (from -r requirements.txt (line 3))) Something went wrong! Sending 'virtualenv_run' back in time, so make knows it's invalid. ''' % (PYTHON_LIB, PYTHON_LIB) ) in out
def test_package_name_normalization_with_dots(tmpdir, install_req): """Packages with dots should be installable with either dots or dashes.""" with tmpdir.as_cwd(): enable_coverage() requirements(install_req) venv_update() assert pip_freeze().startswith('dotted.package-name==')
def install_twice(tmpdir, between): """install twice, and the second one should be faster, due to whl caching""" tmpdir.chdir() # Arbitrary packages that takes a bit of time to install: # Should I make a fixture c-extension to remove these dependencies? # NOTE: Avoid projects that use 2to3 (urwid). It makes the runtime vary too widely. requirements('''\ simplejson==3.6.5 pyyaml==3.11 pylint==1.4.0 astroid<1.3.3 pytest==2.6.4 unittest2==0.8.0 six<=1.8.0 chroniker ''') from time import time enable_coverage(tmpdir) assert pip_freeze() == '\n'.join( ('cov-core==1.15.0', 'coverage==4.0a1', '')) start = time() venv_update() time1 = time() - start assert pip_freeze() == '\n'.join( ('PyYAML==3.11', 'astroid==1.3.2', 'chroniker==0.0.0', 'logilab-common==0.63.2', 'py==1.4.26', 'pylint==1.4.0', 'pytest==2.6.4', 'simplejson==3.6.5', 'six==1.8.0', 'unittest2==0.8.0', 'wheel==0.24.0', '')) between() enable_coverage(tmpdir) # there may be more or less packages depending on what exactly happened between assert 'cov-core==1.15.0\ncoverage==4.0a1\n' in pip_freeze() start = time() # second install should also need no network access # these are localhost addresses with arbitrary invalid ports venv_update( http_proxy='http://127.0.0.1:111111', https_proxy='https://127.0.0.1:222222', ftp_proxy='ftp://127.0.0.1:333333', ) time2 = time() - start assert pip_freeze() == '\n'.join( ('PyYAML==3.11', 'astroid==1.3.2', 'chroniker==0.0.0', 'logilab-common==0.63.2', 'py==1.4.26', 'pylint==1.4.0', 'pytest==2.6.4', 'simplejson==3.6.5', 'six==1.8.0', 'unittest2==0.8.0', 'wheel==0.24.0', '')) # second install should be at least twice as fast ratio = time1 / time2 print('%.2fx speedup' % ratio) return ratio
def test_not_installable_thing(tmpdir): tmpdir.chdir() enable_coverage() install_coverage() requirements('not-a-real-package-plz') with pytest.raises(CalledProcessError): venv_update()
def test_trivial(tmpdir): tmpdir.chdir() requirements('') enable_coverage() venv_update() # Originally suggested by none other than @bukzor in: # https://github.com/pypa/virtualenv/issues/118 # This directory now just causes problems (especially with relocating) # since the debian issue has been fixed. assert not tmpdir.join('venv', 'local').exists()
def test_eggless_url(tmpdir): tmpdir.chdir() enable_coverage() # An arbitrary url requirement. requirements('-e file://' + str(TOP / 'tests/testing/packages/pure_python_package')) venv_update() assert '#egg=pure_python_package' in pip_freeze()
def test_relocatable(tmpdir): tmpdir.chdir() requirements('') venv_update('--python=python') # this makes pypy work right. derp. Path('virtualenv_run').rename('relocated') python = 'relocated/bin/python' assert Path(python).exists() run(python, '-m', 'pip.__main__', '--version')
def test_relocatable(tmpdir): tmpdir.chdir() requirements('') venv_update() Path('venv').rename('relocated') python = 'relocated/bin/python' assert Path(python).exists() run(python, '-m', 'pip.__main__', '--version')
def test_recreate_active_virtualenv(tmpdir): with tmpdir.as_cwd(): run('virtualenv', 'venv') run('venv/bin/pip', 'install', '-r', str(TOP / 'requirements.d/coverage.txt')) requirements('project_with_c') venv_update_symlink_pwd() run('venv/bin/python', 'venv_update.py') assert_c_extension_runs()
def test_editable_egg_conflict(tmpdir): conflicting_package = tmpdir / 'tmp/conflicting_package' many_versions_package_2 = tmpdir / 'tmp/many_versions_package_2' from shutil import copytree copytree( str(T.TOP / 'tests/testing/packages/conflicting_package'), str(conflicting_package), ) copytree( str(T.TOP / 'tests/testing/packages/many_versions_package_2'), str(many_versions_package_2), ) with many_versions_package_2.as_cwd(): from sys import executable as python T.run(python, 'setup.py', 'bdist_egg', '--dist-dir', str(conflicting_package)) with tmpdir.as_cwd(): T.requirements('-r %s/requirements.d/coverage.txt' % T.TOP) T.venv_update() T.requirements('-e %s' % conflicting_package) with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) assert err == '' out = T.uncolor(out) expected = '\nSuccessfully installed many-versions-package conflicting-package\n' assert expected in out rest = out.rsplit(expected, 1)[-1] if True: # :pragma:nocover:pylint:disable=using-constant-test # Debian de-vendorizes the version of pip it ships try: from sysconfig import get_python_version except ImportError: # <= python2.6 from distutils.sysconfig import get_python_version assert ( '''\ Cleaning up... Error: version conflict: many-versions-package 2 (tmp/conflicting_package/many_versions_package-2-py{0}.egg)''' ''' <-> many-versions-package<2 (from conflicting-package==1->-r requirements.txt (line 1)) Storing debug log for failure in {1}/home/.pip/pip.log Something went wrong! Sending 'venv' back in time, so make knows it's invalid. '''.format(get_python_version(), tmpdir) ) == rest assert_venv_marked_invalid(tmpdir.join('venv'))
def time_savings(tmpdir, between): """install twice, and the second one should be faster, due to whl caching""" with tmpdir.as_cwd(): enable_coverage() install_coverage() requirements('\n'.join( ('project_with_c', 'pure_python_package==0.2.0', 'slow_python_package==0.1.0', 'dependant_package', 'many_versions_package>=2,<3', ''))) from time import time start = time() venv_update( PIP_VERBOSE='1', PIP_RETRIES='0', PIP_TIMEOUT='0', ) time1 = time() - start expected = '\n'.join( ('dependant-package==1', 'implicit-dependency==1', 'many-versions-package==2.1', 'project-with-c==0.1.0', 'pure-python-package==0.2.0', 'slow-python-package==0.1.0', 'venv-update==%s' % __version__, 'wheel==0.29.0', '')) assert pip_freeze() == expected between() install_coverage() start = time() # second install should also need no network access # these are localhost addresses with arbitrary invalid ports venv_update( PIP_VERBOSE='1', PIP_RETRIES='0', PIP_TIMEOUT='0', http_proxy='http://127.0.0.1:111111', https_proxy='https://127.0.0.1:222222', ftp_proxy='ftp://127.0.0.1:333333', ) time2 = time() - start assert pip_freeze() == expected print() print('%.3fs originally' % time1) print('%.3fs subsequently' % time2) difference = time1 - time2 print('%.2fs speedup' % difference) ratio = time1 / time2 percent = (ratio - 1) * 100 print('%.2f%% speedup' % percent) return difference
def test_editable_egg_conflict(tmpdir): conflicting_package = tmpdir / 'tmp/conflicting_package' many_versions_package_2 = tmpdir / 'tmp/many_versions_package_2' from shutil import copytree copytree( str(T.TOP / 'tests/testing/packages/conflicting_package'), str(conflicting_package), ) copytree( str(T.TOP / 'tests/testing/packages/many_versions_package_2'), str(many_versions_package_2), ) with many_versions_package_2.as_cwd(): from sys import executable as python T.run(python, 'setup.py', 'bdist_egg', '--dist-dir', str(conflicting_package)) with tmpdir.as_cwd(): T.requirements('-r %s/requirements.d/coverage.txt' % T.TOP) T.venv_update() T.requirements('-e %s' % conflicting_package) with pytest.raises(CalledProcessError) as excinfo: T.venv_update() assert excinfo.value.returncode == 1 out, err = excinfo.value.result err = T.strip_coverage_warnings(err) assert err == '' out = T.uncolor(out) expected = '\nSuccessfully installed many-versions-package conflicting-package\n' assert expected in out rest = out.rsplit(expected, 1)[-1] if True: # :pragma:nocover:pylint:disable=using-constant-test # Debian de-vendorizes the version of pip it ships try: from sysconfig import get_python_version except ImportError: # <= python2.6 from distutils.sysconfig import get_python_version assert ( '''\ Cleaning up... Error: version conflict: many-versions-package 2 (tmp/conflicting_package/many_versions_package-2-py{0}.egg)''' ''' <-> many-versions-package<2 (from conflicting-package==1->-r requirements.txt (line 1)) Storing debug log for failure in {1}/home/.pip/pip.log Something went wrong! Sending 'venv' back in time, so make knows it's invalid. '''.format(get_python_version(), tmpdir)) == rest assert_venv_marked_invalid(tmpdir.join('venv'))
def test_wrong_wheel(tmpdir): tmpdir.chdir() requirements('') venv_update('venv1', 'requirements.txt', '-ppython2.7') # A different python # Before fixing, this would install argparse using the `py2-none-any` # wheel, even on py3 ret2out, _ = venv_update('venv2', 'requirements.txt', '-ppython3.3') assert 'py2-none-any' not in ret2out
def test_remove_stale_cache_values(tmpdir): """Tests that we remove stale (older than a week) cached packages and wheels, while still keeping everything created within the past week. """ import os import time tmpdir.chdir() home_path = str(Path('.').realpath()) pip_path = home_path + '/.pip' cache_path = pip_path + '/cache' wheelhouse_path = pip_path + '/wheelhouse' stale_cached_package = cache_path + '/stale_package' fresh_cached_package = cache_path + '/new_package' stale_cached_wheel = wheelhouse_path + '/stale_wheel' fresh_cached_wheel = wheelhouse_path + '/new_wheel' # Creates a cached package and wheel in their respective # .pip/cache/ and .pip/wheelhouse directories. os.makedirs(stale_cached_package) os.makedirs(fresh_cached_package) os.makedirs(stale_cached_wheel) os.makedirs(fresh_cached_wheel) # Create some rough times for testing. These represent, in # seconds since epoch, a time from today, this week, and last month seconds_in_day = 86400 today_time = int(time.time()) this_week_time = int(time.time()) - seconds_in_day * 3 last_month_time = int(time.time()) - seconds_in_day * 40 # Set access times of stale package/wheel to be older than a week. os.utime(stale_cached_package, (0, 0)) # Jan 1, 1970 os.utime(stale_cached_wheel, (last_month_time, last_month_time)) # Set access times of fresh package/wheel to be within the past week. os.utime(fresh_cached_package, (today_time, today_time)) os.utime(fresh_cached_wheel, (this_week_time, this_week_time)) requirements('') venv_update() # Assert that we can no longer access the stale package/wheel # that have been removed. assert not os.access(stale_cached_package, os.F_OK) assert not os.access(stale_cached_wheel, os.F_OK) # Assert that we can still access the fresh package/wheel, # they should not have been removed. assert os.access(fresh_cached_package, os.F_OK) assert os.access(fresh_cached_wheel, os.F_OK)
def test_extra_index_url_doesnt_cache(tmpdir): tmpdir.chdir() enable_coverage() install_coverage() requirements('pure-python-package==0.2.1') venv_update( 'pip-command=', 'pip-faster', 'install', '--extra-index-url=https://pypi.python.org/simple', ) assert not tuple(cached_wheels(tmpdir))
def test_eggless_url(tmpdir): tmpdir.chdir() requirements('') venv_update() assert 'venv-update' not in pip_freeze() # An arbitrary git-url requirement. requirements('git+git://github.com/Yelp/venv-update.git') venv_update() assert 'venv-update' in pip_freeze()
def test_wrong_wheel(tmpdir): tmpdir.chdir() requirements('pure_python_package==0.1.0') venv_update('venv1') # A different python # Before fixing, this would install argparse using the `py2-none-any` # wheel, even on py3 other_python = OtherPython() ret2out, _ = venv_update('venv2', '-p' + other_python.interpreter, '--', '-vv', '-r', 'requirements.txt') assert ''' No wheel found locally for pinned requirement pure-python-package==0.1.0 (from -r requirements.txt (line 1)) ''' in uncolor(ret2out)
def it_can_handle_requirements_already_met(tmpdir): venv = tmpdir.join('venv') install_coverage(venv) pip = venv.join('bin/pip').strpath run(pip, 'install', 'venv-update==' + __version__) requirements('many-versions-package==1') run(str(venv.join('bin/pip-faster')), 'install', '-r', 'requirements.txt') assert 'many-versions-package==1\n' in pip_freeze(str(venv)) run(str(venv.join('bin/pip-faster')), 'install', '-r', 'requirements.txt') assert 'many-versions-package==1\n' in pip_freeze(str(venv))