Skip to content
This repository was archived by the owner on Dec 1, 2021. It is now read-only.

Implemented easydict. #1094

Merged
merged 9 commits into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions blueoil/utils/smartdict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# Copyright 2018 The Blueoil Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================


class SmartDict(dict):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add license header.

def __init__(self, d=None, **kwargs):
super(SmartDict, self).__init__()
self.update(d, **kwargs)

def update(self, d=None, **kwargs):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this method non-public? _update

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@a-hanamoto
Since the update function is in dict, I think it is necessary for SmartDict which inherits dict.
https://docs.python.org/ja/3/library/stdtypes.html?highlight=dict#dict.update

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then could you please write test cases for update?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added test case for update function. Please review it.

d = d or {}
d.update(kwargs)
for key, value in d.items():
self[key] = value

def __setitem__(self, name, value):
if isinstance(value, (list, tuple)):
value = [
self.__class__(x) if isinstance(x, dict) else x

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SmartDict? I wonder why there are both of self.__class__ and SmartDict

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@a-hanamoto
Your question is, why do you write "self.class(x)" instead of "SmartDict(x)"?
This is because if you inherit "SmartDict", "self.class" will be a subclass.

class HyperSmartDict(SmartDict):
    pass

d = HyperSmartDict()
d.__class__ == HyperSmartDict

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got your point. Thanks!

for x in value
]
elif isinstance(value, dict) and not isinstance(value, self.__class__):
value = self.__class__(value)
super(SmartDict, self).__setitem__(name, value)

def __getattr__(self, name):
if name in self:
return self[name]
raise AttributeError("'{}' object has no attribute '{}'".format(
self.__class__.__name__, name,
))

def __setattr__(self, name, value):
self[name] = value

def __dir__(self):
parent = super(SmartDict, self).__dir__()
attrs = parent + list(self.keys())
return sorted(attrs)
98 changes: 98 additions & 0 deletions tests/unit/util_tests/test_smartdict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
# Copyright 2018 The Blueoil Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
import pytest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.


from blueoil.utils.smartdict import SmartDict


def test_init():
d = SmartDict(a=10, b=20, c=30)
assert isinstance(d, SmartDict)
assert d.a == 10
assert d.b == 20
assert d.c == 30
assert d["a"] == 10
assert d["b"] == 20
assert d["c"] == 30


def test_init_with_dict():
d = SmartDict({"a": 10, "b": 20, "c": 30})
assert isinstance(d, SmartDict)
assert d.a == 10
assert d.b == 20
assert d.c == 30
assert d["a"] == 10
assert d["b"] == 20
assert d["c"] == 30


def test_update():
d = SmartDict({"a": 10, "b": 20, "c": 30})
d.update({"a": 40, "b": 50})
assert d.a == 40
assert d.b == 50
assert d.c == 30
d.update(c=60)
assert d.c == 60


def test_setitem():
d = SmartDict()
d["a"] = [
100,
{"a": 10, "b": 20, "c": 30},
]
assert d.a[0] == 100
assert isinstance(d.a[1], SmartDict)
assert d.a[1].a == 10
assert d.a[1].b == 20
assert d.a[1].c == 30

d["b"] = {"a": 10, "b": 20, "c": 30}
assert isinstance(d.b, SmartDict)
assert d.b.a == 10
assert d.b.b == 20
assert d.b.c == 30


def test_getattr():
d = SmartDict(a=10, b=20, c=30)
assert d.a == 10
assert d.b == 20
assert d.c == 30
with pytest.raises(AttributeError):
d.d


def test_setattr():
d = SmartDict()
d.a = 10
d.b = 20
d.c = 30
assert d["a"] == 10
assert d["b"] == 20
assert d["c"] == 30


def test_dir():
d = SmartDict(a=10, b=20, c=30)
expects = sorted(
dir(dict())
+ ["a", "b", "c"]
+ ["__dict__", "__getattr__", "__module__", "__weakref__"]
)
assert dir(d) == expects