Skip to content

Dict

The tool to check the availability or syntax of domain, IP or URL.

::

██████╗ ██╗   ██╗███████╗██╗   ██╗███╗   ██╗ ██████╗███████╗██████╗ ██╗     ███████╗
██╔══██╗╚██╗ ██╔╝██╔════╝██║   ██║████╗  ██║██╔════╝██╔════╝██╔══██╗██║     ██╔════╝
██████╔╝ ╚████╔╝ █████╗  ██║   ██║██╔██╗ ██║██║     █████╗  ██████╔╝██║     █████╗
██╔═══╝   ╚██╔╝  ██╔══╝  ██║   ██║██║╚██╗██║██║     ██╔══╝  ██╔══██╗██║     ██╔══╝
██║        ██║   ██║     ╚██████╔╝██║ ╚████║╚██████╗███████╗██████╔╝███████╗███████╗
╚═╝        ╚═╝   ╚═╝      ╚═════╝ ╚═╝  ╚═══╝ ╚═════╝╚══════╝╚═════╝ ╚══════╝╚══════╝

Provides the dict helpers.

Author: Nissar Chababy, @funilrys, contactTATAfunilrysTODTODcom

Special thanks: https://pyfunceble.github.io/#/special-thanks

Contributors: https://pyfunceble.github.io/#/contributors

Project link: https://github.com/funilrys/PyFunceble

Project documentation: https://docs.pyfunceble.com

Project homepage: https://pyfunceble.github.io/

License: ::

Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

DictHelper

Simplify some :code:dict manipulation.

Parameters:

Name Type Description Default
main dict

The main :code:dict to work with.

required

Raises:

Type Description
TypeError

When :code:main is not a dict nor a list (tolarated).

