diff options
Diffstat (limited to 'kconfiglib.py')
| -rw-r--r-- | kconfiglib.py | 132 |
1 files changed, 31 insertions, 101 deletions
diff --git a/kconfiglib.py b/kconfiglib.py index ce40eb7..2bbc517 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -5,7 +5,7 @@ Overview ======== -Kconfiglib is a Python 2/3 library for scripting and extracting information +Kconfiglib is a Python 3 library for scripting and extracting information from Kconfig (https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt) configuration systems. @@ -52,17 +52,14 @@ sections. make kmenuconfig ---------------- -This target runs the curses menuconfig interface with Python 3. As of -Kconfiglib 12.2.0, both Python 2 and Python 3 are supported (previously, only -Python 3 was supported, so this was a backport). +This target runs the curses menuconfig interface with Python 3. make guiconfig -------------- -This target runs the Tkinter menuconfig interface. Both Python 2 and Python 3 -are supported. To change the Python interpreter used, pass -PYTHONCMD=<executable> to 'make'. The default is 'python'. +This target runs the Tkinter menuconfig interface. To change the Python +interpreter used, pass PYTHONCMD=<executable> to 'make'. The default is 'python'. make [ARCH=<arch>] iscriptconfig @@ -878,11 +875,8 @@ class Kconfig(object): 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' are available). Note that IOError is an alias for OSError in + Python 3, so it's enough to catch OSError. filename (default: "Kconfig"): The Kconfig file to load. For the Linux kernel, you'll want "Kconfig" @@ -925,11 +919,6 @@ class Kconfig(object): The "utf-8" default avoids exceptions on systems that are configured to use the C locale, which implies an ASCII encoding. - This parameter has no effect on Python 2, due to implementation - issues (regular strings turning into Unicode strings, which are - distinct in Python 2). Python 2 doesn't decode regular strings - anyway. - Related PEP: https://www.python.org/dev/peps/pep-0538/ suppress_traceback (default: False): @@ -2118,18 +2107,12 @@ class Kconfig(object): try: return self._open(join(self.srctree, filename), "r") except EnvironmentError as e2: - # This is needed for Python 3, because e2 is deleted after - # the try block: - # - # https://docs.python.org/3/reference/compound_stmts.html#the-try-statement - e = e2 - - raise _KconfigIOError( - e, "Could not open '{}' ({}: {}). Check that the $srctree " - "environment variable ({}) is set correctly." - .format(filename, errno.errorcode[e.errno], e.strerror, - "set to '{}'".format(self.srctree) if self.srctree - else "unset or blank")) + raise _KconfigIOError( + e2, "Could not open '{}' ({}: {}). Check that the $srctree " + "environment variable ({}) is set correctly." + .format(filename, errno.errorcode[e.errno], e.strerror, + "set to '{}'".format(self.srctree) if self.srctree + else "unset or blank")) def _enter_file(self, filename): # Jumps to the beginning of a sourced Kconfig file, saving the previous @@ -3895,41 +3878,8 @@ class Kconfig(object): self._parse_error("extra tokens at end of line") def _open(self, filename, mode): - # open() wrapper: - # - # - Enable universal newlines mode on Python 2 to ease - # interoperability between Linux and Windows. It's already the - # default on Python 3. - # - # The "U" flag would currently work for both Python 2 and 3, but it's - # deprecated on Python 3, so play it future-safe. - # - # io.open() defaults to universal newlines on Python 2 (and is an - # alias for open() on Python 3), but it returns 'unicode' strings and - # slows things down: - # - # Parsing x86 Kconfigs on Python 2 - # - # with open(..., "rU"): - # - # real 0m0.930s - # user 0m0.905s - # sys 0m0.025s - # - # with io.open(): - # - # real 0m1.069s - # user 0m1.040s - # sys 0m0.029s - # - # There's no appreciable performance difference between "r" and - # "rU" for parsing performance on Python 2. - # - # - For Python 3, force the encoding. Forcing the encoding on Python 2 - # turns strings into Unicode strings, which gets messy. Python 2 - # doesn't decode regular strings anyway. - return open(filename, "rU" if mode == "r" else mode) if _IS_PY2 else \ - open(filename, mode, encoding=self._encoding) + # open() wrapper that forces the encoding + return open(filename, mode, encoding=self._encoding) def _check_undef_syms(self): # Prints warnings for all references to undefined symbols within the @@ -3958,7 +3908,7 @@ class Kconfig(object): return True - for sym in (self.syms.viewvalues if _IS_PY2 else self.syms.values)(): + for sym in self.syms.values(): # - sym.nodes empty means the symbol is undefined (has no # definition locations) # @@ -6513,16 +6463,9 @@ def _save_old(path): if islink(path): # Preserve symlinks copy_fn = copy - elif hasattr(os, "replace"): - # Python 3 (3.3+) only. Best choice when available, because it - # removes <filename>.old on both *nix and Windows. - copy_fn = os.replace - elif os.name == "posix": - # Removes <filename>.old on POSIX systems - copy_fn = os.rename else: - # Fall back on copying - copy_fn = copy + # atomic replace of <filename>.old + copy_fn = os.replace try: copy_fn(path, path + ".old") @@ -6894,30 +6837,21 @@ def _error_if_fn(kconf, _, cond, msg): def _shell_fn(kconf, _, command): import subprocess # Only import as needed, to save some startup time - stdout, stderr = subprocess.Popen( - command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ).communicate() - - if not _IS_PY2: - try: - stdout = stdout.decode(kconf._encoding) - stderr = stderr.decode(kconf._encoding) - except UnicodeDecodeError as e: - _decoding_error(e, kconf.filename, kconf.linenr) + result = subprocess.run( + command, + shell=True, + capture_output=True, + text=True, + encoding=kconf._encoding + ) - if stderr: + if result.stderr: kconf._warn("'{}' wrote to stderr: {}".format( - command, "\n".join(stderr.splitlines())), + command, "\n".join(result.stderr.splitlines())), kconf.loc) - # Universal newlines with splitlines() (to prevent e.g. stray \r's in - # command output on Windows), trailing newline removal, and - # newline-to-space conversion. - # - # On Python 3 versions before 3.6, it's not possible to specify the - # encoding when passing universal_newlines=True to Popen() (the 'encoding' - # parameter was added in 3.6), so we do this manual version instead. - return "\n".join(stdout.splitlines()).rstrip("\n").replace("\n", " ") + # Trailing newline removal, and newline-to-space conversion. + return result.stdout.rstrip("\n").replace("\n", " ") # # Global constants @@ -6940,9 +6874,6 @@ STR_TO_TRI = { # Symbol will do. We test this with 'is'. _NO_CACHED_SELECTION = 0 -# Are we running on Python 2? -_IS_PY2 = sys.version_info[0] < 3 - try: _UNAME_RELEASE = os.uname()[2] except AttributeError: @@ -7231,15 +7162,14 @@ KIND_TO_STR = { # Helper functions for getting compiled regular expressions, with the needed # matching function returned directly as a small optimization. # -# Use ASCII regex matching on Python 3. It's already the default on Python 2. - +# Use ASCII regex matching on Python 3. def _re_match(regex): - return re.compile(regex, 0 if _IS_PY2 else re.ASCII).match + return re.compile(regex, re.ASCII).match def _re_search(regex): - return re.compile(regex, 0 if _IS_PY2 else re.ASCII).search + return re.compile(regex, re.ASCII).search # Various regular expressions used during parsing |
