2013-03-27 06:26:52 +01:00
|
|
|
import os
|
|
|
|
import shutil
|
2013-05-01 01:02:10 +02:00
|
|
|
import tempfile
|
2013-03-27 06:26:52 +01:00
|
|
|
|
2013-08-18 11:59:44 +02:00
|
|
|
import pytest
|
|
|
|
|
2013-11-21 11:06:27 +01:00
|
|
|
from mock import Mock, patch, mock_open
|
2014-01-28 15:17:51 +01:00
|
|
|
from pip.exceptions import (
|
|
|
|
PreviousBuildDirError, InvalidWheelFilename, UnsupportedWheel,
|
|
|
|
)
|
2014-05-07 01:25:44 +02:00
|
|
|
from pip.download import PipSession
|
2014-05-26 06:00:39 +02:00
|
|
|
from pip._vendor import pkg_resources
|
2013-03-27 06:26:52 +01:00
|
|
|
from pip.index import PackageFinder
|
2013-05-01 00:30:15 +02:00
|
|
|
from pip.log import logger
|
2014-01-12 19:05:11 +01:00
|
|
|
from pip.req import (InstallRequirement, RequirementSet,
|
|
|
|
Requirements, parse_requirements)
|
|
|
|
from pip.req.req_install import parse_editable
|
|
|
|
from pip.util import read_text_file
|
2013-08-23 13:12:37 +02:00
|
|
|
from tests.lib import assert_raises_regexp
|
2013-03-27 06:26:52 +01:00
|
|
|
|
2013-05-01 01:02:10 +02:00
|
|
|
|
2013-03-27 06:26:52 +01:00
|
|
|
class TestRequirementSet(object):
|
|
|
|
"""RequirementSet tests"""
|
|
|
|
|
|
|
|
def setup(self):
|
2013-05-01 01:02:10 +02:00
|
|
|
logger.consumers = [(logger.NOTIFY, Mock())]
|
2013-03-27 06:26:52 +01:00
|
|
|
self.tempdir = tempfile.mkdtemp()
|
|
|
|
|
|
|
|
def teardown(self):
|
2013-05-01 00:30:15 +02:00
|
|
|
logger.consumers = []
|
2013-03-27 06:26:52 +01:00
|
|
|
shutil.rmtree(self.tempdir, ignore_errors=True)
|
|
|
|
|
2013-06-13 08:36:16 +02:00
|
|
|
def basic_reqset(self):
|
2013-03-27 06:26:52 +01:00
|
|
|
return RequirementSet(
|
|
|
|
build_dir=os.path.join(self.tempdir, 'build'),
|
|
|
|
src_dir=os.path.join(self.tempdir, 'src'),
|
|
|
|
download_dir=None,
|
2014-05-07 01:25:44 +02:00
|
|
|
session=PipSession(),
|
2014-02-24 22:52:23 +01:00
|
|
|
)
|
2013-03-27 06:26:52 +01:00
|
|
|
|
2013-08-23 13:49:04 +02:00
|
|
|
def test_no_reuse_existing_build_dir(self, data):
|
2013-03-27 06:26:52 +01:00
|
|
|
"""Test prepare_files raise exception with previous build dir"""
|
|
|
|
|
|
|
|
build_dir = os.path.join(self.tempdir, 'build', 'simple')
|
|
|
|
os.makedirs(build_dir)
|
|
|
|
open(os.path.join(build_dir, "setup.py"), 'w')
|
|
|
|
reqset = self.basic_reqset()
|
|
|
|
req = InstallRequirement.from_line('simple')
|
|
|
|
reqset.add_requirement(req)
|
2014-05-07 01:25:44 +02:00
|
|
|
finder = PackageFinder([data.find_links], [], session=PipSession())
|
2013-03-27 06:26:52 +01:00
|
|
|
assert_raises_regexp(
|
|
|
|
PreviousBuildDirError,
|
2014-01-28 15:17:51 +01:00
|
|
|
"pip can't proceed with [\s\S]*%s[\s\S]*%s" %
|
|
|
|
(req, build_dir.replace('\\', '\\\\')),
|
2013-03-27 06:26:52 +01:00
|
|
|
reqset.prepare_files,
|
2014-02-24 22:52:23 +01:00
|
|
|
finder,
|
|
|
|
)
|
2013-03-27 06:26:52 +01:00
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
|
2013-11-21 11:06:27 +01:00
|
|
|
@pytest.mark.parametrize(('file_contents', 'expected'), [
|
|
|
|
(b'\xf6\x80', b'\xc3\xb6\xe2\x82\xac'), # cp1252
|
|
|
|
(b'\xc3\xb6\xe2\x82\xac', b'\xc3\xb6\xe2\x82\xac'), # utf-8
|
|
|
|
(b'\xc3\xb6\xe2', b'\xc3\x83\xc2\xb6\xc3\xa2'), # Garbage
|
|
|
|
])
|
|
|
|
def test_egg_info_data(file_contents, expected):
|
|
|
|
om = mock_open(read_data=file_contents)
|
|
|
|
em = Mock()
|
|
|
|
em.return_value = 'cp1252'
|
2014-01-12 19:05:11 +01:00
|
|
|
with patch('pip.util.open', om, create=True):
|
2013-11-21 13:28:50 +01:00
|
|
|
with patch('locale.getpreferredencoding', em):
|
|
|
|
ret = read_text_file('foo')
|
2013-11-21 11:06:27 +01:00
|
|
|
assert ret == expected.decode('utf-8')
|
|
|
|
|
|
|
|
|
2013-11-15 01:35:24 +01:00
|
|
|
class TestInstallRequirement(object):
|
2013-05-28 23:58:08 +02:00
|
|
|
|
2013-11-15 01:35:24 +01:00
|
|
|
def test_url_with_query(self):
|
|
|
|
"""InstallRequirement should strip the fragment, but not the query."""
|
|
|
|
url = 'http://foo.com/?p=bar.git;a=snapshot;h=v0.1;sf=tgz'
|
|
|
|
fragment = '#egg=bar'
|
|
|
|
req = InstallRequirement.from_line(url + fragment)
|
|
|
|
assert req.url == url, req.url
|
|
|
|
|
|
|
|
def test_unsupported_wheel_requirement_raises(self):
|
|
|
|
with pytest.raises(UnsupportedWheel):
|
2014-01-28 15:17:51 +01:00
|
|
|
InstallRequirement.from_line(
|
|
|
|
'peppercorn-0.4-py2.py3-bogus-any.whl',
|
|
|
|
)
|
2013-11-15 01:35:24 +01:00
|
|
|
|
|
|
|
def test_invalid_wheel_requirement_raises(self):
|
|
|
|
with pytest.raises(InvalidWheelFilename):
|
2014-01-28 15:17:51 +01:00
|
|
|
InstallRequirement.from_line('invalid.whl')
|
2013-05-28 23:58:08 +02:00
|
|
|
|
2014-05-26 06:00:39 +02:00
|
|
|
def test_wheel_requirement_sets_req_attribute(self):
|
|
|
|
req = InstallRequirement.from_line('simple-0.1-py2.py3-none-any.whl')
|
|
|
|
assert req.req == pkg_resources.Requirement.parse('simple==0.1')
|
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
|
|
|
|
def test_requirements_data_structure_keeps_order():
|
|
|
|
requirements = Requirements()
|
|
|
|
requirements['pip'] = 'pip'
|
|
|
|
requirements['nose'] = 'nose'
|
|
|
|
requirements['coverage'] = 'coverage'
|
|
|
|
|
|
|
|
assert ['pip', 'nose', 'coverage'] == list(requirements.values())
|
|
|
|
assert ['pip', 'nose', 'coverage'] == list(requirements.keys())
|
|
|
|
|
|
|
|
|
|
|
|
def test_requirements_data_structure_implements__repr__():
|
|
|
|
requirements = Requirements()
|
|
|
|
requirements['pip'] = 'pip'
|
|
|
|
requirements['nose'] = 'nose'
|
|
|
|
|
|
|
|
assert "Requirements({'pip': 'pip', 'nose': 'nose'})" == repr(requirements)
|
|
|
|
|
|
|
|
|
|
|
|
def test_requirements_data_structure_implements__contains__():
|
|
|
|
requirements = Requirements()
|
|
|
|
requirements['pip'] = 'pip'
|
|
|
|
|
|
|
|
assert 'pip' in requirements
|
|
|
|
assert 'nose' not in requirements
|
|
|
|
|
2014-01-28 15:17:51 +01:00
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
@patch('os.path.normcase')
|
2014-01-12 19:05:11 +01:00
|
|
|
@patch('pip.req.req_install.os.getcwd')
|
|
|
|
@patch('pip.req.req_install.os.path.exists')
|
|
|
|
@patch('pip.req.req_install.os.path.isdir')
|
2014-01-28 15:17:51 +01:00
|
|
|
def test_parse_editable_local(
|
|
|
|
isdir_mock, exists_mock, getcwd_mock, normcase_mock):
|
2013-05-28 23:58:08 +02:00
|
|
|
exists_mock.return_value = isdir_mock.return_value = True
|
|
|
|
# mocks needed to support path operations on windows tests
|
|
|
|
normcase_mock.return_value = getcwd_mock.return_value = "/some/path"
|
2013-08-18 11:59:44 +02:00
|
|
|
assert parse_editable('.', 'git') == (None, 'file:///some/path', None)
|
2013-05-28 23:58:08 +02:00
|
|
|
normcase_mock.return_value = "/some/path/foo"
|
2014-01-28 15:17:51 +01:00
|
|
|
assert parse_editable('foo', 'git') == (
|
|
|
|
None, 'file:///some/path/foo', None,
|
|
|
|
)
|
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
|
|
|
|
def test_parse_editable_default_vcs():
|
2014-01-28 15:17:51 +01:00
|
|
|
assert parse_editable('https://foo#egg=foo', 'git') == (
|
|
|
|
'foo',
|
|
|
|
'git+https://foo#egg=foo',
|
|
|
|
{'egg': 'foo'},
|
|
|
|
)
|
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
|
|
|
|
def test_parse_editable_explicit_vcs():
|
2014-01-28 15:17:51 +01:00
|
|
|
assert parse_editable('svn+https://foo#egg=foo', 'git') == (
|
|
|
|
'foo',
|
|
|
|
'svn+https://foo#egg=foo',
|
|
|
|
{'egg': 'foo'},
|
|
|
|
)
|
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
|
|
|
|
def test_parse_editable_vcs_extras():
|
2014-01-28 15:17:51 +01:00
|
|
|
assert parse_editable('svn+https://foo#egg=foo[extras]', 'git') == (
|
|
|
|
'foo[extras]',
|
|
|
|
'svn+https://foo#egg=foo[extras]',
|
|
|
|
{'egg': 'foo[extras]'},
|
|
|
|
)
|
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
|
|
|
|
@patch('os.path.normcase')
|
2014-01-12 19:05:11 +01:00
|
|
|
@patch('pip.req.req_install.os.getcwd')
|
|
|
|
@patch('pip.req.req_install.os.path.exists')
|
|
|
|
@patch('pip.req.req_install.os.path.isdir')
|
2014-01-28 15:17:51 +01:00
|
|
|
def test_parse_editable_local_extras(
|
|
|
|
isdir_mock, exists_mock, getcwd_mock, normcase_mock):
|
2013-05-28 23:58:08 +02:00
|
|
|
exists_mock.return_value = isdir_mock.return_value = True
|
|
|
|
normcase_mock.return_value = getcwd_mock.return_value = "/some/path"
|
2014-01-28 15:17:51 +01:00
|
|
|
assert parse_editable('.[extras]', 'git') == (
|
|
|
|
None, 'file://' + "/some/path", ('extras',),
|
|
|
|
)
|
2013-05-28 23:58:08 +02:00
|
|
|
normcase_mock.return_value = "/some/path/foo"
|
2014-01-28 15:17:51 +01:00
|
|
|
assert parse_editable('foo[bar,baz]', 'git') == (
|
|
|
|
None, 'file:///some/path/foo', ('bar', 'baz'),
|
|
|
|
)
|
|
|
|
|
2013-05-28 23:58:08 +02:00
|
|
|
|
|
|
|
def test_remote_reqs_parse():
|
|
|
|
"""
|
|
|
|
Test parsing a simple remote requirements file
|
|
|
|
"""
|
|
|
|
# this requirements file just contains a comment
|
2014-01-28 15:17:51 +01:00
|
|
|
# previously this has failed in py3: https://github.com/pypa/pip/issues/760
|
|
|
|
for req in parse_requirements(
|
2014-05-07 01:35:18 +02:00
|
|
|
'https://raw.githubusercontent.com/pypa/pip-test-package/master/'
|
2014-05-07 01:25:44 +02:00
|
|
|
'tests/req_just_comment.txt', session=PipSession()):
|
2013-05-28 23:58:08 +02:00
|
|
|
pass
|
2013-06-07 04:11:43 +02:00
|
|
|
|
2014-01-28 15:17:51 +01:00
|
|
|
|
2014-06-10 14:55:57 +02:00
|
|
|
def test_req_file_parse_no_use_wheel(data):
|
2013-06-07 04:11:43 +02:00
|
|
|
"""
|
2014-06-10 14:55:57 +02:00
|
|
|
Test parsing --no-use-wheel from a req file
|
2013-06-07 04:11:43 +02:00
|
|
|
"""
|
2014-05-07 01:25:44 +02:00
|
|
|
finder = PackageFinder([], [], session=PipSession())
|
2014-01-28 15:17:51 +01:00
|
|
|
for req in parse_requirements(
|
2014-05-07 01:25:44 +02:00
|
|
|
data.reqfiles.join("supported_options.txt"), finder,
|
|
|
|
session=PipSession()):
|
2013-06-07 04:11:43 +02:00
|
|
|
pass
|
2014-06-10 14:55:57 +02:00
|
|
|
assert not finder.use_wheel
|
2014-01-23 03:50:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_req_file_parse_comment_start_of_line(tmpdir):
|
|
|
|
"""
|
|
|
|
Test parsing comments in a requirements file
|
|
|
|
"""
|
|
|
|
with open(tmpdir.join("req1.txt"), "w") as fp:
|
|
|
|
fp.write("# Comment ")
|
|
|
|
|
2014-05-07 01:25:44 +02:00
|
|
|
finder = PackageFinder([], [], session=PipSession())
|
|
|
|
reqs = list(parse_requirements(tmpdir.join("req1.txt"), finder,
|
|
|
|
session=PipSession()))
|
2014-01-23 03:50:57 +01:00
|
|
|
|
|
|
|
assert not reqs
|
|
|
|
|
|
|
|
|
|
|
|
def test_req_file_parse_comment_end_of_line_with_url(tmpdir):
|
|
|
|
"""
|
|
|
|
Test parsing comments in a requirements file
|
|
|
|
"""
|
|
|
|
with open(tmpdir.join("req1.txt"), "w") as fp:
|
|
|
|
fp.write("https://example.com/foo.tar.gz # Comment ")
|
|
|
|
|
2014-05-07 01:25:44 +02:00
|
|
|
finder = PackageFinder([], [], session=PipSession())
|
|
|
|
reqs = list(parse_requirements(tmpdir.join("req1.txt"), finder,
|
|
|
|
session=PipSession()))
|
2014-01-23 03:50:57 +01:00
|
|
|
|
|
|
|
assert len(reqs) == 1
|
|
|
|
assert reqs[0].url == "https://example.com/foo.tar.gz"
|
|
|
|
|
|
|
|
|
|
|
|
def test_req_file_parse_egginfo_end_of_line_with_url(tmpdir):
|
|
|
|
"""
|
|
|
|
Test parsing comments in a requirements file
|
|
|
|
"""
|
|
|
|
with open(tmpdir.join("req1.txt"), "w") as fp:
|
|
|
|
fp.write("https://example.com/foo.tar.gz#egg=wat")
|
|
|
|
|
2014-05-07 01:25:44 +02:00
|
|
|
finder = PackageFinder([], [], session=PipSession())
|
|
|
|
reqs = list(parse_requirements(tmpdir.join("req1.txt"), finder,
|
|
|
|
session=PipSession()))
|
2014-01-23 03:50:57 +01:00
|
|
|
|
|
|
|
assert len(reqs) == 1
|
|
|
|
assert reqs[0].name == "wat"
|