def test_get_class_enumerations_config(self): from c2cgeoportal_geoportal.lib.dbreflection import get_class enumerations_config = { "child1_id": { "value": "id", "order_by": "name" } } self._create_table("table_d") cls = get_class("table_d", enumerations_config=enumerations_config) self.assertEqual(enumerations_config, cls.__enumerations_config__) association_proxy = getattr(cls, cls.child1_id.info["association_proxy"]) self.assertEqual("id", association_proxy.value_attr) self.assertEqual("name", association_proxy.order_by) # Without order_by. enumerations_config = {"child1_id": {"value": "id"}} cls = get_class("table_d", enumerations_config=enumerations_config) association_proxy = getattr(cls, cls.child1_id.info["association_proxy"]) self.assertEqual("id", association_proxy.value_attr) self.assertEqual("id", association_proxy.order_by)
def test_get_class_exclude_properties(self): import c2cgeoportal_geoportal.lib.dbreflection from c2cgeoportal_geoportal.lib.dbreflection import get_class self._create_table("table_d") get_class("table_d", exclude_properties=["foo", "bar"]) # the class should now be in the cache self.assertTrue( ("public", "table_d", ("foo", "bar"), None, (), ()) in c2cgeoportal_geoportal.lib.dbreflection._class_cache)
def get_layer_class(layer, with_last_update_columns=False): """ Get the SQLAlchemy class to edit a GeoMapFish layer :param layer: :param with_last_update_columns: False to just have a class to access to the table and be able to modify the last_update_columns, True to have a correct class to build the UI (without the hidden column). :return: SQLAlchemy class """ # Exclude the columns used to record the last features update exclude = [] if layer.exclude_properties is None else layer.exclude_properties.split( ",") if with_last_update_columns: last_update_date = Layers.get_metadata(layer, "lastUpdateDateColumn") if last_update_date is not None: exclude.append(last_update_date) last_update_user = Layers.get_metadata(layer, "lastUpdateUserColumn") if last_update_user is not None: exclude.append(last_update_user) else: exclude = [] m = Layers.get_metadata(layer, "editingAttributesOrder") attributes_order = m.split(",") if m else None m = Layers.get_metadata(layer, "readonlyAttributes") readonly_attributes = m.split(",") if m else None primary_key = Layers.get_metadata(layer, "geotablePrimaryKey") cls = get_class( str(layer.geo_table.format(os.environ)), exclude_properties=exclude, primary_key=primary_key, attributes_order=attributes_order, readonly_attributes=readonly_attributes, ) mapper = class_mapper(cls) column_properties = [ p.key for p in mapper.iterate_properties if isinstance(p, ColumnProperty) ] for attribute_name in attributes_order or []: if attribute_name not in column_properties: table = mapper.mapped_table LOG.warning( 'Attribute "%s" does not exists in table "%s.%s".\n' 'Please correct metadata "editingAttributesOrder" in layer "%s" (id=%s).\n' "Available attributes are: %s.", attribute_name, table.schema, table.name, layer.name, layer.id, ", ".join(column_properties), ) return cls
def test_get_class_attributes_order(self): from c2cgeoportal_geoportal.lib.dbreflection import get_class attributes_order = ["child1_id", "point", "child2_id"] self._create_table("table_d") cls = get_class("table_d", attributes_order=attributes_order) self.assertEqual(attributes_order, cls.__attributes_order__)
def get_layer_metadatas(layer): # exclude the columns used to record the last features update exclude = [] if layer.exclude_properties is None else layer.exclude_properties.split( ",") date_metadata = layer.get_metadatas("lastUpdateDateColumn") last_update_date = date_metadata[0] if len(date_metadata) == 1 else None if last_update_date is not None: exclude.append(last_update_date.value) user_metadata = layer.get_metadatas("lastUpdateUserColumn") last_update_user = user_metadata[0] if len(user_metadata) == 1 else None if last_update_user is not None: exclude.append(last_update_user.value) cls = get_class(layer.geo_table, exclude_properties=exclude) edit_columns = [] for column_property in class_mapper(cls).iterate_properties: if isinstance(column_property, ColumnProperty): if len(column_property.columns) != 1: raise NotImplementedError # pragma: no cover column = column_property.columns[0] # Exclude columns that are primary keys if not column.primary_key: properties = _convert_column_type(column.type) properties["name"] = column.key if column.nullable: properties["nillable"] = True edit_columns.append(properties) else: for k, p in cls.__dict__.items(): if not isinstance(p, _AssociationProxy): continue relationship_property = class_mapper(cls) \ .get_property(p.target) target_cls = relationship_property.argument query = models.DBSession.query( getattr(target_cls, p.value_attr)) properties = {} if column.nullable: properties["nillable"] = True properties["name"] = k properties["restriction"] = "enumeration" properties["type"] = "xsd:string" properties["enumeration"] = [] for value in query: properties["enumeration"].append(value[0]) edit_columns.append(properties) return edit_columns
def test_get_class_dotted_notation(self): from c2cgeoportal_geoportal.lib.dbreflection import get_class self._create_table("table_b") modelclass = get_class("public.table_b") assert modelclass.__name__.startswith("Table_b_") self.assertEqual(modelclass.__table__.name, "table_b") self.assertEqual(modelclass.__table__.schema, "public")
def test_get_class_readonly_attributes(self): from c2cgeoportal_geoportal.lib.dbreflection import get_class readonly_attributes = ["child1_id", "point"] self._create_table("table_d") cls = get_class("table_d", readonly_attributes=readonly_attributes) self.assertEqual(True, cls.child1_id.info.get("readonly")) self.assertEqual(True, cls.point.info.get("readonly"))
def test_get_class_attributes_order(self): import c2cgeoportal_geoportal.lib.dbreflection from c2cgeoportal_geoportal.lib.dbreflection import get_class attributes_order = ["child1_id", "point", "child2_id"] self._create_table("table_d") cls = get_class("table_d", attributes_order=attributes_order) self.assertEqual(attributes_order, cls.__attributes_order__) # the class should now be in the cache self.assertTrue( ("public", "table_d", (), None, ("child1_id", "point", "child2_id"), ()) in c2cgeoportal_geoportal.lib.dbreflection._class_cache)
def get_layer_class(layer): # exclude the columns used to record the last features update exclude = [] if layer.exclude_properties is None else layer.exclude_properties.split(",") last_update_date = Layers.get_metadata(layer, "lastUpdateDateColumn") if last_update_date is not None: exclude.append(last_update_date) last_update_user = Layers.get_metadata(layer, "lastUpdateUserColumn") if last_update_user is not None: exclude.append(last_update_user) primary_key = Layers.get_metadata(layer, "geotablePrimaryKey") return get_class( str(layer.geo_table), exclude_properties=exclude, primary_key=primary_key )
def test_get_class_readonly_attributes(self): import c2cgeoportal_geoportal.lib.dbreflection from c2cgeoportal_geoportal.lib.dbreflection import get_class readonly_attributes = ["child1_id", "point"] self._create_table("table_d") cls = get_class("table_d", readonly_attributes=readonly_attributes) self.assertEqual(True, cls.child1_id.info.get('readonly')) self.assertEqual(True, cls.point.info.get('readonly')) # the class should now be in the cache self.assertTrue(("public", "table_d", (), None, (), ( "child1_id", "point")) in c2cgeoportal_geoportal.lib.dbreflection._class_cache)
def _get_geom_col_info(layer): """ Return information about the layer's geometry column, namely a ``(name, srid)`` tuple, where ``name`` is the name of the geometry column, and ``srid`` its srid. This function assumes that the names of geometry attributes in the mapped class are the same as those of geometry columns. """ mapped_class = get_class(layer.geo_table) for p in class_mapper(mapped_class).iterate_properties: if not isinstance(p, ColumnProperty): continue # pragma: no cover col = p.columns[0] if isinstance(col.type, Geometry): return col.name, col.type.srid raise HTTPInternalServerError( 'Failed getting geometry column info for table "{0!s}".'.format( layer.geo_table)) # pragma: no cover
def metadata(self): set_common_headers(self.request, "layers", PRIVATE_CACHE) layer = self._get_layer_for_request() if not layer.public and self.request.user is None: raise HTTPForbidden() # exclude the columns used to record the last features update exclude = [] if layer.exclude_properties is None else layer.exclude_properties.split( ",") last_update_date = self._get_metadata(layer, "lastUpdateDateColumn") if last_update_date is not None: exclude.append(last_update_date) last_update_user = self._get_metadata(layer, "lastUpdateUserColumn") if last_update_user is not None: exclude.append(last_update_user) return get_class(layer.geo_table, exclude_properties=exclude)
def _import_layer_wms(self, layer, messages): server = layer.ogc_server url = server.url_wfs or server.url if url is None: return for wms_layer in layer.layer.split(","): self._import_layer_attributes(url, wms_layer, layer.item_type, layer.name, messages) if layer.geo_table is not None and layer.geo_table != "": exclude = [] if layer.exclude_properties is None else layer.exclude_properties.split( ",") last_update_date = layer.get_metadatas("lastUpdateDateColumn") if len(last_update_date) == 1: exclude.append(last_update_date[0].value) last_update_user = layer.get_metadatas("lastUpdateUserColumn") if len(last_update_user) == 1: exclude.append(last_update_user[0].value) try: cls = get_class(layer.geo_table, exclude_properties=exclude) for column_property in class_mapper(cls).iterate_properties: if isinstance(column_property, ColumnProperty) and len( column_property.columns) == 1: column = column_property.columns[0] if not column.primary_key and not isinstance( column.type, Geometry): if column.foreign_keys: name = "type_" if column.name == "type_id" else \ column.name[0:column.name.rindex("_id")] else: name = column_property.key messages.append( Message(None, name, None, [], "", "", (".".join([ "edit", layer.item_type, str(layer.id) ]), layer.name))) except NoSuchTableError: print( colorize( "ERROR! No such table '{}' for layer '{}'.".format( layer.geo_table, layer.name), RED)) print(colorize(traceback.format_exc(), RED)) if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE": raise
def test_mixing_get_class_and_queries(self): """ This test shows that we can mix the use of DBSession and the db reflection API. """ from c2cgeoportal_geoportal.lib.dbreflection import get_class from c2cgeoportal_commons.models import DBSession from sqlalchemy import text import transaction self._create_table("table_c") DBSession.execute(text("SELECT id FROM table_c")) modelclass = get_class("table_c") self.assertEqual(modelclass.__name__, "Table_c") # This commits the transaction created by DBSession.execute. This # is required here in the test because tearDown does table.drop, # which will block forever if the transaction is not committed. transaction.commit()
def _import_layer_wms(self, layer, messages): server = layer.ogc_server url = server.url_wfs or server.url if url is None: return for wms_layer in layer.layer.split(","): self._import_layer_attributes(url, wms_layer, layer.item_type, layer.name, messages) if layer.geo_table is not None and layer.geo_table != "": exclude = [] if layer.exclude_properties is None else layer.exclude_properties.split(",") last_update_date = layer.get_metadatas("lastUpdateDateColumn") if len(last_update_date) == 1: exclude.append(last_update_date[0].value) last_update_user = layer.get_metadatas("lastUpdateUserColumn") if len(last_update_user) == 1: exclude.append(last_update_user[0].value) try: cls = get_class(layer.geo_table, exclude_properties=exclude) for column_property in class_mapper(cls).iterate_properties: if isinstance(column_property, ColumnProperty) and len(column_property.columns) == 1: column = column_property.columns[0] if not column.primary_key and not isinstance(column.type, Geometry): if column.foreign_keys: name = "type_" if column.name == "type_id" else \ column.name[0:column.name.rindex("_id")] else: name = column_property.key messages.append(Message( None, name, None, [], "", "", (".".join(["edit", layer.item_type, str(layer.id)]), layer.name) )) except NoSuchTableError: print(colorize( "ERROR! No such table '{}' for layer '{}'.".format(layer.geo_table, layer.name), RED )) print(colorize(traceback.format_exc(), RED)) if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE": raise
def _get_protocol_for_layer(self, layer, **kwargs): """ Returns a papyrus ``Protocol`` for the ``Layer`` object. """ cls = get_class(layer.geo_table) geom_attr = self._get_geom_col_info(layer)[0] return Protocol(models.DBSession, cls, geom_attr, **kwargs)
def test_get_class(self): from geoalchemy2 import Geometry import c2cgeoportal_geoportal.lib.dbreflection from c2cgeoportal_geoportal.lib.dbreflection import get_class, _AssociationProxy self._create_table("table_a") modelclass = get_class("table_a") # test the class self.assertEqual(modelclass.__name__, "Table_a") self.assertEqual(modelclass.__table__.name, "table_a") self.assertEqual(modelclass.__table__.schema, "public") self.assertTrue(isinstance(modelclass.point.type, Geometry)) self.assertTrue(isinstance(modelclass.linestring.type, Geometry)) self.assertTrue(isinstance(modelclass.polygon.type, Geometry)) self.assertTrue(isinstance(modelclass.multipoint.type, Geometry)) self.assertTrue(isinstance(modelclass.multilinestring.type, Geometry)) self.assertTrue(isinstance(modelclass.multipolygon.type, Geometry)) self.assertTrue(isinstance(modelclass.child1, _AssociationProxy)) self.assertTrue(modelclass.child1.nullable) self.assertEqual(modelclass.child1_id.info.get('association_proxy'), 'child1') self.assertTrue(isinstance(modelclass.child2, _AssociationProxy)) self.assertFalse(modelclass.child2.nullable) self.assertEqual(modelclass.child2_id.info.get('association_proxy'), 'child2') # test the Table object table = modelclass.__table__ self.assertTrue("id" in table.c) self.assertTrue("child1_id" in table.c) self.assertTrue("child2_id" in table.c) self.assertTrue("point" in table.c) self.assertTrue("linestring" in table.c) self.assertTrue("polygon" in table.c) self.assertTrue("multipoint" in table.c) self.assertTrue("multilinestring" in table.c) self.assertTrue("multipolygon" in table.c) col_child1_id = table.c["child1_id"] self.assertEqual(col_child1_id.name, "child1_id") col_child2_id = table.c["child2_id"] self.assertEqual(col_child2_id.name, "child2_id") col_point = table.c["point"] self.assertEqual(col_point.name, "point") self.assertEqual(col_point.type.geometry_type, "POINT") col_linestring = table.c["linestring"] self.assertEqual(col_linestring.name, "linestring") self.assertEqual(col_linestring.type.geometry_type, "LINESTRING") col_polygon = table.c["polygon"] self.assertEqual(col_polygon.name, "polygon") self.assertEqual(col_polygon.type.geometry_type, "POLYGON") col_multipoint = table.c["multipoint"] self.assertEqual(col_multipoint.name, "multipoint") self.assertEqual(col_multipoint.type.geometry_type, "MULTIPOINT") col_multilinestring = table.c["multilinestring"] self.assertEqual(col_multilinestring.name, "multilinestring") self.assertEqual(col_multilinestring.type.geometry_type, "MULTILINESTRING") col_multipolygon = table.c["multipolygon"] self.assertEqual(col_multipolygon.name, "multipolygon") self.assertEqual(col_multipolygon.type.geometry_type, "MULTIPOLYGON") # the class should now be in the cache self.assertTrue( ("public", "table_a", (), None, (), ()) in c2cgeoportal_geoportal.lib.dbreflection._class_cache) _modelclass = get_class("table_a") self.assertTrue(_modelclass is modelclass)
def test_get_class_exclude_properties(self): from c2cgeoportal_geoportal.lib.dbreflection import get_class self._create_table("table_d") assert get_class("table_d", exclude_properties=["foo", "bar"]) is not None
def test_get_class(self): from geoalchemy2 import Geometry from c2cgeoportal_geoportal.lib.dbreflection import _AssociationProxy, get_class init_region({"backend": "dogpile.cache.memory"}, "std") init_region({"backend": "dogpile.cache.memory"}, "obj") self._create_table("table_a") modelclass = get_class("table_a") # test the class assert modelclass.__name__.startswith("Table_a_") self.assertEqual(modelclass.__table__.name, "table_a") self.assertEqual(modelclass.__table__.schema, "public") self.assertTrue(isinstance(modelclass.point.type, Geometry)) self.assertTrue(isinstance(modelclass.linestring.type, Geometry)) self.assertTrue(isinstance(modelclass.polygon.type, Geometry)) self.assertTrue(isinstance(modelclass.multipoint.type, Geometry)) self.assertTrue(isinstance(modelclass.multilinestring.type, Geometry)) self.assertTrue(isinstance(modelclass.multipolygon.type, Geometry)) self.assertTrue(isinstance(modelclass.child1, _AssociationProxy)) self.assertTrue(modelclass.child1.nullable) self.assertEqual(modelclass.child1_id.info.get("association_proxy"), "child1") self.assertTrue(isinstance(modelclass.child2, _AssociationProxy)) self.assertFalse(modelclass.child2.nullable) self.assertEqual(modelclass.child2_id.info.get("association_proxy"), "child2") child1_asso_proxy = getattr(modelclass, modelclass.child1_id.info["association_proxy"]) self.assertEqual("name", child1_asso_proxy.value_attr) self.assertEqual("name", child1_asso_proxy.order_by) # test the Table object table = modelclass.__table__ self.assertTrue("id" in table.c) self.assertTrue("child1_id" in table.c) self.assertTrue("child2_id" in table.c) self.assertTrue("point" in table.c) self.assertTrue("linestring" in table.c) self.assertTrue("polygon" in table.c) self.assertTrue("multipoint" in table.c) self.assertTrue("multilinestring" in table.c) self.assertTrue("multipolygon" in table.c) col_child1_id = table.c["child1_id"] self.assertEqual(col_child1_id.name, "child1_id") col_child2_id = table.c["child2_id"] self.assertEqual(col_child2_id.name, "child2_id") col_point = table.c["point"] self.assertEqual(col_point.name, "point") self.assertEqual(col_point.type.geometry_type, "POINT") col_linestring = table.c["linestring"] self.assertEqual(col_linestring.name, "linestring") self.assertEqual(col_linestring.type.geometry_type, "LINESTRING") col_polygon = table.c["polygon"] self.assertEqual(col_polygon.name, "polygon") self.assertEqual(col_polygon.type.geometry_type, "POLYGON") col_multipoint = table.c["multipoint"] self.assertEqual(col_multipoint.name, "multipoint") self.assertEqual(col_multipoint.type.geometry_type, "MULTIPOINT") col_multilinestring = table.c["multilinestring"] self.assertEqual(col_multilinestring.name, "multilinestring") self.assertEqual(col_multilinestring.type.geometry_type, "MULTILINESTRING") col_multipolygon = table.c["multipolygon"] self.assertEqual(col_multipolygon.name, "multipolygon") self.assertEqual(col_multipolygon.type.geometry_type, "MULTIPOLYGON") assert get_class("table_a") is modelclass