def test_traverse_lines(self): name = self.name subject = self.subject grade = self.grade rank = self.rank hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict11 = {'Alice': {'Grade': 4.0}} value_dict12 = {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.0}} value_dict21 = {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}, 'CS': {'Rank': 2, 'Grade': 3.9}}} value_dict22 = {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}, 'CS': {'Rank': 2, 'Grade': 3.8}}, 'Bob': {'Math': {'Rank': 2, 'Grade': 3.0}, 'CS': {'Rank': 1, 'Grade': 3.9}}} value_lines11 = [{'Name': 'Alice', 'Grade': 4.0}] value_lines12 = [{'Name': 'Alice', 'Grade': 4.0}, {'Name': 'Bob', 'Grade': 3.0}] value_lines21 = [{'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0}, {'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.9}] value_lines22 = [{'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0}, {'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.8}, {'Name': 'Bob', 'Subject': 'Math', 'Rank': 2, 'Grade': 3.0}, {'Name': 'Bob', 'Subject': 'CS', 'Rank': 1, 'Grade': 3.9}] self.assertEqual(value_dict11, Hierarchy.traverse_lines(hierarchy1, value_lines11)) self.assertEqual(value_dict12, Hierarchy.traverse_lines(hierarchy1, value_lines12)) self.assertEqual(value_dict21, Hierarchy.traverse_lines(hierarchy2, value_lines21)) self.assertEqual(value_dict22, Hierarchy.traverse_lines(hierarchy2, value_lines22))
def test_apply_post_map(self): name = self.name subject = self.subject grade = self.grade rank = self.rank grade.post_map_f = lambda _, x: x - 1.0 rank.post_map_f = lambda _, x: x + 1 hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict1 = {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.0}} value_dict2 = { 'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 } }, 'Bob': { 'CS': { 'Rank': 2, 'Grade': 3.0 } } } Hierarchy.apply_post_map(hierarchy1, value_dict1, {}) Hierarchy.apply_post_map(hierarchy2, value_dict2, {}) self.assertEqual(value_dict1, { 'Alice': { 'Grade': 3.0 }, 'Bob': { 'Grade': 2.0 } }) self.assertEqual( value_dict2, { 'Alice': { 'Math': { 'Rank': 2, 'Grade': 3.0 } }, 'Bob': { 'CS': { 'Rank': 3, 'Grade': 2.0 } } })
def __init__(self, hierarchy_spec, value_line): """Initialize the writer. :param hierarchy_spec: a hierarchy specification (described in Hierarchy.py) describing the input dictionary. :param value_line ([GeneralValue]): an ordered value object list specifying each line of output. """ Hierarchy.check(hierarchy_spec) for value in value_line: if not isinstance(value, GeneralValue): raise ValueError("Value is not a value object") self.hierarchy_spec = hierarchy_spec self.value_line = value_line
def test_merge(self): name = self.name subject = self.subject grade = self.grade rank = self.rank.state_value() grade.reduce_f = max rank.reduce_f = min grade.post_map_f = lambda _, x: x - 1.0 rank.post_map_f = lambda _, x: x + 1 grade.post_reduce_f = min rank.post_reduce_f = max hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict11 = {'Alice': {'Grade': 4.0}} value_dict12 = {'Alice': {'Grade': 3.0}} value_dict13 = {'Bob': {'Grade': 3.5}} value_dict20 = {'Alice': {'Math': {'Rank': 2, 'Grade': 3.0}}} value_dict21 = {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}}} value_dict22 = {'Alice': {'CS': {'Rank': 2, 'Grade': 3.9}}} value_dict23 = {'Bob': {'Math': {'Rank': 2, 'Grade': 3.0}}} self.assertEqual(Hierarchy.merge(hierarchy1, value_dict11, value_dict12), {'Alice': {'Grade': 4.0}}) self.assertEqual(Hierarchy.merge(hierarchy1, value_dict11, value_dict12, True), {'Alice': {'Grade': 2.0}}) self.assertEqual(Hierarchy.merge(hierarchy1, value_dict11, value_dict13), {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.5}}) self.assertEqual(Hierarchy.merge(hierarchy1, value_dict11, value_dict13, True), {'Alice': {'Grade': 3.0}, 'Bob': {'Grade': 2.5}}) self.assertEqual(Hierarchy.merge(hierarchy2, value_dict20, value_dict21), {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}}}) self.assertEqual(Hierarchy.merge(hierarchy2, value_dict20, value_dict21, True), {'Alice': {'Math': {'Rank': 3, 'Grade': 2.0}}}) self.assertEqual(Hierarchy.merge(hierarchy2, value_dict21, value_dict22), {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}, 'CS': {'Rank': 2, 'Grade': 3.9}}}) self.assertEqual(Hierarchy.merge(hierarchy2, value_dict21, value_dict22, True), {'Alice': {'Math': {'Rank': 2, 'Grade': 3.0}, 'CS': {'Rank': 3, 'Grade': 2.9}}}) self.assertEqual(Hierarchy.merge(hierarchy2, value_dict21, value_dict23), {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}}, 'Bob': {'Math': {'Rank': 2, 'Grade': 3.0}}}) self.assertEqual(Hierarchy.merge(hierarchy2, value_dict21, value_dict23, True), {'Alice': {'Math': {'Rank': 2, 'Grade': 3.0}}, 'Bob': {'Math': {'Rank': 3, 'Grade': 2.0}}})
def __init__(self, hierarchy_spec, state=State({}), filter_f=lambda _, x: True): """Initialize the reader. :param hierarchy_spec: a (or a list of) hierarchy specification (described in Hierarchy.py). :param state (State): the state involved in reading. :param filter_f (State * Line -> bool): the predicate for filtering lines with access to state. """ Hierarchy.check(hierarchy_spec) if not isinstance(state, State): raise ValueError("State is a State object") self.hierarchy_spec = hierarchy_spec self.state = state self.filter_f = filter_f self.__init_state = deepcopy(self.state)
def read_lines(self, value_lines, apply_post_map=False, carry_state=False): """Store the data in a list of lines with respect to the hierarchy specification of values :param value_lines ([dict]): a list of (name => value) dictionary :param apply_post_map (bool): whether apply post_map or not :param carry_state: whether mutate the input state :return (dict): the result dictionary and the final state. """ # if not carry state, copy the state object such that the input state is not mutated. if not carry_state: current_state = deepcopy(self.state) else: current_state = self.state value_hierarchy = Hierarchy.traverse_lines(self.hierarchy_spec, value_lines, current_state, self.filter_f) # apply post_map_f in each value if apply_post_map is true if apply_post_map: Hierarchy.apply_post_map(self.hierarchy_spec, value_hierarchy, current_state) return value_hierarchy, current_state
def write(self, out_file, value_hierarchy, mode='w', sort_by=None, reverse=False): """Write a file according to value line specification. :param out_file (OutputFile): the file to write. :param value_hierarchy (dict): a value hierarchy (dictionary) for writing to the file. :param mode (str): writing mode ("w", "w+", ...) :param sort_by (str): the name of a value to sort by. :param reverse: sort in reverse order or not. """ # flatten the value hierarchy (dictionary) value_lines = Hierarchy.flatten(self.hierarchy_spec, value_hierarchy) self.write_lines(out_file, value_lines, mode, sort_by, reverse)
def test_apply_post_map(self): name = self.name subject = self.subject grade = self.grade rank = self.rank grade.post_map_f = lambda _, x: x - 1.0 rank.post_map_f = lambda _, x: x + 1 hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict1 = {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.0}} value_dict2 = {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}}, 'Bob': {'CS': {'Rank': 2, 'Grade': 3.0}}} Hierarchy.apply_post_map(hierarchy1, value_dict1, {}) Hierarchy.apply_post_map(hierarchy2, value_dict2, {}) self.assertEqual(value_dict1, {'Alice': {'Grade': 3.0}, 'Bob': {'Grade': 2.0}}) self.assertEqual(value_dict2, {'Alice': {'Math': {'Rank': 2, 'Grade': 3.0}}, 'Bob': {'CS': {'Rank': 3, 'Grade': 2.0}}})
def test_flatten(self): name = self.name subject = self.subject grade = self.grade rank = self.rank.state_value() hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict11 = {'Alice': {'Grade': 4.0}} value_dict12 = {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.0}} value_dict21 = {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}, 'CS': {'Rank': 2, 'Grade': 3.9}}} value_dict22 = {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}, 'CS': {'Rank': 2, 'Grade': 3.8}}, 'Bob': {'Math': {'Rank': 2, 'Grade': 3.0}, 'CS': {'Rank': 1, 'Grade': 3.9}}} def key(v): return v['Grade'] value_lines11 = Hierarchy.flatten(hierarchy1, value_dict11) self.assertEqual(value_lines11, [{'Name': 'Alice', 'Grade': 4.0}]) value_lines12 = Hierarchy.flatten(hierarchy1, value_dict12) self.assertEqual(sorted(value_lines12, key=key), sorted([{'Name': 'Alice', 'Grade': 4.0}, {'Name': 'Bob', 'Grade': 3.0}], key=key)) value_lines21 = Hierarchy.flatten(hierarchy2, value_dict21) self.assertEqual(sorted(value_lines21, key=key), sorted([{'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0}, {'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.9}], key=key)) value_lines22 = Hierarchy.flatten(hierarchy2, value_dict22) self.assertEqual(sorted(value_lines22, key=key), sorted([{'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0}, {'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.8}, {'Name': 'Bob', 'Subject': 'Math', 'Rank': 2, 'Grade': 3.0}, {'Name': 'Bob', 'Subject': 'CS', 'Rank': 1, 'Grade': 3.9}], key=key))
def test_traverse_lines(self): name = self.name subject = self.subject grade = self.grade rank = self.rank hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict11 = {'Alice': {'Grade': 4.0}} value_dict12 = {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.0}} value_dict21 = { 'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 }, 'CS': { 'Rank': 2, 'Grade': 3.9 } } } value_dict22 = { 'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 }, 'CS': { 'Rank': 2, 'Grade': 3.8 } }, 'Bob': { 'Math': { 'Rank': 2, 'Grade': 3.0 }, 'CS': { 'Rank': 1, 'Grade': 3.9 } } } value_lines11 = [{'Name': 'Alice', 'Grade': 4.0}] value_lines12 = [{ 'Name': 'Alice', 'Grade': 4.0 }, { 'Name': 'Bob', 'Grade': 3.0 }] value_lines21 = [{ 'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0 }, { 'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.9 }] value_lines22 = [{ 'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0 }, { 'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.8 }, { 'Name': 'Bob', 'Subject': 'Math', 'Rank': 2, 'Grade': 3.0 }, { 'Name': 'Bob', 'Subject': 'CS', 'Rank': 1, 'Grade': 3.9 }] self.assertEqual(value_dict11, Hierarchy.traverse_lines(hierarchy1, value_lines11)) self.assertEqual(value_dict12, Hierarchy.traverse_lines(hierarchy1, value_lines12)) self.assertEqual(value_dict21, Hierarchy.traverse_lines(hierarchy2, value_lines21)) self.assertEqual(value_dict22, Hierarchy.traverse_lines(hierarchy2, value_lines22))
def test_flatten(self): name = self.name subject = self.subject grade = self.grade rank = self.rank.state_value() hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict11 = {'Alice': {'Grade': 4.0}} value_dict12 = {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.0}} value_dict21 = { 'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 }, 'CS': { 'Rank': 2, 'Grade': 3.9 } } } value_dict22 = { 'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 }, 'CS': { 'Rank': 2, 'Grade': 3.8 } }, 'Bob': { 'Math': { 'Rank': 2, 'Grade': 3.0 }, 'CS': { 'Rank': 1, 'Grade': 3.9 } } } def key(v): return v['Grade'] value_lines11 = Hierarchy.flatten(hierarchy1, value_dict11) self.assertEqual(value_lines11, [{'Name': 'Alice', 'Grade': 4.0}]) value_lines12 = Hierarchy.flatten(hierarchy1, value_dict12) self.assertEqual( sorted(value_lines12, key=key), sorted([{ 'Name': 'Alice', 'Grade': 4.0 }, { 'Name': 'Bob', 'Grade': 3.0 }], key=key)) value_lines21 = Hierarchy.flatten(hierarchy2, value_dict21) self.assertEqual( sorted(value_lines21, key=key), sorted([{ 'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0 }, { 'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.9 }], key=key)) value_lines22 = Hierarchy.flatten(hierarchy2, value_dict22) self.assertEqual( sorted(value_lines22, key=key), sorted([{ 'Name': 'Alice', 'Subject': 'Math', 'Rank': 1, 'Grade': 4.0 }, { 'Name': 'Alice', 'Subject': 'CS', 'Rank': 2, 'Grade': 3.8 }, { 'Name': 'Bob', 'Subject': 'Math', 'Rank': 2, 'Grade': 3.0 }, { 'Name': 'Bob', 'Subject': 'CS', 'Rank': 1, 'Grade': 3.9 }], key=key))
def test_traverse(self): name = self.name subject = self.subject grade = self.grade rank = self.rank.state_value() grade.map_f = lambda _, x: float(x) grade.reduce_f = max rank.map_f = lambda _, x: int(x) rank.reduce_f = min hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} line11 = {'Name': 'Alice', 'Subject': 'Math', 'Grade': '3.0'} line12 = {'Name': 'Alice', 'Subject': 'Math', 'Grade': '4.0'} line13 = {'Name': 'Alice', 'Subject': 'CS', 'Grade': '3.5'} line21 = {'Name': 'Bob', 'Subject': 'CS', 'Grade': '3.5'} line22 = {'Name': 'Bob', 'Subject': 'CS', 'Grade': '3.0'} line23 = {'Name': 'Bob', 'Subject': 'Math', 'Grade': '4.0'} value_dict1 = {} Hierarchy.traverse(hierarchy1, line11, {'Rank': '3'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 3.0}}) Hierarchy.traverse(hierarchy1, line12, {'Rank': '1'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 4.0}}) Hierarchy.traverse(hierarchy1, line13, {'Rank': '2'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 4.0}}) Hierarchy.traverse(hierarchy1, line21, {'Rank': '2'}, value_dict1) self.assertEqual(value_dict1, { 'Alice': { 'Grade': 4.0 }, 'Bob': { 'Grade': 3.5 } }) Hierarchy.traverse(hierarchy1, line22, {'Rank': '3'}, value_dict1) self.assertEqual(value_dict1, { 'Alice': { 'Grade': 4.0 }, 'Bob': { 'Grade': 3.5 } }) Hierarchy.traverse(hierarchy1, line23, {'Rank': '1'}, value_dict1) self.assertEqual(value_dict1, { 'Alice': { 'Grade': 4.0 }, 'Bob': { 'Grade': 4.0 } }) value_dict2 = {} Hierarchy.traverse(hierarchy2, line11, {'Rank': '3'}, value_dict2) self.assertEqual(value_dict2, {'Alice': { 'Math': { 'Grade': 3.0, 'Rank': 3 } }}) Hierarchy.traverse(hierarchy2, line12, {'Rank': '1'}, value_dict2) self.assertEqual(value_dict2, {'Alice': { 'Math': { 'Grade': 4.0, 'Rank': 1 } }}) Hierarchy.traverse(hierarchy2, line13, {'Rank': '2'}, value_dict2) self.assertEqual( value_dict2, { 'Alice': { 'Math': { 'Grade': 4.0, 'Rank': 1 }, 'CS': { 'Grade': 3.5, 'Rank': 2 } } }) Hierarchy.traverse(hierarchy2, line21, {'Rank': '2'}, value_dict2) self.assertEqual( value_dict2, { 'Alice': { 'Math': { 'Grade': 4.0, 'Rank': 1 }, 'CS': { 'Grade': 3.5, 'Rank': 2 } }, 'Bob': { 'CS': { 'Grade': 3.5, 'Rank': 2 } } }) Hierarchy.traverse(hierarchy2, line22, {'Rank': '3'}, value_dict2) self.assertEqual( value_dict2, { 'Alice': { 'Math': { 'Grade': 4.0, 'Rank': 1 }, 'CS': { 'Grade': 3.5, 'Rank': 2 } }, 'Bob': { 'CS': { 'Grade': 3.5, 'Rank': 2 } } }) Hierarchy.traverse(hierarchy2, line23, {'Rank': '1'}, value_dict2) self.assertEqual( value_dict2, { 'Alice': { 'Math': { 'Grade': 4.0, 'Rank': 1 }, 'CS': { 'Grade': 3.5, 'Rank': 2 } }, 'Bob': { 'CS': { 'Grade': 3.5, 'Rank': 2 }, 'Math': { 'Grade': 4.0, 'Rank': 1 } } })
def test_check(self): name = self.name subject = self.subject grade = self.grade rank = self.rank s_name = self.name.state_value() s_subject = self.subject.state_value() s_grade = self.grade.state_value() s_rank = self.rank.state_value() Hierarchy.check({name: [grade]}) Hierarchy.check({name: [grade, subject]}) Hierarchy.check({name: [grade, subject, rank]}) Hierarchy.check({name: {subject: [grade, rank]}}) Hierarchy.check({name: {subject: {grade: [rank]}}}) Hierarchy.check({s_name: [s_grade]}) Hierarchy.check({s_name: [s_grade, s_subject]}) Hierarchy.check({s_name: [s_grade, s_subject, s_rank]}) Hierarchy.check({s_name: {s_subject: [s_grade, s_rank]}}) Hierarchy.check({s_name: {s_subject: {s_grade: [s_rank]}}}) with self.assertRaises(Exception): Hierarchy.check(name) with self.assertRaises(Exception): Hierarchy.check({name: grade}) with self.assertRaises(Exception): Hierarchy.check({name: {subject: [grade], rank: [grade]}}) with self.assertRaises(Exception): Hierarchy.check([{name: grade}]) with self.assertRaises(Exception): Hierarchy.check(s_name) with self.assertRaises(Exception): Hierarchy.check({s_name: s_grade}) with self.assertRaises(Exception): Hierarchy.check( {s_name: { s_subject: [s_grade], s_rank: [s_grade] }}) with self.assertRaises(Exception): Hierarchy.check([{s_name: s_grade}])
def test_merge(self): name = self.name subject = self.subject grade = self.grade rank = self.rank.state_value() grade.reduce_f = max rank.reduce_f = min grade.post_map_f = lambda _, x: x - 1.0 rank.post_map_f = lambda _, x: x + 1 grade.post_reduce_f = min rank.post_reduce_f = max hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} value_dict11 = {'Alice': {'Grade': 4.0}} value_dict12 = {'Alice': {'Grade': 3.0}} value_dict13 = {'Bob': {'Grade': 3.5}} value_dict20 = {'Alice': {'Math': {'Rank': 2, 'Grade': 3.0}}} value_dict21 = {'Alice': {'Math': {'Rank': 1, 'Grade': 4.0}}} value_dict22 = {'Alice': {'CS': {'Rank': 2, 'Grade': 3.9}}} value_dict23 = {'Bob': {'Math': {'Rank': 2, 'Grade': 3.0}}} self.assertEqual( Hierarchy.merge(hierarchy1, value_dict11, value_dict12), {'Alice': { 'Grade': 4.0 }}) self.assertEqual( Hierarchy.merge(hierarchy1, value_dict11, value_dict12, True), {'Alice': { 'Grade': 2.0 }}) self.assertEqual( Hierarchy.merge(hierarchy1, value_dict11, value_dict13), { 'Alice': { 'Grade': 4.0 }, 'Bob': { 'Grade': 3.5 } }) self.assertEqual( Hierarchy.merge(hierarchy1, value_dict11, value_dict13, True), { 'Alice': { 'Grade': 3.0 }, 'Bob': { 'Grade': 2.5 } }) self.assertEqual( Hierarchy.merge(hierarchy2, value_dict20, value_dict21), {'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 } }}) self.assertEqual( Hierarchy.merge(hierarchy2, value_dict20, value_dict21, True), {'Alice': { 'Math': { 'Rank': 3, 'Grade': 2.0 } }}) self.assertEqual( Hierarchy.merge(hierarchy2, value_dict21, value_dict22), { 'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 }, 'CS': { 'Rank': 2, 'Grade': 3.9 } } }) self.assertEqual( Hierarchy.merge(hierarchy2, value_dict21, value_dict22, True), { 'Alice': { 'Math': { 'Rank': 2, 'Grade': 3.0 }, 'CS': { 'Rank': 3, 'Grade': 2.9 } } }) self.assertEqual( Hierarchy.merge(hierarchy2, value_dict21, value_dict23), { 'Alice': { 'Math': { 'Rank': 1, 'Grade': 4.0 } }, 'Bob': { 'Math': { 'Rank': 2, 'Grade': 3.0 } } }) self.assertEqual( Hierarchy.merge(hierarchy2, value_dict21, value_dict23, True), { 'Alice': { 'Math': { 'Rank': 2, 'Grade': 3.0 } }, 'Bob': { 'Math': { 'Rank': 3, 'Grade': 2.0 } } })
def read(self, data_file, mode='r', apply_post_map=False, carry_state=False): """Read a file to store the data with respect to the hierarchy specification of values. :param data_file (DataFile): the file to read. :param mode (str): reading mode ('r', 'r+', ...). :param apply_post_map (bool): whether apply post_map for each value or not. :param carry_state (bool): whether keep the mutated state or not. :return (dict, State): the result dictionary and the final state. """ if not isinstance(data_file, DataFile): raise ValueError("Data file is not a DataFile object.") lineno = 0 value_hierarchy = {} # if not carry state, copy the state object such that the input state is not mutated. if not carry_state: current_state = deepcopy(self.state) else: current_state = self.state filter_f = self.filter_f hierarchy_spec = self.hierarchy_spec file_name = data_file.file_name line = data_file.line header_lineno = data_file.header_lineno store_line = line.store set_line_header = line.set_header release = current_state.release update = current_state.update lock = current_state.lock traverse = Hierarchy.traverse def update_state(line): release() update(line) lock() with open(file_name, mode) as file: for data_line in file: try: # read a line store_line(data_line[:-1]) # set header if header line number matches if header_lineno == lineno: set_line_header() lineno += 1 continue # update state # current_state.release() # current_state.update(line) # current_state.lock() update_state(line) # filter out a line if predicate returns false if not filter_f(current_state, line): lineno += 1 continue # traverse a line with respect to hierarchy traverse(hierarchy_spec, line, current_state, value_hierarchy) except (KeyError, ValueError): print("Error occurred when reading line %s of %s" % (str(lineno+1), file_name)) raise lineno += 1 # apply post_map_f in each value if apply_post_map is true if apply_post_map: Hierarchy.apply_post_map(hierarchy_spec, value_hierarchy, current_state) return value_hierarchy, current_state
def read(self, data_file, mode='r', apply_post_map=False, carry_state=False): """Read a file to store the data with respect to the hierarchy specification of values. :param data_file (DataFile): the file to read. :param mode (str): reading mode ('r', 'r+', ...). :param apply_post_map (bool): whether apply post_map for each value or not. :param carry_state (bool): whether keep the mutated state or not. :return (dict, State): the result dictionary and the final state. """ if not isinstance(data_file, DataFile): raise ValueError("Data file is not a DataFile object.") lineno = 0 value_hierarchy = {} # if not carry state, copy the state object such that the input state is not mutated. if not carry_state: current_state = deepcopy(self.state) else: current_state = self.state filter_f = self.filter_f hierarchy_spec = self.hierarchy_spec file_name = data_file.file_name line = data_file.line header_lineno = data_file.header_lineno store_line = line.store set_line_header = line.set_header release = current_state.release update = current_state.update lock = current_state.lock traverse = Hierarchy.traverse def update_state(line): release() update(line) lock() with open(file_name, mode) as file: for data_line in file: try: # read a line store_line(data_line[:-1]) # set header if header line number matches if header_lineno == lineno: set_line_header() lineno += 1 continue # update state # current_state.release() # current_state.update(line) # current_state.lock() update_state(line) # filter out a line if predicate returns false if not filter_f(current_state, line): lineno += 1 continue # traverse a line with respect to hierarchy traverse(hierarchy_spec, line, current_state, value_hierarchy) except (KeyError, ValueError): print("Error occurred when reading line %s of %s" % (str(lineno + 1), file_name)) raise lineno += 1 # apply post_map_f in each value if apply_post_map is true if apply_post_map: Hierarchy.apply_post_map(hierarchy_spec, value_hierarchy, current_state) return value_hierarchy, current_state
def test_traverse(self): name = self.name subject = self.subject grade = self.grade rank = self.rank.state_value() grade.map_f = lambda _, x: float(x) grade.reduce_f = max rank.map_f = lambda _, x: int(x) rank.reduce_f = min hierarchy1 = {name: [grade]} hierarchy2 = {name: {subject: [rank, grade]}} line11 = {'Name': 'Alice', 'Subject': 'Math', 'Grade': '3.0'} line12 = {'Name': 'Alice', 'Subject': 'Math', 'Grade': '4.0'} line13 = {'Name': 'Alice', 'Subject': 'CS', 'Grade': '3.5'} line21 = {'Name': 'Bob', 'Subject': 'CS', 'Grade': '3.5'} line22 = {'Name': 'Bob', 'Subject': 'CS', 'Grade': '3.0'} line23 = {'Name': 'Bob', 'Subject': 'Math', 'Grade': '4.0'} value_dict1 = {} Hierarchy.traverse(hierarchy1, line11, {'Rank': '3'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 3.0}}) Hierarchy.traverse(hierarchy1, line12, {'Rank': '1'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 4.0}}) Hierarchy.traverse(hierarchy1, line13, {'Rank': '2'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 4.0}}) Hierarchy.traverse(hierarchy1, line21, {'Rank': '2'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.5}}) Hierarchy.traverse(hierarchy1, line22, {'Rank': '3'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 3.5}}) Hierarchy.traverse(hierarchy1, line23, {'Rank': '1'}, value_dict1) self.assertEqual(value_dict1, {'Alice': {'Grade': 4.0}, 'Bob': {'Grade': 4.0}}) value_dict2 = {} Hierarchy.traverse(hierarchy2, line11, {'Rank': '3'}, value_dict2) self.assertEqual(value_dict2, {'Alice': {'Math': {'Grade': 3.0, 'Rank': 3}}}) Hierarchy.traverse(hierarchy2, line12, {'Rank': '1'}, value_dict2) self.assertEqual(value_dict2, {'Alice': {'Math': {'Grade': 4.0, 'Rank': 1}}}) Hierarchy.traverse(hierarchy2, line13, {'Rank': '2'}, value_dict2) self.assertEqual(value_dict2, {'Alice': {'Math': {'Grade': 4.0, 'Rank': 1}, 'CS': {'Grade': 3.5, 'Rank': 2}}}) Hierarchy.traverse(hierarchy2, line21, {'Rank': '2'}, value_dict2) self.assertEqual(value_dict2, {'Alice': {'Math': {'Grade': 4.0, 'Rank': 1}, 'CS': {'Grade': 3.5, 'Rank': 2}}, 'Bob': {'CS': {'Grade': 3.5, 'Rank': 2}}}) Hierarchy.traverse(hierarchy2, line22, {'Rank': '3'}, value_dict2) self.assertEqual(value_dict2, {'Alice': {'Math': {'Grade': 4.0, 'Rank': 1}, 'CS': {'Grade': 3.5, 'Rank': 2}}, 'Bob': {'CS': {'Grade': 3.5, 'Rank': 2}}}) Hierarchy.traverse(hierarchy2, line23, {'Rank': '1'}, value_dict2) self.assertEqual(value_dict2, {'Alice': {'Math': {'Grade': 4.0, 'Rank': 1}, 'CS': {'Grade': 3.5, 'Rank': 2}}, 'Bob': {'CS': {'Grade': 3.5, 'Rank': 2}, 'Math': {'Grade': 4.0, 'Rank': 1}}})
def test_check(self): name = self.name subject = self.subject grade = self.grade rank = self.rank s_name = self.name.state_value() s_subject = self.subject.state_value() s_grade = self.grade.state_value() s_rank = self.rank.state_value() Hierarchy.check({name: [grade]}) Hierarchy.check({name: [grade, subject]}) Hierarchy.check({name: [grade, subject, rank]}) Hierarchy.check({name: {subject: [grade, rank]}}) Hierarchy.check({name: {subject: {grade: [rank]}}}) Hierarchy.check({s_name: [s_grade]}) Hierarchy.check({s_name: [s_grade, s_subject]}) Hierarchy.check({s_name: [s_grade, s_subject, s_rank]}) Hierarchy.check({s_name: {s_subject: [s_grade, s_rank]}}) Hierarchy.check({s_name: {s_subject: {s_grade: [s_rank]}}}) with self.assertRaises(Exception): Hierarchy.check(name) with self.assertRaises(Exception): Hierarchy.check({name: grade}) with self.assertRaises(Exception): Hierarchy.check({name: {subject: [grade], rank: [grade]}}) with self.assertRaises(Exception): Hierarchy.check([{name: grade}]) with self.assertRaises(Exception): Hierarchy.check(s_name) with self.assertRaises(Exception): Hierarchy.check({s_name: s_grade}) with self.assertRaises(Exception): Hierarchy.check({s_name: {s_subject: [s_grade], s_rank: [s_grade]}}) with self.assertRaises(Exception): Hierarchy.check([{s_name: s_grade}])