예제 #1
0
    def configure(self):
        if self.var('_provider'):
            self.provider = self.var('_provider')
        else:
            self.provider = self.root.create_object(provider.Object,
                                                    self.config,
                                                    shared=True)

        s = self.var('title') or self.var('index')
        self.template = self.provider.print_template(s)
        if not self.template:
            raise gws.Error(f'print template {s!r} not found')

        uid = self.var('uid') or (gws.sha256(self.provider.path) + '_' +
                                  str(self.template.index))
        self.set_uid(uid)

        self.map_position = self.var('mapPosition')

        for el in self.template.elements:
            if el.type == 'page' and el.size:
                self.page_size = el.size
            if el.type == 'map' and el.size:
                self.map_size = el.size
                self.map_position = el.position

        if not self.page_size or not self.map_size or not self.map_position:
            raise gws.Error('cannot read page or map size')
예제 #2
0
def parse_dict(d: dict, trusted, with_strict_mode) -> dict:
    res = dict(_DEFAULTS)

    for key, val in d.items():
        if val is None:
            continue
        k = key.replace('-', '_')
        if k.startswith('__'):
            k = k[2:]

        fn = gws.get(_ParseFunctions, k)

        if not fn:
            err = f'style: invalid css property {key!r}'
            if with_strict_mode:
                raise gws.Error(err)
            else:
                gws.log.error(err)
                continue

        try:
            v = fn(val, trusted)
            if v is not None:
                res[k] = v
        except Exception as exc:
            err = f'style: invalid css value for {key!r}'
            if with_strict_mode:
                raise gws.Error(err) from exc
            else:
                gws.log.error(err)

    return res
예제 #3
0
def require_for(obj: gws.INode) -> Object:
    uid = obj.var('db')
    if uid:
        prov = obj.root.find(klass=Object, uid=uid)
        if not prov:
            raise gws.Error(f'{obj.uid}: db provider {uid!r} not found')
    else:
        prov = obj.root.find(klass=Object)
        if not prov:
            raise gws.Error(f'{obj.uid}: db provider postgres not found')
    return prov
예제 #4
0
    def configure_table(self, cfg: gws.base.db.SqlTableConfig) -> gws.SqlTable:
        table = gws.SqlTable(name=cfg.get('name'))
        cols = self.describe(table)

        if not cols:
            raise gws.Error(
                f'table {table.name!r} not found or not accessible')

        cname = cfg.get('keyColumn')
        if cname:
            for col in cols:
                if col.name == cname:
                    table.key_column = col
                    break
            if not table.key_column:
                raise gws.Error(
                    f'invalid keyColumn {cname!r} for table {table.name!r}')
        else:
            cs = [col for col in cols if col.is_key]
            if len(cs) == 1:
                table.key_column = cs[0]

        cname = cfg.get('geometryColumn')
        if cname:
            for col in cols:
                if col.name == cname and col.is_geometry:
                    table.geometry_column = col
                    break
            if not table.geometry_column:
                raise gws.Error(
                    f'invalid geometryColumn {cname!r} for table {table.name!r}'
                )
        else:
            cs = [col for col in cols if col.is_geometry]
            if len(cs) == 1:
                table.geometry_column = cs[0]
            if len(cs) > 1:
                table.geometry_column = cs[0]
                gws.log.debug(
                    f'found multiple geometry columns for table {table.name!r}, using {table.geometry_column.name!r}'
                )

        cname = cfg.get('searchColumn')
        if cname:
            for col in cols:
                if col.name == cname:
                    table.search_column = col
                    break
            if not table.search_column:
                raise gws.Error(
                    f'invalid searchColumn {cname!r} for table {table.name!r}')

        return table
예제 #5
0
    def _render_legend(self, kwargs):
        layers = self._legend_layers(kwargs)
        if not layers:
            raise gws.Error('no legend layers')

        lro = gws.gis.legend.render(gws.Legend(layers=layers))
        if not lro:
            raise gws.Error('no legend output')

        img_path = gws.gis.legend.to_image_path(lro)
        if not img_path:
            raise gws.Error('no legend image path')

        self.legend_count += 1
        return f'<img src="{img_path}"/>'
