dict_manip

The dictionary manipulation module is primarily focused on methods that can be used to restructure dictionaries or lists. It contains some useful helper methods as well as more-complex methods.

convert_tuplish_dict(data: dict | list, pair_name: str | None = None, key_name: str | None = None, val_name: str | None = None) dict

Handles the conversion of data structured as either a dictionary or a list containing key-value pairs into a dictionary representation. The conversion process adheres to specific rules based on the following criteria:

  1. If pair_name is specified.

  2. If both key_name and val_name are specified.

    Be aware that specifying only one of these will result in both being ignored.

  3. If key_name is equal to val_name and both are specified.

When pair_name is specified and key_name, val_name, or both are missing, the function conducts a depth-first search to locate a dictionary containing pair_name as a key. It traverses through lists and their nested lists to find the desired pairs. If a dictionary with pair_name as a key is found, the function inspects the corresponding value. If the value is a list, it identifies the lowest-level lists within it and constructs pairs using the merge_tuplish_pair() function. If successful, this process is repeated for other lists. If elements in the list are dictionaries with only one key, the function delves deeper into them following the same search pattern.

When both key_name and val_name are specified but pair_name is not, the search method depends on whether key_name equals val_nam. If they are equal, the function performs the same search as it would for pair_name but searches for key_name instead. If they are unequal, it searches for a dictionary containing both key_name and val_name in the same manner as for pair_name. Once the target dictionary is found, the function evaluates only one pair from it. If the value under key_name is a list, it iterates through it to ensure there are no un-hashable values within, then constructs the pair using merge_tuplish_pair(). This process is repeated for as many pairs as it can find.

When pair_name, key_name, and val_name are all specified, the search method is the same as for pair_name until a dictionary containing pair_name is found. Once such a dictionary is found, the same process as when key_name and val_name are specified is attempted on the value under the pair_name key.

If neither pair_name, key_name, nor val_name is specified, the search method attempts to find each lowest-level list just as it normally would when pair_name is the only value specified.

Note

When attempting to find a dictionary containing target key(s) convert_tuplish_dict() will stop at dictionaries containing more than one key if they do not contain the target key.

Parameters:
  • data (Union[dict, list]) – The data to treat as a tuplish dict.

  • pair_name (str) – The name used to represent a pair. If omitted, will not expect pairs to be under keys.

  • key_name (str) – The name used to represent a key. If either this or val_name is omitted, neither will be used and pairs will be constructed using the best identifiable method.

  • val_name (str) – The name used to represent a value. If either this or key_name is omitted, neither will be used and pairs will be constructed using the best identifiable method.

Returns:

A flat dictionary made of key-value pairs found in the given data.

Note

Please be aware that the returned dictionary may not be completely flat, as there is a chance of a value being under a path of keys.

merge_tuplish_pair(pair: list, builder: dict, unsafe: bool = False)

Merges a list representing a key-value pair into a dictionary builder.

This function iterates over the elements of the input pair list, representing a key-value pair, and merges it into the given dictionary builder. The builder is progressively updated to construct a nested dictionary structure based on the keys in the pair list. It will construct paths that are missing on its own.

Parameters:
  • pair (list) – A list representing a key-value pair, where all items except the last represent a path of keys under which the last item is to be stored.

  • builder (dict) – The dictionary to merge pair into.

  • unsafe (bool) – Whether a failure to merge should actually raise an error. Defaults to False.

Warning

Default behavior is if the function encounters a key in the pair list that already exists in the builder and the corresponding value is not a dictionary, but there are more keys involved in the path to the value, it will not attempt to update the value or build the dictionary any deeper, but instead will do nothing to builder. It logs a message under the dict_manip logger at the info level when this occurs. You can turn on this logger by setting the DICT_MANIP_LOG_LEVEL environment variable to 'info'.

merge_to_dict(data: dict, builder: dict)

Merges data into builder while doing as much as possible to preserve builder’s structure. If it finds a value that coincides with another value’s position within builder, it will perform the following in an attempt to turn those values into a singular list: - If both the value in builder and in data are lists, it will use the value from data to extend the value in builder. - If the value in builder is a list, but the value in data is not, it will append the value from data to the value in builder. - If the value in builder is not a list, but the value in data is, a list shall be constructed containing the items from data and the value from builder. - If the value in builder and the value in data are not lists, it will create a list where each of them is an item.

Warning

If a value in data is at the same position as a dictionary in builder, merge_to_dict will not attempt to add that value at the risk of deleting an intended branch in builder. It logs a message under the dict_manip logger at the info level when this occurs. You can turn on this logger by setting the DICT_MANIP_LOG_LEVEL environment variable to 'info'.

Parameters:
  • data (dict) – The dictionary to have its values merged into builder.

  • builder (dict) – The dictionary to merge the values from data into.

