summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2018-09-08 16:17:09 -0400
committerNed Batchelder <ned@nedbatchelder.com>2018-09-08 16:17:09 -0400
commitdde0a3ef3b88eb79bff8a36943cf934452eb8c26 (patch)
treeda7de4d5c688bc1b1ee5e85f9371de032d6661d4
parentf4a99853c8dc38a2feafcd0d575a99633786d22d (diff)
downloadpython-coveragepy-git-dde0a3ef3b88eb79bff8a36943cf934452eb8c26.tar.gz
Move variable substitution to be independent
-rw-r--r--coverage/config.py19
-rw-r--r--coverage/misc.py37
-rw-r--r--tests/test_misc.py18
3 files changed, 56 insertions, 18 deletions
diff --git a/coverage/config.py b/coverage/config.py
index 061fa304..69c929b4 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -10,6 +10,7 @@ import re
from coverage import env
from coverage.backward import configparser, iitems, string_class
from coverage.misc import contract, CoverageException, isolate_module
+from coverage.misc import substitute_variables
os = isolate_module(os)
@@ -85,23 +86,7 @@ class HandyConfigParser(configparser.RawConfigParser):
raise configparser.NoOptionError
v = configparser.RawConfigParser.get(self, real_section, option, *args, **kwargs)
- def dollar_replace(m):
- """Called for each $replacement."""
- # Only one of the groups will have matched, just get its text.
- word = next(w for w in m.groups() if w is not None) # pragma: part covered
- if word == "$":
- return "$"
- else:
- return os.environ.get(word, '')
-
- dollar_pattern = r"""(?x) # Use extended regex syntax
- \$(?: # A dollar sign, then
- (?P<v1>\w+) | # a plain word,
- {(?P<v2>\w+)} | # or a {-wrapped word,
- (?P<char>[$]) # or a dollar sign.
- )
- """
- v = re.sub(dollar_pattern, dollar_replace, v)
+ v = substitute_variables(v)
return v
def getlist(self, section, option):
diff --git a/coverage/misc.py b/coverage/misc.py
index ab950846..e2031852 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -8,6 +8,7 @@ import hashlib
import inspect
import locale
import os
+import re
import sys
import types
@@ -250,6 +251,42 @@ def _needs_to_implement(that, func_name):
)
+def substitute_variables(text, variables=os.environ):
+ """Substitute ``${VAR}`` variables in `text` with their values.
+
+ Variables in the text can take a number of shell-inspired forms::
+
+ $VAR
+ ${VAR}
+
+ A dollar can be inserted with ``$$``.
+
+ `variables` is a dictionary of variable values, defaulting to the
+ environment variables.
+
+ Returns the resulting text with values substituted.
+
+ """
+ def dollar_replace(m):
+ """Called for each $replacement."""
+ # Only one of the groups will have matched, just get its text.
+ word = next(w for w in m.groups() if w is not None) # pragma: part covered
+ if word == "$":
+ return "$"
+ else:
+ return variables.get(word, '')
+
+ dollar_pattern = r"""(?x) # Use extended regex syntax
+ \$(?: # A dollar sign, then
+ (?P<v1>\w+) | # a plain word,
+ {(?P<v2>\w+)} | # or a {-wrapped word,
+ (?P<char>[$]) # or a dollar sign.
+ )
+ """
+ text = re.sub(dollar_pattern, dollar_replace, text)
+ return text
+
+
class BaseCoverageException(Exception):
"""The base of all Coverage exceptions."""
pass
diff --git a/tests/test_misc.py b/tests/test_misc.py
index 1d01537b..77200b3c 100644
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -6,7 +6,7 @@
import pytest
from coverage.misc import contract, dummy_decorator_with_args, file_be_gone
-from coverage.misc import format_lines, Hasher, one_of
+from coverage.misc import format_lines, Hasher, one_of, substitute_variables
from tests.coveragetest import CoverageTest
@@ -135,3 +135,19 @@ class ContractTest(CoverageTest):
])
def test_format_lines(statements, lines, result):
assert format_lines(statements, lines) == result
+
+
+@pytest.mark.parametrize("before, after", [
+ ("Nothing to do", "Nothing to do"),
+ ("Dollar: $$", "Dollar: $"),
+ ("Simple: $FOO is fooey", "Simple: fooey is fooey"),
+ ("Braced: X${FOO}X.", "Braced: XfooeyX."),
+ ("Missing: x$NOTHING is x", "Missing: x is x"),
+ ("Multiple: $$ $FOO $BAR ${FOO}", "Multiple: $ fooey xyzzy fooey"),
+])
+def test_substitute_variables(before, after):
+ variables = {
+ 'FOO': 'fooey',
+ 'BAR': 'xyzzy',
+ }
+ assert substitute_variables(before, variables) == after