diff options
author | Mats Wichmann <mats@linux.com> | 2024-03-05 14:08:19 (GMT) |
---|---|---|
committer | Mats Wichmann <mats@linux.com> | 2024-03-08 19:07:39 (GMT) |
commit | 14b5110b31b596990238f5b8eb5814e5090b2aa8 (patch) | |
tree | 23948558c2f7b800d4843495181632748837b6ab /SCons/Warnings.py | |
parent | 3b168f538bff5506bd32921ea803ff1e9078ddda (diff) | |
download | SCons-14b5110b31b596990238f5b8eb5814e5090b2aa8.zip SCons-14b5110b31b596990238f5b8eb5814e5090b2aa8.tar.gz SCons-14b5110b31b596990238f5b8eb5814e5090b2aa8.tar.bz2 |
Cleanup Warnings module
* Added docstrings on warning classes and module docstring.
* Move globals to top of file.
* Typing.
* Dropped DeprecatedSourceCodeWarning, last use was removed, with the
feature, for SCons 3.1.2.
* Dropped TaskmasterNeedsExecuteWarning, now enforced by Python via an
abstract base class (unused/unneeded since 4.0.0).
* Dropped DeprecatedMissingSConscriptWarning. This was a transitional
warning, no longer needed; can use MissingSConscriptWarning, which
also is no longer used but is left in in case it might be useful.
* Two in-use warnings added to manpage section on enabling warnings
(cache-cleanup-error, future-reserved-variable).
* Improve unittest a bit.
* Sphinx build set not to show inherited memerber for Warnings -
got ugly exception stuff otherwise.
Signed-off-by: Mats Wichmann <mats@linux.com>
Diffstat (limited to 'SCons/Warnings.py')
-rw-r--r-- | SCons/Warnings.py | 230 |
1 files changed, 143 insertions, 87 deletions
diff --git a/SCons/Warnings.py b/SCons/Warnings.py index f6809fb..d604659 100644 --- a/SCons/Warnings.py +++ b/SCons/Warnings.py @@ -21,159 +21,211 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -"""The SCons warnings framework.""" +"""The SCons Warnings framework. + +Enables issuing warnings in situations where it is useful to alert +the user of a condition that does not warrant raising an exception +that could terminate the program. + +A new warning class should inherit (perhaps indirectly) from one of +two base classes: :exc:`SConsWarning` or :exc:`WarningOnByDefault`, +which are the same except warnings derived from the latter will start +out in an enabled state. Enabled warnings cause a message to be +printed when called, disabled warnings are silent. + +There is also a hierarchy for indicating deprecations and future +changes: for these, derive from :exc:`DeprecatedWarning`, +:exc:`MandatoryDeprecatedWarning`, :exc:`FutureDeprecatedWarning` +or :exc:`FutureReservedVariableWarning`. + +Whether or not to display warnings, beyond those that are on by +default, is controlled through the command line (``--warn``) or +through ``SetOption('warn')``. The names used there use a different +naming style than the warning class names. :func:`process_warn_strings` +converts the names before enabling/disabling. + +The behavior of issuing only a message (for "enabled" warnings) can +be toggled to raising an exception instead by calling the +:func:`warningAsException` function. + +For new/removed warnings, the manpage needs to be kept in sync. +Any warning class defined here is accepted, but we don't want to make +people have to dig around to find the names. Warnings do not have to +be defined in this file, though it is preferred: those defined elsewhere +cannot use the enable/disable functionality unless they monkeypatch the +warning into this module's namespace. + +You issue a warning, either in SCons code or in a build project's +SConscripts, by calling the :func:`warn` function defined in this module. +Raising directly with an instance of a warning class bypasses the +framework and it will behave like an ordinary exception. +""" import sys +from typing import Callable, Sequence, Optional import SCons.Errors +# _enabled is a list of 2-tuples with a warning class object and a +# boolean (True if that warning is enabled). Initialized in SCons/Main.py. +_enabled = [] + +# If False, just emit the msg for an enabled warning; else raise exception +_warningAsException: bool = False + +# Function to emit the warning. Initialized by SCons/Main.py for regular use; +# the unit test will set to a capturing version for testing. +_warningOut: Optional[Callable] = None + + class SConsWarning(SCons.Errors.UserError): - pass + """Base class for all SCons warnings.""" class WarningOnByDefault(SConsWarning): - pass + """Base class for SCons warnings that are enabled by default.""" +SConsWarningOnByDefault = WarningOnByDefault # transition to new name -# NOTE: If you add a new warning class, add it to the man page, too! -# Not all warnings are defined here, some are defined in the location of use -class TargetNotBuiltWarning(SConsWarning): # Should go to OnByDefault - pass +class LinkWarning(WarningOnByDefault): + """Base class for linker warnings.""" + +# NOTE: If you add a new warning class here, add it to the man page, too! + +# General warnings class CacheVersionWarning(WarningOnByDefault): - pass + """The derived-file cache directory has an out of date config.""" class CacheWriteErrorWarning(SConsWarning): - pass + """Problems writing a derived file to the cache.""" class CacheCleanupErrorWarning(SConsWarning): - pass + """Problems removing retrieved target prior to rebuilding.""" class CorruptSConsignWarning(WarningOnByDefault): - pass + """Problems decoding the contents of the sconsign database.""" class DependencyWarning(SConsWarning): - pass + """A scanner identified a dependency but did not add it.""" class DevelopmentVersionWarning(WarningOnByDefault): - pass + """Use of a deprecated feature.""" class DuplicateEnvironmentWarning(WarningOnByDefault): - pass + """A target appears in more than one consenv with identical actions. -class FutureReservedVariableWarning(WarningOnByDefault): - pass + A duplicate target with different rules cannot be built; + with the same rule it can, but this could indicate a problem in + the build configuration. + """ -class LinkWarning(WarningOnByDefault): - pass +class FortranCxxMixWarning(LinkWarning): + """Fortran and C++ objects appear together in a link line. + + Some compilers support this, others do not. + """ + +class FutureReservedVariableWarning(WarningOnByDefault): + """Setting a variable marked to become reserved in a future release.""" class MisleadingKeywordsWarning(WarningOnByDefault): - pass + """Use of possibly misspelled kwargs in Builder calls.""" -# TODO: no longer needed, now an error instead of warning. Leave for a bit. class MissingSConscriptWarning(WarningOnByDefault): - pass + """The script specified in an SConscript() call was not found. + + TODO: this is now an error, so no need for a warning. Left in for + a while in case anyone is using, remove eventually. + + Manpage entry removed in 4.6.0. + """ class NoObjectCountWarning(WarningOnByDefault): - pass + """Object counting (debug mode) could not be enabled.""" class NoParallelSupportWarning(WarningOnByDefault): - pass + """Fell back to single-threaded build, as no thread support found.""" class ReservedVariableWarning(WarningOnByDefault): - pass + """Attempt to set reserved construction variable names.""" class StackSizeWarning(WarningOnByDefault): - pass + """Requested thread stack size could not be set.""" + +class TargetNotBuiltWarning(SConsWarning): # TODO: should go to OnByDefault + """A target build indicated success but the file is not found.""" class VisualCMissingWarning(WarningOnByDefault): - pass + """Requested MSVC version not found and policy is to not fail.""" -# Used when MSVC_VERSION and MSVS_VERSION do not point to the -# same version (MSVS_VERSION is deprecated) class VisualVersionMismatch(WarningOnByDefault): - pass + """``MSVC_VERSION`` and ``MSVS_VERSION`` do not match. -class VisualStudioMissingWarning(SConsWarning): - pass + Note ``MSVS_VERSION`` is deprecated, use ``MSVC_VERSION``. + """ -class FortranCxxMixWarning(LinkWarning): +class VisualStudioMissingWarning(SConsWarning): # TODO: unused pass # Deprecation warnings class FutureDeprecatedWarning(SConsWarning): - pass + """Base class for features that will become deprecated in a future release.""" class DeprecatedWarning(SConsWarning): - pass + """Base class for deprecated features, will be removed in future.""" class MandatoryDeprecatedWarning(DeprecatedWarning): - pass + """Base class for deprecated features where warning cannot be disabled.""" # Special case; base always stays DeprecatedWarning class PythonVersionWarning(DeprecatedWarning): - pass - -class DeprecatedSourceCodeWarning(FutureDeprecatedWarning): - pass - -class TaskmasterNeedsExecuteWarning(DeprecatedWarning): - pass + """SCons was run with a deprecated Python version.""" class DeprecatedOptionsWarning(MandatoryDeprecatedWarning): - pass + """Options that are deprecated.""" class DeprecatedDebugOptionsWarning(MandatoryDeprecatedWarning): - pass + """Option-arguments to --debug that are deprecated.""" -class DeprecatedMissingSConscriptWarning(DeprecatedWarning): +class ToolQtDeprecatedWarning(DeprecatedWarning): # TODO: unused pass -class ToolQtDeprecatedWarning(DeprecatedWarning): - pass - -# The below is a list of 2-tuples. The first element is a class object. -# The second element is true if that class is enabled, false if it is disabled. -_enabled = [] - -# If set, raise the warning as an exception -_warningAsException = False - -# If not None, a function to call with the warning -_warningOut = None def suppressWarningClass(clazz) -> None: - """Suppresses all warnings of type clazz or derived from clazz.""" + """Suppresses all warnings of type *clazz* or derived from *clazz*.""" _enabled.insert(0, (clazz, False)) def enableWarningClass(clazz) -> None: - """Enables all warnings of type clazz or derived from clazz.""" + """Enables all warnings of type *clazz* or derived from *clazz*.""" _enabled.insert(0, (clazz, True)) -def warningAsException(flag: bool=True): - """Set global _warningAsExeption flag. +def warningAsException(flag: bool = True) -> bool: + """Sets global :data:`_warningAsExeption` flag. + + If true, any enabled warning will cause an exception to be raised. Args: - flag: value to set warnings-as-exceptions to [default: True] + flag: new value for warnings-as-exceptions. Returns: The previous value. """ - global _warningAsException + global _warningAsException # pylint: disable=global-statement old = _warningAsException _warningAsException = flag return old -def warn(clazz, *args): +def warn(clazz, *args) -> None: """Issue a warning, accounting for SCons rules. - Check if warnings for this class are enabled. - If warnings are treated as exceptions, raise exception. - Use the global warning-emitter _warningOut, which allows selecting - different ways of presenting a traceback (see Script/Main.py) + Check if warnings for this class are enabled. If warnings are treated + as exceptions, raise exception. Use the global warning emitter + :data:`_warningOut`, which allows selecting different ways of + presenting a traceback (see Script/Main.py). """ warning = clazz(args) for cls, flag in _enabled: @@ -182,30 +234,32 @@ def warn(clazz, *args): if _warningAsException: raise warning - if _warningOut: + if _warningOut is not None: _warningOut(warning) break -def process_warn_strings(arguments) -> None: +def process_warn_strings(arguments: Sequence[str]) -> None: """Process requests to enable/disable warnings. - The requests are strings passed to the --warn option or the - SetOption('warn') function. + The requests come from the option-argument string passed to the + ``--warn`` command line option or as the value passed to the + ``SetOption`` function with a first argument of ``warn``; - An argument to this option should be of the form "warning-class" - or "no-warning-class". The warning class is munged and has - the suffix "Warning" added in order to get an actual class name - from the classes above, which we need to pass to the - {enable,disable}WarningClass() functions. - For example, "deprecated" will enable the DeprecatedWarning class. - "no-dependency" will disable the DependencyWarning class. + The arguments are expected to be as documented in the SCons manual + page for the ``--warn`` option, in the style ``some-type``, + which is converted here to a camel-case name like ``SomeTypeWarning``, + to try to match the warning classes defined here, which are then + passed to :func:`enableWarningClass` or :func:`suppressWarningClass`. - As a special case, --warn=all and --warn=no-all will enable or - disable (respectively) the base class of all SCons warnings. - """ + For example, a string``"deprecated"`` enables the + :exc:`DeprecatedWarning` class, while a string``"no-dependency"`` + disables the :exc:`DependencyWarning` class. - def _classmunge(s): + As a special case, the string ``"all"`` disables all warnings and + a the string ``"no-all"`` disables all warnings. + """ + def _classmunge(s: str) -> str: """Convert a warning argument to SConsCase. The result is CamelCase, except "Scons" is changed to "SCons" @@ -215,7 +269,10 @@ def process_warn_strings(arguments) -> None: for arg in arguments: enable = True - if arg.startswith("no-"): + if arg.startswith("no-") and arg not in ( + "no-object-count", + "no-parallel-support", + ): enable = False arg = arg[len("no-") :] if arg == 'all': @@ -225,13 +282,12 @@ def process_warn_strings(arguments) -> None: try: clazz = globals()[class_name] except KeyError: - sys.stderr.write("No warning type: '%s'\n" % arg) + sys.stderr.write(f"No warning type: {arg!r}\n") else: if enable: enableWarningClass(clazz) elif issubclass(clazz, MandatoryDeprecatedWarning): - fmt = "Can not disable mandataory warning: '%s'\n" - sys.stderr.write(fmt % arg) + sys.stderr.write(f"Can not disable mandataory warning: {arg!r}\n") else: suppressWarningClass(clazz) |