dive_to_dicts(data: dict | list, *needed_keys) Generator[dict, None, None]

This will find the dictionaries at the lowest level within a list [1]. The list may contain other lists, which will be searched for dictionaries as well. It is a Generator, and can be iterated through.

Warning

This will not find the lowest-level dictionaries, but every highest-level dictionary ignoring dictionaries that only have one key unless that key happens to be the only value in needed_keys, in which case it will return that dictionary.

Parameters:
  • data (Union[dict, list]) – The data to find highest-level dictionaries in.

  • needed_keys (Any) – The keys that found dictionaries must contain. If there are no needed_keys specified, then any dictionary will be considered valid and will be returned.

dive_to_lowest_lists(data: dict | list) Generator[list | None, bool | None, None]

This will find the lowest-level lists within a list [2]. The list may contain other lists, which will be searched through to see if they contain lists as well. It will keep searching until it has found all the lists which contain no lists. It is a generator, and can be iterated through, but also has a valid ``send` option. When sent the boolean value True via its .send method, it will continue to iterate through lowest-level lists, but will also check inside any dictionaries contained within the current list to see if there are lowest-level lists within those, whereas it would not normally do so.

Parameters:

data (Union[dict, list]) – The dictionary or list to search for lowest-level lists in.

Returns:

A generator which can be used ot iterate over all lowest-level lists inside a dictionary or list. This generator has can be sent a boolean value of True during iteration to change its behavior.

align_to_list(order: list | dict, to_align: dict, default: Any | None = None) list

Realigns the values from a dictionary to the order specified by order. It does not require all expected keys to be in to_align.

Parameters:
  • order – The order that keys should go in. If this is a list, it will be used as-is. If it is a dictionary, its keys will be converted to a list which will be used in its place.

  • to_align – The dictionary to align to order.

  • default – The default value that should be used at a position if no value is specified for it in to_align.

Returns:

A list of the values from to_align in the order specified by order.

nest_under_keys(data: Any, *keys) dict

Generates a nested dictionary using keys as the nesting keys.

get_subset(data: dict, *keys) dict

Retrieves a subset of keys from a dictionary in the format of a dictionary. Any keys that do not exist will simply be omitted.

get_subset_values(data: dict, *keys) tuple

Retrieves a subset values (based on keys) from a dictionary in the format of a tuple. Any keys that do not exist will have None as their value.

tuples_to_dict(*pairs: Tuple[Any, Any], all_pairs: Iterable[Tuple[Any, Any]] | None = None) dict

Constructs a dictionary from provided tuples.

get_val_from_path(source: dict, *path: Any, default: Any | None = None, unsafe: bool = False) Any

Follow a path through a dictionary to find the value at the end.

Parameters:
  • source – The dictionary to get a value from.

  • path – The paht of keys to follow to get to the desired value inside source.

  • default – A default value to return if the path ends prematurely. Will be ignored if unsafe is True.

  • unsafe – Whether to raise an exception if the path ends early. Overrides default.

Returns:

The value at the end of the desired path in source, if it exists. Otherwise, default.

get_one_of_keys(source: dict, *keys: Any | list, default: Any = None) Any

Get the value at one of the keys (or key paths) specified in keys from source. Will return default if none of the keys/key paths exist in source.

Parameters:
  • source (dict) – The source dict to get the value from.

  • keys (Union[Any, list]) – The possible keys or key paths the sought value could be located at.

  • default (Any) – The default value to return if the target value cannot be found.

Returns:

The target value, if it is found. Otherwise, default.

class DictBuilder(*args, clazz: ~typing.Type = <class 'dict'>, **kwargs)

Bases: object

A builder for dictionaries that has a few helpful methods for merging in data from other dictionaries.

Parameters:
  • _map (Mapping) – The Mapping to start the builder out with. Works like it does for dict.

  • clazz (Type) – A dictionary class to inherit from. Used to make sure the builder is the desired type of dictionary.

  • _other (dict) – The other dictionary to use for pull_from_other(), get_from_other(), update_from_other(), and get_one_of_keys_from_other(). If this is not specified, those methods will not work. It can be changed later.

  • _transformer (Callable) – The default transformer to use for values retrieved from another dict. Defaults to a function that does nothing to the input.

  • kwargs – The kwargs to construct the starting builder with. Works like it does for dict.

CUR = <funk_py.sorting.dict_manip.DictBuilder._Cur object>

_Cur: A placeholder that can be used to represent the current DictBuilder inside its own methods and allows the use of a few types of getters including __getitem__, get, keys, values, and items’ methods.

Warning

Using this can have unintended consequences and can allow recursion. Use at your own risk.

build(strict: bool = True) dict

Build the dictionary from the DictBuilder.

Parameters:

strict (bool) – Whether to return a strict copy of the dictionary, maintaining all types. True will result all internal dictionaries being maintained as their original types. False will result in all internal dictionaries being converted to dict.

Returns:

The dictionary that was built.

property clazz: type

The default class for the DictBuilder.

get_from(other: dict | _Cur | _Instruction, key: Any, _as: Any, transformer: Callable = Ellipsis, default: Any = Ellipsis) DictBuilder

Get a value from another dictionary at a given key, and insert it at the key specified in _as. If key cannot be found in other or the value cannot be added to this ``DictBuilder, then the value simply won’t be added.

Parameters:
  • other (dict) – The dictionary to grab the key from.

  • key (Union[Any, list]) – The key at which to find a value in other.

  • _as (Union[Any, list]) – The key at which to place the found value from other.

  • transformer (Callable) – A transformer that should be called on a value if found.

  • default – The default value to use if a value cannot be found. If omitted, and the value is not found, then the value simply won’t be added.

Returns:

The current DictBuilder for chaining.

get_from_other(key: Any, _as: Any, transformer: Callable = Ellipsis, default: Any = Ellipsis) DictBuilder

Get a value from the DictBuilder's other at a given key, and insert it at the key specified in _as. If key cannot be found in other or the value cannot be added to this DictBuilder, then the value simply won’t be added.

Parameters:
  • key (Union[Any, list]) – The key at which to find a value in other.

  • _as (Union[Any, list]) – The key at which to place the found value from other.

  • transformer (Callable) – A transformer that should be called on a value if found.

  • default – The default value to use if a value cannot be found. If omitted, and the value is not found, then the value simply won’t be added.

Returns:

The current DictBuilder for chaining.

get_one_of_keys_from(other: dict, _as: Any, *keys: Any, transformer: Callable = Ellipsis, default: Any = Ellipsis) DictBuilder

Gets the value at one of the keys (or key paths) specified in keys from other and adds it at _as within the DictBuilder.

Parameters:
  • other (dict) – The source dict to get the value from.

  • _as (Union[Any, list]) – The key or key path to add a found value at.

  • keys (Union[Any, list]) – The possible keys or key paths the sought value could be located at.

  • default (Any) – The default value to return if the target value cannot be found. If this is not specified, then should no value be found, a value simply won’t be added.

Returns:

The current DictBuilder for chaining.

get_one_of_keys_from_other(_as: Any | list, *keys: Any | list, transformer: Callable = Ellipsis, default: Any = Ellipsis) DictBuilder

Gets the value at one of the keys (or key paths) specified in keys from the DictBuilder's other and adds it at _as within the DictBuilder.

Parameters:
  • _as (Union[Any, list]) – The key or key path to add a found value at.

  • keys (Union[Any, list]) – The possible keys or key paths the sought value could be located at.

  • default (Any) – The default value to return if the target value cannot be found. If this is not specified, then should no value be found, a value simply won’t be added.

Returns:

The current DictBuilder for chaining.

pull_from(other: dict | _Cur | _Instruction, key: Any, _as: Any, transformer: Callable = Ellipsis) DictBuilder

Get a value from another dictionary at a given key, and insert it at the key specified in _as. Using this will raise an error if the key doesn’t exist in other or if it cannot safely be added to the DictBuilder.

Parameters:
  • other (dict) – The dictionary to grab the key from.

  • key (Union[Any, list]) – The key at which to find a value in other.

  • _as (Union[Any, list]) – The key at which to place the found value from other.

  • transformer (Callable) – A transformer that should be called on a value if found.

Returns:

The current DictBuilder for chaining.

pull_from_other(key: Any, _as: Any, transformer: Callable = Ellipsis) DictBuilder

Get a value from the DictBuilder's other at a given key, and insert it at the key specified in _as. Using this will raise an error if the key doesn’t exist in other or if it cannot safely be added to the DictBuilder.

Parameters:
  • key (Union[Any, list]) – The key at which to find a value in other.

  • _as (Union[Any, list]) – The key at which to place the found value from other.

  • transformer (Callable) – A transformer that should be called on a value if found.

Returns:

The current DictBuilder for chaining.

update_from(other: dict | _Cur | _Instruction, key: Any = None, _as: Any = None, keys: list = None, transformer: Callable = Ellipsis, unsafe: bool = False, classes: List[Type[dict]] | Type[dict] = None, val_is_list: bool = False) DictBuilder

Update this DictBuilder from another dict.

Parameters:
  • other (dict) – The dictionary to update with.

  • key (Union[Any, None, list]) – The key at which the source dictionary should be in other. If not specified other will be used as-is unless keys is specified.

  • _as (Union[Any, None, list]) – The key at which to place update with the found value from other. If not specified, will simply update the entire DictBuilder.

  • keys (Optional[List[Union[Any, None, list]]]) – A list of possible keys at which the source dictionary might be located in other. Each key should follow the same rules as key. If key is specified, key will be attempted first, then keys will be attempted.

  • transformer (Callable) – A transformer that should be called on the value being used to update the DictBuilder.

  • unsafe (bool) – Whether an error should be raised if the desired operation cannot be completed.

  • classes (Optional[Union[List[Type[dict]], Type[dict]]]) –

    The types of internal dictionaries to generate if parts of paths do not exist. Will override what type of dictionary is used at each point in the path until the end of _as. There are different behaviors based on how this is specified (or not specified).

    • If this is a list, each class will be used in succession while following the path specified by _as. If the end is reached before _as is over, new dictionaries will be of the same type as the DictBuilder.clazz. If this longer than _as, it will only be used for needed locations.

    • If this is a single type, any new dicts generated when following the path described by _as will be of the type specified.

    • If this is not specified, each generated dictionary will be of the same type as the DictBuilder.clazz.

  • val_is_list (bool) – Whether the value at key in other should be considered as a list and its values iterated over and individually used to update the DictBuilder. Defaults to False.

Returns:

The current DictBuilder for chaining.

update_from_list(other: List[dict], _as: Any = None, transformer: Callable = Ellipsis, unsafe: bool = False, classes: List[Type[dict]] | Type[dict] = None) DictBuilder

Update this DictBuilder from another dict.

Parameters:
  • other (dict) – The dictionary to update with.

  • _as (Union[Any, None, list]) – The key at which to place update with the found value from other. If not specified, will simply update the entire DictBuilder.

  • transformer (Callable) – A transformer that should be called on the value being used to update the DictBuilder.

  • unsafe (bool) – Whether an error should be raised if the desired operation cannot be completed.

  • classes (Optional[Union[List[Type[dict]], Type[dict]]]) –

    The types of internal dictionaries to generate if parts of paths do not exist. Will override what type of dictionary is used at each point in the path until the end of _as. There are different behaviors based on how this is specified (or not specified).

    • If this is a list, each class will be used in succession while following the path specified by _as. If the end is reached before _as is over, new dictionaries will be of the same type as the DictBuilder.clazz. If this longer than _as, it will only be used for needed locations.

    • If this is a single type, any new dicts generated when following the path described by _as will be of the type specified.

    • If this is not specified, each generated dictionary will be of the same type as the DictBuilder.clazz.

Returns:

The current DictBuilder for chaining.

update_from_other(key: Any | None = None, _as: Any | None | list = None, keys: List[Any] | None = None, transformer: Callable = Ellipsis, unsafe: bool = False, classes: List[Type[dict]] | Type[dict] | None = None, val_is_list: bool = False) DictBuilder

Update this DictBuilder from it’s stored other.

Parameters:
  • key (Optional[Union[Any, None, list]]) – The key at which the source dictionary should be in other. If not specified other will be used as-is unless keys is specified.

  • _as (Union[Any, None, list]) – The key at which to place update with the found value from other. If not specified, will simply update the entire DictBuilder.

  • keys (Optional[List[Union[Any, None, list]]]) – A list of possible keys at which the source dictionary might be located in other. Each key should follow the same rules as key. If key is specified, key will be attempted first, then keys will be attempted.

  • transformer (Callable) – A transformer that should be called on the value being used to update the DictBuilder.

  • unsafe (bool) – Whether an error should be raised if the desired operation cannot be completed.

  • classes (Optional[Union[List[Type[dict]], Type[dict]]]) –

    The types of internal dictionaries to generate if parts of paths do not exist. Will override what type of dictionary is used at each point in the path until the end of _as. There are different behaviors based on how this is specified (or not specified).

    • If this is a list, each class will be used in succession while following the path specified by _as. If the end is reached before _as is over, new dictionaries will be of the same type as the DictBuilder.clazz. If this longer than _as, it will only be used for needed locations.

    • If this is a single type, any new dicts generated when following the path described by _as will be of the type specified.

    • If this is not specified, each generated dictionary will be of the same type as the DictBuilder.clazz.

  • val_is_list (bool) – Whether the value at key in other should be considered as a list and its values iterated over and individually used to update the DictBuilder. Defaults to False.

Returns:

The current DictBuilder for chaining.

use(other: dict = Ellipsis, transformer: Callable = Ellipsis) DictBuilder

Set parameter defaults for other and/or transformer.

Parameters:
  • other – The new other to use. If omitted other will not be changed. If None is given, then the current other will be erased, and pull_from_other(), get_from_other(), update_from_other(), and get_one_of_keys_from_other() will cease to work until a new other is specified.

  • transformer – The new transformer to use as a default transformer in functions. If omitted, transformer will remain the same. If None is given, then transformer will be set to its default value (a non-transforming function).

Returns:

The current DictBuilder for chaining.