python-bunch 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_bunch-0.1.0 → python_bunch-0.1.1}/PKG-INFO +13 -2
- {python_bunch-0.1.0 → python_bunch-0.1.1}/README.md +12 -1
- python_bunch-0.1.1/bunch/bunch.py +70 -0
- python_bunch-0.1.1/bunch/immutable_bunch.py +75 -0
- {python_bunch-0.1.0 → python_bunch-0.1.1}/pyproject.toml +1 -1
- {python_bunch-0.1.0 → python_bunch-0.1.1}/python_bunch.egg-info/PKG-INFO +13 -2
- {python_bunch-0.1.0 → python_bunch-0.1.1}/python_bunch.egg-info/SOURCES.txt +3 -1
- python_bunch-0.1.1/tests/test_bunch.py +108 -0
- python_bunch-0.1.1/tests/test_immutable_bunch.py +114 -0
- python_bunch-0.1.0/bunch/bunch.py +0 -44
- python_bunch-0.1.0/tests/test_bunch.py +0 -37
- {python_bunch-0.1.0 → python_bunch-0.1.1}/LICENSE +0 -0
- {python_bunch-0.1.0 → python_bunch-0.1.1}/bunch/__init__.py +0 -0
- {python_bunch-0.1.0 → python_bunch-0.1.1}/python_bunch.egg-info/dependency_links.txt +0 -0
- {python_bunch-0.1.0 → python_bunch-0.1.1}/python_bunch.egg-info/top_level.txt +0 -0
- {python_bunch-0.1.0 → python_bunch-0.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: python-bunch
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.1
|
4
4
|
Summary: A lightweight Python class that behaves like a dict but supports attribute-style access.
|
5
5
|
Author-email: Your Name <your.email@example.com>
|
6
6
|
License: MIT
|
@@ -32,10 +32,21 @@ You can install this package via PIP: _pip install bunch_
|
|
32
32
|
### <ins> Usage </ins>
|
33
33
|
|
34
34
|
```python
|
35
|
-
|
35
|
+
# - Mutable Bunch -
|
36
|
+
from bunch.bunch import Bunch
|
36
37
|
|
37
38
|
my_bunch = Bunch({'name': 'Jane', 'age': 30})
|
38
39
|
|
39
40
|
print(my_bunch.name) # Output: Jane
|
40
41
|
print(my_bunch['age']) # Output: 30
|
42
|
+
|
43
|
+
# - Immutable Bunch -
|
44
|
+
from bunch.immutable_bunch import ImmutableBunch
|
45
|
+
|
46
|
+
my_immutable_bunch = ImmutableBunch({'name': 'John', 'age': 25})
|
47
|
+
print(my_immutable_bunch.name) # Output: John
|
48
|
+
print(my_immutable_bunch['age']) # Output: 35
|
49
|
+
|
50
|
+
# Attempting to modify an ImmutableBunch will raise an Exception
|
51
|
+
my_immutable_bunch.name = 'Alice' # Raises ImmutableBunchException
|
41
52
|
```
|
@@ -17,10 +17,21 @@ You can install this package via PIP: _pip install bunch_
|
|
17
17
|
### <ins> Usage </ins>
|
18
18
|
|
19
19
|
```python
|
20
|
-
|
20
|
+
# - Mutable Bunch -
|
21
|
+
from bunch.bunch import Bunch
|
21
22
|
|
22
23
|
my_bunch = Bunch({'name': 'Jane', 'age': 30})
|
23
24
|
|
24
25
|
print(my_bunch.name) # Output: Jane
|
25
26
|
print(my_bunch['age']) # Output: 30
|
27
|
+
|
28
|
+
# - Immutable Bunch -
|
29
|
+
from bunch.immutable_bunch import ImmutableBunch
|
30
|
+
|
31
|
+
my_immutable_bunch = ImmutableBunch({'name': 'John', 'age': 25})
|
32
|
+
print(my_immutable_bunch.name) # Output: John
|
33
|
+
print(my_immutable_bunch['age']) # Output: 35
|
34
|
+
|
35
|
+
# Attempting to modify an ImmutableBunch will raise an Exception
|
36
|
+
my_immutable_bunch.name = 'Alice' # Raises ImmutableBunchException
|
26
37
|
```
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
|
5
|
+
class Bunch:
|
6
|
+
def __init__(self, *args, **kwargs):
|
7
|
+
for arg in args:
|
8
|
+
if not isinstance(arg, dict):
|
9
|
+
kwargs[arg] = None
|
10
|
+
self.__dict__.update(kwargs)
|
11
|
+
|
12
|
+
def __getitem__(self, key: Any) -> Any or None:
|
13
|
+
return self.__dict__.get(key, None)
|
14
|
+
|
15
|
+
def __setitem__(self, key: Any, value: Any) -> None:
|
16
|
+
self.__dict__[key] = value
|
17
|
+
|
18
|
+
def __delitem__(self, key: Any) -> None:
|
19
|
+
del self.__dict__[key]
|
20
|
+
|
21
|
+
def __contains__(self, key: Any) -> bool:
|
22
|
+
return key in self.__dict__
|
23
|
+
|
24
|
+
def __str__(self) -> str:
|
25
|
+
return json.dumps(self.__dict__, sort_keys=False)
|
26
|
+
|
27
|
+
def __repr__(self) -> str:
|
28
|
+
return self.__str__()
|
29
|
+
|
30
|
+
def __getattr__(self, key: Any) -> Any or None:
|
31
|
+
if key in self.__dict__:
|
32
|
+
return self.__dict__[key]
|
33
|
+
return None
|
34
|
+
|
35
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
36
|
+
self.__dict__[name] = value
|
37
|
+
|
38
|
+
def __delattr__(self, name) -> None:
|
39
|
+
del self.__dict__[name]
|
40
|
+
|
41
|
+
def contains_value(self, value: Any) -> bool:
|
42
|
+
return value in self.__dict__.values()
|
43
|
+
|
44
|
+
def clear(self) -> None:
|
45
|
+
self.__dict__.clear()
|
46
|
+
|
47
|
+
def pop(self, key: Any, default: Any = None) -> Any or None:
|
48
|
+
return self.__dict__.pop(key, default)
|
49
|
+
|
50
|
+
def popitem(self) -> Any or None:
|
51
|
+
return self.__dict__.popitem()
|
52
|
+
|
53
|
+
def update(self, other: dict) -> None:
|
54
|
+
self.__dict__.update(other)
|
55
|
+
|
56
|
+
def setdefault(self, key: Any, default: Any = None) -> Any or None:
|
57
|
+
return self.__dict__.setdefault(key, default)
|
58
|
+
|
59
|
+
def keys(self):
|
60
|
+
return self.__dict__.keys()
|
61
|
+
|
62
|
+
def values(self):
|
63
|
+
return self.__dict__.values()
|
64
|
+
|
65
|
+
def items(self):
|
66
|
+
return self.__dict__.items()
|
67
|
+
|
68
|
+
@staticmethod
|
69
|
+
def from_dict(dictionary: dict) -> Any:
|
70
|
+
return Bunch(**dictionary)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
|
5
|
+
class ImmutableBunchException(Exception):
|
6
|
+
def __init__(self, message: str) -> None:
|
7
|
+
super().__init__(message)
|
8
|
+
|
9
|
+
|
10
|
+
class ImmutableBunch:
|
11
|
+
def __init__(self, *args, **kwargs):
|
12
|
+
for arg in args:
|
13
|
+
if not isinstance(arg, dict):
|
14
|
+
kwargs[arg] = None
|
15
|
+
self.__dict__.update(kwargs)
|
16
|
+
|
17
|
+
def __getitem__(self, key: Any) -> Any or None:
|
18
|
+
return self.__dict__.get(key, None)
|
19
|
+
|
20
|
+
def __setitem__(self, key: Any, value: Any) -> None:
|
21
|
+
raise ImmutableBunchException('ImmutableBunch does not support item assignment')
|
22
|
+
|
23
|
+
def __delitem__(self, key: Any) -> None:
|
24
|
+
raise ImmutableBunchException('ImmutableBunch does not support item deletion')
|
25
|
+
|
26
|
+
def __contains__(self, key: Any) -> bool:
|
27
|
+
return key in self.__dict__
|
28
|
+
|
29
|
+
def __str__(self) -> str:
|
30
|
+
return json.dumps(self.__dict__, sort_keys=False)
|
31
|
+
|
32
|
+
def __repr__(self) -> str:
|
33
|
+
return self.__str__()
|
34
|
+
|
35
|
+
def __getattr__(self, key: Any) -> Any or None:
|
36
|
+
if key in self.__dict__:
|
37
|
+
return self.__dict__[key]
|
38
|
+
return None
|
39
|
+
|
40
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
41
|
+
raise ImmutableBunchException('ImmutableBunch does not support attribute assignment')
|
42
|
+
|
43
|
+
def __delattr__(self, name) -> None:
|
44
|
+
raise ImmutableBunchException('ImmutableBunch does not support attribute deletion')
|
45
|
+
|
46
|
+
def contains_value(self, value: Any) -> bool:
|
47
|
+
return value in self.__dict__.values()
|
48
|
+
|
49
|
+
def clear(self) -> None:
|
50
|
+
raise ImmutableBunchException('ImmutableBunch does not support clearing')
|
51
|
+
|
52
|
+
def pop(self, key: Any, default: Any = None) -> Any or None:
|
53
|
+
raise ImmutableBunchException('ImmutableBunch does not support popping')
|
54
|
+
|
55
|
+
def popitem(self) -> Any or None:
|
56
|
+
raise ImmutableBunchException('ImmutableBunch does not support popitem')
|
57
|
+
|
58
|
+
def update(self, other: dict) -> None:
|
59
|
+
raise ImmutableBunchException('ImmutableBunch does not support update')
|
60
|
+
|
61
|
+
def setdefault(self, key: Any, default: Any = None) -> Any or None:
|
62
|
+
raise ImmutableBunchException('ImmutableBunch does not support setdefault')
|
63
|
+
|
64
|
+
def keys(self):
|
65
|
+
return self.__dict__.keys()
|
66
|
+
|
67
|
+
def values(self):
|
68
|
+
return self.__dict__.values()
|
69
|
+
|
70
|
+
def items(self):
|
71
|
+
return self.__dict__.items()
|
72
|
+
|
73
|
+
@staticmethod
|
74
|
+
def from_dict(dictionary: dict) -> Any:
|
75
|
+
return ImmutableBunch(**dictionary)
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "python-bunch"
|
7
|
-
version = "0.1.
|
7
|
+
version = "0.1.1"
|
8
8
|
description = "A lightweight Python class that behaves like a dict but supports attribute-style access."
|
9
9
|
readme = "README.md"
|
10
10
|
requires-python = ">=3.7"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: python-bunch
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.1
|
4
4
|
Summary: A lightweight Python class that behaves like a dict but supports attribute-style access.
|
5
5
|
Author-email: Your Name <your.email@example.com>
|
6
6
|
License: MIT
|
@@ -32,10 +32,21 @@ You can install this package via PIP: _pip install bunch_
|
|
32
32
|
### <ins> Usage </ins>
|
33
33
|
|
34
34
|
```python
|
35
|
-
|
35
|
+
# - Mutable Bunch -
|
36
|
+
from bunch.bunch import Bunch
|
36
37
|
|
37
38
|
my_bunch = Bunch({'name': 'Jane', 'age': 30})
|
38
39
|
|
39
40
|
print(my_bunch.name) # Output: Jane
|
40
41
|
print(my_bunch['age']) # Output: 30
|
42
|
+
|
43
|
+
# - Immutable Bunch -
|
44
|
+
from bunch.immutable_bunch import ImmutableBunch
|
45
|
+
|
46
|
+
my_immutable_bunch = ImmutableBunch({'name': 'John', 'age': 25})
|
47
|
+
print(my_immutable_bunch.name) # Output: John
|
48
|
+
print(my_immutable_bunch['age']) # Output: 35
|
49
|
+
|
50
|
+
# Attempting to modify an ImmutableBunch will raise an Exception
|
51
|
+
my_immutable_bunch.name = 'Alice' # Raises ImmutableBunchException
|
41
52
|
```
|
@@ -3,8 +3,10 @@ README.md
|
|
3
3
|
pyproject.toml
|
4
4
|
bunch/__init__.py
|
5
5
|
bunch/bunch.py
|
6
|
+
bunch/immutable_bunch.py
|
6
7
|
python_bunch.egg-info/PKG-INFO
|
7
8
|
python_bunch.egg-info/SOURCES.txt
|
8
9
|
python_bunch.egg-info/dependency_links.txt
|
9
10
|
python_bunch.egg-info/top_level.txt
|
10
|
-
tests/test_bunch.py
|
11
|
+
tests/test_bunch.py
|
12
|
+
tests/test_immutable_bunch.py
|
@@ -0,0 +1,108 @@
|
|
1
|
+
import json
|
2
|
+
import unittest
|
3
|
+
from collections import Counter
|
4
|
+
|
5
|
+
from bunch.bunch import Bunch
|
6
|
+
|
7
|
+
|
8
|
+
class TestBunch(unittest.TestCase):
|
9
|
+
def test_getitem(self):
|
10
|
+
b = Bunch(name='Alice', age=30)
|
11
|
+
self.assertEqual(b['name'], 'Alice')
|
12
|
+
|
13
|
+
def test_setitem(self):
|
14
|
+
b = Bunch(name='Alice')
|
15
|
+
b['age'] = 30
|
16
|
+
self.assertEqual(b.age, 30)
|
17
|
+
|
18
|
+
def test_delitem(self):
|
19
|
+
b = Bunch(name='Alice', age=30)
|
20
|
+
del b['name']
|
21
|
+
self.assertEqual(b.name, None)
|
22
|
+
|
23
|
+
def test_contains(self):
|
24
|
+
b = Bunch(name='Alice', age=30)
|
25
|
+
self.assertTrue('name' in b)
|
26
|
+
self.assertFalse('location' in b)
|
27
|
+
|
28
|
+
def test_str(self):
|
29
|
+
b = Bunch(name='Alice', age=30)
|
30
|
+
expected_str = json.dumps({'name': 'Alice', 'age': 30})
|
31
|
+
self.assertEqual(b.__str__(), expected_str)
|
32
|
+
|
33
|
+
def test_repr(self):
|
34
|
+
b = Bunch(name='Alice', age=30)
|
35
|
+
expected_repr = json.dumps({'name': 'Alice', 'age': 30})
|
36
|
+
self.assertEqual(b.__repr__(), expected_repr)
|
37
|
+
|
38
|
+
def test_getattr(self):
|
39
|
+
b = Bunch(name='Alice', age=30)
|
40
|
+
self.assertEqual(b.age, 30)
|
41
|
+
|
42
|
+
def test_setattr(self):
|
43
|
+
b = Bunch(name='Alice', age=30)
|
44
|
+
b.age = 40
|
45
|
+
b.location = 'New York'
|
46
|
+
self.assertEqual(b.age, 40)
|
47
|
+
self.assertEqual(b.location, 'New York')
|
48
|
+
|
49
|
+
def test_delattr(self):
|
50
|
+
b = Bunch(name='Alice', age=30)
|
51
|
+
del b.age
|
52
|
+
self.assertEqual(b.age, None)
|
53
|
+
|
54
|
+
def test_contains_value(self):
|
55
|
+
b = Bunch(name='Alice', age=30)
|
56
|
+
self.assertTrue(b.contains_value('Alice'))
|
57
|
+
self.assertFalse(b.contains_value('Bob'))
|
58
|
+
|
59
|
+
def test_clear(self):
|
60
|
+
b = Bunch(name='Alice', age=30)
|
61
|
+
b.clear()
|
62
|
+
self.assertEqual(len(b.keys()), 0)
|
63
|
+
|
64
|
+
def test_pop(self):
|
65
|
+
b = Bunch(name='Alice', age=30)
|
66
|
+
popped_value = b.pop('name')
|
67
|
+
self.assertEqual(popped_value, 'Alice')
|
68
|
+
self.assertEqual(b.name, None)
|
69
|
+
|
70
|
+
def test_popitem(self):
|
71
|
+
b = Bunch(name='Alice', age=30)
|
72
|
+
popped_value = b.popitem()
|
73
|
+
self.assertEqual(popped_value, ('age', 30))
|
74
|
+
self.assertEqual(b.age, None)
|
75
|
+
|
76
|
+
def test_update(self):
|
77
|
+
b = Bunch(name='Alice', age=30)
|
78
|
+
d = {'name': 'Bob', 'age': 35}
|
79
|
+
b.update(d)
|
80
|
+
self.assertEqual(d['name'], 'Bob')
|
81
|
+
self.assertEqual(d['age'], 35)
|
82
|
+
|
83
|
+
def test_setdefault(self):
|
84
|
+
b = Bunch(name='Alice', age=30)
|
85
|
+
b.setdefault('location')
|
86
|
+
self.assertEqual(b.location, None)
|
87
|
+
|
88
|
+
def test_keys(self):
|
89
|
+
b = Bunch(name='Alice', age=30)
|
90
|
+
self.assertEqual(Counter(b.keys()), Counter(['name', 'age']))
|
91
|
+
|
92
|
+
def test_values(self):
|
93
|
+
b = Bunch(name='Alice', age=30)
|
94
|
+
self.assertEqual(Counter(b.values()), Counter(['Alice', 30]))
|
95
|
+
|
96
|
+
def test_items(self):
|
97
|
+
b = Bunch(name='Alice', age=30)
|
98
|
+
self.assertEqual(Counter(b.items()), Counter([('name', 'Alice'), ('age', 30)]))
|
99
|
+
|
100
|
+
def test_from_dict(self):
|
101
|
+
data = {'fruit': 'apple', 'color': 'red'}
|
102
|
+
b = Bunch.from_dict(data)
|
103
|
+
self.assertEqual(b.fruit, 'apple')
|
104
|
+
self.assertEqual(b.color, 'red')
|
105
|
+
|
106
|
+
|
107
|
+
if __name__ == '__main__':
|
108
|
+
unittest.main()
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import json
|
2
|
+
import unittest
|
3
|
+
from collections import Counter
|
4
|
+
from contextlib import contextmanager
|
5
|
+
|
6
|
+
from bunch.immutable_bunch import ImmutableBunch, ImmutableBunchException
|
7
|
+
|
8
|
+
|
9
|
+
@contextmanager
|
10
|
+
def raise_immutable_exception():
|
11
|
+
try:
|
12
|
+
yield
|
13
|
+
except ImmutableBunchException:
|
14
|
+
pass
|
15
|
+
else:
|
16
|
+
raise Exception('ImmutableBunchException not raised as expected')
|
17
|
+
|
18
|
+
|
19
|
+
class TestBunch(unittest.TestCase):
|
20
|
+
def test_getitem(self):
|
21
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
22
|
+
self.assertEqual(ib['name'], 'Alice')
|
23
|
+
|
24
|
+
def test_setitem(self):
|
25
|
+
ib = ImmutableBunch(name='Alice')
|
26
|
+
with raise_immutable_exception():
|
27
|
+
ib['age'] = 30
|
28
|
+
|
29
|
+
def test_delitem(self):
|
30
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
31
|
+
with raise_immutable_exception():
|
32
|
+
del ib['name']
|
33
|
+
|
34
|
+
def test_contains(self):
|
35
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
36
|
+
self.assertTrue('name' in ib)
|
37
|
+
self.assertFalse('location' in ib)
|
38
|
+
|
39
|
+
def test_str(self):
|
40
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
41
|
+
expected_str = json.dumps({'name': 'Alice', 'age': 30})
|
42
|
+
self.assertEqual(ib.__str__(), expected_str)
|
43
|
+
|
44
|
+
def test_repr(self):
|
45
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
46
|
+
expected_repr = json.dumps({'name': 'Alice', 'age': 30})
|
47
|
+
self.assertEqual(ib.__repr__(), expected_repr)
|
48
|
+
|
49
|
+
def test_getattr(self):
|
50
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
51
|
+
self.assertEqual(ib.age, 30)
|
52
|
+
|
53
|
+
def test_setattr(self):
|
54
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
55
|
+
with raise_immutable_exception():
|
56
|
+
ib.age = 40
|
57
|
+
|
58
|
+
def test_delattr(self):
|
59
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
60
|
+
with raise_immutable_exception():
|
61
|
+
del ib.age
|
62
|
+
|
63
|
+
def test_contains_value(self):
|
64
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
65
|
+
self.assertTrue(ib.contains_value('Alice'))
|
66
|
+
self.assertFalse(ib.contains_value('Bob'))
|
67
|
+
|
68
|
+
def test_clear(self):
|
69
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
70
|
+
with raise_immutable_exception():
|
71
|
+
ib.clear()
|
72
|
+
|
73
|
+
def test_pop(self):
|
74
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
75
|
+
with raise_immutable_exception():
|
76
|
+
ib.pop('name')
|
77
|
+
|
78
|
+
def test_popitem(self):
|
79
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
80
|
+
with raise_immutable_exception():
|
81
|
+
ib.popitem()
|
82
|
+
|
83
|
+
def test_update(self):
|
84
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
85
|
+
d = {'name': 'Bob', 'age': 35}
|
86
|
+
with raise_immutable_exception():
|
87
|
+
ib.update(d)
|
88
|
+
|
89
|
+
def test_setdefault(self):
|
90
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
91
|
+
with raise_immutable_exception():
|
92
|
+
ib.setdefault('location')
|
93
|
+
|
94
|
+
def test_keys(self):
|
95
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
96
|
+
self.assertEqual(Counter(ib.keys()), Counter(['name', 'age']))
|
97
|
+
|
98
|
+
def test_values(self):
|
99
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
100
|
+
self.assertEqual(Counter(ib.values()), Counter(['Alice', 30]))
|
101
|
+
|
102
|
+
def test_items(self):
|
103
|
+
ib = ImmutableBunch(name='Alice', age=30)
|
104
|
+
self.assertEqual(Counter(ib.items()), Counter([('name', 'Alice'), ('age', 30)]))
|
105
|
+
|
106
|
+
def test_from_dict(self):
|
107
|
+
data = {'fruit': 'apple', 'color': 'red'}
|
108
|
+
ib = ImmutableBunch.from_dict(data)
|
109
|
+
self.assertEqual(ib.fruit, 'apple')
|
110
|
+
self.assertEqual(ib.color, 'red')
|
111
|
+
|
112
|
+
|
113
|
+
if __name__ == '__main__':
|
114
|
+
unittest.main()
|
@@ -1,44 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
from typing import Any
|
3
|
-
|
4
|
-
|
5
|
-
class Bunch:
|
6
|
-
def __init__(self, *args, **kwargs):
|
7
|
-
for arg in args:
|
8
|
-
if not isinstance(arg, dict):
|
9
|
-
kwargs[arg] = None
|
10
|
-
self.__dict__.update(kwargs)
|
11
|
-
|
12
|
-
def __getitem__(self, key):
|
13
|
-
return self.__dict__[key]
|
14
|
-
|
15
|
-
def __setitem__(self, key, value):
|
16
|
-
self.__dict__[key] = value
|
17
|
-
|
18
|
-
def __contains__(self, key):
|
19
|
-
return key in self.__dict__
|
20
|
-
|
21
|
-
def __str__(self):
|
22
|
-
return json.dumps(self.__dict__, indent=4, sort_keys=False)
|
23
|
-
|
24
|
-
def __repr__(self):
|
25
|
-
return self.__str__()
|
26
|
-
|
27
|
-
def __delitem__(self, key):
|
28
|
-
del self.__dict__[key]
|
29
|
-
|
30
|
-
def contains_value(self, value):
|
31
|
-
return value in self.__dict__.values()
|
32
|
-
|
33
|
-
def keys(self):
|
34
|
-
return self.__dict__.keys()
|
35
|
-
|
36
|
-
def values(self):
|
37
|
-
return self.__dict__.values()
|
38
|
-
|
39
|
-
def items(self):
|
40
|
-
return self.__dict__.items()
|
41
|
-
|
42
|
-
@staticmethod
|
43
|
-
def from_dict(dictionary: dict) -> Any:
|
44
|
-
return Bunch(**dictionary)
|
@@ -1,37 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
from bunch.bunch import Bunch
|
3
|
-
|
4
|
-
class TestBunch(unittest.TestCase):
|
5
|
-
def test_init(self):
|
6
|
-
b = Bunch(name='Alice', age=30)
|
7
|
-
self.assertEqual(b.name, 'Alice')
|
8
|
-
self.assertEqual(b.age, 30)
|
9
|
-
|
10
|
-
def test_getitem(self):
|
11
|
-
b = Bunch(name='Alice', age=30)
|
12
|
-
self.assertEqual(b['name'], 'Alice')
|
13
|
-
|
14
|
-
def test_setitem(self):
|
15
|
-
b = Bunch(name='Alice')
|
16
|
-
b['age'] = 30
|
17
|
-
self.assertEqual(b.age, 30)
|
18
|
-
|
19
|
-
def test_contains(self):
|
20
|
-
b = Bunch(name='Alice', age=30)
|
21
|
-
self.assertTrue('name' in b)
|
22
|
-
self.assertFalse('location' in b)
|
23
|
-
|
24
|
-
def test_contains_value(self):
|
25
|
-
b = Bunch(name='Alice', age=30)
|
26
|
-
self.assertTrue(b.contains_value('Alice'))
|
27
|
-
self.assertFalse(b.contains_value('Bob'))
|
28
|
-
|
29
|
-
def test_from_dict(self):
|
30
|
-
# Test from_dict static method
|
31
|
-
data = {'fruit': 'apple', 'color': 'red'}
|
32
|
-
b = Bunch.from_dict(data)
|
33
|
-
self.assertEqual(b.fruit, 'apple')
|
34
|
-
self.assertEqual(b.color, 'red')
|
35
|
-
|
36
|
-
if __name__ == '__main__':
|
37
|
-
unittest.main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|