Coder Social home page Coder Social logo

addict's Introduction

addict

Tests Coverage Status PyPI version Anaconda-Server Badge

addict is a Python module that gives you dictionaries whose values are both gettable and settable using attributes, in addition to standard item-syntax.

This means that you don't have to write dictionaries like this anymore:

body = {
    'query': {
        'filtered': {
            'query': {
                'match': {'description': 'addictive'}
            },
            'filter': {
                'term': {'created_by': 'Mats'}
            }
        }
    }
}

Instead, you can simply write the following three lines:

body = Dict()
body.query.filtered.query.match.description = 'addictive'
body.query.filtered.filter.term.created_by = 'Mats'

Installing

You can install via pip

pip install addict

or through conda

conda install addict -c conda-forge

Addict runs on Python 2 and Python 3, and every build is tested towards 2.7, 3.6 and 3.7.

Usage

addict inherits from dict, but is more flexible in terms of accessing and setting its values. Working with dictionaries are now a joy! Setting the items of a nested Dict is a dream:

>>> from addict import Dict
>>> mapping = Dict()
>>> mapping.a.b.c.d.e = 2
>>> mapping
{'a': {'b': {'c': {'d': {'e': 2}}}}}

If the Dict is instantiated with any iterable values, it will iterate through and clone these values, and turn dicts into Dicts. Hence, the following works

>>> mapping = {'a': [{'b': 3}, {'b': 3}]}
>>> dictionary = Dict(mapping)
>>> dictionary.a[0].b
3

but mapping['a'] is no longer the same reference as dictionary['a'].

>>> mapping['a'] is dictionary['a']
False

This behavior is limited to the constructor, and not when items are set using attribute or item syntax, references are untouched:

>>> a = Dict()
>>> b = [1, 2, 3]
>>> a.b = b
>>> a.b is b
True

Stuff to keep in mind

Remember that ints are not valid attribute names, so keys of the dict that are not strings must be set/get with the get-/setitem syntax

>>> addicted = Dict()
>>> addicted.a.b.c.d.e = 2
>>> addicted[2] = [1, 2, 3]
{2: [1, 2, 3], 'a': {'b': {'c': {'d': {'e': 2}}}}}

However feel free to mix the two syntaxes:

>>> addicted.a.b['c'].d.e
2

Attributes like keys, items etc.

addict will not let you override attributes that are native to dict, so the following will not work

>>> mapping = Dict()
>>> mapping.keys = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "addict/addict.py", line 53, in __setattr__
    raise AttributeError("'Dict' object attribute '%s' is read-only" % name)
AttributeError: 'Dict' object attribute 'keys' is read-only

However, the following is fine

>>> a = Dict()
>>> a['keys'] = 2
>>> a
{'keys': 2}
>>> a['keys']
2

just like a regular dict. There are no restrictions (other than what a regular dict imposes) regarding what keys you can use.

Default values

For keys that are not in the dictionary, addict behaves like defaultdict(Dict), so missing keys return an empty Dict rather than raising KeyError. If this behaviour is not desired, it can be overridden using

>>> class DictNoDefault(Dict):
>>>     def __missing__(self, key):
>>>         raise KeyError(key)

but beware that you will then lose the shorthand assignment functionality (addicted.a.b.c.d.e = 2).

Recursive Fallback to dict

If you don't feel safe shipping your addict around to other modules, use the to_dict()-method, which returns a regular dict clone of the addict dictionary.

>>> regular_dict = my_addict.to_dict()
>>> regular_dict.a = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'a'

This is perfect for when you wish to create a nested Dict in a few lines, and then ship it on to a different module.

body = Dict()
body.query.filtered.query.match.description = 'addictive'
body.query.filtered.filter.term.created_by = 'Mats'
third_party_module.search(query=body.to_dict())

Counting

Dict's ability to easily access and modify deeply-nested attributes makes it ideal for counting. This offers a distinct advantage over collections.Counter, as it will easily allow for counting by multiple levels.

Consider this data:

data = [
    {'born': 1980, 'gender': 'M', 'eyes': 'green'},
    {'born': 1980, 'gender': 'F', 'eyes': 'green'},
    {'born': 1980, 'gender': 'M', 'eyes': 'blue'},
    {'born': 1980, 'gender': 'M', 'eyes': 'green'},
    {'born': 1980, 'gender': 'M', 'eyes': 'green'},
    {'born': 1980, 'gender': 'F', 'eyes': 'blue'},
    {'born': 1981, 'gender': 'M', 'eyes': 'blue'},
    {'born': 1981, 'gender': 'F', 'eyes': 'green'},
    {'born': 1981, 'gender': 'M', 'eyes': 'blue'},
    {'born': 1981, 'gender': 'F', 'eyes': 'blue'},
    {'born': 1981, 'gender': 'M', 'eyes': 'green'},
    {'born': 1981, 'gender': 'F', 'eyes': 'blue'}
]

If you want to count how many people were born in born of gender gender with eyes eyes, you can easily calculate this information:

counter = Dict()

for row in data:
    born = row['born']
    gender = row['gender']
    eyes = row['eyes']

    counter[born][gender][eyes] += 1

print(counter)
{1980: {'M': {'blue': 1, 'green': 3}, 'F': {'blue': 1, 'green': 1}}, 1981: {'M': {'blue': 2, 'green': 1}, 'F': {'blue': 2, 'green': 1}}}

Update

addicts update functionality is altered for convenience from a normal dict. Where updating nested item using a dict would overwrite it:

>>> d = {'a': {'b': 3}}
>>> d.update({'a': {'c': 4}})
>>> print(d)
{'a': {'c': 4}}

addict will recurse and actually update the nested Dict.

>>> D = Dict({'a': {'b': 3}})
>>> D.update({'a': {'c': 4}})
>>> print(D)
{'a': {'b': 3, 'c': 4}}

When is this especially useful?

This module rose from the entirely tiresome creation of Elasticsearch queries in Python. Whenever you find yourself writing out dicts over multiple lines, just remember that you don't have to. Use addict instead.

Perks

As it is a dict, it will serialize into JSON perfectly, and with the to_dict()-method you can feel safe shipping your addict anywhere.

Testing, Development and CI

Issues and Pull Requests are more than welcome. Feel free to open an issue to spark a discussion around a feature or a bug, or simply reply to the existing ones. As for Pull Requests, keeping in touch with the surrounding code style will be appreciated, and as such, writing tests are crucial. Pull requests and commits will be automatically run against TravisCI and coveralls.

The unit tests are implemented in the test_addict.py file and use the unittest python framework. Running the tests is rather simple:

python -m unittest -v test_addict

# - or -
python test_addict.py

Testimonials

@spiritsack - "Mother of God, this changes everything."

@some guy on Hacker News - "...the purpose itself is grossly unpythonic"

addict's People

Contributors

adamtheturtle avatar alvynmcq avatar burk avatar grundic avatar hl037 avatar iiseymour avatar jhermann avatar jwilk avatar loonghao avatar mewwts avatar mistervladimir avatar nicolewhite avatar ohjeah avatar sabhiram avatar sbillaudelle avatar spiritsack avatar stevenmaude avatar sumukhbarve avatar svisser avatar thefourtheye avatar timgates42 avatar tritemio avatar who8mylunch avatar zulko avatar zxf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

addict's Issues

Handle setdefault on proxy dicts

With 2.0.0, the following pattern I was using is broken:

command.environment.setdefault('variables', []).append(value)

The idea here is that command['environment']['variables'] is a list of dicts, but any part of that path might or might not exist. In 1.x, the command.environment would actually insert a environment key into command. In 2.0.0, the environment dict is created but not inserted into the parent, because there is no setitem.

Proposal: all mutating member functions of Dict (specifically including setdefault) should insert into the parent.

Is turning dicts in to Dicts unwanted behaviour?

Some people have over the weekend expressed their concern that the fact that we are not keeping the original dict-object, merely a Dict-clone of it, in our Dict, might be dangerous. In situations where you do

>>> something = {'a': [1, 2, 3]}
>>> a  = Dict(something)
>>> something['a'].append(4)
>>> a
 {'a': [1, 2, 3]}
>>> something
 {'a': [1, 2, 3, 4]}

I completely understand this concern. Perhaps Dict.init may have a parameter to control this behaviour, during construction. And then we remove this for dicts that are added not through Dict.init. Something in the lines of:

>>> a = Dict({'b': {'c': 2}}, addicted=True)
>>> a.b.d = {'e': 3}
>>> a
{'b': {'c': 2, 'd': {'e': 3}}}
>>> a.b.d.f = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'dict'

Attributes lost from Dict child classes

When I implement my own class that inherits from Dict, I get an error accessing the attributes of the nested items. That is, anything besides the top node does not contain my class' attributes.

