bedrock.helpers.dictionary

  1import uuid
  2from typing import Type, Any
  3
  4from bedrock._helpers.string import camelCase_to_snake_case, snake_case_to_camelCase
  5
  6
  7def exclude_keys_from_dict(dictionary: dict, exclude_keys: list[str]) -> dict:  # pragma: unit
  8    """
  9    Returns a copy of the dictionary without the specified keys.
 10    :param dictionary: The original dictionary
 11    :param exclude_keys: The keys to exclude
 12    :return: A new dictionary
 13    """
 14    d = dictionary.copy()
 15    for key in exclude_keys:
 16        if key in d:
 17            del d[key]
 18    return d
 19
 20
 21def merge_dictionaries(base_dictionary: dict, dictionary_to_merge: dict = None,
 22                       bypass_nones=False) -> dict:  # pragma: unit
 23    """
 24    Superficially merges two dictionaries, with the second dictionary taking precedence (i.e.: if any key is present in
 25    both dictionaries, the value in the second dictionary will be used).
 26    :param base_dictionary: A dictionary
 27    :param dictionary_to_merge: The dictionary to merge into the base dictionary
 28    :param bypass_nones: Whether to bypass None values in the second dictionary
 29    :return: A new dictionary
 30    """
 31    body = base_dictionary.copy()
 32    if dictionary_to_merge is None:
 33        return body
 34
 35    for key in dictionary_to_merge:
 36        if not (bypass_nones and dictionary_to_merge[key] is None):
 37            body[snake_case_to_camelCase(key)] = dictionary_to_merge[key]
 38    return body
 39
 40
 41def get_dict_key_with_fallback(dictionary: dict, key: str, fallback=None) -> Any:  # pragma: unit
 42    """
 43    Returns the value of the specified key in the dictionary, or the fallback value if the key does not exist.
 44    :param dictionary: Dictionary to search in
 45    :param key: The key in the dictionary
 46    :param fallback: The fallback value when `key` is not found
 47    :return: Either `dictionary[key]` or `fallback`
 48    """
 49    try:
 50        return dictionary[key]
 51    except (KeyError, TypeError):
 52        if fallback is None:
 53            raise Exception(f"Could not find attribute {key} in dictionary")
 54        return fallback
 55
 56
 57def check_dict_key(dictionary: dict, key: str, exception: Type[Exception] = Exception):  # pragma: unit
 58    """
 59    Checks if the specified key exists in the dictionary, and raises the provided exception if it does not.
 60
 61    This is a handy shortcut to turn a `KeyError` or `TypeError` into a custom exception.
 62
 63    :param dictionary: Dictionary to search in
 64    :param key: The key in the dictionary
 65    :param exception: The exception to raise if the key is not found (Default: `Exception`)
 66    """
 67    try:
 68        dictionary[key]
 69    except (KeyError, TypeError):
 70        raise exception(f"{key} is required")
 71
 72
 73def get_snake_or_camel_case_key(dictionary: dict, key: str) -> str:  # pragma: unit
 74    """
 75    Returns the key in the dictionary that matches the specified key, regardless of whether it is in snake_case or camelCase.
 76    :param dictionary: The dictionary to search in
 77    :param key: The key to search for
 78    :return: The properly formatted key
 79    """
 80    try:
 81        _key = camelCase_to_snake_case(key)
 82        dictionary[_key]  # Check if the key exists
 83        return _key
 84    except KeyError:
 85        _key = snake_case_to_camelCase(key)
 86        dictionary[_key]  # Check if the key exists
 87        return _key
 88
 89
 90def get_snake_or_camel_case_value(dictionary: dict, key: str) -> Any:  # pragma: unit
 91    """
 92    Returns the value in the dictionary that matches the specified key, regardless of whether it is in snake_case or
 93    camelCase.
 94    :param dictionary: The dictionary to search in
 95    :param key: The key to search for (either in snake_case or camelCase)
 96    """
 97    try:
 98        return dictionary[camelCase_to_snake_case(key)]
 99    except KeyError:
100        return dictionary[snake_case_to_camelCase(key)]
101
102
103def has_key_value(dictionary: dict, key: str, value,
104                  snake_and_camel_case: bool = False,
105                  compare_lists_with_contains=False) -> bool:  # pragma: unit
106    """
107    Checks whether the specified key exists in the dictionary, and whether the value matches the specified value.
108    This method treats a string UUID and an object UUID the same
109
110    Optionally:
111    * the key can be in snake_case or camelCase (with `snake_and_camel_case`)
112    * the value can be a list, in which case the value will be checked with `in` instead of `==` (with `compare_lists_with_contains`)
113
114    :param dictionary: The dictionary to search in
115    :param key: The key to search for
116    :param value: The value to compare with
117    :param snake_and_camel_case: Whether the key can be in snake_case or camelCase
118    :param compare_lists_with_contains: Whether to compare lists with `in` instead of `==`
119    :return:
120    """
121    try:
122        if snake_and_camel_case:
123            _key = get_snake_or_camel_case_key(dictionary, key)
124        else:
125            _key = key
126
127        if compare_lists_with_contains and isinstance(value, list):
128            return dictionary[_key] in value
129        if isinstance(dictionary[_key], uuid.UUID):
130            return str(dictionary[_key]) == str(value)
131        return dictionary[_key] == value
132    except (KeyError, TypeError):
133        return False
134
135
136def has_key(dictionary: dict, key: str, snake_and_camel_case: bool = False) -> bool:  # pragma: unit
137    """
138    Checks whether the specified key exists in the dictionary.
139
140    Optionally, the key can be in snake_case or camelCase (with `snake_and_camel_case`).
141
142    :param dictionary: The dictionary to search in
143    :param key: The key to search for
144    :param snake_and_camel_case: Whether the key can be in snake_case or camelCase
145    """
146    try:
147        if snake_and_camel_case:
148            _key = get_snake_or_camel_case_key(dictionary, key)
149        else:
150            _key = key
151        return _key in dictionary
152    except KeyError:
153        return False
154
155
156def contains_keys(dictionary, keys, snake_and_camel_case: bool = False):  # pragma: unit
157    """
158    Checks if the dictionary contains all the specified keys.
159
160    Optionally, the keys can be in snake_case or camelCase (with `snake_and_camel_case`).
161
162    :param dictionary: The dictionary to search in
163    :param keys: The keys to search for
164    :param snake_and_camel_case: Whether the keys can be in snake_case or camelCase
165    """
166    for key in keys:
167        if not has_key(dictionary, key, snake_and_camel_case):
168            return False
169    return True
def exclude_keys_from_dict(dictionary: dict, exclude_keys: list[str]) -> dict:
 8def exclude_keys_from_dict(dictionary: dict, exclude_keys: list[str]) -> dict:  # pragma: unit
 9    """
10    Returns a copy of the dictionary without the specified keys.
11    :param dictionary: The original dictionary
12    :param exclude_keys: The keys to exclude
13    :return: A new dictionary
14    """
15    d = dictionary.copy()
16    for key in exclude_keys:
17        if key in d:
18            del d[key]
19    return d

Returns a copy of the dictionary without the specified keys.

Parameters
  • dictionary: The original dictionary
  • exclude_keys: The keys to exclude
Returns

A new dictionary

def merge_dictionaries( base_dictionary: dict, dictionary_to_merge: dict = None, bypass_nones=False) -> dict:
22def merge_dictionaries(base_dictionary: dict, dictionary_to_merge: dict = None,
23                       bypass_nones=False) -> dict:  # pragma: unit
24    """
25    Superficially merges two dictionaries, with the second dictionary taking precedence (i.e.: if any key is present in
26    both dictionaries, the value in the second dictionary will be used).
27    :param base_dictionary: A dictionary
28    :param dictionary_to_merge: The dictionary to merge into the base dictionary
29    :param bypass_nones: Whether to bypass None values in the second dictionary
30    :return: A new dictionary
31    """
32    body = base_dictionary.copy()
33    if dictionary_to_merge is None:
34        return body
35
36    for key in dictionary_to_merge:
37        if not (bypass_nones and dictionary_to_merge[key] is None):
38            body[snake_case_to_camelCase(key)] = dictionary_to_merge[key]
39    return body

