summaryrefslogtreecommitdiff
path: root/coverage/tomlconfig.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2022-10-27 11:48:07 -0400
committerNed Batchelder <ned@nedbatchelder.com>2022-10-28 06:49:09 -0400
commit44fbd3b02ad22326767dc37fe3b94aa93b36e8a3 (patch)
tree4436af357817104861a154edd57d9ffa5e6c591e /coverage/tomlconfig.py
parent89aabf3e008082d1ace0efafda2bdb1c0b93a78b (diff)
downloadpython-coveragepy-git-44fbd3b02ad22326767dc37fe3b94aa93b36e8a3.tar.gz
fix: in toml config, only apply environment substitution to coverage settings. #1481
Diffstat (limited to 'coverage/tomlconfig.py')
-rw-r--r--coverage/tomlconfig.py69
1 files changed, 47 insertions, 22 deletions
diff --git a/coverage/tomlconfig.py b/coverage/tomlconfig.py
index 148c34f8..0b5052b4 100644
--- a/coverage/tomlconfig.py
+++ b/coverage/tomlconfig.py
@@ -52,7 +52,6 @@ class TomlConfigParser:
except OSError:
return []
if tomllib is not None:
- toml_text = substitute_variables(toml_text, os.environ)
try:
self.data = tomllib.loads(toml_text)
except tomllib.TOMLDecodeError as err:
@@ -101,9 +100,21 @@ class TomlConfigParser:
if data is None:
raise configparser.NoSectionError(section)
try:
- return name, data[option]
+ value = data[option]
except KeyError as exc:
raise configparser.NoOptionError(option, name) from exc
+ return name, value
+
+ def _get_single(self, section, option):
+ """Get a single-valued option.
+
+ Performs environment substitution if the value is a string. Other types
+ will be converted later as needed.
+ """
+ name, value = self._get(section, option)
+ if isinstance(value, str):
+ value = substitute_variables(value, os.environ)
+ return name, value
def has_option(self, section, option):
_, data = self._get_section(section)
@@ -126,29 +137,45 @@ class TomlConfigParser:
return data
def get(self, section, option):
- _, value = self._get(section, option)
+ _, value = self._get_single(section, option)
return value
- def _check_type(self, section, option, value, type_, type_desc):
- if not isinstance(value, type_):
- raise ValueError(
- 'Option {!r} in section {!r} is not {}: {!r}'
- .format(option, section, type_desc, value)
- )
+ def _check_type(self, section, option, value, type_, converter, type_desc):
+ """Check that `value` has the type we want, converting if needed.
+
+ Returns the resulting value of the desired type.
+ """
+ if isinstance(value, type_):
+ return value
+ if isinstance(value, str) and converter is not None:
+ try:
+ return converter(value)
+ except Exception as e:
+ raise ValueError(
+ f"Option [{section}]{option} couldn't convert to {type_desc}: {value!r}"
+ ) from e
+ raise ValueError(
+ f"Option [{section}]{option} is not {type_desc}: {value!r}"
+ )
def getboolean(self, section, option):
- name, value = self._get(section, option)
- self._check_type(name, option, value, bool, "a boolean")
- return value
+ name, value = self._get_single(section, option)
+ bool_strings = {"true": True, "false": False}
+ return self._check_type(name, option, value, bool, bool_strings.__getitem__, "a boolean")
- def getlist(self, section, option):
+ def _get_list(self, section, option):
+ """Get a list of strings, substituting environment variables in the elements."""
name, values = self._get(section, option)
- self._check_type(name, option, values, list, "a list")
+ values = self._check_type(name, option, values, list, None, "a list")
+ values = [substitute_variables(value, os.environ) for value in values]
+ return name, values
+
+ def getlist(self, section, option):
+ _, values = self._get_list(section, option)
return values
def getregexlist(self, section, option):
- name, values = self._get(section, option)
- self._check_type(name, option, values, list, "a list")
+ name, values = self._get_list(section, option)
for value in values:
value = value.strip()
try:
@@ -158,13 +185,11 @@ class TomlConfigParser:
return values
def getint(self, section, option):
- name, value = self._get(section, option)
- self._check_type(name, option, value, int, "an integer")
- return value
+ name, value = self._get_single(section, option)
+ return self._check_type(name, option, value, int, int, "an integer")
def getfloat(self, section, option):
- name, value = self._get(section, option)
+ name, value = self._get_single(section, option)
if isinstance(value, int):
value = float(value)
- self._check_type(name, option, value, float, "a float")
- return value
+ return self._check_type(name, option, value, float, float, "a float")