The class:

from six import string_types
from collections import Iterable
from addict import Dict


def isiterable(arg):
    # copied from
    # https://stackoverflow.com/questions/1055360/how-to-tell-a-variable-is-iterable-but-not-a-string/44328500#44328500
    return isinstance(arg, Iterable) and not isinstance(arg, string_types)


class IndexedDict(Dict):
    """
    Allows setting and getting keys/values by passing in the key index. 

    We cannot use an integer key to set a value to None. The workaround is to
    use a slice:
    >>> d = IndexedDict()
    >>> d['a'] = 0
    >>> d.iloc(slice(1), [None])
    >>> d
    {'a': None}
    """
    def _get_with_int(self, key, value):
        return self[key]

    def _get_with_slice(self, key, value):
        return [self[k] for k in key]

    def _set_with_int(self, key, value):
        self[key] = value

    def _set_with_slice(self, key, value):
        for k, v in zip(key, value):
            self[k] = v

    def iloc(self, i, value=None):
        # throws IndexError if the key has not already been set
        keys = list(self.keys())[i]
        method_dict = {(True, False): self._get_with_int,
                       (True, True): self._get_with_slice,
                       (False, False): self._set_with_int,
                       (False, True): self._set_with_slice}

        method = method_dict[(value is None, 
                              isiterable(keys) and isiterable(value))]
        return method(keys, value)

The errors come up when I do:

d = IndexedDict()
d['a']['b']['c'] = 5
type(d['a']['b']) # returns Dict
# set value of 'c' key to 1
# tries to call iloc() on Dict
d['c'].iloc(0, 1)

I think this can be fixed by changing __getitem__ to return a instance of self.__class__ instead of Dict.

def __getitem__(self, name):
    if name not in self:
        return self.__class__(__parent=self, __key=name)
    return super().__getitem__(name)

or maybe instead of using the if/then statement in __getitem__ we could just add a __missing__ method and get rid of __getitem__ altogether. Besides the if/then statement, as it stands Dict's __getitem__ is the same as dict.__getitem__

def __missing__(self, name):
    return self.__class__(__parent=self, __key=name)

instead of

def __getitem__(self, name):
    if name not in self:
        return Dict(__parent=self, __key=name)
    return super().__getitem__(name)

To be consistent, I'd also change any references to super(Dict, self) to super() e.g. in __deepcopy__.

Dict kwargs recursive wrapping breaks reference assignment

After #92 you can't make reference from Dict to Dict when creating instance:

>>> from addict import Dict
>>> d = Dict(a=1, b=2)
>>> a = Dict(d=d)
>>> a.d
{'a': 1, 'b': 2}
>>> d
{'a': 1, 'b': 2}
>>> a.d is d
False
>>>

I expect, that changes to a.d will affect d.

Add functionality to flat entries

It would be helpful to flat entries like:

>>> foo = {'foo': {'bar': 'baz', 'qux': 'corge'}}
>>> # to
>>> foo
{'foo:bar': 'baz', 'foo:qux': 'corge'}

To save complex structures in a simple key value store.

why is it different than AttrDict module?

