From bf36f5de0f49d56975b1a844e25484ec385dc971 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Mon, 3 Jun 2019 01:55:50 +0200 Subject: Improve warning control API (with backwards compatibility) A wart of the warning control API (enable/disable_*_warnings()) is that the current warning settings can't be queried. Querying warning settings is useful in functions that want to temporarily enable/disable some warning and then put things back to how they were. kconfiglib.load_allconfig() ran into this, for example. Make the internal warning control variables public (improve the naming at the same time), and encourage just setting them directly. Keep the old API for backwards compatibility. Also remove _warn_redun_assign() and _warn_override(). They're trivial and were called in a single place. --- README.rst | 4 +- allmodconfig.py | 4 +- allnoconfig.py | 4 +- allyesconfig.py | 4 +- examples/menuconfig_example.py | 5 +- examples/merge_config.py | 6 +- kconfiglib.py | 230 +++++++++++++++++++++++------------------ menuconfig.py | 3 +- testsuite.py | 28 ++--- 9 files changed, 160 insertions(+), 128 deletions(-) diff --git a/README.rst b/README.rst index 590106a..c13fc78 100644 --- a/README.rst +++ b/README.rst @@ -384,8 +384,8 @@ The following Kconfig extensions are available: for all assignments to undefined symbols within ``.config`` files. By default, no such warnings are generated. - This warning can also be enabled/disabled via - ``Kconfig.enable/disable_undef_warnings()``. + This warning can also be enabled/disabled by setting + ``Kconfig.warn_assign_undef`` to ``True``/``False``. Other features -------------- diff --git a/allmodconfig.py b/allmodconfig.py index add16a8..9ae0b3b 100755 --- a/allmodconfig.py +++ b/allmodconfig.py @@ -20,7 +20,7 @@ def main(): kconf = kconfiglib.standard_kconfig() # See allnoconfig.py - kconf.disable_warnings() + kconf.warn = False for sym in kconf.unique_defined_syms: if sym.orig_type == kconfiglib.BOOL: @@ -35,7 +35,7 @@ def main(): for choice in kconf.unique_choices: choice.set_value(2 if choice.orig_type == kconfiglib.BOOL else 1) - kconf.enable_warnings() + kconf.warn = True kconfiglib.load_allconfig(kconf, "allmod.config") diff --git a/allnoconfig.py b/allnoconfig.py index a0afd78..e162ccb 100755 --- a/allnoconfig.py +++ b/allnoconfig.py @@ -31,10 +31,10 @@ def main(): # 2. Assigning values invalid for the type (only bool/tristate symbols # accept 0/1/2, for n/m/y). The assignments will be ignored for other # symbol types, which is what we want. - kconf.disable_warnings() + kconf.warn = False for sym in kconf.unique_defined_syms: sym.set_value(2 if sym.is_allnoconfig_y else 0) - kconf.enable_warnings() + kconf.warn = True kconfiglib.load_allconfig(kconf, "allno.config") diff --git a/allyesconfig.py b/allyesconfig.py index 45231bc..e19ab31 100755 --- a/allyesconfig.py +++ b/allyesconfig.py @@ -20,7 +20,7 @@ def main(): kconf = kconfiglib.standard_kconfig() # See allnoconfig.py - kconf.disable_warnings() + kconf.warn = False # Try to set all symbols to 'y'. Dependencies might truncate the value down # later, but this will at least give the highest possible value. @@ -45,7 +45,7 @@ def main(): for choice in kconf.unique_choices: choice.set_value(2) - kconf.enable_warnings() + kconf.warn = True kconfiglib.load_allconfig(kconf, "allyes.config") diff --git a/examples/menuconfig_example.py b/examples/menuconfig_example.py index b265e69..2c98fff 100755 --- a/examples/menuconfig_example.py +++ b/examples/menuconfig_example.py @@ -277,9 +277,8 @@ def get_value_from_user(sc): val = "0x" + val # Let Kconfiglib itself print a warning here if the value is invalid. We - # could also disable warnings temporarily with - # kconf.disable_warnings() / kconf.enable_warnings() and print our own - # warning. + # could also disable warnings temporarily with 'kconf.warn = False' and + # print our own warning. return sc.set_value(val) diff --git a/examples/merge_config.py b/examples/merge_config.py index 6f60375..ef11d79 100755 --- a/examples/merge_config.py +++ b/examples/merge_config.py @@ -82,7 +82,7 @@ if len(sys.argv) < 4: kconf = Kconfig(sys.argv[1]) # Enable warnings for assignments to undefined symbols -kconf.enable_undef_warnings() +kconf.warn_assign_undef = True # (This script uses alldefconfig as the base. Other starting states could be # set up here as well. The approach in examples/allnoconfig_simpler.py could @@ -91,8 +91,8 @@ kconf.enable_undef_warnings() # Disable warnings generated for multiple assignments to the same symbol within # a (set of) configuration files. Assigning a symbol multiple times might be # done intentionally when merging configuration files. -kconf.disable_override_warnings() -kconf.disable_redun_warnings() +kconf.warn_assign_override = False +kconf.warn_assign_redun = False # Create a merged configuration by loading the fragments with replace=False. # load_config() and write_config() returns a message to print. diff --git a/kconfiglib.py b/kconfiglib.py index d33a690..69093fb 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -450,8 +450,8 @@ Some optional warnings can be controlled via environment variables: all assignments to undefined symbols within .config files. By default, no such warnings are generated. - This warning can also be enabled/disabled via - Kconfig.enable/disable_undef_warnings(). + This warning can also be enabled/disabled via the Kconfig.warn_assign_undef + variable. Preprocessor user functions defined in Python @@ -705,18 +705,55 @@ class Kconfig(object): A dictionary with all preprocessor variables, indexed by name. See the Variable class. + warn: + Set this variable to True/False to enable/disable warnings. See + Kconfig.__init__(). + + When 'warn' is False, the values of the other warning-related variables + are ignored. + + This variable as well as the other warn* variables can be read to check + the current warning settings. + + warn_to_stderr: + Set this variable to True/False to enable/disable warnings on stderr. See + Kconfig.__init__(). + + warn_assign_undef: + Set this variable to True to generate warnings for assignments to + undefined symbols in configuration files. + + This variable is False by default unless the KCONFIG_WARN_UNDEF_ASSIGN + environment variable was set to 'y' when the Kconfig instance was + created. + + warn_assign_override: + Set this variable to True to generate warnings for multiple assignments + to the same symbol in configuration files, where the assignments set + different values (e.g. CONFIG_FOO=m followed by CONFIG_FOO=y, where the + last value would get used). + + This variable is True by default. Disabling it might be useful when + merging configurations. + + warn_assign_redun: + Like warn_assign_override, but for multiple assignments setting a symbol + to the same value. + + This variable is True by default. Disabling it might be useful when + merging configurations. + warnings: - A list of strings containing all warnings that have been generated. This - allows flexibility in how warnings are printed and processed. + A list of strings containing all warnings that have been generated, for + cases where more flexibility is needed. See the 'warn_to_stderr' parameter to Kconfig.__init__() and the - Kconfig.enable/disable_stderr_warnings() functions as well. Note that - warnings still get added to Kconfig.warnings when 'warn_to_stderr' is - True. + Kconfig.warn_to_stderr variable as well. Note that warnings still get + added to Kconfig.warnings when 'warn_to_stderr' is True. - Just as for warnings printed to stderr, only optional warnings that are - enabled will get added to Kconfig.warnings. See the various - Kconfig.enable/disable_*_warnings() functions. + Just as for warnings printed to stderr, only warnings that are enabled + will get added to Kconfig.warnings. See the various Kconfig.warn* + variables. missing_syms: A list with (name, value) tuples for all assignments to undefined symbols @@ -757,12 +794,7 @@ class Kconfig(object): "_set_match", "_srctree_prefix", "_unset_match", - "_warn_for_no_prompt", - "_warn_for_override", - "_warn_for_redun_assign", - "_warn_for_undef_assign", - "_warn_to_stderr", - "_warnings_enabled", + "_warn_no_prompt", "choices", "comments", "config_prefix", @@ -784,6 +816,11 @@ class Kconfig(object): "unique_choices", "unique_defined_syms", "variables", + "warn", + "warn_assign_override", + "warn_assign_redun", + "warn_assign_undef", + "warn_to_stderr", "warnings", "y", @@ -835,12 +872,12 @@ class Kconfig(object): warn (default: True): True if warnings related to this configuration should be generated. - This can be changed later with Kconfig.enable/disable_warnings(). It + This can be changed later by setting Kconfig.warn to True/False. It is provided as a constructor argument since warnings might be generated during parsing. - See the other Kconfig.enable_*_warnings() functions as well, which - enable or suppress certain warnings when warnings are enabled. + See the other Kconfig.warn_* variables as well, which enable or + suppress certain warnings when warnings are enabled. All generated warnings are added to the Kconfig.warnings list. See the class documentation. @@ -849,8 +886,8 @@ class Kconfig(object): True if warnings should be printed to stderr in addition to being added to Kconfig.warnings. - This can be changed later with - Kconfig.enable/disable_stderr_warnings(). + This can be changed later by setting Kconfig.warn_to_stderr to + True/False. encoding (default: "utf-8"): The encoding to use when reading and writing files. If None, the @@ -882,11 +919,11 @@ class Kconfig(object): self.warnings = [] - self._warnings_enabled = warn - self._warn_to_stderr = warn_to_stderr - self._warn_for_undef_assign = \ + self.warn = warn + self.warn_to_stderr = warn_to_stderr + self.warn_assign_undef = \ os.environ.get("KCONFIG_WARN_UNDEF_ASSIGN") == "y" - self._warn_for_redun_assign = self._warn_for_override = True + self.warn_assign_override = self.warn_assign_redun = True self._encoding = encoding @@ -1038,7 +1075,7 @@ class Kconfig(object): self._add_choice_deps() - self._warn_for_no_prompt = True + self._warn_no_prompt = True self.mainmenu_text = self.top_node.prompt[0] @@ -1143,15 +1180,15 @@ class Kconfig(object): # Disable the warning about assigning to symbols without prompts. This # is normal and expected within a .config file. - self._warn_for_no_prompt = False + self._warn_no_prompt = False - # This stub only exists to make sure _warn_for_no_prompt gets reenabled + # This stub only exists to make sure _warn_no_prompt gets reenabled try: self._load_config(filename, replace) except UnicodeDecodeError as e: _decoding_error(e, filename) finally: - self._warn_for_no_prompt = True + self._warn_no_prompt = True return ("Loaded" if replace else "Merged") + msg @@ -1274,14 +1311,15 @@ class Kconfig(object): else: display_user_val = sym.user_value - msg = '{} set more than once. Old value: "{}", new value: "{}".'.format( + msg = '{} set more than once. Old value "{}", new value "{}".'.format( _name_and_loc(sym), display_user_val, val ) if display_user_val == val: - self._warn_redun_assign(msg, filename, linenr) - else: - self._warn_override(msg, filename, linenr) + if self.warn_assign_redun: + self._warn(msg, filename, linenr) + elif self.warn_assign_override: + self._warn(msg, filename, linenr) sym.set_value(val) @@ -1301,8 +1339,7 @@ class Kconfig(object): # Called for assignments to undefined symbols during .config loading self.missing_syms.append((name, val)) - - if self._warn_for_undef_assign: + if self.warn_assign_undef: self._warn( "attempt to assign the value '{}' to the undefined symbol {}" .format(val, name), filename, linenr) @@ -1840,7 +1877,7 @@ class Kconfig(object): Removes any user values from all symbols, as if Kconfig.load_config() or Symbol.set_value() had never been called. """ - self._warn_for_no_prompt = False + self._warn_no_prompt = False try: # set_value() already rejects undefined symbols, and they don't # need to be invalidated (because their value never changes), so we @@ -1851,98 +1888,100 @@ class Kconfig(object): for choice in self.unique_choices: choice.unset_value() finally: - self._warn_for_no_prompt = True + self._warn_no_prompt = True def enable_warnings(self): """ - See Kconfig.__init__(). + Do 'Kconfig.warn = True' instead. Maintained for backwards + compatibility. """ - self._warnings_enabled = True + self.warn = True def disable_warnings(self): """ - See Kconfig.__init__(). + Do 'Kconfig.warn = False' instead. Maintained for backwards + compatibility. """ - self._warnings_enabled = False + self.warn = False def enable_stderr_warnings(self): """ - See Kconfig.__init__(). + Do 'Kconfig.warn_to_stderr = True' instead. Maintained for backwards + compatibility. """ - self._warn_to_stderr = True + self.warn_to_stderr = True def disable_stderr_warnings(self): """ - See Kconfig.__init__(). + Do 'Kconfig.warn_to_stderr = False' instead. Maintained for backwards + compatibility. """ - self._warn_to_stderr = False + self.warn_to_stderr = False def enable_undef_warnings(self): """ - Enables warnings for assignments to undefined symbols. Disabled by - default unless the KCONFIG_WARN_UNDEF_ASSIGN environment variable was - set to 'y' when the Kconfig instance was created. + Do 'Kconfig.warn_assign_undef = True' instead. Maintained for backwards + compatibility. """ - self._warn_for_undef_assign = True + self.warn_assign_undef = True def disable_undef_warnings(self): """ - See enable_undef_assign(). + Do 'Kconfig.warn_assign_undef = False' instead. Maintained for + backwards compatibility. """ - self._warn_for_undef_assign = False + self.warn_assign_undef = False def enable_override_warnings(self): """ - Enables warnings for duplicated assignments in .config files that set - different values (e.g. CONFIG_FOO=m followed by CONFIG_FOO=y, where - the last value set is used). - - These warnings are enabled by default. Disabling them might be helpful - in certain cases when merging configurations. + Do 'Kconfig.warn_assign_override = True' instead. Maintained for + backwards compatibility. """ - self._warn_for_override = True + self.warn_assign_override = True def disable_override_warnings(self): """ - See enable_override_warnings(). + Do 'Kconfig.warn_assign_override = False' instead. Maintained for + backwards compatibility. """ - self._warn_for_override = False + self.warn_assign_override = False def enable_redun_warnings(self): """ - Enables warnings for duplicated assignments in .config files that all - set the same value. - - These warnings are enabled by default. Disabling them might be helpful - in certain cases when merging configurations. + Do 'Kconfig.warn_assign_redun = True' instead. Maintained for backwards + compatibility. """ - self._warn_for_redun_assign = True + self.warn_assign_redun = True def disable_redun_warnings(self): """ - See enable_redun_warnings(). + Do 'Kconfig.warn_assign_redun = False' instead. Maintained for + backwards compatibility. """ - self._warn_for_redun_assign = False + self.warn_assign_redun = False def __repr__(self): """ Returns a string with information about the Kconfig object when it is evaluated on e.g. the interactive Python prompt. """ + def status(flag): + return "enabled" if flag else "disabled" + return "<{}>".format(", ".join(( "configuration with {} symbols".format(len(self.syms)), 'main menu prompt "{}"'.format(self.mainmenu_text), "srctree is current directory" if not self.srctree else 'srctree "{}"'.format(self.srctree), 'config symbol prefix "{}"'.format(self.config_prefix), - "warnings " + - ("enabled" if self._warnings_enabled else "disabled"), - "printing of warnings to stderr " + - ("enabled" if self._warn_to_stderr else "disabled"), + "warnings " + status(self.warn), + "printing of warnings to stderr " + status(self.warn_to_stderr), "undef. symbol assignment warnings " + - ("enabled" if self._warn_for_undef_assign else "disabled"), + status(self.warn_assign_undef), + "overriding symbol assignment warnings " + + status(self.warn_assign_override), "redundant symbol assignment warnings " + - ("enabled" if self._warn_for_redun_assign else "disabled") + status(self.warn_assign_redun) ))) # @@ -3805,26 +3844,16 @@ class Kconfig(object): def _warn(self, msg, filename=None, linenr=None): # For printing general warnings - if self._warnings_enabled: - msg = "warning: " + msg - if filename is not None: - msg = "{}:{}: {}".format(filename, linenr, msg) - - self.warnings.append(msg) - if self._warn_to_stderr: - sys.stderr.write(msg + "\n") - - def _warn_override(self, msg, filename, linenr): - # See the class documentation - - if self._warn_for_override: - self._warn(msg, filename, linenr) + if not self.warn: + return - def _warn_redun_assign(self, msg, filename, linenr): - # See the class documentation + msg = "warning: " + msg + if filename is not None: + msg = "{}:{}: {}".format(filename, linenr, msg) - if self._warn_for_redun_assign: - self._warn(msg, filename, linenr) + self.warnings.append(msg) + if self.warn_to_stderr: + sys.stderr.write(msg + "\n") class Symbol(object): @@ -4709,7 +4738,7 @@ class Symbol(object): self._rec_invalidate() return - if self.kconfig._warn_for_no_prompt: + if self.kconfig._warn_no_prompt: self.kconfig._warn(_name_and_loc(self) + " has no prompt, meaning " "user values have no effect on it") @@ -6004,8 +6033,8 @@ def load_allconfig(kconf, filename): Linux kernel. Disables warnings for duplicated assignments within configuration files for - the duration of the call (disable_override_warnings() + - disable_redun_warnings()), and enables them at the end. The + the duration of the call (kconf.warn_assign_override/warn_assign_redun = False), + and restores the previous warning settings at the end. The KCONFIG_ALLCONFIG configuration file is expected to override symbols. Exits with sys.exit() (which raises a SystemExit exception) and prints an @@ -6028,8 +6057,9 @@ def load_allconfig(kconf, filename): # __str__() message. The standard message is better here. return IOError(e.errno, e.strerror, e.filename) - kconf.disable_override_warnings() - kconf.disable_redun_warnings() + old_warn_assign_override = kconf.warn_assign_override + old_warn_assign_redun = kconf.warn_assign_redun + kconf.warn_assign_override = kconf.warn_assign_redun = False if allconfig in ("", "1"): try: @@ -6049,10 +6079,8 @@ def load_allconfig(kconf, filename): "could not be opened: {}" .format(allconfig, std_msg(e))) - # API wart: It would be nice if there was a way to query and/or push/pop - # warning settings - kconf.enable_override_warnings() - kconf.enable_redun_warnings() + kconf.warn_assign_override = old_warn_assign_override + kconf.warn_assign_redun = old_warn_assign_redun # diff --git a/menuconfig.py b/menuconfig.py index a7f921b..a5345b2 100755 --- a/menuconfig.py +++ b/menuconfig.py @@ -673,7 +673,7 @@ def menuconfig(kconf): # Disable warnings. They get mangled in curses mode, and we deal with # errors ourselves. - kconf.disable_warnings() + kconf.warn = False # Make curses use the locale settings specified in the environment locale.setlocale(locale.LC_ALL, "") @@ -923,6 +923,7 @@ def _quit_dialog(): return None if c == "y": + # Returns a message to print msg = _try_save(_kconf.write_config, _conf_filename, "configuration") if msg: return msg diff --git a/testsuite.py b/testsuite.py index 376f165..8e17d84 100644 --- a/testsuite.py +++ b/testsuite.py @@ -356,7 +356,7 @@ def run_selftests(): verify_eval('"foo" = "foo"', 2) # Undefined symbols get their name as their value - c.disable_warnings() + c.warn = False verify_eval("'not_defined' = not_defined", 2) verify_eval("not_defined_2 = not_defined_2", 2) verify_eval("not_defined_1 != not_defined_2", 2) @@ -957,20 +957,21 @@ config DEP_REM_CORNER_CASES print("Testing Kconfig.__repr__()") verify_repr(c, """ - + """) os.environ["srctree"] = "Kconfiglib" os.environ["CONFIG_"] = "CONFIG_ value" c = Kconfig("tests/Krepr", warn=False) - c.enable_warnings() - c.disable_stderr_warnings() - c.disable_redun_warnings() - c.enable_undef_warnings() + c.warn = True + c.warn_to_stderr = False + c.warn_assign_override = False + c.warn_assign_redun = False + c.warn_assign_undef = True verify_repr(c, """ - + """) os.environ.pop("srctree", None) @@ -1311,7 +1312,7 @@ tests/Krecursive2:1 print("Testing split_expr()") c = Kconfig("Kconfiglib/tests/empty") - c.disable_warnings() + c.warn = False def verify_split(to_split, op, operand_strs): # The same hackage as in Kconfig.eval_string() @@ -1630,7 +1631,7 @@ tests/Krecursive2:1 # User values and dependent ranges # Avoid warnings for assigning values outside the active range - c.disable_warnings() + c.warn = False def verify_range(sym_name, low, high, default): # Verifies that all values in the range 'low'-'high' can be assigned, @@ -1760,7 +1761,7 @@ tests/Krecursive2:1 # Avoid warnings from assigning invalid user values and assigning user # values to symbols without prompts - c.disable_warnings() + c.warn = False syms = [c.syms[name] for name in ("BOOL", "TRISTATE", "STRING", "INT", "HEX")] @@ -2803,6 +2804,8 @@ def test_sanity(arch, srcarch): kconf.modules kconf.defconfig_list kconf.defconfig_filename + + # Legacy warning functions kconf.enable_redun_warnings() kconf.disable_redun_warnings() kconf.enable_undef_warnings() @@ -2811,6 +2814,7 @@ def test_sanity(arch, srcarch): kconf.disable_warnings() kconf.enable_stderr_warnings() kconf.disable_stderr_warnings() + kconf.mainmenu_text kconf.unset_values() @@ -2843,7 +2847,7 @@ def test_sanity(arch, srcarch): sym.set_value(2) sym.set_value("foo") sym.unset_value() - kconf.enable_warnings() + kconf.enable_warnings() # Legacy warning function sym.str_value sym.tri_value sym.type @@ -2881,7 +2885,7 @@ def test_sanity(arch, srcarch): sym.set_value(2) sym.set_value("foo") sym.unset_value() - kconf.enable_warnings() + kconf.enable_warnings() # Legacy warning function sym.str_value sym.tri_value sym.type -- cgit v1.2.3