summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Magnusson <ulfalizer@gmail.com>2018-10-30 23:57:16 +0100
committerUlf Magnusson <ulfalizer@gmail.com>2018-10-31 00:02:43 +0100
commit14603c0fed58ebbd137b39b1be2d645d5152716b (patch)
treeee3a8a9c7b0e37647425fdfe032361393afcb055
parentac5ac5f8ada90e3b41b998bd715497be4109b3ab (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.py40
-rwxr-xr-xmenuconfig.py14
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):