Skip to content

Commit

Permalink
Merge pull request #24 from robabram/ra/object-update
Browse files Browse the repository at this point in the history
Allow updating object using update() method or plus operator
  • Loading branch information
robabram authored Sep 27, 2023
2 parents 58e9acd + 2ee1ffb commit 9325464
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 2 deletions.
10 changes: 9 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,15 @@ Documentation
:param dates_to_str: Boolean, convert all date or datetime values to string.
:returns: dictionary object

JSONObject.update([Dict|List|Tuple]) accepts either a dictionary object or an iterable of key/value
pairs (as tuples or other iterables of length two). If keyword arguments are specified, the dictionary
is then updated with those key/value pairs: obj.update(sky=1, cloud=2).

Plus Operator: Two JSONObjects may be merged using the plus (+) operator: obj = obj + other_obj.

Number of Properties: The number of managed properties may be determined by using the Python 'len()'
function: len(obj) == 5.

Project Links
=============

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from setuptools import setup, find_packages

__VERSION__ = "1.1.9"
__VERSION__ = "1.1.10"

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

Expand Down
31 changes: 31 additions & 0 deletions src/python_easy_json/json_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,34 @@ def to_dict(self, recursive: bool = True, dates_to_str: bool = False):

def __repr__(self):
return self.to_json()

def __len__(self):
return len(self.__data_dict__.keys())

def __add__(self, other):
if not isinstance(other, JSONObject):
raise TypeError(f"Invalid operand type for +: 'JSONObject' and '{str(other)}'")
return self.update(**other.to_dict())

def update(self, *args, **kwargs) -> "JSONObject":
"""
Update or add additional properties to this object by passing a dictionary or list of key value pairs.
"""
if args:
for arg in args:
if isinstance(arg, dict):
for k, v in arg.items():
setattr(self, k, v)
elif isinstance(arg, (list, tuple)):
for item in arg:
if len(item) != 2:
raise ValueError('Invalid tuple size')
setattr(self, item[0], item[1])
else:
raise TypeError(f"TypeError: '{type(arg)}' object is not iterable")

elif kwargs:
for k, v in kwargs.items():
setattr(self, k, v)

return self
101 changes: 101 additions & 0 deletions tests/test_simple_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,104 @@ def test_setattr_after_init(self):
data = obj.to_dict()
self.assertEqual(data['new_prop'], 'abc')
self.assertEqual(data['test_prop'], 123)

def test_update_with_dict(self):
""" Test we can update the JSONObject by passing a dict object """
obj = JSONObject({'test_prop': 123})
self.assertIsInstance(obj, JSONObject)

obj = obj.update({'test_prop': 456, 'new_prop': 987})

self.assertEqual(obj.new_prop, 987)
self.assertEqual(obj.test_prop, 456)

data = obj.to_dict()

self.assertEqual(data['new_prop'], 987)
self.assertEqual(data['test_prop'], 456)

def test_update_with_keyword_args(self):
""" Test we can update the JSONObject by passing key word arguments """
obj = JSONObject({'test_prop': 123})
self.assertIsInstance(obj, JSONObject)

obj = obj.update(test_prop=456, new_prop=987)

self.assertEqual(obj.new_prop, 987)
self.assertEqual(obj.test_prop, 456)

data = obj.to_dict()

self.assertEqual(data['new_prop'], 987)
self.assertEqual(data['test_prop'], 456)

def test_update_with_iterable_pairs(self):
""" Test we can update the JSONObject by passing iterable pair arguments """
obj = JSONObject({'test_prop': 123})
self.assertIsInstance(obj, JSONObject)

obj = obj.update([('test_prop', 456), ('new_prop', 987)])

self.assertEqual(obj.new_prop, 987)
self.assertEqual(obj.test_prop, 456)

data = obj.to_dict()

self.assertEqual(data['new_prop'], 987)
self.assertEqual(data['test_prop'], 456)

def test_update_exceptions(self):
""" Test update using bad data to cause exceptions """

obj = JSONObject({'test_prop': 123})
self.assertIsInstance(obj, JSONObject)

# Test no args, should not raise an error.
self.assertIsInstance(obj.update({}), JSONObject)

# Test non-iterable value raises TypeError
self.assertRaises(TypeError, obj.update, None)
self.assertRaises(TypeError, obj.update, 123)

# Test bad iterable pair raise ValueError
self.assertRaises(ValueError, obj.update, [('test_prop', 456, 333)])

def test_number_of_properties(self):
""" Test the number of properties by calling len() function """

obj = JSONObject({'test_prop': 123, 'another_prop': 'abc'})
self.assertIsInstance(obj, JSONObject)

self.assertEqual(len(obj), 2)

def test_add_object(self):
""" Test add object """
obj = JSONObject({'test_prop': 123})
self.assertIsInstance(obj, JSONObject)

other_obj = JSONObject({'another_prop': 'abc'})
self.assertIsInstance(other_obj, JSONObject)

island_other_obj = JSONObject({'island_prop': 'sandy'})
self.assertIsInstance(island_other_obj, JSONObject)

obj += other_obj

self.assertEqual(obj.test_prop, 123)
self.assertEqual(obj.another_prop, 'abc')

obj = obj + island_other_obj

self.assertEqual(obj.island_prop, 'sandy')

def test_add_invalid_operand(self):
""" Test adding an invalid operand """
obj = JSONObject({'test_prop': 123})
self.assertIsInstance(obj, JSONObject)

try:
obj += {'other_prop': 'abc'}
except TypeError:
pass

self.assertFalse(hasattr(obj, 'other_prop'))

0 comments on commit 9325464

Please sign in to comment.