Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions src/toolbox_python/bools.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]


# ---------------------------------------------------------------------------- #
Expand Down
225 changes: 85 additions & 140 deletions src/toolbox_python/checkers.py

Large diffs are not rendered by default.

15 changes: 1 addition & 14 deletions src/toolbox_python/collection_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

# ## Python StdLib Imports ----
from datetime import datetime
from typing import Any, Literal, Union
from typing import Any, Union


## --------------------------------------------------------------------------- #
Expand All @@ -40,7 +40,6 @@
"int_list",
"int_tuple",
"iterable",
"log_levels",
"scalar",
"str_collection",
"str_dict",
Expand Down Expand Up @@ -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"]
```
"""
10 changes: 7 additions & 3 deletions src/toolbox_python/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,14 @@
# ## 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


# ---------------------------------------------------------------------------- #
# Exports ####
# ---------------------------------------------------------------------------- #


__all__: str_list = ["defaults", "Defaults"]
__all__: list[str] = ["defaults", "Defaults"]


# ---------------------------------------------------------------------------- #
Expand All @@ -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"}
Expand Down Expand Up @@ -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",
Expand Down
16 changes: 7 additions & 9 deletions src/toolbox_python/dictionaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]


# ---------------------------------------------------------------------------- #
Expand All @@ -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.
Expand All @@ -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:
Expand All @@ -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"
Expand Down Expand Up @@ -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."
</div>
"""
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
Expand All @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions src/toolbox_python/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,14 @@

# ## Local First Party Imports ----
from toolbox_python.checkers import assert_is_valid
from toolbox_python.collection_types import str_list


## --------------------------------------------------------------------------- #
## Exports ####
## --------------------------------------------------------------------------- #


__all__: str_list = ["generate_group_cutoffs"]
__all__: list[str] = ["generate_group_cutoffs"]


# ---------------------------------------------------------------------------- #
Expand Down
26 changes: 10 additions & 16 deletions src/toolbox_python/lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]


# ---------------------------------------------------------------------------- #
Expand All @@ -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`.
Expand All @@ -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`.<br>
Expand Down Expand Up @@ -195,15 +189,15 @@ def flatten(
"""
return list(
itertools_collapse(
iterable=list_of_lists, # type: ignore
iterable=list_of_lists,
base_type=base_type,
levels=levels,
)
)


@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`.
Expand All @@ -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"
Expand Down
60 changes: 26 additions & 34 deletions src/toolbox_python/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -54,21 +54,31 @@
assert_is_valid,
is_type,
)
from toolbox_python.collection_types import (
any_list,
any_set,
any_tuple,
log_levels,
str_list,
)


# ---------------------------------------------------------------------------- #
# Exports ####
# ---------------------------------------------------------------------------- #


__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"]
```
"""


# ---------------------------------------------------------------------------- #
Expand Down Expand Up @@ -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):
Expand All @@ -317,7 +309,7 @@ def list_columns(
between columns based on the maximum `#!py len()` of the list items.<br>
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.
Expand Down Expand Up @@ -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)

Expand All @@ -442,15 +434,15 @@ 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)
]

# Ensure the last segment has the correct number of 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

Expand Down
Loading