nattrs


Namenattrs JSON
Version 0.1.1 PyPI version JSON
download
home_pagehttps://github.com/ludvigolsen/nattrs
SummaryNested attribute getter/setter that works with dictionaries and objects interchangeably.
upload_time2023-03-15 10:08:33
maintainer
docs_urlNone
authorLudvig Renbo Olsen
requires_python>=3.7,<4.0
licenseMIT
keywords attributes dictionaries class recursive
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            nattrs
--------

**Nested attributes** utility functions for python. Allows getting/setting of object attributes and dict members interchangeably.
Useful to populate nested dicts for storing outputs of a loop.

Alpha stage. Subject to change.

> https://pypi.python.org/pypi/nattrs/     


# Installation

Install from pip:

```shell
pip install nattrs
```

Install from GitHub:

```shell
python -m pip install git+https://github.com/ludvigolsen/nattrs
```


# Main functions

| Class/Function   | Description |
|:-----------------|:------------|
| `nested_getattr` | Get object attributes/dict members recursively, given by dot-separated names |
| `nested_setattr` | Set object attribute/dict member by recursive lookup, given by dot-separated names. |
| `nested_mutattr` | Apply function (mutate) to object attribute/dict member by recursive lookup, given by dot-separated names. |
| `nested_hasattr` | Check whether recursive object attributes/dict members exist. |
| `populate_product` | Create and populate nested dicts with specified layers and the same leaf value. |


# Examples

Create class `B` with a dict `c` with the member `d`:

```python

class B:
    def __init__(self):
        self.c = {
            "d": 1
        }

```

Add to a dict `a`:

```python

a = {"b": B()}

```

## nested_getattr

Get the value of `d`:

```python

nested_getattr(a, "b.c.d")
>> 1

```

Get default value when not finding an attribute:

```python

nested_getattr(a, "b.o.p", default="not found")
>> "not found"

```

## nested_setattr

Set the value of `d`:

```python

nested_setattr(a, "b.c.d", 2)

```

Check new value of `d`:

```python

nested_getattr(a, "b.c.d")
>> 2

```

## nested_mutattr

Mutate `d` with an anonymous function (lambda):

```python

nested_mutattr(a, "b.c.d", lambda x: x * 5)

```

Check new value of `d`:

```python

nested_getattr(a, "b.c.d")
>> 10

```

Note: If your function performs the assignment *in-place*, remember to enable the `is_inplace_fn` argument.

## nested_hasattr

Check presence of the member 'd':

```python

nested_hasattr(a, "b.c.d")
>> True

```

Fail to find member 'o':

```python

nested_hasattr(a, "b.o.p")
>> False

```

## populate_product

In this example, we wish to pre-populate nested dicts with empty lists to allow appending within a `for` loop. First, we go through the manual approach of doing this. Second, we show how easy it is to do with `populate_product()`. 

Say we have 3 variables that can each hold 2 values. We want to compute *something* for each combination of these values. Let's first define these variables and their options:

```python

animal = ["cat", "dog"]
food = ["strawberry", "cucumber"]
temperature = ["cold", "warm"]

```

Let's generate the product of these options:

```python

import itertools

combinations = list(itertools.product(*[animal, food, temperature]))
combinations
>> [('cat', 'strawberry', 'cold'),
>>  ('cat', 'strawberry', 'warm'),
>>  ('cat', 'cucumber', 'cold'),
>>  ('cat', 'cucumber', 'warm'),
>>  ('dog', 'strawberry', 'cold'),
>>  ('dog', 'strawberry', 'warm'),
>>  ('dog', 'cucumber', 'cold'),
>>  ('dog', 'cucumber', 'warm')]

```

Now we can create a nested dict structure with a list in the leaf element:

```python

# Initialize empty dict
nested_dict = {}

for leaf in combinations:
    # Join each string with dot-separation:
    attr = ".".join(list(leaf))

    # Assign empty list to the leafs
    # `make_missing` creates dicts for each 
    # missing attribute/dict member
    nattrs.nested_setattr(
        obj=nested_dict,
        attr=attr,
        value=[],
        make_missing=True
    )

nested_dict
>> {'cat': {'strawberry': {'cold': [], 'warm': []},
>>          'cucumber':   {'cold': [], 'warm': []}},
>>  'dog': {'strawberry': {'cold': [], 'warm': []},
>>          'cucumber':   {'cold': [], 'warm': []}}}

```

