def drop_tables_from_standard_configuration(configuration_yaml_path, section='pyramid_oereb'): """ Drops all schemas which are defined in the passed yaml file: <section>.<plrs>.[<plr>.<code>]. The code must be camel case. It will be transformed to snake case and used as schema name. Drops all tables inside the created schemas. Args: configuration_yaml_path (str): The absolute path to the yaml file which contains the plr definitions. section (str): The section in yaml file where the plrs are configured in. Default is 'pyramid_oereb'. """ if Config.get_config() is None: Config.init(configuration_yaml_path, section) main_schema_engine = create_engine( Config.get('app_schema').get('db_connection'), echo=True) main_schema_connection = main_schema_engine.connect() main_schema_connection.execute( 'DROP SCHEMA IF EXISTS {name} CASCADE;'.format( name=Config.get('app_schema').get('name'))) main_schema_connection.close() for schema in Config.get('plrs'): if schema.get('standard'): plr_schema_engine = create_engine( schema.get('source').get('params').get('db_connection'), echo=True) plr_schema_connection = plr_schema_engine.connect() plr_schema_connection.execute( 'DROP SCHEMA IF EXISTS {name} CASCADE;'.format( name=convert_camel_case_to_snake_case(schema.get('code')))) plr_schema_connection.close()
def test_parse_configuration(): Config._config = None Config.init('./tests/resources/test_config.yml', 'section2') assert Config.get('param1') == 1 assert len(Config.get('param2')) == 2 assert Config.get('param2')[0] == 'first' assert Config.get('param2')[1] == 'second'
def process(self, real_estate, params, sld_url): """ Central processing method to hook in from webservice. Args: real_estate (pyramid_oereb.lib.records.real_estate.RealEstateRecord): The real estate reader to obtain the real estates record. params (pyramid_oereb.views.webservice.Parameter): The parameters of the extract request. sld_url (str): The URL which provides the sld to style and filter the highlight of the real estate. Returns: pyramid_oereb.lib.records.extract.ExtractRecord: The generated extract record. """ log.debug("process() start") municipality = self._municipality_reader_.read(params, real_estate.fosnr)[0] exclusions_of_liability = self._exclusion_of_liability_reader_.read( params) glossaries = self._glossary_reader_.read(params) extract_raw = self._extract_reader_.read(params, real_estate, municipality) extract = self.plr_tolerance_check(extract_raw) resolver = DottedNameResolver() sort_within_themes_method_string = Config.get('extract').get( 'sort_within_themes_method') if sort_within_themes_method_string: sort_within_themes_method = resolver.resolve( sort_within_themes_method_string) extract = sort_within_themes_method(extract) else: log.info( "No configuration is provided for extract sort_within_themes_method;" " no further sorting is applied.") # the selection of view services is done after the tolerance check. This enables us to take # care about the circumstance that after tolerance check plrs will be dismissed which were # recognized as intersecting before. To avoid this the tolerance check is gathering all plrs # intersecting and not intersecting and starts the legend entry sorting after. self.view_service_handling(extract.real_estate, params.images, params.format) extract.exclusions_of_liability = exclusions_of_liability extract.glossaries = glossaries # obtain the highlight wms url and its content only if the parameter full was requested (PDF) if params.flavour == 'full': if Config.get('full_extract_use_sld', True): extract.real_estate.set_highlight_url(sld_url) log.debug("process() done, returning extract.") return extract
def calculate(self, real_estate, min_length, min_area, length_unit, area_unit): """ Entry method for calculation. It checks if the geometry type of this instance is a geometry collection which has to be unpacked first in case of collection. Args: real_estate (pyramid_oereb.lib.records.real_estate.RealEstateRecord): The real estate record. min_length (float): The threshold to consider or not a line element. min_area (float): The threshold to consider or not a surface element. length_unit (unicode): The thresholds unit for area calculation. area_unit (unicode): The thresholds unit for area calculation. Returns: bool: True if intersection fits the limits. """ geometry_types = Config.get('geometry_types') line_types = geometry_types.get('line').get('types') polygon_types = geometry_types.get('polygon').get('types') point_types = geometry_types.get('point').get('types') if self.published: result = self._extract_collection( self.geom.intersection(real_estate.limit)) # TODO upon update to Shapely 1.7, a check for result.is_emtpy will be needed (see PR#1037) # differentiate between Points and MultiPoint if self.geom.type not in point_types + line_types + polygon_types: supported_types = ', '.join(point_types + line_types + polygon_types) raise AttributeError( u'The passed geometry is not supported: {type}. It should be one of: {types}' .format(type=self.geom.type, types=supported_types)) elif self.geom.type in point_types: if result.type == point_types[1]: # If it is a multipoint make a list and count the number of elements in the list self._nr_of_points = len(list(result.geoms)) self._test_passed = True elif result.type == point_types[0]: # If it is a single point the number of points is one self._nr_of_points = 1 self._test_passed = True elif self.geom.type in line_types and result.type in line_types: self._units = length_unit length_share = result.length if length_share >= min_length: self._length_share = length_share self._test_passed = True elif self.geom.type in polygon_types and result.type in polygon_types: self._units = area_unit area_share = result.area compensated_area = area_share / real_estate.areas_ratio if compensated_area >= min_area: self._area_share = compensated_area self._test_passed = True else: log.debug( u'Intersection result changed geometry type. ' u'Original geometry was {0} and result is {1}'.format( self.geom.type, result.type)) self.calculated = True return self._test_passed
def test_add_existing_connection(): db_url = Config.get('app_schema').get('db_connection') adapter = DatabaseAdapter() adapter.add_connection(db_url) expected_length = len(adapter.get_connections()) adapter.add_connection(db_url) assert len(adapter.get_connections()) == expected_length
def parse(self, view_service): # pragma: no cover language = Config.get('default_language') for element in view_service: if get_tag(element) == self.TAG_LEGEND: count = 1 for legend_entry in element: if get_tag(legend_entry) == self.TAG_LEGEND_ENTRY: sub_theme = parse_string(legend_entry, self.TAG_SUB_THEME) if sub_theme is not None: sub_theme = {language: sub_theme} instance = self._model( id='{0}.legende.{1}'.format( view_service.attrib['TID'], count), symbol=self._parse_symbol(legend_entry, self.TAG_SYMBOL), legend_text=parse_multilingual_text( legend_entry, self.TAG_LEGEND_TEXT), type_code=parse_string(legend_entry, self.TAG_TYPE_CODE), type_code_list=parse_string( legend_entry, self.TAG_TYPE_CODE_LIST), topic=self._topic_code, sub_theme=sub_theme, other_theme=parse_string(legend_entry, self.TAG_OTHER_THEME), view_service_id=view_service.attrib['TID']) self._session.add(instance) count += 1
def __init__(self, configuration, section='pyramid_oereb', c2ctemplate_style=False, directory='sample_data', sql_file=None): """ Args: configuration (str): Path to the configuration yaml file. section (str): The used section within the yaml file. Default is `pyramid_oereb`. c2ctemplate_style (bool): True if the yaml use a c2c template style (vars.[section]). Default is False. directory (str): Location of the sample data. Default is `sample_data`. sql_file (file): The SQL file to be created. Default is None. """ self._configuration = configuration self._section = section self._directory = directory self._sql_file = sql_file Config.init(self._configuration, self._section, c2ctemplate_style) self._engine = create_engine( Config.get('app_schema').get('db_connection'), echo=True) self._connection = None
def parse(self, public_law_restriction): # pragma: no cover language = Config.get('default_language') sub_theme = parse_string(public_law_restriction, self.TAG_SUB_THEME) if sub_theme is not None: sub_theme = {language: sub_theme} instance = self._model( id=public_law_restriction.attrib['TID'], information=parse_multilingual_text(public_law_restriction, self.TAG_INFORMATION), topic=self._topic_code, sub_theme=sub_theme, other_theme=parse_string(public_law_restriction, self.TAG_OTHER_THEME), type_code=parse_string(public_law_restriction, self.TAG_TYPE_CODE), type_code_list=parse_string(public_law_restriction, self.TAG_TYPE_CODE_LIST), law_status=parse_string(public_law_restriction, self.TAG_LAW_STATUS), published_from=parse_string(public_law_restriction, self.TAG_PUBLISHED_FROM), view_service_id=parse_ref(public_law_restriction, self.TAG_VIEW_SERVICE), office_id=parse_ref(public_law_restriction, self.TAG_RESPONSIBLE_OFFICE)) self._session.add(instance)
def get_full_wms_url(self, real_estate, format): """ Returns the WMS URL to get the image. Args: real_estate (pyramid_oereb.lob.records.real_estate.RealEstateRecord): The Real Estate record. format (string): The format currently used. For 'pdf' format, the used map size will be adapted to the pdf format, Returns: str: The url used to query the WMS server. """ assert real_estate.limit is not None map_size = self.get_map_size(format) bbox = self.get_bbox(real_estate.limit) self.reference_wms = add_url_params( self.reference_wms, { "BBOX": ",".join([str(e) for e in bbox]), "SRS": 'EPSG:{0}'.format(Config.get('srid')), "WIDTH": int(map_size[0]), "HEIGHT": int(map_size[1]) }) self.calculate_ns() return self.reference_wms
def test_get_logo_multilingual(language): Config._config = None Config.init('./tests/resources/test_config.yml', 'pyramid_oereb') Config.get('logo')['oereb'] = { 'de': 'pyramid_oereb/standard/logo_oereb_de.png', 'fr': 'pyramid_oereb/standard/logo_oereb_fr.png', 'it': 'pyramid_oereb/standard/logo_oereb_it.png' } logos = Config.get_logo_config(language=language) assert isinstance(logos, dict) logo_oereb = logos.get('oereb') if language is None: assert logo_oereb.content == FileAdapter().read( Config.get('logo').get('oereb').get('de')) else: assert logo_oereb.content == FileAdapter().read( Config.get('logo').get('oereb').get(language))
def create_processor(): """ Creates and returns a processor based on the application configuration. You should use one (and only one) processor per request. Otherwise some results can be mixed or missing. Returns: pyramid_oereb.lib.processor.Processor: A processor. """ real_estate_config = Config.get_real_estate_config() municipality_config = Config.get_municipality_config() exclusion_of_liability_config = Config.get_exclusion_of_liability_config() glossary_config = Config.get_glossary_config() extract = Config.get_extract_config() certification = extract.get('certification') certification_at_web = extract.get('certification_at_web') plr_cadastre_authority = Config.get_plr_cadastre_authority() real_estate_reader = RealEstateReader( real_estate_config.get('source').get('class'), **real_estate_config.get('source').get('params')) municipality_reader = MunicipalityReader( municipality_config.get('source').get('class'), **municipality_config.get('source').get('params')) exclusion_of_liability_reader = ExclusionOfLiabilityReader( exclusion_of_liability_config.get('source').get('class'), **exclusion_of_liability_config.get('source').get('params')) glossary_reader = GlossaryReader( glossary_config.get('source').get('class'), **glossary_config.get('source').get('params')) plr_sources = [] for plr in Config.get('plrs'): plr_source_class = DottedNameResolver().maybe_resolve( plr.get('source').get('class')) plr_sources.append(plr_source_class(**plr)) extract_reader = ExtractReader( plr_sources, plr_cadastre_authority, certification, certification_at_web, ) return Processor( real_estate_reader=real_estate_reader, municipality_reader=municipality_reader, exclusion_of_liability_reader=exclusion_of_liability_reader, glossary_reader=glossary_reader, plr_sources=plr_sources, extract_reader=extract_reader, )
def test_get_logo_config(): Config._config = None Config.init('./tests/resources/test_config.yml', 'pyramid_oereb') logos = Config.get_logo_config() assert isinstance(logos, dict) logo_oereb = logos.get('oereb') assert isinstance(logo_oereb, ImageRecord) assert logo_oereb.content == FileAdapter().read( Config.get('logo').get('oereb'))
def init_processor(): global processor real_estate_config = Config.get_real_estate_config() municipality_config = Config.get_municipality_config() exclusion_of_liability_config = Config.get_exclusion_of_liability_config() glossary_config = Config.get_glossary_config() extract = Config.get_extract_config() certification = extract.get('certification') certification_at_web = extract.get('certification_at_web') logos = Config.get_logo_config() plr_cadastre_authority = Config.get_plr_cadastre_authority() real_estate_reader = RealEstateReader( real_estate_config.get('source').get('class'), **real_estate_config.get('source').get('params')) municipality_reader = MunicipalityReader( municipality_config.get('source').get('class'), **municipality_config.get('source').get('params')) exclusion_of_liability_reader = ExclusionOfLiabilityReader( exclusion_of_liability_config.get('source').get('class'), **exclusion_of_liability_config.get('source').get('params')) glossary_reader = GlossaryReader( glossary_config.get('source').get('class'), **glossary_config.get('source').get('params')) plr_sources = [] for plr in Config.get('plrs'): plr_source_class = DottedNameResolver().maybe_resolve( plr.get('source').get('class')) plr_sources.append(plr_source_class(**plr)) extract_reader = ExtractReader( plr_sources, plr_cadastre_authority, logos, certification, certification_at_web, ) processor = Processor( real_estate_reader=real_estate_reader, municipality_reader=municipality_reader, exclusion_of_liability_reader=exclusion_of_liability_reader, glossary_reader=glossary_reader, plr_sources=plr_sources, extract_reader=extract_reader, )
def __init__(self, current_route_url=None): super(MockRequest, self).__init__() self._current_route_url = current_route_url Config._config = None Config.init(pyramid_oereb_test_yml, 'pyramid_oereb') real_estate_config = Config.get_real_estate_config() municipality_config = Config.get_municipality_config() exclusion_of_liability_config = Config.get_exclusion_of_liability_config( ) glossary_config = Config.get_glossary_config() extract = Config.get_extract_config() certification = extract.get('certification') certification_at_web = extract.get('certification_at_web') logos = Config.get_logo_config() plr_cadastre_authority = Config.get_plr_cadastre_authority() real_estate_reader = RealEstateReader( real_estate_config.get('source').get('class'), **real_estate_config.get('source').get('params')) municipality_reader = MunicipalityReader( municipality_config.get('source').get('class'), **municipality_config.get('source').get('params')) exclusion_of_liability_reader = ExclusionOfLiabilityReader( exclusion_of_liability_config.get('source').get('class'), **exclusion_of_liability_config.get('source').get('params')) glossary_reader = GlossaryReader( glossary_config.get('source').get('class'), **glossary_config.get('source').get('params')) plr_sources = [] for plr in Config.get('plrs'): plr_source_class = DottedNameResolver().maybe_resolve( plr.get('source').get('class')) plr_sources.append(plr_source_class(**plr)) extract_reader = ExtractReader(plr_sources, plr_cadastre_authority, logos, certification, certification_at_web) self.processor = Processor( real_estate_reader=real_estate_reader, municipality_reader=municipality_reader, exclusion_of_liability_reader=exclusion_of_liability_reader, glossary_reader=glossary_reader, plr_sources=plr_sources, extract_reader=extract_reader, )
def parse(self, view_service): # pragma: no cover reference_wms = parse_string(view_service, self.TAG_REFERENCE_WMS) language = Config.get('default_language') legend_at_web = parse_string(view_service, self.TAG_LEGEND_AT_WEB) if legend_at_web is not None: legend_at_web = {language: legend_at_web} if legend_at_web is None and reference_wms is not None: legend_at_web = { language: self._copy_legend_at_web_from_reference_wms(reference_wms) } instance = self._model(id=view_service.attrib['TID'], reference_wms=reference_wms, legend_at_web=legend_at_web) self._session.add(instance) self._legend_entry.parse(view_service)
def includeme(config): """ By including this in your pyramid web app you can easily provide a running OEREB Server Args: config (Configurator): The pyramid apps config object """ global route_prefix # Set route prefix route_prefix = config.route_prefix # Get settings settings = config.get_settings() # Load configuration file cfg_file = settings.get('pyramid_oereb.cfg.file', None) cfg_c2ctemplate_file = settings.get('pyramid_oereb.cfg.c2ctemplate.file', None) cfg_section = settings.get('pyramid_oereb.cfg.section', None) Config.init(cfg_file or cfg_c2ctemplate_file, cfg_section, cfg_file is None) Config.update_settings(settings) settings.update({'pyramid_oereb': Config.get_config()}) config.add_request_method(pyramid_oereb_processor, reify=True) config.add_renderer('pyramid_oereb_extract_json', 'pyramid_oereb.lib.renderer.extract.json_.Renderer') config.add_renderer('pyramid_oereb_extract_xml', 'pyramid_oereb.lib.renderer.extract.xml_.Renderer') config.add_renderer('pyramid_oereb_extract_print', Config.get('print').get('renderer')) config.add_renderer('pyramid_oereb_versions_xml', 'pyramid_oereb.lib.renderer.versions.xml_.Renderer') config.add_renderer( 'pyramid_oereb_capabilities_xml', 'pyramid_oereb.lib.renderer.capabilities.xml_.Renderer') config.add_renderer('pyramid_oereb_getegrid_xml', 'pyramid_oereb.lib.renderer.getegrid.xml_.Renderer') config.include('pyramid_oereb.routes')
def download_wms_content(self): """ Simply downloads the image found behind the URL stored in the instance attribute "reference_wms". Raises: LookupError: Raised if the response is not code 200 or content-type doesn't contains type "image". AttributeError: Raised if the URL itself isn't valid at all. """ main_msg = "Image for WMS couldn't be retrieved." if uri_validator(self.reference_wms): log.debug( "Downloading image, url: {url}".format(url=self.reference_wms)) try: response = requests.get(self.reference_wms, proxies=Config.get('proxies')) except Exception as ex: dedicated_msg = "An image could not be downloaded. URL was: {url}, error was " \ "{response}".format( url=self.reference_wms, response=ex ) log.error(dedicated_msg) raise LookupError(dedicated_msg) content_type = response.headers.get('content-type', '') if response.status_code == 200 and content_type.find('image') > -1: self.image = ImageRecord(response.content) else: dedicated_msg = "The image could not be downloaded. URL was: {url}, Response was " \ "{response}".format( url=self.reference_wms, response=response.content.decode('utf-8') ) log.error(main_msg) log.error(dedicated_msg) raise LookupError(dedicated_msg) else: dedicated_msg = "URL seems to be not valid. URL was: {url}".format( url=self.reference_wms) log.error(main_msg) log.error(dedicated_msg) raise AttributeError(dedicated_msg)
def calculate(self, real_estate, min_length, min_area, length_unit, area_unit): """ Entry method for calculation. It checks if the geometry type of this instance is a geometry collection which has to be unpacked first in case of collection. Args: real_estate (pyramid_oereb.lib.records.real_estate.RealEstateRecord): The real estate record. min_length (float): The threshold to consider or not a line element. min_area (float): The threshold to consider or not a surface element. length_unit (unicode): The thresholds unit for area calculation. area_unit (unicode): The thresholds unit for area calculation. Returns: bool: True if intersection fits the limits. """ geometry_types = Config.get('geometry_types') point_types = geometry_types.get('point').get('types') line_types = geometry_types.get('line').get('types') polygon_types = geometry_types.get('polygon').get('types') if self.published: if self.geom.type in point_types: self._test_passed = real_estate.limit.intersects(self.geom) else: result = self.geom.intersection(real_estate.limit) if self.geom.type in line_types: self._units = length_unit length = result.length if length >= min_length: self._length = length self._test_passed = True elif self.geom.type in polygon_types: self._units = area_unit area = result.area compensated_area = area / real_estate.areas_ratio if compensated_area >= min_area: self._area = compensated_area self._test_passed = True else: # TODO: configure a proper error message log.error('Unknown geometry type') self.calculated = True return self._test_passed
produce a own new topic for the oereb eco system in the specifications shape. To be able to adapt this models to your own infrastructure you must implement the same attribute names! In fact that inheritance is not easily made you need to make your own classes and adapt them to your database. """ import sqlalchemy as sa from pyramid_oereb.standard.models import NAMING_CONVENTION from pyramid_oereb.lib.config import Config from sqlalchemy.ext.declarative import declarative_base from geoalchemy2.types import Geometry as GeoAlchemyGeometry from sqlalchemy.orm import relationship from sqlalchemy_utils import JSONType metadata = sa.MetaData(naming_convention=NAMING_CONVENTION) Base = declarative_base() srid = Config.get('srid') class Availability(Base): """ A simple bucket for achieving a switch per municipality. Here you can configure via the imported data if a public law restriction is available or not. You need to fill it with the data you provided in the app schemas municipality table (fosnr). Attributes: fosnr (int): The identifier of the municipality in your system (id_bfs = fosnr) available (bool): The switch field to configure if this plr is available for the municipality or not. This field has direct influence on the applications behaviour. See documentation for more info. """ __table_args__ = {'schema': 'regional_protected_botanical_objects'}
def create_legend_entries_in_standard_db(config, topic_code, temp_creation_path='/tmp/pyconizer', language='de', section='pyramid_oereb', image_format='image/png', image_height=36, image_width=72, encoding=None, replace_host=None, replace_layer=None, string_keys=False, by_type_code=False): """ Uses the pyconizer lib to create images out of the OEREB server configuration. It is creating symbols for a dedicated topic. This function will clean all previously created icons from database. Args: config (str): The path to the used OEREB server configuration YAML file. topic_code (str): The topic code for which the symbols should be created. It must be configured in the passed yml. temp_creation_path: The path where the images are created in. language: The language which is used to produce the WMS rules. This is a tricky part. You must provide the language your WMS is using. section: The section which the config can be found in the yml. image_format: The image format. This is passed throug to the WMS request. You need to provide a format your WMS is supporting here. image_height: The height of the produced image. image_width: The width of the produced image. encoding (str or unicode): The encoding which is used to encode the XML. Standard is None. This means the encoding is taken from the XML content itself. Only use this parameter if your XML content has no encoding set. replace_host (str or None): The host which should be used instead of the one which is in the data. This is only recommended on deploy process when your WMS might be already available on a DEV instance but not on the production system which is linked in the data. Then you can create legend entries by obtaining them from this DEV instance. replace_layer (str or None): The layer which should be used instead of the one which is in the data. This is only recommended on deploy process when your WMS might be already available on a DEV instance serving a special legend layer but not on the production system which is linked in the data. Then you can create legend entries by obtaining them from this DEV instances special legend layer. string_keys (bool): Switch for setting primary key for legend entries whether to string or integer by_type_code (bool): If set the process will use the type_code instead of name for obtaining the legend icons. This needs a WMS layer to be configured with the type_code in its name property. It prevents the legend entry creation process to be broken for case sensitive class names in MAPSERVER. Because the "RULE" parameter of the GetLegendGraphics request on MAPSERVER seems to be case insensitive. """ # config object parsed from oereb configuration yml Config.init(config, section) db_connection = None found = False # try to find the topic in config and create the orm models for further processing for topic in Config.get('plrs'): if topic.get('code') == topic_code: db_connection = topic.get('source').get('params').get('db_connection') Plr = DottedNameResolver().maybe_resolve( '{models_path}.PublicLawRestriction'.format( models_path=topic.get('source').get('params').get('models') ) ) LegendEntry = DottedNameResolver().maybe_resolve( '{models_path}.LegendEntry'.format( models_path=topic.get('source').get('params').get('models')) ) found = True break if not found: # at this point it was not possible to find the topic in configuration log.error('The topic with code "{0}" was not found in passed configuration!'.format(topic_code)) return # we can start process now... engine = create_engine(db_connection, echo=True) Session = orm.scoped_session(orm.sessionmaker(bind=engine)) session = Session() # clean up table first session.execute('''TRUNCATE TABLE {schema}.{table} RESTART IDENTITY'''.format( schema=LegendEntry.__table__.schema, table=LegendEntry.__table__.name )) # select all plrs from distinct on information, view_service_id and type_code unique_plrs = session.query(Plr).distinct( Plr.view_service_id, Plr.type_code ).all() pyconizer_config = [] type_code_list = [] # first create the configuration for the pyconizer package for unique_plr in unique_plrs: if unique_plr.type_code not in type_code_list: type_code_list.append(unique_plr.type_code) url, params = parse_url(unique_plr.view_service.reference_wms) layer_existent = False service_url = urlunsplit((url.scheme, url.netloc, url.path, '', '')) \ if replace_host is None else replace_host layer = params.get('LAYERS')[0] if replace_layer is None else replace_layer for layer_config in pyconizer_config: if layer_config.get('url') == service_url and \ layer_config.get('layer') == layer: layer_existent = True if not layer_existent: pyconizer_config.append({ 'url': service_url, 'layer': layer, 'get_styles': { 'request': 'GetStyles', 'service': 'WMS', 'srs': params.get('SRS'), 'version': params.get('VERSION') }, 'get_legend': { 'image_format': image_format, 'request': 'GetLegendGraphic', 'service': 'WMS', 'version': params.get('VERSION'), 'width': image_width, 'height': image_height } }) # create the icons with pyconizer package create_icons_from_scratch(pyconizer_config, temp_creation_path, images=True, encoding=encoding) # reuse plr information to build legend entries and assign the symbol i = 1 for unique_plr in unique_plrs: url, params = parse_url(unique_plr.view_service.reference_wms) layer = params.get('LAYERS')[0] if replace_layer is None else replace_layer # obtain symbol from pyconizer structure. if by_type_code: class_name = unique_plr.type_code else: if isinstance(unique_plr.information, dict): class_name = unique_plr.information.get(language) else: class_name = unique_plr.information symbol = get_icon( temp_creation_path, layer, class_name ) if symbol: session.add(LegendEntry( id=str(i) if string_keys else i, symbol=symbol, legend_text=unique_plr.information, type_code=unique_plr.type_code, topic=unique_plr.topic, type_code_list=''.join(type_code_list), view_service_id=unique_plr.view_service_id )) session.flush() i += 1 else: log.warn('It was not possible to find a symbol for the class: {0}'.format(class_name)) session.commit() session.close()
Whenever you configure your own sqlalchemy ORM's to use them in this application you must imitate the behaviour of the ORM's here. This means the names class variables as well as the types of these variables. """ import sqlalchemy as sa from geoalchemy2 import Geometry from sqlalchemy.ext.declarative import declarative_base from sqlalchemy_utils import JSONType from pyramid_oereb.standard.models import NAMING_CONVENTION from pyramid_oereb.lib.config import Config metadata = sa.MetaData(naming_convention=NAMING_CONVENTION) Base = declarative_base() app_schema_name = Config.get('app_schema').get('name') srid = Config.get('srid') class Municipality(Base): """ The municipality is the place where you hold the information about all the municipalities you are having in your canton. This is used also in the applications process to check whether a municipality is published or not. Attributes: fosnr (int): The identifier of the municipality. It is the commonly known id_bfs or as or nofs in the french part. name (str): The Name of the municipality. published (bool): Switch whether a municipality is published or not. This has direct influence on extract generation.
def read(self, params, real_estate, municipality): """ This method finally creates the extract. .. note:: If you subclass this class your implementation needs to offer this method in the same signature. Means the parameters must be the same and the return must be a :ref:`api-pyramid_oereb-lib-records-extract-extractrecord`. Otherwise the API like way the server works would be broken. Args: params (pyramid_oereb.views.webservice.Parameter): The parameters of the extract request. real_estate (pyramid_oereb.lib.records.real_estate.RealEstateRecord): The real estate for which the report should be generated municipality (pyramid_oereb.lib.records.municipiality.MunicipalityRecord): The municipality record. Returns: pyramid_oereb.lib.records.extract.ExtractRecord: The extract record containing all gathered data. """ log.debug("read() start") assert isinstance(municipality.logo, ImageRecord) bbox = ViewServiceRecord.get_bbox(real_estate.limit) bbox = box(bbox[0], bbox[1], bbox[2], bbox[3]) datasource = list() concerned_themes = list() not_concerned_themes = list() themes_without_data = list() if municipality.published: for position, plr_source in enumerate(self._plr_sources_, start=1): if not params.skip_topic(plr_source.info.get('code')): log.debug("read() going to read from plr_source {}".format(plr_source)) plr_source.read(params, real_estate, bbox, position) log.debug("read() done reading from plr_source {}".format(plr_source)) for ds in plr_source.datasource: if not params.skip_topic(ds.theme.code): datasource.append(ds) real_estate.public_law_restrictions.extend(plr_source.records) for plr in real_estate.public_law_restrictions: # Filter topics due to topics parameter if not params.skip_topic(plr.theme.code): if isinstance(plr, PlrRecord): contained = False for theme in concerned_themes: if theme.code == plr.theme.code: contained = True if not contained: concerned_themes.append(plr.theme) elif isinstance(plr, EmptyPlrRecord): if plr.has_data: not_concerned_themes.append(plr.theme) else: themes_without_data.append(plr.theme) else: for plr_source in self._plr_sources_: themes_without_data.append(Config.get_theme(plr_source.info.get('code'))) # Load base data form configuration resolver = DottedNameResolver() date_method_string = Config.get('extract').get('base_data').get('methods').get('date') date_method = resolver.resolve(date_method_string) av_update_date = date_method(real_estate) base_data = Config.get_base_data(av_update_date) general_information = Config.get('extract').get('general_information') logos = Config.get_logo_config(language=params.language) av_provider_method_string = Config.get('extract').get('base_data').get('methods').get('provider') av_provider_method = resolver.resolve(av_provider_method_string) cadaster_state = datetime.datetime.now() embeddable = EmbeddableRecord( cadaster_state, self.plr_cadastre_authority, av_provider_method(real_estate), av_update_date, datasource ) self.extract = ExtractRecord( real_estate, logos.get('oereb'), logos.get('confederation'), logos.get('canton'), municipality.logo, self.plr_cadastre_authority, base_data, embeddable, self.certification, self.certification_at_web, concerned_theme=concerned_themes, not_concerned_theme=not_concerned_themes, theme_without_data=themes_without_data, general_information=general_information ) log.debug("read() done") return self.extract
def _import_forest_perimeters(self): from pyramid_oereb.standard.models import forest_perimeters connection = self._engine.connect() # Add dummy PLR data for line geometry wms_url = u'https://wms.geo.admin.ch/?SERVICE=WMS&REQUEST=GetMap&VERSION=1.1.1&STYLES=default' \ u'&SRS=EPSG:{0}&BBOX=475000,60000,845000,310000&WIDTH=740&HEIGHT=500&FORMAT=image/png' \ u'&LAYERS=ch.bav.kataster-belasteter-standorte-oev.oereb' connection.execute( forest_perimeters.ViewService.__table__.insert(), { 'id': '1', 'reference_wms': wms_url.format(Config.get('srid')), 'layer_index': 1, 'layer_opacity': 1.0 }) connection.execute( forest_perimeters.LegendEntry.__table__.insert(), { 'id': '1', 'symbol': b64.encode(file_adapter.read('tests/resources/symbol.png')), 'legend_text': { 'de': u'Test' }, 'type_code': u'CodeA', 'type_code_list': u'type_code_list', 'topic': u'ForestPerimeters', 'view_service_id': '1' }) connection.execute(forest_perimeters.Office.__table__.insert(), { 'id': '1', 'name': { 'de': u'Test Office' } }) connection.execute( forest_perimeters.DataIntegration.__table__.insert(), { 'id': '1', 'date': u'2017-07-01T00:00:00', 'office_id': '1' }) connection.execute( forest_perimeters.PublicLawRestriction.__table__.insert(), { 'id': '1', 'information': { 'de': u'Long line PLR' }, 'topic': u'ForestPerimeters', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( forest_perimeters.Geometry.__table__.insert(), { 'id': '1', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '1', 'office_id': '1', # example geometry which does not concern the real_estate (tolerance_check) 'geom': u'SRID=2056;LINESTRING (1.5 1.5, 1.5 2.5)' }) connection.close()
def _import_land_use_plans(self): from pyramid_oereb.standard.models import land_use_plans connection = self._engine.connect() # Add dummy PLR data for collection geometry test wms_url = u'https://wms.geo.admin.ch/?SERVICE=WMS&REQUEST=GetMap&VERSION=1.1.1&STYLES=default' \ u'&SRS=EPSG:{0}&BBOX=475000,60000,845000,310000&WIDTH=740&HEIGHT=500&FORMAT=image/png' \ u'&LAYERS=ch.bav.kataster-belasteter-standorte-oev.oereb' connection.execute( land_use_plans.ViewService.__table__.insert(), { 'id': '1', 'reference_wms': wms_url.format(Config.get('srid')), 'layer_index': 1, 'layer_opacity': 1.0 }) connection.execute( land_use_plans.LegendEntry.__table__.insert(), { 'id': '1', 'symbol': b64.encode(file_adapter.read('tests/resources/symbol.png')), 'legend_text': { 'de': u'Test' }, 'type_code': u'CodeA', 'type_code_list': u'type_code_list', 'topic': u'LandUsePlans', 'view_service_id': '1' }) connection.execute(land_use_plans.Office.__table__.insert(), { 'id': '1', 'name': { 'de': u'Test Office' } }) connection.execute(land_use_plans.DataIntegration.__table__.insert(), { 'id': '1', 'date': u'2017-07-01T00:00:00', 'office_id': '1' }) connection.execute( land_use_plans.PublicLawRestriction.__table__.insert(), { 'id': '1', 'information': { 'de': u'Large polygon PLR' }, 'topic': u'LandUsePlans', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( land_use_plans.PublicLawRestriction.__table__.insert(), { 'id': '2', 'information': { 'de': u'Small polygon PLR' }, 'topic': u'LandUsePlans', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( land_use_plans.PublicLawRestriction.__table__.insert(), { 'id': '3', 'information': { 'de': u'Double intersection polygon PLR' }, 'topic': u'LandUsePlans', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( land_use_plans.PublicLawRestriction.__table__.insert(), { 'id': '4', 'information': { 'de': u'Future PLR' }, 'topic': u'LandUsePlans', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': (date.today() + timedelta(days=7)).isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( land_use_plans.Geometry.__table__.insert(), { 'id': '1', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '1', 'office_id': '1', 'geom': u'SRID=2056;GEOMETRYCOLLECTION(' u'POLYGON((1 -1, 9 -1, 9 7, 1 7, 1 8, 10 8, 10 -2, 1 -2, 1 -1)))' }) connection.execute( land_use_plans.Geometry.__table__.insert(), { 'id': '2', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '1', 'office_id': '1', 'geom': u'SRID=2056;GEOMETRYCOLLECTION(POLYGON((0 0, 0 1.5, 1.5 1.5, 1.5 0, 0 0)))' }) connection.execute( land_use_plans.Geometry.__table__.insert(), { 'id': '3', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '1', 'office_id': '1', 'geom': u'SRID=2056;GEOMETRYCOLLECTION(' u'POLYGON((3 2.5, 3 5, 7 5, 7 0, 3 0, 3 1, 6 1, 6 4, 4 2.5, 3 2.5)))' }) connection.execute( land_use_plans.Geometry.__table__.insert(), { 'id': '4', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '1', 'office_id': '1', 'geom': u'SRID=2056;GEOMETRYCOLLECTION(POLYGON((1.5 1.5, 1.5 2, 2 2, 2 1.5, 1.5 1.5)))' }) connection.execute( land_use_plans.Geometry.__table__.insert(), { 'id': '5', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '1', 'office_id': '1', 'geom': u'SRID=2056;GEOMETRYCOLLECTION(POINT(1 2))' }) connection.close()
def _import_motorways_building_lines(self): from pyramid_oereb.standard.models import motorways_building_lines connection = self._engine.connect() # Add dummy PLR data for line geometry wms_url = u'https://wms.geo.admin.ch/?SERVICE=WMS&REQUEST=GetMap&VERSION=1.1.1&STYLES=default' \ u'&SRS=EPSG:{0}&BBOX=475000,60000,845000,310000&WIDTH=740&HEIGHT=500&FORMAT=image/png' \ u'&LAYERS=ch.bav.kataster-belasteter-standorte-oev.oereb' connection.execute( motorways_building_lines.ViewService.__table__.insert(), { 'id': '1', 'reference_wms': wms_url.format(Config.get('srid')), 'layer_index': 1, 'layer_opacity': 1.0 }) connection.execute( motorways_building_lines.LegendEntry.__table__.insert(), { 'id': '1', 'symbol': b64.encode(file_adapter.read('tests/resources/symbol.png')), 'legend_text': { 'de': u'Test' }, 'type_code': u'CodeA', 'type_code_list': u'type_code_list', 'topic': u'MotorwaysBuildingLines', 'view_service_id': '1' }) connection.execute(motorways_building_lines.Office.__table__.insert(), { 'id': '1', 'name': { 'de': u'Test Office' } }) connection.execute( motorways_building_lines.DataIntegration.__table__.insert(), { 'id': '1', 'date': u'2017-07-01T00:00:00', 'office_id': '1' }) connection.execute( motorways_building_lines.PublicLawRestriction.__table__.insert(), { 'id': '1', 'information': { 'de': u'Long line PLR' }, 'topic': u'MotorwaysBuildingLines', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( motorways_building_lines.PublicLawRestriction.__table__.insert(), { 'id': '2', 'information': { 'de': u'Short line PLR' }, 'topic': u'MotorwaysBuildingLines', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( motorways_building_lines.PublicLawRestriction.__table__.insert(), { 'id': '3', 'information': { 'de': u'Double intersection line PLR' }, 'topic': u'MotorwaysBuildingLines', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( motorways_building_lines.PublicLawRestriction.__table__.insert(), { 'id': '4', 'information': { 'de': u'Future geometry' }, 'topic': u'MotorwaysBuildingLines', 'type_code': u'CodeA', "type_code_list": u'', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'view_service_id': '1', 'office_id': '1' }) connection.execute( motorways_building_lines.Geometry.__table__.insert(), { 'id': '1', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '1', 'office_id': '1', 'geom': u'SRID=2056;LINESTRING (0 0, 2 2)' }) connection.execute( motorways_building_lines.Geometry.__table__.insert(), { 'id': '2', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '2', 'office_id': '1', 'geom': u'SRID=2056;LINESTRING (1.5 1.5, 1.5 2.5)' }) connection.execute( motorways_building_lines.Geometry.__table__.insert(), { 'id': '3', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'public_law_restriction_id': '3', 'office_id': '1', 'geom': u'SRID=2056;LINESTRING (3 1, 3 4, 6 4, 6 1, 4.5 1)' }) connection.execute( motorways_building_lines.Geometry.__table__.insert(), { 'id': '4', 'law_status': u'inForce', 'published_from': (date.today() + timedelta(days=7)).isoformat(), 'public_law_restriction_id': '4', 'office_id': '1', 'geom': u'SRID=2056;LINESTRING (0 0, 4 4)' }) connection.execute( motorways_building_lines.DocumentBase.__table__.insert(), { 'id': '1', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'type': u'document' }) connection.execute( motorways_building_lines.Document.__table__.insert(), { 'id': '1', 'document_type': u'Law', 'title': { 'de': u'First level document' }, 'office_id': '1' }) connection.execute( motorways_building_lines.DocumentBase.__table__.insert(), { 'id': '2', 'law_status': u'inForce', 'published_from': (date.today() + timedelta(days=7)).isoformat(), 'type': u'document' }) connection.execute( motorways_building_lines.Document.__table__.insert(), { 'id': '2', 'document_type': u'Law', 'title': { 'de': u'First level future document' }, 'office_id': '1' }) connection.execute( motorways_building_lines.DocumentBase.__table__.insert(), { 'id': '3', 'law_status': u'inForce', 'published_from': date.today().isoformat(), 'type': u'document' }) connection.execute( motorways_building_lines.Document.__table__.insert(), { 'id': '3', 'document_type': u'Law', 'title': { 'de': u'Second level document' }, 'office_id': '1' }) connection.execute( motorways_building_lines.DocumentBase.__table__.insert(), { 'id': '4', 'law_status': u'inForce', 'published_from': (date.today() + timedelta(days=7)).isoformat(), 'type': u'document' }) connection.execute( motorways_building_lines.Document.__table__.insert(), { 'id': '4', 'document_type': u'Law', 'title': { 'de': u'Second level future document' }, 'office_id': '1' }) connection.execute( motorways_building_lines.PublicLawRestrictionDocument.__table__. insert(), { 'id': '1', 'public_law_restriction_id': '1', 'document_id': '1' }) connection.execute( motorways_building_lines.PublicLawRestrictionDocument.__table__. insert(), { 'id': '2', 'public_law_restriction_id': '1', 'document_id': '2' }) connection.execute( motorways_building_lines.DocumentReference.__table__.insert(), { 'id': '1', 'document_id': '1', 'reference_document_id': '3' }) connection.execute( motorways_building_lines.DocumentReference.__table__.insert(), { 'id': '2', 'document_id': '1', 'reference_document_id': '4' }) connection.close()
def __init__(self): self._engine = create_engine( Config.get('app_schema').get('db_connection'))
def create_tables_from_standard_configuration(configuration_yaml_path, section='pyramid_oereb', c2ctemplate_style=False, tables_only=False, sql_file=None): """ Creates all schemas which are defined in the passed yaml file: <section>.<plrs>.[<plr>.<code>]. The code must be camel case. It will be transformed to snake case and used as schema name. Creates all tables inside the created schemas. This only affects the sqlalchemy models which are defined with the Base class from pyramid_oereb.standard.models. Args: configuration_yaml_path (str): The absolute path to the yaml file which contains the plr definitions. section (str): The section in yaml file where the plrs are configured in. Default is 'pyramid_oereb'. c2ctemplate_style (bool): True if the yaml use a c2c template style (vars.[section]). Default is False. tables_only (bool): True to skip creation of schema. Default is False. sql_file (file): the file to generate. Default is None (in the database). """ if Config.get_config() is None: Config.init(configuration_yaml_path, section, c2ctemplate_style) main_schema_engine = create_engine( Config.get('app_schema').get('db_connection'), echo=True) if sql_file is None: if not tables_only: main_schema_connection = main_schema_engine.connect() try: main_schema_connection.execute( 'CREATE SCHEMA IF NOT EXISTS {name};'.format( name=Config.get('app_schema').get('name'))) finally: main_schema_connection.close() else: sql_file.write('CREATE SCHEMA {name};\n'.format( name=Config.get('app_schema').get('name'))) main_base_class = DottedNameResolver().maybe_resolve( '{package}.Base'.format( package=Config.get('app_schema').get('models'))) if sql_file is None: main_base_class.metadata.create_all(main_schema_engine) else: for table in main_base_class.metadata.sorted_tables: create_table = str(CreateTable(table).compile(main_schema_engine))\ .replace('DATETIME', 'timestamp') sql_file.write('{};\n'.format(create_table)) for schema in Config.get('plrs'): plr_schema_engine = create_engine( schema.get('source').get('params').get('db_connection'), echo=True) if sql_file is None: if schema.get('standard'): if not tables_only: plr_schema_connection = plr_schema_engine.connect() try: plr_schema_connection.execute( 'CREATE SCHEMA IF NOT EXISTS {name};'.format( name=convert_camel_case_to_snake_case( schema.get('code')))) finally: plr_schema_connection.close() plr_base = DottedNameResolver().maybe_resolve( '{package}.Base'.format(package=schema.get('source').get( 'params').get('models'))) plr_base.metadata.create_all(plr_schema_engine) else: plr_base = DottedNameResolver().maybe_resolve( '{package}.Base'.format( package=schema.get('source').get('params').get('models'))) sql_file.write('CREATE SCHEMA {name};\n'.format( name=convert_camel_case_to_snake_case(schema.get('code')))) for table in plr_base.metadata.sorted_tables: create_table = str(CreateTable(table).compile(plr_schema_engine))\ .replace('DATETIME', 'timestamp') sql_file.write('{};\n'.format(create_table))
def includeme(config): """ By including this in your pyramid web app you can easily provide a running OEREB Server Args: config (Configurator): The pyramid apps config object """ global route_prefix, app_schema_name, srid # Set route prefix route_prefix = config.route_prefix # Get settings settings = config.get_settings() # Load configuration file cfg_file = settings.get('pyramid_oereb.cfg.file', None) cfg_c2ctemplate_file = settings.get('pyramid_oereb.cfg.c2ctemplate.file', None) cfg_section = settings.get('pyramid_oereb.cfg.section', None) Config.init(cfg_file or cfg_c2ctemplate_file, cfg_section, cfg_file is None) Config.update_settings(settings) real_estate_config = Config.get_real_estate_config() municipality_config = Config.get_municipality_config() exclusion_of_liability_config = Config.get_exclusion_of_liability_config() glossary_config = Config.get_glossary_config() logos = Config.get_logo_config() app_schema_name = Config.get('app_schema').get('name') srid = Config.get('srid') plr_cadastre_authority = Config.get_plr_cadastre_authority() real_estate_reader = RealEstateReader( real_estate_config.get('source').get('class'), **real_estate_config.get('source').get('params')) municipality_reader = MunicipalityReader( municipality_config.get('source').get('class'), **municipality_config.get('source').get('params')) exclusion_of_liability_reader = ExclusionOfLiabilityReader( exclusion_of_liability_config.get('source').get('class'), **exclusion_of_liability_config.get('source').get('params')) glossary_reader = GlossaryReader( glossary_config.get('source').get('class'), **glossary_config.get('source').get('params')) plr_sources = [] for plr in Config.get('plrs'): plr_source_class = DottedNameResolver().maybe_resolve( plr.get('source').get('class')) plr_sources.append(plr_source_class(**plr)) extract_reader = ExtractReader(plr_sources, plr_cadastre_authority, logos) settings.update({ 'pyramid_oereb': parse(cfg_file or cfg_c2ctemplate_file, cfg_section, cfg_file is None) }) processor = Processor( real_estate_reader=real_estate_reader, municipality_reader=municipality_reader, exclusion_of_liability_reader=exclusion_of_liability_reader, glossary_reader=glossary_reader, plr_sources=plr_sources, extract_reader=extract_reader, ) def pyramid_oereb_processor(request): return processor config.add_request_method(pyramid_oereb_processor, reify=True) config.add_renderer('pyramid_oereb_extract_json', 'pyramid_oereb.lib.renderer.extract.json_.Renderer') config.add_renderer('pyramid_oereb_extract_xml', 'pyramid_oereb.lib.renderer.extract.xml_.Renderer') config.add_renderer('pyramid_oereb_extract_print', Config.get('print').get('renderer')) config.add_renderer('pyramid_oereb_versions_xml', 'pyramid_oereb.lib.renderer.versions.xml_.Renderer') config.add_renderer( 'pyramid_oereb_capabilities_xml', 'pyramid_oereb.lib.renderer.capabilities.xml_.Renderer') config.add_renderer('pyramid_oereb_getegrid_xml', 'pyramid_oereb.lib.renderer.getegrid.xml_.Renderer') config.include('pyramid_oereb.routes')
def test_get_localized_text_from_string(): renderer = Renderer(DummyRenderInfo()) localized_text = renderer.get_localized_text('Test') assert isinstance(localized_text, dict) assert localized_text.get('Text') == 'Test' assert localized_text.get('Language') == Config.get('default_language')
def test_add_connection(): db_url = Config.get('app_schema').get('db_connection') adapter = DatabaseAdapter() adapter.add_connection(db_url) assert isinstance(adapter.get_session(db_url), Session)