diff options
| author | Ulf Magnusson <ulfalizer@gmail.com> | 2018-10-30 23:57:16 +0100 |
|---|---|---|
| committer | Ulf Magnusson <ulfalizer@gmail.com> | 2018-10-31 00:02:43 +0100 |
| commit | 14603c0fed58ebbd137b39b1be2d645d5152716b (patch) | |
| tree | ee3a8a9c7b0e37647425fdfe032361393afcb055 | |
| parent | ac5ac5f8ada90e3b41b998bd715497be4109b3ab (diff) | |
Make errno/strerror/filename available on IOError
An error reporting flaw was that most raised IOErrors got their
errno/strerror/filename fields stripped, due to wanting to show a custom
messages. The problem was that adding back 'errno' and 'strerror' made
IOError.__str__() always return a fixed string
("[Errno <errno>] <strerror>"), ignoring any custom message.
This is friendly to users, but unfriendly to scripts (the menuconfig had
a workaround). Make things friendly to both by raising an internal
subclass of IOError instead, that preserves errno/strerror/filename but
prints a custom message. The exception can then still be caught as
IOError/OSError by scripts.
| -rw-r--r-- | kconfiglib.py | 40 | ||||
| -rwxr-xr-x | menuconfig.py | 14 |
2 files changed, 34 insertions, 20 deletions
diff --git a/kconfiglib.py b/kconfiglib.py index ccd1869..116eca7 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -778,14 +778,18 @@ class Kconfig(object): def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True, encoding="utf-8"): """ - Creates a new Kconfig object by parsing Kconfig files. Raises - KconfigError on syntax errors. Note that Kconfig files are not the same - as .config files (which store configuration symbol values). + Creates a new Kconfig object by parsing Kconfig files. + Note that Kconfig files are not the same as .config files (which store + configuration symbol values). See the module docstring for some environment variables that influence default warning settings (KCONFIG_WARN_UNDEF and KCONFIG_WARN_UNDEF_ASSIGN). + Raises KconfigError on syntax errors, and (possibly a subclass of) + IOError on IO errors ('errno', 'strerror', and 'filename' are + available). Note that IOError can be caught as OSError on Python 3. + filename (default: "Kconfig"): The Kconfig file to load. For the Linux kernel, you'll want "Kconfig" from the top-level directory, as environment variables will make sure @@ -1035,6 +1039,10 @@ class Kconfig(object): value might differ from Symbol.str/tri_value if there are unsatisfied dependencies. + Raises (possibly a subclass of) IOError on IO errors ('errno', + 'strerror', and 'filename' are available). Note that IOError can be + caught as OSError on Python 3. + filename: The file to load. Respects $srctree if set (see the class documentation). @@ -1705,7 +1713,7 @@ class Kconfig(object): # https://docs.python.org/3/reference/compound_stmts.html#the-try-statement e = e2 - raise IOError("\n" + textwrap.fill( + raise _KconfigIOError(e, "\n" + textwrap.fill( "Could not open '{}' ({}: {}){}".format( filename, errno.errorcode[e.errno], e.strerror, self._srctree_hint()), @@ -1760,9 +1768,10 @@ class Kconfig(object): try: self._file = self._open(full_filename, "r") except IOError as e: - raise IOError("{}:{}: Could not open '{}' ({}: {})".format( - self._filename, self._linenr, full_filename, - errno.errorcode[e.errno], e.strerror)) + raise _KconfigIOError( + e, "{}:{}: Could not open '{}' ({}: {})" + .format(self._filename, self._linenr, full_filename, + errno.errorcode[e.errno], e.strerror)) self._filename = rel_filename self._linenr = 0 @@ -5333,10 +5342,25 @@ class Variable(object): class KconfigError(Exception): "Exception raised for Kconfig-related errors" +KconfigSyntaxError = KconfigError # Backwards compatibility + class InternalError(Exception): "Exception raised for internal errors" -KconfigSyntaxError = KconfigError # Backwards compatibility +# Workaround: +# +# If 'errno' and 'strerror' are set on IOError, then __str__() always returns +# "[Errno <errno>] <strerror>", ignoring any custom message passed to the +# constructor. By defining our own subclass, we can use a custom message while +# also providing 'errno', 'strerror', and 'filename' to scripts. +class _KconfigIOError(IOError): + def __init__(self, ioerror, msg): + self.msg = msg + super(_KconfigIOError, self).__init__( + ioerror.errno, ioerror.strerror, ioerror.filename) + + def __str__(self): + return self.msg # # Public functions diff --git a/menuconfig.py b/menuconfig.py index 081496f..4aa21c3 100755 --- a/menuconfig.py +++ b/menuconfig.py @@ -1646,22 +1646,12 @@ def _try_load(filename): # filename: # Configuration file to load - # Hack: strerror and errno are lost after we raise the custom IOError with - # troubleshooting help in Kconfig.load_config(). Adding them back to the - # exception loses the custom message. As a workaround, try opening the file - # separately first and report any errors. - try: - open(filename).close() - except OSError as e: - _error("Error loading {}\n\n{} (errno: {})" - .format(filename, e.strerror, errno.errorcode[e.errno])) - return False - try: _kconf.load_config(filename) return True except OSError as e: - _error("Error loading {}\n\nUnknown error".format(filename)) + _error("Error loading {}\n\n{} (errno: {})" + .format(filename, e.strerror, errno.errorcode[e.errno])) return False def _save_dialog(save_fn, default_filename, description): |