Source code in PyFunceble/helpers/dict.py
class DictHelper:
    """
    Simplify some :code:`dict` manipulation.

    :param dict main: The main :code:`dict` to work with.
    :raise TypeError: When :code:`main` is not a dict nor a list (tolarated).
    """

    _subject: Optional[Union[Any, dict]] = None

    def __init__(self, subject: Optional[Union[Any, dict]] = None) -> None:
        if subject is not None:
            self.subject = subject

    @property
    def subject(self) -> Optional[Union[Any, dict]]:
        """
        Provides the current state of the :code:`_subject` attribute.
        """

        return self._subject

    @subject.setter
    def subject(self, value: Any) -> None:
        """
        Sets the subject to work with.

        :param value:
            The value to set.
        """

        self._subject = copy.deepcopy(value)

    def set_subject(self, value: Any) -> "DictHelper":
        """
        Sets the subject to work with.

        :param value:
            The value to set.
        """

        self.subject = value

        return self

    def has_same_keys_as(self, to_check: dict, loop: bool = False) -> bool:
        """
        Checks if keys are presents in both given :py:class:`dict`.

        :param to_check:
            The dict to compare with.
        :param loop:
            DO NOT USE, only used to tell us wen to return the list of dataset
            or the final result.
        """

        result = []

        for key, value in to_check.items():
            if key in self.subject:
                if isinstance(value, dict) and isinstance(self.subject[key], dict):
                    result.extend(
                        DictHelper(self.subject[key]).has_same_keys_as(value, loop=True)
                    )
                else:
                    result.append(True)
            else:
                result.append(False)
        if loop:
            return result
        return False not in result

    def remove_key(
        self, key_to_remove: Union[str, List[str]]
    ) -> Optional[Union[Any, dict]]:
        """
        Remove a given key from a given dictionary.

        :param key_to_remove: The key(s) to delete.

        :return: The dict without the given key(s).
        """

        if isinstance(self.subject, dict):
            if isinstance(key_to_remove, list):
                for key in key_to_remove:
                    self.remove_key(key)
            else:
                try:
                    del self.subject[key_to_remove]
                except KeyError:
                    pass
        return self.subject

    def rename_key(self, key_to_rename: dict, strict: bool = True) -> dict:
        """
        Rename the given keys from the given dictionary.

        :param key_to_rename:
            The key(s) to rename.

            Expected format: :code:`{old:new}`

        :param strict:
            Tell us if we have to rename the exact index or
            the index which looks like the given key(s)

        :return: The well formatted dict.
        """

        if isinstance(self.subject, dict) and isinstance(key_to_rename, dict):
            for old, new in key_to_rename.items():
                if strict:
                    if old in self.subject:
                        self.subject[new] = self.subject.pop(old)
                else:
                    to_rename = {}

                    for index in self.subject:
                        if old in index:
                            to_rename.update({index: new[:-1] + index.split(old)[-1]})

                    self.subject = DictHelper(self.subject).rename_key(to_rename, True)
        return self.subject

    def to_json_file(
        self,
        file_path: str,
        ensure_ascii: bool = False,
        indent: int = 4,
        sort_keys: bool = True,
        encoding: str = "utf-8",
        own_class: Optional[json.JSONEncoder] = None,
    ) -> None:
        """
        Converts the given :code:`dict` to JSON and save the result
        into a given file path.

        :param file_path: The file path.
        :param ensure_ascii: Avoids unicode.
        :param indent: The indentation to apply.
        :param sortkeys: Sorts the keys.
        :param encoding: The encoding to apply.
        :param own_class: A class to use for the conversion to json.
        """

        with open(file_path, "w", encoding=encoding) as file_stream:
            dump(
                self.subject,
                file_stream,
                ensure_ascii=ensure_ascii,
                indent=indent,
                sort_keys=sort_keys,
                cls=own_class,
            )

    @staticmethod
    def from_json_file(
        file_path: str, encoding: str = "utf-8", return_dict_on_error: bool = True
    ) -> Optional[Union[List[Any], dict]]:
        """
        Reads the given file path and convert it's content to
        dict/list (tolarated).

        :param file_path: The file path.
        :param return_dict_on_error: Return a dict instead of a NoneType.
        :parma encoding: The encoding to use.
        """

        try:
            return loads(FileHelper(path=file_path).read(encoding=encoding))
        except (decoder.JSONDecodeError, TypeError):
            return None if not return_dict_on_error else {}

    def to_json(
        self,
        ensure_ascii: bool = False,
        indent: int = 4,
        sort_keys: bool = True,
        own_class: Optional[json.JSONEncoder] = None,
    ) -> str:
        """
        Converts a given dict to JSON and return the json string.

        :param ensure_ascii: Avoids unicode.
        :param indent: The indentation to apply.
        :param sort_keys: Sort the keys.
        :param own_class: A class to use for the conversion to json.
        """

        return dumps(
            self.subject,
            ensure_ascii=ensure_ascii,
            indent=indent,
            sort_keys=sort_keys,
            cls=own_class,
        )

    @staticmethod
    def from_json(
        json_str: str, return_dict_on_error: bool = True
    ) -> Optional[Union[List[Any], dict]]:
        """
        Converts a given JSON string to dict/list.

        :param json_str: The JSON string ot convert.
        :param return_dict_on_error:
            Returns a :py:class:`dict` instead of a :py:class:`None`.
        """

        try:
            return loads(json_str)
        except (decoder.JSONDecodeError, TypeError):
            return None if not return_dict_on_error else {}

    @staticmethod
    def from_yaml_file(
        file_path: str, encoding: str = "utf-8"
    ) -> Union[List[Any], dict]:
        """
        Converts a given YAML formatted file, into dict/list.

        :param file_path: The file path.
        :param encoding: The encoding to use.
        """

        with open(file_path, "r", encoding=encoding) as file_stream:
            data = yaml_load(file_stream)

        return data

    def to_yaml_file(
        self,
        file_path: str,
        encoding: str = "utf-8",
        default_flow_style: bool = False,
        indent: int = 4,
        allow_unicode: bool = True,
        sort_keys: bool = True,
    ) -> None:
        """
        Converts the given dict/list to YAML and save the result into a file.

        :param file_path: The file path.
        :param encoding: The encoding.
        :param default_flow_style: Uses the default flow style.
        :param indent: The indentation to apply.
        :param allow_unicode: Allows the  decoding of unicode chars.
        :param sort_keys: Sorts the keys.
        """

        with open(file_path, "w", encoding=encoding) as file_stream:
            yaml_dump(
                self.subject,
                stream=file_stream,
                default_flow_style=default_flow_style,
                indent=indent,
                allow_unicode=allow_unicode,
                encoding=encoding,
                sort_keys=sort_keys,
            )

    @staticmethod
    def from_yaml(yaml_str) -> Union[List[Any], dict]:
        """
        Converts the given YAML string to dict/list.

        :param str yaml_str: The YAML string to convert.
        """

        return yaml_load(yaml_str)

    def to_yaml(
        self,
        encoding: str = "utf-8",
        default_flow_style: bool = False,
        indent: int = 4,
        allow_unicode: bool = True,
        sort_keys: bool = True,
    ) -> str:
        """
        Converts the given dict/list to the YAML format and return
        the result.

        :param str encoding: The encoding to use.
        :param bool default_flow_style: Uses the default flow style.
        :param int indent: The indentation to apply.
        :param bool allow_unicode: Allows the decoding of unicode chars.
        :param bool sort_keys: Sors the keys.

        :rtype: dict|list
        """

        return yaml_dump(
            self.subject,
            default_flow_style=default_flow_style,
            indent=indent,
            allow_unicode=allow_unicode,
            encoding=encoding,
            sort_keys=sort_keys,
        ).decode()

    def flatten(
        self,
        *,
        separator: str = ".",
        previous: Optional[str] = None,
        data: Optional[Any] = None,
    ) -> dict:
        """
        Flatten the current dictionnary.

        :param separator:
            The separator to apply.
        :param previous:
            The previous key we are working with.
        :param data:
            The data to work with. If not given, we fallback to :code:`self.subject`.
        """

        if data is None:
            data = self.subject

        result = {}

        if isinstance(data, dict):
            for key, value in data.items():
                for yek, eulav in (
                    DictHelper(value).flatten(separator=separator, previous=key).items()
                ):
                    if previous is not None:
                        result[f"{previous}{separator}{yek}"] = eulav
                    else:
                        result[yek] = eulav
        else:
            if previous:
                result[previous] = data
            else:
                result[separator] = data

        return result

    def unflatten(self, *, separator: str = ".", data: Optional[Any] = None):
        """
        Unflatten a previously flatten dictionnary.

        :param separator:
            The separator to split.
        """

        if data is None:
            data = self.subject

        result = {}

        for key, value in data.items():
            local_result = result

            if separator in key:
                splitted_sep = key.replace(separator + separator, separator).split(
                    separator
                )

                for yek in splitted_sep[:-1]:
                    if yek not in local_result:
                        local_result[yek] = {}

                    local_result = local_result[yek]
                local_result[splitted_sep[-1]] = value
            else:
                local_result[key] = value

        return result