Superficially merges two dictionaries, with the second dictionary taking precedence (i.e.: if any key is present in both dictionaries, the value in the second dictionary will be used).

Parameters
  • base_dictionary: A dictionary
  • dictionary_to_merge: The dictionary to merge into the base dictionary
  • bypass_nones: Whether to bypass None values in the second dictionary
Returns

A new dictionary

def get_dict_key_with_fallback(dictionary: dict, key: str, fallback=None) -> Any:
42def get_dict_key_with_fallback(dictionary: dict, key: str, fallback=None) -> Any:  # pragma: unit
43    """
44    Returns the value of the specified key in the dictionary, or the fallback value if the key does not exist.
45    :param dictionary: Dictionary to search in
46    :param key: The key in the dictionary
47    :param fallback: The fallback value when `key` is not found
48    :return: Either `dictionary[key]` or `fallback`
49    """
50    try:
51        return dictionary[key]
52    except (KeyError, TypeError):
53        if fallback is None:
54            raise Exception(f"Could not find attribute {key} in dictionary")
55        return fallback

Returns the value of the specified key in the dictionary, or the fallback value if the key does not exist.

Parameters
  • dictionary: Dictionary to search in
  • key: The key in the dictionary
  • fallback: The fallback value when key is not found
Returns

Either dictionary[key] or fallback

def check_dict_key( dictionary: dict, key: str, exception: Type[Exception] = <class 'Exception'>):
58def check_dict_key(dictionary: dict, key: str, exception: Type[Exception] = Exception):  # pragma: unit
59    """
60    Checks if the specified key exists in the dictionary, and raises the provided exception if it does not.
61
62    This is a handy shortcut to turn a `KeyError` or `TypeError` into a custom exception.
63
64    :param dictionary: Dictionary to search in
65    :param key: The key in the dictionary
66    :param exception: The exception to raise if the key is not found (Default: `Exception`)
67    """
68    try:
69        dictionary[key]
70    except (KeyError, TypeError):
71        raise exception(f"{key} is required")

Checks if the specified key exists in the dictionary, and raises the provided exception if it does not.

This is a handy shortcut to turn a KeyError or TypeError into a custom exception.

Parameters
  • dictionary: Dictionary to search in
  • key: The key in the dictionary
  • exception: The exception to raise if the key is not found (Default: Exception)
def get_snake_or_camel_case_key(dictionary: dict, key: str) -> str:
74def get_snake_or_camel_case_key(dictionary: dict, key: str) -> str:  # pragma: unit
75    """
76    Returns the key in the dictionary that matches the specified key, regardless of whether it is in snake_case or camelCase.
77    :param dictionary: The dictionary to search in
78    :param key: The key to search for
79    :return: The properly formatted key
80    """
81    try:
82        _key = camelCase_to_snake_case(key)
83        dictionary[_key]  # Check if the key exists
84        return _key
85    except KeyError:
86        _key = snake_case_to_camelCase(key)
87        dictionary[_key]  # Check if the key exists
88        return _key

Returns the key in the dictionary that matches the specified key, regardless of whether it is in snake_case or camelCase.

Parameters
  • dictionary: The dictionary to search in
  • key: The key to search for
Returns

The properly formatted key

def get_snake_or_camel_case_value(dictionary: dict, key: str) -> Any:
 91def get_snake_or_camel_case_value(dictionary: dict, key: str) -> Any:  # pragma: unit
 92    """
 93    Returns the value in the dictionary that matches the specified key, regardless of whether it is in snake_case or
 94    camelCase.
 95    :param dictionary: The dictionary to search in
 96    :param key: The key to search for (either in snake_case or camelCase)
 97    """
 98    try:
 99        return dictionary[camelCase_to_snake_case(key)]
100    except KeyError:
101        return dictionary[snake_case_to_camelCase(key)]

Returns the value in the dictionary that matches the specified key, regardless of whether it is in snake_case or camelCase.

