summaryrefslogtreecommitdiff
path: root/coverage/tomlconfig.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2022-12-29 10:42:03 -0500
committerNed Batchelder <ned@nedbatchelder.com>2022-12-29 11:28:03 -0500
commit46dd5bd33031d6c0501238e8459d81e8b91a416d (patch)
tree5e4ab6dd610192acf90dd381a4a1c1bc4aed6763 /coverage/tomlconfig.py
parentd4c2b18bdd0102ff873514e53ec560c3083c3413 (diff)
downloadpython-coveragepy-git-46dd5bd33031d6c0501238e8459d81e8b91a416d.tar.gz
mypy: check tomlconfig.py
Diffstat (limited to 'coverage/tomlconfig.py')
-rw-r--r--coverage/tomlconfig.py57
1 files changed, 36 insertions, 21 deletions
diff --git a/coverage/tomlconfig.py b/coverage/tomlconfig.py
index a25b3e35..31cd0bb0 100644
--- a/coverage/tomlconfig.py
+++ b/coverage/tomlconfig.py
@@ -5,10 +5,14 @@
import os
import re
+import sys
+
+from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type, TypeVar
from coverage import env
from coverage.exceptions import ConfigError
from coverage.misc import import_third_party, substitute_variables
+from coverage.types import TConfigSection, TConfigValue
if env.PYVERSION >= (3, 11, 0, "alpha", 7):
@@ -23,6 +27,8 @@ class TomlDecodeError(Exception):
pass
+TWant = TypeVar("TWant")
+
class TomlConfigParser:
"""TOML file reading with the interface of HandyConfigParser."""
@@ -30,11 +36,11 @@ class TomlConfigParser:
# need for docstrings.
# pylint: disable=missing-function-docstring
- def __init__(self, our_file):
+ def __init__(self, our_file: bool) -> None:
self.our_file = our_file
- self.data = None
+ self.data: Dict[str, Any] = {}
- def read(self, filenames):
+ def read(self, filenames: Iterable[str]) -> List[str]:
# RawConfigParser takes a filename or list of filenames, but we only
# ever call this with a single filename.
assert isinstance(filenames, (bytes, str, os.PathLike))
@@ -45,7 +51,7 @@ class TomlConfigParser:
toml_text = fp.read()
except OSError:
return []
- if tomllib is not None:
+ if sys.version_info >= (3, 11) or tomllib is not None:
try:
self.data = tomllib.loads(toml_text)
except tomllib.TOMLDecodeError as err:
@@ -59,7 +65,7 @@ class TomlConfigParser:
raise ConfigError(msg.format(filename))
return []
- def _get_section(self, section):
+ def _get_section(self, section: str) -> Tuple[Optional[str], Optional[TConfigSection]]:
"""Get a section from the data.
Arguments:
@@ -86,18 +92,19 @@ class TomlConfigParser:
return None, None
return real_section, data
- def _get(self, section, option):
+ def _get(self, section: str, option: str) -> Tuple[str, TConfigValue]:
"""Like .get, but returns the real section name and the value."""
name, data = self._get_section(section)
if data is None:
raise ConfigError(f"No section: {section!r}")
+ assert name is not None
try:
value = data[option]
except KeyError:
raise ConfigError(f"No option {option!r} in section: {name!r}") from None
return name, value
- def _get_single(self, section, option):
+ def _get_single(self, section: str, option: str) -> Any:
"""Get a single-valued option.
Performs environment substitution if the value is a string. Other types
@@ -108,35 +115,43 @@ class TomlConfigParser:
value = substitute_variables(value, os.environ)
return name, value
- def has_option(self, section, option):
+ def has_option(self, section: str, option: str) -> bool:
_, data = self._get_section(section)
if data is None:
return False
return option in data
- def real_section(self, section):
+ def real_section(self, section: str) -> Optional[str]:
name, _ = self._get_section(section)
return name
- def has_section(self, section):
+ def has_section(self, section: str) -> bool:
name, _ = self._get_section(section)
return bool(name)
- def options(self, section):
+ def options(self, section: str) -> List[str]:
_, data = self._get_section(section)
if data is None:
raise ConfigError(f"No section: {section!r}")
return list(data.keys())
- def get_section(self, section):
+ def get_section(self, section: str) -> TConfigSection:
_, data = self._get_section(section)
- return data
+ return data or {}
- def get(self, section, option):
+ def get(self, section: str, option: str) -> Any:
_, value = self._get_single(section, option)
return value
- def _check_type(self, section, option, value, type_, converter, type_desc):
+ def _check_type(
+ self,
+ section: str,
+ option: str,
+ value: Any,
+ type_: Type[TWant],
+ converter: Optional[Callable[[Any], TWant]],
+ type_desc: str,
+ ) -> TWant:
"""Check that `value` has the type we want, converting if needed.
Returns the resulting value of the desired type.
@@ -154,23 +169,23 @@ class TomlConfigParser:
f"Option [{section}]{option} is not {type_desc}: {value!r}"
)
- def getboolean(self, section, option):
+ def getboolean(self, section: str, option: str) -> bool:
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 _get_list(self, section, option):
+ def _get_list(self, section: str, option: str) -> Tuple[str, List[str]]:
"""Get a list of strings, substituting environment variables in the elements."""
name, values = self._get(section, option)
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):
+ def getlist(self, section: str, option: str) -> List[str]:
_, values = self._get_list(section, option)
return values
- def getregexlist(self, section, option):
+ def getregexlist(self, section: str, option: str) -> List[str]:
name, values = self._get_list(section, option)
for value in values:
value = value.strip()
@@ -180,11 +195,11 @@ class TomlConfigParser:
raise ConfigError(f"Invalid [{name}].{option} value {value!r}: {e}") from e
return values
- def getint(self, section, option):
+ def getint(self, section: str, option: str) -> int:
name, value = self._get_single(section, option)
return self._check_type(name, option, value, int, int, "an integer")
- def getfloat(self, section, option):
+ def getfloat(self, section: str, option: str) -> float:
name, value = self._get_single(section, option)
if isinstance(value, int):
value = float(value)