diff options
-rw-r--r-- | doc/config.txt | 14 | ||||
-rw-r--r-- | doc/example/basic.txt | 24 | ||||
-rw-r--r-- | tests/conftest.py | 28 | ||||
-rw-r--r-- | tests/test_config.py | 40 | ||||
-rw-r--r-- | tests/test_venv.py | 61 | ||||
-rw-r--r-- | tox.ini | 6 | ||||
-rw-r--r-- | tox/_config.py | 18 | ||||
-rw-r--r-- | tox/_venv.py | 38 |
8 files changed, 158 insertions, 71 deletions
diff --git a/doc/config.txt b/doc/config.txt index fae93f2..f9cf80f 100644 --- a/doc/config.txt +++ b/doc/config.txt @@ -19,6 +19,7 @@ List of optional global options:: distdir=path # defaults to {toxworkdir}/dist distshare=path # defaults to {homedir}/.tox/distshare envlist=ENVLIST # defaults to the list of all environments + ``tox`` autodetects if it is running in a Hudson_ context (by checking for existence of the ``HUDSON_URL`` environment variable) @@ -27,7 +28,15 @@ and will first lookup global tox settings in this section:: [tox:hudson] ... # override [tox] settings for the hudson context # note: for hudson distshare defaults to ``{toxworkdir}/distshare``. + +.. confval:: indexserver= + name URL + name URL + ... + Definition of "name -> URL" mappings which can be used in + dependency specifications to install packages from different + indexservers. envlist setting +++++++++++++++++++++++++ @@ -104,11 +113,6 @@ Complete list of settings that you can put into ``testenv*`` sections: passed to easy_install/pip for processing. It usually can be a file, and URL or a package name. -.. confval:: indexserver=URL - - The Index server to use. When nothing is specified the default - of the installation tool (easy_install or pip) will be used. - .. confval:: upgrade=True|False(default) Install dependencies in "upgrade" mode by passing upgrade flag to install tools. diff --git a/doc/example/basic.txt b/doc/example/basic.txt index f46b401..c3b4de6 100644 --- a/doc/example/basic.txt +++ b/doc/example/basic.txt @@ -51,13 +51,35 @@ using a different PyPI server .. versionadded: 0.9 To install dependencies and packages from a different -PyPI servertype:: +PyPI server type:: tox --indexserver http://pypi.testrun.org This causes both the internal pip and easy-install steps to use the specified server for upgrading. +installing dependencies from multiple PyPI server +--------------------------------------------------- + +.. versionadded: 0.9 + +You can instrument tox to install dependencies from +different PyPI servers, example:: + + [tox] + indexserver = + DEV http://mypypiserver.org + + [testenv] + deps = + docutils # comes from standard PyPI + DEV mypackage # will come from custom PYPI above + +Note that the ``--indexserver`` command line overrides +the default index server, not the ``DEV`` one here. +This will cause both the internal pip and easy-install steps +to use the specified servers accordingly. + upgrading packages ----------------------------------------------- diff --git a/tests/conftest.py b/tests/conftest.py index b1e57db..0e5d367 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,6 +6,7 @@ from py.builtin import print_ from fnmatch import fnmatch import time from tox._config import parseconfig +from tox._venv import VirtualEnv def pytest_configure(): if 'TOXENV' in os.environ: @@ -82,6 +83,7 @@ def pytest_funcarg__mocksession(request): class MockSession(Session): def __init__(self): self._clearmocks() + #self.config = request.getfuncargvalue("newconfig")([], "") def _clearmocks(self): self._pcalls = [] self.report = ReportExpectMock() @@ -91,6 +93,32 @@ def pytest_funcarg__mocksession(request): self._pcalls.append(pcallMock(args, log, cwd, env)) return MockSession() +def pytest_funcarg__mocksession(request): + from tox._cmdline import Session + class MockSession(Session): + def __init__(self): + self._clearmocks() + #self.config = request.getfuncargvalue("newconfig")([], "") + def getenv(self, name): + return VirtualEnv(self.config.envconfigs[name], session=self) + def _clearmocks(self): + self._pcalls = [] + self.report = ReportExpectMock() + def make_emptydir(self, path): + pass + def pcall(self, args, log, cwd, env=None): + self._pcalls.append(pcallMock(args, log, cwd, env)) + return MockSession() + +def pytest_funcarg__newmocksession(request): + mocksession = request.getfuncargvalue("mocksession") + newconfig = request.getfuncargvalue("newconfig") + def newmocksession(args, source): + config = newconfig(args, source) + mocksession.config = config + return mocksession + return newmocksession + class Cmd: def __init__(self, request): self.tmpdir = request.getfuncargvalue("tmpdir") diff --git a/tests/test_config.py b/tests/test_config.py index 85592bf..58ed2c8 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -25,7 +25,7 @@ class TestVenvConfig: basepython=hello deps= world1 - world2 + xyz world2 """ % (tmpdir, )) assert config.toxworkdir == tmpdir assert len(config.envconfigs) == 2 @@ -34,7 +34,7 @@ class TestVenvConfig: assert config.envconfigs['py1'].deps == ['hello'] assert config.envconfigs['py2'].basepython == "hello" assert config.envconfigs['py2'].envdir == tmpdir.join("py2") - assert config.envconfigs['py2'].deps == ['world1', 'world2'] + assert config.envconfigs['py2'].deps == ['world1', 'xyz world2'] class TestConfigPackage: def test_defaults(self, tmpdir, newconfig): @@ -43,7 +43,6 @@ class TestConfigPackage: assert config.toxworkdir == tmpdir.join(".tox") envconfig = config.envconfigs['python'] assert envconfig.args_are_paths - assert not envconfig.indexserver assert not envconfig.upgrade def test_defaults_distshare(self, tmpdir, newconfig): @@ -265,15 +264,6 @@ class TestConfigTestEnv: assert envconfig.changedir.basename == "xyz" assert envconfig.changedir == config.toxinidir.join("xyz") - def test_indexurl(self, tmpdir, newconfig): - config = newconfig(""" - [testenv] - indexserver = XYZ - """) - assert len(config.envconfigs) == 1 - envconfig = config.envconfigs['python'] - assert envconfig.indexserver == "XYZ" - def test_envbindir(self, tmpdir, newconfig): config = newconfig(""" [testenv] @@ -497,16 +487,32 @@ class TestGlobalOptions: assert env.basepython == "python2.4" assert env.commands == [['xyz']] -class TestParseEnv: +class TestIndexServer: + def test_indexserver(self, tmpdir, newconfig): + config = newconfig(""" + [tox] + indexserver = + name1 XYZ + name2 ABC + """) + assert config.indexserver['default'] == None + assert config.indexserver['name1'] == "XYZ" + assert config.indexserver['name2'] == "ABC" + def test_parse_indexserver(self, newconfig): inisource = """ - [testenv:hello] - indexserver = XYZ + [tox] + indexserver = + default http://pypi.testrun.org + name2 XYZ """ config = newconfig([], inisource) - assert config.envconfigs['hello'].indexserver == "XYZ" + assert config.indexserver['default'] == "http://pypi.testrun.org" config = newconfig(["--indexserver", "ABC"], inisource) - assert config.envconfigs['hello'].indexserver == "ABC" + assert config.indexserver['default'] == "ABC" + assert config.indexserver['name2'] == "XYZ" + +class TestParseEnv: def test_parse_upgrade(self, newconfig): inisource = "" diff --git a/tests/test_venv.py b/tests/test_venv.py index 7e49b58..1c0602d 100644 --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -119,16 +119,15 @@ def test_create_sitepackages(monkeypatch, mocksession, newconfig): assert "--no-site-packages" in " ".join(args) @py.test.mark.skipif("sys.version_info[0] >= 3") -def test_install_downloadcache(mocksession, newconfig): - config = newconfig([], """ +def test_install_downloadcache(newmocksession): + mocksession = newmocksession([], """ [testenv:py123] distribute=True deps= dep1 dep2 """) - envconfig = config.envconfigs['py123'] - venv = VirtualEnv(envconfig, session=mocksession) + venv = mocksession.getenv("py123") venv.create() l = mocksession._pcalls assert len(l) == 1 @@ -139,40 +138,47 @@ def test_install_downloadcache(mocksession, newconfig): assert l[1].cwd == venv.envconfig.envlogdir assert "pip" in str(args[0]) assert args[1] == "install" - arg = "--download-cache=" + str(envconfig.downloadcache) + arg = "--download-cache=" + str(venv.envconfig.downloadcache) assert arg in args[2:] assert "dep1" in args assert "dep2" in args deps = filter(None, [x[1] for x in venv._getliveconfig().deps]) assert deps == ['dep1', 'dep2'] -def test_install_indexserver(mocksession, newconfig): - config = newconfig([], """ +def test_install_indexserver(newmocksession): + mocksession = newmocksession([], """ + [tox] + indexserver= + abc ABC + [testenv:py123] - indexserver=XYZ - deps= dep1 + deps= + dep1 + abc dep2 """) - envconfig = config.envconfigs['py123'] - venv = VirtualEnv(envconfig, session=mocksession) + venv = mocksession.getenv('py123') venv.create() l = mocksession._pcalls assert len(l) == 1 + l[:] = [] venv.install_deps() + # two different index servers, two calls assert len(l) == 2 - args = l[1].args + args = " ".join(l[0].args) + assert "-i" not in args + assert "dep1" in args - i = args.index('-i') - assert i != -1 - assert args[i+1] == "XYZ" + args = " ".join(l[1].args) + assert "-i ABC" in args + assert "dep2" in args -def test_install_upgrade(mocksession, newconfig): - config = newconfig(['--upgrade'], """ +def test_install_upgrade(newmocksession): + mocksession = newmocksession(['--upgrade'], """ [testenv] deps=xyz """) - envconfig = config.envconfigs['python'] - venv = VirtualEnv(envconfig, session=mocksession) + venv = mocksession.getenv('python') venv.create() l = mocksession._pcalls assert len(l) == 1 @@ -181,18 +187,17 @@ def test_install_upgrade(mocksession, newconfig): assert len(l) == 2 assert '-U' in l[1].args -def test_install_python3(tmpdir, mocksession, newconfig): +def test_install_python3(tmpdir, newmocksession): if not py.path.local.sysfind('python3.1'): py.test.skip("needs python3.1") - config = newconfig([], """ + mocksession = newmocksession([], """ [testenv:py123] basepython=python3.1 deps= dep1 dep2 """) - envconfig = config.envconfigs['py123'] - venv = VirtualEnv(envconfig, session=mocksession) + venv = mocksession.getenv('py123') venv.create() l = mocksession._pcalls assert len(l) == 1 @@ -317,13 +322,13 @@ class TestCreationConfig: class TestVenvTest: - def test_patchPATH(self, newconfig, mocksession, monkeypatch): - config = newconfig([], """ + def test_patchPATH(self, newmocksession, monkeypatch): + mocksession = newmocksession([], """ [testenv:python] commands=abc """) - envconfig = config.envconfigs['python'] - venv = VirtualEnv(envconfig, session=mocksession) + venv = mocksession.getenv("python") + envconfig = venv.envconfig monkeypatch.setenv("PATH", "xyz") oldpath = venv.patchPATH() assert oldpath == "xyz" @@ -337,7 +342,7 @@ class TestVenvTest: assert envconfig.commands monkeypatch.setattr(venv, '_pcall', lambda *args, **kwargs: 0/0) - py.test.raises(ZeroDivisionError, "venv._install([1,2,3])") + py.test.raises(ZeroDivisionError, "venv._install(list('123'))") py.test.raises(ZeroDivisionError, "venv.test()") py.test.raises(ZeroDivisionError, "venv.easy_install(['qwe'])") py.test.raises(ZeroDivisionError, "venv.pip_install(['qwe'])") @@ -1,10 +1,12 @@ [tox] envlist=py27,py26,py25,py24,py31,docs +indexserver= + dev http://pypi.testrun.org [testenv] -indexserver=http://pypi.testrun.org commands=py.test --junitxml={envlogdir}/junit-{envname}.xml [] -deps=pytest +deps= + dev pytest [testenv:docs] basepython=python diff --git a/tox/_config.py b/tox/_config.py index ec15194..9e17582 100644 --- a/tox/_config.py +++ b/tox/_config.py @@ -58,7 +58,8 @@ def prepare_parse(): parser.add_argument("--sdistonly", action="store_true", dest="sdistonly", help="only perform the sdist activity.") parser.add_argument("--indexserver", action="store", dest="indexserver", - help="use the specified PyPI indexserver for installation actions") + default=None, metavar="URL", + help="indexserver for installing deps (default pypi python.org"), parser.add_argument("-U", "--upgrade", action="store_true", dest="upgrade", help="try to upgrade dependencies in installation step") parser.add_argument("args", nargs="*", @@ -122,6 +123,17 @@ class parseini: homedir=config.homedir) config.toxworkdir = reader.getpath(toxsection, "toxworkdir", "{toxinidir}/.tox") + + # determine indexserver dictionary + config.indexserver = d = {} + for line in reader.getlist(toxsection, "indexserver"): + name, value = line.strip().split(None, 1) + d.setdefault(name, value) + if config.opts.indexserver: + d['default'] = config.opts.indexserver + else: + d.setdefault('default', None) + reader.addsubstitions(toxworkdir=config.toxworkdir) config.distdir = reader.getpath(toxsection, "distdir", "{toxworkdir}/dist") @@ -173,10 +185,6 @@ class parseini: vc.upgrade = True else: vc.upgrade = reader.getbool(section, "upgrade", False) - if config.opts.indexserver: - vc.indexserver = config.opts.indexserver - else: - vc.indexserver = reader.getdefault(section, "indexserver", None) args = config.opts.args if args: if vc.args_are_paths: diff --git a/tox/_venv.py b/tox/_venv.py index a4349ab..8253154 100644 --- a/tox/_venv.py +++ b/tox/_venv.py @@ -178,20 +178,20 @@ class VirtualEnv(object): self.session.report.action("installing dependencies %s" %(deps)) self._install(deps) - def _commoninstallopts(self): + def _commoninstallopts(self, indexserver): l = [] - if self.envconfig.indexserver: - l += ["-i", self.envconfig.indexserver] + if indexserver: + l += ["-i", indexserver] if self.envconfig.upgrade: l += ["-U"] return l - def easy_install(self, args): - argv = ["easy_install"] + self._commoninstallopts() + args + def easy_install(self, args, indexserver=None): + argv = ["easy_install"] + self._commoninstallopts(indexserver) + args self._pcall(argv, cwd=self.envconfig.envlogdir) - def pip_install(self, args): - argv = ["pip", "install"] + self._commoninstallopts() + def pip_install(self, args, indexserver=None): + argv = ["pip", "install"] + self._commoninstallopts(indexserver) if self.envconfig.downloadcache: self.envconfig.downloadcache.ensure(dir=1) argv.append("--download-cache=%s" % @@ -203,13 +203,25 @@ class VirtualEnv(object): argv += args self._pcall(argv, cwd=self.envconfig.envlogdir) - def _install(self, args): - if not args: + def _install(self, deps): + if not deps: return - if self._ispython3(): - self.easy_install(args) - else: - self.pip_install(args) + d = {} + for depline in deps: + try: + parts = depline.split(None, 1) + except AttributeError: # e.g. py.path.local + parts = depline, + if len(parts) == 1: + d.setdefault('default', []).append(depline) + else: + d.setdefault(parts[0], []).append(parts[1]) + for name, args in d.items(): + indexserver = self.session.config.indexserver[name] + if self._ispython3(): + self.easy_install(args, indexserver) + else: + self.pip_install(args, indexserver) def test(self): self.session.make_emptydir(self.envconfig.envtmpdir) |