import re import os import filecmp import textwrap import sys from os.path import abspath, join, curdir, pardir from nose import SkipTest from nose.tools import assert_raises from mock import patch from pip.util import rmtree, find_command from pip.exceptions import BadCommand from tests.test_pip import (here, reset_env, run_pip, pyversion, mkdir, src_folder, write_file) from tests.local_repos import local_checkout from tests.path import Path def test_correct_pip_version(): """ Check we are running proper version of pip in run_pip. """ reset_env() # output is like: # pip PIPVERSION from PIPDIRECTORY (python PYVERSION) result = run_pip('--version') # compare the directory tree of the invoked pip with that of this source distribution dir = re.match(r'pip \d(\.[\d])+(\.(pre|post)\d+)? from (.*) \(python \d(.[\d])+\)$', result.stdout).group(4) pip_folder = join(src_folder, 'pip') pip_folder_outputed = join(dir, 'pip') diffs = filecmp.dircmp(pip_folder, pip_folder_outputed) # If any non-matching .py files exist, we have a problem: run_pip # is picking up some other version! N.B. if this project acquires # primary resources other than .py files, this code will need # maintenance mismatch_py = [x for x in diffs.left_only + diffs.right_only + diffs.diff_files if x.endswith('.py')] assert not mismatch_py, 'mismatched source files in %r and %r'% (pip_folder, pip_folder_outputed) def test_pip_second_command_line_interface_works(): """ Check if ``pip-`` commands behaves equally """ e = reset_env() result = e.run('pip-%s' % pyversion, 'install', 'INITools==0.2') egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion initools_folder = e.site_packages / 'initools' assert egg_info_folder in result.files_created, str(result) assert initools_folder in result.files_created, str(result) #def test_distutils_configuration_setting(): # """ # Test the distutils-configuration-setting command (which is distinct from other commands). # """ #print run_pip('-vv', '--distutils-cfg=easy_install:index_url:http://download.zope.org/ppix/', expect_error=True) #Script result: python ../../poacheggs.py -E .../poacheggs-tests/test-scratch -vv --distutils-cfg=easy_install:index_url:http://download.zope.org/ppix/ #-- stdout: -------------------- #Distutils config .../poacheggs-tests/test-scratch/lib/python.../distutils/distutils.cfg is writable #Replaced setting index_url #Updated .../poacheggs-tests/test-scratch/lib/python.../distutils/distutils.cfg # #-- updated: ------------------- # lib/python2.4/distutils/distutils.cfg (346 bytes) def test_install_from_pypi(): """ Test installing a package from PyPI. """ e = reset_env() result = run_pip('install', '-vvv', 'INITools==0.2') egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion initools_folder = e.site_packages / 'initools' assert egg_info_folder in result.files_created, str(result) assert initools_folder in result.files_created, str(result) def test_install_from_mirrors(): """ Test installing a package from the PyPI mirrors. """ e = reset_env() result = run_pip('install', '-vvv', '--use-mirrors', '--no-index', 'INITools==0.2') egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion initools_folder = e.site_packages / 'initools' assert egg_info_folder in result.files_created, str(result) assert initools_folder in result.files_created, str(result) def test_install_from_mirrors_with_specific_mirrors(): """ Test installing a package from a specific PyPI mirror. """ e = reset_env() result = run_pip('install', '-vvv', '--use-mirrors', '--mirrors', "http://d.pypi.python.org/", '--no-index', 'INITools==0.2') egg_info_folder = e.site_packages / 'INITools-0.2-py%s.egg-info' % pyversion initools_folder = e.site_packages / 'initools' assert egg_info_folder in result.files_created, str(result) assert initools_folder in result.files_created, str(result) def test_editable_install(): """ Test editable installation. """ reset_env() result = run_pip('install', '-e', 'INITools==0.2', expect_error=True) assert "--editable=INITools==0.2 should be formatted with svn+URL" in result.stdout assert len(result.files_created) == 1, result.files_created assert not result.files_updated, result.files_updated def test_install_editable_from_svn(): """ Test checking out from svn. """ reset_env() result = run_pip('install', '-e', '%s#egg=initools-dev' % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk')) result.assert_installed('INITools', with_files=['.svn']) def test_download_editable_to_custom_path(): """ Test downloading an editable using a relative custom src folder. """ reset_env() mkdir('customdl') result = run_pip('install', '-e', '%s#egg=initools-dev' % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), '--src', 'customsrc', '--download', 'customdl') customsrc = Path('scratch')/'customsrc'/'initools' assert customsrc in result.files_created, sorted(result.files_created.keys()) assert customsrc/'setup.py' in result.files_created, sorted(result.files_created.keys()) customdl = Path('scratch')/'customdl'/'initools' customdl_files_created = [filename for filename in result.files_created if filename.startswith(customdl)] assert customdl_files_created def test_editable_no_install_followed_by_no_download(): """ Test installing an editable in two steps (first with --no-install, then with --no-download). """ reset_env() result = run_pip('install', '-e', '%s#egg=initools-dev' % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), '--no-install', expect_error=True) result.assert_installed('INITools', without_egg_link=True, with_files=['.svn']) result = run_pip('install', '-e', '%s#egg=initools-dev' % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), '--no-download', expect_error=True) result.assert_installed('INITools', without_files=[curdir, '.svn']) def test_no_install_followed_by_no_download(): """ Test installing in two steps (first with --no-install, then with --no-download). """ env = reset_env() egg_info_folder = env.site_packages/'INITools-0.2-py%s.egg-info' % pyversion initools_folder = env.site_packages/'initools' build_dir = env.venv/'build'/'INITools' result1 = run_pip('install', 'INITools==0.2', '--no-install', expect_error=True) assert egg_info_folder not in result1.files_created, str(result1) assert initools_folder not in result1.files_created, sorted(result1.files_created) assert build_dir in result1.files_created, result1.files_created assert build_dir/'INITools.egg-info' in result1.files_created result2 = run_pip('install', 'INITools==0.2', '--no-download', expect_error=True) assert egg_info_folder in result2.files_created, str(result2) assert initools_folder in result2.files_created, sorted(result2.files_created) assert build_dir not in result2.files_created assert build_dir/'INITools.egg-info' not in result2.files_created def test_bad_install_with_no_download(): """ Test that --no-download behaves sensibly if the package source can't be found. """ reset_env() result = run_pip('install', 'INITools==0.2', '--no-download', expect_error=True) assert "perhaps --no-download was used without first running "\ "an equivalent install with --no-install?" in result.stdout def test_install_dev_version_from_pypi(): """ Test using package==dev. """ e = reset_env() result = run_pip('install', 'INITools==dev', expect_error=True) assert (e.site_packages / 'initools') in result.files_created, str(result.stdout) def test_install_editable_from_git(): """ Test cloning from Git. """ reset_env() args = ['install'] args.extend(['-e', '%s#egg=pip-test-package' % local_checkout('git+http://github.com/pypa/pip-test-package.git')]) result = run_pip(*args, **{"expect_error": True}) result.assert_installed('pip-test-package', with_files=['.git']) def test_install_editable_from_hg(): """ Test cloning from Mercurial. """ reset_env() result = run_pip('install', '-e', '%s#egg=django-registration' % local_checkout('hg+http://bitbucket.org/ubernostrum/django-registration'), expect_error=True) result.assert_installed('django-registration', with_files=['.hg']) def test_vcs_url_final_slash_normalization(): """ Test that presence or absence of final slash in VCS URL is normalized. """ reset_env() result = run_pip('install', '-e', '%s/#egg=django-registration' % local_checkout('hg+http://bitbucket.org/ubernostrum/django-registration'), expect_error=True) assert 'pip-log.txt' not in result.files_created, result.files_created['pip-log.txt'].bytes def test_install_editable_from_bazaar(): """ Test checking out from Bazaar. """ reset_env() result = run_pip('install', '-e', '%s/@174#egg=django-wikiapp' % local_checkout('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1'), expect_error=True) result.assert_installed('django-wikiapp', with_files=['.bzr']) def test_vcs_url_urlquote_normalization(): """ Test that urlquoted characters are normalized for repo URL comparison. """ reset_env() result = run_pip('install', '-e', '%s/#egg=django-wikiapp' % local_checkout('bzr+http://bazaar.launchpad.net/%7Edjango-wikiapp/django-wikiapp/release-0.1'), expect_error=True) assert 'pip-log.txt' not in result.files_created, result.files_created['pip-log.txt'].bytes def test_install_from_local_directory(): """ Test installing from a local directory. """ env = reset_env() to_install = abspath(join(here, 'packages', 'FSPkg')) result = run_pip('install', to_install, expect_error=False) fspkg_folder = env.site_packages/'fspkg' egg_info_folder = env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion assert fspkg_folder in result.files_created, str(result.stdout) assert egg_info_folder in result.files_created, str(result) def test_install_from_local_directory_with_no_setup_py(): """ Test installing from a local directory with no 'setup.py'. """ reset_env() result = run_pip('install', here, expect_error=True) assert len(result.files_created) == 1, result.files_created assert 'pip-log.txt' in result.files_created, result.files_created assert "is not installable. File 'setup.py' not found." in result.stdout def test_install_curdir(): """ Test installing current directory ('.'). """ env = reset_env() run_from = abspath(join(here, 'packages', 'FSPkg')) # Python 2.4 Windows balks if this exists already egg_info = join(run_from, "FSPkg.egg-info") if os.path.isdir(egg_info): rmtree(egg_info) result = run_pip('install', curdir, cwd=run_from, expect_error=False) fspkg_folder = env.site_packages/'fspkg' egg_info_folder = env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion assert fspkg_folder in result.files_created, str(result.stdout) assert egg_info_folder in result.files_created, str(result) def test_install_curdir_usersite_fails_in_old_python(): """ Test --user option on older Python versions (pre 2.6) fails intelligibly """ if sys.version_info >= (2, 6): raise SkipTest() reset_env() run_from = abspath(join(here, 'packages', 'FSPkg')) result = run_pip('install', '--user', curdir, cwd=run_from, expect_error=True) assert '--user is only supported in Python version 2.6 and newer' in result.stdout def test_install_curdir_usersite(): """ Test installing current directory ('.') into usersite """ if sys.version_info < (2, 6): raise SkipTest() # FIXME distutils --user option seems to be broken in pypy if hasattr(sys, "pypy_version_info"): raise SkipTest() env = reset_env(use_distribute=True) run_from = abspath(join(here, 'packages', 'FSPkg')) result = run_pip('install', '--user', curdir, cwd=run_from, expect_error=False) fspkg_folder = env.user_site/'fspkg' egg_info_folder = env.user_site/'FSPkg-0.1dev-py%s.egg-info' % pyversion assert fspkg_folder in result.files_created, str(result.stdout) assert egg_info_folder in result.files_created, str(result) def test_install_subversion_usersite_editable_with_distribute(): """ Test installing current directory ('.') into usersite after installing distribute """ if sys.version_info < (2, 6): raise SkipTest() # FIXME distutils --user option seems to be broken in pypy if hasattr(sys, "pypy_version_info"): raise SkipTest() env = reset_env(use_distribute=True) (env.lib_path/'no-global-site-packages.txt').rm() # this one reenables user_site result = run_pip('install', '--user', '-e', '%s#egg=initools-dev' % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk')) result.assert_installed('INITools', use_user_site=True) def test_install_subversion_usersite_editable_with_setuptools_fails(): """ Test installing current directory ('.') into usersite using setuptools fails """ # --user only works on 2.6 or higher if sys.version_info < (2, 6): raise SkipTest() # We don't try to use setuptools for 3.X. elif sys.version_info >= (3,): raise SkipTest() env = reset_env(use_distribute=False) no_site_packages = env.lib_path/'no-global-site-packages.txt' if os.path.isfile(no_site_packages): no_site_packages.rm() # this re-enables user_site result = run_pip('install', '--user', '-e', '%s#egg=initools-dev' % local_checkout('svn+http://svn.colorstudy.com/INITools/trunk'), expect_error=True) assert '--user --editable not supported with setuptools, use distribute' in result.stdout def test_install_pardir(): """ Test installing parent directory ('..'). """ env = reset_env() run_from = abspath(join(here, 'packages', 'FSPkg', 'fspkg')) result = run_pip('install', pardir, cwd=run_from, expect_error=False) fspkg_folder = env.site_packages/'fspkg' egg_info_folder = env.site_packages/'FSPkg-0.1dev-py%s.egg-info' % pyversion assert fspkg_folder in result.files_created, str(result.stdout) assert egg_info_folder in result.files_created, str(result) def test_install_global_option(): """ Test using global distutils options. (In particular those that disable the actual install action) """ reset_env() result = run_pip('install', '--global-option=--version', "INITools==0.1") assert '0.1\n' in result.stdout def test_install_with_pax_header(): """ test installing from a tarball with pax header for python<2.6 """ reset_env() run_from = abspath(join(here, 'packages')) run_pip('install', 'paxpkg.tar.bz2', cwd=run_from) def test_install_using_install_option_and_editable(): """ Test installing a tool using -e and --install-option """ env = reset_env() folder = 'script_folder' mkdir(folder) url = 'git+git://github.com/pypa/virtualenv' result = run_pip('install', '-e', '%s#egg=virtualenv' % local_checkout(url), '--install-option=--script-dir=%s' % folder) virtualenv_bin = env.venv/'src'/'virtualenv'/folder/'virtualenv'+env.exe assert virtualenv_bin in result.files_created def test_install_global_option_using_editable(): """ Test using global distutils options, but in an editable installation """ reset_env() url = 'hg+http://bitbucket.org/runeh/anyjson' result = run_pip('install', '--global-option=--version', '-e', '%s@0.2.5#egg=anyjson' % local_checkout(url)) assert '0.2.5\n' in result.stdout def test_install_package_with_same_name_in_curdir(): """ Test installing a package with the same name of a local folder """ env = reset_env() mkdir('mock==0.6') result = run_pip('install', 'mock==0.6') egg_folder = env.site_packages / 'mock-0.6.0-py%s.egg-info' % pyversion assert egg_folder in result.files_created, str(result) mock100_setup_py = textwrap.dedent('''\ from setuptools import setup setup(name='mock', version='100.1')''') def test_install_folder_using_dot_slash(): """ Test installing a folder using pip install ./foldername """ env = reset_env() mkdir('mock') pkg_path = env.scratch_path/'mock' write_file('setup.py', mock100_setup_py, pkg_path) result = run_pip('install', './mock') egg_folder = env.site_packages / 'mock-100.1-py%s.egg-info' % pyversion assert egg_folder in result.files_created, str(result) def test_install_folder_using_slash_in_the_end(): r""" Test installing a folder using pip install foldername/ or foldername\ """ env = reset_env() mkdir('mock') pkg_path = env.scratch_path/'mock' write_file('setup.py', mock100_setup_py, pkg_path) result = run_pip('install', 'mock' + os.path.sep) egg_folder = env.site_packages / 'mock-100.1-py%s.egg-info' % pyversion assert egg_folder in result.files_created, str(result) def test_install_folder_using_relative_path(): """ Test installing a folder using pip install folder1/folder2 """ env = reset_env() mkdir('initools') mkdir(Path('initools')/'mock') pkg_path = env.scratch_path/'initools'/'mock' write_file('setup.py', mock100_setup_py, pkg_path) result = run_pip('install', Path('initools')/'mock') egg_folder = env.site_packages / 'mock-100.1-py%s.egg-info' % pyversion assert egg_folder in result.files_created, str(result) def test_install_package_which_contains_dev_in_name(): """ Test installing package from pypi which contains 'dev' in name """ env = reset_env() result = run_pip('install', 'django-devserver==0.0.4') devserver_folder = env.site_packages/'devserver' egg_info_folder = env.site_packages/'django_devserver-0.0.4-py%s.egg-info' % pyversion assert devserver_folder in result.files_created, str(result.stdout) assert egg_info_folder in result.files_created, str(result) def test_install_package_with_target(): """ Test installing a package using pip install --target """ env = reset_env() target_dir = env.scratch_path/'target' result = run_pip('install', '-t', target_dir, "initools==0.1") assert Path('scratch')/'target'/'initools' in result.files_created, str(result) def test_find_command_folder_in_path(): """ If a folder named e.g. 'git' is in PATH, and find_command is looking for the 'git' executable, it should not match the folder, but rather keep looking. """ env = reset_env() mkdir('path_one') path_one = env.scratch_path/'path_one' mkdir(path_one/'foo') mkdir('path_two') path_two = env.scratch_path/'path_two' write_file(path_two/'foo', '# nothing') found_path = find_command('foo', map(str, [path_one, path_two])) assert found_path == path_two/'foo' def test_does_not_find_command_because_there_is_no_path(): """ Test calling `pip.utils.find_command` when there is no PATH env variable """ environ_before = os.environ os.environ = {} try: try: find_command('anycommand') except BadCommand: e = sys.exc_info()[1] assert e.args == ("Cannot find command 'anycommand'",) else: raise AssertionError("`find_command` should raise `BadCommand`") finally: os.environ = environ_before @patch('os.pathsep', ':') @patch('pip.util.get_pathext') @patch('os.path.isfile') def test_find_command_trys_all_pathext(mock_isfile, getpath_mock): """ If no pathext should check default list of extensions, if file does not exist. """ mock_isfile.return_value = False getpath_mock.return_value = os.pathsep.join([".COM", ".EXE"]) paths = [os.path.join('path_one', f) for f in ['foo.com', 'foo.exe', 'foo']] expected = [((p,),) for p in paths] assert_raises(BadCommand, find_command, 'foo', 'path_one') assert mock_isfile.call_args_list == expected, "Actual: %s\nExpected %s" % (mock_isfile.call_args_list, expected) assert getpath_mock.called, "Should call get_pathext" @patch('os.pathsep', ':') @patch('pip.util.get_pathext') @patch('os.path.isfile') def test_find_command_trys_supplied_pathext(mock_isfile, getpath_mock): """ If pathext supplied find_command should use all of its list of extensions to find file. """ mock_isfile.return_value = False getpath_mock.return_value = ".FOO" pathext = os.pathsep.join([".RUN", ".CMD"]) paths = [os.path.join('path_one', f) for f in ['foo.run', 'foo.cmd', 'foo']] expected = [((p,),) for p in paths] assert_raises(BadCommand, find_command, 'foo', 'path_one', pathext) assert mock_isfile.call_args_list == expected, "Actual: %s\nExpected %s" % (mock_isfile.call_args_list, expected) assert not getpath_mock.called, "Should not call get_pathext"