subject property writable

Provides the current state of the :code:_subject attribute.

flatten(*, separator='.', previous=None, data=None)

Flatten the current dictionnary.

Parameters:

Name Type Description Default
separator str

The separator to apply.

'.'
previous Optional[str]

The previous key we are working with.

None
data Optional[Any]

The data to work with. If not given, we fallback to :code:self.subject.

None
Source code in PyFunceble/helpers/dict.py
def flatten(
    self,
    *,
    separator: str = ".",
    previous: Optional[str] = None,
    data: Optional[Any] = None,
) -> dict:
    """
    Flatten the current dictionnary.

    :param separator:
        The separator to apply.
    :param previous:
        The previous key we are working with.
    :param data:
        The data to work with. If not given, we fallback to :code:`self.subject`.
    """

    if data is None:
        data = self.subject

    result = {}

    if isinstance(data, dict):
        for key, value in data.items():
            for yek, eulav in (
                DictHelper(value).flatten(separator=separator, previous=key).items()
            ):
                if previous is not None:
                    result[f"{previous}{separator}{yek}"] = eulav
                else:
                    result[yek] = eulav
    else:
        if previous:
            result[previous] = data
        else:
            result[separator] = data

    return result

from_json(json_str, return_dict_on_error=True) staticmethod

Converts a given JSON string to dict/list.

