From e26a42569ffbbac17e84931c8ca826793b372c24 Mon Sep 17 00:00:00 2001 From: Christian Herz Date: Thu, 20 Oct 2016 17:24:56 -0400 Subject: [PATCH 1/3] BUG: For preventing unexpected behavior while executing are_same, contains or json_are_same several times, setting lists to None instead of [] for reference see http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments --- jsoncompare/jsoncompare.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jsoncompare/jsoncompare.py b/jsoncompare/jsoncompare.py index 9a2357f..80da069 100644 --- a/jsoncompare/jsoncompare.py +++ b/jsoncompare/jsoncompare.py @@ -144,7 +144,8 @@ def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False) return False, Stack().append(StackItem('Unhandled Type: {0}'.format(type(expected)), expected, actual)) -def are_same(original_a, original_b, ignore_list_order_recursively=False, ignore_value_of_keys=[]): +def are_same(original_a, original_b, ignore_list_order_recursively=False, ignore_value_of_keys=None): + ignore_value_of_keys = ignore_value_of_keys if ignore_value_of_keys else [] if ignore_list_order_recursively: a = _bottom_up_sort(original_a) b = _bottom_up_sort(original_b) @@ -154,7 +155,9 @@ def are_same(original_a, original_b, ignore_list_order_recursively=False, ignore return _are_same(a, b, ignore_value_of_keys) -def contains(expected_original, actual_original, ignore_list_order_recursively=False, ignore_value_of_keys=[]): +def contains(expected_original, actual_original, ignore_list_order_recursively=False, ignore_value_of_keys=None): + ignore_value_of_keys = ignore_value_of_keys if ignore_value_of_keys else [] + if ignore_list_order_recursively: actual = _bottom_up_sort(actual_original) expected = _bottom_up_sort(expected_original) @@ -163,6 +166,7 @@ def contains(expected_original, actual_original, ignore_list_order_recursively=F expected = expected_original return _are_same(expected, actual, ignore_value_of_keys, True) -def json_are_same(a, b, ignore_list_order_recursively=False, ignore_value_of_keys=[]): +def json_are_same(a, b, ignore_list_order_recursively=False, ignore_value_of_keys=None): + ignore_value_of_keys = ignore_value_of_keys if ignore_value_of_keys else [] return are_same(json.loads(a), json.loads(b), ignore_list_order_recursively, ignore_value_of_keys) From 5969ff5a8c9860fc33238e29c3d47f348e46bc58 Mon Sep 17 00:00:00 2001 From: Christian Herz Date: Thu, 20 Oct 2016 18:45:22 -0400 Subject: [PATCH 2/3] ENH: Refactoring and simplified code --- jsoncompare/jsoncompare.py | 70 ++++++++++++++------------------------ 1 file changed, 25 insertions(+), 45 deletions(-) diff --git a/jsoncompare/jsoncompare.py b/jsoncompare/jsoncompare.py index 80da069..bfcfe79 100644 --- a/jsoncompare/jsoncompare.py +++ b/jsoncompare/jsoncompare.py @@ -1,5 +1,5 @@ import json -from pprint import pprint + class Stack: def __init__(self): @@ -52,7 +52,9 @@ def _generate_pprint_json(value): def _is_dict_same(expected, actual, ignore_value_of_keys): # DAN - I had to flip flop this for key in expected: - if not key in actual: + if key in ignore_value_of_keys: + continue + if key not in actual: return False, \ Stack().append( StackItem('Expected key "{0}" Missing from Actual' @@ -60,15 +62,13 @@ def _is_dict_same(expected, actual, ignore_value_of_keys): expected, actual)) - if not key in ignore_value_of_keys: - # have to change order - #are_same_flag, stack = _are_same(actual[key], expected[key], ignore_value_of_keys) - are_same_flag, stack = _are_same(expected[key], actual[key],ignore_value_of_keys) - if not are_same_flag: - return False, \ - stack.append(StackItem('Different values', expected[key], actual[key])) + are_same_flag, stack = _are_same(expected[key], actual[key],ignore_value_of_keys) + if not are_same_flag: + return False, \ + stack.append(StackItem('Different values', expected[key], actual[key])) return True, Stack() + def _is_list_same(expected, actual, ignore_value_of_keys): for i in xrange(len(expected)): are_same_flag, stack = _are_same(expected[i], actual[i], ignore_value_of_keys) @@ -78,6 +78,7 @@ def _is_list_same(expected, actual, ignore_value_of_keys): StackItem('Different values (Check order)', expected[i], actual[i])) return True, Stack() + def _bottom_up_sort(unsorted_json): if isinstance(unsorted_json, list): new_list = [] @@ -94,6 +95,7 @@ def _bottom_up_sort(unsorted_json): else: return unsorted_json + def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False): # Check for None if expected is None: @@ -112,29 +114,14 @@ def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False) if type(expected) in (int, str, bool, long, float, unicode): return expected == actual, Stack() - # Ensure collections have the same length (if applicable) - if ignore_missing_keys: - # Ensure collections has minimum length (if applicable) - # This is a short-circuit condition because (b contains a) - if len(expected) > len(actual): - return False, \ - Stack().append( - StackItem('Length Mismatch: Minimum Expected Length: {0}, Actual Length: {1}' - .format(len(expected), len(actual)), - expected, - actual)) - - else: - # Ensure collections has same length - if len(expected) != len(actual): - return False, \ - Stack().append( - StackItem('Length Mismatch: Expected Length: {0}, Actual Length: {1}' - .format(len(expected), len(actual)), - expected, - actual)) - - + if not ignore_missing_keys and len(expected) > len(actual): + # TODO: you could also take ignore_value_of_keys into account + return False, \ + Stack().append( + StackItem('Length Mismatch: Expected Length: {0}, Actual Length: {1}' + .format(len(expected), len(actual)), + expected, + actual)) if isinstance(expected, dict): return _is_dict_same(expected, actual, ignore_value_of_keys) @@ -144,28 +131,21 @@ def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False) return False, Stack().append(StackItem('Unhandled Type: {0}'.format(type(expected)), expected, actual)) + def are_same(original_a, original_b, ignore_list_order_recursively=False, ignore_value_of_keys=None): ignore_value_of_keys = ignore_value_of_keys if ignore_value_of_keys else [] - if ignore_list_order_recursively: - a = _bottom_up_sort(original_a) - b = _bottom_up_sort(original_b) - else: - a = original_a - b = original_b + a = _bottom_up_sort(original_a) if ignore_list_order_recursively else original_a + b = _bottom_up_sort(original_b) if ignore_list_order_recursively else original_b return _are_same(a, b, ignore_value_of_keys) def contains(expected_original, actual_original, ignore_list_order_recursively=False, ignore_value_of_keys=None): ignore_value_of_keys = ignore_value_of_keys if ignore_value_of_keys else [] - - if ignore_list_order_recursively: - actual = _bottom_up_sort(actual_original) - expected = _bottom_up_sort(expected_original) - else: - actual = actual_original - expected = expected_original + actual = _bottom_up_sort(actual_original) if ignore_list_order_recursively else actual_original + expected = _bottom_up_sort(expected_original) if ignore_list_order_recursively else expected_original return _are_same(expected, actual, ignore_value_of_keys, True) + def json_are_same(a, b, ignore_list_order_recursively=False, ignore_value_of_keys=None): ignore_value_of_keys = ignore_value_of_keys if ignore_value_of_keys else [] return are_same(json.loads(a), json.loads(b), ignore_list_order_recursively, ignore_value_of_keys) From b8289b51cbc1f971754565bc6f8504f24963bfc0 Mon Sep 17 00:00:00 2001 From: Christian Herz Date: Thu, 20 Oct 2016 19:03:36 -0400 Subject: [PATCH 3/3] ENH: Added missing keys to Stack --- jsoncompare/jsoncompare.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/jsoncompare/jsoncompare.py b/jsoncompare/jsoncompare.py index bfcfe79..7829e94 100644 --- a/jsoncompare/jsoncompare.py +++ b/jsoncompare/jsoncompare.py @@ -115,13 +115,11 @@ def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False) return expected == actual, Stack() if not ignore_missing_keys and len(expected) > len(actual): - # TODO: you could also take ignore_value_of_keys into account - return False, \ - Stack().append( - StackItem('Length Mismatch: Expected Length: {0}, Actual Length: {1}' - .format(len(expected), len(actual)), - expected, - actual)) + stack = Stack().append(StackItem('Length Mismatch: Expected Length: {0}, Actual Length: {1}' + .format(len(expected), len(actual)), expected, actual)) + if isinstance(expected, dict): + stack.append('Missing keys: {0}'.format(get_missing_keys(expected, actual))) + return False, stack if isinstance(expected, dict): return _is_dict_same(expected, actual, ignore_value_of_keys) @@ -132,6 +130,10 @@ def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False) return False, Stack().append(StackItem('Unhandled Type: {0}'.format(type(expected)), expected, actual)) +def get_missing_keys(expected, actual): + return [key for key in expected if key not in actual] + + def are_same(original_a, original_b, ignore_list_order_recursively=False, ignore_value_of_keys=None): ignore_value_of_keys = ignore_value_of_keys if ignore_value_of_keys else [] a = _bottom_up_sort(original_a) if ignore_list_order_recursively else original_a