Parameters
  • dictionary: The dictionary to search in
  • key: The key to search for (either in snake_case or camelCase)
def has_key_value( dictionary: dict, key: str, value, snake_and_camel_case: bool = False, compare_lists_with_contains=False) -> bool:
104def has_key_value(dictionary: dict, key: str, value,
105                  snake_and_camel_case: bool = False,
106                  compare_lists_with_contains=False) -> bool:  # pragma: unit
107    """
108    Checks whether the specified key exists in the dictionary, and whether the value matches the specified value.
109    This method treats a string UUID and an object UUID the same
110
111    Optionally:
112    * the key can be in snake_case or camelCase (with `snake_and_camel_case`)
113    * the value can be a list, in which case the value will be checked with `in` instead of `==` (with `compare_lists_with_contains`)
114
115    :param dictionary: The dictionary to search in
116    :param key: The key to search for
117    :param value: The value to compare with
118    :param snake_and_camel_case: Whether the key can be in snake_case or camelCase
119    :param compare_lists_with_contains: Whether to compare lists with `in` instead of `==`
120    :return:
121    """
122    try:
123        if snake_and_camel_case:
124            _key = get_snake_or_camel_case_key(dictionary, key)
125        else:
126            _key = key
127
128        if compare_lists_with_contains and isinstance(value, list):
129            return dictionary[_key] in value
130        if isinstance(dictionary[_key], uuid.UUID):
131            return str(dictionary[_key]) == str(value)
132        return dictionary[_key] == value
133    except (KeyError, TypeError):
134        return False

Checks whether the specified key exists in the dictionary, and whether the value matches the specified value. This method treats a string UUID and an object UUID the same

Optionally:

  • the key can be in snake_case or camelCase (with snake_and_camel_case)
  • the value can be a list, in which case the value will be checked with in instead of == (with compare_lists_with_contains)
Parameters
  • dictionary: The dictionary to search in
  • key: The key to search for
  • value: The value to compare with
  • snake_and_camel_case: Whether the key can be in snake_case or camelCase
  • compare_lists_with_contains: Whether to compare lists with in instead of ==
Returns
def has_key(dictionary: dict, key: str, snake_and_camel_case: bool = False) -> bool:
137def has_key(dictionary: dict, key: str, snake_and_camel_case: bool = False) -> bool:  # pragma: unit
138    """
139    Checks whether the specified key exists in the dictionary.
140
141    Optionally, the key can be in snake_case or camelCase (with `snake_and_camel_case`).
142
143    :param dictionary: The dictionary to search in
144    :param key: The key to search for
145    :param snake_and_camel_case: Whether the key can be in snake_case or camelCase
146    """
147    try:
148        if snake_and_camel_case:
149            _key = get_snake_or_camel_case_key(dictionary, key)
150        else:
151            _key = key
152        return _key in dictionary
153    except KeyError:
154        return False

Checks whether the specified key exists in the dictionary.

Optionally, the key can be in snake_case or camelCase (with snake_and_camel_case).

Parameters
  • dictionary: The dictionary to search in
  • key: The key to search for
  • snake_and_camel_case: Whether the key can be in snake_case or camelCase
def contains_keys(dictionary, keys, snake_and_camel_case: bool = False):
157def contains_keys(dictionary, keys, snake_and_camel_case: bool = False):  # pragma: unit
158    """
159    Checks if the dictionary contains all the specified keys.
160
161    Optionally, the keys can be in snake_case or camelCase (with `snake_and_camel_case`).
162
163    :param dictionary: The dictionary to search in
164    :param keys: The keys to search for
165    :param snake_and_camel_case: Whether the keys can be in snake_case or camelCase
166    """
167    for key in keys:
168        if not has_key(dictionary, key, snake_and_camel_case):
169            return False
170    return True

Checks if the dictionary contains all the specified keys.

Optionally, the keys can be in snake_case or camelCase (with snake_and_camel_case).

Parameters
  • dictionary: The dictionary to search in
  • keys: The keys to search for
  • snake_and_camel_case: Whether the keys can be in snake_case or camelCase