Parameters:

Name Type Description Default
json_str str

The JSON string ot convert.

required
return_dict_on_error bool

Returns a class:dict instead of a class:None.

True
Source code in PyFunceble/helpers/dict.py
@staticmethod
def from_json(
    json_str: str, return_dict_on_error: bool = True
) -> Optional[Union[List[Any], dict]]:
    """
    Converts a given JSON string to dict/list.

    :param json_str: The JSON string ot convert.
    :param return_dict_on_error:
        Returns a :py:class:`dict` instead of a :py:class:`None`.
    """

    try:
        return loads(json_str)
    except (decoder.JSONDecodeError, TypeError):
        return None if not return_dict_on_error else {}

from_json_file(file_path, encoding='utf-8', return_dict_on_error=True) staticmethod

Reads the given file path and convert it's content to dict/list (tolarated).

:parma encoding: The encoding to use.

Parameters:

Name Type Description Default
file_path str

The file path.

required
return_dict_on_error bool

Return a dict instead of a NoneType.

True
Source code in PyFunceble/helpers/dict.py
@staticmethod
def from_json_file(
    file_path: str, encoding: str = "utf-8", return_dict_on_error: bool = True
) -> Optional[Union[List[Any], dict]]:
    """
    Reads the given file path and convert it's content to
    dict/list (tolarated).

    :param file_path: The file path.
    :param return_dict_on_error: Return a dict instead of a NoneType.
    :parma encoding: The encoding to use.
    """

    try:
        return loads(FileHelper(path=file_path).read(encoding=encoding))
    except (decoder.JSONDecodeError, TypeError):
        return None if not return_dict_on_error else {}

from_yaml(yaml_str) staticmethod

Converts the given YAML string to dict/list.

Parameters:

Name Type Description Default
yaml_str str

The YAML string to convert.

required
Source code in PyFunceble/helpers/dict.py
@staticmethod
def from_yaml(yaml_str) -> Union[List[Any], dict]:
    """
    Converts the given YAML string to dict/list.

    :param str yaml_str: The YAML string to convert.
    """

    return yaml_load(yaml_str)

from_yaml_file(file_path, encoding='utf-8') staticmethod

Converts a given YAML formatted file, into dict/list.

Parameters:

Name Type Description Default
file_path str

The file path.

required
encoding str

The encoding to use.

'utf-8'
Source code in PyFunceble/helpers/dict.py
@staticmethod
def from_yaml_file(
    file_path: str, encoding: str = "utf-8"
) -> Union[List[Any], dict]:
    """
    Converts a given YAML formatted file, into dict/list.

    :param file_path: The file path.
    :param encoding: The encoding to use.
    """

    with open(file_path, "r", encoding=encoding) as file_stream:
        data = yaml_load(file_stream)

    return data

has_same_keys_as(to_check, loop=False)

Checks if keys are presents in both given class:dict.

Parameters:

Name Type Description Default
to_check dict

The dict to compare with.

required
loop bool

DO NOT USE, only used to tell us wen to return the list of dataset or the final result.

False
Source code in PyFunceble/helpers/dict.py
def has_same_keys_as(self, to_check: dict, loop: bool = False) -> bool:
    """
    Checks if keys are presents in both given :py:class:`dict`.

    :param to_check:
        The dict to compare with.
    :param loop:
        DO NOT USE, only used to tell us wen to return the list of dataset
        or the final result.
    """

    result = []

    for key, value in to_check.items():
        if key in self.subject:
            if isinstance(value, dict) and isinstance(self.subject[key], dict):
                result.extend(
                    DictHelper(self.subject[key]).has_same_keys_as(value, loop=True)
                )
            else:
                result.append(True)
        else:
            result.append(False)
    if loop:
        return result
    return False not in result

remove_key(key_to_remove)

Remove a given key from a given dictionary.

Parameters:

Name Type Description Default
key_to_remove Union[str, List[str]]

The key(s) to delete.

required

Returns:

Type Description
Optional[Union[Any, dict]]