예제 #6
0
def _tag(geom, opts):
    typ = geom.type

    if typ == 'Point':
        return opts.ns + 'Point', _pos(geom, opts, False)

    if typ == 'LineString':
        return opts.ns + 'Curve', (opts.ns + 'segments',
                                   (opts.ns + 'LineStringSegment',
                                    _pos(geom, opts)))

    if typ == 'Polygon':
        return (opts.ns + 'Polygon', (opts.ns + 'exterior',
                                      (opts.ns + 'LinearRing',
                                       _pos(geom.exterior, opts))),
                [(opts.ns + 'interior', (opts.ns + 'LinearRing', _pos(r,
                                                                      opts)))
                 for r in geom.interiors])

    if typ == 'MultiPoint':
        return opts.ns + 'MultiPoint', [
            (opts.ns + 'pointMember', _tag(p, opts)) for p in geom
        ]

    if typ == 'MultiLineString':
        return opts.ns + 'MultiCurve', [
            (opts.ns + 'curveMember', _tag(p, opts)) for p in geom
        ]

    if typ == 'MultiPolygon':
        return opts.ns + 'MultiSurface', [
            (opts.ns + 'surfaceMember', _tag(p, opts)) for p in geom
        ]

    raise gws.Error(f'cannot convert geometry type {typ!r} to GML')
예제 #7
0
    def configure(self):
        uid = self.var('uid') or 'map'
        project = self.get_closest('gws.base.project')
        if project:
            uid = project.uid + '.' + uid
        self.set_uid(uid)

        p = self.var('crs')
        self.crs = gws.gis.crs.require(p) if p else gws.gis.crs.get3857()

        self.title = self.var('title') or self.uid

        self.resolutions = _DEFAULT_RESOLUTIONS
        self.init_resolution = _DEFAULT_RESOLUTIONS[-1]

        zoom = self.var('zoom')
        if zoom:
            self.resolutions = gws.gis.zoom.resolutions_from_config(zoom)
            self.init_resolution = gws.gis.zoom.init_resolution(
                zoom, self.resolutions)

        self.layers = self.create_children('gws.ext.layer', self.var('layers'))

        self.extent = _configure_extent(self, self.crs, None)
        if not self.extent:
            raise gws.Error(f'no extent found for {self.uid!r}')
        _set_default_extent(self, self.extent)

        self.center = self.var('center') or gws.gis.extent.center(self.extent)

        self.coordinate_precision = self.var('coordinatePrecision')
        if self.coordinate_precision is None:
            self.coordinate_precision = 2 if self.crs.units == 'm' else 7
예제 #8
0
    def configure(self):
        # with reqSize=1 MP will request the same tile multiple times
        # reqSize=4 is more efficient, however, reqSize=1 yields the first tile faster
        # which is crucial when browsing non-cached low resoltions
        # so, let's use 1 as default, overridable in the config
        #
        # @TODO make MP cache network requests

        self.grid.reqSize = self.grid.reqSize or 1
        self.url = self.var('url')

        p = self.var('service', default=gws.Data())
        self.service = Service(crs=gws.gis.crs.get(p.crs)
                               or gws.gis.crs.get3857(),
                               origin=p.origin,
                               tile_size=p.tileSize,
                               extent=p.extent)

        if not self.service.extent:
            if self.service.crs.srid == gws.gis.crs.c3857:
                self.service.extent = gws.gis.crs.c3857_extent
            else:
                raise gws.Error(
                    f'service extent required for crs {self.service.crs.srid!r}'
                )
