summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorholger krekel <holger@merlinux.eu>2014-09-02 14:52:12 +0200
committerholger krekel <holger@merlinux.eu>2014-09-02 14:52:12 +0200
commit45a0a8507d53fe85c748dbbed8b940ea2ee2d4dd (patch)
tree2a76c349dbfe8f5face3975f44d6e3dc209ea780
parentc0af5a5eb243d3eb0b4cdd8e452e00838c187010 (diff)
parent0a8c4513f6ea3f51b2e8861eae2fbb6faa0a3892 (diff)
downloadtox-45a0a8507d53fe85c748dbbed8b940ea2ee2d4dd.tar.gz
Merged in myint/tox (pull request #118)
Fix "__PYVENV_LAUNCHER__" problem
-rw-r--r--doc/config.txt81
-rw-r--r--tests/test_config.py28
-rw-r--r--tox/_config.py14
3 files changed, 90 insertions, 33 deletions
diff --git a/doc/config.txt b/doc/config.txt
index 0721a87..8ce64db 100644
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -405,7 +405,7 @@ However, a better approach looks like this::
pytest
django15: Django>=1.5,<1.6
django16: Django>=1.6,<1.7
- !py27: unittest2
+ py26: unittest2
commands = py.test
This uses two new facilities of tox-1.8:
@@ -417,6 +417,7 @@ This uses two new facilities of tox-1.8:
Let's go through this step by step.
+
Generative envlist
+++++++++++++++++++++++
@@ -432,7 +433,7 @@ like this::
py27-django15
py27-django16
-You can still list environments explicitely along with generated ones::
+You can still list environments explicitly along with generated ones::
envlist = {py26,py27}-django{15,16}, docs, flake
@@ -441,13 +442,13 @@ You can still list environments explicitely along with generated ones::
To help with understanding how the variants will produce section values,
you can ask tox to show their expansion with a new option::
- $ tox -l
- py26-django15
- py26-django16
- py27-django15
- py27-django16
- docs
- flake
+ $ tox -l
+ py26-django15
+ py26-django16
+ py27-django15
+ py27-django16
+ docs
+ flake
Factors and factor-conditional settings
@@ -471,23 +472,14 @@ optional lines with unconditional ones::
pytest
django15: Django>=1.5,<1.6
django16: Django>=1.6,<1.7
- !py27: unittest2
-
-The last line here uses negation of a factor, this means ``unittest2`` will be
-in ``deps`` for all pythons except python2.7. The whole effect of this setting
-definition could be described with a table:
+ py26: unittest2
-=============== ==================================
-environment deps
-=============== ==================================
-py26-django15 pytest, Django>=1.5,<1.6, unitest2
-py26-django16 pytest, Django>=1.6,<1.7, unitest2
-py27-django15 pytest, Django>=1.5,<1.6
-py27-django16 pytest, Django>=1.6,<1.7
-=============== ==================================
+Reading it line by line:
-And this table can significantly grow as you have more dependencies and other
-factors such as platform, python version and/or database.
+- ``pytest`` will be included unconditionally,
+- ``Django>=1.5,<1.6`` will be included for environments containing ``django15`` factor,
+- ``Django>=1.6,<1.7`` similarly depends on ``django16`` factor,
+- ``unittest`` will be loaded for Python 2.6 environments.
.. note::
@@ -496,6 +488,47 @@ factors such as platform, python version and/or database.
setting.
+Complex factor conditions
++++++++++++++++++++++++++
+
+Sometimes you need to specify same line for several factors or create a special
+case for a combination of factors. Here is how you do it::
+
+ [tox]
+ envlist = py{26,27,33}-django{15,16}-{sqlite,mysql}
+
+ [testenv]
+ deps =
+ py33-mysql: PyMySQL ; use if both py33 and mysql are in an env name
+ py26,py27: urllib3 ; use if any of py26 or py27 are in an env name
+ py{26,27}-sqlite: mock ; mocking sqlite in python 2.x
+
+Take a look at first ``deps`` line. It shows how you can special case something
+for a combination of factors, you just join combining factors with a hyphen.
+This particular line states that ``PyMySQL`` will be loaded for python 3.3,
+mysql environments, e.g. ``py33-django15-mysql`` and ``py33-django16-mysql``.
+
+The second line shows how you use same line for several factors - by listing
+them delimited by commas. It's possible to list not only simple factors, but
+also their combinations like ``py26-sqlite,py27-sqlite``.
+
+Finally, factor expressions are expanded the same way as envlist, so last
+example could be rewritten as ``py{26,27}-sqlite``.
+
+.. note::
+
+ Factors don't do substring matching against env name, instead every
+ hyphenated expression is split by ``-`` and if ALL the factors in an
+ expression are also factors of an env then that condition is considered
+ hold.
+
+ For example, environment ``py26-mysql``:
+
+ - could be matched with expressions ``py26``, ``py26-mysql``,
+ ``mysql-py26``,
+ - but not with ``py2`` or ``py26-sql``.
+
+
Other Rules and notes
=====================
diff --git a/tests/test_config.py b/tests/test_config.py
index 28afa6c..7cbb656 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -835,20 +835,38 @@ class TestConfigTestEnv:
def test_factors(self, newconfig):
inisource="""
[tox]
- envlist = a,b
+ envlist = a-x,b
[testenv]
deps=
dep-all
a: dep-a
b: dep-b
- !a: dep-not-a
+ x: dep-x
"""
conf = newconfig([], inisource)
configs = conf.envconfigs
- assert [dep.name for dep in configs['a'].deps] == ["dep-all", "dep-a"]
- assert [dep.name for dep in configs['b'].deps] == \
- ["dep-all", "dep-b", "dep-not-a"]
+ assert [dep.name for dep in configs['a-x'].deps] == \
+ ["dep-all", "dep-a", "dep-x"]
+ assert [dep.name for dep in configs['b'].deps] == ["dep-all", "dep-b"]
+
+ def test_factor_ops(self, newconfig):
+ inisource="""
+ [tox]
+ envlist = {a,b}-{x,y}
+
+ [testenv]
+ deps=
+ a,b: dep-a-or-b
+ a-x: dep-a-and-x
+ {a,b}-y: dep-ab-and-y
+ """
+ configs = newconfig([], inisource).envconfigs
+ get_deps = lambda env: [dep.name for dep in configs[env].deps]
+ assert get_deps("a-x") == ["dep-a-or-b", "dep-a-and-x"]
+ assert get_deps("a-y") == ["dep-a-or-b", "dep-ab-and-y"]
+ assert get_deps("b-x") == ["dep-a-or-b"]
+ assert get_deps("b-y") == ["dep-a-or-b", "dep-ab-and-y"]
def test_default_factors(self, newconfig):
inisource="""
diff --git a/tox/_config.py b/tox/_config.py
index 6e8e706..26603c9 100644
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -302,7 +302,8 @@ class parseini:
factors = set()
if section in self._cfg:
for _, value in self._cfg[section].items():
- factors.update(re.findall(r'^!?(\w+)\:\s+', value, re.M))
+ exprs = re.findall(r'^([\w{},-]+)\:\s+', value, re.M)
+ factors.update(*mapcat(_split_factor_expr, exprs))
return factors
def _makeenvconfig(self, name, section, subs, config):
@@ -434,12 +435,17 @@ class parseini:
dep2_name = pkg_resources.Requirement.parse(dep2).project_name
return dep1_name == dep2_name
+
def _split_env(env):
"""if handed a list, action="append" was used for -e """
if not isinstance(env, list):
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)
@@ -628,12 +634,12 @@ class IniReader:
def _apply_factors(self, s):
def factor_line(line):
- m = re.search(r'^(!)?(\w+)\:\s+(.+)', line)
+ m = re.search(r'^([\w{},-]+)\:\s+(.+)', line)
if not m:
return line
- negate, factor, line = m.groups()
- if bool(negate) ^ (factor in self.factors):
+ expr, line = m.groups()
+ if any(fs <= self.factors for fs in _split_factor_expr(expr)):
return line
lines = s.strip().splitlines()