The dict without the given key(s).

Source code in PyFunceble/helpers/dict.py
def remove_key(
    self, key_to_remove: Union[str, List[str]]
) -> Optional[Union[Any, dict]]:
    """
    Remove a given key from a given dictionary.

    :param key_to_remove: The key(s) to delete.

    :return: The dict without the given key(s).
    """

    if isinstance(self.subject, dict):
        if isinstance(key_to_remove, list):
            for key in key_to_remove:
                self.remove_key(key)
        else:
            try:
                del self.subject[key_to_remove]
            except KeyError:
                pass
    return self.subject

rename_key(key_to_rename, strict=True)

Rename the given keys from the given dictionary.

Parameters:

Name Type Description Default
key_to_rename dict

The key(s) to rename. Expected format: :code:{old:new}

required
strict bool

Tell us if we have to rename the exact index or the index which looks like the given key(s)

True

Returns:

Type Description
dict

The well formatted dict.

Source code in PyFunceble/helpers/dict.py
def rename_key(self, key_to_rename: dict, strict: bool = True) -> dict:
    """
    Rename the given keys from the given dictionary.

    :param key_to_rename:
        The key(s) to rename.

        Expected format: :code:`{old:new}`

    :param strict:
        Tell us if we have to rename the exact index or
        the index which looks like the given key(s)

    :return: The well formatted dict.
    """

    if isinstance(self.subject, dict) and isinstance(key_to_rename, dict):
        for old, new in key_to_rename.items():
            if strict:
                if old in self.subject:
                    self.subject[new] = self.subject.pop(old)
            else:
                to_rename = {}

                for index in self.subject:
                    if old in index:
                        to_rename.update({index: new[:-1] + index.split(old)[-1]})

                self.subject = DictHelper(self.subject).rename_key(to_rename, True)
    return self.subject

set_subject(value)

Sets the subject to work with.

Parameters:

Name Type Description Default
value Any

The value to set.

required
Source code in PyFunceble/helpers/dict.py
def set_subject(self, value: Any) -> "DictHelper":
    """
    Sets the subject to work with.

    :param value:
        The value to set.
    """

    self.subject = value

    return self

to_json(ensure_ascii=False, indent=4, sort_keys=True, own_class=None)

Converts a given dict to JSON and return the json string.

Parameters:

Name Type Description Default
ensure_ascii bool

Avoids unicode.

False
indent int

The indentation to apply.

4
sort_keys bool

Sort the keys.

True
own_class Optional[JSONEncoder]

A class to use for the conversion to json.

None
Source code in PyFunceble/helpers/dict.py
def to_json(
    self,
    ensure_ascii: bool = False,
    indent: int = 4,
    sort_keys: bool = True,
    own_class: Optional[json.JSONEncoder] = None,
) -> str:
    """
    Converts a given dict to JSON and return the json string.

    :param ensure_ascii: Avoids unicode.
    :param indent: The indentation to apply.
    :param sort_keys: Sort the keys.
    :param own_class: A class to use for the conversion to json.
    """

    return dumps(
        self.subject,
        ensure_ascii=ensure_ascii,
        indent=indent,
        sort_keys=sort_keys,
        cls=own_class,
    )

to_json_file(file_path, ensure_ascii=False, indent=4, sort_keys=True, encoding='utf-8', own_class=None)

Converts the given :code:dict to JSON and save the result into a given file path.

Parameters:

Name Type Description Default
file_path str

The file path.

required
ensure_ascii bool

Avoids unicode.

False
indent int

The indentation to apply.

4
sortkeys

Sorts the keys.

required
encoding str

The encoding to apply.

'utf-8'
own_class Optional[JSONEncoder]

A class to use for the conversion to json.