예제 #9
0
    def configure(self):
        self.provider = provider.create(self.root, self.config, shared=True)

        self.limit = self.var('limit')

        self.templates = gws.base.template.bundle.create(
            self.root,
            items=self.var('templates'),
            defaults=_DEFAULT_TEMPLATES,
            parent=self)

        self.print_template = self.templates.find(subject='print')
        self.ui = self.var('ui')

        p = self.var('export')
        if p:
            groups = p.groups or _DEFAULT_EXPORT_GROUPS
        elif self.ui.useExport:
            groups = _DEFAULT_EXPORT_GROUPS
        else:
            groups = []
        self.export_groups = [
            self.require_child(ExportGroup, g) for g in groups
        ]

        self.buchung = self.root.create_object(BuchungOptions,
                                               self.var('buchung'))
        self.eigentuemer = self.root.create_object(EigentuemerOptions,
                                                   self.var('eigentuemer'))

        if self.eigentuemer.log_table:
            with self.provider.connection() as conn:
                if not conn.user_can('INSERT', self.eigentuemer.log_table):
                    raise gws.Error(
                        f'no INSERT acccess to {self.eigentuemer.log_table!r}')
예제 #10
0
def _configure_extent(obj, crs: gws.ICrs, default_ext):
    layers = gws.get(obj, 'layers') or []

    # we have an explicit extent provided in the config

    config_ext = obj.var('extent')

    if config_ext:
        ext = gws.gis.extent.from_list(config_ext)
        if not ext:
            raise gws.Error(f'{obj.uid!r}: invalid extent {config_ext!r}')

        # configure sublayers using config_ext as a default
        for la in layers:
            _configure_extent(la, crs, ext)

        obj.extent = ext
        return obj.extent

    if layers:
        # no config extent, configure sublayers using the current default extent
        # set obj.extent to the sum of sublayers' extents

        layer_ext_list = []
        for la in layers:
            layer_ext = _configure_extent(la, crs, default_ext)
            if layer_ext:
                layer_ext_list.append(layer_ext)

        if layer_ext_list:
            obj.extent = gws.gis.extent.merge(layer_ext_list)
        else:
            obj.extent = default_ext
        return obj.extent

    # obj is a leaf layer and has no configured extent
    # check if it has an own extent (from its source)

    own_bounds: gws.Bounds = gws.get(obj, 'own_bounds')

    if own_bounds:
        own_ext = own_bounds.extent
        buf = obj.var('extentBuffer', with_parent=True)
        if buf:
            own_ext = gws.gis.extent.buffer(own_ext, buf)
        own_ext = gws.gis.extent.transform(own_ext, own_bounds.crs, crs)
        obj.extent = own_ext
        return obj.extent

    # obj is a leaf layer and has neither configured nor own extent
    # try using the default extent

    if default_ext:
        obj.extent = default_ext
        return obj.extent

    # no extent can be computed, it will be set to the map extent later on
    return None
예제 #11
0
 def compile(self):
     text = gws.read_file(self.path) if self.path else self.text
     try:
         g = {}
         exec(text, g)
         return g['main']
     except Exception as exc:
         raise gws.Error(
             f'py load error: {exc!r} in {self.path!r}') from exc
예제 #12
0
 def ping():
     gws.log.debug(f'db: ping {self.uid!r}')
     try:
         with self.connection() as conn:
             conn.select_value('select 1 + 1')
             gws.log.debug(f'db connection {self.uid!r}: ok')
     except gws.lib.sql.postgres.Error as exc:
         raise gws.Error(
             f'cannot open db connection {self.uid!r}') from exc
예제 #13
0
def _from_wkb(g, crs):
    crsid = geos.lgeos.GEOSGetSRID(g._geom)
    if crsid:
        crs = gws.gis.crs.get(crsid)
        geos.lgeos.GEOSSetSRID(g._geom, 0)

    if not crs:
        raise gws.Error('missing or invalid crs for WKT')

    return Shape(g, crs)
예제 #14
0
 def _attachment_name():
     if res.attachment_name:
         return res.attachment_name
     if res.path:
         return os.path.basename(res.path)
     if res.mime:
         ext = gws.lib.mime.extension_for(res.mime)
         if ext:
             return 'download.' + ext
     raise gws.Error('missing attachment_name or mime type')
