Coverage for gws-app/gws/plugin/ows_client/wmts/provider.py: 0%
40 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""WMTS service provider."""
3from typing import Optional, cast
5import gws
6import gws.base.layer
7import gws.base.ows.client
8import gws.config.util
9import gws.lib.uom
10import gws.lib.net
12from . import caps
15class Config(gws.base.ows.client.provider.Config):
16 """Connection to a WMTS service."""
19class Object(gws.base.ows.client.provider.Object):
20 """WMTS service provider.
22 Reads the capabilities of a WMTS service, builds tile URL templates and
23 fetches tiles for the layers that use the service.
24 """
26 protocol = gws.OwsProtocol.WMTS
28 tileMatrixSets: list[gws.TileMatrixSet]
29 """Tile matrix sets offered by the service."""
31 def configure(self):
32 cc = caps.parse(self.get_capabilities())
34 self.metadata = cc.metadata
35 self.sourceLayers = cc.sourceLayers
36 self.version = cc.version
37 self.tileMatrixSets = cc.tileMatrixSets
39 self.configure_operations(cc.operations)
41 def tile_url_template(self, sl: gws.SourceLayer, tms: gws.TileMatrixSet, style: gws.SourceStyle) -> str:
42 """Create a tile URL template for a source layer.
44 If the layer has a ``ResourceURL`` of type ``tile``, its template is used,
45 with ``{TileMatrixSet}`` and ``{Style}`` filled in. Otherwise, a KVP GetTile
46 URL is built, with the layer format or ``image/jpeg``. In both cases the
47 result contains the ``{TileMatrix}``, ``{TileCol}`` and ``{TileRow}`` placeholders.
49 Args:
50 sl: Source layer.
51 tms: Tile matrix set.
52 style: Source style.
54 Returns:
55 The URL template.
56 """
57 ru = sl.resourceUrls
58 resource_url = ru.get('tile') if ru else None
60 if resource_url:
61 return (
62 resource_url
63 .replace('{TileMatrixSet}', tms.identifier)
64 .replace('{Style}', style.name))
66 params = {
67 'SERVICE': gws.OwsProtocol.WMTS,
68 'REQUEST': gws.OwsVerb.GetTile,
69 'VERSION': self.version,
70 'LAYER': sl.name,
71 'FORMAT': sl.imageFormat or 'image/jpeg',
72 'TILEMATRIXSET': tms.identifier,
73 'STYLE': style.name,
74 'TILEMATRIX': '{TileMatrix}',
75 'TILECOL': '{TileCol}',
76 'TILEROW': '{TileRow}',
77 }
79 op = self.get_operation(gws.OwsVerb.GetTile)
80 args = self.prepare_operation(op, params=params)
81 url = gws.lib.net.add_params(args.url, args.params)
83 # {} should not be encoded
84 return url.replace('%7B', '{').replace('%7D', '}')
86 def get_tile(self, url_template: str, matrix_uid: str, col: int, row: int) -> bytes:
87 """Fetch a tile.
89 Args:
90 url_template: URL template from ``tile_url_template``.
91 matrix_uid: Tile matrix identifier.
92 col: Tile column.
93 row: Tile row.
95 Returns:
96 The tile image content.
98 Raises:
99 ``gws.ExternalServiceError``: If the request fails or the response is not an image.
100 """
101 url = url_template
102 url = url.replace('{TileMatrix}', matrix_uid)
103 url = url.replace('{TileCol}', str(col))
104 url = url.replace('{TileRow}', str(row))
106 res = gws.lib.net.http_request(url)
107 if not res.ok:
108 raise gws.ExternalServiceError(f'tile request failed: status={res.status_code} url={url!r}')
109 if not res.content_type.startswith('image/'):
110 raise gws.ExternalServiceError(f'tile request failed: content type {res.content_type!r} url={url!r}')
111 return res.content