Skip to main content

A utility that makes it easy to use dot notation with python dictionaries

Project description



waterbear, A Base Classs That Makes Python Dictionary Accessible With The Dot Notation, Recursively and with Default Values

Now introducing the smallest bear! Waterbear.

Waterbear makes it easy to use python dictionaries with dot notation!


  • [ ] fix class extension usage pattern
  • [ ] [STRIKEOUT:merge python2.7 version with python3]
  • [ ] [STRIKEOUT:make another package called tardigrade]


pip install waterbear


For more usage examples, take a look at the!

There are two classes, the Bear and the DefaultBear. Default Bear allows you to pass in a default factory as the first argument. Bear allows you do do so via a keyword argument __default

Example usage below:

# Waterbear is a bear!
from waterbear import Bear

waterbear = Bear(**{"key": 100})
assert waterbear.key == 100, 'now waterbear.key is accessible!'
assert waterbear['key'] == 100, 'item access syntax is also supported!'

Similar to collection.defaultdict, there is DefaultBear

bear = DefaultBear(None, a=10, b=100)
assert vars(bear) == {'a': 10, 'b': 100}

assert bear.does_not_exist is None, "default value works"

DefaultBear like defaultdict

You can use the DefaultBear class and pass in a default factor as the first parameter.

bear = DefaultBear(tuple, a=10, b=100)
assert bear.does_not_exist is (), "default factory also works!"

You can also use it with vars, str, print(repr), dict etc.

bear = Bear(a=10, b=100)
assert str(bear) == "{'a': 10, 'b': 100}"
assert dir(bear) == ['a', 'b']
assert list(iter(bear)) == ['a', 'b']
assert dict(bear) == {'a': 10, 'b': 100}

As Bool in Condition Logic

When used in conditional logic, Bear and DefaultBear behaves exactly like an ordinary dictionary!

def test_dict_comparison():
    bear = Bear()
    assert not {}, 'empty dictionary are treated as False value.'
    assert not bear, 'bear should be treated as False value too!'

Using with Pickle

When using with default factories, only non-callables are picklable.

def test_pickle_setstate_getstate():
    # create a default bear with a default factory
    bear = DefaultBear('hey', a=10, b=100)
    pickle_string = pickle.dumps(bear)
    bear_reborn = pickle.loads(pickle_string)
    assert type(bear_reborn) == DefaultBear
    assert vars(bear_reborn) == {'a': 10, 'b': 100}

    bear = DefaultBear(lambda: 'hey', a=10, b=100)
    function_fails = False
    except AttributeError as e:
        function_fails = True
    assert function_fails

Using deepcopy

You can just do copy.deepcopy(bear)!

def test_deepcopy():
    from copy import deepcopy
    original = Bear(a=1, b={'ha': 0})
    copy = deepcopy(original)
    copy.b.ha += 1
    assert copy.b.ha == 1
    assert original.b.ha == 0

As A Base Class

Waterbear is completely rewritten to play well with class extension!

class ExtendBear(Bear):
    def _hidden_stuff(self):
        return "._hidden_stuff"

    def __mangled_stuff(self):
        return ".__mangled_stuff"

    def __dict__(self):
        return ".__dict__"

e = ExtendBear()
assert e.__dict__ == ".__dict__"
assert e._hidden_stuff == '._hidden_stuff'
assert e._ExtendBear__mangled_stuff == ".__mangled_stuff"

More Usages Could Be Found in The Tests!

For more usage examples, take a look at

test_dict = {
    'a': 0,
    'b': 1

# Use spread operators to construct with a dictionary!
test_args = Bear(**test_dict)
assert test_args.a == 0
assert test_args.b == 1
# the value should now be accessible through the key name.
test_args.haha = 0
assert test_args.haha == 0

# You can also use a nested dictionary.
test_args.haha = {'a': 1}
assert test_args.haha != {'a': 1}
assert vars(test_args.haha) == {'a': 1}
assert test_args.haha.a == 1
assert test_args.__dict__['haha']['a'] == 1
assert vars(test_args)['haha']['a'] == 1
assert str(test_args) == "{'a': 0, 'b': 1, 'haha': {'a': 1}}", \
    'test_args should be this value "{\'a\': 0, \'b\': 1, \'haha\': {\'a\': 1}}"'

# To set recursion to false, use this `__recursive` parameter.
test_args = Bear(__recursive=False, **test_dict)
assert test_args.__is_recursive == False
assert test_args.a == 0
assert test_args.b == 1
test_args.haha = {'a': 1}
assert test_args.haha['a'] == 1
assert test_args.haha == {'a': 1}

# Some other usage patterns
test_args = Bear(**test_dict, **{'ha': 'ha', 'no': 'no'})
assert test_args.ha == 'ha', 'key ha should be ha'

To Develop

git clone
cd waterbear
make dev

This make dev command should build the wheel and install it in your current python environment. Take a look at the for details.

To publish, first update the version number, then do:

make publish

* image credit goes to BBC waterbear: The Smallest Bear! 😛 tardigrade

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Filename, size & hash SHA256 hash help File type Python version Upload date
waterbear-2.3.1-py3-none-any.whl (9.1 kB) Copy SHA256 hash SHA256 Wheel py3

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN SignalFx SignalFx Supporter DigiCert DigiCert EV certificate StatusPage StatusPage Status page