Skip to content

Commit 9325464

Browse files
authored
Merge pull request #24 from robabram/ra/object-update
Allow updating object using update() method or plus operator
2 parents 58e9acd + 2ee1ffb commit 9325464

4 files changed

Lines changed: 142 additions & 2 deletions

File tree

README.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,15 @@ Documentation
165165
:param dates_to_str: Boolean, convert all date or datetime values to string.
166166
:returns: dictionary object
167167

168-
168+
JSONObject.update([Dict|List|Tuple]) accepts either a dictionary object or an iterable of key/value
169+
pairs (as tuples or other iterables of length two). If keyword arguments are specified, the dictionary
170+
is then updated with those key/value pairs: obj.update(sky=1, cloud=2).
171+
172+
Plus Operator: Two JSONObjects may be merged using the plus (+) operator: obj = obj + other_obj.
173+
174+
Number of Properties: The number of managed properties may be determined by using the Python 'len()'
175+
function: len(obj) == 5.
176+
169177
Project Links
170178
=============
171179

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from setuptools import setup, find_packages
88

9-
__VERSION__ = "1.1.9"
9+
__VERSION__ = "1.1.10"
1010

1111
base_dir = os.path.abspath(os.path.dirname(__file__))
1212

src/python_easy_json/json_object.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,34 @@ def to_dict(self, recursive: bool = True, dates_to_str: bool = False):
267267

268268
def __repr__(self):
269269
return self.to_json()
270+
271+
def __len__(self):
272+
return len(self.__data_dict__.keys())
273+
274+
def __add__(self, other):
275+
if not isinstance(other, JSONObject):
276+
raise TypeError(f"Invalid operand type for +: 'JSONObject' and '{str(other)}'")
277+
return self.update(**other.to_dict())
278+
279+
def update(self, *args, **kwargs) -> "JSONObject":
280+
"""
281+
Update or add additional properties to this object by passing a dictionary or list of key value pairs.
282+
"""
283+
if args:
284+
for arg in args:
285+
if isinstance(arg, dict):
286+
for k, v in arg.items():
287+
setattr(self, k, v)
288+
elif isinstance(arg, (list, tuple)):
289+
for item in arg:
290+
if len(item) != 2:
291+
raise ValueError('Invalid tuple size')
292+
setattr(self, item[0], item[1])
293+
else:
294+
raise TypeError(f"TypeError: '{type(arg)}' object is not iterable")
295+
296+
elif kwargs:
297+
for k, v in kwargs.items():
298+
setattr(self, k, v)
299+
300+
return self

tests/test_simple_json.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,104 @@ def test_setattr_after_init(self):
109109
data = obj.to_dict()
110110
self.assertEqual(data['new_prop'], 'abc')
111111
self.assertEqual(data['test_prop'], 123)
112+
113+
def test_update_with_dict(self):
114+
""" Test we can update the JSONObject by passing a dict object """
115+
obj = JSONObject({'test_prop': 123})
116+
self.assertIsInstance(obj, JSONObject)
117+
118+
obj = obj.update({'test_prop': 456, 'new_prop': 987})
119+
120+
self.assertEqual(obj.new_prop, 987)
121+
self.assertEqual(obj.test_prop, 456)
122+
123+
data = obj.to_dict()
124+
125+
self.assertEqual(data['new_prop'], 987)
126+
self.assertEqual(data['test_prop'], 456)
127+
128+
def test_update_with_keyword_args(self):
129+
""" Test we can update the JSONObject by passing key word arguments """
130+
obj = JSONObject({'test_prop': 123})
131+
self.assertIsInstance(obj, JSONObject)
132+
133+
obj = obj.update(test_prop=456, new_prop=987)
134+
135+
self.assertEqual(obj.new_prop, 987)
136+
self.assertEqual(obj.test_prop, 456)
137+
138+
data = obj.to_dict()
139+
140+
self.assertEqual(data['new_prop'], 987)
141+
self.assertEqual(data['test_prop'], 456)
142+
143+
def test_update_with_iterable_pairs(self):
144+
""" Test we can update the JSONObject by passing iterable pair arguments """
145+
obj = JSONObject({'test_prop': 123})
146+
self.assertIsInstance(obj, JSONObject)
147+
148+
obj = obj.update([('test_prop', 456), ('new_prop', 987)])
149+
150+
self.assertEqual(obj.new_prop, 987)
151+
self.assertEqual(obj.test_prop, 456)
152+
153+
data = obj.to_dict()
154+
155+
self.assertEqual(data['new_prop'], 987)
156+
self.assertEqual(data['test_prop'], 456)
157+
158+
def test_update_exceptions(self):
159+
""" Test update using bad data to cause exceptions """
160+
161+
obj = JSONObject({'test_prop': 123})
162+
self.assertIsInstance(obj, JSONObject)
163+
164+
# Test no args, should not raise an error.
165+
self.assertIsInstance(obj.update({}), JSONObject)
166+
167+
# Test non-iterable value raises TypeError
168+
self.assertRaises(TypeError, obj.update, None)
169+
self.assertRaises(TypeError, obj.update, 123)
170+
171+
# Test bad iterable pair raise ValueError
172+
self.assertRaises(ValueError, obj.update, [('test_prop', 456, 333)])
173+
174+
def test_number_of_properties(self):
175+
""" Test the number of properties by calling len() function """
176+
177+
obj = JSONObject({'test_prop': 123, 'another_prop': 'abc'})
178+
self.assertIsInstance(obj, JSONObject)
179+
180+
self.assertEqual(len(obj), 2)
181+
182+
def test_add_object(self):
183+
""" Test add object """
184+
obj = JSONObject({'test_prop': 123})
185+
self.assertIsInstance(obj, JSONObject)
186+
187+
other_obj = JSONObject({'another_prop': 'abc'})
188+
self.assertIsInstance(other_obj, JSONObject)
189+
190+
island_other_obj = JSONObject({'island_prop': 'sandy'})
191+
self.assertIsInstance(island_other_obj, JSONObject)
192+
193+
obj += other_obj
194+
195+
self.assertEqual(obj.test_prop, 123)
196+
self.assertEqual(obj.another_prop, 'abc')
197+
198+
obj = obj + island_other_obj
199+
200+
self.assertEqual(obj.island_prop, 'sandy')
201+
202+
def test_add_invalid_operand(self):
203+
""" Test adding an invalid operand """
204+
obj = JSONObject({'test_prop': 123})
205+
self.assertIsInstance(obj, JSONObject)
206+
207+
try:
208+
obj += {'other_prop': 'abc'}
209+
except TypeError:
210+
pass
211+
212+
self.assertFalse(hasattr(obj, 'other_prop'))

0 commit comments

Comments
 (0)