decomply


Namedecomply JSON
Version 1.1.2 PyPI version JSON
download
home_pagehttps://github.com/truekenji/decomply
Summarydecomply allows unified processing of nested dictionaries
upload_time2024-08-20 07:23:59
maintainerNone
docs_urlNone
authorTrueKenji
requires_pythonNone
licenseNone
keywords dictionary recursive traverse apply decompose partition nested loop list json
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <h1>decomply</h1>
decomply (decomposeApply) is a short utility package, providing functionality to traverse nested dictionaries (or any enumerable object) and apply a custom function on their values.

Supports also lists, using their indexes as key. Additionally, custom handlers can be supplied to extend support to more types.

<h3>Example:</h3>
Consider a dictionary like this

~~~
input_data = {
    "First Layer": {
        "Second layer": 3,
        "Second layer 2nd element": 4
    },
    "First layer 2nd element": -1
}
~~~

Suppose you want to increment the numbers by 1. Then you can use

~~~
Decomply(
  apply=lambda _, item: item + 1
  ).decomply(input_data)
~~~

Output

~~~
{
  "First Layer": {
      "Second layer": 4,
      "Second layer 2nd element": 5
  },
  "First layer 2nd element": 0
}
~~~

decomply will traverse the dictionary, stopping at certain points. Then it will apply the desired function on the value at hand and "repeat" the process. In a sense, it decomposes the object into a partition and then applies a function on each part, hence the name decomposeApply, in short `decomply`

<h2>Install</h2>

`pip install decomply`

<h2>API</h2>

<h3>Decomply</h3>

The constructor's signature is 

~~~
def __init__(
    self,
    traverse: callable = lambda trace, item: True,
    apply: callable = lambda trace, item: item,
    delete: callable = lambda trace, item: str(trace[-1]).startswith("_"),
    handlers: set[EnumerableHandler] = None
):
~~~

Decomply accepts 4 parameters, each with a default value.
The first 3 parameters are callables, which all receive two parameters:
~~~
trace: a list of keys, reflecting the path to traverse to the current item
item: the current value
~~~

The callables are

~~~
apply: lambda: trace, item: item
~~~

`apply` is the function to be applied on the single items.  It defaults to returning the original item

~~~
traverse: lambda: trace, item: True
~~~

`traverse` allows to specify whether to keep traversing. If the function evaluates to `False`, traversal is stopped and `apply` is applied to the current item

~~~
delete: lambda: trace, item: str(trace[-1]).startswith("_")
~~~

`delete` allows to drop key/values entirely. Defaults to dropping those keys, which start with _, allowing a commenting-like functionality (especially useful when dealing with jsons).

The fourth parameter is a set of objects implementing the EnumerableHandler interface. Such a handler must be able to iterate through an associated object type and offer some more methods to handle.

<h2>decomply</h2>

To invoke, the decomply method is used. It's signature is

~~~
def decomply(self, item: Union[dict, list], trace: List[Union[str, int]] = None, initial_check: bool = True) -> dict:
~~~

It accepts 3 parameters:

~~~
item: Union[dict, list]
~~~

`item` is the object to decomply, either a nested dict or list. Both types can appear interchangeably within.

~~~
trace: List[Union[str, int]] = None
~~~

`trace` is a list of keys, which are used to traverse the item until a certain place. Typically this trace is initialized as an empty list

~~~
initial_check: bool = True
~~~

`initial_check` is a boolean indicating whether the passed item should already be tested against `self.traverse`.

<h3>Complete Example</h3>

Let's take the following input

~~~
input_data = {
    "First Layer": {
        "Second layer": 3,
        "_Second layer 2nd element": 4,
        "Second layer 3rd element": [
            42,
            69
        ]
    },
    "First layer 2nd element": {
        "fuu": {
            "fuu 1st entry": 6,
            "fuu 2nd entry": 10,
            "fuu 3rd entry": {
                "I will be dropped": 0
            }
        }
    }
}

Decomply(
    traverse = lambda _, item: not isinstance(item, list),
    apply = lambda _, item: item + [666] if isinstance(item, list) else item + 1,
    delete = lambda trace, _: len(trace) > 3
).decomply(input_data)
~~~

- traverse the dict as long as 
    - the next item is not a list
    - AND: the item is enumerable (<- this is a mandatory part of the traverse condition always attached within Decomply constructor) 
- When either condition fails, check out the item at hand. If it is
    - a list, extend it with the value 666
    - not a list, increment it by 1
- Delete all layers with a depth greater than 3

Output

