def test_regularfield_default_twoorders_02(self): "Add not natural ordering." sorter = QuerySorter() field_name1 = 'first_name' field_name2 = 'last_name' field_name3 = 'phone' build_cell = partial(EntityCellRegularField.build, model=FakeContact) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), build_cell(name=field_name3), ] key = cells[2].key sortinfo1 = sorter.get(model=FakeContact, cells=cells, cell_key=key) self.assertEqual( (field_name3, field_name2, field_name1, 'cremeentity_ptr_id'), sortinfo1.field_names) # DESC ------------------ sortinfo2 = sorter.get(model=FakeContact, cells=cells, cell_key=key, order=Order(False)) self.assertEqual(('-' + field_name3, field_name2, field_name1, '-cremeentity_ptr_id'), sortinfo2.field_names)
def test_regularfield_registry_argument(self): class MyFKRegistry(CellSorterRegistry): def get_field_name(this, cell): return cell.value + '_id' sorter = QuerySorter(MyFKRegistry()) field_name1 = 'title' field_name2 = 'linked_folder' self.assertEqual((field_name1, ), FakeDocument._meta.ordering) build_cell = partial(EntityCellRegularField.build, model=FakeDocument) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[1].key sortinfo = sorter.get(model=FakeDocument, cells=cells, cell_key=key) self.assertEqual( ( field_name2 + '_id', # not '__header_filter_search_field' field_name1, 'cremeentity_ptr_id', ), sortinfo.field_names) self.assertEqual(cells[1].key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_twoordersdesc(self): "meta.ordering: 2 fields (one is DESC)." sorter = QuerySorter() field_name1 = 'name' field_name2 = 'expiration_date' self.assertEqual((field_name1, '-' + field_name2), FakeInvoice._meta.ordering) build_cell = partial(EntityCellRegularField.build, model=FakeInvoice) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[0].key sortinfo1 = sorter.get(model=FakeInvoice, cells=cells, cell_key=key) self.assertEqual( (field_name1, '-' + field_name2, 'cremeentity_ptr_id'), sortinfo1.field_names) self.assertEqual(key, sortinfo1.main_cell_key) self.assertTrue(sortinfo1.main_order.asc) # DESC ----------------------------- sortinfo2 = sorter.get(model=FakeInvoice, cells=cells, cell_key=key, order=Order(False)) self.assertEqual( ('-' + field_name1, field_name2, '-cremeentity_ptr_id'), sortinfo2.field_names) self.assertEqual(key, sortinfo2.main_cell_key) self.assertTrue(sortinfo2.main_order.desc)
def test_regularfield_register_fieldtype(self): "Register model field type." sorter = QuerySorter() fields_registry = sorter.registry[EntityCellRegularField.type_id] self.assertIsInstance( fields_registry.sorter_4_model_field_type(IntegerField), RegularFieldSorter) fields_registry.register_model_field_type(type=IntegerField, sorter_cls=VoidSorter) self.assertIsInstance( fields_registry.sorter_4_model_field_type(IntegerField), VoidSorter) self.assertIsInstance( fields_registry.sorter_4_model_field_type(CharField), RegularFieldSorter) field_name1 = 'name' field_name2 = 'capital' build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] sortinfo = sorter.get(model=FakeOrganisation, cells=cells, cell_key=cells[1].key) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo.field_names)
def test_regularfield_register_field(self): "Register model field." sorter = QuerySorter() fields_registry = sorter.registry[EntityCellRegularField.type_id] self.assertIsNone( fields_registry.sorter_4_model_field( model=FakeInvoice, field_name='issuing_date', )) fields_registry.register_model_field( model=FakeInvoice, field_name='issuing_date', sorter_cls=VoidSorter, ) self.assertIsInstance( fields_registry.sorter_4_model_field( model=FakeInvoice, field_name='issuing_date', ), VoidSorter) field_name1 = 'issuing_date' field_name2 = 'expiration_date' build_cell = partial(EntityCellRegularField.build, model=FakeInvoice) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] sortinfo = sorter.get(model=FakeInvoice, cells=cells, cell_key=cells[0].key) self.assertEqual(('-expiration_date', '-cremeentity_ptr_id'), sortinfo.field_names)
def test_functionfield03(self): "<sorter_class> attribute." class PhoneSorter(AbstractCellSorter): def get_field_name(this, cell): return 'modified' # NB: it has no sense, it's just for testing purposes... class PhoneFunctionField(FunctionField): name = 'phone_or_mobile' verbose_name = 'Phone or mobile' sorter_class = PhoneSorter # def __call__(self, entity, user): # return self.result_type(entity.phone or entity.mobile) function_field = PhoneFunctionField() sorter = QuerySorter() cells = [ EntityCellRegularField.build(model=FakeOrganisation, name='name'), EntityCellFunctionField(model=FakeOrganisation, func_field=function_field), ] key = cells[1].key sortinfo = sorter.get(model=FakeOrganisation, cells=cells, cell_key=key) self.assertEqual(('modified', 'name', 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_oneorder_08(self): "Natural ordering field not in cells." sorter = QuerySorter() build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) cells = [ build_cell(name='phone'), build_cell(name='email'), ] key = cells[0].key sortinfo1 = sorter.get(model=FakeOrganisation, cells=cells, cell_key=key) self.assertEqual(('phone', 'cremeentity_ptr_id'), sortinfo1.field_names) self.assertEqual(key, sortinfo1.main_cell_key) self.assertTrue(sortinfo1.main_order.asc) # Initial sortinfo2 = sorter.get(model=FakeOrganisation, cells=cells, cell_key=None) self.assertEqual(('cremeentity_ptr_id', ), sortinfo2.field_names)
def test_regularfield_default_descorder_01(self): "Natural ordering is DESC." sorter = QuerySorter() field_name1 = 'start' field_name2 = 'title' self.assertEqual(('-' + field_name1, ), FakeActivity._meta.ordering) build_cell = partial(EntityCellRegularField.build, model=FakeActivity) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[0].key sortinfo1 = sorter.get(model=FakeActivity, cells=cells, cell_key=key) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo1.field_names) self.assertEqual(key, sortinfo1.main_cell_key) self.assertEqual('ASC', str(sortinfo1.main_order)) # DESC ------------ sortinfo2 = sorter.get(model=FakeActivity, cells=cells, cell_key=key, order=Order(False)) self.assertEqual(('-' + field_name1, '-cremeentity_ptr_id'), sortinfo2.field_names) self.assertEqual(key, sortinfo2.main_cell_key) self.assertEqual('DESC', str(sortinfo2.main_order))
def test_regularfield_default_oneorder_01(self): "Ordering: natural ordering key." sorter = QuerySorter(CellSorterRegistry()) field_name1 = 'name' field_name2 = 'email' self.assertEqual((field_name1, ), FakeOrganisation._meta.ordering) build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) cells = [ build_cell(name=field_name2), build_cell(name=field_name1), # meta._meta.ordering[0] ] key = cells[1].key sortinfo1 = sorter.get(model=FakeOrganisation, cells=cells, cell_key=key, order=Order()) self.assertIsInstance(sortinfo1, QuerySortInfo) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo1.field_names) self.assertEqual(key, sortinfo1.main_cell_key) self.assertEqual('ASC', str(sortinfo1.main_order)) # Fast mode ------------------- sortinfo2 = sorter.get( model=FakeOrganisation, cells=cells, cell_key=key, # order='ASC', order=Order(), fast_mode=True, ) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo2.field_names) # DESC ------------------- sortinfo3 = sorter.get( model=FakeOrganisation, cells=cells, cell_key=key, order=Order(False), ) self.assertEqual(('-' + field_name1, '-cremeentity_ptr_id'), sortinfo3.field_names) self.assertEqual(key, sortinfo3.main_cell_key) self.assertTrue(sortinfo3.main_order.desc)
def test_functionfield02(self): "Register a function field." class PhoneFunctionField(FunctionField): name = 'phone_or_mobile' verbose_name = 'Phone or mobile' # def __call__(self, entity, user): # return self.result_type(entity.phone or entity.mobile) function_field1 = PropertiesField() function_field2 = PhoneFunctionField() class PropertySorter(AbstractCellSorter): def get_field_name(this, cell): return 'created' # NB: it has no sense, it's just for testing purposes... sorter = QuerySorter() ffield_registry = sorter.registry[EntityCellFunctionField.type_id] self.assertIsNone(ffield_registry.sorter(function_field1)) ffield_registry.register( ffield=function_field1, sorter_cls=PropertySorter, ) self.assertIsInstance(ffield_registry.sorter(function_field1), PropertySorter) cells = [ EntityCellRegularField.build(model=FakeOrganisation, name='name'), EntityCellFunctionField(model=FakeOrganisation, func_field=function_field1), EntityCellFunctionField(model=FakeOrganisation, func_field=function_field2), ] prop_key = cells[1].key sortinfo1 = sorter.get(model=FakeOrganisation, cells=cells, cell_key=prop_key) self.assertEqual(('created', 'name', 'cremeentity_ptr_id'), sortinfo1.field_names) self.assertEqual(prop_key, sortinfo1.main_cell_key) self.assertTrue(sortinfo1.main_order.asc) # --- sortinfo2 = sorter.get(model=FakeOrganisation, cells=cells, cell_key=cells[2].key) self.assertEqual(('name', 'cremeentity_ptr_id'), sortinfo2.field_names)
def test_regularfield_default_twoorders_04(self): sorter = QuerySorter() build_cell = partial(EntityCellRegularField.build, model=FakeContact) cells = [ build_cell(name='phone'), build_cell(name='email'), ] sortinfo = sorter.get(model=FakeContact, cells=cells, cell_key=None) self.assertEqual(('cremeentity_ptr_id', ), sortinfo.field_names) self.assertIsNone(sortinfo.main_cell_key ) # Fallback to (first) natural ordering field self.assertTrue(sortinfo.main_order.asc)
def test_not_entity(self): sorter = QuerySorter(CellSorterRegistry()) model = FakeCivility field_name1 = 'title' field_name2 = 'shortcut' self.assertEqual(('title', ), model._meta.ordering) build_cell = partial(EntityCellRegularField.build, model=FakeCivility) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[0].key get_sortinfo = partial(sorter.get, model=model, cells=cells, cell_key=key) sortinfo1 = get_sortinfo(order=Order()) self.assertIsInstance(sortinfo1, QuerySortInfo) self.assertEqual((field_name1, 'id'), sortinfo1.field_names) self.assertEqual(key, sortinfo1.main_cell_key) self.assertEqual('ASC', str(sortinfo1.main_order)) # DESC --- sortinfo2 = get_sortinfo(order=Order(False)) self.assertEqual(('-' + field_name1, '-id'), sortinfo2.field_names) self.assertEqual(key, sortinfo2.main_cell_key) self.assertTrue(sortinfo2.main_order.desc)
def test_regularfield_default_twoorders_06(self): "One natural ordering field not in cells, but an smart index exists." sorter = QuerySorter() field_name1 = 'last_name' build_cell = partial(EntityCellRegularField.build, model=FakeContact) cells = [ build_cell(name='email'), build_cell(name=field_name1), ] sortinfo = sorter.get(model=FakeContact, cells=cells, cell_key=None) self.assertEqual(cells[1].key, sortinfo.main_cell_key) # First natural order self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_oneorder_03(self): "Empty cell key => fallback on natural model ordering." sorter = QuerySorter(cell_sorter_registry=CellSorterRegistry()) field_name1 = 'name' build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) main_cell = build_cell(name=field_name1) cells = [build_cell(name='email'), main_cell] sortinfo = sorter.get(model=FakeOrganisation, cells=cells, cell_key=None, order=None) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(main_cell.key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_descorder_03(self): "Natural ordering is DESC + another field." sorter = QuerySorter() field_name1 = 'start' # field_name2 = 'title' field_name2 = 'place' # Not unique (see below) build_cell = partial(EntityCellRegularField.build, model=FakeActivity) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[1].key sortinfo1 = sorter.get(model=FakeActivity, cells=cells, cell_key=key, order=None) self.assertEqual( (field_name2, '-' + field_name1, 'cremeentity_ptr_id'), sortinfo1.field_names) self.assertEqual(key, sortinfo1.main_cell_key) self.assertTrue(sortinfo1.main_order.asc) # DESC ------------------------------ sortinfo2 = sorter.get(model=FakeActivity, cells=cells, cell_key=key, order=Order(False)) self.assertEqual(( '-' + field_name2, '-' + field_name1, '-cremeentity_ptr_id', ), sortinfo2.field_names) self.assertEqual(key, sortinfo2.main_cell_key) self.assertTrue(sortinfo2.main_order.desc) # FAST MODE sortinfo3 = sorter.get(model=FakeActivity, cells=cells, cell_key=key, fast_mode=True) self.assertEqual((field_name2, 'cremeentity_ptr_id'), sortinfo3.field_names)
def test_regularfield_default_oneorder_04(self): "Invalid cell key => fallback on natural model ordering." sorter = QuerySorter() field_name1 = 'name' build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) cells = [ build_cell(name=field_name1), build_cell(name='email'), ] sortinfo = sorter.get(model=FakeOrganisation, cells=cells, cell_key='invalid') self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(cells[0].key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_not_sortable01(self): "DatePeriodField is not sortable." sorter = QuerySorter() field_name1 = 'name' field_name2 = 'periodicity' build_cell = partial(EntityCellRegularField.build, model=FakeInvoice) cells = [build_cell(name=field_name1), build_cell(name=field_name2)] sortinfo = sorter.get( model=FakeInvoice, cells=cells, cell_key=cells[1].key, order=Order(), ) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(cells[0].key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_twoorders_03(self): "Add invalid order." sorter = QuerySorter() field_name1 = 'first_name' field_name2 = 'last_name' build_cell = partial(EntityCellRegularField.build, model=FakeContact) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] sortinfo = sorter.get(model=FakeContact, cells=cells, cell_key='invalid') self.assertEqual((field_name2, field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(cells[1].key, sortinfo.main_cell_key ) # Fallback to (first) natural ordering field self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_oneorder_02(self): "Ordering: add a not natural ordering key." sorter = QuerySorter() field_name1 = 'name' field_name2 = 'email' build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) cells = [ build_cell(name=field_name2), build_cell(name=field_name1), ] key = cells[0].key sortinfo = sorter.get(model=FakeOrganisation, cells=cells, cell_key=key) self.assertEqual((field_name2, field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_descorder_02(self): "Natural ordering is DESC => Empty GET/POST => DESC." sorter = QuerySorter() field_name1 = 'start' field_name2 = 'title' build_cell = partial(EntityCellRegularField.build, model=FakeActivity) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[0].key sortinfo = sorter.get(model=FakeActivity, cells=cells, cell_key=None, order=None) self.assertEqual(('-' + field_name1, '-cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.desc)
def test_relation(self): "EntityCellRelation are not sortable." sorter = QuerySorter() field_name = 'name' cells = [ EntityCellRegularField.build(model=FakeOrganisation, name=field_name), EntityCellRelation.build(model=FakeOrganisation, rtype_id=REL_SUB_HAS), ] sortinfo = sorter.get( model=FakeInvoice, cells=cells, cell_key=cells[1].key, order=Order(), ) self.assertEqual((field_name, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(cells[0].key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_functionfield01(self): "Function field are not sortable by default." sorter = QuerySorter() field_name = 'name' cells = [ EntityCellRegularField.build(model=FakeOrganisation, name=field_name), EntityCellFunctionField.build( model=FakeContact, func_field_name='get_pretty_properties'), ] sortinfo = sorter.get( model=FakeInvoice, cells=cells, cell_key=cells[1].key, order=Order(), ) self.assertEqual((field_name, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(cells[0].key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_register_related_model(self): sorter = QuerySorter() fk_registry = sorter.registry[ EntityCellRegularField.type_id].sorter_4_model_field_type( ForeignKey) efk_registry = fk_registry.sorter(CremeEntity) self.assertIsInstance(efk_registry, EntityForeignKeySorter) class MyEntityForeignKeySorter(AbstractCellSorter): def get_field_name(self, cell): return cell.value + '__created' efk_registry = fk_registry.register( model=CremeEntity, sorter_cls=MyEntityForeignKeySorter, ) self.assertIsInstance(efk_registry.sorter(CremeEntity), MyEntityForeignKeySorter) self.assertIsNone(efk_registry.sorter(FakeSector)) field_name1 = 'title' field_name2 = 'linked_folder' build_cell = partial(EntityCellRegularField.build, model=FakeDocument) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] sortinfo = sorter.get(model=FakeDocument, cells=cells, cell_key=cells[1].key) self.assertEqual(( field_name2 + '__created', field_name1, 'cremeentity_ptr_id', ), sortinfo.field_names)
def test_regularfield_default_oneorder_05(self): "Cell is not displayed => fallback on basic ordering." sorter = QuerySorter() field_name1 = 'name' field_name2 = 'phone' build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) unused_cell = EntityCellRegularField.build(model=FakeOrganisation, name='email') main_cell = build_cell(name=field_name1) # NB: meta.ordering[0] cells1 = [build_cell(name=field_name2), main_cell] sortinfo1 = sorter.get(model=FakeOrganisation, cells=cells1, cell_key=unused_cell.key) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo1.field_names) self.assertEqual(main_cell.key, sortinfo1.main_cell_key) self.assertTrue(sortinfo1.main_order.asc) # Natural ordering not displayed --------------- cells2 = [ build_cell(name=field_name2), build_cell(name='sector'), ] sortinfo2 = sorter.get(model=FakeOrganisation, cells=cells2, cell_key=unused_cell.key) # TODO ? Use index # self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo2.field_names) self.assertEqual(('cremeentity_ptr_id', ), sortinfo2.field_names) self.assertIsNone( sortinfo2.main_cell_key) # TODO: Fallback on first column ? self.assertTrue(sortinfo2.main_order.asc)
def test_regularfield_default_oneorder_06(self): "Ordering: add a not natural ordering key (FK to CremeEntity)." sorter = QuerySorter() field_name1 = 'title' field_name2 = 'linked_folder' self.assertEqual((field_name1, ), FakeDocument._meta.ordering) build_cell = partial(EntityCellRegularField.build, model=FakeDocument) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[1].key sortinfo = sorter.get(model=FakeDocument, cells=cells, cell_key=key) self.assertEqual(( field_name2 + '__header_filter_search_field', field_name1, 'cremeentity_ptr_id', ), sortinfo.field_names) self.assertEqual(cells[1].key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_twoorders_05(self): "One natural ordering field not in cells." sorter = QuerySorter() self.assertEqual(('name', '-expiration_date'), FakeInvoice._meta.ordering) self.assertIsNone( get_indexed_ordering(FakeInvoice, ['name', '-expiration_date'])) field_name1 = 'name' build_cell = partial(EntityCellRegularField.build, model=FakeInvoice) cells = [ build_cell(name='number'), build_cell(name=field_name1), # Not expiration_date ] sortinfo = sorter.get(model=FakeInvoice, cells=cells, cell_key=None) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(cells[1].key, sortinfo.main_cell_key) # First natural order self.assertTrue(sortinfo.main_order.asc)
def test_regularfield_default_oneorder_07(self): "Ordering: add a not natural ordering key (FK to CremeModel)." self.assertEqual(('order', ), FakeSector._meta.ordering) sorter = QuerySorter() field_name1 = 'name' field_name2 = 'sector' build_cell = partial(EntityCellRegularField.build, model=FakeOrganisation) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[1].key sortinfo = sorter.get(model=FakeOrganisation, cells=cells, cell_key=key) self.assertEqual( (field_name2 + '__order', field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(key, sortinfo.main_cell_key) self.assertTrue(sortinfo.main_order.asc)
def test_key_already_unique(self): sorter = QuerySorter() model = FakeActivity field_name1 = 'start' field_name2 = 'title' self.assertTrue(model._meta.get_field(field_name2).unique) build_cell = partial(EntityCellRegularField.build, model=model) cells = [ build_cell(name=field_name1), build_cell(name=field_name2), ] key = cells[1].key get_sortinfo = partial(sorter.get, model=model, cells=cells, cell_key=key) sortinfo1 = get_sortinfo(order=None) self.assertEqual((field_name2, '-' + field_name1), sortinfo1.field_names) self.assertEqual(key, sortinfo1.main_cell_key) self.assertTrue(sortinfo1.main_order.asc) # DESC ------------------------------ sortinfo2 = get_sortinfo(order=Order(False)) self.assertEqual(('-' + field_name2, '-' + field_name1), sortinfo2.field_names) self.assertEqual(key, sortinfo2.main_cell_key) self.assertTrue(sortinfo2.main_order.desc) # FAST MODE ------------------------------ sortinfo3 = get_sortinfo(fast_mode=True) self.assertEqual((field_name2, ), sortinfo3.field_names) # FAST MODE + DESC ------------------------------ sortinfo3 = get_sortinfo(fast_mode=True, order=Order(False)) self.assertEqual(('-' + field_name2, ), sortinfo3.field_names)