def test_load_value_continuation_data(self): "a CIF parser should parse a multi-line document with value continuations" cifparser.parser.print_ast(io.StringIO(self.value_continuation_data)) values = cifparser.parser.parse_file(io.StringIO(self.value_continuation_data)) self.assertEquals(values.get_field(make_path('toplevel'), 'field1'), ' first line\n second line\n third line') self.assertEquals(values.get_field(make_path('toplevel'), 'field2'), ' value2') self.assertEquals(values.get_field(ROOT_PATH, 'field3'), ' value3')
def test_load_field_keys_with_spaces(self): "a CIF parser should parse a multi-line document with keys that have embedded space" cifparser.parser.print_ast(io.StringIO(self.field_key_with_spaces_data)) values = cifparser.parser.parse_file(io.StringIO(self.field_key_with_spaces_data)) self.assertEquals(values.get_field(make_path('toplevel'), 'nospaces'), ' foo') self.assertEquals(values.get_field(make_path('toplevel'), 'with single spaces'), ' bar') self.assertEquals(values.get_field(make_path('toplevel'), 'with extra space'), ' baz')
def test_load_deep_path(self): "a CIF parser should parse a multi-line document with deep paths" cifparser.parser.print_ast(io.StringIO(self.deep_path_data)) values = cifparser.parser.parse_file(io.StringIO(self.deep_path_data)) self.assertEquals(values.get_field(make_path('toplevel.this.is.deep'), 'field1'), ' value1') self.assertEquals(values.get_field(make_path('toplevel.shallow'), 'field2'), ' value2') self.assertEquals(values.get_field(ROOT_PATH, 'field3'), ' value3')
def test_load_list_continuation_data(self): "a CIF parser should parse a multi-line document with list continuations" cifparser.parser.print_ast(io.StringIO(self.list_continuation_data)) values = cifparser.parser.parse_file(io.StringIO(self.list_continuation_data)) self.assertListEqual(values.get_field_list(make_path('toplevel'), 'field1'), [' list item 1', ' list item 2', ' list item 3']) self.assertEquals(values.get_field(make_path('toplevel'), 'field2'), ' value2') self.assertEquals(values.get_field(ROOT_PATH, 'field3'), ' value3')
def test_load_value_continuation_data(self): "a CIF parser should parse a multi-line document with value continuations" cifparser.parser.print_ast(io.StringIO(self.value_continuation_data)) values = cifparser.parser.parse_file( io.StringIO(self.value_continuation_data)) self.assertEquals(values.get_field(make_path('toplevel'), 'field1'), ' first line\n second line\n third line') self.assertEquals(values.get_field(make_path('toplevel'), 'field2'), ' value2') self.assertEquals(values.get_field(ROOT_PATH, 'field3'), ' value3')
def test_load_list_continuation_data(self): "a CIF parser should parse a multi-line document with list continuations" cifparser.parser.print_ast(io.StringIO(self.list_continuation_data)) values = cifparser.parser.parse_file( io.StringIO(self.list_continuation_data)) self.assertListEqual( values.get_field_list(make_path('toplevel'), 'field1'), [' list item 1', ' list item 2', ' list item 3']) self.assertEquals(values.get_field(make_path('toplevel'), 'field2'), ' value2') self.assertEquals(values.get_field(ROOT_PATH, 'field3'), ' value3')
def test_load_deep_path(self): "a CIF parser should parse a multi-line document with deep paths" cifparser.parser.print_ast(io.StringIO(self.deep_path_data)) values = cifparser.parser.parse_file(io.StringIO(self.deep_path_data)) self.assertEquals( values.get_field(make_path('toplevel.this.is.deep'), 'field1'), ' value1') self.assertEquals( values.get_field(make_path('toplevel.shallow'), 'field2'), ' value2') self.assertEquals(values.get_field(ROOT_PATH, 'field3'), ' value3')
def test_load_field_keys_with_spaces(self): "a CIF parser should parse a multi-line document with keys that have embedded space" cifparser.parser.print_ast(io.StringIO( self.field_key_with_spaces_data)) values = cifparser.parser.parse_file( io.StringIO(self.field_key_with_spaces_data)) self.assertEquals(values.get_field(make_path('toplevel'), 'nospaces'), ' foo') self.assertEquals( values.get_field(make_path('toplevel'), 'with single spaces'), ' bar') self.assertEquals( values.get_field(make_path('toplevel'), 'with extra space'), ' baz')
def test_parse_objectdef_line(self): "a CIF lexer should tokenise <PathSegment> + ':' as a simple object definition" indent,result = cifparser.grammar.parse_line("object:") self.assertIsInstance(result, cifparser.grammar.ObjectDef) result_fields = vars(result) other_fields = vars(cifparser.grammar.ObjectDef(make_path('object'))) self.assertDictEqual(result_fields, other_fields)
def test_parse_deep_listitemdef_line(self): "a CIF lexer should tokenise '-' + *(<PathSegment> + '.') + <PathSegment> + ':' as a deep list item definition" indent,result = cifparser.grammar.parse_line("- deep.nested.object:") self.assertIsInstance(result, cifparser.grammar.ListItemDef) result_fields = vars(result) other_fields = vars(cifparser.grammar.ListItemDef(make_path('deep','nested','object'))) self.assertDictEqual(result_fields, other_fields)
def test_dump_valuetree_to_dict(self): "A ValueTree should dump to a dict" values = ValueTree() values.put_field(ROOT_PATH, 'field1', 'value1') values.put_field_list(ROOT_PATH, 'field2', ['item1', 'item2', 'item3']) values.put_container(make_path('object1')) values.put_field(make_path('object1'), 'field3', 'value3') values.put_field_list(make_path('object1'), 'field4', ['item4', 'item5']) obj = dump(values) self.assertDictEqual(obj, { 'field1': 'value1', 'field2': ['item1', 'item2', 'item3'], 'object1': { 'field3': 'value3', 'field4': ['item4', 'item5'], }, })
def test_load_valuetree_from_dict(self): "A ValueTree should load from a dict" obj = { 'field1': 'value1', 'field2': ['item1', 'item2', 'item3'], 'object1': { 'field3': 'value3', 'field4': ['item4', 'item5'], }, } values = load(obj) self.assertEqual(values.get_field(ROOT_PATH, 'field1'), 'value1') self.assertListEqual(values.get_field_list(ROOT_PATH, 'field2'), ['item1', 'item2', 'item3']) self.assertTrue(values.contains_container(make_path('object1'))) self.assertEqual(values.get_field(make_path('object1'), 'field3'), 'value3') self.assertListEqual(values.get_field_list(make_path('object1'), 'field4'), ['item4', 'item5'])
def test_dump_valuetree_to_dict(self): "A ValueTree should dump to a dict" values = ValueTree() values.put_field(ROOT_PATH, 'field1', 'value1') values.put_field_list(ROOT_PATH, 'field2', ['item1', 'item2', 'item3']) values.put_container(make_path('object1')) values.put_field(make_path('object1'), 'field3', 'value3') values.put_field_list(make_path('object1'), 'field4', ['item4', 'item5']) obj = dump(values) self.assertDictEqual( obj, { 'field1': 'value1', 'field2': ['item1', 'item2', 'item3'], 'object1': { 'field3': 'value3', 'field4': ['item4', 'item5'], }, })
def test_load_valuetree_from_dict(self): "A ValueTree should load from a dict" obj = { 'field1': 'value1', 'field2': ['item1', 'item2', 'item3'], 'object1': { 'field3': 'value3', 'field4': ['item4', 'item5'], }, } values = load(obj) self.assertEqual(values.get_field(ROOT_PATH, 'field1'), 'value1') self.assertListEqual(values.get_field_list(ROOT_PATH, 'field2'), ['item1', 'item2', 'item3']) self.assertTrue(values.contains_container(make_path('object1'))) self.assertEqual(values.get_field(make_path('object1'), 'field3'), 'value3') self.assertListEqual( values.get_field_list(make_path('object1'), 'field4'), ['item4', 'item5'])
def _load(_obj, container): for name,value in _obj.items(): if isinstance(value, dict): path = make_path(name) container.put_container(path) _load(value, container.get_container(path)) elif isinstance(value, list): for item in value: container.append_field(ROOT_PATH, name, item) elif isinstance(value, str): container.put_field(ROOT_PATH, name, value) else: raise ValueError()
def remove_field(self, path, name): """ :param path: str or Path instance :param name: :type name: str """ path = make_path(path) container = self.get_container(path) try: value = container._values[name] if isinstance(value, ValueTree): raise TypeError() del container._values[name] except KeyError: pass
def contains_container(self, path): """ Returns True if a container exists at the specified path, otherwise False. :param path: str or Path instance :return: :rtype: bool :raises ValueError: A component of path is a field name. """ path = make_path(path) try: self.get_container(path) return True except KeyError: return False
def put_field_list(self, path, name, values): """ :param path: str or Path instance :param name: :type name: str :param values: :type values: list[str] """ if not isinstance(values, list): raise ValueError() path = make_path(path) container = self.get_container(path) current = self._values.get(name) if current is not None and isinstance(current, ValueTree): raise TypeError() container._values[name] = values
def test_load_multi_line(self): "a CIF parser should parse a multi-line document" cifparser.parser.print_ast(io.StringIO(self.multi_line_data)) values = cifparser.parser.parse_file(io.StringIO(self.multi_line_data)) self.assertEquals(values.get_field(ROOT_PATH, 'field1'), ' value1') self.assertEquals(values.get_field(ROOT_PATH, 'field2'), ' value2') self.assertEquals(values.get_field(make_path('object1'), 'field3'), ' value3') self.assertEquals(values.get_field(make_path('object1'), 'field6'), ' value6') self.assertEquals(values.get_field(make_path('object1.object2'), 'field4'), ' value4') self.assertEquals(values.get_field(make_path('object1.object2.object3'), 'field5'), ' value5') self.assertEquals(values.get_field(make_path('object1.object4'), 'field7'), ' value7') self.assertEquals(values.get_field(ROOT_PATH, 'field8'), ' value8') self.assertEquals(values.get_field(make_path('object5'), 'field9'), ' value9')
def put_field(self, path, name, value): """ Creates a field with the specified name an value at path. If the field already exists, it will be overwritten with the new value. :param path: str or Path instance :param name: :type name: str :param value: :type value: str """ if not isinstance(value, str): raise ValueError() path = make_path(path) container = self.get_container(path) current = self._values.get(name) if current is not None and isinstance(current, ValueTree): raise TypeError() container._values[name] = value
def put_container(self, path): """ Creates a container at the specified path, creating any necessary intermediate containers. :param path: str or Path instance :raises ValueError: A component of path is a field name. """ path = make_path(path) container = self for segment in path: try: container = container._values[segment] if not isinstance(container, ValueTree): raise ValueError() except KeyError: valuetree = ValueTree() container._values[segment] = valuetree container = valuetree
def remove_container(self, path): """ Removes the container at the specified path. :param path: str or Path instance :raises ValueError: A component of path is a field name. :raises KeyError: A component of path doesn't exist. """ path = make_path(path) container = self parent = None for segment in path: parent = container try: container = container._values[segment] if not isinstance(container, ValueTree): raise ValueError() except KeyError: raise KeyError() del parent._values[path.segments[-1]]
def get_container(self, path): """ Retrieves the container at the specified path. :param path: str or Path instance :return: :rtype: ValueTree :raises ValueError: A component of path is a field name. :raises KeyError: A component of path doesn't exist. """ path = make_path(path) container = self for segment in path: try: container = container._values[segment] if not isinstance(container, ValueTree): raise ValueError() except KeyError: raise KeyError() return container
def append_field(self, path, name, value): """ Appends the field to the container at the specified path. :param path: str or Path instance :param name: :type name: str :param value: :type value: str """ path = make_path(path) container = self.get_container(path) current = container._values.get(name, None) if current is None: container._values[name] = value elif isinstance(current, ValueTree): raise TypeError() elif isinstance(current, list): container._values[name] = current + [value] else: container._values[name] = [current, value]
def test_load_multi_line(self): "a CIF parser should parse a multi-line document" cifparser.parser.print_ast(io.StringIO(self.multi_line_data)) values = cifparser.parser.parse_file(io.StringIO(self.multi_line_data)) self.assertEquals(values.get_field(ROOT_PATH, 'field1'), ' value1') self.assertEquals(values.get_field(ROOT_PATH, 'field2'), ' value2') self.assertEquals(values.get_field(make_path('object1'), 'field3'), ' value3') self.assertEquals(values.get_field(make_path('object1'), 'field6'), ' value6') self.assertEquals( values.get_field(make_path('object1.object2'), 'field4'), ' value4') self.assertEquals( values.get_field(make_path('object1.object2.object3'), 'field5'), ' value5') self.assertEquals( values.get_field(make_path('object1.object4'), 'field7'), ' value7') self.assertEquals(values.get_field(ROOT_PATH, 'field8'), ' value8') self.assertEquals(values.get_field(make_path('object5'), 'field9'), ' value9')