~~~
{
    "First Layer": {
        "Second layer": 4,
        "_Second layer 2nd element": 5,
        "Second layer 3rd element": [
            42,
            69,
            666
        ]
    },
    "First layer 2nd element": {
        "fuu": {
            "fuu 1st entry": 7,
            "fuu 2nd entry": 11,
            "fuu 3rd entry": {}
        }
    }
}
~~~

I published a use case in my [jsgui](https://github.com/TrueKenji/jsgui) package, feel free to check it out for more complex examples.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/truekenji/decomply",
    "name": "decomply",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "Dictionary, Recursive, Traverse, Apply, Decompose, Partition, Nested, Loop, List, JSON",
    "author": "TrueKenji",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/ba/a3/5e25b864ec5b6c59277929b7c0eb59f7c5453ecffd21876c87fd26d37c0c/decomply-1.1.2.tar.gz",
    "platform": null,
    "description": "<h1>decomply</h1>\r\ndecomply (decomposeApply) is a short utility package, providing functionality to traverse nested dictionaries (or any enumerable object) and apply a custom function on their values.\r\n\r\nSupports also lists, using their indexes as key. Additionally, custom handlers can be supplied to extend support to more types.\r\n\r\n<h3>Example:</h3>\r\nConsider a dictionary like this\r\n\r\n~~~\r\ninput_data = {\r\n    \"First Layer\": {\r\n        \"Second layer\": 3,\r\n        \"Second layer 2nd element\": 4\r\n    },\r\n    \"First layer 2nd element\": -1\r\n}\r\n~~~\r\n\r\nSuppose you want to increment the numbers by 1. Then you can use\r\n\r\n~~~\r\nDecomply(\r\n  apply=lambda _, item: item + 1\r\n  ).decomply(input_data)\r\n~~~\r\n\r\nOutput\r\n\r\n~~~\r\n{\r\n  \"First Layer\": {\r\n      \"Second layer\": 4,\r\n      \"Second layer 2nd element\": 5\r\n  },\r\n  \"First layer 2nd element\": 0\r\n}\r\n~~~\r\n\r\ndecomply will traverse the dictionary, stopping at certain points. Then it will apply the desired function on the value at hand and \"repeat\" the process. In a sense, it decomposes the object into a partition and then applies a function on each part, hence the name decomposeApply, in short `decomply`\r\n\r\n<h2>Install</h2>\r\n\r\n`pip install decomply`\r\n\r\n<h2>API</h2>\r\n\r\n<h3>Decomply</h3>\r\n\r\nThe constructor's signature is \r\n\r\n~~~\r\ndef __init__(\r\n    self,\r\n    traverse: callable = lambda trace, item: True,\r\n    apply: callable = lambda trace, item: item,\r\n    delete: callable = lambda trace, item: str(trace[-1]).startswith(\"_\"),\r\n    handlers: set[EnumerableHandler] = None\r\n):\r\n~~~\r\n\r\nDecomply accepts 4 parameters, each with a default value.\r\nThe first 3 parameters are callables, which all receive two parameters:\r\n~~~\r\ntrace: a list of keys, reflecting the path to traverse to the current item\r\nitem: the current value\r\n~~~\r\n\r\nThe callables are\r\n\r\n~~~\r\napply: lambda: trace, item: item\r\n~~~\r\n\r\n`apply` is the function to be applied on the single items.  It defaults to returning the original item\r\n\r\n~~~\r\ntraverse: lambda: trace, item: True\r\n~~~\r\n\r\n`traverse` allows to specify whether to keep traversing. If the function evaluates to `False`, traversal is stopped and `apply` is applied to the current item\r\n\r\n~~~\r\ndelete: lambda: trace, item: str(trace[-1]).startswith(\"_\")\r\n~~~\r\n\r\n`delete` allows to drop key/values entirely. Defaults to dropping those keys, which start with _, allowing a commenting-like functionality (especially useful when dealing with jsons).\r\n\r\nThe fourth parameter is a set of objects implementing the EnumerableHandler interface. Such a handler must be able to iterate through an associated object type and offer some more methods to handle.\r\n\r\n<h2>decomply</h2>\r\n\r\nTo invoke, the decomply method is used. It's signature is\r\n\r\n~~~\r\ndef decomply(self, item: Union[dict, list], trace: List[Union[str, int]] = None, initial_check: bool = True) -> dict:\r\n~~~\r\n\r\nIt accepts 3 parameters:\r\n\r\n~~~\r\nitem: Union[dict, list]\r\n~~~\r\n\r\n`item` is the object to decomply, either a nested dict or list. Both types can appear interchangeably within.\r\n\r\n~~~\r\ntrace: List[Union[str, int]] = None\r\n~~~\r\n\r\n`trace` is a list of keys, which are used to traverse the item until a certain place. Typically this trace is initialized as an empty list\r\n\r\n~~~\r\ninitial_check: bool = True\r\n~~~\r\n\r\n`initial_check` is a boolean indicating whether the passed item should already be tested against `self.traverse`.\r\n\r\n<h3>Complete Example</h3>\r\n\r\nLet's take the following input\r\n\r\n~~~\r\ninput_data = {\r\n    \"First Layer\": {\r\n        \"Second layer\": 3,\r\n        \"_Second layer 2nd element\": 4,\r\n        \"Second layer 3rd element\": [\r\n            42,\r\n            69\r\n        ]\r\n    },\r\n    \"First layer 2nd element\": {\r\n        \"fuu\": {\r\n            \"fuu 1st entry\": 6,\r\n            \"fuu 2nd entry\": 10,\r\n            \"fuu 3rd entry\": {\r\n                \"I will be dropped\": 0\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nDecomply(\r\n    traverse = lambda _, item: not isinstance(item, list),\r\n    apply = lambda _, item: item + [666] if isinstance(item, list) else item + 1,\r\n    delete = lambda trace, _: len(trace) > 3\r\n).decomply(input_data)\r\n~~~\r\n\r\n- traverse the dict as long as \r\n    - the next item is not a list\r\n    - AND: the item is enumerable (<- this is a mandatory part of the traverse condition always attached within Decomply constructor) \r\n- When either condition fails, check out the item at hand. If it is\r\n    - a list, extend it with the value 666\r\n    - not a list, increment it by 1\r\n- Delete all layers with a depth greater than 3\r\n\r\nOutput\r\n\r\n~~~\r\n{\r\n    \"First Layer\": {\r\n        \"Second layer\": 4,\r\n        \"_Second layer 2nd element\": 5,\r\n        \"Second layer 3rd element\": [\r\n            42,\r\n            69,\r\n            666\r\n        ]\r\n    },\r\n    \"First layer 2nd element\": {\r\n        \"fuu\": {\r\n            \"fuu 1st entry\": 7,\r\n            \"fuu 2nd entry\": 11,\r\n            \"fuu 3rd entry\": {}\r\n        }\r\n    }\r\n}\r\n~~~\r\n\r\nI published a use case in my [jsgui](https://github.com/TrueKenji/jsgui) package, feel free to check it out for more complex examples.\r\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "decomply allows unified processing of nested dictionaries",
    "version": "1.1.2",
    "project_urls": {
        "Homepage": "https://github.com/truekenji/decomply"
    },
    "split_keywords": [
        "dictionary",
        " recursive",
        " traverse",
        " apply",
        " decompose",
        " partition",
        " nested",
        " loop",
        " list",
        " json"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4b04c43ba79db823af95dd7adb0599e7928846e172e7098d2ee57dcfeb8a941b",
                "md5": "8044b573d3638e599fb27cfca98e4dcb",
                "sha256": "28f3cf2cdba069351e769a3e5b2bb4245ba4983440d32a3c554879d28718184e"
            },
            "downloads": -1,
            "filename": "decomply-1.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8044b573d3638e599fb27cfca98e4dcb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 6893,
            "upload_time": "2024-08-20T07:23:57",
            "upload_time_iso_8601": "2024-08-20T07:23:57.571706Z",
            "url": "https://files.pythonhosted.org/packages/4b/04/c43ba79db823af95dd7adb0599e7928846e172e7098d2ee57dcfeb8a941b/decomply-1.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "baa35e25b864ec5b6c59277929b7c0eb59f7c5453ecffd21876c87fd26d37c0c",
                "md5": "f862092963ae1547dde5d8597225c964",
                "sha256": "c83227e9a3670cc58585db77f1b72d1d898fdbcc8ffc95601303d92508f1a3c6"
            },
            "downloads": -1,
            "filename": "decomply-1.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "f862092963ae1547dde5d8597225c964",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 6114,
            "upload_time": "2024-08-20T07:23:59",
            "upload_time_iso_8601": "2024-08-20T07:23:59.031341Z",
            "url": "https://files.pythonhosted.org/packages/ba/a3/5e25b864ec5b6c59277929b7c0eb59f7c5453ecffd21876c87fd26d37c0c/decomply-1.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-08-20 07:23:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "truekenji",
    "github_project": "decomply",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "decomply"
}
        
Elapsed time: 0.30682s