From 0d523a9a751d53bf1b9450d33c81c5699a8b8773 Mon Sep 17 00:00:00 2001
From: Chris Mahoney <44449504+chrimaho@users.noreply.github.com>
Date: Sat, 3 Jan 2026 08:53:04 +1100
Subject: [PATCH 1/7] Standardise type hints and simplify overloads - Replace
custom type aliases from the `toolbox_python.collection_types` module with
standard library types like `list[str]`, `Collection[Any]`, and `Dict[Any,
Any]`. - Simplify `is_value_of_type()` and `assert_value_of_type()` function
overloads by using `Collection[type]` to handle multiple input sequences. -
Relocate the `log_levels` type literal to `output.py` module to better align
with its usage in output formatting. - Add explicit `Callable` type hints to
function aliases within the `checkers.py` module for improved type clarity. -
Update the `Defaults()` class docstring to include a dedicated methods
section documenting the `.get()` method. - Refactor the `flatten()` function
and the `list_columns()` function to use standard collection types and remove
redundant `@overload` definitions. - Improve type checking logic in the
`checkers.py` module to handle generic collections of types more robustly.
---
src/toolbox_python/bools.py | 11 +-
src/toolbox_python/checkers.py | 217 +++++++++----------------
src/toolbox_python/collection_types.py | 15 +-
src/toolbox_python/defaults.py | 10 +-
src/toolbox_python/dictionaries.py | 16 +-
src/toolbox_python/generators.py | 3 +-
src/toolbox_python/lists.py | 26 ++-
src/toolbox_python/output.py | 60 +++----
src/toolbox_python/retry.py | 9 +-
src/toolbox_python/strings.py | 22 +--
10 files changed, 151 insertions(+), 238 deletions(-)
diff --git a/src/toolbox_python/bools.py b/src/toolbox_python/bools.py
index b81d229..9a8bd43 100644
--- a/src/toolbox_python/bools.py
+++ b/src/toolbox_python/bools.py
@@ -33,21 +33,12 @@
# ---------------------------------------------------------------------------- #
-# ---------------------------------------------------------------------------- #
-# Imports ####
-# ---------------------------------------------------------------------------- #
-
-
-# ## Local First Party Imports ----
-from toolbox_python.collection_types import str_list
-
-
# ---------------------------------------------------------------------------- #
# Exports ####
# ---------------------------------------------------------------------------- #
-__all__: str_list = ["strtobool", "STR_TO_BOOL_MAP"]
+__all__: list[str] = ["strtobool", "STR_TO_BOOL_MAP"]
# ---------------------------------------------------------------------------- #
diff --git a/src/toolbox_python/checkers.py b/src/toolbox_python/checkers.py
index 70451c1..c73c642 100644
--- a/src/toolbox_python/checkers.py
+++ b/src/toolbox_python/checkers.py
@@ -38,26 +38,19 @@
# ## Python StdLib Imports ----
import operator
+from collections.abc import Collection
from typing import Any, Callable, Union, overload
# ## Python Third Party Imports ----
from typeguard import typechecked
-# ## Local First Party Imports ----
-from toolbox_python.collection_types import (
- any_collection,
- scalar,
- str_collection,
- str_list,
-)
-
## --------------------------------------------------------------------------- #
## Exports ####
## --------------------------------------------------------------------------- #
-__all__: str_list = [
+__all__: list[str] = [
"OPERATORS",
"is_value_of_type",
"is_all_values_of_type",
@@ -130,10 +123,8 @@
@overload
def is_value_of_type(value: Any, check_type: type) -> bool: ...
@overload
-def is_value_of_type(value: Any, check_type: tuple[type, ...]) -> bool: ...
-@overload
-def is_value_of_type(value: Any, check_type: list[type]) -> bool: ...
-def is_value_of_type(value: Any, check_type: Union[type, tuple[type, ...], list[type]]) -> bool:
+def is_value_of_type(value: Any, check_type: Collection[type]) -> bool: ...
+def is_value_of_type(value: Any, check_type: Union[type, Collection[type]]) -> bool:
"""
!!! note "Summary"
Check if a given value is of a specified type or types.
@@ -144,8 +135,8 @@ def is_value_of_type(value: Any, check_type: Union[type, tuple[type, ...], list[
Params:
value (Any):
The value to check.
- check_type (Union[type, tuple[type, ...], list[type]]):
- The type or tuple of types to check against.
+ check_type (Union[type, Collection[type]]):
+ The type or Sequence of types to check against.
Returns:
(bool):
@@ -185,20 +176,15 @@ def is_value_of_type(value: Any, check_type: Union[type, tuple[type, ...], list[
- [`is_value_of_type()`][toolbox_python.checkers.is_value_of_type]
- [`is_type()`][toolbox_python.checkers.is_type]
"""
- check_type = tuple(check_type) if isinstance(check_type, list) else check_type
+ check_type = tuple(check_type) if not isinstance(check_type, type) else check_type
return isinstance(value, check_type)
@overload
-def is_all_values_of_type(values: any_collection, check_type: type) -> bool: ...
+def is_all_values_of_type(values: Collection[Any], check_type: type) -> bool: ...
@overload
-def is_all_values_of_type(values: any_collection, check_type: tuple[type, ...]) -> bool: ...
-@overload
-def is_all_values_of_type(values: any_collection, check_type: list[type]) -> bool: ...
-def is_all_values_of_type(
- values: any_collection,
- check_type: Union[type, tuple[type, ...], list[type]],
-) -> bool:
+def is_all_values_of_type(values: Collection[Any], check_type: Collection[type]) -> bool: ...
+def is_all_values_of_type(values: Collection[Any], check_type: Union[type, Collection[type]]) -> bool:
"""
!!! note "Summary"
Check if all values in an iterable are of a specified type or types.
@@ -207,10 +193,10 @@ def is_all_values_of_type(
This function is used to verify if all values in a given iterable match a specified type or any of the types in a tuple of types.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- check_type (Union[type, tuple[type, ...], list[type]]):
- The type or tuple of types to check against.
+ check_type (Union[type, Collection[type]]):
+ The type or Sequence of types to check against.
Returns:
(bool):
@@ -252,20 +238,15 @@ def is_all_values_of_type(
- [`is_type()`][toolbox_python.checkers.is_type]
- [`is_all_type()`][toolbox_python.checkers.is_all_type]
"""
- check_type = tuple(check_type) if isinstance(check_type, list) else check_type
+ check_type = tuple(check_type) if not isinstance(check_type, type) else check_type
return all(isinstance(value, check_type) for value in values)
@overload
-def is_any_values_of_type(values: any_collection, check_type: type) -> bool: ...
-@overload
-def is_any_values_of_type(values: any_collection, check_type: tuple[type, ...]) -> bool: ...
+def is_any_values_of_type(values: Collection[Any], check_type: type) -> bool: ...
@overload
-def is_any_values_of_type(values: any_collection, check_type: list[type]) -> bool: ...
-def is_any_values_of_type(
- values: any_collection,
- check_type: Union[type, tuple[type, ...], list[type]],
-) -> bool:
+def is_any_values_of_type(values: Collection[Any], check_type: Collection[type]) -> bool: ...
+def is_any_values_of_type(values: Collection[Any], check_type: Union[type, Collection[type]]) -> bool:
"""
!!! note "Summary"
Check if any value in an iterable is of a specified type or types.
@@ -274,10 +255,10 @@ def is_any_values_of_type(
This function is used to verify if any value in a given iterable matches a specified type or any of the types in a tuple of types.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- check_type (Union[type, tuple[type, ...], list[type]]):
- The type or tuple of types to check against.
+ check_type (Union[type, Collection[type]]):
+ The type or Sequence of types to check against.
Returns:
(bool):
@@ -319,15 +300,12 @@ def is_any_values_of_type(
- [`is_type()`][toolbox_python.checkers.is_type]
- [`is_any_type()`][toolbox_python.checkers.is_any_type]
"""
- check_type = tuple(check_type) if isinstance(check_type, list) else check_type
+ check_type = tuple(check_type) if not isinstance(check_type, type) else check_type
return any(isinstance(value, check_type) for value in values)
@typechecked
-def is_value_in_iterable(
- value: scalar,
- iterable: any_collection,
-) -> bool:
+def is_value_in_iterable(value: Any, iterable: Collection[Any]) -> bool:
"""
!!! note "Summary"
Check if a given value is present in an iterable.
@@ -336,9 +314,9 @@ def is_value_in_iterable(
This function is used to verify if a given value exists within an iterable such as a list, tuple, or set.
Params:
- value (scalar):
+ value (Any):
The value to check.
- iterable (any_collection):
+ iterable (Collection[Any]):
The iterable to check within.
Raises:
@@ -387,10 +365,7 @@ def is_value_in_iterable(
@typechecked
-def is_all_values_in_iterable(
- values: any_collection,
- iterable: any_collection,
-) -> bool:
+def is_all_values_in_iterable(values: Collection[Any], iterable: Collection[Any]) -> bool:
"""
!!! note "Summary"
Check if all values in an iterable are present in another iterable.
@@ -399,9 +374,9 @@ def is_all_values_in_iterable(
This function is used to verify if all values in a given iterable exist within another iterable.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- iterable (any_collection):
+ iterable (Collection[Any]):
The iterable to check within.
Raises:
@@ -452,10 +427,7 @@ def is_all_values_in_iterable(
@typechecked
-def is_any_values_in_iterable(
- values: any_collection,
- iterable: any_collection,
-) -> bool:
+def is_any_values_in_iterable(values: Collection[Any], iterable: Collection[Any]) -> bool:
"""
!!! note "Summary"
Check if any value in an iterable is present in another iterable.
@@ -464,9 +436,9 @@ def is_any_values_in_iterable(
This function is used to verify if any value in a given iterable exists within another iterable.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- iterable (any_collection):
+ iterable (Collection[Any]):
The iterable to check within.
Raises:
@@ -575,13 +547,13 @@ def is_valid_value(value: Any, op: str, target: Any) -> bool:
### Aliases ----
-is_type = is_value_of_type
-is_all_type = is_all_values_of_type
-is_any_type = is_any_values_of_type
-is_in = is_value_in_iterable
-is_any_in = is_any_values_in_iterable
-is_all_in = is_all_values_in_iterable
-is_valid = is_valid_value
+is_type: Callable[..., bool] = is_value_of_type
+is_all_type: Callable[..., bool] = is_all_values_of_type
+is_any_type: Callable[..., bool] = is_any_values_of_type
+is_in: Callable[..., bool] = is_value_in_iterable
+is_any_in: Callable[..., bool] = is_any_values_in_iterable
+is_all_in: Callable[..., bool] = is_all_values_in_iterable
+is_valid: Callable[..., bool] = is_valid_value
## --------------------------------------------------------------------------- #
@@ -592,13 +564,8 @@ def is_valid_value(value: Any, op: str, target: Any) -> bool:
@overload
def assert_value_of_type(value: Any, check_type: type) -> None: ...
@overload
-def assert_value_of_type(value: Any, check_type: tuple[type, ...]) -> None: ...
-@overload
-def assert_value_of_type(value: Any, check_type: list[type]) -> None: ...
-def assert_value_of_type(
- value: Any,
- check_type: Union[type, tuple[type, ...], list[type]],
-) -> None:
+def assert_value_of_type(value: Any, check_type: Collection[type]) -> None: ...
+def assert_value_of_type(value: Any, check_type: Union[type, Collection[type]]) -> None:
"""
!!! note "Summary"
Assert that a given value is of a specified type or types.
@@ -609,7 +576,7 @@ def assert_value_of_type(
Params:
value (Any):
The value to check.
- check_type (Union[type, tuple[type, ...], list[type]]):
+ check_type (Union[type, Collection[type]]):
The type or tuple of types to check against.
Raises:
@@ -684,15 +651,10 @@ def assert_value_of_type(
@overload
-def assert_all_values_of_type(values: any_collection, check_type: type) -> None: ...
+def assert_all_values_of_type(values: Collection[Any], check_type: type) -> None: ...
@overload
-def assert_all_values_of_type(values: any_collection, check_type: tuple[type, ...]) -> None: ...
-@overload
-def assert_all_values_of_type(values: any_collection, check_type: list[type]) -> None: ...
-def assert_all_values_of_type(
- values: any_collection,
- check_type: Union[type, tuple[type, ...], list[type]],
-) -> None:
+def assert_all_values_of_type(values: Collection[Any], check_type: Collection[type]) -> None: ...
+def assert_all_values_of_type(values: Collection[Any], check_type: Union[type, Collection[type]]) -> None:
"""
!!! note "Summary"
Assert that all values in an iterable are of a specified type or types.
@@ -701,9 +663,9 @@ def assert_all_values_of_type(
This function is used to assert that all values in a given iterable match a specified type or any of the types in a tuple of types. If any value does not match the specified type(s), a `#!py TypeError` is raised.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- check_type (Union[type, tuple[type, ...], list[type]]):
+ check_type (Union[type, Collection[type]]):
The type or tuple of types to check against.
Raises:
@@ -771,27 +733,22 @@ def assert_all_values_of_type(
- [`is_all_type()`][toolbox_python.checkers.is_all_type]
"""
if not is_all_type(values=values, check_type=check_type):
- invalid_values = [value for value in values if not is_type(value, check_type)]
- invalid_types = [f"'{type(value).__name__}'" for value in values if not is_type(value, check_type)]
+ invalid_values: list[Any] = [value for value in values if not is_type(value, check_type)]
+ invalid_types: list[str] = [f"'{type(value).__name__}'" for value in values if not is_type(value, check_type)]
msg: str = f"Some elements {invalid_values} have the incorrect type {invalid_types}. "
if isinstance(check_type, type):
msg += f"Must be '{check_type}'"
else:
- types: str_list = [f"'{typ.__name__}'" for typ in check_type]
+ types: list[str] = [f"'{typ.__name__}'" for typ in check_type]
msg += f"Must be: {' or '.join(types)}"
raise TypeError(msg)
@overload
-def assert_any_values_of_type(values: any_collection, check_type: type) -> None: ...
-@overload
-def assert_any_values_of_type(values: any_collection, check_type: tuple[type, ...]) -> None: ...
+def assert_any_values_of_type(values: Collection[Any], check_type: type) -> None: ...
@overload
-def assert_any_values_of_type(values: any_collection, check_type: list[type]) -> None: ...
-def assert_any_values_of_type(
- values: any_collection,
- check_type: Union[type, tuple[type, ...], list[type]],
-) -> None:
+def assert_any_values_of_type(values: Collection[Any], check_type: Collection[type]) -> None: ...
+def assert_any_values_of_type(values: Collection[Any], check_type: Union[type, Collection[type]]) -> None:
"""
!!! note "Summary"
Assert that any value in an iterable is of a specified type or types.
@@ -800,9 +757,9 @@ def assert_any_values_of_type(
This function is used to assert that at least one value in a given iterable matches a specified type or any of the types in a tuple of types. If none of the values match the specified type(s), a `#!py TypeError` is raised.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- check_type (Union[type, tuple[type, ...], list[type]]):
+ check_type (Union[type, Collection[type]]):
The type or tuple of types to check against.
Raises:
@@ -870,20 +827,17 @@ def assert_any_values_of_type(
- [`is_any_type()`][toolbox_python.checkers.is_any_type]
"""
if not is_any_type(values=values, check_type=check_type):
- invalid_values = [value for value in values if not is_type(value, check_type)]
+ invalid_values: list[Any] = [value for value in values if not is_type(value, check_type)]
msg: str = f"None of the elements in {invalid_values} have the correct type. "
if isinstance(check_type, type):
msg += f"Must be: '{check_type.__name__}'"
else:
- types: str_list = [f"'{typ.__name__}'" for typ in check_type]
+ types: list[str] = [f"'{typ.__name__}'" for typ in check_type]
msg += f"Must be: {' or '.join(types)}"
raise TypeError(msg)
-def assert_value_in_iterable(
- value: scalar,
- iterable: any_collection,
-) -> None:
+def assert_value_in_iterable(value: Any, iterable: Collection[Any]) -> None:
"""
!!! note "Summary"
Assert that a given value is present in an iterable.
@@ -892,9 +846,9 @@ def assert_value_in_iterable(
This function is used to assert that a given value exists within an iterable such as a `#!py list`, `#!py tuple`, or `#!py set`. If the value is not found in the iterable, a `#!py LookupError` is raised.
Params:
- value (scalar):
+ value (Any):
The value to check.
- iterable (any_collection):
+ iterable (Collection[Any]):
The iterable to check within.
Raises:
@@ -943,10 +897,7 @@ def assert_value_in_iterable(
raise LookupError(f"Value '{value}' not found in iterable: {iterable}")
-def assert_any_values_in_iterable(
- values: any_collection,
- iterable: any_collection,
-) -> None:
+def assert_any_values_in_iterable(values: Collection[Any], iterable: Collection[Any]) -> None:
"""
!!! note "Summary"
Assert that any value in an iterable is present in another iterable.
@@ -955,9 +906,9 @@ def assert_any_values_in_iterable(
This function is used to assert that at least one value in a given iterable exists within another iterable. If none of the values are found in the iterable, a `#!py LookupError` is raised.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- iterable (any_collection):
+ iterable (Collection[Any]):
The iterable to check within.
Raises:
@@ -1008,10 +959,7 @@ def assert_any_values_in_iterable(
raise LookupError(f"None of the values in {values} can be found in {iterable}")
-def assert_all_values_in_iterable(
- values: any_collection,
- iterable: any_collection,
-) -> None:
+def assert_all_values_in_iterable(values: Collection[Any], iterable: Collection[Any]) -> None:
"""
!!! note "Summary"
Assert that all values in an iterable are present in another iterable.
@@ -1020,9 +968,9 @@ def assert_all_values_in_iterable(
This function is used to assert that all values in a given iterable exist within another iterable. If any value is not found in the iterable, a `#!py LookupError` is raised.
Params:
- values (any_collection):
+ values (Collection[Any]):
The iterable containing values to check.
- iterable (any_collection):
+ iterable (Collection[Any]):
The iterable to check within.
Raises:
@@ -1070,7 +1018,7 @@ def assert_all_values_in_iterable(
- [`is_all_in()`][toolbox_python.checkers.is_all_in]
"""
if not is_all_in(values=values, iterable=iterable):
- missing_values = [value for value in values if not is_in(value, iterable)]
+ missing_values: list[Any] = [value for value in values if not is_in(value, iterable)]
raise LookupError(f"Some values {missing_values} are missing from {iterable}")
@@ -1131,16 +1079,16 @@ def assert_is_valid_value(value: Any, op: str, target: Any) -> None:
### Aliases ----
-assert_type = assert_value_of_type
-assert_is_type = assert_value_of_type
-assert_all_type = assert_all_values_of_type
-assert_all_is_type = assert_all_values_of_type
-assert_any_type = assert_any_values_of_type
-assert_any_is_type = assert_any_values_of_type
-assert_in = assert_value_in_iterable
-assert_any_in = assert_any_values_in_iterable
-assert_all_in = assert_all_values_in_iterable
-assert_is_valid = assert_is_valid_value
+assert_type: Callable[..., None] = assert_value_of_type
+assert_is_type: Callable[..., None] = assert_value_of_type
+assert_all_type: Callable[..., None] = assert_all_values_of_type
+assert_all_is_type: Callable[..., None] = assert_all_values_of_type
+assert_any_type: Callable[..., None] = assert_any_values_of_type
+assert_any_is_type: Callable[..., None] = assert_any_values_of_type
+assert_in: Callable[..., None] = assert_value_in_iterable
+assert_any_in: Callable[..., None] = assert_any_values_in_iterable
+assert_all_in: Callable[..., None] = assert_all_values_in_iterable
+assert_is_valid: Callable[..., None] = assert_is_valid_value
## --------------------------------------------------------------------------- #
@@ -1149,10 +1097,7 @@ def assert_is_valid_value(value: Any, op: str, target: Any) -> None:
@typechecked
-def any_element_contains(
- iterable: str_collection,
- check: str,
-) -> bool:
+def any_element_contains(iterable: Collection[str], check: str) -> bool:
"""
!!! note "Summary"
Check to see if any element in a given iterable contains a given string value.
@@ -1162,7 +1107,7 @@ def any_element_contains(
This function is helpful for doing a quick check to see if any element in a `#!py list` contains a given `#!py str` value. For example, checking if any column header contains a specific string value.
Params:
- iterable (str_collection):
+ iterable (Collection[str]):
The iterables to check within. Because this function uses an `#!py in` operation to check if `check` string exists in the elements of `iterable`, therefore all elements of `iterable` must be `#!py str` type.
check (str):
The string value to check exists in any of the elements in `iterable`.
@@ -1209,7 +1154,7 @@ def any_element_contains(
@typechecked
-def all_elements_contains(iterable: str_collection, check: str) -> bool:
+def all_elements_contains(iterable: Collection[str], check: str) -> bool:
"""
!!! note "Summary"
Check to see if all elements in a given iterable contains a given string value.
@@ -1219,7 +1164,7 @@ def all_elements_contains(iterable: str_collection, check: str) -> bool:
This function is helpful for doing a quick check to see if all element in a `#!py list` contains a given `#!py str` value. For example, checking if all columns in a DataFrame contains a specific string value.
Params:
- iterable (str_collection):
+ iterable (Collection[str]):
The iterables to check within. Because this function uses an `#!py in` operation to check if `check` string exists in the elements of `iterable`, therefore all elements of `iterable` must be `#!py str` type.
check (str):
The string value to check exists in any of the elements in `iterable`.
@@ -1266,14 +1211,14 @@ def all_elements_contains(iterable: str_collection, check: str) -> bool:
@typechecked
-def get_elements_containing(iterable: str_collection, check: str) -> tuple[str, ...]:
+def get_elements_containing(iterable: Collection[str], check: str) -> tuple[str, ...]:
"""
!!! note "Summary"
Extract all elements in a given iterable which contains a given string value.
!!! warning "Note: This check _is_ case sensitive."
Params:
- iterable (str_collection):
+ iterable (Collection[str]):
The iterables to check within. Because this function uses an `#!py in` operation to check if `check` string exists in the elements of `iterable`, therefore all elements of `iterable` must be `#!py str` type.
check (str):
The string value to check exists in any of the elements in `iterable`.
diff --git a/src/toolbox_python/collection_types.py b/src/toolbox_python/collection_types.py
index 60977d4..4cb63e5 100644
--- a/src/toolbox_python/collection_types.py
+++ b/src/toolbox_python/collection_types.py
@@ -20,7 +20,7 @@
# ## Python StdLib Imports ----
from datetime import datetime
-from typing import Any, Literal, Union
+from typing import Any, Union
## --------------------------------------------------------------------------- #
@@ -40,7 +40,6 @@
"int_list",
"int_tuple",
"iterable",
- "log_levels",
"scalar",
"str_collection",
"str_dict",
@@ -128,15 +127,3 @@
]
```
"""
-
-
-log_levels = Literal["debug", "info", "warning", "error", "critical"]
-"""
-!!! note "Summary"
- To streamline other functions, this `type` alias is created for all of the `log` levels available.
-!!! abstract "Details"
- The structure of the `type` is as follows:
- ```pycon {.py .python linenums="1" title="Type structure"}
- Literal["debug", "info", "warning", "error", "critical"]
- ```
-"""
diff --git a/src/toolbox_python/defaults.py b/src/toolbox_python/defaults.py
index 8172401..bf4b892 100644
--- a/src/toolbox_python/defaults.py
+++ b/src/toolbox_python/defaults.py
@@ -48,7 +48,6 @@
# ## Local First Party Imports ----
from toolbox_python.bools import strtobool
from toolbox_python.checkers import is_type
-from toolbox_python.collection_types import str_list
# ---------------------------------------------------------------------------- #
@@ -56,7 +55,7 @@
# ---------------------------------------------------------------------------- #
-__all__: str_list = ["defaults", "Defaults"]
+__all__: list[str] = ["defaults", "Defaults"]
# ---------------------------------------------------------------------------- #
@@ -77,6 +76,11 @@ class Defaults:
When we create and use Python variables, it is sometimes handy to add a default value for that variable.
This class will handle that process.
+ Methods:
+ - get(): From the value that is parsed in to the `value` parameter, convert it to `default` if `value` is `#!py None`, and convert it to `cast` if `cast` is not `#!py None`.
+ - _validate_value_and_default(): Validate to ensure that `value` and `default` are not both `#!py None`.
+ - _validate_type(): Check to ensure that `check_type` is a valid Python type
+
???+ example "Examples"
```pycon {.py .python linenums="1" title="Set up data for examples"}
@@ -396,7 +400,7 @@ def _validate_type(
??? tip "See Also"
- [`Defaults.get()`][toolbox_python.defaults.Defaults.get]
"""
- valid_types: str_list = [
+ valid_types: list[str] = [
"bool",
"dict",
"int",
diff --git a/src/toolbox_python/dictionaries.py b/src/toolbox_python/dictionaries.py
index bdd4a43..b3e02e5 100644
--- a/src/toolbox_python/dictionaries.py
+++ b/src/toolbox_python/dictionaries.py
@@ -44,15 +44,13 @@
# ## Python Third Party Imports ----
from typeguard import typechecked
-# ## Local First Party Imports ----
-from toolbox_python.collection_types import dict_any, dict_str_any, str_list
-
# ---------------------------------------------------------------------------- #
# Exports ####
# ---------------------------------------------------------------------------- #
-__all__: str_list = ["dict_reverse_keys_and_values", "DotDict"]
+
+__all__: list[str] = ["dict_reverse_keys_and_values", "DotDict"]
# ---------------------------------------------------------------------------- #
@@ -63,7 +61,7 @@
@typechecked
-def dict_reverse_keys_and_values(dictionary: dict_any) -> dict_str_any:
+def dict_reverse_keys_and_values(dictionary: dict[Any, Any]) -> dict[str, Any]:
"""
!!! note "Summary"
Take the `key` and `values` of a dictionary, and reverse them.
@@ -72,7 +70,7 @@ def dict_reverse_keys_and_values(dictionary: dict_any) -> dict_str_any:
This process is simple enough if the `values` are atomic types, like `#!py str`, `#!py int`, or `#!py float` types. But it is a little more tricky when the `values` are more complex types, like `#!py list` or `#!py dict`; here we need to use some recursion.
Params:
- dictionary (dict_any):
+ dictionary (Dict[Any, Any]):
The input `#!py dict` that you'd like to have the `keys` and `values` switched.
Raises:
@@ -82,7 +80,7 @@ def dict_reverse_keys_and_values(dictionary: dict_any) -> dict_str_any:
When there are duplicate `values` being coerced to `keys` in the new dictionary. Raised because a Python `#!py dict` cannot have duplicate keys of the same value.
Returns:
- output_dict (dict_str_int):
+ output_dict (Dict[str,Any]):
The updated `#!py dict`.
???+ example "Examples"
@@ -204,7 +202,7 @@ def dict_reverse_keys_and_values(dictionary: dict_any) -> dict_str_any:
!!! observation "Here, the process would be to run a recursive process when it recognises that any `value` is a `#!py dict` object. So long as there are no duplicate values in any of the contained `#!py dict`'s, the resulting output will be a big, flat dictionary."
"""
- output_dict: dict_str_any = dict()
+ output_dict: dict[str, Any] = dict()
for key, value in dictionary.items():
if isinstance(value, (str, int, float)):
output_dict[str(value)] = key
@@ -219,7 +217,7 @@ def dict_reverse_keys_and_values(dictionary: dict_any) -> dict_str_any:
)
output_dict[str(elem)] = key
elif isinstance(value, dict):
- interim_dict: dict_str_any = dict_reverse_keys_and_values(value)
+ interim_dict: dict[str, Any] = dict_reverse_keys_and_values(value)
output_dict = {
**output_dict,
**interim_dict,
diff --git a/src/toolbox_python/generators.py b/src/toolbox_python/generators.py
index e76aaee..856794d 100644
--- a/src/toolbox_python/generators.py
+++ b/src/toolbox_python/generators.py
@@ -41,7 +41,6 @@
# ## Local First Party Imports ----
from toolbox_python.checkers import assert_is_valid
-from toolbox_python.collection_types import str_list
## --------------------------------------------------------------------------- #
@@ -49,7 +48,7 @@
## --------------------------------------------------------------------------- #
-__all__: str_list = ["generate_group_cutoffs"]
+__all__: list[str] = ["generate_group_cutoffs"]
# ---------------------------------------------------------------------------- #
diff --git a/src/toolbox_python/lists.py b/src/toolbox_python/lists.py
index efcb906..99e0490 100644
--- a/src/toolbox_python/lists.py
+++ b/src/toolbox_python/lists.py
@@ -39,27 +39,21 @@
# ## Python StdLib Imports ----
+from collections.abc import Collection
from itertools import product as itertools_product
-from typing import Any, Optional, Union
+from typing import Any, Optional
# ## Python Third Party Imports ----
from more_itertools import collapse as itertools_collapse
from typeguard import typechecked
-# ## Local First Party Imports ----
-from toolbox_python.collection_types import (
- any_list,
- collection,
- scalar,
- str_list,
-)
-
# ---------------------------------------------------------------------------- #
# Exports ####
# ---------------------------------------------------------------------------- #
-__all__: str_list = ["flatten", "flat_list", "product"]
+
+__all__: list[str] = ["flatten", "flat_list", "product"]
# ---------------------------------------------------------------------------- #
@@ -71,10 +65,10 @@
@typechecked
def flatten(
- list_of_lists: Union[scalar, collection],
+ list_of_lists: Collection[Collection[Any]],
base_type: Optional[type] = None,
levels: Optional[int] = None,
-) -> any_list:
+) -> list[Any]:
"""
!!! note "Summary"
For a given `#!py list` of `#!py list`'s, flatten it out to be a single `#!py list`.
@@ -86,7 +80,7 @@ def flatten(
[more_itertools.collapse]: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse
Params:
- list_of_lists (Union[scalar, collection]):
+ list_of_lists (Collection[Collection[Any]]):
The input `#!py list` of `#!py list`'s that you'd like to flatten to a single-level `#!py list`.
base_type (Optional[type], optional):
Binary and text strings are not considered iterable and will not be collapsed. To avoid collapsing other types, specify `base_type`.
@@ -195,7 +189,7 @@ def flatten(
"""
return list(
itertools_collapse(
- iterable=list_of_lists, # type: ignore
+ iterable=list_of_lists,
base_type=base_type,
levels=levels,
)
@@ -203,7 +197,7 @@ def flatten(
@typechecked
-def flat_list(*inputs: Any) -> any_list:
+def flat_list(*inputs: Any) -> list[Any]:
"""
!!! note "Summary"
Take in any number of inputs, and output them all in to a single flat `#!py list`.
@@ -217,7 +211,7 @@ def flat_list(*inputs: Any) -> any_list:
If any of the inputs parsed to the parameters of this function are not the correct type. Uses the [`@typeguard.typechecked`](https://typeguard.readthedocs.io/en/stable/api.html#typeguard.typechecked) decorator.
Returns:
- (any_list):
+ (list[Any]):
The input having been coerced to a single flat `#!py list`.
???+ example "Examples"
diff --git a/src/toolbox_python/output.py b/src/toolbox_python/output.py
index 8a0a38f..ed02c57 100644
--- a/src/toolbox_python/output.py
+++ b/src/toolbox_python/output.py
@@ -39,7 +39,7 @@
# ## Python StdLib Imports ----
-from collections.abc import Generator
+from collections.abc import Collection, Generator
from logging import Logger, _nameToLevel
from math import ceil
from typing import Any, Literal, Optional, Union, overload
@@ -54,13 +54,6 @@
assert_is_valid,
is_type,
)
-from toolbox_python.collection_types import (
- any_list,
- any_set,
- any_tuple,
- log_levels,
- str_list,
-)
# ---------------------------------------------------------------------------- #
@@ -68,7 +61,24 @@
# ---------------------------------------------------------------------------- #
-__all__: str_list = ["print_or_log_output", "list_columns"]
+__all__: list[str] = ["print_or_log_output", "list_columns", "log_levels"]
+
+
+## --------------------------------------------------------------------------- #
+## Constants ####
+## --------------------------------------------------------------------------- #
+
+
+log_levels = Literal["debug", "info", "warning", "error", "critical"]
+"""
+!!! note "Summary"
+ To streamline other functions, this `type` alias is created for all of the `log` levels available.
+!!! abstract "Details"
+ The structure of the `type` is as follows:
+ ```pycon {.py .python linenums="1" title="Type structure"}
+ Literal["debug", "info", "warning", "error", "critical"]
+ ```
+"""
# ---------------------------------------------------------------------------- #
@@ -265,38 +275,20 @@ def print_or_log_output(
return None
-@overload
-@typechecked
-def list_columns(
- obj: Union[any_list, any_set, any_tuple, Generator],
- cols_wide: int = 4,
- columnwise: bool = True,
- gap: int = 4,
- print_output: Literal[False] = False,
-) -> str: ...
-@overload
-@typechecked
-def list_columns(
- obj: Union[any_list, any_set, any_tuple, Generator],
- cols_wide: int = 4,
- columnwise: bool = True,
- gap: int = 4,
- print_output: Literal[True] = True,
-) -> None: ...
@typechecked
def list_columns(
- obj: Union[any_list, any_set, any_tuple, Generator],
+ obj: Union[Collection[Any], Generator],
cols_wide: int = 4,
columnwise: bool = True,
gap: int = 4,
- print_output: bool = False,
+ print_output: Literal[True, False] = False,
) -> Optional[str]:
"""
!!! note "Summary"
Print the given list in evenly-spaced columns.
Params:
- obj (Union[any_list, any_set, any_tuple, Generator]):
+ obj (Union[Collection[Any], Generator]):
The list to be formatted.
cols_wide (int, optional):
@@ -317,7 +309,7 @@ def list_columns(
between columns based on the maximum `#!py len()` of the list items.
Defaults to: `#!py 4`.
- print_output (bool, optional):
+ print_output (Literal[True, False], optional):
Whether or not to print the output to the terminal.
- `#!py True`: Will print and return.
@@ -433,7 +425,7 @@ def list_columns(
assert_is_valid(gap, ">", 0)
# Prepare the string representation of the object
- string_list: str_list = [str(item) for item in obj]
+ string_list: list[str] = [str(item) for item in obj]
cols_wide = min(cols_wide, len(string_list))
max_len: int = max(len(item) for item in string_list)
@@ -442,7 +434,7 @@ def list_columns(
cols_wide = int(ceil(len(string_list) / cols_wide))
# Segment the list into chunks
- segmented_list: list[str_list] = [
+ segmented_list: list[list[str]] = [
string_list[index : index + cols_wide] for index in range(0, len(string_list), cols_wide)
]
@@ -450,7 +442,7 @@ def list_columns(
if columnwise:
if len(segmented_list[-1]) != cols_wide:
segmented_list[-1].extend([""] * (len(string_list) - len(segmented_list[-1])))
- combined_list: Union[list[str_list], Any] = zip(*segmented_list)
+ combined_list: Union[list[list[str]], Any] = zip(*segmented_list)
else:
combined_list = segmented_list
diff --git a/src/toolbox_python/retry.py b/src/toolbox_python/retry.py
index 709decd..91955f2 100644
--- a/src/toolbox_python/retry.py
+++ b/src/toolbox_python/retry.py
@@ -53,7 +53,6 @@
# ## Local First Party Imports ----
from toolbox_python.checkers import assert_is_valid
from toolbox_python.classes import get_full_class_name
-from toolbox_python.collection_types import str_list
from toolbox_python.output import print_or_log_output
@@ -62,7 +61,7 @@
# ---------------------------------------------------------------------------- #
-__all__: str_list = ["retry"]
+__all__: list[str] = ["retry"]
# ---------------------------------------------------------------------------- #
@@ -77,11 +76,15 @@
]
"""
!!! note "Summary"
- This
+ A type alias for a single or collection of `Exception` types.
"""
R = TypeVar("R")
+"""
+!!! note "Summary"
+ A generic type variable to represent the return type of a function.
+"""
# ---------------------------------------------------------------------------- #
diff --git a/src/toolbox_python/strings.py b/src/toolbox_python/strings.py
index e9d3b67..ab37e45 100644
--- a/src/toolbox_python/strings.py
+++ b/src/toolbox_python/strings.py
@@ -46,14 +46,14 @@
# ## Local First Party Imports ----
from toolbox_python.checkers import is_type
-from toolbox_python.collection_types import str_list, str_list_tuple
# ---------------------------------------------------------------------------- #
# Exports ####
# ---------------------------------------------------------------------------- #
-__all__: str_list = [
+
+__all__: list[str] = [
"str_replace",
"str_contains",
"str_contains_any",
@@ -226,7 +226,7 @@ def str_contains(check_string: str, sub_string: str) -> bool:
@typechecked
def str_contains_any(
check_string: str,
- sub_strings: str_list_tuple,
+ sub_strings: Union[list[str], tuple[str, ...]],
) -> bool:
"""
!!! note "Summary"
@@ -235,7 +235,7 @@ def str_contains_any(
Params:
check_string (str):
The main string to check.
- sub_strings (str_list_tuple):
+ sub_strings (Union[list[str], tuple[str, ...]]):
The collection of substrings to check.
Raises:
@@ -300,7 +300,7 @@ def str_contains_any(
@typechecked
def str_contains_all(
check_string: str,
- sub_strings: str_list_tuple,
+ sub_strings: Union[list[str], tuple[str, ...]],
) -> bool:
"""
!!! note "Summary"
@@ -309,7 +309,7 @@ def str_contains_all(
Params:
check_string (str):
The main string to check.
- sub_strings (str_list_tuple):
+ sub_strings (Union[list[str], tuple[str, ...]]):
The collection of substrings to check.
Raises:
@@ -382,7 +382,7 @@ def str_contains_all(
@typechecked
-def str_separate_number_chars(text: str) -> str_list:
+def str_separate_number_chars(text: str) -> list[str]:
"""
!!! note "Summary"
Take in a string that contains both numbers and letters, and output a list of strings, separated to have each element containing either entirely number or entirely letters.
@@ -400,7 +400,7 @@ def str_separate_number_chars(text: str) -> str_list:
If any of the inputs parsed to the parameters of this function are not the correct type. Uses the [`@typeguard.typechecked`](https://typeguard.readthedocs.io/en/stable/api.html#typeguard.typechecked) decorator.
Returns:
- (str_list):
+ (list[str]):
The updated list, with each element of the list containing either entirely characters or entirely numbers.
???+ example "Examples"
@@ -474,12 +474,12 @@ def str_separate_number_chars(text: str) -> str_list:
@overload
@typechecked
-def str_to_list(obj: str) -> str_list: ...
+def str_to_list(obj: str) -> list[str]: ...
@overload
@typechecked
def str_to_list(obj: Any) -> Any: ...
@typechecked
-def str_to_list(obj: Any) -> Union[str_list, Any]:
+def str_to_list(obj: Any) -> Union[list[str], Any]:
"""
!!! note "Summary"
Convert a string to a list containing that string as the only element.
@@ -496,7 +496,7 @@ def str_to_list(obj: Any) -> Union[str_list, Any]:
If `obj` is not a string or a list.
Returns:
- (Union[str_list, Any]):
+ (Union[list[str], Any]):
If `obj` is a string, returns a list containing that string as the only element. If `obj` is not a string, returns it unchanged.
???+ example "Examples"
From 7eb6a372bd67178b57387b4b58b40504ca2d88e6 Mon Sep 17 00:00:00 2001
From: Chris Mahoney <44449504+chrimaho@users.noreply.github.com>
Date: Sat, 3 Jan 2026 09:26:02 +1100
Subject: [PATCH 2/7] Fix typo
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/toolbox_python/checkers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/toolbox_python/checkers.py b/src/toolbox_python/checkers.py
index c73c642..178a6db 100644
--- a/src/toolbox_python/checkers.py
+++ b/src/toolbox_python/checkers.py
@@ -196,7 +196,7 @@ def is_all_values_of_type(values: Collection[Any], check_type: Union[type, Colle
values (Collection[Any]):
The iterable containing values to check.
check_type (Union[type, Collection[type]]):
- The type or Sequence of types to check against.
+ The type or Collection of types to check against.
Returns:
(bool):
From d487a03700b75445b0009d2064ed310e9f0e0d94 Mon Sep 17 00:00:00 2001
From: Chris Mahoney <44449504+chrimaho@users.noreply.github.com>
Date: Sat, 3 Jan 2026 09:26:23 +1100
Subject: [PATCH 3/7] Fix typo
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/toolbox_python/checkers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/toolbox_python/checkers.py b/src/toolbox_python/checkers.py
index 178a6db..71fe736 100644
--- a/src/toolbox_python/checkers.py
+++ b/src/toolbox_python/checkers.py
@@ -258,7 +258,7 @@ def is_any_values_of_type(values: Collection[Any], check_type: Union[type, Colle
values (Collection[Any]):
The iterable containing values to check.
check_type (Union[type, Collection[type]]):
- The type or Sequence of types to check against.
+ The type or Collection of types to check against.
Returns:
(bool):
From 469fc66c762559435c2212b889330e41e2bd6685 Mon Sep 17 00:00:00 2001
From: Chris Mahoney <44449504+chrimaho@users.noreply.github.com>
Date: Sat, 3 Jan 2026 09:26:36 +1100
Subject: [PATCH 4/7] Fix typo
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/toolbox_python/checkers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/toolbox_python/checkers.py b/src/toolbox_python/checkers.py
index 71fe736..71ed370 100644
--- a/src/toolbox_python/checkers.py
+++ b/src/toolbox_python/checkers.py
@@ -577,7 +577,7 @@ def assert_value_of_type(value: Any, check_type: Union[type, Collection[type]])
value (Any):
The value to check.
check_type (Union[type, Collection[type]]):
- The type or tuple of types to check against.
+ The type or Collection of types to check against.
Raises:
(TypeError):
From 81b4053801c7cb66096ff6558d327c3579622257 Mon Sep 17 00:00:00 2001
From: Chris Mahoney <44449504+chrimaho@users.noreply.github.com>
Date: Sat, 3 Jan 2026 09:35:20 +1100
Subject: [PATCH 5/7] Fix typo
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/toolbox_python/checkers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/toolbox_python/checkers.py b/src/toolbox_python/checkers.py
index 71ed370..8005ea6 100644
--- a/src/toolbox_python/checkers.py
+++ b/src/toolbox_python/checkers.py
@@ -136,7 +136,7 @@ def is_value_of_type(value: Any, check_type: Union[type, Collection[type]]) -> b
value (Any):
The value to check.
check_type (Union[type, Collection[type]]):
- The type or Sequence of types to check against.
+ The type or Collection of types to check against.
Returns:
(bool):
From 512d5607bd6765430b5c709c3e3bf21b73609216 Mon Sep 17 00:00:00 2001
From: Chris Mahoney <44449504+chrimaho@users.noreply.github.com>
Date: Sat, 3 Jan 2026 09:37:36 +1100
Subject: [PATCH 6/7] Fix missing `.__name__` attribute
When accessing and formatting the type in the error message. This line should be `msg += f"Must be '{check_type.__name__}'"` to be consistent with line 647 in `assert_value_of_type()` and to produce cleaner error messages that show just the type name (e.g., `'int'`) rather than the full type object representation (e.g., ``).
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/toolbox_python/checkers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/toolbox_python/checkers.py b/src/toolbox_python/checkers.py
index 8005ea6..886189e 100644
--- a/src/toolbox_python/checkers.py
+++ b/src/toolbox_python/checkers.py
@@ -737,7 +737,7 @@ def assert_all_values_of_type(values: Collection[Any], check_type: Union[type, C
invalid_types: list[str] = [f"'{type(value).__name__}'" for value in values if not is_type(value, check_type)]
msg: str = f"Some elements {invalid_values} have the incorrect type {invalid_types}. "
if isinstance(check_type, type):
- msg += f"Must be '{check_type}'"
+ msg += f"Must be '{check_type.__name__}'"
else:
types: list[str] = [f"'{typ.__name__}'" for typ in check_type]
msg += f"Must be: {' or '.join(types)}"
From d7d73f1f22b515f656f323838c716acc87a1c399 Mon Sep 17 00:00:00 2001
From: Chris Mahoney <44449504+chrimaho@users.noreply.github.com>
Date: Sat, 3 Jan 2026 09:41:52 +1100
Subject: [PATCH 7/7] Fix typo
---
src/toolbox_python/checkers.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/toolbox_python/checkers.py b/src/toolbox_python/checkers.py
index 886189e..625ff26 100644
--- a/src/toolbox_python/checkers.py
+++ b/src/toolbox_python/checkers.py
@@ -666,7 +666,7 @@ def assert_all_values_of_type(values: Collection[Any], check_type: Union[type, C
values (Collection[Any]):
The iterable containing values to check.
check_type (Union[type, Collection[type]]):
- The type or tuple of types to check against.
+ The type or Collection of types to check against.
Raises:
(TypeError):
@@ -760,7 +760,7 @@ def assert_any_values_of_type(values: Collection[Any], check_type: Union[type, C
values (Collection[Any]):
The iterable containing values to check.
check_type (Union[type, Collection[type]]):
- The type or tuple of types to check against.
+ The type or Collection of types to check against.
Raises:
(TypeError):