예제 #15
0
    def _get_crs(self, js):
        p = js.get('crs')
        if not p:
            return

        if p.get('type') == 'name':
            crs = gws.gis.crs.get(gws.get(p, 'properties.name'))
            if crs:
                return crs

        raise gws.Error(f'unsupported geojson crs format')
예제 #16
0
    def render(self, tri, notify=None):
        mp = tri.maps[0]

        mri = gws.MapRenderInput(
            background_color=mp.background_color,
            bbox=mp.bbox,
            center=mp.center,
            crs=tri.crs,
            dpi=tri.dpi,
            out_size=self.page_size,
            planes=mp.planes,
            rotation=mp.rotation,
            scale=mp.scale,
        )

        notify = notify or (lambda a, b=None: None)

        notify('begin_print')
        notify('begin_page')
        notify('begin_map')

        mro = gws.gis.render.render_map(mri, notify)
        html = gws.gis.render.output_to_html_string(mro, wrap='fixed')

        notify('end_map')
        notify('end_page')
        notify('finalize_print')

        if not tri.out_mime or tri.out_mime == gws.lib.mime.HTML:
            notify('end_print')
            return gws.ContentResponse(mime=gws.lib.mime.HTML, content=html)

        if tri.out_mime == gws.lib.mime.PDF:
            res_path = gws.tempname('map.pdf')
            gws.lib.html2.render_to_pdf(
                html,
                out_path=res_path,
                page_size=self.page_size,
            )
            notify('end_print')
            return gws.ContentResponse(path=res_path)

        if tri.out_mime == gws.lib.mime.PNG:
            res_path = gws.tempname('map.png')
            gws.lib.html2.render_to_png(
                html,
                out_path=res_path,
                page_size=self.page_size,
            )
            notify('end_print')
            return gws.ContentResponse(path=res_path)

        raise gws.Error(f'invalid output mime: {tri.out_mime!r}')
예제 #17
0
    def render(self, tri, notify=None):
        fn = self.compile()

        ctx = self.prepare_context(tri.context)
        if isinstance(ctx, dict):
            ctx = gws.Data(ctx)

        try:
            return fn(ctx)
        except Exception as exc:
            gws.log.exception()
            raise gws.Error(f'py error: {exc!r} path={self.path!r}') from exc
예제 #18
0
def union(shapes: t.List[gws.IShape]) -> gws.IShape:
    if not shapes:
        raise gws.Error('empty shape union')

    if len(shapes) == 1:
        return shapes[0]

    crs = shapes[0].crs
    shapes = [s.transformed_to(crs) for s in shapes]
    geom = shapely.ops.unary_union([getattr(s, 'geom') for s in shapes])

    return Shape(geom, crs)
예제 #19
0
def from_wkt(s: str, crs: gws.ICrs = None) -> gws.IShape:
    if s.startswith('SRID='):
        # EWKT
        c = s.index(';')
        crsid = s[len('SRID='):c]
        s = s[c + 1:]
        crs = gws.gis.crs.get(crsid)

    if not crs:
        raise gws.Error('missing or invalid crs for WKT')

    geom = geos.WKTReader(geos.lgeos).read(s)
    return Shape(geom, crs)
예제 #20
0
    def new_stored_session(self, typ: str, method: gws.IAuthMethod,
                           user: gws.IUser) -> gws.IAuthSession:
        self.store.cleanup(self.session_life_time)

        uid = self.store.create(typ=typ,
                                method_uid=method.uid,
                                provider_uid=user.provider.uid,
                                user_uid=user.uid,
                                str_user=self.serialize_user(user))

        sess = self.find_stored_session(uid)
        if not sess:
            raise gws.Error('failed to create a new session')

        return sess
