nested-lookup/test_lookup_api.py
Salfiii 4f37d265c8 "nested_alter" and update of "nested_update" (#16)
* Update lookup_api.py

moved the typecheck of the value argument to the wrapper function.

* added tests for nested_update Test

* pep8 format standards
moded _call_callback out of the nested_alter Method
Raised an Exception is no list is provided but treas_as_elemenet is false
treat_list_as_element:bool renamed to treat_as_element:bool and set default to True

* Auto commit via script

* Create CONTRIBUTORS.rst

* Rename CONTRIBUTORS.rst to CONTRIBUTING.rst

* Update CONTRIBUTING.rst

* Fix for issue #17 (#18)

* Fix for issue #17
* Updating version (and) Adding Travis CI support
* Adding Build status to README

* changed the type annotation of the input document (removed it)
removed the output type hint
change the Readme

* Update lookup_api.py

moved the typecheck of the value argument to the wrapper function.

* added tests for nested_update Test

* pep8 format standards
moded _call_callback out of the nested_alter Method
Raised an Exception is no list is provided but treas_as_elemenet is false
treat_list_as_element:bool renamed to treat_as_element:bool and set default to True


* changed the type annotation of the input document (removed it)
removed the output type hint
change the Readme
2019-04-29 20:06:10 -04:00

635 lines
22 KiB
Python

from unittest import TestCase
from nested_lookup import nested_lookup, nested_update
from nested_lookup import nested_delete, nested_alter
class BaseLookUpApi(TestCase):
def setUp(self):
self.sample_data1 = {
"build_version": {
"model_name": 'MacBook Pro',
"build_version": {
"processor_name": 'Intel Core i7',
"processor_speed": '2.7 GHz',
"core_details": {
"build_version": '4',
"l2_cache(per_core)": '256 KB'
}
},
"number_of_cores": '4',
"memory": '256 KB'
},
"os_details": {
"product_version": '10.13.6',
"build_version": '17G65'
},
"name": 'Test',
"date": 'YYYY-MM-DD HH:MM:SS'
}
self.sample_data2 = {
"hardware_details": {
"model_name": 'MacBook Pro',
"processor_details": [
{
"processor_name": 'Intel Core i7',
"processor_speed": '2.7 GHz'
},
{
"total_number_of_cores": '4',
"l2_cache(per_core)": '256 KB'
}
],
"total_number_of_cores": '5',
"memory": '16 GB'
}
}
self.sample_data3 = {
"values": [{
"checks": [{
"monitoring_zones":
["mzdfw", "mzfra", "mzhkg", "mziad",
"mzlon", "mzord", "mzsyd"]
}]
}]
}
self.sample_data4 = {
"modelversion": "1.1.0",
"vorgangsID": "1",
"versorgungsvorschlagDatum": 1510558834978,
"eingangsdatum": 1510558834978,
"plz": 82269,
"vertragsteile": [
{
"typ": "1",
"beitragsDaten": {
"endalter": 85,
"brutto": 58.76,
"netto": 58.76,
"zahlungsrhythmus": "MONATLICH",
"plz": 86899
},
"beginn": 1512082800000,
"lebenslang": "True",
"ueberschussverwendung": {
"ueberschussverwendung": "2",
"indexoption": "3"
},
"deckung": [
{
"typ": "2",
"art": "1",
"leistung": {
"value": 7500242424.0,
"einheit": "2"
},
"leistungsRhythmus": "1"
}
],
"zuschlagNachlass": []
},
{
"typ": "1",
"beitragsDaten": {
"endalter": 85,
"brutto": 0.6,
"netto": 0.6,
"zahlungsrhythmus": "1"
},
"zuschlagNachlass": []
}
]
}
class TestNestedDelete(BaseLookUpApi):
def test_sample_data1(self):
result = {
"os_details": {
"product_version": '10.13.6'
},
"name": 'Test',
"date": 'YYYY-MM-DD HH:MM:SS'
}
self.assertEqual(
result, nested_delete(self.sample_data1, 'build_version')
)
def test_sample_data2(self):
result = {
"hardware_details": {
"model_name": 'MacBook Pro',
"total_number_of_cores": '5',
"memory": '16 GB'
}
}
self.assertEqual(
result, nested_delete(self.sample_data2, 'processor_details')
)
def test_sample_data3(self):
result = {"values": [{"checks": [{}]}]}
self.assertEqual(
result, nested_delete(self.sample_data3, 'monitoring_zones')
)
class TestNestedUpdate(BaseLookUpApi):
def test_sample_data1(self):
result = {
"build_version": "Test1",
"os_details": {
"product_version": '10.13.6',
"build_version": 'Test1'
},
"name": 'Test',
"date": 'YYYY-MM-DD HH:MM:SS'
}
self.assertEqual(
result, nested_update(self.sample_data1, 'build_version', 'Test1')
)
def test_sample_data1_list_input_treat_list_as_element_true(self):
result = {
"build_version": ["Test5", "Test6", "Test7"],
"os_details": {
"product_version": '10.13.6',
"build_version": ["Test5", "Test6", "Test7"]
},
"name": 'Test',
"date": 'YYYY-MM-DD HH:MM:SS'
}
self.assertEqual(
result, nested_update(
self.sample_data1,
'build_version',
["Test5", "Test6", "Test7"],
treat_as_element=True)
)
def test_nested_update_in_place_false(self):
"""
ested_update should mutate and return a copy of the original document
"""
before_id = id(self.sample_data1)
result = nested_update(self.sample_data1, 'build_version', 'Test2',
in_place=False)
after_id = id(result)
# the object ids should _not_ match.
self.assertNotEqual(before_id, after_id)
def test_nested_update_in_place_true(self):
"""
nested_update should mutate and return the original document
"""
before_id = id(self.sample_data1)
result = nested_update(
self.sample_data1, 'build_version', 'Test2', in_place=True)
after_id = id(result)
# the object ids should match.
self.assertEqual(before_id, after_id)
def test_nested_update_in_place_true_list_input(self):
doc = self.sample_data4
# get all instances of the given element
findings = nested_lookup("plz", doc, False, True)
# alter those instances
updated_findings = list()
for key, val in findings.items():
for elem in val:
updated_findings.append(elem + 300)
# update those instances with the altered results
doc_updated = nested_update(
doc, "plz", updated_findings, treat_as_element=False)
elem1 = doc_updated["plz"] # 85269
# 87199
elem2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
self.assertEqual(elem1, 82569)
self.assertEqual(elem2, 87199)
def test_nested_update_in_place_false_list_input(self):
doc = self.sample_data4
# get all instances of the given element
findings = nested_lookup("plz", doc, False, True)
# alter those instances
updated_findings = list()
for key, val in findings.items():
for elem in val:
updated_findings.append(elem + 300)
# update those instances with the altered results
doc_updated = nested_update(
doc, "plz", updated_findings, in_place=False,
treat_as_element=False)
elem1 = doc_updated["plz"]
elem2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
self.assertEqual(elem1, 82569)
self.assertEqual(elem2, 87199)
def test_nested_update_in_place_false_list_input_as_element_false(self):
doc = self.sample_data4
# get all instances of the given element
list_input = [1, 2, 3, 4, 5]
# update those instances with the altered results
doc_updated = nested_update(
doc, "plz", list_input, in_place=False, treat_as_element=False)
elem1 = doc_updated["plz"]
elem2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
# should not work without specifying "treat_list_as_element = True"
# in nested_update
self.assertNotEqual(elem1, list_input)
self.assertNotEqual(elem2, list_input)
def test_nested_update_in_place_false_list_input_as_element_true(self):
doc = self.sample_data4
# get all instances of the given element
list_input = [1, 2, 3, 4, 5]
# update those instances with the altered results
doc_updated = nested_update(
doc, "plz", list_input, in_place=False, treat_as_element=True)
elem1 = doc_updated["plz"]
elem2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
# should not work without specifying "treat_list_as_element = True"
# in nested_update
self.assertEqual(elem1, list_input)
self.assertEqual(elem2, list_input)
def test_nested_update_in_place_true_list_input_as_element_false(self):
doc = self.sample_data4
# get all instances of the given element
list_input = [1, 2, 3, 4, 5]
# update those instances with the altered results
doc_updated = nested_update(
doc, "plz", list_input, in_place=True, treat_as_element=False)
elem1 = doc_updated["plz"]
elem2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
# should not work without specifying "treat_list_as_element = True"
# in nested_update
self.assertNotEqual(elem1, list_input)
self.assertNotEqual(elem2, list_input)
def test_nested_update_in_place_true_list_input_as_element_true(self):
doc = self.sample_data4
# get all instances of the given element
list_input = [1, 2, 3, 4, 5]
# update those instances with the altered results
doc_updated = nested_update(
doc, "plz", list_input, in_place=True, treat_as_element=True)
elem1 = doc_updated["plz"]
elem2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
# should not work without specifying "treat_list_as_element = True"
# in nested_update
self.assertEqual(elem1, list_input)
self.assertEqual(elem2, list_input)
def test_nested_delete_in_place_false(self):
"""
nested_delete should mutate and return a copy of the original document
"""
before_id = id(self.sample_data1)
result = nested_delete(
self.sample_data1, 'build_version', in_place=False)
after_id = id(result)
# the object ids should _not_ match.
self.assertNotEqual(before_id, after_id)
def test_nested_delete_in_place_true(self):
"""nested_delete should mutate and return the original document"""
before_id = id(self.sample_data1)
result = nested_delete(
self.sample_data1, 'build_version', in_place=True)
after_id = id(result)
# the object ids should match.
self.assertEqual(before_id, after_id)
def test_nested_update_taco_for_example(self):
document = [
{'taco': 42},
{'salsa': [{'burrito': {'taco': 69}}]}
]
updated_document = nested_update(
document, "taco", [100, 200], treat_as_element=False)
self.assertEqual(updated_document[0]["taco"], 100)
# The multi-update version only works for scalar input,
# if you need to adress a list of dicts, you have to
# manually iterate over those and pass them to nested_update
# one by one
self.assertNotEqual(
updated_document[1]["salsa"][0]["burrito"]["taco"], 200)
def test_nested_update_raise_error(self):
doc = self.sample_data4
# get all instances of the given element
list_input = 1
# update those instances with the altered results
self.assertRaises(
Exception,
nested_update, doc, "plz", list_input,
in_place=True, treat_as_element=False
)
def test_sample_data2(self):
result = {
"hardware_details": {
"model_name": 'MacBook Pro',
"processor_details": {
'test_key1': 'test_value1'
},
"total_number_of_cores": '5',
"memory": '16 GB'
}
}
self.assertEqual(
result, nested_update(
self.sample_data2, 'processor_details',
{'test_key1': 'test_value1'}
)
)
def test_sample_data3(self):
result = {
"values": [{
"checks": {
'key1': ['value1'],
'key2': 'value2'
}
}]
}
self.assertEqual(
result, nested_update(
self.sample_data3, 'checks',
{
'key1': ['value1'],
'key2': 'value2'
}
)
)
def test_sample_data4(self):
result = {
"modelversion": {
'key1': ['value1'],
'key2': 'value2'
},
"vorgangsID": "1",
"versorgungsvorschlagDatum": 1510558834978,
"eingangsdatum": 1510558834978,
"plz": 82269,
"vertragsteile": [
{
"typ": "1",
"beitragsDaten": {
"endalter": 85,
"brutto": 58.76,
"netto": 58.76,
"zahlungsrhythmus": "MONATLICH",
"plz": 86899
},
"beginn": 1512082800000,
"lebenslang": "True",
"ueberschussverwendung": {
"ueberschussverwendung": "2",
"indexoption": "3"
},
"deckung": [
{
"typ": "2",
"art": "1",
"leistung": {
"value": 7500242424.0,
"einheit": "2"
},
"leistungsRhythmus": "1"
}
],
"zuschlagNachlass": []
},
{
"typ": "1",
"beitragsDaten": {
"endalter": 85,
"brutto": 0.6,
"netto": 0.6,
"zahlungsrhythmus": "1"
},
"zuschlagNachlass": []
}
]
}
self.assertEqual(
result, nested_update(
self.sample_data4, 'modelversion',
{
'key1': ['value1'],
'key2': 'value2'
}
)
)
class TestNestedAlter(BaseLookUpApi):
def test_nested_alter_in_place_true(self):
# callback functions
def callback(data):
return str(data) + "###"
doc_updated = nested_alter(
self.sample_data4, "vorgangsID", callback, in_place=True)
vorgangsid = doc_updated["vorgangsID"]
self.assertEqual(vorgangsid, "1###")
def test_nested_alter_in_place_false(self):
# callback functions
def callback(data):
return str(data) + "###"
doc_updated = nested_alter(
self.sample_data4, "vorgangsID", callback, in_place=False)
vorgangsid = doc_updated["vorgangsID"]
# should not work without specifying
# "treat_list_as_element = True" in nested_update
self.assertEqual(vorgangsid, "1###")
def test_nested_alter_list_input_in_place_true(self):
# callback functions
def callback(data):
return str(data) + "###"
doc_updated = nested_alter(
self.sample_data4, ["plz", "vorgangsID"], callback, in_place=True)
plz1 = doc_updated["plz"]
plz2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
vorgangsid = doc_updated["vorgangsID"]
# should not work without specifying
# "treat_list_as_element = True" in nested_update
self.assertEqual(plz1, "82269###")
self.assertEqual(plz2, "86899###")
self.assertEqual(vorgangsid, "1###")
def test_nested_alter_list_input_with_args_in_place_true(self):
# callback functions
def callback(data, str1, str2):
return str(data) + str1 + str2
doc_updated = nested_alter(self.sample_data4, [
"plz", "vorgangsID"],
callback,
function_parameters=["abc", "def"],
in_place=True
)
plz1 = doc_updated["plz"]
plz2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
vorgangsid = doc_updated["vorgangsID"]
# should not work without specifying
# "treat_list_as_element = True" in nested_update
self.assertEqual(plz1, "82269abcdef")
self.assertEqual(plz2, "86899abcdef")
self.assertEqual(vorgangsid, "1abcdef")
def test_nested_alter_list_input_with_args_in_place_false(self):
# callback functions
def callback(data, str1, str2):
return str(data) + str1 + str2
doc_updated = nested_alter(self.sample_data4, [
"plz", "vorgangsID"],
callback,
function_parameters=["abc", "def"],
in_place=False
)
plz1 = doc_updated["plz"]
plz2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
vorgangsid = doc_updated["vorgangsID"]
# should not work without specifying
# "treat_list_as_element = True" in nested_update
self.assertEqual(plz1, "82269abcdef")
self.assertEqual(plz2, "86899abcdef")
self.assertEqual(vorgangsid, "1abcdef")
def test_nested_alter_list_input_in_place_false(self):
# callback functions
def callback(data):
return str(data) + "###"
doc_updated = nested_alter(
self.sample_data4, ["plz", "vorgangsID"], callback, in_place=False)
plz1 = doc_updated["plz"]
plz2 = doc_updated["vertragsteile"][0]["beitragsDaten"]["plz"]
vorgangsid = doc_updated["vorgangsID"]
# should not work without specifying
# "treat_list_as_element = True" in nested_update
self.assertEqual(plz1, "82269###")
self.assertEqual(plz2, "86899###")
self.assertEqual(vorgangsid, "1###")
def test_nested_alter_taco_for_example(self):
documents = [
{'taco': 42},
{'salsa': [{'burrito': {'taco': 69}}]}
]
# write a callback function which processes a scalar value.
# Be aware about the possible types which can be passed to
# the callback functions.
# In this example we can be sure that only int will be passed,
# in production you should check the type because it could be
# anything.
def callback(data):
return data + 10 # (data/100*10)
# The alter-version only works for scalar input (one dict),
# if you need to adress a list of dicts, you have to
# manually iterate over those and pass them to
# nested_update one by one
out = []
for elem in documents:
altered_document = nested_alter(elem, "taco", callback)
out.append(altered_document)
self.maxDiff = None
self.assertEqual(out[0]["taco"], 52)
self.assertEqual(out[1]["salsa"][0]["burrito"]["taco"], 79)
def test_sample_data4(self):
result = {
"modelversion": "1.1.0",
"vorgangsID": "1",
"versorgungsvorschlagDatum": 1510558834978,
"eingangsdatum": 1510558834978,
"plz": 82270,
"vertragsteile": [
{
"typ": "1",
"beitragsDaten": {
"endalter": 85,
"brutto": 58.76,
"netto": 58.76,
"zahlungsrhythmus": "MONATLICH",
"plz": 86900
},
"beginn": 1512082800000,
"lebenslang": "True",
"ueberschussverwendung": {
"ueberschussverwendung": "2",
"indexoption": "3"
},
"deckung": [
{
"typ": "2",
"art": "1",
"leistung": {
"value": 7500242424.0,
"einheit": "2"
},
"leistungsRhythmus": "1"
}
],
"zuschlagNachlass": []
},
{
"typ": "1",
"beitragsDaten": {
"endalter": 85,
"brutto": 0.6,
"netto": 0.6,
"zahlungsrhythmus": "1"
},
"zuschlagNachlass": []
}
]
}
# add +1 to all plz
def callback(data):
return data + 1
self.maxDiff = None
self.assertEqual(
result, nested_alter(self.sample_data4, 'plz', callback)
)