None
Source code in PyFunceble/helpers/dict.py
def to_json_file(
    self,
    file_path: str,
    ensure_ascii: bool = False,
    indent: int = 4,
    sort_keys: bool = True,
    encoding: str = "utf-8",
    own_class: Optional[json.JSONEncoder] = None,
) -> None:
    """
    Converts the given :code:`dict` to JSON and save the result
    into a given file path.

    :param file_path: The file path.
    :param ensure_ascii: Avoids unicode.
    :param indent: The indentation to apply.
    :param sortkeys: Sorts the keys.
    :param encoding: The encoding to apply.
    :param own_class: A class to use for the conversion to json.
    """

    with open(file_path, "w", encoding=encoding) as file_stream:
        dump(
            self.subject,
            file_stream,
            ensure_ascii=ensure_ascii,
            indent=indent,
            sort_keys=sort_keys,
            cls=own_class,
        )

to_yaml(encoding='utf-8', default_flow_style=False, indent=4, allow_unicode=True, sort_keys=True)

Converts the given dict/list to the YAML format and return the result.

Parameters:

Name Type Description Default
encoding str

The encoding to use.

'utf-8'
default_flow_style bool

Uses the default flow style.

False
indent int

The indentation to apply.

4
allow_unicode bool

Allows the decoding of unicode chars.

True
sort_keys bool

Sors the keys.

True
Source code in PyFunceble/helpers/dict.py
def to_yaml(
    self,
    encoding: str = "utf-8",
    default_flow_style: bool = False,
    indent: int = 4,
    allow_unicode: bool = True,
    sort_keys: bool = True,
) -> str:
    """
    Converts the given dict/list to the YAML format and return
    the result.

    :param str encoding: The encoding to use.
    :param bool default_flow_style: Uses the default flow style.
    :param int indent: The indentation to apply.
    :param bool allow_unicode: Allows the decoding of unicode chars.
    :param bool sort_keys: Sors the keys.

    :rtype: dict|list
    """

    return yaml_dump(
        self.subject,
        default_flow_style=default_flow_style,
        indent=indent,
        allow_unicode=allow_unicode,
        encoding=encoding,
        sort_keys=sort_keys,
    ).decode()

to_yaml_file(file_path, encoding='utf-8', default_flow_style=False, indent=4, allow_unicode=True, sort_keys=True)

Converts the given dict/list to YAML and save the result into a file.

Parameters:

Name Type Description Default
file_path str

The file path.

required
encoding str

The encoding.

'utf-8'
default_flow_style bool

Uses the default flow style.

False
indent int

The indentation to apply.

4
allow_unicode bool

Allows the decoding of unicode chars.

True
sort_keys bool

Sorts the keys.

True
Source code in PyFunceble/helpers/dict.py
def to_yaml_file(
    self,
    file_path: str,
    encoding: str = "utf-8",
    default_flow_style: bool = False,
    indent: int = 4,
    allow_unicode: bool = True,
    sort_keys: bool = True,
) -> None:
    """
    Converts the given dict/list to YAML and save the result into a file.

    :param file_path: The file path.
    :param encoding: The encoding.
    :param default_flow_style: Uses the default flow style.
    :param indent: The indentation to apply.
    :param allow_unicode: Allows the  decoding of unicode chars.
    :param sort_keys: Sorts the keys.
    """

    with open(file_path, "w", encoding=encoding) as file_stream:
        yaml_dump(
            self.subject,
            stream=file_stream,
            default_flow_style=default_flow_style,
            indent=indent,
            allow_unicode=allow_unicode,
            encoding=encoding,
            sort_keys=sort_keys,
        )

unflatten(*, separator='.', data=None)

Unflatten a previously flatten dictionnary.

Parameters:

Name Type Description Default
separator str

The separator to split.

'.'
Source code in PyFunceble/helpers/dict.py
def unflatten(self, *, separator: str = ".", data: Optional[Any] = None):
    """
    Unflatten a previously flatten dictionnary.

    :param separator:
        The separator to split.
    """

    if data is None:
        data = self.subject

    result = {}

    for key, value in data.items():
        local_result = result

        if separator in key:
            splitted_sep = key.replace(separator + separator, separator).split(
                separator
            )

            for yek in splitted_sep[:-1]:
                if yek not in local_result:
                    local_result[yek] = {}

                local_result = local_result[yek]
            local_result[splitted_sep[-1]] = value
        else:
            local_result[key] = value

    return result