예제 #21
0
def configure_layers(obj: gws.IOwsClient, provider_class, **filter_args):
    if obj.var('_provider'):
        obj.provider = obj.var('_provider')
        obj.source_layers = obj.var('_source_layers')
    else:
        obj.provider = obj.root.create_object(provider_class,
                                              obj.config,
                                              shared=True)
        slf = gws.merge(gws.gis.source.LayerFilter(level=1), filter_args,
                        obj.var('sourceLayers'))
        obj.source_layers = gws.gis.source.filter_layers(
            obj.provider.source_layers, slf)

    if not obj.source_layers:
        raise gws.Error(f'no source layers found for {obj.uid!r}')
예제 #22
0
def render_map(mri: gws.MapRenderInput,
               notify: t.Callable = None) -> gws.MapRenderOutput:
    rd = _Renderer(mri=mri,
                   mro=gws.MapRenderOutput(planes=[]),
                   img_count=0,
                   svg_count=0)

    # vectors always use PDF_DPI
    rd.vector_view = _map_view(mri.bbox, mri.center, mri.crs, units.PDF_DPI,
                               mri.rotation, mri.scale, mri.out_size)
    rd.mro.view = rd.vector_view

    if mri.out_size[2] == units.PX:
        # if they want pixels, use PDF_PDI for rasters as well
        rd.raster_view = rd.vector_view

    elif mri.out_size[2] == units.MM:
        # if they want mm, rasters should use they own dpi
        raster_dpi = min(MAX_DPI, max(MIN_DPI, rd.mri.dpi))
        rd.raster_view = _map_view(mri.bbox, mri.center, mri.crs, raster_dpi,
                                   mri.rotation, mri.scale, mri.out_size)

    else:
        raise gws.Error(f'invalid size {mri.out_size!r}')

    # NB: planes are top-to-bottom

    for p in reversed(mri.planes):
        if notify:
            notify('begin_plane', p)
        try:
            _render_plane(rd, p)
        except Exception:
            # swallow exceptions so that we still can render if some layer fails
            gws.log.exception('render: input plane failed')
        if notify:
            notify('end_plane', p)

    return rd.mro
예제 #23
0
    def configure_source(self):
        gws.gis.ows.client.configure_layers(self, provider_module.Object)

        self.source_crs = gws.gis.crs.best_match(
            self.provider.force_crs or self.crs,
            gws.gis.source.supported_crs_list(self.source_layers))

        if len(self.source_layers) > 1:
            gws.log.warn(f'multiple layers found for {self.uid!r}, using the first one')
        self.source_layer = self.source_layers[0]

        self.tile_matrix_set = self.get_tile_matrix_set_for_crs(self.source_crs)
        if not self.tile_matrix_set:
            raise gws.Error(f'no suitable tile matrix set found for layer={self.uid!r}')

        self.style_name = ''
        if self.source_layer.default_style:
            self.style_name = self.source_layer.default_style.name

        self.grid.reqSize = self.grid.reqSize or 1

        return True
예제 #24
0
    def render(self, tri, notify=None):
        notify = notify or _dummy_fn

        notify('begin_print')

        if self.root.application.developer_option('template.always_reload'):
            if self.path:
                self.text = gws.read_file(self.path)

        parser = _Parser()
        rt = _Runtime(self, tri, notify)

        html = self._do_render(self.text, self.prepare_context(tri.context),
                               parser, rt)

        notify('finalize_print')

        mime = tri.out_mime
        if not mime and self.mimes:
            mime = self.mimes[0]
        if not mime:
            mime = gws.lib.mime.HTML

        if mime == gws.lib.mime.HTML:
            notify('end_print')
            return gws.ContentResponse(mime=mime, content=html)

        if mime == gws.lib.mime.PDF:
            res_path = self._finalize_pdf(tri, html, parser)
            notify('end_print')
            return gws.ContentResponse(path=res_path)

        if mime == gws.lib.mime.PNG:
            res_path = self._finalize_png(tri, html, parser)
            notify('end_print')
            return gws.ContentResponse(path=res_path)

        raise gws.Error(f'invalid output mime: {tri.out_mime!r}')
