Gentoo Archives: gentoo-portage-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-portage-dev@l.g.o
Cc: "Michał Górny" <mgorny@g.o>
Subject: [gentoo-portage-dev] [PATCH 2/2] portage.util.configparser: Commonize portable config file reading routine
Date: Sun, 22 May 2016 08:42:06
Message-Id: 20160522084148.2658-2-mgorny@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH 1/2] portage.util.configparser: Provide common code to handle cp imports by "Michał Górny"
1 ---
2 pym/portage/_sets/__init__.py | 29 ++-----------------
3 pym/portage/repository/config.py | 38 ++-----------------------
4 pym/portage/util/_desktop_entry.py | 20 ++-----------
5 pym/portage/util/configparser.py | 57 +++++++++++++++++++++++++++++++++++++-
6 4 files changed, 64 insertions(+), 80 deletions(-)
7
8 diff --git a/pym/portage/_sets/__init__.py b/pym/portage/_sets/__init__.py
9 index ec42f7c..6d69bda 100644
10 --- a/pym/portage/_sets/__init__.py
11 +++ b/pym/portage/_sets/__init__.py
12 @@ -22,7 +22,7 @@ from portage.exception import PackageSetNotFound
13 from portage.localization import _
14 from portage.util import writemsg_level
15 from portage.util.configparser import (SafeConfigParser,
16 - NoOptionError, ParsingError)
17 + NoOptionError, ParsingError, read_configs)
18
19 SETPREFIX = "@"
20
21 @@ -50,32 +50,7 @@ class SetConfig(object):
22 })
23
24 if _ENABLE_SET_CONFIG:
25 - # use read_file/readfp in order to control decoding of unicode
26 - try:
27 - # Python >=3.2
28 - read_file = self._parser.read_file
29 - except AttributeError:
30 - read_file = self._parser.readfp
31 -
32 - for p in paths:
33 - f = None
34 - try:
35 - f = io.open(_unicode_encode(p,
36 - encoding=_encodings['fs'], errors='strict'),
37 - mode='r', encoding=_encodings['repo.content'],
38 - errors='replace')
39 - except EnvironmentError:
40 - pass
41 - else:
42 - try:
43 - read_file(f)
44 - except ParsingError as e:
45 - writemsg_level(_unicode_decode(
46 - _("!!! Error while reading sets config file: %s\n")
47 - ) % e, level=logging.ERROR, noiselevel=-1)
48 - finally:
49 - if f is not None:
50 - f.close()
51 + read_configs(self._parser, paths)
52 else:
53 self._create_default_config()
54
55 diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py
56 index 9039886..a23f4bd 100644
57 --- a/pym/portage/repository/config.py
58 +++ b/pym/portage/repository/config.py
59 @@ -17,7 +17,8 @@ from portage.eapi import eapi_allows_directories_on_profile_level_and_repository
60 from portage.env.loaders import KeyValuePairFileLoader
61 from portage.util import (normalize_path, read_corresponding_eapi_file, shlex_split,
62 stack_lists, writemsg, writemsg_level, _recursive_file_list)
63 -from portage.util.configparser import SafeConfigParser, ConfigParserError
64 +from portage.util.configparser import (SafeConfigParser, ConfigParserError,
65 + read_configs)
66 from portage.util._path import isdir_raise_eaccess
67 from portage.util.path import first_existing
68 from portage.localization import _
69 @@ -542,15 +543,6 @@ class RepoConfigLoader(object):
70 """Parse files in paths to load config"""
71 parser = SafeConfigParser(defaults=default_opts)
72
73 - # use read_file/readfp in order to control decoding of unicode
74 - try:
75 - # Python >=3.2
76 - read_file = parser.read_file
77 - source_kwarg = 'source'
78 - except AttributeError:
79 - read_file = parser.readfp
80 - source_kwarg = 'filename'
81 -
82 recursive_paths = []
83 for p in paths:
84 if isinstance(p, basestring):
85 @@ -558,31 +550,7 @@ class RepoConfigLoader(object):
86 else:
87 recursive_paths.append(p)
88
89 - for p in recursive_paths:
90 - if isinstance(p, basestring):
91 - f = None
92 - try:
93 - f = io.open(_unicode_encode(p,
94 - encoding=_encodings['fs'], errors='strict'),
95 - mode='r', encoding=_encodings['repo.content'],
96 - errors='replace')
97 - except EnvironmentError:
98 - pass
99 - else:
100 - # The 'source' keyword argument is needed since otherwise
101 - # ConfigParser in Python <3.3.3 may throw a TypeError
102 - # because it assumes that f.name is a native string rather
103 - # than binary when constructing error messages.
104 - kwargs = {source_kwarg: p}
105 - read_file(f, **portage._native_kwargs(kwargs))
106 - finally:
107 - if f is not None:
108 - f.close()
109 - elif isinstance(p, io.StringIO):
110 - kwargs = {source_kwarg: "<io.StringIO>"}
111 - read_file(p, **portage._native_kwargs(kwargs))
112 - else:
113 - raise TypeError("Unsupported type %r of element %r of 'paths' argument" % (type(p), p))
114 + read_configs(parser, recursive_paths)
115
116 prepos['DEFAULT'] = RepoConfig("DEFAULT",
117 parser.defaults(), local_config=local_config)
118 diff --git a/pym/portage/util/_desktop_entry.py b/pym/portage/util/_desktop_entry.py
119 index 95a015e..4fe4194 100644
120 --- a/pym/portage/util/_desktop_entry.py
121 +++ b/pym/portage/util/_desktop_entry.py
122 @@ -9,7 +9,8 @@ import sys
123 import portage
124 from portage import _encodings, _unicode_encode, _unicode_decode
125 from portage.util import writemsg
126 -from portage.util.configparser import ConfigParserError, RawConfigParser
127 +from portage.util.configparser import (ConfigParserError, RawConfigParser,
128 + read_configs)
129
130
131 def parse_desktop_entry(path):
132 @@ -20,22 +21,7 @@ def parse_desktop_entry(path):
133 """
134 parser = RawConfigParser()
135
136 - # use read_file/readfp in order to control decoding of unicode
137 - try:
138 - # Python >=3.2
139 - read_file = parser.read_file
140 - except AttributeError:
141 - read_file = parser.readfp
142 -
143 - with io.open(_unicode_encode(path,
144 - encoding=_encodings['fs'], errors='strict'),
145 - mode='r', encoding=_encodings['repo.content'],
146 - errors='replace') as f:
147 - content = f.read()
148 -
149 - # In Python 3.2, read_file does not support bytes in file names
150 - # (see bug #429544), so use StringIO to hide the file name.
151 - read_file(io.StringIO(content))
152 + read_configs(parser, [path])
153
154 return parser
155
156 diff --git a/pym/portage/util/configparser.py b/pym/portage/util/configparser.py
157 index d305052..fb1a351 100644
158 --- a/pym/portage/util/configparser.py
159 +++ b/pym/portage/util/configparser.py
160 @@ -2,12 +2,13 @@
161 # Distributed under the terms of the GNU General Public License v2
162
163 __all__ = ['ConfigParserError', 'NoOptionError', 'ParsingError',
164 - 'RawConfigParser', 'SafeConfigParser']
165 + 'RawConfigParser', 'SafeConfigParser', 'read_configs']
166
167 # the following scary compatibility thing provides two classes:
168 # - SafeConfigParser that provides safe interpolation for values,
169 # - RawConfigParser that provides no interpolation for values.
170
171 +import io
172 import sys
173
174 try:
175 @@ -20,3 +21,57 @@ try:
176 except ImportError:
177 from ConfigParser import (Error as ConfigParserError,
178 NoOptionError, ParsingError, RawConfigParser, SafeConfigParser)
179 +
180 +from portage import _encodings
181 +from portage import _native_kwargs
182 +from portage import _unicode_encode
183 +
184 +
185 +if sys.hexversion >= 0x3000000:
186 + # pylint: disable=W0622
187 + basestring = str
188 +
189 +
190 +def read_configs(parser, paths):
191 + """
192 + Read configuration files from given paths into the specified
193 + ConfigParser, handling path encoding portably.
194 + @param parser: target *ConfigParser instance
195 + @type parser: SafeConfigParser or RawConfigParser
196 + @param paths: list of paths to read
197 + @type paths: iterable
198 + """
199 + # use read_file/readfp in order to control decoding of unicode
200 + try:
201 + # Python >=3.2
202 + read_file = parser.read_file
203 + source_kwarg = 'source'
204 + except AttributeError:
205 + read_file = parser.readfp
206 + source_kwarg = 'filename'
207 +
208 + for p in paths:
209 + if isinstance(p, basestring):
210 + f = None
211 + try:
212 + f = io.open(_unicode_encode(p,
213 + encoding=_encodings['fs'], errors='strict'),
214 + mode='r', encoding=_encodings['repo.content'],
215 + errors='replace')
216 + except EnvironmentError:
217 + pass
218 + else:
219 + # The 'source' keyword argument is needed since otherwise
220 + # ConfigParser in Python <3.3.3 may throw a TypeError
221 + # because it assumes that f.name is a native string rather
222 + # than binary when constructing error messages.
223 + kwargs = {source_kwarg: p}
224 + read_file(f, **_native_kwargs(kwargs))
225 + finally:
226 + if f is not None:
227 + f.close()
228 + elif isinstance(p, io.StringIO):
229 + kwargs = {source_kwarg: "<io.StringIO>"}
230 + read_file(p, **_native_kwargs(kwargs))
231 + else:
232 + raise TypeError("Unsupported type %r of element %r of 'paths' argument" % (type(p), p))
233 --
234 2.8.3

Replies