diff options
| author | Vladimir Vitvitskiy <vladimir.vitvitskiy@hp.com> | 2015-04-23 00:18:46 +0300 |
|---|---|---|
| committer | Vladimir Vitvitskiy <vladimir.vitvitskiy@hp.com> | 2015-04-23 00:18:46 +0300 |
| commit | ad220729fd9c08662f2fbc5beda265ddaffe62a0 (patch) | |
| tree | 76ad86167ce78fdeaf9eaed20d2646218332626c | |
| parent | accadc9fadca83bd9fbe4bc06884d268ff8f9618 (diff) | |
| download | tox-ad220729fd9c08662f2fbc5beda265ddaffe62a0.tar.gz | |
fix PEP8 violations
* tox.ini updated to run PEP8 checks along with flakes
* added dev test environment to run any command in it or looponfail tests
* fixed all PEP8 violations pytest-pep8 complained about
* line width set to 99
| -rw-r--r-- | tests/test_config.py | 96 | ||||
| -rw-r--r-- | tests/test_interpreters.py | 9 | ||||
| -rw-r--r-- | tests/test_result.py | 13 | ||||
| -rw-r--r-- | tests/test_venv.py | 58 | ||||
| -rw-r--r-- | tests/test_z_cmdline.py | 75 | ||||
| -rw-r--r-- | tox.ini | 27 | ||||
| -rw-r--r-- | tox/__init__.py | 4 | ||||
| -rw-r--r-- | tox/_cmdline.py | 94 | ||||
| -rw-r--r-- | tox/_config.py | 175 | ||||
| -rw-r--r-- | tox/_exception.py | 14 | ||||
| -rw-r--r-- | tox/_pytestplugin.py | 64 | ||||
| -rw-r--r-- | tox/_quickstart.py | 17 | ||||
| -rw-r--r-- | tox/_venv.py | 57 | ||||
| -rw-r--r-- | tox/_verlib.py | 16 | ||||
| -rw-r--r-- | tox/interpreters.py | 24 | ||||
| -rw-r--r-- | tox/result.py | 13 |
16 files changed, 466 insertions, 290 deletions
diff --git a/tests/test_config.py b/tests/test_config.py index b474c96..0f271d7 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -65,8 +65,8 @@ class TestVenvConfig: def test_force_dep_version(self, initproj): """ - Make sure we can override dependencies configured in tox.ini when using the command line option - --force-dep. + Make sure we can override dependencies configured in tox.ini when using the command line + option --force-dep. """ initproj("example123-0.5", filedefs={ 'tox.ini': ''' @@ -83,7 +83,7 @@ class TestVenvConfig: config = parseconfig( ['--force-dep=dep1==1.5', '--force-dep=dep2==2.1', '--force-dep=dep3==3.0']) - assert config.option.force_dep== [ + assert config.option.force_dep == [ 'dep1==1.5', 'dep2==2.1', 'dep3==3.0'] assert [str(x) for x in config.envconfigs['python'].deps] == [ 'dep1==1.5', 'dep2==2.1', 'dep3==3.0', 'dep4==4.0', @@ -126,7 +126,6 @@ class TestConfigPlatform: monkeypatch.undo() assert not venv.matching_platform() - @pytest.mark.parametrize("plat", ["win", "lin", ]) def test_config_parse_platform_with_factors(self, newconfig, plat, monkeypatch): monkeypatch.setattr(sys, "platform", "win32") @@ -171,6 +170,7 @@ class TestConfigPackage: """ % tmpdir) assert config.toxworkdir == tmpdir + class TestParseconfig: def test_search_parents(self, tmpdir): b = tmpdir.mkdir("a").mkdir("b") @@ -182,12 +182,13 @@ class TestParseconfig: old.chdir() assert config.toxinipath == toxinipath + def test_get_homedir(monkeypatch): monkeypatch.setattr(py.path.local, "_gethomedir", classmethod(lambda x: {}[1])) assert not get_homedir() monkeypatch.setattr(py.path.local, "_gethomedir", - classmethod(lambda x: 0/0)) + classmethod(lambda x: 0 / 0)) assert not get_homedir() monkeypatch.setattr(py.path.local, "_gethomedir", classmethod(lambda x: "123")) @@ -224,7 +225,8 @@ class TestIniParserAgainstCommandsKey: assert x == [["echo", "whatever"]] def test_command_substitution_from_other_section_multiline(self, newconfig): - """Ensure referenced multiline commands form from other section injected as multiple commands.""" + """Ensure referenced multiline commands form from other section injected + as multiple commands.""" config = newconfig(""" [section] commands = @@ -275,7 +277,7 @@ class TestIniParser: reader = IniReader(config._cfg, fallbacksections=['mydefault']) assert reader is not None py.test.raises(tox.exception.ConfigError, - 'reader.getdefault("mydefault", "key2")') + 'reader.getdefault("mydefault", "key2")') def test_getdefault_fallback_sections(self, tmpdir, newconfig): config = newconfig(""" @@ -346,7 +348,7 @@ class TestIniParser: x = reader.getdefault("section", "key1") assert x == "hello" py.test.raises(tox.exception.ConfigError, - 'reader.getdefault("section", "key2")') + 'reader.getdefault("section", "key2")') def test_getdefault_environment_substitution_with_default(self, monkeypatch, newconfig): monkeypatch.setenv("KEY1", "hello") @@ -392,7 +394,7 @@ class TestIniParser: """) reader = IniReader(config._cfg) reader.addsubstitutions(item1="with space", item2="grr") - #py.test.raises(tox.exception.ConfigError, + # py.test.raises(tox.exception.ConfigError, # "reader.getargvlist('section', 'key1')") assert reader.getargvlist('section', 'key1') == [] x = reader.getargvlist("section", "key2") @@ -418,7 +420,7 @@ class TestIniParser: """) reader = IniReader(config._cfg) reader.addsubstitutions(item1="with space", item2="grr") - #py.test.raises(tox.exception.ConfigError, + # py.test.raises(tox.exception.ConfigError, # "reader.getargvlist('section', 'key1')") assert reader.getargvlist('section', 'key1') == [] x = reader.getargvlist("section", "key2") @@ -446,7 +448,7 @@ class TestIniParser: reader = IniReader(config._cfg) posargs = ['hello', 'world'] reader.addsubstitutions(posargs, item2="value2") - #py.test.raises(tox.exception.ConfigError, + # py.test.raises(tox.exception.ConfigError, # "reader.getargvlist('section', 'key1')") assert reader.getargvlist('section', 'key1') == [] argvlist = reader.getargvlist("section", "key2") @@ -455,7 +457,7 @@ class TestIniParser: reader = IniReader(config._cfg) reader.addsubstitutions([], item2="value2") - #py.test.raises(tox.exception.ConfigError, + # py.test.raises(tox.exception.ConfigError, # "reader.getargvlist('section', 'key1')") assert reader.getargvlist('section', 'key1') == [] argvlist = reader.getargvlist("section", "key2") @@ -490,8 +492,7 @@ class TestIniParser: x = reader.getargvlist("section", "key2") assert x == [["cmd1", "-f", "foo", "bar baz"]] - def test_positional_arguments_are_only_replaced_when_standing_alone(self, - tmpdir, newconfig): + def test_positional_arguments_are_only_replaced_when_standing_alone(self, tmpdir, newconfig): config = newconfig(""" [section] key= @@ -520,7 +521,9 @@ class TestIniParser: posargs = ['hello', 'world'] reader.addsubstitutions(posargs, envlogdir='ENV_LOG_DIR', envname='ENV_NAME') - expected = ['py.test', '-n5', '--junitxml=ENV_LOG_DIR/junit-ENV_NAME.xml', 'hello', 'world'] + expected = [ + 'py.test', '-n5', '--junitxml=ENV_LOG_DIR/junit-ENV_NAME.xml', 'hello', 'world' + ] assert reader.getargvlist('section', 'key')[0] == expected def test_getargv(self, newconfig): @@ -582,8 +585,8 @@ class TestConfigTestEnv: envconfig = config.envconfigs['python'] assert envconfig.commands == [["xyz", "--abc"]] assert envconfig.changedir == config.setupdir - assert envconfig.sitepackages == False - assert envconfig.develop == False + assert envconfig.sitepackages is False + assert envconfig.develop is False assert envconfig.envlogdir == envconfig.envdir.join("log") assert list(envconfig.setenv.keys()) == ['PYTHONHASHSEED'] hashseed = envconfig.setenv['PYTHONHASHSEED'] @@ -596,7 +599,7 @@ class TestConfigTestEnv: def test_sitepackages_switch(self, tmpdir, newconfig): config = newconfig(["--sitepackages"], "") envconfig = config.envconfigs['python'] - assert envconfig.sitepackages == True + assert envconfig.sitepackages is True def test_installpkg_tops_develop(self, newconfig): config = newconfig(["--installpkg=abc"], """ @@ -918,7 +921,7 @@ class TestConfigTestEnv: assert argv[0] == ["cmd1", "hello"] def test_take_dependencies_from_other_testenv(self, newconfig): - inisource=""" + inisource = """ [testenv] deps= pytest @@ -933,7 +936,7 @@ class TestConfigTestEnv: assert packages == ['pytest', 'pytest-cov', 'fun'] def test_take_dependencies_from_other_section(self, newconfig): - inisource=""" + inisource = """ [testing:pytest] deps= pytest @@ -953,7 +956,7 @@ class TestConfigTestEnv: assert packages == ['pytest', 'pytest-cov', 'mock', 'fun'] def test_multilevel_substitution(self, newconfig): - inisource=""" + inisource = """ [testing:pytest] deps= pytest @@ -978,7 +981,7 @@ class TestConfigTestEnv: assert packages == ['pytest', 'pytest-cov', 'mock', 'fun'] def test_recursive_substitution_cycle_fails(self, newconfig): - inisource=""" + inisource = """ [testing:pytest] deps= {[testing:mock]deps} @@ -1004,7 +1007,7 @@ class TestConfigTestEnv: assert conf.changedir.dirpath().realpath() == tmpdir.realpath() def test_factors(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = a-x,b @@ -1022,7 +1025,7 @@ class TestConfigTestEnv: assert [dep.name for dep in configs['b'].deps] == ["dep-all", "dep-b"] def test_factor_ops(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = {a,b}-{x,y} @@ -1040,7 +1043,7 @@ class TestConfigTestEnv: assert get_deps("b-y") == ["dep-a-or-b", "dep-ab-and-y"] def test_default_factors(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = py{26,27,33,34}-dep @@ -1055,7 +1058,7 @@ class TestConfigTestEnv: @pytest.mark.issue188 def test_factors_in_boolean(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = py{27,33} @@ -1069,7 +1072,7 @@ class TestConfigTestEnv: @pytest.mark.issue190 def test_factors_in_setenv(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = py27,py26 @@ -1083,7 +1086,7 @@ class TestConfigTestEnv: @pytest.mark.issue191 def test_factor_use_not_checked(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = py27-{a,b} @@ -1095,7 +1098,7 @@ class TestConfigTestEnv: @pytest.mark.issue198 def test_factors_groups_touch(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = {a,b}{-x,} @@ -1107,7 +1110,7 @@ class TestConfigTestEnv: assert set(configs.keys()) == set(['a', 'a-x', 'b', 'b-x']) def test_period_in_factor(self, newconfig): - inisource=""" + inisource = """ [tox] envlist = py27-{django1.6,django1.7} @@ -1185,7 +1188,7 @@ class TestGlobalOptions: [testenv:py27] basepython=python2.7 """ - #py.test.raises(tox.exception.ConfigError, + # py.test.raises(tox.exception.ConfigError, # "newconfig(['-exyz'], inisource)") config = newconfig([], inisource) assert config.envlist == ["py26"] @@ -1222,7 +1225,7 @@ class TestGlobalOptions: assert env.basepython == name else: assert name.startswith("py") - bp = "python%s.%s" %(name[2], name[3]) + bp = "python%s.%s" % (name[2], name[3]) assert env.basepython == bp def test_envlist_expansion(self, newconfig): @@ -1284,6 +1287,7 @@ class TestGlobalOptions: assert env.basepython == "python2.4" assert env.commands == [['xyz']] + class TestHashseedOption: def _get_envconfigs(self, newconfig, args=None, tox_ini=None, @@ -1331,7 +1335,7 @@ class TestHashseedOption: args = ['--hashseed', ''] self._check_testenv(newconfig, '', args=args) - @pytest.mark.xfail(sys.version_info >= (3,2), + @pytest.mark.xfail(sys.version_info >= (3, 2), reason="at least Debian python 3.2/3.3 have a bug: " "http://bugs.python.org/issue11884") def test_passing_no_argument(self, tmpdir, newconfig): @@ -1378,6 +1382,7 @@ class TestHashseedOption: """ next_seed = [1000] # This function is guaranteed to generate a different value each time. + def make_hashseed(): next_seed[0] += 1 return str(next_seed[0]) @@ -1401,6 +1406,7 @@ class TestHashseedOption: self._check_hashseed(envconfigs["hash1"], '2') self._check_hashseed(envconfigs["hash2"], '123456789') + class TestIndexServer: def test_indexserver(self, tmpdir, newconfig): config = newconfig(""" @@ -1409,7 +1415,7 @@ class TestIndexServer: name1 = XYZ name2 = ABC """) - assert config.indexserver['default'].url == None + assert config.indexserver['default'].url is None assert config.indexserver['name1'].url == "XYZ" assert config.indexserver['name2'].url == "ABC" @@ -1423,10 +1429,10 @@ class TestIndexServer: config = newconfig([], inisource) assert config.indexserver['default'].url == "http://pypi.testrun.org" assert config.indexserver['name1'].url == "whatever" - config = newconfig(['-i','qwe'], inisource) + config = newconfig(['-i', 'qwe'], inisource) assert config.indexserver['default'].url == "qwe" assert config.indexserver['name1'].url == "whatever" - config = newconfig(['-i','name1=abc', '-i','qwe2'], inisource) + config = newconfig(['-i', 'name1=abc', '-i', 'qwe2'], inisource) assert config.indexserver['default'].url == "qwe2" assert config.indexserver['name1'].url == "abc" @@ -1447,8 +1453,8 @@ class TestIndexServer: config = newconfig([], inisource) expected = "file://%s/.pip/downloads/simple" % config.homedir assert config.indexserver['default'].url == expected - assert config.indexserver['local1'].url == \ - config.indexserver['default'].url + assert config.indexserver['local1'].url == config.indexserver['default'].url + class TestParseEnv: @@ -1467,6 +1473,7 @@ class TestParseEnv: config = newconfig([], inisource) assert config.envconfigs['hello'].recreate + class TestCmdInvocation: def test_help(self, cmd): result = cmd.run("tox", "-h") @@ -1544,6 +1551,7 @@ class TestCmdInvocation: r'*deps=*dep1, dep2==5.0*', ]) + class TestArgumentParser: def test_dash_e_single_1(self): @@ -1591,12 +1599,15 @@ class TestCommandParser: assert list(p.words()) == ['{sub:something with spaces}'] def test_command_parser_with_complex_word_set(self): - complex_case = 'word [] [literal] {something} {some:other thing} w{ord} w{or}d w{ord} w{o:rd} w{o:r}d {w:or}d w[]ord {posargs:{a key}}' + complex_case = ( + 'word [] [literal] {something} {some:other thing} w{ord} w{or}d w{ord} ' + 'w{o:rd} w{o:r}d {w:or}d w[]ord {posargs:{a key}}') p = CommandParser(complex_case) parsed = list(p.words()) expected = [ 'word', ' ', '[]', ' ', '[literal]', ' ', '{something}', ' ', '{some:other thing}', - ' ', 'w', '{ord}', ' ', 'w', '{or}', 'd', ' ', 'w', '{ord}', ' ', 'w', '{o:rd}', ' ', 'w', '{o:r}', 'd', ' ', '{w:or}', 'd', + ' ', 'w', '{ord}', ' ', 'w', '{or}', 'd', ' ', 'w', '{ord}', ' ', 'w', '{o:rd}', ' ', + 'w', '{o:r}', 'd', ' ', '{w:or}', 'd', ' ', 'w[]ord', ' ', '{posargs:{a key}}', ] @@ -1619,7 +1630,10 @@ class TestCommandParser: cmd = "nosetests -v -a !deferred --with-doctest []" p = CommandParser(cmd) parsed = list(p.words()) - assert parsed == ['nosetests', ' ', '-v', ' ', '-a', ' ', '!deferred', ' ', '--with-doctest', ' ', '[]'] + assert parsed == [ + 'nosetests', ' ', '-v', ' ', '-a', ' ', '!deferred', ' ', + '--with-doctest', ' ', '[]' + ] @pytest.mark.skipif("sys.platform != 'win32'") def test_commands_with_backslash(self, newconfig): diff --git a/tests/test_interpreters.py b/tests/test_interpreters.py index f06a69a..1c5a77d 100644 --- a/tests/test_interpreters.py +++ b/tests/test_interpreters.py @@ -4,10 +4,12 @@ import os import pytest from tox.interpreters import * # noqa + @pytest.fixture def interpreters(): return Interpreters() + @pytest.mark.skipif("sys.platform != 'win32'") def test_locate_via_py(monkeypatch): class PseudoPy: @@ -16,6 +18,7 @@ def test_locate_via_py(monkeypatch): assert args[1] == '-c' # Return value needs to actually exist! return sys.executable + @staticmethod def ret_pseudopy(name): assert name == 'py' @@ -24,6 +27,7 @@ def test_locate_via_py(monkeypatch): monkeypatch.setattr(py.path.local, 'sysfind', ret_pseudopy) assert locate_via_py('3', '2') == sys.executable + def test_find_executable(): p = find_executable(sys.executable) assert p == py.path.local(sys.executable) @@ -41,10 +45,11 @@ def test_find_executable(): p = find_executable(name) assert p popen = py.std.subprocess.Popen([str(p), '-V'], - stderr=py.std.subprocess.PIPE) + stderr=py.std.subprocess.PIPE) stdout, stderr = popen.communicate() assert ver in py.builtin._totext(stderr, "ascii") + def test_find_executable_extra(monkeypatch): @staticmethod def sysfind(x): @@ -53,6 +58,7 @@ def test_find_executable_extra(monkeypatch): t = find_executable("qweqwe") assert t == "hello" + def test_run_and_get_interpreter_info(): name = os.path.basename(sys.executable) info = run_and_get_interpreter_info(name, sys.executable) @@ -60,6 +66,7 @@ def test_run_and_get_interpreter_info(): assert info.name == name assert info.executable == sys.executable + class TestInterpreters: def test_get_info_self_exceptions(self, interpreters): diff --git a/tests/test_result.py b/tests/test_result.py index 206a99c..48dd831 100644 --- a/tests/test_result.py +++ b/tests/test_result.py @@ -4,12 +4,14 @@ from tox.result import ResultLog import tox import pytest + @pytest.fixture def pkg(tmpdir): p = tmpdir.join("hello-1.0.tar.gz") p.write("whatever") return p + def test_pre_set_header(pkg): replog = ResultLog() d = replog.dict @@ -22,6 +24,7 @@ def test_pre_set_header(pkg): replog2 = ResultLog.loads_json(data) assert replog2.dict == replog.dict + def test_set_header(pkg): replog = ResultLog() d = replog.dict @@ -31,13 +34,15 @@ def test_set_header(pkg): assert replog.dict["toxversion"] == tox.__version__ assert replog.dict["platform"] == sys.platform assert replog.dict["host"] == py.std.socket.getfqdn() - assert replog.dict["installpkg"] == {"basename": "hello-1.0.tar.gz", - "md5": pkg.computehash("md5"), - "sha256": pkg.computehash("sha256")} + assert replog.dict["installpkg"] == { + "basename": "hello-1.0.tar.gz", + "md5": pkg.computehash("md5"), + "sha256": pkg.computehash("sha256")} data = replog.dumps_json() replog2 = ResultLog.loads_json(data) assert replog2.dict == replog.dict + def test_addenv_setpython(pkg): replog = ResultLog() replog.set_header(installpkg=pkg) @@ -47,6 +52,7 @@ def test_addenv_setpython(pkg): assert envlog.dict["python"]["version"] == sys.version assert envlog.dict["python"]["executable"] == sys.executable + def test_get_commandlog(pkg): replog = ResultLog() replog.set_header(installpkg=pkg) @@ -60,4 +66,3 @@ def test_get_commandlog(pkg): assert envlog.dict["setup"] setuplog2 = replog.get_envlog("py26").get_commandlog("setup") assert setuplog2.list == setuplog.list - diff --git a/tests/test_venv.py b/tests/test_venv.py index 1baf578..538b7e5 100644 --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -1,12 +1,13 @@ import py import tox import pytest -import os, sys +import os +import sys import tox._config from tox._venv import * # noqa from tox.interpreters import NoInterpreterInfo -#def test_global_virtualenv(capfd): +# def test_global_virtualenv(capfd): # v = VirtualEnv() # l = v.list() # assert l @@ -14,8 +15,11 @@ from tox.interpreters import NoInterpreterInfo # assert not out # assert not err # + + def test_getdigest(tmpdir): - assert getdigest(tmpdir) == "0"*32 + assert getdigest(tmpdir) == "0" * 32 + def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession): config = newconfig([], """ @@ -25,8 +29,7 @@ def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession): venv = VirtualEnv(config.envconfigs['python'], session=mocksession) interp = venv.getsupportedinterpreter() # realpath needed for debian symlinks - assert py.path.local(interp).realpath() \ - == py.path.local(sys.executable).realpath() + assert py.path.local(interp).realpath() == py.path.local(sys.executable).realpath() monkeypatch.setattr(sys, 'platform', "win32") monkeypatch.setattr(venv.envconfig, 'basepython', 'jython') py.test.raises(tox.exception.UnsupportedInterpreter, @@ -58,14 +61,14 @@ def test_create(monkeypatch, mocksession, newconfig): assert "virtualenv" == str(args[2]) if sys.platform != "win32": # realpath is needed for stuff like the debian symlinks - assert py.path.local(sys.executable).realpath() \ - == py.path.local(args[0]).realpath() - #assert Envconfig.toxworkdir in args + assert py.path.local(sys.executable).realpath() == py.path.local(args[0]).realpath() + # assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) interp = venv._getliveconfig().python assert interp == venv.envconfig._basepython_info.executable assert venv.path_config.check(exists=False) + @pytest.mark.skipif("sys.platform == 'win32'") def test_commandpath_venv_precendence(tmpdir, monkeypatch, mocksession, newconfig): @@ -80,6 +83,7 @@ def test_commandpath_venv_precendence(tmpdir, monkeypatch, p = venv.getcommandpath("easy_install") assert py.path.local(p).relto(envconfig.envbindir), p + def test_create_sitepackages(monkeypatch, mocksession, newconfig): config = newconfig([], """ [testenv:site] @@ -106,6 +110,7 @@ def test_create_sitepackages(monkeypatch, mocksession, newconfig): assert "--system-site-packages" not in map(str, args) assert "--no-site-packages" not in map(str, args) + def test_install_deps_wildcard(newmocksession): mocksession = newmocksession([], """ [tox] @@ -128,8 +133,8 @@ def test_install_deps_wildcard(newmocksession): assert l[-1].cwd == venv.envconfig.config.toxinidir assert "pip" in str(args[0]) assert args[1] == "install" - #arg = "--download-cache=" + str(venv.envconfig.downloadcache) - #assert arg in args[2:] + # arg = "--download-cache=" + str(venv.envconfig.downloadcache) + # assert arg in args[2:] args = [arg for arg in args if str(arg).endswith("dep1-1.1.zip")] assert len(args) == 1 @@ -162,6 +167,7 @@ def test_install_downloadcache(newmocksession, monkeypatch, tmpdir, envdc): deps = list(filter(None, [x[1] for x in venv._getliveconfig().deps])) assert deps == ['dep1', 'dep2'] + def test_install_deps_indexserver(newmocksession): mocksession = newmocksession([], """ [tox] @@ -194,6 +200,7 @@ def test_install_deps_indexserver(newmocksession): assert "-i ABC" in args assert "dep3" in args + def test_install_deps_pre(newmocksession): mocksession = newmocksession([], """ [testenv] @@ -213,6 +220,7 @@ def test_install_deps_pre(newmocksession): assert "--pre " in args assert "dep1" in args + def test_installpkg_indexserver(newmocksession, tmpdir): mocksession = newmocksession([], """ [tox] @@ -228,6 +236,7 @@ def test_installpkg_indexserver(newmocksession, tmpdir): args = " ".join(l[0].args) assert "-i ABC" in args + def test_install_recreate(newmocksession, tmpdir): pkg = tmpdir.ensure("package.tar.gz") mocksession = newmocksession(['--recreate'], """ @@ -241,6 +250,7 @@ def test_install_recreate(newmocksession, tmpdir): venv.update() mocksession.report.expect("verbosity0", "*recreate*") + def test_test_hashseed_is_in_output(newmocksession): original_make_hashseed = tox._config.make_hashseed tox._config.make_hashseed = lambda: '123456789' @@ -255,6 +265,7 @@ def test_test_hashseed_is_in_output(newmocksession): venv.test() mocksession.report.expect("verbosity0", "python runtests: PYTHONHASHSEED='123456789'") + def test_test_runtests_action_command_is_in_output(newmocksession): mocksession = newmocksession([], ''' [testenv] @@ -265,6 +276,7 @@ def test_test_runtests_action_command_is_in_output(newmocksession): venv.test() mocksession.report.expect("verbosity0", "*runtests*commands?0? | echo foo bar") + def test_install_error(newmocksession, monkeypatch): mocksession = newmocksession(['--recreate'], """ [testenv] @@ -277,6 +289,7 @@ def test_install_error(newmocksession, monkeypatch): mocksession.report.expect("error", "*not find*qwelkqw*") assert venv.status == "commands failed" + def test_install_command_not_installed(newmocksession, monkeypatch): mocksession = newmocksession(['--recreate'], """ [testenv] @@ -288,6 +301,7 @@ def test_install_command_not_installed(newmocksession, monkeypatch): mocksession.report.expect("warning", "*test command found but not*") assert venv.status == 0 + def test_install_command_whitelisted(newmocksession, monkeypatch): mocksession = newmocksession(['--recreate'], """ [testenv] @@ -303,6 +317,7 @@ def test_install_command_whitelisted(newmocksession, monkeypatch): invert=True) assert venv.status == "commands failed" + @pytest.mark.skipif("not sys.platform.startswith('linux')") def test_install_command_not_installed_bash(newmocksession): mocksession = newmocksession(['--recreate'], """ @@ -340,6 +355,7 @@ def test_install_python3(tmpdir, newmocksession): for x in args: assert "--download-cache" not in args, args + class TestCreationConfig: def test_basic(self, newconfig, mocksession, tmpdir): @@ -435,7 +451,7 @@ class TestCreationConfig: venv = VirtualEnv(envconfig, session=mocksession) venv.update() cconfig = venv._getliveconfig() - cconfig.deps[:] = [("1"*32, "xyz.zip")] + cconfig.deps[:] = [("1" * 32, "xyz.zip")] cconfig.writeconfig(venv.path_config) mocksession._clearmocks() venv.update() @@ -453,6 +469,7 @@ class TestCreationConfig: venv.update() mocksession.report.expect("verbosity0", "*recreate*") + class TestVenvTest: def test_patchPATH(self, newmocksession, monkeypatch): @@ -468,14 +485,14 @@ class TestVenvTest: assert oldpath == "xyz" res = os.environ['PATH'] assert res == "%s%sxyz" % (envconfig.envbindir, os.pathsep) - p = "xyz"+os.pathsep+str(envconfig.envbindir) + p = "xyz" + os.pathsep + str(envconfig.envbindir) monkeypatch.setenv("PATH", p) venv.patchPATH() res = os.environ['PATH'] - assert res == "%s%s%s" %(envconfig.envbindir, os.pathsep, p) + assert res == "%s%s%s" % (envconfig.envbindir, os.pathsep, p) assert envconfig.commands - monkeypatch.setattr(venv, '_pcall', lambda *args, **kwargs: 0/0) + monkeypatch.setattr(venv, '_pcall', lambda *args, **kwargs: 0 / 0) py.test.raises(ZeroDivisionError, "venv._install(list('123'))") py.test.raises(ZeroDivisionError, "venv.test()") py.test.raises(ZeroDivisionError, "venv.run_install_command(['qwe'])") @@ -488,6 +505,7 @@ class TestVenvTest: assert 'PIP_REQUIRE_VIRTUALENV' not in os.environ assert '__PYVENV_LAUNCHER__' not in os.environ + def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatch): pkg = tmpdir.ensure("package.tar.gz") monkeypatch.setenv("X123", "123") @@ -516,11 +534,12 @@ def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatc assert env['X123'] == "123" assert set(["ENV_VAR", "VIRTUAL_ENV", "PYTHONHASHSEED", "X123", "PATH"])\ - .issubset(env) + .issubset(env) - #for e in os.environ: + # for e in os.environ: # assert e in env + def test_installpkg_no_upgrade(tmpdir, newmocksession): pkg = tmpdir.ensure("package.tar.gz") mocksession = newmocksession([], "") @@ -532,6 +551,7 @@ def test_installpkg_no_upgrade(tmpdir, newmocksession): assert len(l) == 1 assert '-U' not in l[0].args + def test_installpkg_upgrade(newmocksession, tmpdir): pkg = tmpdir.ensure("package.tar.gz") mocksession = newmocksession([], "") @@ -545,6 +565,7 @@ def test_installpkg_upgrade(newmocksession, tmpdir): assert '-U' in l[0].args[:index] assert '--no-deps' in l[0].args[:index] + def test_run_install_command(newmocksession): mocksession = newmocksession([], "") venv = mocksession.getenv('python') @@ -559,6 +580,7 @@ def test_run_install_command(newmocksession): env = l[0].env assert env is not None + def test_run_custom_install_command(newmocksession): mocksession = newmocksession([], """ [testenv] @@ -574,6 +596,7 @@ def test_run_custom_install_command(newmocksession): assert 'easy_install' in l[0].args[0] assert l[0].args[1:] == ['whatever'] + def test_command_relative_issue26(newmocksession, tmpdir, monkeypatch): mocksession = newmocksession([], """ [testenv] @@ -591,6 +614,7 @@ def test_command_relative_issue26(newmocksession, tmpdir, monkeypatch): assert x4.endswith(os.sep + 'x') mocksession.report.expect("warning", "*test command found but not*") + def test_sethome_only_on_option(newmocksession, monkeypatch): mocksession = newmocksession([], "") venv = mocksession.getenv('python') @@ -598,6 +622,7 @@ def test_sethome_only_on_option(newmocksession, monkeypatch): monkeypatch.setattr(tox._venv, "hack_home_env", None) venv._install(["x"], action=action) + def test_sethome_works_on_option(newmocksession, monkeypatch): mocksession = newmocksession(["--set-home", "-i ALL=http://qwe"], "") venv = mocksession.getenv('python') @@ -622,6 +647,7 @@ def test_hack_home_env(tmpdir): assert not tmpdir.join(".pydistutils.cfg").check() assert "PIP_INDEX_URL" not in env + def test_hack_home_env_passthrough(tmpdir, monkeypatch): from tox._venv import hack_home_env env = hack_home_env(tmpdir, "http://index") diff --git a/tests/test_z_cmdline.py b/tests/test_z_cmdline.py index 391bc4b..e793804 100644 --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -12,35 +12,40 @@ pytest_plugins = "pytester" from tox._cmdline import Session from tox._config import parseconfig + def test_report_protocol(newconfig): config = newconfig([], """ [testenv:mypython] deps=xy """) + class Popen: def __init__(self, *args, **kwargs): pass + def communicate(self): return "", "" + def wait(self): pass session = Session(config, popen=Popen, - Report=ReportExpectMock) + Report=ReportExpectMock) report = session.report report.expect("using") venv = session.getvenv("mypython") venv.update() report.expect("logpopen") + def test__resolve_pkg(tmpdir, mocksession): distshare = tmpdir.join("distshare") spec = distshare.join("pkg123-*") py.test.raises(tox.exception.MissingDirectory, - 'mocksession._resolve_pkg(spec)') + 'mocksession._resolve_pkg(spec)') distshare.ensure(dir=1) py.test.raises(tox.exception.MissingDependency, - 'mocksession._resolve_pkg(spec)') + 'mocksession._resolve_pkg(spec)') distshare.ensure("pkg123-1.3.5.zip") p = distshare.ensure("pkg123-1.4.5.zip") @@ -58,6 +63,7 @@ def test__resolve_pkg(tmpdir, mocksession): result = mocksession._resolve_pkg(spec) assert result == p + def test__resolve_pkg_doubledash(tmpdir, mocksession): distshare = tmpdir.join("distshare") p = distshare.ensure("pkg-mine-1.3.0.zip") @@ -68,7 +74,6 @@ def test__resolve_pkg_doubledash(tmpdir, mocksession): assert res == p - class TestSession: def test_make_sdist(self, initproj): initproj("example123-0.5", filedefs={ @@ -116,7 +121,7 @@ class TestSession: action.popen(["echo", ]) match = mocksession.report.getnext("logpopen") assert match[1].outpath.relto(mocksession.config.logdir) - assert match[1].shell == False + assert match[1].shell is False def test_summary_status(self, initproj, capfd): initproj("logexample123-0.5", filedefs={ @@ -177,6 +182,7 @@ def XXX_test_package(cmd, initproj): "*created sdist package at*", ]) + def test_minversion(cmd, initproj): initproj("interp123-0.5", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, @@ -191,6 +197,7 @@ def test_minversion(cmd, initproj): ]) assert result.ret + def test_run_custom_install_command_error(cmd, initproj): initproj("interp123-0.5", filedefs={ 'tox.ini': ''' @@ -204,6 +211,7 @@ def test_run_custom_install_command_error(cmd, initproj): ]) assert result.ret + def test_unknown_interpreter_and_env(cmd, initproj): initproj("interp123-0.5", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, @@ -226,6 +234,7 @@ def test_unknown_interpreter_and_env(cmd, initproj): "*ERROR*unknown*", ]) + def test_unknown_interpreter(cmd, initproj): initproj("interp123-0.5", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, @@ -242,6 +251,7 @@ def test_unknown_interpreter(cmd, initproj): "*ERROR*InterpreterNotFound*xyz_unknown_interpreter*", ]) + def test_skip_platform_mismatch(cmd, initproj): initproj("interp123-0.5", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, @@ -260,6 +270,7 @@ def test_skip_platform_mismatch(cmd, initproj): "*python*platform mismatch*" ]) + def test_skip_unknown_interpreter(cmd, initproj): initproj("interp123-0.5", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, @@ -276,6 +287,7 @@ def test_skip_unknown_interpreter(cmd, initproj): "*SKIPPED*InterpreterNotFound*xyz_unknown_interpreter*", ]) + def test_unknown_dep(cmd, initproj): initproj("dep123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, @@ -291,6 +303,7 @@ def test_unknown_dep(cmd, initproj): "*ERROR*could not install*qweqwe123*", ]) + def test_unknown_environment(cmd, initproj): initproj("env123-0.7", filedefs={ 'tox.ini': '' @@ -301,13 +314,13 @@ def test_unknown_environment(cmd, initproj): "*ERROR*unknown*environment*qpwoei*", ]) + def test_skip_sdist(cmd, initproj): initproj("pkg123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, 'setup.py': """ syntax error - """ - , + """, 'tox.ini': ''' [tox] skipsdist=True @@ -318,12 +331,12 @@ def test_skip_sdist(cmd, initproj): result = cmd.run("tox", ) assert result.ret == 0 + def test_minimal_setup_py_empty(cmd, initproj): initproj("pkg123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, 'setup.py': """ - """ - , + """, 'tox.ini': '' }) @@ -333,13 +346,13 @@ def test_minimal_setup_py_empty(cmd, initproj): "*ERROR*empty*", ]) + def test_minimal_setup_py_comment_only(cmd, initproj): initproj("pkg123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, 'setup.py': """\n# some comment - """ - , + """, 'tox.ini': '' }) @@ -349,14 +362,14 @@ def test_minimal_setup_py_comment_only(cmd, initproj): "*ERROR*empty*", ]) + def test_minimal_setup_py_non_functional(cmd, initproj): initproj("pkg123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, 'setup.py': """ import sys - """ - , + """, 'tox.ini': '' }) @@ -366,13 +379,13 @@ def test_minimal_setup_py_non_functional(cmd, initproj): "*ERROR*check setup.py*", ]) + def test_sdist_fails(cmd, initproj): initproj("pkg123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, 'setup.py': """ syntax error - """ - , + """, 'tox.ini': '', }) result = cmd.run("tox", ) @@ -381,6 +394,7 @@ def test_sdist_fails(cmd, initproj): "*FAIL*could not package project*", ]) + def test_package_install_fails(cmd, initproj): initproj("pkg123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, @@ -395,8 +409,7 @@ def test_package_install_fails(cmd, initproj): packages=['pkg123',], install_requires=['qweqwe123'], ) - """ - , + """, 'tox.ini': '', }) result = cmd.run("tox", ) @@ -406,14 +419,14 @@ def test_package_install_fails(cmd, initproj): ]) - class TestToxRun: @pytest.fixture def example123(self, initproj): initproj("example123-0.5", filedefs={ - 'tests': {'test_hello.py': """ - def test_hello(pytestconfig): - pass + 'tests': { + 'test_hello.py': """ + def test_hello(pytestconfig): + pass """, }, 'tox.ini': ''' @@ -475,6 +488,7 @@ def test_develop(initproj, cmd): assert not result.ret assert "sdist-make" not in result.stdout.str() + def test_usedevelop(initproj, cmd): initproj("example123", filedefs={'tox.ini': """ [testenv] @@ -484,6 +498,7 @@ def test_usedevelop(initproj, cmd): assert not result.ret assert "sdist-make" not in result.stdout.str() + def test_usedevelop_mixed(initproj, cmd): initproj("example123", filedefs={'tox.ini': """ [testenv:devenv] @@ -502,11 +517,13 @@ def test_usedevelop_mixed(initproj, cmd): assert not result.ret assert "sdist-make" in result.stdout.str() + def test_test_usedevelop(cmd, initproj): initproj("example123-0.5", filedefs={ - 'tests': {'test_hello.py': """ - def test_hello(pytestconfig): - pass + 'tests': { + 'test_hello.py': """ + def test_hello(pytestconfig): + pass """, }, 'tox.ini': ''' @@ -568,6 +585,7 @@ def test_test_piphelp(initproj, cmd): result = cmd.run("tox") assert not result.ret + def test_notest(initproj, cmd): initproj("example123", filedefs={'tox.ini': """ # content of: tox.ini @@ -586,6 +604,7 @@ def test_notest(initproj, cmd): "*py26*reusing*", ]) + def test_PYC(initproj, cmd, monkeypatch): initproj("example123", filedefs={'tox.ini': ''}) monkeypatch.setenv("PYTHONDOWNWRITEBYTECODE", 1) @@ -595,6 +614,7 @@ def test_PYC(initproj, cmd, monkeypatch): "*create*", ]) + def test_env_VIRTUALENV_PYTHON(initproj, cmd, monkeypatch): initproj("example123", filedefs={'tox.ini': ''}) monkeypatch.setenv("VIRTUALENV_PYTHON", '/FOO') @@ -604,6 +624,7 @@ def test_env_VIRTUALENV_PYTHON(initproj, cmd, monkeypatch): "*create*", ]) + def test_sdistonly(initproj, cmd): initproj("example123", filedefs={'tox.ini': """ """}) @@ -614,6 +635,7 @@ def test_sdistonly(initproj, cmd): ]) assert "-mvirtualenv" not in result.stdout.str() + def test_separate_sdist_no_sdistfile(cmd, initproj): distshare = cmd.tmpdir.join("distshare") initproj(("pkg123-foo", "0.7"), filedefs={ @@ -629,6 +651,7 @@ def test_separate_sdist_no_sdistfile(cmd, initproj): sdistfile = l[0] assert 'pkg123-foo-0.7.zip' in str(sdistfile) + def test_separate_sdist(cmd, initproj): distshare = cmd.tmpdir.join("distshare") initproj("pkg123-0.7", filedefs={ @@ -663,6 +686,7 @@ def test_sdist_latest(tmpdir, newconfig): sdist_path = session.sdist() assert sdist_path == p + def test_installpkg(tmpdir, newconfig): p = tmpdir.ensure("pkg123-1.0.zip") config = newconfig(["--installpkg=%s" % p], "") @@ -670,6 +694,7 @@ def test_installpkg(tmpdir, newconfig): sdist_path = session.sdist() assert sdist_path == p + @pytest.mark.xfail("sys.platform == 'win32' and sys.version_info < (2,6)", reason="test needs better impl") def test_envsitepackagesdir(cmd, initproj): @@ -685,6 +710,7 @@ def test_envsitepackagesdir(cmd, initproj): X:*tox*site-packages* """) + def verify_json_report_format(data, testenvs=True): assert data["reportversion"] == "1" assert data["toxversion"] == tox.__version__ @@ -700,4 +726,3 @@ def verify_json_report_format(data, testenvs=True): assert isinstance(pyinfo["version_info"], list) assert pyinfo["version"] assert pyinfo["executable"] - @@ -20,8 +20,29 @@ commands= [testenv:flakes] deps = pytest-flakes>=0.2 -commands = py.test --flakes -m flakes tox tests + pytest-pep8 + +commands = py.test -x --flakes --pep8 tox tests + +[testenv:dev] +# required to make looponfail reload on every source code change +usedevelop = True + +deps = + pytest-xdist>=1.11 +commands = {posargs:py.test -s -x -f -v} [pytest] -rsyncdirs=tests tox -addopts = -rsxXf +rsyncdirs = tests tox +addopts = -rsxX +# pytest-xdist plugin configuration +looponfailroots = tox tests +norecursedirs = .hg .tox + +# pytest-pep8 plugin configuration +pep8maxlinelength = 99 +# W503 - line break before binary operator +# E402 - module level import not at top of file +# E731 - do not assign a lambda expression, use a def +pep8ignore = + *.py W503 E402 E731 diff --git a/tox/__init__.py b/tox/__init__.py index 95f2dfb..7869fcb 100644 --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,10 +1,12 @@ # __version__ = '2.0.0.dev1' + class exception: class Error(Exception): def __str__(self): - return "%s: %s" %(self.__class__.__name__, self.args[0]) + return "%s: %s" % (self.__class__.__name__, self.args[0]) + class ConfigError(Error): """ error in tox configuration. """ class UnsupportedInterpreter(Error): diff --git a/tox/_cmdline.py b/tox/_cmdline.py index 5846c7c..0236d17 100644 --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -17,9 +17,11 @@ from tox._config import parseconfig from tox.result import ResultLog from subprocess import STDOUT + def now(): return py.std.time.time() + def main(args=None): try: config = parseconfig(args, 'tox') @@ -28,6 +30,7 @@ def main(args=None): except KeyboardInterrupt: raise SystemExit(2) + class Action(object): def __init__(self, session, venv, msg, args): self.venv = venv @@ -55,12 +58,10 @@ class Action(object): def setactivity(self, name, msg): self.activity = name - self.report.verbosity0("%s %s: %s" %(self.venvname, name, msg), - bold=True) + self.report.verbosity0("%s %s: %s" % (self.venvname, name, msg), bold=True) def info(self, name, msg): - self.report.verbosity1("%s %s: %s" %(self.venvname, name, msg), - bold=True) + self.report.verbosity1("%s %s: %s" % (self.venvname, name, msg), bold=True) def _initlogpath(self, actionid): if self.venv: @@ -83,8 +84,8 @@ class Action(object): resultjson = self.session.config.option.resultjson if resultjson or redirect: fout = self._initlogpath(self.id) - fout.write("actionid=%s\nmsg=%s\ncmdargs=%r\nenv=%s\n" %( - self.id, self.msg, args, env)) + fout.write("actionid=%s\nmsg=%s\ncmdargs=%r\nenv=%s\n" % ( + self.id, self.msg, args, env)) fout.flush() self.popen_outpath = outpath = py.path.local(fout.name) fin = outpath.open() @@ -154,9 +155,9 @@ class Action(object): if hasattr(self, "commandlog"): self.commandlog.add_command(popen.args, out, ret) raise tox.exception.InvocationError( - "%s (see %s)" %(invoked, outpath), ret) + "%s (see %s)" % (invoked, outpath), ret) else: - raise tox.exception.InvocationError("%r" %(invoked, )) + raise tox.exception.InvocationError("%r" % (invoked, )) if not out and outpath: out = outpath.read() if hasattr(self, "commandlog"): @@ -170,8 +171,8 @@ class Action(object): arg = cwd.bestrelpath(arg) newargs.append(str(arg)) - #subprocess does not always take kindly to .py scripts - #so adding the interpreter here. + # subprocess does not always take kindly to .py scripts + # so adding the interpreter here. if sys.platform == "win32": ext = os.path.splitext(str(newargs[0]))[1].lower() if ext == '.py' and self.venv: @@ -184,39 +185,37 @@ class Action(object): if env is None: env = os.environ.copy() return self.session.popen(args, shell=False, cwd=str(cwd), - universal_newlines=True, - stdout=stdout, stderr=stderr, env=env) - + universal_newlines=True, + stdout=stdout, stderr=stderr, env=env) class Reporter(object): actionchar = "-" + def __init__(self, session): self.tw = py.io.TerminalWriter() self.session = session self._reportedlines = [] - #self.cumulated_time = 0.0 + # self.cumulated_time = 0.0 def logpopen(self, popen, env): """ log information about the action.popen() created process. """ cmd = " ".join(map(str, popen.args)) if popen.outpath: - self.verbosity1(" %s$ %s >%s" %(popen.cwd, cmd, - popen.outpath, - )) + self.verbosity1(" %s$ %s >%s" % (popen.cwd, cmd, popen.outpath,)) else: - self.verbosity1(" %s$ %s " %(popen.cwd, cmd)) + self.verbosity1(" %s$ %s " % (popen.cwd, cmd)) def logaction_start(self, action): msg = action.msg + " " + " ".join(map(str, action.args)) - self.verbosity2("%s start: %s" %(action.venvname, msg), bold=True) + self.verbosity2("%s start: %s" % (action.venvname, msg), bold=True) assert not hasattr(action, "_starttime") action._starttime = now() def logaction_finish(self, action): duration = now() - action._starttime - #self.cumulated_time += duration - self.verbosity2("%s finish: %s after %.2f seconds" %( + # self.cumulated_time += duration + self.verbosity2("%s finish: %s after %.2f seconds" % ( action.venvname, action.msg, duration), bold=True) def startsummary(self): @@ -228,8 +227,7 @@ class Reporter(object): def using(self, msg): if self.session.config.option.verbosity >= 1: - self.logline("using %s" %(msg,), bold=True) - + self.logline("using %s" % (msg,), bold=True) def keyboard_interrupt(self): self.error("KEYBOARDINTERRUPT") @@ -275,7 +273,7 @@ class Reporter(object): if self.session.config.option.verbosity >= 2: self.logline("%s" % msg, **opts) - #def log(self, msg): + # def log(self, msg): # py.builtin.print_(msg, file=sys.stderr) @@ -288,13 +286,15 @@ class Session: self.report = Report(self) self.make_emptydir(config.logdir) config.logdir.ensure(dir=1) - #self.report.using("logdir %s" %(self.config.logdir,)) - self.report.using("tox.ini: %s" %(self.config.toxinipath,)) + # self.report.using("logdir %s" %(self.config.logdir,)) + self.report.using("tox.ini: %s" % (self.config.toxinipath,)) self._spec2pkg = {} self._name2venv = {} try: - self.venvlist = [self.getvenv(x) - for x in self.config.envlist] + self.venvlist = [ + self.getvenv(x) + for x in self.config.envlist + ] except LookupError: raise SystemExit(1) self._actions = [] @@ -321,15 +321,14 @@ class Session: return action def runcommand(self): - self.report.using("tox-%s from %s" %(tox.__version__, - tox.__file__)) + self.report.using("tox-%s from %s" % (tox.__version__, tox.__file__)) if self.config.minversion: minversion = NormalizedVersion(self.config.minversion) toxversion = NormalizedVersion(tox.__version__) if toxversion < minversion: self.report.error( - "tox version is %s, required is at least %s" %( - toxversion, minversion)) + "tox version is %s, required is at least %s" % ( + toxversion, minversion)) raise SystemExit(1) if self.config.option.showconfig: self.showconfig() @@ -342,7 +341,7 @@ class Session: for relpath in pathlist: src = srcdir.join(relpath) if not src.check(): - self.report.error("missing source file: %s" %(src,)) + self.report.error("missing source file: %s" % (src,)) raise SystemExit(1) target = destdir.join(relpath) target.dirpath().ensure(dir=1) @@ -358,7 +357,7 @@ class Session: self.make_emptydir(self.config.distdir) action.popen([sys.executable, setup, "sdist", "--formats=zip", "--dist-dir", self.config.distdir, ], - cwd=self.config.setupdir) + cwd=self.config.setupdir) try: return self.config.distdir.listdir()[0] except py.error.ENOENT: @@ -375,12 +374,11 @@ class Session: ) raise SystemExit(1) self.report.error( - 'No dist directory found. Please check setup.py, e.g with:\n'\ + 'No dist directory found. Please check setup.py, e.g with:\n' ' python setup.py sdist' - ) + ) raise SystemExit(1) - def make_emptydir(self, path): if path.check(): self.report.info(" removing %s" % path) @@ -446,25 +444,25 @@ class Session: :rtype: py.path.local """ if not self.config.option.sdistonly and (self.config.sdistsrc or - self.config.option.installpkg): + self.config.option.installpkg): sdist_path = self.config.option.installpkg if not sdist_path: sdist_path = self.config.sdistsrc sdist_path = self._resolve_pkg(sdist_path) self.report.info("using package %r, skipping 'sdist' activity " % - str(sdist_path)) + str(sdist_path)) else: try: sdist_path = self._makesdist() except tox.exception.InvocationError: v = sys.exc_info()[1] self.report.error("FAIL could not package project - v = %r" % - v) + v) return sdistfile = self.config.distshare.join(sdist_path.basename) if sdistfile != sdist_path: self.report.info("copying new sdistfile to %r" % - str(sdistfile)) + str(sdistfile)) try: sdistfile.dirpath().ensure(dir=1) except py.error.Error: @@ -513,24 +511,23 @@ class Session: for venv in self.venvlist: status = venv.status if isinstance(status, tox.exception.InterpreterNotFound): - msg = " %s: %s" %(venv.envconfig.envname, str(status)) + msg = " %s: %s" % (venv.envconfig.envname, str(status)) if self.config.option.skip_missing_interpreters: self.report.skip(msg) else: retcode = 1 self.report.error(msg) elif status == "platform mismatch": - msg = " %s: %s" %(venv.envconfig.envname, str(status)) + msg = " %s: %s" % (venv.envconfig.envname, str(status)) self.report.verbosity1(msg) elif status and status != "skipped tests": - msg = " %s: %s" %(venv.envconfig.envname, str(status)) + msg = " %s: %s" % (venv.envconfig.envname, str(status)) self.report.error(msg) retcode = 1 else: if not status: status = "commands succeeded" - self.report.good(" %s: %s" %(venv.envconfig.envname, - status)) + self.report.good(" %s: %s" % (venv.envconfig.envname, status)) if not retcode: self.report.good(" congratulations :)") @@ -586,7 +583,6 @@ class Session: versions.append("virtualenv-%s" % version.strip()) self.report.keyvalue("tool-versions:", " ".join(versions)) - def _resolve_pkg(self, pkgspec): try: return self._spec2pkg[pkgspec] @@ -614,7 +610,7 @@ class Session: items.append((ver, x)) else: self.report.warning("could not determine version of: %s" % - str(x)) + str(x)) items.sort() if not items: raise tox.exception.MissingDependency(pkgspec) @@ -624,6 +620,8 @@ class Session: _rex_getversion = py.std.re.compile("[\w_\-\+\.]+-(.*)(\.zip|\.tar.gz)") + + def getversion(basename): m = _rex_getversion.match(basename) if m is None: diff --git a/tox/_config.py b/tox/_config.py index 9d054a0..afd2c55 100644 --- a/tox/_config.py +++ b/tox/_config.py @@ -45,7 +45,7 @@ def parseconfig(args=None, pkg=None): if inipath.check(): break else: - feedback("toxini file %r not found" %(basename), sysexit=True) + feedback("toxini file %r not found" % (basename), sysexit=True) try: parseini(config, inipath) except tox.exception.InterpreterNotFound: @@ -54,98 +54,104 @@ def parseconfig(args=None, pkg=None): py.builtin.print_("ERROR: " + str(exn)) return config + def feedback(msg, sysexit=False): py.builtin.print_("ERROR: " + msg, file=sys.stderr) if sysexit: raise SystemExit(1) + class VersionAction(argparse.Action): def __call__(self, argparser, *args, **kwargs): name = argparser.pkgname mod = __import__(name) version = mod.__version__ - py.builtin.print_("%s imported from %s" %(version, mod.__file__)) + py.builtin.print_("%s imported from %s" % (version, mod.__file__)) raise SystemExit(0) + class CountAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): if hasattr(namespace, self.dest): - setattr(namespace, self.dest, int(getattr(namespace, self.dest))+1) + setattr(namespace, self.dest, int(getattr(namespace, self.dest)) + 1) else: setattr(namespace, self.dest, 0) + def prepare_parse(pkgname): parser = argparse.ArgumentParser(description=__doc__,) - #formatter_class=argparse.ArgumentDefaultsHelpFormatter) + # formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.pkgname = pkgname parser.add_argument("--version", nargs=0, action=VersionAction, - dest="version", - help="report version information to stdout.") + dest="version", + help="report version information to stdout.") parser.add_argument("-v", nargs=0, action=CountAction, default=0, - dest="verbosity", - help="increase verbosity of reporting output.") + dest="verbosity", + help="increase verbosity of reporting output.") parser.add_argument("--showconfig", action="store_true", - help="show configuration information for all environments. ") + help="show configuration information for all environments. ") parser.add_argument("-l", "--listenvs", action="store_true", - dest="listenvs", help="show list of test environments") + dest="listenvs", help="show list of test environments") parser.add_argument("-c", action="store", default="tox.ini", - dest="configfile", - help="use the specified config file name.") + dest="configfile", + help="use the specified config file name.") parser.add_argument("-e", action="append", dest="env", - metavar="envlist", - help="work against specified environments (ALL selects all).") + metavar="envlist", + help="work against specified environments (ALL selects all).") parser.add_argument("--notest", action="store_true", dest="notest", - help="skip invoking test commands.") + help="skip invoking test commands.") parser.add_argument("--sdistonly", action="store_true", dest="sdistonly", - help="only perform the sdist packaging activity.") + help="only perform the sdist packaging activity.") parser.add_argument("--installpkg", action="store", default=None, - metavar="PATH", - help="use specified package for installation into venv, instead of " - "creating an sdist.") + metavar="PATH", + help="use specified package for installation into venv, instead of " + "creating an sdist.") parser.add_argument("--develop", action="store_true", dest="develop", - help="install package in the venv using 'setup.py develop' via " - "'pip -e .'") + help="install package in the venv using 'setup.py develop' via " + "'pip -e .'") parser.add_argument("--set-home", action="store_true", dest="sethome", - help="(experimental) force creating a new $HOME for each test " - "environment and create .pydistutils.cfg|pip.conf files " - "if index servers are specified with tox. ") + help="(experimental) force creating a new $HOME for each test " + "environment and create .pydistutils.cfg|pip.conf files " + "if index servers are specified with tox. ") parser.add_argument('-i', action="append", - dest="indexurl", metavar="URL", - help="set indexserver url (if URL is of form name=url set the " - "url for the 'name' indexserver, specifically)") + dest="indexurl", metavar="URL", + help="set indexserver url (if URL is of form name=url set the " + "url for the 'name' indexserver, specifically)") parser.add_argument("--pre", action="store_true", dest="pre", - help="install pre-releases and development versions of dependencies. " - "This will pass the --pre option to install_command (pip by default).") + help="install pre-releases and development versions of dependencies. " + "This will pass the --pre option to install_command " + "(pip by default).") parser.add_argument("-r", "--recreate", action="store_true", - dest="recreate", - help="force recreation of virtual environments") + dest="recreate", + help="force recreation of virtual environments") parser.add_argument("--result-json", action="store", - dest="resultjson", metavar="PATH", - help="write a json file with detailed information about " - "all commands and results involved. This will turn off " - "pass-through output from running test commands which is " - "instead captured into the json result file.") + dest="resultjson", metavar="PATH", + help="write a json file with detailed information about " + "all commands and results involved. This will turn off " + "pass-through output from running test commands which is " + "instead captured into the json result file.") # We choose 1 to 4294967295 because it is the range of PYTHONHASHSEED. parser.add_argument("--hashseed", action="store", - metavar="SEED", default=None, - help="set PYTHONHASHSEED to SEED before running commands. " - "Defaults to a random integer in the range [1, 4294967295] " - "([1, 1024] on Windows). " - "Passing 'noset' suppresses this behavior.") + metavar="SEED", default=None, + help="set PYTHONHASHSEED to SEED before running commands. " + "Defaults to a random integer in the range [1, 4294967295] " + "([1, 1024] on Windows). " + "Passing 'noset' suppresses this behavior.") parser.add_argument("--force-dep", action="append", - metavar="REQ", default=None, - help="Forces a certain version of one of the dependencies " - "when configuring the virtual environment. REQ Examples " - "'pytest<2.7' or 'django>=1.6'.") + metavar="REQ", default=None, + help="Forces a certain version of one of the dependencies " + "when configuring the virtual environment. REQ Examples " + "'pytest<2.7' or 'django>=1.6'.") parser.add_argument("--sitepackages", action="store_true", - help="override sitepackages setting to True in all envs") + help="override sitepackages setting to True in all envs") parser.add_argument("--skip-missing-interpreters", action="store_true", - help="don't fail tests for missing interpreters") + help="don't fail tests for missing interpreters") parser.add_argument("args", nargs="*", - help="additional arguments available to command positional substitution") + help="additional arguments available to command positional substitution") return parser + class Config(object): def __init__(self): self.envconfigs = {} @@ -167,8 +173,9 @@ class VenvConfig: @property def envbindir(self): - if (sys.platform == "win32" and "jython" not in self.basepython - and "pypy" not in self.basepython): + if (sys.platform == "win32" + and "jython" not in self.basepython + and "pypy" not in self.basepython): return self.envdir.join("Scripts") else: return self.envdir.join("bin") @@ -185,8 +192,8 @@ class VenvConfig: def envsitepackagesdir(self): self.getsupportedinterpreter() # for throwing exceptions x = self.config.interpreters.get_sitepackagesdir( - info=self._basepython_info, - envdir=self.envdir) + info=self._basepython_info, + envdir=self.envdir) return x def getsupportedinterpreter(self): @@ -200,27 +207,29 @@ class VenvConfig: if not info.version_info: raise tox.exception.InvocationError( 'Failed to get version_info for %s: %s' % (info.name, info.err)) - if info.version_info < (2,6): + if info.version_info < (2, 6): raise tox.exception.UnsupportedInterpreter( "python2.5 is not supported anymore, sorry") return info.executable - testenvprefix = "testenv:" + def get_homedir(): try: return py.path.local._gethomedir() except Exception: return None + def make_hashseed(): max_seed = 4294967295 if sys.platform == 'win32': max_seed = 1024 return str(random.randint(1, max_seed)) + class parseini: def __init__(self, config, inipath): config.toxinipath = inipath @@ -287,8 +296,7 @@ class parseini: config.indexserver[name] = IndexServerConfig(name, override) reader.addsubstitutions(toxworkdir=config.toxworkdir) - config.distdir = reader.getpath(toxsection, "distdir", - "{toxworkdir}/dist") + config.distdir = reader.getpath(toxsection, "distdir", "{toxworkdir}/dist") reader.addsubstitutions(distdir=config.distdir) config.distshare = reader.getpath(toxsection, "distshare", distshare_default) @@ -335,18 +343,18 @@ class parseini: def _makeenvconfig(self, name, section, subs, config): vc = VenvConfig(config=config, envname=name) factors = set(name.split('-')) - reader = IniReader(self._cfg, fallbacksections=["testenv"], - factors=factors) + reader = IniReader(self._cfg, fallbacksections=["testenv"], factors=factors) reader.addsubstitutions(**subs) - vc.develop = not config.option.installpkg and \ - reader.getbool(section, "usedevelop", config.option.develop) + vc.develop = ( + not config.option.installpkg + and reader.getbool(section, "usedevelop", config.option.develop)) vc.envdir = reader.getpath(section, "envdir", "{toxworkdir}/%s" % name) vc.args_are_paths = reader.getbool(section, "args_are_paths", True) if reader.getdefault(section, "python", None): raise tox.exception.ConfigError( "'python=' key was renamed to 'basepython='") bp = next((default_factors[f] for f in factors if f in default_factors), - sys.executable) + sys.executable) vc.basepython = reader.getdefault(section, "basepython", bp) vc._basepython_info = config.interpreters.get_info(vc.basepython) reader.addsubstitutions(envdir=vc.envdir, envname=vc.envname, @@ -410,8 +418,9 @@ class parseini: break vc.platform = platform - vc.sitepackages = self.config.option.sitepackages or \ - reader.getbool(section, "sitepackages", False) + vc.sitepackages = ( + self.config.option.sitepackages + or reader.getbool(section, "sitepackages", False)) vc.downloadcache = None downloadcache = reader.getdefault(section, "downloadcache") @@ -424,10 +433,10 @@ class parseini: section, "install_command", "pip install {opts} {packages}", - ) + ) if '{packages}' not in vc.install_command: raise tox.exception.ConfigError( - "'install_command' must contain '{packages}' substitution") + "'install_command' must contain '{packages}' substitution") vc.pip_pre = config.option.pre or reader.getbool( section, "pip_pre", False) @@ -488,10 +497,12 @@ def _split_env(env): env = [env] return mapcat(_expand_envstr, env) + def _split_factor_expr(expr): partial_envs = _expand_envstr(expr) return [set(e.split('-')) for e in partial_envs] + def _expand_envstr(envstr): # split by commas not in groups tokens = re.split(r'((?:\{[^}]+\})+)|,', envstr) @@ -505,9 +516,11 @@ def _expand_envstr(envstr): return mapcat(expand, envlist) + def mapcat(f, seq): return list(itertools.chain.from_iterable(map(f, seq))) + class DepConfig: def __init__(self, name, indexserver=None): self.name = name @@ -710,7 +723,7 @@ class IniReader: x = self._replace(x) finally: assert self._subststack.pop() == (section, name) - #print "getdefault", section, name, "returned", repr(x) + # print "getdefault", section, name, "returned", repr(x) return x def _apply_factors(self, s): @@ -740,7 +753,7 @@ class IniReader: else: envkey = match_value - if not envkey in os.environ and default is None: + if envkey not in os.environ and default is None: raise tox.exception.ConfigError( "substitution env:%r: unkown environment variable %r" % (envkey, envkey)) @@ -750,11 +763,11 @@ class IniReader: def _substitute_from_other_section(self, key): if key.startswith("[") and "]" in key: i = key.find("]") - section, item = key[1:i], key[i+1:] + section, item = key[1:i], key[i + 1:] if section in self._cfg and item in self._cfg[section]: if (section, item) in self._subststack: - raise ValueError('%s already in %s' %( - (section, item), self._subststack)) + raise ValueError('%s already in %s' % ( + (section, item), self._subststack)) x = str(self._cfg[section][item]) self._subststack.append((section, item)) try: @@ -785,13 +798,14 @@ class IniReader: return '{%s}' % sub_value handlers = { - 'env' : self._replace_env, - None : self._replace_substitution, - } + 'env': self._replace_env, + None: self._replace_substitution, + } try: sub_type = g['sub_type'] except KeyError: - raise tox.exception.ConfigError("Malformed substitution; no substitution type provided") + raise tox.exception.ConfigError( + "Malformed substitution; no substitution type provided") try: handler = handlers[sub_type] @@ -808,6 +822,7 @@ class IniReader: def _parse_command(self, command): pass + class CommandParser(object): class State(object): @@ -824,11 +839,11 @@ class CommandParser(object): def word_has_ended(): return ((cur_char in string.whitespace and ps.word and - ps.word[-1] not in string.whitespace) or - (cur_char == '{' and ps.depth == 0 and not ps.word.endswith('\\')) or - (ps.depth == 0 and ps.word and ps.word[-1] == '}') or - (cur_char not in string.whitespace and ps.word and - ps.word.strip() == '')) + ps.word[-1] not in string.whitespace) or + (cur_char == '{' and ps.depth == 0 and not ps.word.endswith('\\')) or + (ps.depth == 0 and ps.word and ps.word[-1] == '}') or + (cur_char not in string.whitespace and ps.word and + ps.word.strip() == '')) def yield_this_word(): yieldword = ps.word @@ -869,8 +884,8 @@ class CommandParser(object): yield_this_word() return ps.yield_words + def getcontextname(): if any(env in os.environ for env in ['JENKINS_URL', 'HUDSON_URL']): return 'jenkins' return None - diff --git a/tox/_exception.py b/tox/_exception.py index 5244171..9917f09 100644 --- a/tox/_exception.py +++ b/tox/_exception.py @@ -1,16 +1,28 @@ class Error(Exception): def __str__(self): - return "%s: %s" %(self.__class__.__name__, self.args[0]) + return "%s: %s" % (self.__class__.__name__, self.args[0]) + + class UnsupportedInterpreter(Error): "signals an unsupported Interpreter" + + class InterpreterNotFound(Error): "signals that an interpreter could not be found" + + class InvocationError(Error): """ an error while invoking a script. """ + + class MissingFile(Error): """ an error while invoking a script. """ + + class MissingDirectory(Error): """ a directory did not exist. """ + + class MissingDependency(Error): """ a dependency could not be found or determined. """ diff --git a/tox/_pytestplugin.py b/tox/_pytestplugin.py index ded13ec..9d7488a 100644 --- a/tox/_pytestplugin.py +++ b/tox/_pytestplugin.py @@ -1,4 +1,5 @@ -import pytest, py +import py +import pytest import tox import os import sys @@ -10,6 +11,7 @@ from tox._venv import VirtualEnv from tox._cmdline import Action from tox.result import ResultLog + def pytest_configure(): if 'TOXENV' in os.environ: del os.environ['TOXENV'] @@ -19,12 +21,14 @@ def pytest_configure(): def pytest_addoption(parser): parser.addoption("--no-network", action="store_true", - dest="no_network", - help="don't run tests requiring network") + dest="no_network", + help="don't run tests requiring network") + def pytest_report_header(): return "tox comes from: %r" % (tox.__file__) + @pytest.fixture def newconfig(request, tmpdir): def newconfig(args, source=None): @@ -41,12 +45,14 @@ def newconfig(request, tmpdir): old.chdir() return newconfig + @pytest.fixture def cmd(request): if request.config.option.no_network: pytest.skip("--no-network was specified, test cannot run") return Cmd(request) + class ReportExpectMock: def __init__(self, session): self._calls = [] @@ -61,13 +67,13 @@ class ReportExpectMock: raise AttributeError(name) def generic_report(*args, **kwargs): - self._calls.append((name,)+args) - print ("%s" %(self._calls[-1], )) + self._calls.append((name,) + args) + print ("%s" % (self._calls[-1], )) return generic_report def action(self, venv, msg, *args): self._calls.append(("action", venv, msg)) - print ("%s" %(self._calls[-1], )) + print ("%s" % (self._calls[-1], )) return Action(self.session, venv, msg, args) def getnext(self, cat): @@ -82,7 +88,7 @@ class ReportExpectMock: newindex += 1 raise LookupError( "looking for %r, no reports found at >=%d in %r" % - (cat, self._index+1, self._calls)) + (cat, self._index + 1, self._calls)) def expect(self, cat, messagepattern="*", invert=False): __tracebackhide__ = True @@ -98,16 +104,17 @@ class ReportExpectMock: if fnmatch(lmsg, messagepattern): if invert: raise AssertionError("found %s(%r), didn't expect it" % - (cat, messagepattern)) + (cat, messagepattern)) return if not invert: raise AssertionError( - "looking for %s(%r), no reports found at >=%d in %r" % - (cat, messagepattern, self._index+1, self._calls)) + "looking for %s(%r), no reports found at >=%d in %r" % + (cat, messagepattern, self._index + 1, self._calls)) def not_expect(self, cat, messagepattern="*"): return self.expect(cat, messagepattern, invert=True) + class pcallMock: def __init__(self, args, cwd, env, stdout, stderr, shell): self.arg0 = args[0] @@ -120,44 +127,54 @@ class pcallMock: def communicate(self): return "", "" + def wait(self): pass + @pytest.fixture def mocksession(request): from tox._cmdline import Session + class MockSession(Session): def __init__(self): self._clearmocks() self.config = request.getfuncargvalue("newconfig")([], "") self.resultlog = ResultLog() self._actions = [] + def getenv(self, name): return VirtualEnv(self.config.envconfigs[name], session=self) + def _clearmocks(self): self._pcalls = [] self._spec2pkg = {} self.report = ReportExpectMock(self) + def make_emptydir(self, path): pass + def popen(self, args, cwd, shell=None, - universal_newlines=False, - stdout=None, stderr=None, env=None): + universal_newlines=False, + stdout=None, stderr=None, env=None): pm = pcallMock(args, cwd, env, stdout, stderr, shell) self._pcalls.append(pm) return pm return MockSession() + @pytest.fixture def 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") @@ -175,7 +192,7 @@ class Cmd: env['PYTHONPATH'] = ":".join(filter(None, [ str(os.getcwd()), env.get('PYTHONPATH', '')])) kw['env'] = env - #print "env", env + # print "env", env return py.std.subprocess.Popen(argv, stdout=stdout, stderr=stderr, **kw) def run(self, *argv): @@ -188,7 +205,7 @@ class Cmd: f2 = p2.open("wb") now = time.time() popen = self.popen(argv, stdout=f1, stderr=f2, - close_fds=(sys.platform != "win32")) + close_fds=(sys.platform != "win32")) ret = popen.wait() f1.close() f2.close() @@ -196,6 +213,7 @@ class Cmd: out = getdecoded(out).splitlines() err = p2.read("rb") err = getdecoded(err).splitlines() + def dump_lines(lines, fp): try: for line in lines: @@ -204,14 +222,16 @@ class Cmd: print("couldn't print to %s because of encoding" % (fp,)) dump_lines(out, sys.stdout) dump_lines(err, sys.stderr) - return RunResult(ret, out, err, time.time()-now) + return RunResult(ret, out, err, time.time() - now) + def getdecoded(out): try: return out.decode("utf-8") except UnicodeDecodeError: return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % ( - py.io.saferepr(out),) + py.io.saferepr(out),) + class RunResult: def __init__(self, ret, outlines, errlines, duration): @@ -222,8 +242,9 @@ class RunResult: self.stderr = LineMatcher(errlines) self.duration = duration + class LineMatcher: - def __init__(self, lines): + def __init__(self, lines): self.lines = lines def str(self): @@ -260,6 +281,7 @@ class LineMatcher: else: assert line == nextline + @pytest.fixture def initproj(request, tmpdir): """ create a factory function for creating example projects. """ @@ -288,16 +310,18 @@ def initproj(request, tmpdir): ) ''' % locals()}) if name not in filedefs: - create_files(base, {name: - {'__init__.py': '__version__ = %r' % version}}) + create_files(base, { + name: {'__init__.py': '__version__ = %r' % version} + }) manifestlines = [] for p in base.visit(lambda x: x.check(file=1)): manifestlines.append("include %s" % p.relto(base)) create_files(base, {"MANIFEST.in": "\n".join(manifestlines)}) - print ("created project in %s" %(base,)) + print ("created project in %s" % (base,)) base.chdir() return initproj + def create_files(base, filedefs): for key, value in filedefs.items(): if isinstance(value, dict): diff --git a/tox/_quickstart.py b/tox/_quickstart.py index e7c4f03..a397cb1 100644 --- a/tox/_quickstart.py +++ b/tox/_quickstart.py @@ -78,11 +78,13 @@ deps = %(deps)s class ValidationError(Exception): """Raised for validation errors.""" + def nonempty(x): if not x: raise ValidationError("Please enter some text.") return x + def choice(*l): def val(x): if x not in l: @@ -90,17 +92,20 @@ def choice(*l): return x return val + def boolean(x): if x.upper() not in ('Y', 'YES', 'N', 'NO'): raise ValidationError("Please enter either 'y' or 'n'.") return x.upper() in ('Y', 'YES') + def suffix(x): if not (x[0:1] == '.' and len(x) > 1): raise ValidationError("Please enter a file suffix, " "e.g. '.rst' or '.txt'.") return x + def ok(x): return x @@ -159,7 +164,7 @@ What Python versions do you want to test against? Choices: [3] (All versions) %s [4] Choose each one-by-one''' % ', '.join(all_envs)) do_prompt(d, 'canned_pyenvs', 'Enter the number of your choice', - '3', choice('1', '2', '3', '4')) + '3', choice('1', '2', '3', '4')) if d['canned_pyenvs'] == '1': d['py27'] = True @@ -197,17 +202,20 @@ What extra dependencies do your tests have?''') def process_input(d): d['envlist'] = ', '.join([env for env in all_envs if d.get(env) is True]) - d['deps'] = '\n' + '\n'.join([' %s' % dep.strip() - for dep in d['deps'].split(',')]) + d['deps'] = '\n' + '\n'.join([ + ' %s' % dep.strip() + for dep in d['deps'].split(',')]) return d + def rtrim_right(text): lines = [] for line in text.split("\n"): lines.append(line.rstrip()) return "\n".join(lines) + def generate(d, overwrite=True, silent=False): """Generate project based on values in *d*.""" @@ -236,7 +244,8 @@ def generate(d, overwrite=True, silent=False): if silent: return sys.stdout.write('\n') - print('Finished: A tox.ini file has been created. For information on this file, see http://tox.testrun.org/latest/config.html') + print('Finished: A tox.ini file has been created. For information on this file, ' + 'see http://tox.testrun.org/latest/config.html') print(''' Execute `tox` to test your project. ''') diff --git a/tox/_venv.py b/tox/_venv.py index 926a893..f642be0 100644 --- a/tox/_venv.py +++ b/tox/_venv.py @@ -1,11 +1,13 @@ from __future__ import with_statement -import sys, os +import os +import sys import re import codecs import py import tox from tox._config import DepConfig + class CreationConfig: def __init__(self, md5, python, version, sitepackages, develop, deps): @@ -43,11 +45,12 @@ class CreationConfig: def matches(self, other): return (other and self.md5 == other.md5 - and self.python == other.python - and self.version == other.version - and self.sitepackages == other.sitepackages - and self.develop == other.develop - and self.deps == other.deps) + and self.python == other.python + and self.version == other.version + and self.sitepackages == other.sitepackages + and self.develop == other.develop + and self.deps == other.deps) + class VirtualEnv(object): def __init__(self, envconfig=None, session=None): @@ -61,7 +64,7 @@ class VirtualEnv(object): return self.envconfig.envname def __repr__(self): - return "<VirtualEnv at %r>" %(self.path) + return "<VirtualEnv at %r>" % (self.path) def getcommandpath(self, name=None, venv=True, cwd=None): if name is None: @@ -81,7 +84,7 @@ class VirtualEnv(object): p = py.path.local.sysfind(name) if p is None: raise tox.exception.InvocationError( - "could not find executable %r" % (name,)) + "could not find executable %r" % (name,)) # p is not found in virtualenv script/bin dir if venv: if not self.is_allowed_external(p): @@ -89,15 +92,16 @@ class VirtualEnv(object): "test command found but not installed in testenv\n" " cmd: %s\n" " env: %s\n" - "Maybe forgot to specify a dependency?" % (p, - self.envconfig.envdir)) - return str(p) # will not be rewritten for reporting + "Maybe forgot to specify a dependency?" % (p, self.envconfig.envdir)) + return str(p) # will not be rewritten for reporting def is_allowed_external(self, p): tryadd = [""] if sys.platform == "win32": - tryadd += [os.path.normcase(x) - for x in os.environ['PATHEXT'].split(os.pathsep)] + tryadd += [ + os.path.normcase(x) + for x in os.environ['PATHEXT'].split(os.pathsep) + ] p = py.path.local(os.path.normcase(str(p))) for x in self.envconfig.whitelist_externals: for add in tryadd: @@ -116,7 +120,7 @@ class VirtualEnv(object): action = self.session.newaction(self, "update") rconfig = CreationConfig.readconfig(self.path_config) if not self.envconfig.recreate and rconfig and \ - rconfig.matches(self._getliveconfig()): + rconfig.matches(self._getliveconfig()): action.info("reusing", self.envconfig.envdir) return if rconfig is None: @@ -167,7 +171,7 @@ class VirtualEnv(object): return re.match(self.envconfig.platform, sys.platform) def create(self, action=None): - #if self.getcommandpath("activate").dirpath().check(): + # if self.getcommandpath("activate").dirpath().check(): # return if action is None: action = self.session.newaction(self, "create") @@ -179,11 +183,11 @@ class VirtualEnv(object): # add interpreter explicitly, to prevent using # default (virtualenv.ini) args.extend(['--python', str(config_interpreter)]) - #if sys.platform == "win32": + # if sys.platform == "win32": # f, path, _ = py.std.imp.find_module("virtualenv") # f.close() # args[:1] = [str(config_interpreter), str(path)] - #else: + # else: self.session.make_emptydir(self.path) basepath = self.path.dirpath() basepath.ensure(dir=1) @@ -191,7 +195,6 @@ class VirtualEnv(object): self._pcall(args, venv=False, action=action, cwd=basepath) self.just_created = True - def finish(self): self._getliveconfig().writeconfig(self.path_config) @@ -204,8 +207,8 @@ class VirtualEnv(object): name = output.strip() egg_info = setupdir.join('.'.join((name, 'egg-info'))) for conf_file in (setup_py, setup_cfg): - if (not egg_info.check() or (conf_file.check() - and conf_file.mtime() > egg_info.mtime())): + if (not egg_info.check() + or (conf_file.check() and conf_file.mtime() > egg_info.mtime())): return True return False @@ -240,8 +243,7 @@ class VirtualEnv(object): deps = self._getresolvedeps() if deps: depinfo = ", ".join(map(str, deps)) - action.setactivity("installdeps", - "%s" % depinfo) + action.setactivity("installdeps", "%s" % depinfo) self._install(deps, action=action) def _installopts(self, indexserver): @@ -261,10 +263,10 @@ class VirtualEnv(object): argv = self.envconfig.install_command[:] # use pip-script on win32 to avoid the executable locking i = argv.index('{packages}') - argv[i:i+1] = packages + argv[i:i + 1] = packages if '{opts}' in argv: i = argv.index('{opts}') - argv[i:i+1] = list(options) + argv[i:i + 1] = list(options) for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV', '__PYVENV_LAUNCHER__'): try: @@ -301,7 +303,7 @@ class VirtualEnv(object): if self.envconfig.config.option.sethome: extraenv = hack_home_env( homedir=self.envconfig.envtmpdir.join("pseudo-home"), - index_url = ixserver.url) + index_url=ixserver.url) else: extraenv = {} @@ -351,7 +353,8 @@ class VirtualEnv(object): ignore_ret = False try: - self._pcall(argv, cwd=cwd, action=action, redirect=redirect, ignore_ret=ignore_ret) + self._pcall(argv, cwd=cwd, action=action, redirect=redirect, + ignore_ret=ignore_ret) except tox.exception.InvocationError: val = sys.exc_info()[1] self.session.report.error(str(val)) @@ -362,7 +365,7 @@ class VirtualEnv(object): raise def _pcall(self, args, venv=True, cwd=None, extraenv={}, - action=None, redirect=True, ignore_ret=False): + action=None, redirect=True, ignore_ret=False): for name in ("VIRTUALENV_PYTHON", "PYTHONDONTWRITEBYTECODE"): try: del os.environ[name] diff --git a/tox/_verlib.py b/tox/_verlib.py index a234176..a2e7471 100644 --- a/tox/_verlib.py +++ b/tox/_verlib.py @@ -10,10 +10,12 @@ licensed under the PSF license (i guess) import re + class IrrationalVersionError(Exception): """This is an irrational version.""" pass + class HugeMajorVersionNumError(IrrationalVersionError): """An irrational version because the major version number is huge (often because a year or date was used). @@ -52,6 +54,7 @@ VERSION_RE = re.compile(r''' (?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)? $''', re.VERBOSE) + class NormalizedVersion(object): """A rational version. @@ -136,7 +139,8 @@ class NormalizedVersion(object): parts.append(FINAL_MARKER) self.parts = tuple(parts) if error_on_huge_major_num and self.parts[0][0] > 1980: - raise HugeMajorVersionNumError("huge major version number, %r, " + raise HugeMajorVersionNumError( + "huge major version number, %r, " "which might cause future problems: %r" % (self.parts[0][0], s)) def _parse_numdots(self, s, full_ver_str, drop_trailing_zeros=True, @@ -154,7 +158,8 @@ class NormalizedVersion(object): nums = [] for n in s.split("."): if len(n) > 1 and n[0] == '0': - raise IrrationalVersionError("cannot have leading zero in " + raise IrrationalVersionError( + "cannot have leading zero in " "version number segment: '%s' in %r" % (n, full_ver_str)) nums.append(int(n)) if drop_trailing_zeros: @@ -193,7 +198,7 @@ class NormalizedVersion(object): def _cannot_compare(self, other): raise TypeError("cannot compare %s and %s" - % (type(self).__name__, type(other).__name__)) + % (type(self).__name__, type(other).__name__)) def __eq__(self, other): if not isinstance(other, NormalizedVersion): @@ -217,6 +222,7 @@ class NormalizedVersion(object): def __ge__(self, other): return self.__eq__(other) or self.__gt__(other) + def suggest_normalized_version(s): """Suggest a normalized version close to the given version string. @@ -272,7 +278,7 @@ def suggest_normalized_version(s): rs = rs[1:] # Clean leading '0's on numbers. - #TODO: unintended side-effect on, e.g., "2003.05.09" + # TODO: unintended side-effect on, e.g., "2003.05.09" # PyPI stats: 77 (~2%) better rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) @@ -318,7 +324,6 @@ def suggest_normalized_version(s): # PyPI stats: ~21 (0.62%) better rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) - # Tcl/Tk uses "px" for their post release markers rs = re.sub(r"p(\d+)$", r".post\1", rs) @@ -328,4 +333,3 @@ def suggest_normalized_version(s): except IrrationalVersionError: pass return None - diff --git a/tox/interpreters.py b/tox/interpreters.py index 241651f..76075b8 100644 --- a/tox/interpreters.py +++ b/tox/interpreters.py @@ -3,6 +3,7 @@ import py import re import inspect + class Interpreters: def __init__(self): self.name2executable = {} @@ -42,20 +43,21 @@ class Interpreters: envdir = str(envdir) try: res = exec_on_interpreter(info.executable, - [inspect.getsource(sitepackagesdir), - "print (sitepackagesdir(%r))" % envdir]) + [inspect.getsource(sitepackagesdir), + "print (sitepackagesdir(%r))" % envdir]) except ExecFailed: val = sys.exc_info()[1] - print ("execution failed: %s -- %s" %(val.out, val.err)) + print ("execution failed: %s -- %s" % (val.out, val.err)) return "" else: return res["dir"] + def run_and_get_interpreter_info(name, executable): assert executable try: result = exec_on_interpreter(executable, - [inspect.getsource(pyinfo), "print (pyinfo())"]) + [inspect.getsource(pyinfo), "print (pyinfo())"]) except ExecFailed: val = sys.exc_info()[1] return NoInterpreterInfo(name, executable=val.executable, @@ -63,6 +65,7 @@ def run_and_get_interpreter_info(name, executable): else: return InterpreterInfo(name, executable, **result) + def exec_on_interpreter(executable, source): if isinstance(source, list): source = "\n".join(source) @@ -80,6 +83,7 @@ def exec_on_interpreter(executable, source): "could not decode %r" % out) return result + class ExecFailed(Exception): def __init__(self, executable, source, out, err): self.executable = executable @@ -87,6 +91,7 @@ class ExecFailed(Exception): self.out = out self.err = err + class InterpreterInfo: runnable = True @@ -99,10 +104,12 @@ class InterpreterInfo: def __str__(self): return "<executable at %s, version_info %s>" % ( - self.executable, self.version_info) + self.executable, self.version_info) + class NoInterpreterInfo: runnable = False + def __init__(self, name, executable=None, out=None, err="not found"): self.name = name @@ -124,9 +131,10 @@ if sys.platform != "win32": else: # Exceptions to the usual windows mapping win32map = { - 'python': sys.executable, - 'jython': "c:\jython2.5.1\jython.bat", + 'python': sys.executable, + 'jython': "c:\jython2.5.1\jython.bat", } + def locate_via_py(v_maj, v_min): ver = "-%s.%s" % (v_maj, v_min) script = "import sys; print(sys.executable)" @@ -162,11 +170,13 @@ else: if m: return locate_via_py(*m.groups()) + def pyinfo(): import sys return dict(version_info=tuple(sys.version_info), sysplatform=sys.platform) + def sitepackagesdir(envdir): from distutils.sysconfig import get_python_lib return dict(dir=get_python_lib(prefix=envdir)) diff --git a/tox/result.py b/tox/result.py index ee5ad09..7bedd3f 100644 --- a/tox/result.py +++ b/tox/result.py @@ -46,23 +46,24 @@ class EnvLog: def set_python_info(self, pythonexecutable): pythonexecutable = py.path.local(pythonexecutable) out = pythonexecutable.sysexec("-c", - "import sys; " - "print (sys.executable);" - "print (list(sys.version_info)); " - "print (sys.version)") + "import sys; " + "print (sys.executable);" + "print (list(sys.version_info)); " + "print (sys.version)") lines = out.splitlines() executable = lines.pop(0) version_info = eval(lines.pop(0)) version = "\n".join(lines) self.dict["python"] = dict( executable=executable, - version_info = version_info, - version = version) + version_info=version_info, + version=version) def get_commandlog(self, name): l = self.dict.setdefault(name, []) return CommandLog(self, l) + class CommandLog: def __init__(self, envlog, list): self.envlog = envlog |