예제 #25
0
    def configure(self):
        self.path = self.var('path')
        self.root.application.monitor.add_path(self.path)

        self.url = 'http://%s:%s' % (self.root.application.var(
            'server.qgis.host'), self.root.application.var('server.qgis.port'))

        self.source_text = self._read(self.path)
        cc = caps.parse(self.source_text)

        self.metadata = cc.metadata
        self.print_templates = cc.print_templates
        self.properties = cc.properties
        self.source_layers = cc.source_layers
        self.version = cc.version

        self.force_crs = gws.gis.crs.get(self.var('forceCrs'))
        self.project_crs = cc.project_crs
        self.crs = self.force_crs or self.project_crs
        if not self.crs:
            raise gws.Error(f'unknown CRS for in {self.path!r}')

        self.direct_render = set(self.var('directRender', default=[]))
        self.direct_search = set(self.var('directSearch', default=[]))
예제 #26
0
    def caps(self, p: CapsParams):
        """Print the capabilities of a service in JSON format"""

        protocol = None

        if p.type:
            protocol = p.type.lower()
        else:
            u = p.src.lower()
            for s in ('wms', 'wmts', 'wfs'):
                if s in u:
                    protocol = s
                    break

        if not protocol:
            raise gws.Error('unknown service')

        if p.src.startswith(('http:', 'https:')):
            xml = gws.gis.ows.request.get_text(
                p.src,
                protocol=t.cast(gws.OwsProtocol, protocol.upper()),
                verb=gws.OwsVerb.GetCapabilities)
        else:
            xml = gws.read_file(p.src)

        mod = gws.import_from_path(
            f'gws/plugin/ows_provider/{protocol}/caps.py')
        res = mod.parse(xml)

        js = gws.lib.json2.to_pretty_string(res, default=_caps_json)

        if p.out:
            gws.write_file(p.out, js)
            gws.log.info(f'saved to {p.out!r}')
        else:
            print(js)
예제 #27
0
def parse(xml: str) -> Caps:
    root_el = xml2.from_string(xml,
                               sort_atts=True,
                               strip_ns=True,
                               to_lower=True)

    ver = root_el.attributes.get('version', '').split('-')[0]
    if not ver.startswith('3'):
        raise gws.Error(f'unsupported QGIS version {ver!r}')

    caps = Caps(version=ver)

    caps.properties = _properties(xml2.first(root_el, 'properties'))
    caps.metadata = _project_meta_from_props(caps.properties)
    caps.project_crs = gws.gis.crs.get(
        xml2.text(root_el, 'projectCrs spatialrefsys authid'))
    caps.print_templates = _layouts(root_el)

    map_layers = _map_layers(root_el, caps.properties)
    root_group = _map_layer_tree(xml2.first(root_el, 'layer-tree-group'),
                                 map_layers)
    caps.source_layers = gws.gis.source.check_layers(root_group.layers)

    return caps
예제 #28
0
    def _configure_rule(self, r):
        rule = Rule(r)

        name = rule.get('name')
        title = rule.get('title')

        if not name:
            name = gws.to_uid(title) if title else rule.get('source')

        if not name:
            raise gws.Error('missing attribute name')

        rule.name = name
        rule.title = title or name

        rule.type = rule.get('type') or gws.AttributeType.str

        if not rule.editor:
            rule.editor = AttributeEditor(
                type=_DEFAULT_EDITOR.get(rule.type, 'str'))

        rule.validators = r.get('validators') or []

        return rule
예제 #29
0
def run(root: gws.IRoot, uid):
    job = get(root, uid)
    if not job:
        raise gws.Error('invalid job_uid {uid!r}')
    gws.log.debug('running job', job.uid)
    job.run()
예제 #30
0
 def require_helper(self, ext_type):
     for obj in self.helpers:
         if obj.ext_type == ext_type:
             return obj
     raise gws.Error(f'helper {ext_type!r} not found')