summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2024-11-24 22:17:53 (GMT)
committerGitHub <noreply@github.com>2024-11-24 22:17:53 (GMT)
commitc580a721ccabcf1fc9789e0a3f906cb2c08db0da (patch)
treeae383c93fcc74318ee4f837d46ecc55c3b6d8a59
parent502665a28dc0187d23a3ca19f17f3336a1465abc (diff)
parent488707f4a9d1f1c7c7cd2b28a0bcbaf4e9bbb0dc (diff)
downloadSCons-c580a721ccabcf1fc9789e0a3f906cb2c08db0da.zip
SCons-c580a721ccabcf1fc9789e0a3f906cb2c08db0da.tar.gz
SCons-c580a721ccabcf1fc9789e0a3f906cb2c08db0da.tar.bz2
Merge pull request #4650 from Repiteo/node-explicit-types
Add type hints to main Node script
-rw-r--r--CHANGES.txt1
-rw-r--r--RELEASE.txt2
-rw-r--r--SCons/Node/NodeTests.py30
-rw-r--r--SCons/Node/__init__.py251
4 files changed, 147 insertions, 137 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index e65ba36..e449bba 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -83,6 +83,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
detect and upgrade legacy type-hint syntax.
- Removed "SCons.Util.sctyping.py", as the functionality can now be substituted
via top-level `from __future__ import annotations`.
+ - Implemented type hints for Nodes.
From Alex James:
- On Darwin, PermissionErrors are now handled while trying to access
diff --git a/RELEASE.txt b/RELEASE.txt
index a73e654..8e88a0b 100644
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -194,6 +194,8 @@ DEVELOPMENT
- Removed "SCons.Util.sctyping.py", as the functionality can now be substituted
via top-level `from __future__ import annotations`.
+- Implemented type hints for Nodes.
+
Thanks to the following contributors listed below for their contributions to this release.
==========================================================================================
.. code-block:: text
diff --git a/SCons/Node/NodeTests.py b/SCons/Node/NodeTests.py
index 6c7437d..d8288f4 100644
--- a/SCons/Node/NodeTests.py
+++ b/SCons/Node/NodeTests.py
@@ -461,13 +461,13 @@ class NodeTestCase(unittest.TestCase):
"""Test the base push_to_cache() method"""
n = SCons.Node.Node()
r = n.push_to_cache()
- assert r is None, r
+ assert not r, r
def test_retrieve_from_cache(self) -> None:
"""Test the base retrieve_from_cache() method"""
n = SCons.Node.Node()
r = n.retrieve_from_cache()
- assert r == 0, r
+ assert not r, r
def test_visited(self) -> None:
"""Test the base visited() method
@@ -711,21 +711,21 @@ class NodeTestCase(unittest.TestCase):
node = SCons.Node.Node()
node.set_always_build()
assert node.always_build
- node.set_always_build(3)
- assert node.always_build == 3
+ node.set_always_build(3) # type: ignore[arg-type]
+ assert node.always_build
def test_set_noclean(self) -> None:
"""Test setting a Node's noclean value
"""
node = SCons.Node.Node()
node.set_noclean()
- assert node.noclean == 1, node.noclean
- node.set_noclean(7)
- assert node.noclean == 1, node.noclean
- node.set_noclean(0)
- assert node.noclean == 0, node.noclean
- node.set_noclean(None)
- assert node.noclean == 0, node.noclean
+ assert node.noclean, node.noclean
+ node.set_noclean(7) # type: ignore[arg-type]
+ assert node.noclean, node.noclean
+ node.set_noclean(0) # type: ignore[arg-type]
+ assert not node.noclean, node.noclean
+ node.set_noclean(None) # type: ignore[arg-type]
+ assert not node.noclean, node.noclean
def test_set_precious(self) -> None:
"""Test setting a Node's precious value
@@ -733,8 +733,8 @@ class NodeTestCase(unittest.TestCase):
node = SCons.Node.Node()
node.set_precious()
assert node.precious
- node.set_precious(7)
- assert node.precious == 7
+ node.set_precious(7) # type: ignore[arg-type]
+ assert node.precious
def test_set_pseudo(self) -> None:
"""Test setting a Node's pseudo value
@@ -750,14 +750,14 @@ class NodeTestCase(unittest.TestCase):
"""
node = SCons.Node.Node()
e = node.exists()
- assert e == 1, e
+ assert e, e
def test_exists_repo(self) -> None:
"""Test evaluating whether a Node exists locally or in a repository.
"""
node = SCons.Node.Node()
e = node.rexists()
- assert e == 1, e
+ assert e, e
class MyNode(SCons.Node.Node):
def exists(self) -> str:
diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py
index 8ae991e..055c309 100644
--- a/SCons/Node/__init__.py
+++ b/SCons/Node/__init__.py
@@ -45,6 +45,7 @@ from __future__ import annotations
import collections
import copy
from itertools import chain, zip_longest
+from typing import Any, Callable, TYPE_CHECKING
import SCons.Debug
import SCons.Executor
@@ -54,6 +55,12 @@ from SCons.Debug import logInstanceCreation, Trace
from SCons.Executor import Executor
from SCons.Util import hash_signature, is_List, UniqueList, render_tree
+if TYPE_CHECKING:
+ from SCons.Builder import BuilderBase
+ from SCons.Environment import Base as Environment
+ from SCons.Scanner import ScannerBase
+ from SCons.SConsign import SConsignEntry
+
print_duplicate = 0
def classname(obj):
@@ -102,7 +109,7 @@ def do_nothing_node(node) -> None: pass
Annotate = do_nothing_node
# global set for recording all processed SContruct/SConscript nodes
-SConscriptNodes = set()
+SConscriptNodes: set[Node] = set()
# Gets set to 'True' if we're running in interactive mode. Is
# currently used to release parts of a target's info during
@@ -189,7 +196,7 @@ def get_contents_entry(node):
"""Fetch the contents of the entry. Returns the exact binary
contents of the file."""
try:
- node = node.disambiguate(must_exist=1)
+ node = node.disambiguate(must_exist=True)
except SCons.Errors.UserError:
# There was nothing on disk with which to disambiguate
# this entry. Leave it as an Entry, but return a null
@@ -356,7 +363,7 @@ class NodeInfoBase:
__slots__ = ('__weakref__',)
current_version_id = 2
- def update(self, node) -> None:
+ def update(self, node: Node) -> None:
try:
field_list = self.field_list
except AttributeError:
@@ -376,7 +383,7 @@ class NodeInfoBase:
def convert(self, node, val) -> None:
pass
- def merge(self, other) -> None:
+ def merge(self, other: NodeInfoBase) -> None:
"""
Merge the fields of another object into this object. Already existing
information is overwritten by the other instance's data.
@@ -386,7 +393,7 @@ class NodeInfoBase:
state = other.__getstate__()
self.__setstate__(state)
- def format(self, field_list=None, names: int=0):
+ def format(self, field_list: list[str] | None = None, names: bool = False):
if field_list is None:
try:
field_list = self.field_list
@@ -409,7 +416,7 @@ class NodeInfoBase:
fields.append(f)
return fields
- def __getstate__(self):
+ def __getstate__(self) -> dict[str, Any]:
"""
Return all fields that shall be pickled. Walk the slots in the class
hierarchy and add those to the state dictionary. If a '__dict__' slot is
@@ -429,7 +436,7 @@ class NodeInfoBase:
pass
return state
- def __setstate__(self, state) -> None:
+ def __setstate__(self, state: dict[str, Any]) -> None:
"""
Restore the attributes from a pickled state. The version is discarded.
"""
@@ -458,12 +465,12 @@ class BuildInfoBase:
def __init__(self) -> None:
# Create an object attribute from the class attribute so it ends up
# in the pickled data in the .sconsign file.
- self.bsourcesigs = []
- self.bdependsigs = []
- self.bimplicitsigs = []
- self.bactsig = None
+ self.bsourcesigs: list[BuildInfoBase] = []
+ self.bdependsigs: list[BuildInfoBase] = []
+ self.bimplicitsigs: list[BuildInfoBase] = []
+ self.bactsig: str | None = None
- def merge(self, other) -> None:
+ def merge(self, other: BuildInfoBase) -> None:
"""
Merge the fields of another object into this object. Already existing
information is overwritten by the other instance's data.
@@ -473,7 +480,7 @@ class BuildInfoBase:
state = other.__getstate__()
self.__setstate__(state)
- def __getstate__(self):
+ def __getstate__(self) -> dict[str, Any]:
"""
Return all fields that shall be pickled. Walk the slots in the class
hierarchy and add those to the state dictionary. If a '__dict__' slot is
@@ -493,7 +500,7 @@ class BuildInfoBase:
pass
return state
- def __setstate__(self, state) -> None:
+ def __setstate__(self, state: dict[str, Any]) -> None:
"""
Restore the attributes from a pickled state.
"""
@@ -571,42 +578,42 @@ class Node(metaclass=NoSlotsPyPy):
# this way, instead of wrapping up each list+dictionary pair in
# a class. (Of course, we could always still do that in the
# future if we had a good reason to...).
- self.sources = [] # source files used to build node
- self.sources_set = set()
+ self.sources: list[Node] = [] # source files used to build node
+ self.sources_set: set[Node] = set()
self._specific_sources = False
- self.depends = [] # explicit dependencies (from Depends)
- self.depends_set = set()
- self.ignore = [] # dependencies to ignore
- self.ignore_set = set()
- self.prerequisites = None
- self.implicit = None # implicit (scanned) dependencies (None means not scanned yet)
- self.waiting_parents = set()
- self.waiting_s_e = set()
+ self.depends: list[Node] = [] # explicit dependencies (from Depends)
+ self.depends_set: set[Node] = set()
+ self.ignore: list[Node] = [] # dependencies to ignore
+ self.ignore_set: set[Node] = set()
+ self.prerequisites: UniqueList | None = None
+ self.implicit: list[Node] | None = None # implicit (scanned) dependencies (None means not scanned yet)
+ self.waiting_parents: set[Node] = set()
+ self.waiting_s_e: set[Node] = set()
self.ref_count = 0
- self.wkids = None # Kids yet to walk, when it's an array
+ self.wkids: list[Node] | None = None # Kids yet to walk, when it's an array
- self.env = None
+ self.env: Environment | None = None
self.state = no_state
- self.precious = None
+ self.precious = False
self.pseudo = False
- self.noclean = 0
- self.nocache = 0
- self.cached = 0 # is this node pulled from cache?
- self.always_build = None
- self.includes = None
+ self.noclean = False
+ self.nocache = False
+ self.cached = False # is this node pulled from cache?
+ self.always_build = False
+ self.includes: list[str] | None = None
self.attributes = self.Attrs() # Generic place to stick information about the Node.
- self.side_effect = 0 # true iff this node is a side effect
- self.side_effects = [] # the side effects of building this target
- self.linked = 0 # is this node linked to the variant directory?
- self.changed_since_last_build = 0
- self.store_info = 0
- self._tags = None
- self._func_is_derived = 1
- self._func_exists = 1
- self._func_rexists = 1
- self._func_get_contents = 0
- self._func_target_from_source = 0
- self.ninfo = None
+ self.side_effect = False # true iff this node is a side effect
+ self.side_effects: list[Node] = [] # the side effects of building this target
+ self.linked = False # is this node linked to the variant directory?
+ self.changed_since_last_build = 0 # Index for "_decider_map".
+ self.store_info = 0 # Index for "store_info_map".
+ self._tags: dict[str, Any] | None = None
+ self._func_is_derived = 1 # Index for "_is_derived_map".
+ self._func_exists = 1 # Index for "_exists_map"
+ self._func_rexists = 1 # Index for "_rexists_map"
+ self._func_get_contents = 0 # Index for "_get_contents_map"
+ self._func_target_from_source = 0 # Index for "_target_from_source_map"
+ self.ninfo: NodeInfoBase | None = None
self.clear_memoized_values()
@@ -615,14 +622,14 @@ class Node(metaclass=NoSlotsPyPy):
# what line in what file created the node, for example).
Annotate(self)
- def disambiguate(self, must_exist=None):
+ def disambiguate(self, must_exist: bool = False):
return self
def get_suffix(self) -> str:
return ''
@SCons.Memoize.CountMethodCall
- def get_build_env(self):
+ def get_build_env(self) -> Environment:
"""Fetch the appropriate Environment to build this node.
"""
try:
@@ -633,7 +640,7 @@ class Node(metaclass=NoSlotsPyPy):
self._memo['get_build_env'] = result
return result
- def get_build_scanner_path(self, scanner):
+ def get_build_scanner_path(self, scanner: ScannerBase):
"""Fetch the appropriate scanner path for this node."""
return self.get_executor().get_build_scanner_path(scanner)
@@ -641,7 +648,7 @@ class Node(metaclass=NoSlotsPyPy):
"""Set the action executor for this node."""
self.executor = executor
- def get_executor(self, create: int=1) -> Executor:
+ def get_executor(self, create: bool = True) -> Executor:
"""Fetch the action executor for this node. Create one if
there isn't already one, and requested to do so."""
try:
@@ -652,7 +659,7 @@ class Node(metaclass=NoSlotsPyPy):
try:
act = self.builder.action
except AttributeError:
- executor = SCons.Executor.Null(targets=[self]) # type: ignore
+ executor = SCons.Executor.Null(targets=[self]) # type: ignore[assignment]
else:
executor = SCons.Executor.Executor(act,
self.env or self.builder.env,
@@ -665,7 +672,7 @@ class Node(metaclass=NoSlotsPyPy):
def executor_cleanup(self) -> None:
"""Let the executor clean up any cached information."""
try:
- executor = self.get_executor(create=None)
+ executor = self.get_executor(create=False)
except AttributeError:
pass
else:
@@ -682,7 +689,7 @@ class Node(metaclass=NoSlotsPyPy):
def push_to_cache(self) -> bool:
"""Try to push a node into a cache
"""
- pass
+ return False
def retrieve_from_cache(self) -> bool:
"""Try to retrieve the node's content from a cache
@@ -709,7 +716,7 @@ class Node(metaclass=NoSlotsPyPy):
"""
pass
- def prepare(self):
+ def prepare(self) -> None:
"""Prepare for this Node to be built.
This is called after the Taskmaster has decided that the Node
@@ -742,7 +749,7 @@ class Node(metaclass=NoSlotsPyPy):
raise SCons.Errors.StopError(msg % (i, self))
self.binfo = self.get_binfo()
- def build(self, **kw):
+ def build(self, **kw) -> None:
"""Actually build the node.
This is called by the Taskmaster after it's decided that the
@@ -827,10 +834,10 @@ class Node(metaclass=NoSlotsPyPy):
"""
pass
- def add_to_waiting_s_e(self, node) -> None:
+ def add_to_waiting_s_e(self, node: Node) -> None:
self.waiting_s_e.add(node)
- def add_to_waiting_parents(self, node) -> int:
+ def add_to_waiting_parents(self, node: Node) -> int:
"""
Returns the number of nodes added to our waiting parents list:
1 if we add a unique waiting parent, 0 if not. (Note that the
@@ -867,13 +874,13 @@ class Node(metaclass=NoSlotsPyPy):
delattr(self, attr)
except AttributeError:
pass
- self.cached = 0
+ self.cached = False
self.includes = None
def clear_memoized_values(self) -> None:
self._memo = {}
- def builder_set(self, builder) -> None:
+ def builder_set(self, builder: BuilderBase | None) -> None:
self.builder = builder
try:
del self.executor
@@ -899,7 +906,7 @@ class Node(metaclass=NoSlotsPyPy):
b = self.builder = None
return b is not None
- def set_explicit(self, is_explicit) -> None:
+ def set_explicit(self, is_explicit: bool) -> None:
self.is_explicit = is_explicit
def has_explicit_builder(self) -> bool:
@@ -915,7 +922,7 @@ class Node(metaclass=NoSlotsPyPy):
self.is_explicit = False
return False
- def get_builder(self, default_builder=None):
+ def get_builder(self, default_builder: BuilderBase | None = None) -> BuilderBase | None:
"""Return the set builder, or a specified default value"""
try:
return self.builder
@@ -948,7 +955,7 @@ class Node(metaclass=NoSlotsPyPy):
return False
return True
- def check_attributes(self, name):
+ def check_attributes(self, name: str) -> Any | None:
""" Simple API to check if the node.attributes for name has been set"""
return getattr(getattr(self, "attributes", None), name, None)
@@ -958,7 +965,7 @@ class Node(metaclass=NoSlotsPyPy):
"""
return [], None
- def get_found_includes(self, env, scanner, path):
+ def get_found_includes(self, env: Environment, scanner: ScannerBase | None, path) -> list[Node]:
"""Return the scanned include lines (implicit dependencies)
found in this node.
@@ -968,7 +975,7 @@ class Node(metaclass=NoSlotsPyPy):
"""
return []
- def get_implicit_deps(self, env, initial_scanner, path_func, kw = {}):
+ def get_implicit_deps(self, env: Environment, initial_scanner: ScannerBase | None, path_func, kw = {}) -> list[Node]:
"""Return a list of implicit dependencies for this node.
This method exists to handle recursive invocation of the scanner
@@ -1003,7 +1010,7 @@ class Node(metaclass=NoSlotsPyPy):
return dependencies
- def _get_scanner(self, env, initial_scanner, root_node_scanner, kw):
+ def _get_scanner(self, env: Environment, initial_scanner: ScannerBase | None, root_node_scanner: ScannerBase | None, kw: dict[str, Any] | None) -> ScannerBase | None:
if initial_scanner:
# handle explicit scanner case
scanner = initial_scanner.select(self)
@@ -1020,13 +1027,13 @@ class Node(metaclass=NoSlotsPyPy):
return scanner
- def get_env_scanner(self, env, kw={}):
+ def get_env_scanner(self, env: Environment, kw: dict[str, Any] | None = {}) -> ScannerBase | None:
return env.get_scanner(self.scanner_key())
- def get_target_scanner(self):
+ def get_target_scanner(self) -> ScannerBase | None:
return self.builder.target_scanner
- def get_source_scanner(self, node):
+ def get_source_scanner(self, node: Node) -> ScannerBase | None:
"""Fetch the source scanner for the specified node
NOTE: "self" is the target being built, "node" is
@@ -1052,10 +1059,10 @@ class Node(metaclass=NoSlotsPyPy):
scanner = scanner.select(node)
return scanner
- def add_to_implicit(self, deps) -> None:
+ def add_to_implicit(self, deps: list[Node]) -> None:
if not hasattr(self, 'implicit') or self.implicit is None:
self.implicit = []
- self.implicit_set = set()
+ self.implicit_set: set[Node] = set()
self._children_reset()
self._add_child(self.implicit, self.implicit_set, deps)
@@ -1114,10 +1121,10 @@ class Node(metaclass=NoSlotsPyPy):
if scanner:
executor.scan_targets(scanner)
- def scanner_key(self):
+ def scanner_key(self) -> str | None:
return None
- def select_scanner(self, scanner):
+ def select_scanner(self, scanner: ScannerBase) -> ScannerBase | None:
"""Selects a scanner for this Node.
This is a separate method so it can be overridden by Node
@@ -1127,7 +1134,7 @@ class Node(metaclass=NoSlotsPyPy):
"""
return scanner.select(self)
- def env_set(self, env, safe: bool=False) -> None:
+ def env_set(self, env: Environment, safe: bool = False) -> None:
if safe and self.env:
return
self.env = env
@@ -1139,21 +1146,21 @@ class Node(metaclass=NoSlotsPyPy):
NodeInfo = NodeInfoBase
BuildInfo = BuildInfoBase
- def new_ninfo(self):
+ def new_ninfo(self) -> NodeInfoBase:
ninfo = self.NodeInfo()
return ninfo
- def get_ninfo(self):
+ def get_ninfo(self) -> NodeInfoBase:
if self.ninfo is not None:
return self.ninfo
self.ninfo = self.new_ninfo()
return self.ninfo
- def new_binfo(self):
+ def new_binfo(self) -> BuildInfoBase:
binfo = self.BuildInfo()
return binfo
- def get_binfo(self):
+ def get_binfo(self) -> BuildInfoBase:
"""
Fetch a node's build information.
@@ -1212,7 +1219,7 @@ class Node(metaclass=NoSlotsPyPy):
except AttributeError:
pass
- def get_csig(self):
+ def get_csig(self) -> str:
try:
return self.ninfo.csig
except AttributeError:
@@ -1220,13 +1227,13 @@ class Node(metaclass=NoSlotsPyPy):
ninfo.csig = hash_signature(self.get_contents())
return self.ninfo.csig
- def get_cachedir_csig(self):
+ def get_cachedir_csig(self) -> str:
return self.get_csig()
- def get_stored_info(self):
+ def get_stored_info(self) -> SConsignEntry | None:
return None
- def get_stored_implicit(self):
+ def get_stored_implicit(self) -> list[Node] | None:
"""Fetch the stored implicit dependencies"""
return None
@@ -1234,7 +1241,7 @@ class Node(metaclass=NoSlotsPyPy):
#
#
- def set_precious(self, precious: int = 1) -> None:
+ def set_precious(self, precious: bool = True) -> None:
"""Set the Node's precious value."""
self.precious = precious
@@ -1242,19 +1249,15 @@ class Node(metaclass=NoSlotsPyPy):
"""Set the Node's pseudo value."""
self.pseudo = pseudo
- def set_noclean(self, noclean: int = 1) -> None:
+ def set_noclean(self, noclean: bool = True) -> None:
"""Set the Node's noclean value."""
- # Make sure noclean is an integer so the --debug=stree
- # output in Util.py can use it as an index.
- self.noclean = noclean and 1 or 0
+ self.noclean = noclean
- def set_nocache(self, nocache: int = 1) -> None:
+ def set_nocache(self, nocache: bool = True) -> None:
"""Set the Node's nocache value."""
- # Make sure nocache is an integer so the --debug=stree
- # output in Util.py can use it as an index.
- self.nocache = nocache and 1 or 0
+ self.nocache = nocache
- def set_always_build(self, always_build: int = 1) -> None:
+ def set_always_build(self, always_build: bool = True) -> None:
"""Set the Node's always_build value."""
self.always_build = always_build
@@ -1262,12 +1265,12 @@ class Node(metaclass=NoSlotsPyPy):
"""Reports whether node exists."""
return _exists_map[self._func_exists](self)
- def rexists(self):
+ def rexists(self) -> bool:
"""Does this node exist locally or in a repository?"""
# There are no repositories by default:
return _rexists_map[self._func_rexists](self)
- def get_contents(self):
+ def get_contents(self) -> bytes | str:
"""Fetch the contents of the entry."""
return _get_contents_map[self._func_get_contents](self)
@@ -1276,11 +1279,11 @@ class Node(metaclass=NoSlotsPyPy):
not self.linked and \
not self.rexists()
- def remove(self):
+ def remove(self) -> None:
"""Remove this Node: no-op by default."""
return None
- def add_dependency(self, depend):
+ def add_dependency(self, depend: list[Node]) -> None:
"""Adds dependencies."""
try:
self._add_child(self.depends, self.depends_set, depend)
@@ -1292,14 +1295,14 @@ class Node(metaclass=NoSlotsPyPy):
s = str(e)
raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
- def add_prerequisite(self, prerequisite) -> None:
+ def add_prerequisite(self, prerequisite: list[Node]) -> None:
"""Adds prerequisites"""
if self.prerequisites is None:
self.prerequisites = UniqueList()
self.prerequisites.extend(prerequisite)
self._children_reset()
- def add_ignore(self, depend):
+ def add_ignore(self, depend: list[Node]) -> None:
"""Adds dependencies to ignore."""
try:
self._add_child(self.ignore, self.ignore_set, depend)
@@ -1311,7 +1314,7 @@ class Node(metaclass=NoSlotsPyPy):
s = str(e)
raise SCons.Errors.UserError("attempted to ignore a non-Node dependency of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
- def add_source(self, source):
+ def add_source(self, source: list[Node]) -> None:
"""Adds sources."""
if self._specific_sources:
return
@@ -1325,7 +1328,7 @@ class Node(metaclass=NoSlotsPyPy):
s = str(e)
raise SCons.Errors.UserError("attempted to add a non-Node as source of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
- def _add_child(self, collection, set, child) -> None:
+ def _add_child(self, collection: list[Node], set: set[Node], child: list[Node]) -> None:
"""Adds 'child' to 'collection', first checking 'set' to see if it's
already present."""
added = None
@@ -1337,11 +1340,11 @@ class Node(metaclass=NoSlotsPyPy):
if added:
self._children_reset()
- def set_specific_source(self, source) -> None:
+ def set_specific_source(self, source: list[Node]) -> None:
self.add_source(source)
self._specific_sources = True
- def add_wkid(self, wkid) -> None:
+ def add_wkid(self, wkid: Node) -> None:
"""Add a node to the list of kids waiting to be evaluated"""
if self.wkids is not None:
self.wkids.append(wkid)
@@ -1353,7 +1356,7 @@ class Node(metaclass=NoSlotsPyPy):
self.executor_cleanup()
@SCons.Memoize.CountMethodCall
- def _children_get(self):
+ def _children_get(self) -> list[Node]:
try:
return self._memo['_children_get']
except KeyError:
@@ -1384,12 +1387,12 @@ class Node(metaclass=NoSlotsPyPy):
if i not in self.ignore_set:
children.append(i)
else:
- children = self.all_children(scan=0)
+ children = self.all_children(scan=False)
self._memo['_children_get'] = children
return children
- def all_children(self, scan: int=1):
+ def all_children(self, scan: bool = True) -> list[Node]:
"""Return a list of all the node's direct children."""
if scan:
self.scan()
@@ -1413,27 +1416,27 @@ class Node(metaclass=NoSlotsPyPy):
# internally anyway...)
return list(chain.from_iterable([_f for _f in [self.sources, self.depends, self.implicit] if _f]))
- def children(self, scan: int=1):
+ def children(self, scan: bool = True) -> list[Node]:
"""Return a list of the node's direct children, minus those
that are ignored by this node."""
if scan:
self.scan()
return self._children_get()
- def set_state(self, state) -> None:
+ def set_state(self, state: int) -> None:
self.state = state
- def get_state(self):
+ def get_state(self) -> int:
return self.state
- def get_env(self):
+ def get_env(self) -> Environment:
env = self.env
if not env:
import SCons.Defaults
env = SCons.Defaults.DefaultEnvironment()
return env
- def Decider(self, function) -> None:
+ def Decider(self, function: Callable[[Node, Node, NodeInfoBase, Node | None], bool]) -> None:
foundkey = None
for k, v in _decider_map.items():
if v == function:
@@ -1444,19 +1447,19 @@ class Node(metaclass=NoSlotsPyPy):
_decider_map[foundkey] = function
self.changed_since_last_build = foundkey
- def Tag(self, key, value) -> None:
+ def Tag(self, key: str, value: Any | None) -> None:
""" Add a user-defined tag. """
if not self._tags:
self._tags = {}
self._tags[key] = value
- def GetTag(self, key):
+ def GetTag(self, key: str) -> Any | None:
""" Return a user-defined tag. """
if not self._tags:
return None
return self._tags.get(key, None)
- def changed(self, node=None, allowcache: bool=False):
+ def changed(self, node: Node | None = None, allowcache: bool = False) -> bool:
"""
Returns if the node is up-to-date with respect to the BuildInfo
stored last time it was built. The default behavior is to compare
@@ -1535,7 +1538,7 @@ class Node(metaclass=NoSlotsPyPy):
if self.always_build:
return False
state = 0
- for kid in self.children(None):
+ for kid in self.children(False):
s = kid.get_state()
if s and (not state or s > state):
state = s
@@ -1560,13 +1563,13 @@ class Node(metaclass=NoSlotsPyPy):
path = self.get_build_scanner_path(scanner)
else:
path = None
- def f(node, env=env, scanner=scanner, path=path):
+ def f(node: Node, env: Environment = env, scanner: ScannerBase = scanner, path=path):
return node.get_found_includes(env, scanner, path)
return render_tree(s, f, 1)
else:
return None
- def get_abspath(self):
+ def get_abspath(self) -> str:
"""
Return an absolute path to the Node. This will return simply
str(Node) by default, but for Node types that have a concept of
@@ -1574,7 +1577,7 @@ class Node(metaclass=NoSlotsPyPy):
"""
return str(self)
- def for_signature(self):
+ def for_signature(self) -> str:
"""
Return a string representation of the Node that will always
be the same for this particular Node, no matter what. This
@@ -1589,7 +1592,7 @@ class Node(metaclass=NoSlotsPyPy):
"""
return str(self)
- def get_string(self, for_signature):
+ def get_string(self, for_signature: bool) -> str:
"""This is a convenience function designed primarily to be
used in command generators (i.e., CommandGeneratorActions or
Environment variables that are callable), which are called
@@ -1720,9 +1723,9 @@ class NodeList(collections.UserList):
def __str__(self) -> str:
return str(list(map(str, self.data)))
-def get_children(node, parent): return node.children()
-def ignore_cycle(node, stack) -> None: pass
-def do_nothing(node, parent) -> None: pass
+def get_children(node: Node, parent: Node | None) -> list[Node]: return node.children()
+def ignore_cycle(node: Node, stack: list[Node]) -> None: pass
+def do_nothing(node: Node, parent: Node | None) -> None: pass
class Walker:
"""An iterator for walking a Node tree.
@@ -1737,15 +1740,19 @@ class Walker:
This class does not get caught in node cycles caused, for example,
by C header file include loops.
"""
- def __init__(self, node, kids_func=get_children,
- cycle_func=ignore_cycle,
- eval_func=do_nothing) -> None:
+ def __init__(
+ self,
+ node: Node,
+ kids_func: Callable[[Node, Node | None], list[Node]] = get_children,
+ cycle_func: Callable[[Node, list[Node]], None] = ignore_cycle,
+ eval_func: Callable[[Node, Node | None], None] = do_nothing,
+ ) -> None:
self.kids_func = kids_func
self.cycle_func = cycle_func
self.eval_func = eval_func
node.wkids = copy.copy(kids_func(node, None))
self.stack = [node]
- self.history = {} # used to efficiently detect and avoid cycles
+ self.history: dict[Node, Any | None] = {} # used to efficiently detect and avoid cycles
self.history[node] = None
def get_next(self):