diff options
author | Thaddeus Crews <repiteo@outlook.com> | 2024-04-14 18:11:47 (GMT) |
---|---|---|
committer | Thaddeus Crews <repiteo@outlook.com> | 2024-07-09 16:23:26 (GMT) |
commit | 187bf05b1631ff2e2359ce2bc5875854f9082258 (patch) | |
tree | 2beaac20a27430382b1f331a424e5859f01d35d0 | |
parent | 3b10709c1a5486d3e018effd27d85e55807afc56 (diff) | |
download | SCons-187bf05b1631ff2e2359ce2bc5875854f9082258.zip SCons-187bf05b1631ff2e2359ce2bc5875854f9082258.tar.gz SCons-187bf05b1631ff2e2359ce2bc5875854f9082258.tar.bz2 |
Implement somewhat pythonic type hints in sctypes
-rw-r--r-- | CHANGES.txt | 8 | ||||
-rw-r--r-- | RELEASE.txt | 6 | ||||
-rw-r--r-- | SCons/Util/sctypes.py | 38 |
3 files changed, 42 insertions, 10 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 390a0d5..dea43b8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -12,9 +12,11 @@ NOTE: Python 3.6 support is deprecated and will be dropped in a future release. RELEASE VERSION/DATE TO BE FILLED IN LATER - From John Doe: - - - Whatever John Doe did. + From Thaddeus Crews: + - Add explicit return types to sctypes `is_*` functions. For Python <=3.9, + the return type is simply `bool`, same as before. Python 3.10 and later + will benefit from `TypeGuard`/`TypeIs`, to produce intellisense similar + to using `isinstance` directly. RELEASE 4.8.0 - Sun, 07 Jul 2024 17:22:20 -0700 diff --git a/RELEASE.txt b/RELEASE.txt index 1797698..5845e56 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -56,7 +56,11 @@ DOCUMENTATION DEVELOPMENT ----------- -- List visible changes in the way SCons is developed +- sctypes `is_*` functions given explicit return types. Python 3.13+ uses + `TypeIs` for a near-equivalent of `isinstance`. Python 3.10 through 3.12 + uses `TypeGuard`, a less accurate implementation but still provides + usable type hinting. Python 3.9 and earlier simply returns `bool`, same + as before. Thanks to the following contributors listed below for their contributions to this release. ========================================================================================== diff --git a/SCons/Util/sctypes.py b/SCons/Util/sctypes.py index bcbefb6..765458e 100644 --- a/SCons/Util/sctypes.py +++ b/SCons/Util/sctypes.py @@ -11,7 +11,8 @@ import codecs import os import pprint import re -from typing import Optional +import sys +from typing import Optional, Union from collections import UserDict, UserList, UserString, deque from collections.abc import MappingView, Iterable @@ -50,38 +51,63 @@ StringTypes = (str, UserString) # Empirically, it is faster to check explicitly for str than for basestring. BaseStringTypes = str +# Later Python versions allow us to explicitly apply type hints based off the +# return value similar to isinstance(), albeit not as precise. +if sys.version_info >= (3, 13): + from typing import TypeAlias, TypeIs + + DictTypeRet: TypeAlias = TypeIs[Union[dict, UserDict]] + ListTypeRet: TypeAlias = TypeIs[Union[list, UserList, deque]] + SequenceTypeRet: TypeAlias = TypeIs[Union[list, tuple, deque, UserList, MappingView]] + TupleTypeRet: TypeAlias = TypeIs[tuple] + StringTypeRet: TypeAlias = TypeIs[Union[str, UserString]] +elif sys.version_info >= (3, 10): + from typing import TypeAlias, TypeGuard + + DictTypeRet: TypeAlias = TypeGuard[Union[dict, UserDict]] + ListTypeRet: TypeAlias = TypeGuard[Union[list, UserList, deque]] + SequenceTypeRet: TypeAlias = TypeGuard[Union[list, tuple, deque, UserList, MappingView]] + TupleTypeRet: TypeAlias = TypeGuard[tuple] + StringTypeRet: TypeAlias = TypeGuard[Union[str, UserString]] +else: + DictTypeRet = Union[bool, bool] + ListTypeRet = Union[bool, bool] + SequenceTypeRet = Union[bool, bool] + TupleTypeRet = Union[bool, bool] + StringTypeRet = Union[bool, bool] + def is_Dict( # pylint: disable=redefined-outer-name,redefined-builtin obj, isinstance=isinstance, DictTypes=DictTypes -) -> bool: +) -> DictTypeRet: """Check if object is a dict.""" return isinstance(obj, DictTypes) def is_List( # pylint: disable=redefined-outer-name,redefined-builtin obj, isinstance=isinstance, ListTypes=ListTypes -) -> bool: +) -> ListTypeRet: """Check if object is a list.""" return isinstance(obj, ListTypes) def is_Sequence( # pylint: disable=redefined-outer-name,redefined-builtin obj, isinstance=isinstance, SequenceTypes=SequenceTypes -) -> bool: +) -> SequenceTypeRet: """Check if object is a sequence.""" return isinstance(obj, SequenceTypes) def is_Tuple( # pylint: disable=redefined-builtin obj, isinstance=isinstance, tuple=tuple -) -> bool: +) -> TupleTypeRet: """Check if object is a tuple.""" return isinstance(obj, tuple) def is_String( # pylint: disable=redefined-outer-name,redefined-builtin obj, isinstance=isinstance, StringTypes=StringTypes -) -> bool: +) -> StringTypeRet: """Check if object is a string.""" return isinstance(obj, StringTypes) |