| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 """Access to Python's configuration information.""" | 1 """Access to Python's configuration information.""" |
| 2 import os | 2 import os |
| 3 import re | 3 import re |
| 4 import sys | 4 import sys |
| 5 from os.path import pardir, realpath | 5 from os.path import pardir, realpath |
| 6 | |
| 7 import itertools | |
| 8 | |
| 9 class SectionProxy: | |
| 10 def __init__(self, parser, name): | |
| 11 self._parser = parser | |
| 12 self._name = name | |
| 13 | |
| 14 def __getitem__(self, key): | |
| 15 if not self._parser.has_option(self._name, key): | |
| 16 raise KeyError(key) | |
| 17 return self._parser.get(self._name, key) | |
| 18 | |
| 19 def __contains__(self, key): | |
| 20 return self._parser.has_option(self._name, key) | |
| 21 | |
| 22 def __iter__(self): | |
| 23 return iter(self._parser.options(self._name)) | |
| 24 | |
| 25 def get(self, option): | |
| 26 return self._parser.get(self._name, option) | |
| 27 | |
| 28 class _ConfigParser: | |
| 29 """Specialized copy of configparser.RawConfigParser: read-only using dict."" " | |
| 30 | |
| 31 def __init__(self): | |
| 32 self._sections = dict() | |
| 33 self._proxies = dict() | |
| 34 | |
| 35 def sections(self): | |
| 36 return list(self._sections.keys()) | |
| 37 | |
| 38 def add_section(self, section): | |
| 39 if section in self._sections: | |
| 40 raise DuplicateSectionError(section) | |
| 41 self._sections[section] = dict() | |
| 42 self._proxies[section] = SectionProxy(self, section) | |
| 43 | |
| 44 def has_section(self, section): | |
| 45 return section in self._sections | |
| 46 | |
| 47 def options(self, section): | |
| 48 try: | |
| 49 opts = self._sections[section].copy() | |
| 50 except KeyError: | |
| 51 raise NoSectionError(section) | |
| 52 return list(opts.keys()) | |
| 53 | |
| 54 def read(self, filename): | |
| 55 with open(filename) as fp: | |
| 56 self._read(fp, filename) | |
| 57 | |
| 58 def items(self, section): | |
| 59 d = dict() | |
| 60 try: | |
| 61 d.update(self._sections[section]) | |
| 62 except KeyError: | |
| 63 raise NoSectionError(section) | |
| 64 return [(option, d[option]) for option in d.keys()] | |
| 65 | |
| 66 def has_option(self, section, option): | |
| 67 if section not in self._sections: | |
| 68 return False | |
| 69 else: | |
| 70 option = option | |
| 71 return option in self._sections[section] | |
| 72 | |
| 73 def set(self, section, option, value=None): | |
| 74 try: | |
| 75 sectdict = self._sections[section] | |
| 76 except KeyError: | |
| 77 raise NoSectionError(section) | |
| 78 sectdict[option] = value | |
| 79 | |
| 80 def remove_section(self, section): | |
| 81 existed = section in self._sections | |
| 82 if existed: | |
| 83 del self._sections[section] | |
| 84 del self._proxies[section] | |
| 85 return existed | |
| 86 | |
| 87 def __getitem__(self, key): | |
| 88 if not self.has_section(key): | |
| 89 raise KeyError(key) | |
| 90 return self._proxies[key] | |
| 91 | |
| 92 def __setitem__(self, section, keys): | |
| 93 self.remove_section(section) | |
| 94 elements_added = set() | |
| 95 section = str(section) | |
| 96 try: | |
| 97 self.add_section(section) | |
| 98 except (DuplicateSectionError, ValueError): | |
| 99 if section in elements_added: | |
| 100 raise | |
| 101 elements_added.add(section) | |
| 102 for key, value in keys.items(): | |
| 103 key = str(key) | |
| 104 if value is not None: | |
| 105 value = str(value) | |
| 106 if (section, key) in elements_added: | |
| 107 raise DuplicateOptionError(section, key, '<dict>') | |
| 108 elements_added.add((section, key)) | |
| 109 self.set(section, key, value) | |
| 110 | |
| 111 def __contains__(self, key): | |
| 112 return self.has_section(key) | |
| 113 | |
| 114 def __iter__(self): | |
| 115 return iter(self._sections.keys()) | |
| 116 | |
| 117 def _read(self, fp, fpname): | |
| 118 elements_added = set() | |
| 119 cursect = None # None, or a dictionary | |
| 120 sectname = None | |
| 121 optname = None | |
| 122 lineno = 0 | |
| 123 indent_level = 0 | |
| 124 optcre = re.compile(r"(?P<option>.*?)\s*(?P<vi>[=:])\s*(?P<value>.*)$") | |
| 125 nonspacecre = re.compile(r"\S") | |
| 126 e = None # None, or an exception | |
| 127 for lineno, line in enumerate(fp, start=1): | |
| 128 comment_start = None | |
| 129 # strip full line comments | |
| 130 for prefix in ('#', ';'): | |
| 131 if line.strip().startswith(prefix): | |
| 132 comment_start = 0 | |
| 133 break | |
| 134 value = line[:comment_start].strip() | |
| 135 if not value: | |
| 136 # add empty line to the value, but only if there was no | |
| 137 # comment on the line | |
| 138 if (comment_start is None and | |
| 139 cursect is not None and | |
| 140 optname and | |
| 141 cursect[optname] is not None): | |
| 142 cursect[optname].append('') # newlines added at join | |
| 143 continue | |
| 144 # continuation line? | |
| 145 first_nonspace = nonspacecre.search(line) | |
| 146 cur_indent_level = first_nonspace.start() if first_nonspace else 0 | |
| 147 if (cursect is not None and optname and | |
| 148 cur_indent_level > indent_level): | |
| 149 cursect[optname].append(value) | |
| 150 # a section header or option header? | |
| 151 else: | |
| 152 indent_level = cur_indent_level | |
| 153 # is it a section header? | |
| 154 if value.startswith('[') and value.endswith(']'): | |
| 155 sectname = value[1:-1] | |
| 156 if sectname in self._sections: | |
| 157 if sectname in elements_added: | |
| 158 raise DuplicateSectionError(sectname, fpname, | |
| 159 lineno) | |
| 160 cursect = self._sections[sectname] | |
| 161 elements_added.add(sectname) | |
| 162 else: | |
| 163 cursect = dict() | |
| 164 self._sections[sectname] = cursect | |
| 165 self._proxies[sectname] = SectionProxy(self, sectname) | |
| 166 elements_added.add(sectname) | |
| 167 # So sections can't start with a continuation line | |
| 168 optname = None | |
| 169 # no section header in the file? | |
| 170 elif cursect is None: | |
| 171 raise MissingSectionHeaderError(fpname, lineno, line) | |
| 172 # an option line? | |
| 173 else: | |
| 174 mo = optcre.match(value) | |
| 175 if mo: | |
| 176 optname, vi, optval = mo.group('option', 'vi', 'value') | |
| 177 if not optname: | |
| 178 e = self._handle_error(e, fpname, lineno, line) | |
| 179 optname = optname.rstrip() | |
| 180 if (sectname, optname) in elements_added: | |
| 181 raise DuplicateOptionError(sectname, optname, | |
| 182 fpname, lineno) | |
| 183 elements_added.add((sectname, optname)) | |
| 184 # This check is fine because the OPTCRE cannot | |
| 185 # match if it would set optval to None | |
| 186 if optval is not None: | |
| 187 optval = optval.strip() | |
| 188 cursect[optname] = [optval] | |
| 189 else: | |
| 190 # valueless option handling | |
| 191 cursect[optname] = None | |
| 192 else: | |
| 193 # a non-fatal parsing error occurred. set up the | |
| 194 # exception but keep going. the exception will be | |
| 195 # raised at the end of the file and will contain a | |
| 196 # list of all bogus lines | |
| 197 e = self._handle_error(e, fpname, lineno, line) | |
| 198 # if any parsing errors occurred, raise an exception | |
| 199 if e: | |
| 200 raise e | |
| 201 self._join_multiline_values() | |
| 202 | |
| 203 def _join_multiline_values(self): | |
| 204 for section, options in self._sections.items(): | |
| 205 for name, val in options.items(): | |
| 206 if isinstance(val, list): | |
| 207 val = '\n'.join(val).rstrip() | |
| 208 options[name] = val | |
| 209 | |
| 210 def _handle_error(self, exc, fpname, lineno, line): | |
| 211 if not exc: | |
| 212 exc = ParsingError(fpname) | |
| 213 exc.append(lineno, repr(line)) | |
| 214 return exc | |
| 215 | 6 |
| 216 __all__ = [ | 7 __all__ = [ |
| 217 'get_config_h_filename', | 8 'get_config_h_filename', |
| 218 'get_config_var', | 9 'get_config_var', |
| 219 'get_config_vars', | 10 'get_config_vars', |
| 220 'get_makefile_filename', | 11 'get_makefile_filename', |
| 221 'get_path', | 12 'get_path', |
| 222 'get_path_names', | 13 'get_path_names', |
| 223 'get_paths', | 14 'get_paths', |
| 224 'get_platform', | 15 'get_platform', |
| 225 'get_python_version', | 16 'get_python_version', |
| 226 'get_scheme_names', | 17 'get_scheme_names', |
| 227 'parse_config_h', | 18 'parse_config_h', |
| 228 ] | 19 ] |
| 20 | |
| 21 class SectionProxy: | |
| 22 def __init__(self, parser, name): | |
| 23 self._parser = parser | |
| 24 self._name = name | |
| 25 | |
| 26 def __iter__(self): | |
| 27 return iter(self._parser.options(self._name)) | |
| 28 | |
| 29 class _ConfigParser: | |
| 30 """ | |
| 31 configparser.RawConfigParser copy specialized for sysconfig: | |
| 32 - read-only | |
| 33 - use dict | |
| 34 - only support "#" prefix for comments | |
| 35 - only support "=" option name/value separator | |
| 36 - don't use custom exceptions | |
| 37 """ | |
| 38 | |
| 39 def __init__(self): | |
| 40 self._sections = dict() | |
| 41 self._proxies = dict() | |
| 42 | |
| 43 def sections(self): | |
| 44 return list(self._sections.keys()) | |
| 45 | |
| 46 def add_section(self, section): | |
| 47 if section in self._sections: | |
| 48 raise Exception("Section %s already exists" % section) | |
| 49 self._sections[section] = dict() | |
| 50 self._proxies[section] = SectionProxy(self, section) | |
| 51 | |
| 52 def has_section(self, section): | |
| 53 return section in self._sections | |
| 54 | |
| 55 def options(self, section): | |
| 56 return list(self._sections[section].keys()) | |
| 57 | |
| 58 def items(self, section): | |
| 59 return self._sections[section].items() | |
| 60 | |
| 61 def has_option(self, section, option): | |
| 62 if section not in self._sections: | |
| 63 return False | |
| 64 else: | |
| 65 option = option | |
| 66 return option in self._sections[section] | |
| 67 | |
| 68 def set(self, section, option, value=None): | |
| 69 self._sections[section][option] = value | |
| 70 | |
| 71 def remove_section(self, section): | |
| 72 existed = section in self._sections | |
| 73 if existed: | |
| 74 del self._sections[section] | |
| 75 del self._proxies[section] | |
| 76 return existed | |
| 77 | |
| 78 def __getitem__(self, key): | |
| 79 return self._proxies[key] | |
| 80 | |
| 81 def __iter__(self): | |
| 82 return iter(self._sections.keys()) | |
| 83 | |
| 84 def read(self, filename): | |
| 85 with open(filename, encoding="ASCII") as fp: | |
| 86 self._read(fp, filename) | |
| 87 | |
| 88 def _read(self, fp, fpname): | |
| 89 cursect = None # None, or a dictionary | |
| 90 sectname = None | |
| 91 optname = None | |
| 92 lineno = 0 | |
| 93 for lineno, line in enumerate(fp, start=1): | |
| 94 value = line.strip() | |
| 95 if value.startswith('#'): | |
| 96 continue | |
| 97 if not value: | |
| 98 continue | |
| 99 | |
| 100 # is it a section header? | |
| 101 if value.startswith('[') and value.endswith(']'): | |
| 102 sectname = value[1:-1] | |
| 103 if sectname in self._sections: | |
| 104 raise Exception("%s:%s: Section %s already exists" | |
| 105 % (fpname, lineno, sectname)) | |
| 106 else: | |
| 107 cursect = dict() | |
| 108 self._sections[sectname] = cursect | |
| 109 self._proxies[sectname] = SectionProxy(self, sectname) | |
| 110 # So sections can't start with a continuation line | |
| 111 optname = None | |
| 112 # no section header in the file? | |
| 113 elif cursect is None: | |
| 114 raise Exception('%s:%s: File contains no section headers' | |
| 115 % (fpname, lineno)) | |
| 116 # an option line? | |
| 117 else: | |
| 118 optname, optval = value.split('=', 1) | |
| 119 optname = optname.rstrip() | |
| 120 optval = optval.lstrip() | |
|
gregory.p.smith
2012/03/20 05:13:35
do we need to preserve trailing spaces on a value?
haypo
2012/03/20 10:22:22
line.strip() is supposed to have already removed t
| |
| 121 if not optname: | |
| 122 raise ValueError("%s:%s: Empty option name" | |
| 123 % (fpname, lineno)) | |
| 124 optname = optname.rstrip() | |
|
gregory.p.smith
2012/03/20 05:13:35
you already did this above.
haypo
2012/03/20 10:22:22
Ah yes, I forgot it in the cleanup.
| |
| 125 if optname in cursect: | |
| 126 raise DuplicateOptionError(sectname, optname, | |
| 127 fpname, lineno) | |
| 128 cursect[optname] = optval | |
| 229 | 129 |
| 230 # let's read the configuration file | 130 # let's read the configuration file |
| 231 # XXX _CONFIG_DIR will be set by the Makefile later | 131 # XXX _CONFIG_DIR will be set by the Makefile later |
| 232 _CONFIG_DIR = os.path.normpath(os.path.dirname(__file__)) | 132 _CONFIG_DIR = os.path.normpath(os.path.dirname(__file__)) |
| 233 _CONFIG_FILE = os.path.join(_CONFIG_DIR, 'sysconfig.cfg') | 133 _CONFIG_FILE = os.path.join(_CONFIG_DIR, 'sysconfig.cfg') |
| 234 _SCHEMES = _ConfigParser() | 134 _SCHEMES = _ConfigParser() |
| 235 _SCHEMES.read(_CONFIG_FILE) | 135 _SCHEMES.read(_CONFIG_FILE) |
| 236 _VAR_REPL = re.compile(r'\{([^{]*?)\}') | 136 _VAR_REPL = re.compile(r'\{([^{]*?)\}') |
| 237 | 137 |
| 238 | 138 |
| (...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 985 print('Current installation scheme: "%s"' % _get_default_scheme()) | 885 print('Current installation scheme: "%s"' % _get_default_scheme()) |
| 986 print() | 886 print() |
| 987 _print_dict('Paths', get_paths()) | 887 _print_dict('Paths', get_paths()) |
| 988 print() | 888 print() |
| 989 _print_dict('Variables', get_config_vars()) | 889 _print_dict('Variables', get_config_vars()) |
| 990 | 890 |
| 991 | 891 |
| 992 if __name__ == '__main__': | 892 if __name__ == '__main__': |
| 993 _main() | 893 _main() |
| 994 | 894 |
| LEFT | RIGHT |