Merge lp:~jelmer/brz/move-errors-config into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Merge reported by: Jelmer Vernooij
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/move-errors-config
Merge into: lp:brz
Diff against target: 586 lines (+134/-133)
3 files modified
breezy/config.py (+108/-20)
breezy/errors.py (+0/-88)
breezy/tests/test_config.py (+26/-25)
To merge this branch: bzr merge lp:~jelmer/brz/move-errors-config
Reviewer Review Type Date Requested Status
Martin Packman Approve
Review via email: mp+327488@code.launchpad.net

Commit message

Move config-related errors from breezy.errors to breezy.config.

Description of the change

Move config-related errors from breezy.errors to breezy.config.

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

See inline comment, otherwise looks sane.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/config.py'
2--- breezy/config.py 2017-07-04 20:03:11 +0000
3+++ breezy/config.py 2017-07-15 16:04:48 +0000
4@@ -92,7 +92,6 @@
5 controldir,
6 debug,
7 directory_service,
8- errors,
9 lazy_regex,
10 library_state,
11 lockdir,
12@@ -108,6 +107,7 @@
13 """)
14 from . import (
15 commands,
16+ errors,
17 hooks,
18 lazy_regex,
19 registry,
20@@ -155,6 +155,94 @@
21 STORE_GLOBAL = 4
22
23
24+# FIXME: I would prefer to define the config related exception classes in
25+# config.py but the lazy import mechanism proscribes this -- vila 20101222
26+class OptionExpansionLoop(errors.BzrError):
27+
28+ _fmt = 'Loop involving %(refs)r while expanding "%(string)s".'
29+
30+ def __init__(self, string, refs):
31+ self.string = string
32+ self.refs = '->'.join(refs)
33+
34+
35+class ExpandingUnknownOption(errors.BzrError):
36+
37+ _fmt = 'Option "%(name)s" is not defined while expanding "%(string)s".'
38+
39+ def __init__(self, name, string):
40+ self.name = name
41+ self.string = string
42+
43+
44+class IllegalOptionName(errors.BzrError):
45+
46+ _fmt = 'Option "%(name)s" is not allowed.'
47+
48+ def __init__(self, name):
49+ self.name = name
50+
51+
52+class ConfigContentError(errors.BzrError):
53+
54+ _fmt = "Config file %(filename)s is not UTF-8 encoded\n"
55+
56+ def __init__(self, filename):
57+ errors.BzrError.__init__(self)
58+ self.filename = filename
59+
60+
61+class ParseConfigError(errors.BzrError):
62+
63+ _fmt = "Error(s) parsing config file %(filename)s:\n%(errors)s"
64+
65+ def __init__(self, errors, filename):
66+ errors.BzrError.__init__(self)
67+ self.filename = filename
68+ self.errors = '\n'.join(e.msg for e in errors)
69+
70+
71+class ConfigOptionValueError(errors.BzrError):
72+
73+ _fmt = ('Bad value "%(value)s" for option "%(name)s".\n'
74+ 'See ``brz help %(name)s``')
75+
76+ def __init__(self, name, value):
77+ errors.BzrError.__init__(self, name=name, value=value)
78+
79+
80+class NoEmailInUsername(errors.BzrError):
81+
82+ _fmt = "%(username)r does not seem to contain a reasonable email address"
83+
84+ def __init__(self, username):
85+ errors.BzrError.__init__(self)
86+ self.username = username
87+
88+
89+class NoSuchConfig(errors.BzrError):
90+
91+ _fmt = ('The "%(config_id)s" configuration does not exist.')
92+
93+ def __init__(self, config_id):
94+ errors.BzrError.__init__(self, config_id=config_id)
95+
96+
97+class NoSuchConfigOption(errors.BzrError):
98+
99+ _fmt = ('The "%(option_name)s" configuration option does not exist.')
100+
101+ def __init__(self, option_name):
102+ errors.BzrError.__init__(self, option_name=option_name)
103+
104+
105+class NoWhoami(errors.BzrError):
106+
107+ _fmt = ('Unable to determine your name.\n'
108+ "Please, set your name with the 'whoami' command.\n"
109+ 'E.g. brz whoami "Your Name <name@example.com>"')
110+
111+
112 def signature_policy_from_unicode(signature_string):
113 """Convert a string to a signing policy."""
114 if signature_string.lower() == 'check-available':
115@@ -342,11 +430,11 @@
116 else:
117 name = chunk[1:-1]
118 if name in _ref_stack:
119- raise errors.OptionExpansionLoop(string, _ref_stack)
120+ raise OptionExpansionLoop(string, _ref_stack)
121 _ref_stack.append(name)
122 value = self._expand_option(name, env, _ref_stack)
123 if value is None:
124- raise errors.ExpandingUnknownOption(name, string)
125+ raise ExpandingUnknownOption(name, string)
126 if isinstance(value, list):
127 list_value = True
128 chunks.extend(value)
129@@ -666,9 +754,9 @@
130 try:
131 self._parser = ConfigObj(co_input, encoding='utf-8')
132 except configobj.ConfigObjError as e:
133- raise errors.ParseConfigError(e.errors, e.config.filename)
134+ raise ParseConfigError(e.errors, e.config.filename)
135 except UnicodeDecodeError:
136- raise errors.ConfigContentError(self.file_name)
137+ raise ConfigContentError(self.file_name)
138 # Make sure self.reload() will use the right file name
139 self._parser.filename = self.file_name
140 for hook in OldConfigHooks['load']:
141@@ -840,7 +928,7 @@
142 try:
143 del section[option_name]
144 except KeyError:
145- raise errors.NoSuchConfigOption(option_name)
146+ raise NoSuchConfigOption(option_name)
147 self._write_config_file()
148 for hook in OldConfigHooks['remove']:
149 hook(self, option_name)
150@@ -1591,7 +1679,7 @@
151 """
152 name, email = parse_username(e)
153 if not email:
154- raise errors.NoEmailInUsername(e)
155+ raise NoEmailInUsername(e)
156 return email
157
158
159@@ -1669,9 +1757,9 @@
160 # encoded, but the values in the ConfigObj are always Unicode.
161 self._config = ConfigObj(self._input, encoding='utf-8')
162 except configobj.ConfigObjError as e:
163- raise errors.ParseConfigError(e.errors, e.config.filename)
164+ raise ParseConfigError(e.errors, e.config.filename)
165 except UnicodeError:
166- raise errors.ConfigContentError(self._filename)
167+ raise ConfigContentError(self._filename)
168 return self._config
169
170 def _check_permissions(self):
171@@ -2202,9 +2290,9 @@
172 try:
173 conf = ConfigObj(f, encoding='utf-8')
174 except configobj.ConfigObjError as e:
175- raise errors.ParseConfigError(e.errors, self._external_url())
176+ raise ParseConfigError(e.errors, self._external_url())
177 except UnicodeDecodeError:
178- raise errors.ConfigContentError(self._external_url())
179+ raise ConfigContentError(self._external_url())
180 finally:
181 f.close()
182 return conf
183@@ -2320,7 +2408,7 @@
184 trace.warning('Value "%s" is not valid for "%s"',
185 unicode_value, self.name)
186 elif self.invalid == 'error':
187- raise errors.ConfigOptionValueError(self.name, unicode_value)
188+ raise ConfigOptionValueError(self.name, unicode_value)
189 return converted
190
191 def get_override(self):
192@@ -2520,7 +2608,7 @@
193 :param option_name: The name to validate.
194 """
195 if _option_ref_re.match('{%s}' % option_name) is None:
196- raise errors.IllegalOptionName(option_name)
197+ raise IllegalOptionName(option_name)
198
199 def register(self, option):
200 """Register a new option to its name.
201@@ -3153,9 +3241,9 @@
202 list_values=False)
203 except configobj.ConfigObjError as e:
204 self._config_obj = None
205- raise errors.ParseConfigError(e.errors, self.external_url())
206+ raise ParseConfigError(e.errors, self.external_url())
207 except UnicodeDecodeError:
208- raise errors.ConfigContentError(self.external_url())
209+ raise ConfigContentError(self.external_url())
210
211 def save_changes(self):
212 if not self.is_loaded():
213@@ -3717,11 +3805,11 @@
214 expanded = True
215 name = chunk[1:-1]
216 if name in _refs:
217- raise errors.OptionExpansionLoop(string, _refs)
218+ raise OptionExpansionLoop(string, _refs)
219 _refs.append(name)
220 value = self._expand_option(name, env, _refs)
221 if value is None:
222- raise errors.ExpandingUnknownOption(name, string)
223+ raise ExpandingUnknownOption(name, string)
224 chunks.append(value)
225 _refs.pop()
226 result = ''.join(chunks)
227@@ -4112,7 +4200,7 @@
228 if write_access:
229 self.add_cleanup(br.lock_write().unlock)
230 return br.get_config_stack()
231- raise errors.NoSuchConfig(scope)
232+ raise NoSuchConfig(scope)
233 else:
234 try:
235 (_, br, _) = (
236@@ -4137,7 +4225,7 @@
237 value = self._quote_multiline(value)
238 self.outf.write('%s\n' % (value,))
239 else:
240- raise errors.NoSuchConfigOption(name)
241+ raise NoSuchConfigOption(name)
242
243 def _show_matching_options(self, name, directory, scope):
244 name = lazy_regex.lazy_compile(name)
245@@ -4182,7 +4270,7 @@
246 # Explicitly save the changes
247 conf.store.save_changes()
248 except KeyError:
249- raise errors.NoSuchConfigOption(name)
250+ raise NoSuchConfigOption(name)
251
252
253 # Test registries
254
255=== modified file 'breezy/errors.py'
256--- breezy/errors.py 2017-07-15 15:59:40 +0000
257+++ breezy/errors.py 2017-07-15 16:04:48 +0000
258@@ -1639,43 +1639,6 @@
259 _fmt = "Working tree has conflicts."
260
261
262-class ConfigContentError(BzrError):
263-
264- _fmt = "Config file %(filename)s is not UTF-8 encoded\n"
265-
266- def __init__(self, filename):
267- BzrError.__init__(self)
268- self.filename = filename
269-
270-
271-class ParseConfigError(BzrError):
272-
273- _fmt = "Error(s) parsing config file %(filename)s:\n%(errors)s"
274-
275- def __init__(self, errors, filename):
276- BzrError.__init__(self)
277- self.filename = filename
278- self.errors = '\n'.join(e.msg for e in errors)
279-
280-
281-class ConfigOptionValueError(BzrError):
282-
283- _fmt = ('Bad value "%(value)s" for option "%(name)s".\n'
284- 'See ``brz help %(name)s``')
285-
286- def __init__(self, name, value):
287- BzrError.__init__(self, name=name, value=value)
288-
289-
290-class NoEmailInUsername(BzrError):
291-
292- _fmt = "%(username)r does not seem to contain a reasonable email address"
293-
294- def __init__(self, username):
295- BzrError.__init__(self)
296- self.username = username
297-
298-
299 class DependencyNotPresent(BzrError):
300
301 _fmt = 'Unable to import library "%(library)s": %(error)s'
302@@ -2808,22 +2771,6 @@
303 self.user_encoding = get_user_encoding()
304
305
306-class NoSuchConfig(BzrError):
307-
308- _fmt = ('The "%(config_id)s" configuration does not exist.')
309-
310- def __init__(self, config_id):
311- BzrError.__init__(self, config_id=config_id)
312-
313-
314-class NoSuchConfigOption(BzrError):
315-
316- _fmt = ('The "%(option_name)s" configuration option does not exist.')
317-
318- def __init__(self, option_name):
319- BzrError.__init__(self, option_name=option_name)
320-
321-
322 class NoSuchAlias(BzrError):
323
324 _fmt = ('The alias "%(alias_name)s" does not exist.')
325@@ -3023,13 +2970,6 @@
326 self.controldir = controldir
327
328
329-class NoWhoami(BzrError):
330-
331- _fmt = ('Unable to determine your name.\n'
332- "Please, set your name with the 'whoami' command.\n"
333- 'E.g. brz whoami "Your Name <name@example.com>"')
334-
335-
336 class RecursiveBind(BzrError):
337
338 _fmt = ('Branch "%(branch_url)s" appears to be bound to itself. '
339@@ -3039,34 +2979,6 @@
340 self.branch_url = branch_url
341
342
343-# FIXME: I would prefer to define the config related exception classes in
344-# config.py but the lazy import mechanism proscribes this -- vila 20101222
345-class OptionExpansionLoop(BzrError):
346-
347- _fmt = 'Loop involving %(refs)r while expanding "%(string)s".'
348-
349- def __init__(self, string, refs):
350- self.string = string
351- self.refs = '->'.join(refs)
352-
353-
354-class ExpandingUnknownOption(BzrError):
355-
356- _fmt = 'Option "%(name)s" is not defined while expanding "%(string)s".'
357-
358- def __init__(self, name, string):
359- self.name = name
360- self.string = string
361-
362-
363-class IllegalOptionName(BzrError):
364-
365- _fmt = 'Option "%(name)s" is not allowed.'
366-
367- def __init__(self, name):
368- self.name = name
369-
370-
371 class HpssVfsRequestNotAllowed(BzrError):
372
373 _fmt = ("VFS requests over the smart server are not allowed. Encountered: "
374
375=== modified file 'breezy/tests/test_config.py'
376--- breezy/tests/test_config.py 2017-07-04 20:03:11 +0000
377+++ breezy/tests/test_config.py 2017-07-15 16:04:48 +0000
378@@ -654,7 +654,7 @@
379
380 def test_unknown_ref(self):
381 c = self.get_config('')
382- self.assertRaises(errors.ExpandingUnknownOption,
383+ self.assertRaises(config.ExpandingUnknownOption,
384 c.expand_options, '{foo}')
385
386 def test_indirect_ref(self):
387@@ -673,14 +673,15 @@
388
389 def test_simple_loop(self):
390 c = self.get_config('foo={foo}')
391- self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
392+ self.assertRaises(config.OptionExpansionLoop, c.expand_options,
393+ '{foo}')
394
395 def test_indirect_loop(self):
396 c = self.get_config('''
397 foo={bar}
398 bar={baz}
399 baz={foo}''')
400- e = self.assertRaises(errors.OptionExpansionLoop,
401+ e = self.assertRaises(config.OptionExpansionLoop,
402 c.expand_options, '{foo}')
403 self.assertEqual('foo->bar->baz', e.refs)
404 self.assertEqual('{foo}', e.string)
405@@ -739,7 +740,7 @@
406 [/another/branch/path]
407 bar = {foo}/2
408 ''')
409- self.assertRaises(errors.ExpandingUnknownOption,
410+ self.assertRaises(config.ExpandingUnknownOption,
411 c.get_user_option, 'bar', expand=True)
412
413 def test_cross_related_sections(self):
414@@ -1534,7 +1535,7 @@
415 def test_extract_email_address(self):
416 self.assertEqual('jane@test.com',
417 config.extract_email_address('Jane <jane@test.com>'))
418- self.assertRaises(errors.NoEmailInUsername,
419+ self.assertRaises(config.NoEmailInUsername,
420 config.extract_email_address, 'Jane Tester')
421
422 def test_parse_username(self):
423@@ -1595,14 +1596,14 @@
424 t = self.get_transport()
425 t.put_bytes('foo.conf', 'user=foo\n#\xff\n')
426 conf = config.TransportConfig(t, 'foo.conf')
427- self.assertRaises(errors.ConfigContentError, conf._get_configobj)
428+ self.assertRaises(config.ConfigContentError, conf._get_configobj)
429
430 def test_load_erroneous_content(self):
431 """Ensure we display a proper error on content that can't be parsed."""
432 t = self.get_transport()
433 t.put_bytes('foo.conf', '[open_section\n')
434 conf = config.TransportConfig(t, 'foo.conf')
435- self.assertRaises(errors.ParseConfigError, conf._get_configobj)
436+ self.assertRaises(config.ParseConfigError, conf._get_configobj)
437
438 def test_load_permission_denied(self):
439 """Ensure we get an empty config file if the file is inaccessible."""
440@@ -2012,7 +2013,7 @@
441 warnings[0])
442
443 def assertCallsError(self, opt, value):
444- self.assertRaises(errors.ConfigOptionValueError,
445+ self.assertRaises(config.ConfigOptionValueError,
446 opt.convert_from_unicode, None, value)
447
448 def assertConvertInvalid(self, opt, invalid_value):
449@@ -2179,9 +2180,9 @@
450 self.assertEqual('A simple option', self.registry.get_help('foo'))
451
452 def test_dont_register_illegal_name(self):
453- self.assertRaises(errors.IllegalOptionName,
454+ self.assertRaises(config.IllegalOptionName,
455 self.registry.register, config.Option(' foo'))
456- self.assertRaises(errors.IllegalOptionName,
457+ self.assertRaises(config.IllegalOptionName,
458 self.registry.register, config.Option('bar,'))
459
460 lazy_option = config.Option('lazy_foo', help='Lazy help')
461@@ -2202,10 +2203,10 @@
462 # the option name which indirectly requires that the option name is a
463 # valid python identifier. We violate that rule here (using a key that
464 # doesn't match the option name) to test the option name checking.
465- self.assertRaises(errors.IllegalOptionName,
466+ self.assertRaises(config.IllegalOptionName,
467 self.registry.register_lazy, ' foo', self.__module__,
468 'TestOptionRegistry.lazy_option')
469- self.assertRaises(errors.IllegalOptionName,
470+ self.assertRaises(config.IllegalOptionName,
471 self.registry.register_lazy, '1,2', self.__module__,
472 'TestOptionRegistry.lazy_option')
473
474@@ -2519,14 +2520,14 @@
475 t = self.get_transport()
476 t.put_bytes('foo.conf', 'user=foo\n#%s\n' % (self.invalid_utf8_char,))
477 store = config.TransportIniFileStore(t, 'foo.conf')
478- self.assertRaises(errors.ConfigContentError, store.load)
479+ self.assertRaises(config.ConfigContentError, store.load)
480
481 def test_load_erroneous_content(self):
482 """Ensure we display a proper error on content that can't be parsed."""
483 t = self.get_transport()
484 t.put_bytes('foo.conf', '[open_section\n')
485 store = config.TransportIniFileStore(t, 'foo.conf')
486- self.assertRaises(errors.ParseConfigError, store.load)
487+ self.assertRaises(config.ParseConfigError, store.load)
488
489 def test_load_permission_denied(self):
490 """Ensure we get warned when trying to load an inaccessible file."""
491@@ -2576,14 +2577,14 @@
492 with open('foo.conf', 'wb') as f:
493 f.write('user=foo\n#%s\n' % (self.invalid_utf8_char,))
494 conf = config.IniBasedConfig(file_name='foo.conf')
495- self.assertRaises(errors.ConfigContentError, conf._get_parser)
496+ self.assertRaises(config.ConfigContentError, conf._get_parser)
497
498 def test_load_erroneous_content(self):
499 """Ensure we display a proper error on content that can't be parsed."""
500 with open('foo.conf', 'wb') as f:
501 f.write('[open_section\n')
502 conf = config.IniBasedConfig(file_name='foo.conf')
503- self.assertRaises(errors.ParseConfigError, conf._get_parser)
504+ self.assertRaises(config.ParseConfigError, conf._get_parser)
505
506
507 class TestMutableStore(TestStore):
508@@ -2868,7 +2869,7 @@
509 store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
510 self.assertEqual(False, store.is_loaded())
511 exc = self.assertRaises(
512- errors.ParseConfigError, store._load_from_string,
513+ config.ParseConfigError, store._load_from_string,
514 'this is invalid !')
515 self.assertEndsWith(exc.filename, 'foo.conf')
516 # And the load failed
517@@ -3668,7 +3669,7 @@
518 self.assertExpansion('xxx', '{foo}')
519
520 def test_unknown_ref(self):
521- self.assertRaises(errors.ExpandingUnknownOption,
522+ self.assertRaises(config.ExpandingUnknownOption,
523 self.conf.expand_options, '{foo}')
524
525 def test_illegal_def_is_ignored(self):
526@@ -3692,7 +3693,7 @@
527
528 def test_simple_loop(self):
529 self.conf.store._load_from_string('foo={foo}')
530- self.assertRaises(errors.OptionExpansionLoop,
531+ self.assertRaises(config.OptionExpansionLoop,
532 self.conf.expand_options, '{foo}')
533
534 def test_indirect_loop(self):
535@@ -3700,7 +3701,7 @@
536 foo={bar}
537 bar={baz}
538 baz={foo}''')
539- e = self.assertRaises(errors.OptionExpansionLoop,
540+ e = self.assertRaises(config.OptionExpansionLoop,
541 self.conf.expand_options, '{foo}')
542 self.assertEqual('foo->bar->baz', e.refs)
543 self.assertEqual('{foo}', e.string)
544@@ -3771,7 +3772,7 @@
545 [/another/branch/path]
546 bar = {foo}/2
547 ''')
548- self.assertRaises(errors.ExpandingUnknownOption,
549+ self.assertRaises(config.ExpandingUnknownOption,
550 c.get, 'bar', expand=True)
551
552 def test_cross_related_sections(self):
553@@ -3859,7 +3860,7 @@
554 ''')
555 g_store.save()
556 stack = config.LocationStack('/home/user/project/branch')
557- self.assertRaises(errors.ExpandingUnknownOption,
558+ self.assertRaises(config.ExpandingUnknownOption,
559 stack.get, 'gfoo', expand=True)
560
561 def test_expand_local_option_locally(self):
562@@ -4166,7 +4167,7 @@
563
564 def test_non_utf8_config(self):
565 conf = config.AuthenticationConfig(_file=BytesIO(b'foo = bar\xff'))
566- self.assertRaises(errors.ConfigContentError, conf._get_config)
567+ self.assertRaises(config.ConfigContentError, conf._get_config)
568
569 def test_missing_auth_section_header(self):
570 conf = config.AuthenticationConfig(_file=BytesIO(b'foo = bar'))
571@@ -4174,7 +4175,7 @@
572
573 def test_auth_section_header_not_closed(self):
574 conf = config.AuthenticationConfig(_file=BytesIO(b'[DEF'))
575- self.assertRaises(errors.ParseConfigError, conf._get_config)
576+ self.assertRaises(config.ParseConfigError, conf._get_config)
577
578 def test_auth_value_not_boolean(self):
579 conf = config.AuthenticationConfig(_file=BytesIO(b"""\
580@@ -4765,5 +4766,5 @@
581
582 def test_unknown(self):
583 conf = config.MemoryStack('mail_client=firebird')
584- self.assertRaises(errors.ConfigOptionValueError, conf.get,
585+ self.assertRaises(config.ConfigOptionValueError, conf.get,
586 'mail_client')

Subscribers

People subscribed via source and target branches