From e5e2fe5a6f084fb98c2c9b4adec0383fec4a5256 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Mon, 1 Jul 2019 22:52:17 +0200 Subject: Catch EnvironmentError instead of OSError/IOError menuconfig.py tended to crash on I/O errors on Python 2, due to forgetting to update some 'except OSError's. Catch EnvironmentError instead. EnvironmentError is a common base class of IOError and OSError on Python 2, and an alias for OSError on Python 3. Use it elsewhere too, as it might help catch obscure I/O errors on Python 2. --- examples/menuconfig_example.py | 4 ++-- guiconfig.py | 4 ++-- kconfiglib.py | 48 ++++++++++++++++++++++++++++-------------- menuconfig.py | 4 ++-- testsuite.py | 2 +- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/examples/menuconfig_example.py b/examples/menuconfig_example.py index 2c98fff..a06b05e 100755 --- a/examples/menuconfig_example.py +++ b/examples/menuconfig_example.py @@ -305,7 +305,7 @@ if __name__ == "__main__": try: # Returns a message telling which file got loaded print(kconf.load_config(config_filename)) - except IOError as e: + except EnvironmentError as e: print(e, file=sys.stderr) print_menuconfig(kconf) @@ -316,7 +316,7 @@ if __name__ == "__main__": try: # Returns a message telling which file got saved print(kconf.write_config(config_filename)) - except IOError as e: + except EnvironmentError as e: print(e, file=sys.stderr) continue diff --git a/guiconfig.py b/guiconfig.py index 9f72203..f3b17a0 100755 --- a/guiconfig.py +++ b/guiconfig.py @@ -1696,7 +1696,7 @@ def _try_save(save_fn, filename, description): _set_status(msg) print(msg) return True - except (OSError, IOError) as e: + except EnvironmentError as e: messagebox.showerror( "Error saving " + description, "Error saving {} to '{}': {} (errno: {})" @@ -1717,7 +1717,7 @@ def _try_load(filename): _set_status(msg) print(msg) return True - except (OSError, IOError) as e: + except EnvironmentError as e: messagebox.showerror( "Error loading configuration", "Error loading '{}': {} (errno: {})" diff --git a/kconfiglib.py b/kconfiglib.py index 2c26d98..d3b29fc 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -853,9 +853,13 @@ class Kconfig(object): default warning settings (KCONFIG_WARN_UNDEF and KCONFIG_WARN_UNDEF_ASSIGN). - Raises KconfigError on syntax/semantic 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. + Raises KconfigError on syntax/semantic errors, and OSError or (possibly + a subclass of) IOError on IO errors ('errno', 'strerror', and + 'filename' are available). Note that IOError is an alias for OSError on + Python 3, so it's enough to catch OSError there. If you need Python 2/3 + compatibility, it's easiest to catch EnvironmentError, which is a + common base class of OSError/IOError on Python 2 and an alias for + OSError on Python 3. filename (default: "Kconfig"): The Kconfig file to load. For the Linux kernel, you'll want "Kconfig" @@ -1091,7 +1095,7 @@ class Kconfig(object): try: with self._open_config(filename.str_value) as f: return f.name - except IOError: + except EnvironmentError: continue return None @@ -1114,9 +1118,8 @@ class Kconfig(object): True, and appended to otherwise. See the documentation for Kconfig.missing_syms as well. - 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. + See the Kconfig.__init__() docstring for raised exceptions + (OSError/IOError). KconfigError is never raised here. filename (default: None): Path to load configuration from (a string). Respects $srctree if set @@ -1428,6 +1431,9 @@ class Kconfig(object): like the modification time and possibly triggering redundant work in build tools. + See the Kconfig.__init__() docstring for raised exceptions + (OSError/IOError). KconfigError is never raised here. + filename (default: None): Filename to save configuration to (a string). @@ -1567,6 +1573,9 @@ class Kconfig(object): compared to a "full" .config file, especially when configurations files are merged or edited by hand. + See the Kconfig.__init__() docstring for raised exceptions + (OSError/IOError). KconfigError is never raised here. + filename: Self-explanatory. @@ -1631,6 +1640,9 @@ class Kconfig(object): This function is intended to be called during each build, before compiling source files that depend on configuration symbols. + See the Kconfig.__init__() docstring for raised exceptions + (OSError/IOError). KconfigError is never raised here. + path: Path to directory @@ -1741,7 +1753,7 @@ class Kconfig(object): try: auto_conf = self._open(join(path, "auto.conf"), "r") - except IOError as e: + except EnvironmentError as e: if e.errno == errno.ENOENT: # No old values return @@ -2005,12 +2017,12 @@ class Kconfig(object): try: return self._open(filename, "r") - except IOError as e: + except EnvironmentError as e: # This will try opening the same file twice if $srctree is unset, # but it's not a big deal try: return self._open(join(self.srctree, filename), "r") - except IOError as e2: + except EnvironmentError as e2: # This is needed for Python 3, because e2 is deleted after # the try block: # @@ -2077,7 +2089,7 @@ class Kconfig(object): try: self._readline = self._open(filename, "r").readline - except IOError as e: + except EnvironmentError as e: # We already know that the file exists raise _KconfigIOError( e, "{}:{}: Could not open '{}' (in '{}') ({}: {})" @@ -2170,7 +2182,7 @@ class Kconfig(object): # Robust re. things like encoding and line endings (mmap() # trickery isn't) return f.read(len(contents) + 1) == contents - except IOError: + except EnvironmentError: # If the error here would prevent writing the file as well, we'll # notice it later return False @@ -6049,7 +6061,7 @@ def standard_kconfig(): # Only show backtraces for unexpected exceptions try: return Kconfig("Kconfig" if len(sys.argv) < 2 else sys.argv[1]) - except (IOError, KconfigError) as e: + except (EnvironmentError, KconfigError) as e: # Some long exception messages have extra newlines for better # formatting when reported as an unhandled exception. Strip them here. sys.exit(str(e).strip()) @@ -6095,6 +6107,10 @@ def load_allconfig(kconf, filename): def std_msg(e): # "Upcasts" a _KconfigIOError to an IOError, removing the custom # __str__() message. The standard message is better here. + # + # This might also convert an OSError to an IOError in obscure cases, + # but it's probably not a big deal. The distinction is shaky (see + # PEP-3151). return IOError(e.errno, e.strerror, e.filename) old_warn_assign_override = kconf.warn_assign_override @@ -6104,17 +6120,17 @@ def load_allconfig(kconf, filename): if allconfig in ("", "1"): try: print(kconf.load_config(filename, False)) - except IOError as e1: + except EnvironmentError as e1: try: print(kconf.load_config("all.config", False)) - except IOError as e2: + except EnvironmentError as e2: sys.exit("error: KCONFIG_ALLCONFIG is set, but neither {} " "nor all.config could be opened: {}, {}" .format(filename, std_msg(e1), std_msg(e2))) else: try: print(kconf.load_config(allconfig, False)) - except IOError as e: + except EnvironmentError as e: sys.exit("error: KCONFIG_ALLCONFIG is set to '{}', which " "could not be opened: {}" .format(allconfig, std_msg(e))) diff --git a/menuconfig.py b/menuconfig.py index 6afc1c4..799cc4a 100755 --- a/menuconfig.py +++ b/menuconfig.py @@ -1829,7 +1829,7 @@ def _try_load(filename): try: _kconf.load_config(filename) return True - except OSError as e: + except EnvironmentError as e: _error("Error loading '{}'\n\n{} (errno: {})" .format(filename, e.strerror, errno.errorcode[e.errno])) return False @@ -1881,7 +1881,7 @@ def _try_save(save_fn, filename, description): try: # save_fn() returns a message to print return save_fn(filename) - except OSError as e: + except EnvironmentError as e: _error("Error saving {} to '{}'\n\n{} (errno: {})" .format(description, e.filename, e.strerror, errno.errorcode[e.errno])) diff --git a/testsuite.py b/testsuite.py index d5f9726..92a8987 100644 --- a/testsuite.py +++ b/testsuite.py @@ -3111,7 +3111,7 @@ def equal_configs(): try: f = open("._config") - except IOError as e: + except EnvironmentError as e: if e.errno != errno.ENOENT: raise print("._config not found. Did you forget to apply the Makefile patch?") -- cgit v1.2.3