This dict population is actually provided by `populate_product()`. Instead of an empty list, let's set the value to an "edibility" score that could be changed by a later function:

```python

layers = [animal, food, temperature]
populate_product(
    layers=layers,
    val=False
)
>> {'cat': {'strawberry': {'cold': False, 'warm': False},
>>          'cucumber':   {'cold': False, 'warm': False}},
>>  'dog': {'strawberry': {'cold': False, 'warm': False},
>>          'cucumber':   {'cold': False, 'warm': False}}}

```
            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ludvigolsen/nattrs",
    "name": "nattrs",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7,<4.0",
    "maintainer_email": "",
    "keywords": "attributes,dictionaries,class,recursive",
    "author": "Ludvig Renbo Olsen",
    "author_email": "mail@ludvigolsen.dk",
    "download_url": "https://files.pythonhosted.org/packages/05/50/657c0fb1b36776b408490a01bac43d723066eb3ccc5e8666f7caed3116f7/nattrs-0.1.1.tar.gz",
    "platform": null,
    "description": "nattrs\n--------\n\n**Nested attributes** utility functions for python. Allows getting/setting of object attributes and dict members interchangeably.\nUseful to populate nested dicts for storing outputs of a loop.\n\nAlpha stage. Subject to change.\n\n> https://pypi.python.org/pypi/nattrs/     \n\n\n# Installation\n\nInstall from pip:\n\n```shell\npip install nattrs\n```\n\nInstall from GitHub:\n\n```shell\npython -m pip install git+https://github.com/ludvigolsen/nattrs\n```\n\n\n# Main functions\n\n| Class/Function   | Description |\n|:-----------------|:------------|\n| `nested_getattr` | Get object attributes/dict members recursively, given by dot-separated names |\n| `nested_setattr` | Set object attribute/dict member by recursive lookup, given by dot-separated names. |\n| `nested_mutattr` | Apply function (mutate) to object attribute/dict member by recursive lookup, given by dot-separated names. |\n| `nested_hasattr` | Check whether recursive object attributes/dict members exist. |\n| `populate_product` | Create and populate nested dicts with specified layers and the same leaf value. |\n\n\n# Examples\n\nCreate class `B` with a dict `c` with the member `d`:\n\n```python\n\nclass B:\n    def __init__(self):\n        self.c = {\n            \"d\": 1\n        }\n\n```\n\nAdd to a dict `a`:\n\n```python\n\na = {\"b\": B()}\n\n```\n\n## nested_getattr\n\nGet the value of `d`:\n\n```python\n\nnested_getattr(a, \"b.c.d\")\n>> 1\n\n```\n\nGet default value when not finding an attribute:\n\n```python\n\nnested_getattr(a, \"b.o.p\", default=\"not found\")\n>> \"not found\"\n\n```\n\n## nested_setattr\n\nSet the value of `d`:\n\n```python\n\nnested_setattr(a, \"b.c.d\", 2)\n\n```\n\nCheck new value of `d`:\n\n```python\n\nnested_getattr(a, \"b.c.d\")\n>> 2\n\n```\n\n## nested_mutattr\n\nMutate `d` with an anonymous function (lambda):\n\n```python\n\nnested_mutattr(a, \"b.c.d\", lambda x: x * 5)\n\n```\n\nCheck new value of `d`:\n\n```python\n\nnested_getattr(a, \"b.c.d\")\n>> 10\n\n```\n\nNote: If your function performs the assignment *in-place*, remember to enable the `is_inplace_fn` argument.\n\n## nested_hasattr\n\nCheck presence of the member 'd':\n\n```python\n\nnested_hasattr(a, \"b.c.d\")\n>> True\n\n```\n\nFail to find member 'o':\n\n```python\n\nnested_hasattr(a, \"b.o.p\")\n>> False\n\n```\n\n## populate_product\n\nIn this example, we wish to pre-populate nested dicts with empty lists to allow appending within a `for` loop. First, we go through the manual approach of doing this. Second, we show how easy it is to do with `populate_product()`. \n\nSay we have 3 variables that can each hold 2 values. We want to compute *something* for each combination of these values. Let's first define these variables and their options:\n\n```python\n\nanimal = [\"cat\", \"dog\"]\nfood = [\"strawberry\", \"cucumber\"]\ntemperature = [\"cold\", \"warm\"]\n\n```\n\nLet's generate the product of these options:\n\n```python\n\nimport itertools\n\ncombinations = list(itertools.product(*[animal, food, temperature]))\ncombinations\n>> [('cat', 'strawberry', 'cold'),\n>>  ('cat', 'strawberry', 'warm'),\n>>  ('cat', 'cucumber', 'cold'),\n>>  ('cat', 'cucumber', 'warm'),\n>>  ('dog', 'strawberry', 'cold'),\n>>  ('dog', 'strawberry', 'warm'),\n>>  ('dog', 'cucumber', 'cold'),\n>>  ('dog', 'cucumber', 'warm')]\n\n```\n\nNow we can create a nested dict structure with a list in the leaf element:\n\n```python\n\n# Initialize empty dict\nnested_dict = {}\n\nfor leaf in combinations:\n    # Join each string with dot-separation:\n    attr = \".\".join(list(leaf))\n\n    # Assign empty list to the leafs\n    # `make_missing` creates dicts for each \n    # missing attribute/dict member\n    nattrs.nested_setattr(\n        obj=nested_dict,\n        attr=attr,\n        value=[],\n        make_missing=True\n    )\n\nnested_dict\n>> {'cat': {'strawberry': {'cold': [], 'warm': []},\n>>          'cucumber':   {'cold': [], 'warm': []}},\n>>  'dog': {'strawberry': {'cold': [], 'warm': []},\n>>          'cucumber':   {'cold': [], 'warm': []}}}\n\n```\n\nThis dict population is actually provided by `populate_product()`. Instead of an empty list, let's set the value to an \"edibility\" score that could be changed by a later function:\n\n```python\n\nlayers = [animal, food, temperature]\npopulate_product(\n    layers=layers,\n    val=False\n)\n>> {'cat': {'strawberry': {'cold': False, 'warm': False},\n>>          'cucumber':   {'cold': False, 'warm': False}},\n>>  'dog': {'strawberry': {'cold': False, 'warm': False},\n>>          'cucumber':   {'cold': False, 'warm': False}}}\n\n```",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Nested attribute getter/setter that works with dictionaries and objects interchangeably.",
    "version": "0.1.1",
    "split_keywords": [
        "attributes",
        "dictionaries",
        "class",
        "recursive"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "146cc87e7724ad5de1c972fa49d8ef55a0f7bc43f8aeb4a1f58873776c2b12e8",
                "md5": "0b2ca130f17fe14eaa7b737df0c94447",
                "sha256": "d117c0c7a9bc29705cc4d22463407c472392c455682125029e08fa56996fab86"
            },
            "downloads": -1,
            "filename": "nattrs-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0b2ca130f17fe14eaa7b737df0c94447",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7,<4.0",
            "size": 7407,
            "upload_time": "2023-03-15T10:08:32",
            "upload_time_iso_8601": "2023-03-15T10:08:32.111390Z",
            "url": "https://files.pythonhosted.org/packages/14/6c/c87e7724ad5de1c972fa49d8ef55a0f7bc43f8aeb4a1f58873776c2b12e8/nattrs-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0550657c0fb1b36776b408490a01bac43d723066eb3ccc5e8666f7caed3116f7",
                "md5": "c85ce2f6298bc5a397fd3208b755adf2",
                "sha256": "a106c537db90eca181083f5c7aca3b750ad7d003d7334d88693a725be0defddd"
            },
            "downloads": -1,
            "filename": "nattrs-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "c85ce2f6298bc5a397fd3208b755adf2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7,<4.0",
            "size": 6004,
            "upload_time": "2023-03-15T10:08:33",
            "upload_time_iso_8601": "2023-03-15T10:08:33.984669Z",
            "url": "https://files.pythonhosted.org/packages/05/50/657c0fb1b36776b408490a01bac43d723066eb3ccc5e8666f7caed3116f7/nattrs-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-03-15 10:08:33",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "ludvigolsen",
    "github_project": "nattrs",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "nattrs"
}
        
Elapsed time: 0.04698s