(I'm not the author of attrDict)

attrDict does the same dict -to- attribute, dual-interface. It is relativly mature, and has a relatively large user base, and actively maintained and developed.

The main difference i saw so far is Addict's ability to create multiple-child default keys (a.b.c.d = 5), which doesn't exist in AttrDict (But it probably should be included.)

and -- Would you consider joining forces?
or at least inheriting each other's code?

addict outputs {&#39;__unicode__&#39;: {}} rather than empty string when used in django templates.

Here is a rough idea of the code I'm running:

from addict import Dict
def get_dictionary(self, orig_dict):
    new_dict = Dict({'default_key':'default_value'})
    if(orig_dict["code"]==0):
        new_dict.other_key = "Double Quoted String"
    elif(orig_dict["code"]==1):
        new_dict.other_key = "Different Double Quoted String"
    return new_dict

and eventually when I use it with Django's render_to_string("xml_template.xml",dictionary=context_dictionary) into this template:

<ParentTag>
    <MyFirstTag>{{new_dict.default_key}}</MyFirstTag>
    <MySecondTag>{{new_dict.other_key}}</MySecondTag>
</ParentTag>

And it renders as:

<ParentTag>
    <MyFirstTag>default_value</MyFirstTag>
    <MySecondTag>{&#39;__unicode__&#39;: {}</MySecondTag>
</ParentTag>

I think that (for some reason) addict is returning an empty dictionary, but the output is being mangled. I know the docs say you can use to_dict() but it implies you don't need to.

Any idea why this happens?

Nested dicts create nested attributes on Dict(), but not on update()

pip installed addict 2.2.0 on Python 2.7.12/Ubuntu 16.04.5 LTS

If you create Dict() with initial data, all the nested dicts are converted to attributes.
If you update an existing Dict(), the nested dicts remain dicts and nested attributes are not created.

[This, by the way, is contrary to what happens with the two analogues AttrDict and EasyDict. Those two, on the other hand, do not support creation of nested attributes on the fly at assignment, like d=Dict() d.a.b.c=1 ]

>>> from addict import Dict
>>> d={'A': 1, 'B': { 'C':2, 'D':3 }}
>>> x=Dict(d)
>>> x.B
{'C': 2, 'D': 3}
>>> x.B.C
2
>>> y=Dict()
>>> y.update(d)
>>> y.B # appears similar
{'C': 2, 'D': 3}
>>> y.B.C
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'C'

Document that update works differently to normally dictionary

Looking at the source of addict, I noticed that the update method helpfully recurses into nested dictionary to do the update. That isn't documented though, and could be a surprise since it's inconsistent with the base dict class. For example:

>>> d = {'a': {'b': 3}}
>>> d.update({'a': {'c': 4}})
>>> print(d)
{'a': {'c': 4}}
>>> D = Dict({'a': {'b': 3}})
>>> D.update({'a': {'c': 4}})
>>> print(D)
{'a': {'b': 3, 'c': 4}}

Assigning to element of array does not make dicts get wrapped

I've already made a PR for this, apologies if this is excessive. I would like to be able to assign dicts to parts of arrays and still have the dicts wrapped by addict.

p = Dict()
p.a = [{'b':'works'}]
print (p.a[0].b) # b
p.a[0] = {'b':'does not work'}
print (p.a[0].b) # raises exception

consistency of key name restriction

Should we restrict key name in both case?

a = Dict()
a.clear = 2 # AttributeError raised
a['clear'] = 2 # a = {'clear': 2}
print(a.clear) # <built-in method clear of Dict object at 0x01D28C00>
print(a['clear']) # 2

关键字冲突

当我使用图灵机器人时,在返回值中有字段与内建函数名重复,这时使用点语法会报错,请问该如何避免呢

assign

would be great to assign nested levels using double underscores like that:

d = Dict(
a__b__c=1,
z__f__g=2
)

Cannot initialize from zip

dict(zip(['b'], [1]))
>>> {'b': 1}

works, but

Dict(zip(['b'], [1]))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-6ff6a8001986> in <module>()
----> 1 Dict(zip(['b'], [1]))

/home/mq/miniconda3/envs/4cast/lib/python3.5/site-packages/addict/addict.py in __init__(self, *args, **kwargs)
     53             else:
     54                 raise TypeError("Dict does not understand "
---> 55                                 "{0} types".format(type(arg)))
     56 
     57         for key, val in kwargs.items():

TypeError: Dict does not understand <class 'zip'> types

fails.

I think you should change isgenerator to isiterable in
https://github.com/mewwts/addict/blob/master/addict/addict.py#L50

Optionally based on OrderedDict

I'm thinking it would be nice to be able to use this with OrderedDict, such that the order things were put into the dict is the same order they come out when dumped to json for an api endpoint.

Maybe something like the following where

import json
from addict import Dict
...
response = Dict(ordered=True)
response.count = len(results)
response.next = next_url
response.prev = prev_url
response.results = results

print(json.dumps(response))

prints the following in order:

{
    "count": 435,
    "next": "/.../?page=2",
    "prev": null,
    "results": [
        ...
    ]
}

Thoughts?

hasattr behaviour

Hi, I encountered this, when writing an extension to addict.Dict..
I don't think this behaviour is what would be expected..

In [1]: import addict

In [2]: addict.__version__
Out[2]: '2.0.0'

In [3]: d = addict.Dict()

In [4]: hasattr(d, 'this_should_not_exist')
Out[4]: True

IPython autocomplete on Dict keys?

I love the whole concept behind this package! Thanks for making it real.

I spend a lot of time in IPython looking at data and prototyping pieces of my projects. In that environment it is very natural to hit tab and expect autocomplete to show a nice list of available attributes.

The sad part is this doesn't work for the keys of addict's Dicts. This was also noted in another Issue topic: #26 . I don't really know the mechanics of how IPython's autocomplete does its thing. Easy or complicated? I might look into that just to satisfy my curiosity.

base on OrderedDict?

OrderedDict is another dict library inherits to python's dict.
why not base on it ?

__getitem__ subclassing issue for new 2.2.0

Hi I want to say thank you first as I used a lot addict, it's a very nice module!

I upgraded from 2.1.3 to 2.2.0 and encountered this problem:

return self.__class__(__parent=self, __key=name)
TypeError: __init__() got an unexpected keyword argument '__key'

My code:

class PLAYER( Dict ):
    def __init__(self, pid):
        super(PLAYER, self).__init__()
        self.pid = pid

    def __getitem__ (self, name):
        out = super(PLAYER, self).__getitem__(name)   ### ONLY compatible with addict 2.1.3
        if out == {}:
            return getattr(PLAYERDB(self.pid), name)
        else:
            return out

The same code was working perfectly fine with 2.1.3. But for 2.2.0, it has to be solved by:
out = super(PLAYER, self).get( name, {})

However, I wonder if I were wrong at beginning . Since it is stated that 2.2.0 has been improved for better subclassing, please let me know any better subclassing suggestion for the same purpose. The goal is simple: if there was a missing key in PLAYER, return key from PLAYERDB object.

Sorry for my English. Thanks for your help!

Configure default value when key doesn't exist?

Hi folks, great library! I really need the ability to specify a default value when I request a key that doesn't exist, instead of getting an empty Dict as a result. Would this be possible? I'm happy to contribute the code myself if this seems like something you'd want. None, empty string, or anything like that would be great. The other tools I'm using (mongoengine) are barfing because they don't know how to cast an empty Dict to any other type.

Thanks!

Deep merge ( aka jQuery.extend() )

Yesterday I was coding some stuff in Python and I was searching for something that is doing a deep merge of two native dictionaries, and I found this https://www.xormedia.com/recursively-merge-dictionaries-in-python/

Is working awesomely and is doing exactly what jQuery.extend() is doing also. Are you going to merge this awesome stuff in your library as well? The only that I missed while I was reading the README was exactly this.

I'm pretty much sure that this will make it more and more awesome :) Thanks in advice!

conflict on accessing dict methods/attributes

from addict import Dict
a = Dict()
a.items = 'foo'
for k,v in a.items():
    print k,v

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable

I missed one

This guy isn't really adding much value anymore :)

    def __delitem__(self, name):
        """
        Is invoked when del some_instance_of_Dict[b] is called.
        """
        super(Dict, self).__delitem__(name)

License file in pypi archive

The pypi source archive isn't including the LICENSE file. Would it be possible to add it? It is very helpful when packaging this for Linux distributions. Thank you.

Addict: AttributeError: 'dict' object has no attribute 'foo'

Addict: AttributeError: 'dict' object has no attribute 'foo'

In [1]: from addict import Dict

In [2]: x = Dict()

In [3]: x.y = {}

In [4]: x.y.foo = "bar"
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-810a47f3f91e> in <module>()
----> 1 x.y.foo = "bar"

AttributeError: 'dict' object has no attribute 'foo'

If you must have this functionality, one option is to downgrade to the latest prior release that supported the old behavior:

sudo pip install --upgrade addict==0.5.1

... but the better option is to fix your code by just completely removing the x.y = {} (if possible), since everything inside the Dict will always be a Dict by default unless set otherwise.

This option was changed due to discussion in #29 and @mewwts decided (correctly) that Dict should not automatically convert dict to Dict.

This issue added for google juice, closing now.

Try to make a list inside dict

Hi,

I'm maybe didn't use the declaration correctly but I try to make something like:
my_query = Dict()
my_query.query.filtered.filter.bool['must'].bool['should'] = [{'term': {'id': 'foo'}....
this generate the following syntax :
{'query': {'filtered': {'filter': {'bool': {'must': {'bool':...
and not {'query': {'filtered': {'filter': {'bool': {'must': [{'bool':...
as I expected.

What is the good way to perform this?

Thanks for any help!

Read Only version

How can I make this read-only and when you try to add an attribute it will raise an exception, something like a Frozen Addict.

Also why does this create an empty dict on when trying to access an attribute that does not exist. It should raise an exception unless you are setting an attribute that does not exist

test_copy(self) is wrong?

test_copy appears to be a copy of the deep copy test, and not correct

    a = Dict()
    a.child.immutable = 42
    a.child.mutable = foo

    b = a.copy()

    # immutable object should not change
    b.child.immutable = 21
    self.assertEqual(a.child.immutable, 42)

the last line should read

    self.assertEqual(a.child.immutable, 21)

The copy() should be a shallow copy with b.child pointing to the same object as a.child, so have been changed to 21.

`self` can't be used as a key

Dict(self='this')
>>> TypeError: __init__() got multiple values for keyword argument 'self'

That's because init method is present and has self parameter.

There are several ways to overcome this issue:

  1. rename self parameter in init method to some unique string/guid. Here how it could look like:
    def __init__(_8629116b_4d94_42d9_bee1_d8374f6938a7_, *args, **kwargs):
        object.__setattr__(_8629116b_4d94_42d9_bee1_d8374f6938a7_, '__parent', kwargs.pop('__parent', None))
        object.__setattr__(_8629116b_4d94_42d9_bee1_d8374f6938a7_, '__key', kwargs.pop('__key', None))
        for arg in args:
            if not arg:
                continue
            elif isinstance(arg, dict):
                for key, val in arg.items():
                    _8629116b_4d94_42d9_bee1_d8374f6938a7_[key] = _8629116b_4d94_42d9_bee1_d8374f6938a7_._hook(val)
            elif isinstance(arg, tuple) and (not isinstance(arg[0], tuple)):
                _8629116b_4d94_42d9_bee1_d8374f6938a7_[arg[0]] = _8629116b_4d94_42d9_bee1_d8374f6938a7_._hook(arg[1])
            else:
                for key, val in iter(arg):
                    _8629116b_4d94_42d9_bee1_d8374f6938a7_[key] = _8629116b_4d94_42d9_bee1_d8374f6938a7_._hook(val)

        for key, val in kwargs.items():
            _8629116b_4d94_42d9_bee1_d8374f6938a7_[key] = _8629116b_4d94_42d9_bee1_d8374f6938a7_._hook(val)

Though, it's still impossible to use key with _8629116b_4d94_42d9_bee1_d8374f6938a7_ name :)
2. create factory method, which will protect field names and the unprotect them. Here is an example.

Not sure whether you are interested in fixing it, but I thought you would be interested in it.

Dict.update does not accept keyword args

Python dict.update accepts keywords to update specific keys:

https://docs.python.org/3/library/stdtypes.html#dict.update

Addict Dict.update raises an error instead:

In [1]: from addict import Dict

In [2]: d = Dict()

In [3]: d.update(red=1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-5b5e6d65d506> in <module>()
----> 1 d.update(red=1)

TypeError: update() got an unexpected keyword argument 'red'

In [4]: d = {}

In [5]: d.update(red=1)

(last command succedes)

This should be fixed to have drop-in compatibility with python's dict.

A few style niggles

Because pedantry makes my brain release the happy chemicals for some reason:

    def __getitem__(self, name):
        if name in self:
            return super(Dict, self).__getitem__(name)
        else:
            self.__setitem__(name, {})
            return super(Dict, self).__getitem__(name)

could be shortened:

    def __getitem__(self, name):
        if name not in self:
            self.__setitem__(name, {})
        return super(Dict, self).__getitem__(name)

And this entire trio:

    def __delattr__(self, name):
        self._delete(name)

    def __delitem__(self, name):
        self._delete(name)

    def _delete(self, name):
        super(Dict, self).__delitem__(name)

could just fall back on the default __delitem__ and be replaced entirely by:

    def __delattr__(self, name):
        self.__delitem__(name)

IPython adds spurious members to addicts

This isn't really a problem with Addict, but it might deserve a warning or to be a special case.

IPython touches objects with getattr when working interactively to determine their nature. This means that you get the following:


In [1]: import addict 

In [2]: d = addict.Dict()

In [3]: d
Out[3]: {'_ipython_canary_method_should_not_exist_': {}}

due to the way that Addict overloads getattr.

Is there a chance that we could address this somehow? It's a particular matter because one of my biggest reasons for using Addict is the interactive value.

Link to parent causes reference cycles

With addict 2.0.0, this code generates a reference cycle and may lead to memory leaks:

from addict import *
a = Dict()
a.x.y = 1

Here a contains a reference to a.x, and a.x.__parent__ points back to a, thus creating a cycle.

__setitem__ should probably clear __parent and __key after they've served their purpose.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.