eric7/DebugClients/Python/coverage/tomlconfig.py

branch
eric7
changeset 8775
0802ae193343
parent 8527
2bd1325d727e
child 8929
fcca2fa618bf
equal deleted inserted replaced
8774:d728227e8ebb 8775:0802ae193343
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt 2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
3 3
4 """TOML configuration support for coverage.py""" 4 """TOML configuration support for coverage.py"""
5 5
6 import io 6 import configparser
7 import os 7 import os
8 import re 8 import re
9 9
10 from coverage import env 10 from coverage.exceptions import CoverageException
11 from coverage.backward import configparser, path_types 11 from coverage.misc import import_third_party, substitute_variables
12 from coverage.misc import CoverageException, substitute_variables
13 12
14 # TOML support is an install-time extra option. 13 # TOML support is an install-time extra option. (Import typing is here because
15 try: 14 # import_third_party will unload any module that wasn't already imported.
16 import toml 15 # tomli imports typing, and if we unload it, later it's imported again, and on
17 except ImportError: # pragma: not covered 16 # Python 3.6, this causes infinite recursion.)
18 toml = None 17 import typing # pylint: disable=unused-import, wrong-import-order
18 tomli = import_third_party("tomli")
19 19
20 20
21 class TomlDecodeError(Exception): 21 class TomlDecodeError(Exception):
22 """An exception class that exists even when toml isn't installed.""" 22 """An exception class that exists even when toml isn't installed."""
23 pass 23 pass
35 self.data = None 35 self.data = None
36 36
37 def read(self, filenames): 37 def read(self, filenames):
38 # RawConfigParser takes a filename or list of filenames, but we only 38 # RawConfigParser takes a filename or list of filenames, but we only
39 # ever call this with a single filename. 39 # ever call this with a single filename.
40 assert isinstance(filenames, path_types) 40 assert isinstance(filenames, (bytes, str, os.PathLike))
41 filename = filenames 41 filename = os.fspath(filenames)
42 if env.PYVERSION >= (3, 6):
43 filename = os.fspath(filename)
44 42
45 try: 43 try:
46 with io.open(filename, encoding='utf-8') as fp: 44 with open(filename, encoding='utf-8') as fp:
47 toml_text = fp.read() 45 toml_text = fp.read()
48 except IOError: 46 except OSError:
49 return [] 47 return []
50 if toml: 48 if tomli is not None:
51 toml_text = substitute_variables(toml_text, os.environ) 49 toml_text = substitute_variables(toml_text, os.environ)
52 try: 50 try:
53 self.data = toml.loads(toml_text) 51 self.data = tomli.loads(toml_text)
54 except toml.TomlDecodeError as err: 52 except tomli.TOMLDecodeError as err:
55 raise TomlDecodeError(*err.args) 53 raise TomlDecodeError(str(err)) from err
56 return [filename] 54 return [filename]
57 else: 55 else:
58 has_toml = re.search(r"^\[tool\.coverage\.", toml_text, flags=re.MULTILINE) 56 has_toml = re.search(r"^\[tool\.coverage\.", toml_text, flags=re.MULTILINE)
59 if self.our_file or has_toml: 57 if self.our_file or has_toml:
60 # Looks like they meant to read TOML, but we can't read it. 58 # Looks like they meant to read TOML, but we can't read it.
96 name, data = self._get_section(section) 94 name, data = self._get_section(section)
97 if data is None: 95 if data is None:
98 raise configparser.NoSectionError(section) 96 raise configparser.NoSectionError(section)
99 try: 97 try:
100 return name, data[option] 98 return name, data[option]
101 except KeyError: 99 except KeyError as exc:
102 raise configparser.NoOptionError(option, name) 100 raise configparser.NoOptionError(option, name) from exc
103 101
104 def has_option(self, section, option): 102 def has_option(self, section, option):
105 _, data = self._get_section(section) 103 _, data = self._get_section(section)
106 if data is None: 104 if data is None:
107 return False 105 return False
148 for value in values: 146 for value in values:
149 value = value.strip() 147 value = value.strip()
150 try: 148 try:
151 re.compile(value) 149 re.compile(value)
152 except re.error as e: 150 except re.error as e:
153 raise CoverageException( 151 raise CoverageException(f"Invalid [{name}].{option} value {value!r}: {e}") from e
154 "Invalid [%s].%s value %r: %s" % (name, option, value, e)
155 )
156 return values 152 return values
157 153
158 def getint(self, section, option): 154 def getint(self, section, option):
159 name, value = self._get(section, option) 155 name, value = self._get(section, option)
160 self._check_type(name, option, value, int, "an integer") 156 self._check_type(name, option, value, int, "an integer")

eric ide

mercurial