Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3516)

Delta Between Two Patch Sets: Lib/sysconfig.py

Issue 14057: Speedup sysconfig startup
Left Patch Set: Created 1 year, 3 months ago
Right Patch Set: Created 1 year, 3 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/packaging/tests/test_command_install_data.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7