objectutils


Nameobjectutils JSON
Version 0.3.0 PyPI version JSON
download
home_pagehttps://github.com/Chmele/difflib/tree/main
SummaryUtils that extend default dict|list operations
upload_time2023-08-27 14:52:36
maintainer
docs_urlNone
authorChmele
requires_python
licenseMIT
keywords dict json jq jmespath
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # ```objectutils```

## Installation

```bash
pip install objectutils
```

## About
Tiny functions that extend python json-like objects functionality as highly customizable: 

- [traversing](#traverse)
- [transforming](#transformation)
- [flattening](#flatten)
- [sum](#zip_dicts)
- [diff](#using-as-diff-default-mapping-and-filter)

operations on json-like python objects(lists, dicts)

Allows writing comprehensions without comprehensions 🙃

>Only python 3.10+ supported

>Provided as python library and made to be used from python directly. 

Inspired by:
- [jmespath](https://jmespath.org)
- [jq](https://jqlang.github.io/jq/)


## Examples
### Having the following response from some API:

```python
obj = {"computers": [
        {
            "computername": "1",
            "software": ["s1", "s2"],
        },
        {
            "computername": "2",
            "software": ["s2", "s3"],
        },
        {
            "computername": "3",
            "software": ["s1", "s3"],
        },
    ]
}
```
### ```traverse```
You should write something like that to get the ```Counter``` of the software installed in total:

```python
from itertools import chain

c = Counter(chain.from_iterable([computer["software"] for computer in obj["computers"]]))
```

Such expressions getting even worse in more complicated cases.
With ```traverse``` method provided by this tiny lib you should do the following to get the same ```Counter```:

```python
from objectutils import traverse

c = traverse(obj, [Counter, chain.from_iterable, "computers", [], "software"])
```

```traverse``` supports callable objects in its path, as well as the keys of object.
```[]``` considered as all the possible values in iterable, as 'asterisk'(*).

> If applicable, calls the funcs and callable objects with unpacked iterable from the right. On exception that was predicted in this case, tries to call with single argument

As for me, it is much clearer approach than writing comprehensions or loops in such cases.

### Transformation
It is also possible to transform the data selected by traverse using dicts on the path, but this may be a bit tricky:
```python
traverse(
    {"old1": {"old2": "old3"}, "old4": "old5"}, 
    [
        {"new2": []}, 
        [{"new3": ["old1", "old2"], "new4": ["old4"]}, 
        {"anothernew4": ["old4"]}]
    ]
)

#Result {'new2': [{'new3': 'old3', 'new4': 'old5'}, {'anothernew4': 'old5'}]}
```

### ```flatten```
```python
from objectutils import flatten
```
Use ```flatten(obj)``` to get a flat dictionary in form ```{path: plain value}``` 
For the data above, the result is the following:
```python
{
    ("computers", 0, "computername"): "1",
    ("computers", 0, "software", 0): "s1",
    ("computers", 0, "software", 1): "s2",
    ("computers", 1, "computername"): "2",
    ("computers", 1, "software", 0): "s2",
    ("computers", 1, "software", 1): "s3",
    ("computers", 2, "computername"): "3",
    ("computers", 2, "software", 0): "s1",
    ("computers", 2, "software", 1): "s3",
}
```
### ```zip_dicts```
Used to join values of two similar dicts on same paths. May be used to find a diff betweens two dicts, join values as a sum

```python
from objectutils import zip_dicts


d1 = {
    1: {
        2: 3,
        3: 3,
    }
}
d2 = {
    1: {
        2: 4,
        3: 3,
    }
}
zip_dicts(d1, d2, lambda a, b: a+b, lambda a, b: a==b) # {1: {3: 6}} - "find a sum on all same paths where values are equal"
```
Third argument is a function for two items on the same paths, fourth is the filter for leaf dict values. 

#### Using as diff (default mapping and filter)
```python
d1 = {
    1: {
        3: 3,
        4: 2,
    }
}
d2 = {
    1: {
        3: 3,
        4: 3,
    }
}
zip_dicts(d1, d2) # {1: {4: (2, 3)}} - elements on path [1, 4] not equal(2 and 3 correspondingly)
```


The keys are the paths that may be used in ```traverse``` to get the value next to them. However intended usage is to reduce the path somehow, using ```".".join()``` or something like that

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Chmele/difflib/tree/main",
    "name": "objectutils",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "dict,json,jq,jmespath",
    "author": "Chmele",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/21/60/c45ee483cda738a887e4adb0738646a502806f53800419979e3ddb48c25a/objectutils-0.3.0.tar.gz",
    "platform": null,
    "description": "# ```objectutils```\n\n## Installation\n\n```bash\npip install objectutils\n```\n\n## About\nTiny functions that extend python json-like objects functionality as highly customizable: \n\n- [traversing](#traverse)\n- [transforming](#transformation)\n- [flattening](#flatten)\n- [sum](#zip_dicts)\n- [diff](#using-as-diff-default-mapping-and-filter)\n\noperations on json-like python objects(lists, dicts)\n\nAllows writing comprehensions without comprehensions \ud83d\ude43\n\n>Only python 3.10+ supported\n\n>Provided as python library and made to be used from python directly. \n\nInspired by:\n- [jmespath](https://jmespath.org)\n- [jq](https://jqlang.github.io/jq/)\n\n\n## Examples\n### Having the following response from some API:\n\n```python\nobj = {\"computers\": [\n        {\n            \"computername\": \"1\",\n            \"software\": [\"s1\", \"s2\"],\n        },\n        {\n            \"computername\": \"2\",\n            \"software\": [\"s2\", \"s3\"],\n        },\n        {\n            \"computername\": \"3\",\n            \"software\": [\"s1\", \"s3\"],\n        },\n    ]\n}\n```\n### ```traverse```\nYou should write something like that to get the ```Counter``` of the software installed in total:\n\n```python\nfrom itertools import chain\n\nc = Counter(chain.from_iterable([computer[\"software\"] for computer in obj[\"computers\"]]))\n```\n\nSuch expressions getting even worse in more complicated cases.\nWith ```traverse``` method provided by this tiny lib you should do the following to get the same ```Counter```:\n\n```python\nfrom objectutils import traverse\n\nc = traverse(obj, [Counter, chain.from_iterable, \"computers\", [], \"software\"])\n```\n\n```traverse``` supports callable objects in its path, as well as the keys of object.\n```[]``` considered as all the possible values in iterable, as 'asterisk'(*).\n\n> If applicable, calls the funcs and callable objects with unpacked iterable from the right. On exception that was predicted in this case, tries to call with single argument\n\nAs for me, it is much clearer approach than writing comprehensions or loops in such cases.\n\n### Transformation\nIt is also possible to transform the data selected by traverse using dicts on the path, but this may be a bit tricky:\n```python\ntraverse(\n    {\"old1\": {\"old2\": \"old3\"}, \"old4\": \"old5\"}, \n    [\n        {\"new2\": []}, \n        [{\"new3\": [\"old1\", \"old2\"], \"new4\": [\"old4\"]}, \n        {\"anothernew4\": [\"old4\"]}]\n    ]\n)\n\n#Result {'new2': [{'new3': 'old3', 'new4': 'old5'}, {'anothernew4': 'old5'}]}\n```\n\n### ```flatten```\n```python\nfrom objectutils import flatten\n```\nUse ```flatten(obj)``` to get a flat dictionary in form ```{path: plain value}``` \nFor the data above, the result is the following:\n```python\n{\n    (\"computers\", 0, \"computername\"): \"1\",\n    (\"computers\", 0, \"software\", 0): \"s1\",\n    (\"computers\", 0, \"software\", 1): \"s2\",\n    (\"computers\", 1, \"computername\"): \"2\",\n    (\"computers\", 1, \"software\", 0): \"s2\",\n    (\"computers\", 1, \"software\", 1): \"s3\",\n    (\"computers\", 2, \"computername\"): \"3\",\n    (\"computers\", 2, \"software\", 0): \"s1\",\n    (\"computers\", 2, \"software\", 1): \"s3\",\n}\n```\n### ```zip_dicts```\nUsed to join values of two similar dicts on same paths. May be used to find a diff betweens two dicts, join values as a sum\n\n```python\nfrom objectutils import zip_dicts\n\n\nd1 = {\n    1: {\n        2: 3,\n        3: 3,\n    }\n}\nd2 = {\n    1: {\n        2: 4,\n        3: 3,\n    }\n}\nzip_dicts(d1, d2, lambda a, b: a+b, lambda a, b: a==b) # {1: {3: 6}} - \"find a sum on all same paths where values are equal\"\n```\nThird argument is a function for two items on the same paths, fourth is the filter for leaf dict values. \n\n#### Using as diff (default mapping and filter)\n```python\nd1 = {\n    1: {\n        3: 3,\n        4: 2,\n    }\n}\nd2 = {\n    1: {\n        3: 3,\n        4: 3,\n    }\n}\nzip_dicts(d1, d2) # {1: {4: (2, 3)}} - elements on path [1, 4] not equal(2 and 3 correspondingly)\n```\n\n\nThe keys are the paths that may be used in ```traverse``` to get the value next to them. However intended usage is to reduce the path somehow, using ```\".\".join()``` or something like that\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Utils that extend default dict|list operations",
    "version": "0.3.0",
    "project_urls": {
        "Homepage": "https://github.com/Chmele/difflib/tree/main"
    },
    "split_keywords": [
        "dict",
        "json",
        "jq",
        "jmespath"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9d37e92c61c5c0c8f06ac148992a654d7a38ea2fc6c3a729cae7f09f8ed92afe",
                "md5": "7977abb2b94d34bce6173f3c2fa17e00",
                "sha256": "c37ef04b23cba6736137e34797ebef6829f90b1e2dc92128e7b7f856f04a3c0b"
            },
            "downloads": -1,
            "filename": "objectutils-0.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7977abb2b94d34bce6173f3c2fa17e00",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 9257,
            "upload_time": "2023-08-27T14:52:35",
            "upload_time_iso_8601": "2023-08-27T14:52:35.659973Z",
            "url": "https://files.pythonhosted.org/packages/9d/37/e92c61c5c0c8f06ac148992a654d7a38ea2fc6c3a729cae7f09f8ed92afe/objectutils-0.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2160c45ee483cda738a887e4adb0738646a502806f53800419979e3ddb48c25a",
                "md5": "b6eef54ecf59108015d804423b66deb9",
                "sha256": "0c5cca2bf74ef0d0c1a41a7c50eb9b8d73e7cf0f60fc16bf869833954d8ab63c"
            },
            "downloads": -1,
            "filename": "objectutils-0.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "b6eef54ecf59108015d804423b66deb9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 9642,
            "upload_time": "2023-08-27T14:52:36",
            "upload_time_iso_8601": "2023-08-27T14:52:36.653004Z",
            "url": "https://files.pythonhosted.org/packages/21/60/c45ee483cda738a887e4adb0738646a502806f53800419979e3ddb48c25a/objectutils-0.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-08-27 14:52:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Chmele",
    "github_project": "difflib",
    "github_not_found": true,
    "lcname": "objectutils"
}
        
Elapsed time: 0.12712s