<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"
}