summaryrefslogtreecommitdiffstats
path: root/SCons/Warnings.py
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2024-03-05 14:08:19 (GMT)
committerMats Wichmann <mats@linux.com>2024-03-08 19:07:39 (GMT)
commit14b5110b31b596990238f5b8eb5814e5090b2aa8 (patch)
tree23948558c2f7b800d4843495181632748837b6ab /SCons/Warnings.py
parent3b168f538bff5506bd32921ea803ff1e9078ddda (diff)
downloadSCons-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.py230
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)