Coverage for gws-app/gws/plugin/ows_client/wmts/provider.py: 0%
42 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-23 20:06 +0200
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-23 20:06 +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 if not op:
81 raise gws.Error(f'WMTS: no GetTile operation and no ResourceURL for layer {sl.name!r}')
82 args = self.prepare_operation(op, params=params)
83 url = gws.lib.net.add_params(args.url, args.params)
85 # {} should not be encoded
86 return url.replace('%7B', '{').replace('%7D', '}')
88 def get_tile(self, url_template: str, matrix_uid: str, col: int, row: int) -> bytes:
89 """Fetch a tile.
91 Args:
92 url_template: URL template from ``tile_url_template``.
93 matrix_uid: Tile matrix identifier.
94 col: Tile column.
95 row: Tile row.
97 Returns:
98 The tile image content.
100 Raises:
101 ``gws.ExternalServiceError``: If the request fails or the response is not an image.
102 """
103 url = url_template
104 url = url.replace('{TileMatrix}', matrix_uid)
105 url = url.replace('{TileCol}', str(col))
106 url = url.replace('{TileRow}', str(row))
108 res = gws.lib.net.http_request(url)
109 if not res.ok:
110 raise gws.ExternalServiceError(f'tile request failed: status={res.status_code} url={url!r}')
111 if not res.content_type.startswith('image/'):
112 raise gws.ExternalServiceError(f'tile request failed: content type {res.content_type!r} url={url!r}')
113 return res.content