Coverage for gws-app/gws/plugin/ows_client/wms/flatlayer.py: 0%

81 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-05 13:35 +0200

1"""WMS flat layer.""" 

2 

3from typing import Optional 

4 

5import gws 

6import gws.base.layer 

7import gws.base.legend 

8import gws.base.model 

9import gws.base.search 

10import gws.base.template 

11import gws.config.util 

12import gws.base.metadata 

13import gws.lib.crs 

14import gws.gis.source 

15import gws.gis.zoom 

16 

17from . import grabber, provider 

18 

19 

20@gws.ext.config.layer('wmsflat') 

21class Config(gws.base.layer.Config): 

22 """Layer that renders selected WMS layers as a single image.""" 

23 

24 provider: Optional[provider.Config] 

25 """WMS service the layer is loaded from.""" 

26 sourceLayers: Optional[gws.gis.source.LayerFilter] 

27 """Source layers to render.""" 

28 

29 

30@gws.ext.object.layer('wmsflat') 

31class Object(gws.base.layer.image.Object): 

32 """Image layer that renders selected WMS source layers as a single image. 

33 

34 Map images are fetched with GetMap through a WMS grabber. Queryable source 

35 layers can be searched with a ``wms`` finder. 

36 """ 

37 

38 provider: provider.Object 

39 """WMS service provider.""" 

40 sourceLayers: list[gws.SourceLayer] 

41 """Source layers selected for this layer.""" 

42 sourceCrs: gws.Crs 

43 """CRS of GetMap requests: the forced CRS of the provider, or the source CRS that best matches the map CRS.""" 

44 

45 imageLayers: list[gws.SourceLayer] 

46 """Source layers that are rendered as images.""" 

47 searchLayers: list[gws.SourceLayer] 

48 """Source layers that are queryable.""" 

49 

50 def configure(self): 

51 self.configure_layer() 

52 

53 def create_cache_name(self, cache): 

54 return gws.u.sha256([ 

55 self.provider.cache_hash(), 

56 [sl.name for sl in self.imageLayers], 

57 vars(self.imageFormat), 

58 list(self.wgsExtent), 

59 cache.requestBuffer, 

60 cache.requestTiles, 

61 ])[: gws.base.layer.image.CACHE_NAME_LENGTH] 

62 

63 def create_grabber(self, opts): 

64 return grabber.Object(opts, provider=self.provider, sourceLayers=self.imageLayers, sourceCrs=self.sourceCrs) 

65 

66 def configure_provider(self): 

67 return gws.config.util.configure_provider_for(self, provider.Object) 

68 

69 def configure_sources(self): 

70 if super().configure_sources(): 

71 return True 

72 

73 gws.u.require(self.provider, 'failed to configure service provider') 

74 

75 self.configure_source_layers() 

76 if not self.sourceLayers: 

77 raise gws.Error(f'layer {self!r}: no source layers found for {self.provider.url!r}') 

78 

79 self.imageLayers = gws.gis.source.filter_layers(self.sourceLayers, is_image=True) 

80 self.searchLayers = gws.gis.source.filter_layers(self.sourceLayers, is_queryable=True) 

81 

82 self.sourceCrs = self.provider.forceCrs or gws.lib.crs.best_match( 

83 self.mapCrs, 

84 gws.gis.source.combined_crs_list(self.sourceLayers)) 

85 

86 def configure_source_layers(self): 

87 """Select the source layers from the layers of the provider. 

88 

89 Returns: 

90 Always ``True``. 

91 """ 

92 return gws.config.util.configure_source_layers_for(self, self.provider.sourceLayers) 

93 

94 def configure_models(self): 

95 return gws.config.util.configure_models_for(self, with_default=True) 

96 

97 def create_model(self, cfg): 

98 """Create a ``wms`` model bound to the provider and the source layers of the layer. 

99 

100 Args: 

101 cfg: Model configuration, or ``None`` for the default model. 

102 

103 Returns: 

104 The model object. 

105 """ 

106 return self.create_child( 

107 gws.ext.object.model, 

108 cfg, 

109 type='wms', 

110 _defaultProvider=self.provider, 

111 _defaultSourceLayers=self.sourceLayers 

112 ) 

113 

114 def configure_extent(self): 

115 if super().configure_extent(): 

116 return True 

117 self.wgsExtent = gws.gis.source.combined_wgs_extent(self.imageLayers) or self.mapCrs.wgsExtent 

118 return True 

119 

120 def configure_resolutions(self): 

121 if super().configure_resolutions(): 

122 return True 

123 self.resolutions = gws.gis.zoom.resolutions_from_source_layers( 

124 self.sourceLayers, self.cfg('_parentResolutions'), self.mapCrs) 

125 if self.resolutions: 

126 return True 

127 raise gws.Error(f'layer {self!r}: no matching resolutions') 

128 

129 def configure_legend(self): 

130 if super().configure_legend(): 

131 return True 

132 urls = gws.u.compact(sl.legendUrl for sl in self.imageLayers) 

133 if urls: 

134 self.legend = self.create_child(gws.ext.object.legend, type='remote', urls=urls) 

135 return True 

136 

137 def configure_metadata(self): 

138 if super().configure_metadata(): 

139 return True 

140 if len(self.sourceLayers) == 1: 

141 self.metadata = self.sourceLayers[0].metadata 

142 return True 

143 

144 def configure_search(self): 

145 if super().configure_search(): 

146 return True 

147 if self.searchLayers: 

148 self.finders.append(self.create_finder(None)) 

149 return True 

150 

151 def create_finder(self, cfg): 

152 """Create a ``wms`` finder bound to the provider and the queryable source layers of the layer. 

153 

154 Args: 

155 cfg: Finder configuration, or ``None`` for the default finder. 

156 

157 Returns: 

158 The finder object. 

159 """ 

160 return self.create_child( 

161 gws.ext.object.finder, 

162 cfg, 

163 type='wms', 

164 _defaultProvider=self.provider, 

165 _defaultSourceLayers=self.searchLayers 

166 )