Skip to content

Commit 9d741a5

Browse files
committed
interative shell dependent config
1 parent ad81f9a commit 9d741a5

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

changelog/947.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
allow injecting config value inside the ini file dependent of the fact that we're connected to an interactive shell or not - by :user:`gaborbernat`

doc/config.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,17 @@ the above example is roughly equivalent to
564564
.. _`command positional substitution`:
565565
.. _`positional substitution`:
566566

567+
interactive shell substitution
568+
++++++++++++++++++++++++++++++
569+
570+
It's possible to inject a config value only when tox is running in interactive shell (standard input):
571+
572+
{tty:ON_VALUE:OFF_VALUE}
573+
574+
The first value is the value to inject when the interactive terminal is available,
575+
the second value is the value to use when it's not. The later on is optional. A good use case
576+
for this is e.g. passing in the ``--pdb`` flag for pytest.
577+
567578
substitutions for positional arguments in commands
568579
++++++++++++++++++++++++++++++++++++++++++++++++++
569580

src/tox/config.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,23 +1430,27 @@ def _replace_match(self, match):
14301430

14311431
if sub_type == "env":
14321432
return self._replace_env(match)
1433+
if sub_type == "tty":
1434+
if is_interactive():
1435+
return match.group("substitution_value")
1436+
return match.group("default_value")
14331437
if sub_type is not None:
14341438
raise tox.exception.ConfigError(
14351439
"No support for the {} substitution type".format(sub_type)
14361440
)
14371441
return self._replace_substitution(match)
14381442

14391443
def _replace_env(self, match):
1440-
envkey = match.group("substitution_value")
1441-
if not envkey:
1444+
key = match.group("substitution_value")
1445+
if not key:
14421446
raise tox.exception.ConfigError("env: requires an environment variable name")
14431447
default = match.group("default_value")
1444-
envvalue = self.reader.get_environ_value(envkey)
1445-
if envvalue is not None:
1446-
return envvalue
1448+
value = self.reader.get_environ_value(key)
1449+
if value is not None:
1450+
return value
14471451
if default is not None:
14481452
return default
1449-
raise tox.exception.MissingSubstitution(envkey)
1453+
raise tox.exception.MissingSubstitution(key)
14501454

14511455
def _substitute_from_other_section(self, key):
14521456
if key.startswith("[") and "]" in key:
@@ -1475,6 +1479,10 @@ def _replace_substitution(self, match):
14751479
return str(val)
14761480

14771481

1482+
def is_interactive():
1483+
return sys.stdin.isatty()
1484+
1485+
14781486
class _ArgvlistReader:
14791487
@classmethod
14801488
def getargvlist(cls, reader, value, replace=True):

tests/unit/test_config.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2724,3 +2724,29 @@ def test_config_bad_config_type_specified(monkeypatch, tmpdir, capsys):
27242724
msg = "\n".join(notes) + "\n"
27252725
assert err == msg
27262726
assert "ERROR:" not in out
2727+
2728+
2729+
def test_interactive_na(newconfig, monkeypatch):
2730+
monkeypatch.setattr(tox.config, "is_interactive", lambda: False)
2731+
config = newconfig(
2732+
"""
2733+
[testenv:py]
2734+
setenv = A = {tty:X:Y}
2735+
"""
2736+
)
2737+
assert config.envconfigs["py"].setenv["A"] == "Y"
2738+
2739+
2740+
def test_interactive_available(newconfig, monkeypatch):
2741+
monkeypatch.setattr(tox.config, "is_interactive", lambda: True)
2742+
config = newconfig(
2743+
"""
2744+
[testenv:py]
2745+
setenv = A = {tty:X:Y}
2746+
"""
2747+
)
2748+
assert config.envconfigs["py"].setenv["A"] == "X"
2749+
2750+
2751+
def test_interactive():
2752+
tox.config.is_interactive()

0 commit comments

Comments
 (0)