MapProxy 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. MapProxy-2.1.0.dist-info/AUTHORS.txt +33 -0
  2. MapProxy-2.1.0.dist-info/COPYING.txt +60 -0
  3. MapProxy-2.1.0.dist-info/LICENSE.txt +202 -0
  4. MapProxy-2.1.0.dist-info/METADATA +165 -0
  5. MapProxy-2.1.0.dist-info/RECORD +459 -0
  6. MapProxy-2.1.0.dist-info/WHEEL +5 -0
  7. MapProxy-2.1.0.dist-info/entry_points.txt +4 -0
  8. MapProxy-2.1.0.dist-info/top_level.txt +1 -0
  9. mapproxy/__init__.py +0 -0
  10. mapproxy/cache/__init__.py +36 -0
  11. mapproxy/cache/azureblob.py +145 -0
  12. mapproxy/cache/base.py +120 -0
  13. mapproxy/cache/compact.py +665 -0
  14. mapproxy/cache/couchdb.py +301 -0
  15. mapproxy/cache/dummy.py +36 -0
  16. mapproxy/cache/file.py +200 -0
  17. mapproxy/cache/geopackage.py +647 -0
  18. mapproxy/cache/legend.py +87 -0
  19. mapproxy/cache/mbtiles.py +411 -0
  20. mapproxy/cache/meta.py +80 -0
  21. mapproxy/cache/path.py +261 -0
  22. mapproxy/cache/redis.py +152 -0
  23. mapproxy/cache/renderd.py +100 -0
  24. mapproxy/cache/riak.py +206 -0
  25. mapproxy/cache/s3.py +209 -0
  26. mapproxy/cache/tile.py +736 -0
  27. mapproxy/client/__init__.py +0 -0
  28. mapproxy/client/arcgis.py +82 -0
  29. mapproxy/client/cgi.py +141 -0
  30. mapproxy/client/http.py +295 -0
  31. mapproxy/client/log.py +33 -0
  32. mapproxy/client/tile.py +158 -0
  33. mapproxy/client/wms.py +255 -0
  34. mapproxy/compat/__init__.py +0 -0
  35. mapproxy/compat/image.py +86 -0
  36. mapproxy/config/__init__.py +22 -0
  37. mapproxy/config/config-schema.json +813 -0
  38. mapproxy/config/config.py +213 -0
  39. mapproxy/config/coverage.py +108 -0
  40. mapproxy/config/defaults.py +102 -0
  41. mapproxy/config/loader.py +2399 -0
  42. mapproxy/config/spec.py +657 -0
  43. mapproxy/config/validator.py +242 -0
  44. mapproxy/config_template/__init__.py +0 -0
  45. mapproxy/config_template/base_config/config.wsgi +10 -0
  46. mapproxy/config_template/base_config/full_example.yaml +598 -0
  47. mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
  48. mapproxy/config_template/base_config/log.ini +35 -0
  49. mapproxy/config_template/base_config/mapproxy.yaml +60 -0
  50. mapproxy/config_template/base_config/seed.yaml +27 -0
  51. mapproxy/exception.py +149 -0
  52. mapproxy/featureinfo.py +251 -0
  53. mapproxy/grid.py +1199 -0
  54. mapproxy/image/__init__.py +549 -0
  55. mapproxy/image/fonts/DejaVuSans.ttf +0 -0
  56. mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
  57. mapproxy/image/fonts/LICENSE +99 -0
  58. mapproxy/image/fonts/__init__.py +0 -0
  59. mapproxy/image/mask.py +79 -0
  60. mapproxy/image/merge.py +323 -0
  61. mapproxy/image/message.py +357 -0
  62. mapproxy/image/opts.py +185 -0
  63. mapproxy/image/tile.py +171 -0
  64. mapproxy/image/transform.py +350 -0
  65. mapproxy/layer.py +489 -0
  66. mapproxy/multiapp.py +230 -0
  67. mapproxy/proj.py +309 -0
  68. mapproxy/request/__init__.py +18 -0
  69. mapproxy/request/arcgis.py +268 -0
  70. mapproxy/request/base.py +466 -0
  71. mapproxy/request/tile.py +131 -0
  72. mapproxy/request/wms/__init__.py +829 -0
  73. mapproxy/request/wms/exception.py +107 -0
  74. mapproxy/request/wmts.py +442 -0
  75. mapproxy/response.py +237 -0
  76. mapproxy/script/__init__.py +0 -0
  77. mapproxy/script/conf/__init__.py +0 -0
  78. mapproxy/script/conf/app.py +222 -0
  79. mapproxy/script/conf/caches.py +44 -0
  80. mapproxy/script/conf/geopackage.py +136 -0
  81. mapproxy/script/conf/layers.py +54 -0
  82. mapproxy/script/conf/seeds.py +36 -0
  83. mapproxy/script/conf/sources.py +88 -0
  84. mapproxy/script/conf/utils.py +148 -0
  85. mapproxy/script/defrag.py +187 -0
  86. mapproxy/script/export.py +337 -0
  87. mapproxy/script/grids.py +198 -0
  88. mapproxy/script/scales.py +134 -0
  89. mapproxy/script/util.py +410 -0
  90. mapproxy/script/wms_capabilities.py +160 -0
  91. mapproxy/seed/__init__.py +0 -0
  92. mapproxy/seed/cachelock.py +127 -0
  93. mapproxy/seed/cleanup.py +191 -0
  94. mapproxy/seed/config.py +481 -0
  95. mapproxy/seed/script.py +391 -0
  96. mapproxy/seed/seeder.py +551 -0
  97. mapproxy/seed/spec.py +66 -0
  98. mapproxy/seed/util.py +266 -0
  99. mapproxy/service/__init__.py +14 -0
  100. mapproxy/service/base.py +45 -0
  101. mapproxy/service/demo.py +364 -0
  102. mapproxy/service/kml.py +333 -0
  103. mapproxy/service/ows.py +39 -0
  104. mapproxy/service/template_helper.py +55 -0
  105. mapproxy/service/templates/demo/capabilities_demo.html +18 -0
  106. mapproxy/service/templates/demo/demo.html +181 -0
  107. mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
  108. mapproxy/service/templates/demo/static/img/blank.gif +0 -0
  109. mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
  110. mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
  111. mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
  112. mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
  113. mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
  114. mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
  115. mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
  116. mapproxy/service/templates/demo/static/logo.png +0 -0
  117. mapproxy/service/templates/demo/static/ol.css +345 -0
  118. mapproxy/service/templates/demo/static/ol.js +4 -0
  119. mapproxy/service/templates/demo/static/proj4.min.js +1 -0
  120. mapproxy/service/templates/demo/static/proj4defs.js +1 -0
  121. mapproxy/service/templates/demo/static/site.css +137 -0
  122. mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
  123. mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
  124. mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
  125. mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
  126. mapproxy/service/templates/demo/static.html +34 -0
  127. mapproxy/service/templates/demo/tms_demo.html +117 -0
  128. mapproxy/service/templates/demo/wms_demo.html +144 -0
  129. mapproxy/service/templates/demo/wmts_demo.html +118 -0
  130. mapproxy/service/templates/tms_capabilities.xml +13 -0
  131. mapproxy/service/templates/tms_exception.xml +4 -0
  132. mapproxy/service/templates/tms_root_resource.xml +7 -0
  133. mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
  134. mapproxy/service/templates/wms100capabilities.xml +112 -0
  135. mapproxy/service/templates/wms100exception.xml +4 -0
  136. mapproxy/service/templates/wms110capabilities.xml +152 -0
  137. mapproxy/service/templates/wms110exception.xml +5 -0
  138. mapproxy/service/templates/wms111capabilities.xml +183 -0
  139. mapproxy/service/templates/wms111exception.xml +5 -0
  140. mapproxy/service/templates/wms130capabilities.xml +326 -0
  141. mapproxy/service/templates/wms130exception.xml +8 -0
  142. mapproxy/service/templates/wmts100capabilities.xml +155 -0
  143. mapproxy/service/templates/wmts100exception.xml +9 -0
  144. mapproxy/service/tile.py +540 -0
  145. mapproxy/service/wms.py +868 -0
  146. mapproxy/service/wmts.py +387 -0
  147. mapproxy/source/__init__.py +83 -0
  148. mapproxy/source/arcgis.py +39 -0
  149. mapproxy/source/error.py +40 -0
  150. mapproxy/source/mapnik.py +262 -0
  151. mapproxy/source/tile.py +97 -0
  152. mapproxy/source/wms.py +273 -0
  153. mapproxy/srs.py +734 -0
  154. mapproxy/template.py +54 -0
  155. mapproxy/test/__init__.py +0 -0
  156. mapproxy/test/conftest.py +8 -0
  157. mapproxy/test/helper.py +255 -0
  158. mapproxy/test/http.py +511 -0
  159. mapproxy/test/image.py +219 -0
  160. mapproxy/test/mocker.py +2291 -0
  161. mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
  162. mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
  163. mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
  164. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
  165. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
  166. mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
  167. mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
  168. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
  169. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
  170. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
  171. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
  172. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
  173. mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
  174. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
  175. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
  176. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
  177. mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
  178. mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
  179. mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
  180. mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
  181. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
  182. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
  183. mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
  184. mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
  185. mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
  186. mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
  187. mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
  188. mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
  189. mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
  190. mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
  191. mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
  192. mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
  193. mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
  194. mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
  195. mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
  196. mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
  197. mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
  198. mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
  199. mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
  200. mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
  201. mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
  202. mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
  203. mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
  204. mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
  205. mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
  206. mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
  207. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
  208. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
  209. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
  210. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
  211. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
  212. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
  213. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
  214. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
  215. mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
  216. mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  217. mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
  218. mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  219. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
  220. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
  221. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
  222. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
  223. mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
  224. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
  225. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
  226. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
  227. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
  228. mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
  229. mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  230. mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
  231. mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  232. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
  233. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
  234. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
  235. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
  236. mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
  237. mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
  238. mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
  239. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
  240. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
  241. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
  242. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
  243. mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
  244. mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
  245. mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
  246. mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
  247. mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
  248. mapproxy/test/schemas/xml.xsd +287 -0
  249. mapproxy/test/system/__init__.py +98 -0
  250. mapproxy/test/system/fixture/arcgis.yaml +57 -0
  251. mapproxy/test/system/fixture/auth.yaml +70 -0
  252. mapproxy/test/system/fixture/cache.mbtiles +0 -0
  253. mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
  254. mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
  255. mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
  256. mapproxy/test/system/fixture/cache_coverage.yaml +84 -0
  257. mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
  258. mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
  259. mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
  260. mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
  261. mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
  262. mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
  263. mapproxy/test/system/fixture/cache_s3.yaml +58 -0
  264. mapproxy/test/system/fixture/cache_source.yaml +81 -0
  265. mapproxy/test/system/fixture/combined_sources.yaml +130 -0
  266. mapproxy/test/system/fixture/coverage.yaml +77 -0
  267. mapproxy/test/system/fixture/demo.yaml +135 -0
  268. mapproxy/test/system/fixture/dimension.yaml +59 -0
  269. mapproxy/test/system/fixture/disable_storage.yaml +25 -0
  270. mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
  271. mapproxy/test/system/fixture/formats.yaml +72 -0
  272. mapproxy/test/system/fixture/inspire.yaml +101 -0
  273. mapproxy/test/system/fixture/inspire_full.yaml +124 -0
  274. mapproxy/test/system/fixture/kml_layer.yaml +66 -0
  275. mapproxy/test/system/fixture/layer.yaml +260 -0
  276. mapproxy/test/system/fixture/layergroups.yaml +57 -0
  277. mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
  278. mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
  279. mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
  280. mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
  281. mapproxy/test/system/fixture/mapserver.yaml +23 -0
  282. mapproxy/test/system/fixture/minimal_cgi.py +16 -0
  283. mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
  284. mapproxy/test/system/fixture/multi_cache_layers.yaml +111 -0
  285. mapproxy/test/system/fixture/multiapp1.yaml +20 -0
  286. mapproxy/test/system/fixture/multiapp2.yaml +19 -0
  287. mapproxy/test/system/fixture/renderd_client.yaml +55 -0
  288. mapproxy/test/system/fixture/scalehints.yaml +70 -0
  289. mapproxy/test/system/fixture/seed.yaml +94 -0
  290. mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
  291. mapproxy/test/system/fixture/seed_old.yaml +12 -0
  292. mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
  293. mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
  294. mapproxy/test/system/fixture/seedonly.yaml +51 -0
  295. mapproxy/test/system/fixture/sld.yaml +35 -0
  296. mapproxy/test/system/fixture/source_errors.yaml +84 -0
  297. mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
  298. mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
  299. mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
  300. mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
  301. mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
  302. mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
  303. mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
  304. mapproxy/test/system/fixture/util_grids.yaml +29 -0
  305. mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
  306. mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
  307. mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
  308. mapproxy/test/system/fixture/watermark.yaml +50 -0
  309. mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
  310. mapproxy/test/system/fixture/wms_versions.yaml +38 -0
  311. mapproxy/test/system/fixture/wmts.yaml +134 -0
  312. mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
  313. mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
  314. mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
  315. mapproxy/test/system/test_arcgis.py +156 -0
  316. mapproxy/test/system/test_auth.py +1133 -0
  317. mapproxy/test/system/test_behind_proxy.py +75 -0
  318. mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
  319. mapproxy/test/system/test_cache_azureblob.py +127 -0
  320. mapproxy/test/system/test_cache_band_merge.py +103 -0
  321. mapproxy/test/system/test_cache_coverage.py +168 -0
  322. mapproxy/test/system/test_cache_geopackage.py +144 -0
  323. mapproxy/test/system/test_cache_grid_names.py +89 -0
  324. mapproxy/test/system/test_cache_mbtiles.py +85 -0
  325. mapproxy/test/system/test_cache_s3.py +115 -0
  326. mapproxy/test/system/test_cache_source.py +146 -0
  327. mapproxy/test/system/test_combined_sources.py +335 -0
  328. mapproxy/test/system/test_coverage.py +140 -0
  329. mapproxy/test/system/test_decorate_img.py +214 -0
  330. mapproxy/test/system/test_demo.py +56 -0
  331. mapproxy/test/system/test_demo_with_extra_service.py +57 -0
  332. mapproxy/test/system/test_dimensions.py +279 -0
  333. mapproxy/test/system/test_disable_storage.py +42 -0
  334. mapproxy/test/system/test_formats.py +219 -0
  335. mapproxy/test/system/test_inspire_vs.py +173 -0
  336. mapproxy/test/system/test_kml.py +264 -0
  337. mapproxy/test/system/test_layergroups.py +160 -0
  338. mapproxy/test/system/test_legendgraphic.py +308 -0
  339. mapproxy/test/system/test_mapnik.py +162 -0
  340. mapproxy/test/system/test_mapserver.py +83 -0
  341. mapproxy/test/system/test_mixed_mode_format.py +201 -0
  342. mapproxy/test/system/test_multi_cache_layers.py +169 -0
  343. mapproxy/test/system/test_multiapp.py +92 -0
  344. mapproxy/test/system/test_refresh.py +206 -0
  345. mapproxy/test/system/test_renderd_client.py +304 -0
  346. mapproxy/test/system/test_response_headers.py +54 -0
  347. mapproxy/test/system/test_scalehints.py +140 -0
  348. mapproxy/test/system/test_seed.py +425 -0
  349. mapproxy/test/system/test_seed_only.py +93 -0
  350. mapproxy/test/system/test_sld.py +120 -0
  351. mapproxy/test/system/test_source_errors.py +377 -0
  352. mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
  353. mapproxy/test/system/test_tms.py +277 -0
  354. mapproxy/test/system/test_tms_origin.py +46 -0
  355. mapproxy/test/system/test_util_conf.py +434 -0
  356. mapproxy/test/system/test_util_export.py +210 -0
  357. mapproxy/test/system/test_util_grids.py +88 -0
  358. mapproxy/test/system/test_util_wms_capabilities.py +182 -0
  359. mapproxy/test/system/test_watermark.py +91 -0
  360. mapproxy/test/system/test_wms.py +1616 -0
  361. mapproxy/test/system/test_wms_srs_extent.py +165 -0
  362. mapproxy/test/system/test_wms_version.py +85 -0
  363. mapproxy/test/system/test_wmsc.py +116 -0
  364. mapproxy/test/system/test_wmts.py +334 -0
  365. mapproxy/test/system/test_wmts_dimensions.py +206 -0
  366. mapproxy/test/system/test_wmts_restful.py +198 -0
  367. mapproxy/test/system/test_xslt_featureinfo.py +423 -0
  368. mapproxy/test/test_http_helper.py +217 -0
  369. mapproxy/test/unit/__init__.py +0 -0
  370. mapproxy/test/unit/epsg +2 -0
  371. mapproxy/test/unit/polygons/polygons.dbf +0 -0
  372. mapproxy/test/unit/polygons/polygons.shp +0 -0
  373. mapproxy/test/unit/polygons/polygons.shx +0 -0
  374. mapproxy/test/unit/test_async.py +242 -0
  375. mapproxy/test/unit/test_auth.py +430 -0
  376. mapproxy/test/unit/test_cache.py +1356 -0
  377. mapproxy/test/unit/test_cache_azureblob.py +97 -0
  378. mapproxy/test/unit/test_cache_compact.py +324 -0
  379. mapproxy/test/unit/test_cache_couchdb.py +118 -0
  380. mapproxy/test/unit/test_cache_geopackage.py +256 -0
  381. mapproxy/test/unit/test_cache_redis.py +123 -0
  382. mapproxy/test/unit/test_cache_riak.py +80 -0
  383. mapproxy/test/unit/test_cache_s3.py +93 -0
  384. mapproxy/test/unit/test_cache_tile.py +477 -0
  385. mapproxy/test/unit/test_client.py +488 -0
  386. mapproxy/test/unit/test_client_arcgis.py +74 -0
  387. mapproxy/test/unit/test_client_cgi.py +140 -0
  388. mapproxy/test/unit/test_collections.py +116 -0
  389. mapproxy/test/unit/test_concat_legends.py +37 -0
  390. mapproxy/test/unit/test_conf_loader.py +1267 -0
  391. mapproxy/test/unit/test_conf_validator.py +427 -0
  392. mapproxy/test/unit/test_config.py +118 -0
  393. mapproxy/test/unit/test_decorate_img.py +185 -0
  394. mapproxy/test/unit/test_exceptions.py +270 -0
  395. mapproxy/test/unit/test_featureinfo.py +313 -0
  396. mapproxy/test/unit/test_file_lock_load.py +49 -0
  397. mapproxy/test/unit/test_geom.py +512 -0
  398. mapproxy/test/unit/test_grid.py +1279 -0
  399. mapproxy/test/unit/test_image.py +1051 -0
  400. mapproxy/test/unit/test_image_mask.py +181 -0
  401. mapproxy/test/unit/test_image_messages.py +209 -0
  402. mapproxy/test/unit/test_image_options.py +160 -0
  403. mapproxy/test/unit/test_isodate.py +118 -0
  404. mapproxy/test/unit/test_multiapp.py +163 -0
  405. mapproxy/test/unit/test_ogr_reader.py +51 -0
  406. mapproxy/test/unit/test_request.py +745 -0
  407. mapproxy/test/unit/test_request_wmts.py +178 -0
  408. mapproxy/test/unit/test_response.py +78 -0
  409. mapproxy/test/unit/test_seed.py +365 -0
  410. mapproxy/test/unit/test_seed_cachelock.py +91 -0
  411. mapproxy/test/unit/test_srs.py +215 -0
  412. mapproxy/test/unit/test_tiled_source.py +122 -0
  413. mapproxy/test/unit/test_tilefilter.py +31 -0
  414. mapproxy/test/unit/test_times.py +25 -0
  415. mapproxy/test/unit/test_timeutils.py +50 -0
  416. mapproxy/test/unit/test_util_conf_utils.py +75 -0
  417. mapproxy/test/unit/test_utils.py +476 -0
  418. mapproxy/test/unit/test_wms_capabilities.py +44 -0
  419. mapproxy/test/unit/test_wms_layer.py +113 -0
  420. mapproxy/test/unit/test_yaml.py +68 -0
  421. mapproxy/tilefilter.py +61 -0
  422. mapproxy/util/__init__.py +0 -0
  423. mapproxy/util/async_.py +229 -0
  424. mapproxy/util/collections.py +134 -0
  425. mapproxy/util/coverage.py +337 -0
  426. mapproxy/util/ext/__init__.py +14 -0
  427. mapproxy/util/ext/dictspec/__init__.py +1 -0
  428. mapproxy/util/ext/dictspec/spec.py +131 -0
  429. mapproxy/util/ext/dictspec/test/__init__.py +0 -0
  430. mapproxy/util/ext/dictspec/test/test_validator.py +278 -0
  431. mapproxy/util/ext/dictspec/validator.py +194 -0
  432. mapproxy/util/ext/local.py +198 -0
  433. mapproxy/util/ext/lockfile.py +140 -0
  434. mapproxy/util/ext/odict.py +321 -0
  435. mapproxy/util/ext/serving.py +491 -0
  436. mapproxy/util/ext/tempita/__init__.py +1093 -0
  437. mapproxy/util/ext/tempita/_looper.py +163 -0
  438. mapproxy/util/ext/tempita/string_utils.py +24 -0
  439. mapproxy/util/ext/wmsparse/__init__.py +3 -0
  440. mapproxy/util/ext/wmsparse/duration.py +600 -0
  441. mapproxy/util/ext/wmsparse/parse.py +307 -0
  442. mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
  443. mapproxy/util/ext/wmsparse/test/test_parse.py +111 -0
  444. mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
  445. mapproxy/util/ext/wmsparse/test/wms-example-111.xml +90 -0
  446. mapproxy/util/ext/wmsparse/test/wms-example-130.xml +120 -0
  447. mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
  448. mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
  449. mapproxy/util/ext/wmsparse/util.py +189 -0
  450. mapproxy/util/fs.py +164 -0
  451. mapproxy/util/geom.py +307 -0
  452. mapproxy/util/lib.py +117 -0
  453. mapproxy/util/lock.py +171 -0
  454. mapproxy/util/ogr.py +247 -0
  455. mapproxy/util/py.py +75 -0
  456. mapproxy/util/times.py +78 -0
  457. mapproxy/util/yaml.py +58 -0
  458. mapproxy/version.py +33 -0
  459. mapproxy/wsgiapp.py +167 -0
@@ -0,0 +1,829 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2010 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """
17
+ Service requests (parsing, handling, etc).
18
+ """
19
+ import codecs
20
+ import re
21
+ from mapproxy.request.wms import exception
22
+ from mapproxy.exception import RequestError
23
+ from mapproxy.srs import SRS, make_lin_transf
24
+ from mapproxy.request.base import RequestParams, BaseRequest, split_mime_type
25
+
26
+
27
+ import logging
28
+ log = logging.getLogger(__name__)
29
+
30
+
31
+ class WMSMapRequestParams(RequestParams):
32
+ """
33
+ This class represents key-value parameters for WMS map requests.
34
+
35
+ All values can be accessed as a property.
36
+ Some properties return processed values. ``size`` returns a tuple of the width
37
+ and height, ``layers`` returns an iterator of all layers, etc.
38
+
39
+ """
40
+
41
+ def _get_layers(self):
42
+ """
43
+ List with all layer names.
44
+ """
45
+ return sum((layers.split(',') for layers in self.params.get_all('layers')), [])
46
+
47
+ def _set_layers(self, layers):
48
+ if isinstance(layers, (list, tuple)):
49
+ layers = ','.join(layers)
50
+ self.params['layers'] = layers
51
+ layers = property(_get_layers, _set_layers)
52
+ del _get_layers
53
+ del _set_layers
54
+
55
+ def _get_bbox(self):
56
+ """
57
+ ``bbox`` as a tuple (minx, miny, maxx, maxy).
58
+ """
59
+ if 'bbox' not in self.params or self.params['bbox'] is None:
60
+ return None
61
+ points = map(float, self.params['bbox'].split(','))
62
+ return tuple(points)
63
+
64
+ def _set_bbox(self, value):
65
+ if value is not None and not isinstance(value, str):
66
+ value = ','.join(str(x) for x in value)
67
+ self['bbox'] = value
68
+ bbox = property(_get_bbox, _set_bbox)
69
+ del _get_bbox
70
+ del _set_bbox
71
+
72
+ def _get_size(self):
73
+ """
74
+ Size of the request in pixel as a tuple (width, height),
75
+ or None if one is missing.
76
+ """
77
+ if 'height' not in self or 'width' not in self:
78
+ return None
79
+ width = int(float(self.params['width'])) # allow float sizes (100.0), but truncate decimals
80
+ height = int(float(self.params['height']))
81
+ return (width, height)
82
+
83
+ def _set_size(self, value):
84
+ self['width'] = str(value[0])
85
+ self['height'] = str(value[1])
86
+ size = property(_get_size, _set_size)
87
+ del _get_size
88
+ del _set_size
89
+
90
+ def _get_srs(self):
91
+ return self.params.get('srs', None)
92
+
93
+ def _set_srs(self, srs):
94
+ if hasattr(srs, 'srs_code'):
95
+ self.params['srs'] = srs.srs_code
96
+ else:
97
+ self.params['srs'] = srs
98
+
99
+ srs = property(_get_srs, _set_srs)
100
+ del _get_srs
101
+ del _set_srs
102
+
103
+ def _get_transparent(self):
104
+ """
105
+ ``True`` if transparent is set to true, otherwise ``False``.
106
+ """
107
+ if self.get('transparent', 'false').lower() == 'true':
108
+ return True
109
+ return False
110
+
111
+ def _set_transparent(self, transparent):
112
+ self.params['transparent'] = str(transparent).lower()
113
+ transparent = property(_get_transparent, _set_transparent)
114
+ del _get_transparent
115
+ del _set_transparent
116
+
117
+ @property
118
+ def bgcolor(self):
119
+ """
120
+ The background color in PIL format (#rrggbb). Defaults to '#ffffff'.
121
+ """
122
+ color = self.get('bgcolor', '0xffffff')
123
+ return '#'+color[2:]
124
+
125
+ def _get_format(self):
126
+ """
127
+ The requested format as string (w/o any 'image/', 'text/', etc prefixes)
128
+ """
129
+ _mime_class, format, options = split_mime_type(self.get('format', default=''))
130
+ return format
131
+
132
+ def _set_format(self, format):
133
+ if '/' not in format:
134
+ format = 'image/' + format
135
+ self['format'] = format
136
+
137
+ format = property(_get_format, _set_format)
138
+ del _get_format
139
+ del _set_format
140
+
141
+ @property
142
+ def format_mime_type(self):
143
+ return self.get('format')
144
+
145
+ def __repr__(self):
146
+ return '%s(param=%r)' % (self.__class__.__name__, self.params)
147
+
148
+
149
+ class WMSRequest(BaseRequest):
150
+ request_params = RequestParams
151
+ request_handler_name = None
152
+ fixed_params = {}
153
+ expected_param = []
154
+ non_strict_params = set()
155
+ xml_exception_handler = None
156
+
157
+ def __init__(self, param=None, url='', validate=False, non_strict=False, **kw):
158
+ self.non_strict = non_strict
159
+ BaseRequest.__init__(self, param=param, url=url, validate=validate, **kw)
160
+ self.adapt_to_111()
161
+
162
+ def adapt_to_111(self):
163
+ pass
164
+
165
+ def adapt_params_to_version(self):
166
+ params = self.params.copy()
167
+ for key, value in self.fixed_params.items():
168
+ params[key] = value
169
+ if 'styles' not in params:
170
+ params['styles'] = ''
171
+ return params
172
+
173
+ @property
174
+ def query_string(self):
175
+ return self.adapt_params_to_version().query_string
176
+
177
+
178
+ class WMSMapRequest(WMSRequest):
179
+ """
180
+ Base class for all WMS GetMap requests.
181
+
182
+ :ivar requests: the ``RequestParams`` class for this request
183
+ :ivar request_handler_name: the name of the server handler
184
+ :ivar fixed_params: parameters that are fixed for a request
185
+ :ivar expected_param: required parameters, used for validating
186
+ """
187
+ request_params = WMSMapRequestParams
188
+ request_handler_name = 'map'
189
+ fixed_params = {'request': 'GetMap', 'service': 'WMS'}
190
+ expected_param = ['version', 'request', 'layers', 'styles', 'srs', 'bbox',
191
+ 'width', 'height', 'format']
192
+ xml_exception_handler = None
193
+ prevent_image_exception = False
194
+ dimension_params = ['time', 'elevation']
195
+ dimension_prefix = 'dim_'
196
+
197
+ def __init__(self, param=None, url='', validate=False, non_strict=False, **kw):
198
+ self.dimensions = self._get_dimensions(param)
199
+ WMSRequest.__init__(self, param=param, url=url, validate=validate,
200
+ non_strict=non_strict, **kw)
201
+
202
+ def _get_dimensions(self, param):
203
+ if param:
204
+ regex = "(?i)%s%s" % (("^%s|" % self.dimension_prefix if self.dimension_prefix else ""),
205
+ "^(%s)$" % "|".join(self.dimension_params))
206
+ keys = []
207
+ if isinstance(param, RequestParams):
208
+ keys = list(map(lambda k: k[0], param.iteritems()))
209
+ else:
210
+ keys = list(param.keys())
211
+ if len(keys) > 0:
212
+ return dict(map(lambda k: (k, param.get(k)), filter(lambda k: re.search(regex, k), keys)))
213
+ else:
214
+ return None
215
+ else:
216
+ return None
217
+
218
+ def validate(self):
219
+ self.validate_param()
220
+ self.validate_bbox()
221
+ self.validate_styles()
222
+
223
+ def validate_param(self):
224
+ missing_param = []
225
+ for param in self.expected_param:
226
+ if self.non_strict and param in self.non_strict_params:
227
+ continue
228
+ if param not in self.params:
229
+ missing_param.append(param)
230
+
231
+ if missing_param:
232
+ if 'format' in missing_param:
233
+ self.params['format'] = 'image/png'
234
+ raise RequestError('missing parameters ' + str(missing_param),
235
+ request=self)
236
+
237
+ def validate_bbox(self):
238
+ x0, y0, x1, y1 = self.params.bbox
239
+ if x0 >= x1 or y0 >= y1:
240
+ raise RequestError('invalid bbox ' + self.params.get('bbox', None),
241
+ request=self)
242
+
243
+ def validate_format(self, image_formats):
244
+ format = self.params['format']
245
+ if format not in image_formats:
246
+ format = self.params['format']
247
+ self.params['format'] = 'image/png'
248
+ raise RequestError('unsupported image format: ' + format,
249
+ code='InvalidFormat', request=self)
250
+
251
+ def validate_srs(self, srs):
252
+ if self.params['srs'].upper() not in srs:
253
+ raise RequestError('unsupported srs: ' + self.params['srs'],
254
+ code='InvalidSRS', request=self)
255
+
256
+ def validate_styles(self):
257
+ if 'styles' in self.params:
258
+ styles = self.params['styles']
259
+ if not set(styles.split(',')).issubset(set(['default', '', 'inspire_common:DEFAULT'])):
260
+ raise RequestError('unsupported styles: ' + self.params['styles'],
261
+ code='StyleNotDefined', request=self)
262
+
263
+ @property
264
+ def exception_handler(self):
265
+ if self.prevent_image_exception:
266
+ return self.xml_exception_handler()
267
+ if 'exceptions' in self.params:
268
+ if 'image' in self.params['exceptions'].lower():
269
+ return exception.WMSImageExceptionHandler()
270
+ elif 'blank' in self.params['exceptions'].lower():
271
+ return exception.WMSBlankExceptionHandler()
272
+ return self.xml_exception_handler()
273
+
274
+ def copy(self):
275
+ return self.__class__(param=self.params.copy(), url=self.url)
276
+
277
+
278
+ class Version(object):
279
+ _versions = {}
280
+
281
+ def __new__(cls, version):
282
+ if version in cls._versions:
283
+ return cls._versions[version]
284
+ version_obj = object.__new__(cls)
285
+ version_obj.__init__(version)
286
+ cls._versions[version] = version_obj
287
+ return version_obj
288
+
289
+ def __init__(self, version):
290
+ self.parts = tuple(int(x) for x in version.split('.'))
291
+
292
+ def __lt__(self, other):
293
+ if not isinstance(other, Version):
294
+ return NotImplemented
295
+ return self.parts < other.parts
296
+
297
+ def __ge__(self, other):
298
+ if not isinstance(other, Version):
299
+ return NotImplemented
300
+ return self.parts >= other.parts
301
+
302
+ def __repr__(self):
303
+ return "Version('%s')" % ('.'.join(str(part) for part in self.parts),)
304
+
305
+
306
+ class WMS100MapRequest(WMSMapRequest):
307
+ version = Version('1.0.0')
308
+ xml_exception_handler = exception.WMS100ExceptionHandler
309
+ fixed_params = {'request': 'map', 'wmtver': '1.0.0'}
310
+ expected_param = ['wmtver', 'request', 'layers', 'styles', 'srs', 'bbox',
311
+ 'width', 'height', 'format']
312
+ dimension_params = []
313
+ dimension_prefix = ''
314
+
315
+ def adapt_to_111(self):
316
+ del self.params['wmtver']
317
+ self.params['version'] = '1.0.0'
318
+ self.params['request'] = 'GetMap'
319
+
320
+ def adapt_params_to_version(self):
321
+ params = WMSMapRequest.adapt_params_to_version(self)
322
+ del params['version']
323
+ del params['service']
324
+
325
+ image_format = params['format']
326
+ if '/' in image_format:
327
+ params['format'] = image_format.split('/', 1)[1].upper()
328
+ return params
329
+
330
+ def validate_format(self, image_formats):
331
+ format = self.params['format']
332
+ image_formats100 = [f.split('/', 1)[1].upper() for f in image_formats]
333
+
334
+ if format in image_formats100:
335
+ format = 'image/' + format.lower()
336
+ self.params['format'] = format
337
+
338
+ if format not in image_formats:
339
+ format = self.params['format']
340
+ self.params['format'] = 'image/png'
341
+ raise RequestError('unsupported image format: ' + format,
342
+ code='InvalidFormat', request=self)
343
+
344
+
345
+ class WMS110MapRequest(WMSMapRequest):
346
+ version = Version('1.1.0')
347
+ fixed_params = {'request': 'GetMap', 'version': '1.1.0', 'service': 'WMS'}
348
+ xml_exception_handler = exception.WMS110ExceptionHandler
349
+
350
+ def adapt_to_111(self):
351
+ del self.params['wmtver']
352
+
353
+
354
+ class WMS111MapRequest(WMSMapRequest):
355
+ version = Version('1.1.1')
356
+ fixed_params = {'request': 'GetMap', 'version': '1.1.1', 'service': 'WMS'}
357
+ xml_exception_handler = exception.WMS111ExceptionHandler
358
+
359
+ def adapt_to_111(self):
360
+ del self.params['wmtver']
361
+
362
+
363
+ def switch_bbox_epsg_axis_order(bbox, srs):
364
+ if bbox is not None and srs is not None:
365
+ try:
366
+ if SRS(srs).is_axis_order_ne:
367
+ return bbox[1], bbox[0], bbox[3], bbox[2]
368
+ except RuntimeError:
369
+ log.warning('unknown SRS %s' % srs)
370
+ return bbox
371
+
372
+
373
+ def _switch_bbox(self):
374
+ self.bbox = switch_bbox_epsg_axis_order(self.bbox, self.srs)
375
+
376
+
377
+ class WMS130MapRequestParams(WMSMapRequestParams):
378
+ """
379
+ RequestParams for WMS 1.3.0 GetMap requests. Handles bbox axis-order.
380
+ """
381
+ switch_bbox = _switch_bbox
382
+
383
+
384
+ class WMS130MapRequest(WMSMapRequest):
385
+ version = Version('1.3.0')
386
+ request_params = WMS130MapRequestParams
387
+ xml_exception_handler = exception.WMS130ExceptionHandler
388
+ fixed_params = {'request': 'GetMap', 'version': '1.3.0', 'service': 'WMS'}
389
+ expected_param = ['version', 'request', 'layers', 'styles', 'crs', 'bbox',
390
+ 'width', 'height', 'format']
391
+
392
+ def adapt_to_111(self):
393
+ del self.params['wmtver']
394
+ if 'crs' in self.params:
395
+ self.params['srs'] = self.params['crs']
396
+ del self.params['crs']
397
+ self.params.switch_bbox()
398
+
399
+ def adapt_params_to_version(self):
400
+ params = WMSMapRequest.adapt_params_to_version(self)
401
+ params.switch_bbox()
402
+ if 'srs' in params:
403
+ params['crs'] = params['srs']
404
+ del params['srs']
405
+ return params
406
+
407
+ def validate_srs(self, srs):
408
+ # its called crs in 1.3.0 and we validate before adapt_to_111
409
+ if self.params['srs'].upper() not in srs:
410
+ raise RequestError('unsupported crs: ' + self.params['srs'],
411
+ code='InvalidCRS', request=self)
412
+
413
+ def copy_with_request_params(self, req):
414
+ new_req = WMSMapRequest.copy_with_request_params(self, req)
415
+ new_req.params.switch_bbox()
416
+ return new_req
417
+
418
+
419
+ class WMSLegendGraphicRequestParams(WMSMapRequestParams):
420
+ """
421
+ RequestParams for WMS GetLegendGraphic requests.
422
+ """
423
+
424
+ def _set_layer(self, value):
425
+ self.params['layer'] = value
426
+
427
+ def _get_layer(self):
428
+ """
429
+ Layer for which to produce legend graphic.
430
+ """
431
+ return self.params.get('layer')
432
+ layer = property(_get_layer, _set_layer)
433
+ del _set_layer
434
+ del _get_layer
435
+
436
+ @property
437
+ def sld_version(self):
438
+ """
439
+ Specification version for SLD-specification
440
+ """
441
+ return self.params.get('sld_version')
442
+
443
+ def _set_scale(self, value):
444
+ self.params['scale'] = value
445
+
446
+ def _get_scale(self):
447
+ if self.params.get('scale') is not None:
448
+ return float(self['scale'])
449
+ return None
450
+
451
+ scale = property(_get_scale, _set_scale)
452
+ del _set_scale
453
+ del _get_scale
454
+
455
+
456
+ class WMSFeatureInfoRequestParams(WMSMapRequestParams):
457
+ """
458
+ RequestParams for WMS GetFeatureInfo requests.
459
+ """
460
+ @property
461
+ def query_layers(self):
462
+ """
463
+ List with all query_layers.
464
+ """
465
+ return sum((layers.split(',') for layers in self.params.get_all('query_layers')), [])
466
+
467
+ def _get_pos(self):
468
+ """x, y query image coordinates (in pixel)"""
469
+ if '.' in self['x'] or '.' in self['y']:
470
+ return float(self['x']), float(self['y'])
471
+ return int(self['x']), int(self['y'])
472
+
473
+ def _set_pos(self, value):
474
+ self['x'] = str(value[0])
475
+ self['y'] = str(value[1])
476
+ pos = property(_get_pos, _set_pos)
477
+ del _get_pos
478
+ del _set_pos
479
+
480
+ @property
481
+ def pos_coords(self):
482
+ """x, y query coordinates (in request SRS)"""
483
+ width, height = self.size
484
+ bbox = self.bbox
485
+ return make_lin_transf((0, 0, width, height), bbox)(self.pos)
486
+
487
+
488
+ class WMS130FeatureInfoRequestParams(WMSFeatureInfoRequestParams):
489
+ switch_bbox = _switch_bbox
490
+
491
+
492
+ class WMSLegendGraphicRequest(WMSMapRequest):
493
+ request_params = WMSLegendGraphicRequestParams
494
+ request_handler_name = 'legendgraphic'
495
+ non_strict_params = set(['sld_version', 'scale'])
496
+ fixed_params = {'request': 'GetLegendGraphic', 'service': 'WMS', 'sld_version': '1.1.0'}
497
+ expected_param = ['version', 'request', 'layer', 'format', 'sld_version']
498
+
499
+ def validate(self):
500
+ self.validate_param()
501
+ self.validate_sld_version()
502
+
503
+ def validate_sld_version(self):
504
+ if self.params.get('sld_version', '1.1.0') != '1.1.0':
505
+ raise RequestError('invalid sld_version ' + self.params.get('sld_version'),
506
+ request=self)
507
+
508
+
509
+ class WMS111LegendGraphicRequest(WMSLegendGraphicRequest):
510
+ version = Version('1.1.1')
511
+ fixed_params = WMSLegendGraphicRequest.fixed_params.copy()
512
+ fixed_params['version'] = '1.1.1'
513
+ xml_exception_handler = exception.WMS111ExceptionHandler
514
+
515
+
516
+ class WMS130LegendGraphicRequest(WMSLegendGraphicRequest):
517
+ version = Version('1.3.0')
518
+ fixed_params = WMSLegendGraphicRequest.fixed_params.copy()
519
+ fixed_params['version'] = '1.3.0'
520
+ xml_exception_handler = exception.WMS130ExceptionHandler
521
+
522
+
523
+ class WMSFeatureInfoRequest(WMSMapRequest):
524
+ non_strict_params = set(['format', 'styles'])
525
+
526
+ def validate_format(self, image_formats):
527
+ if self.non_strict:
528
+ return
529
+ WMSMapRequest.validate_format(self, image_formats)
530
+
531
+
532
+ class WMS111FeatureInfoRequest(WMSFeatureInfoRequest):
533
+ version = Version('1.1.1')
534
+ request_params = WMSFeatureInfoRequestParams
535
+ xml_exception_handler = exception.WMS111ExceptionHandler
536
+ request_handler_name = 'featureinfo'
537
+ fixed_params = WMS111MapRequest.fixed_params.copy()
538
+ fixed_params['request'] = 'GetFeatureInfo'
539
+ expected_param = WMSMapRequest.expected_param[:] + ['query_layers', 'x', 'y']
540
+
541
+
542
+ class WMS110FeatureInfoRequest(WMSFeatureInfoRequest):
543
+ version = Version('1.1.0')
544
+ request_params = WMSFeatureInfoRequestParams
545
+ xml_exception_handler = exception.WMS110ExceptionHandler
546
+ request_handler_name = 'featureinfo'
547
+ fixed_params = WMS110MapRequest.fixed_params.copy()
548
+ fixed_params['request'] = 'GetFeatureInfo'
549
+ expected_param = WMSMapRequest.expected_param[:] + ['query_layers', 'x', 'y']
550
+
551
+
552
+ class WMS100FeatureInfoRequest(WMSFeatureInfoRequest):
553
+ version = Version('1.0.0')
554
+ request_params = WMSFeatureInfoRequestParams
555
+ xml_exception_handler = exception.WMS100ExceptionHandler
556
+ request_handler_name = 'featureinfo'
557
+ fixed_params = WMS100MapRequest.fixed_params.copy()
558
+ fixed_params['request'] = 'feature_info'
559
+ expected_param = WMS100MapRequest.expected_param[:] + ['query_layers', 'x', 'y']
560
+
561
+ def adapt_to_111(self):
562
+ del self.params['wmtver']
563
+
564
+ def adapt_params_to_version(self):
565
+ params = WMSMapRequest.adapt_params_to_version(self)
566
+ del params['version']
567
+ return params
568
+
569
+
570
+ class WMS130FeatureInfoRequest(WMS130MapRequest):
571
+ # XXX: this class inherits from WMS130MapRequest to reuse
572
+ # the axis order stuff
573
+ version = Version('1.3.0')
574
+ request_params = WMS130FeatureInfoRequestParams
575
+ xml_exception_handler = exception.WMS130ExceptionHandler
576
+ request_handler_name = 'featureinfo'
577
+ fixed_params = WMS130MapRequest.fixed_params.copy()
578
+ fixed_params['request'] = 'GetFeatureInfo'
579
+ expected_param = WMS130MapRequest.expected_param[:] + ['query_layers', 'i', 'j']
580
+ non_strict_params = set(['format', 'styles'])
581
+
582
+ def adapt_to_111(self):
583
+ WMS130MapRequest.adapt_to_111(self)
584
+ # only set x,y when present,
585
+ # avoids empty values for request templates
586
+ if 'i' in self.params:
587
+ self.params['x'] = self.params['i']
588
+ if 'j' in self.params:
589
+ self.params['y'] = self.params['j']
590
+ del self.params['i']
591
+ del self.params['j']
592
+
593
+ def adapt_params_to_version(self):
594
+ params = WMS130MapRequest.adapt_params_to_version(self)
595
+ params['i'] = self.params['x']
596
+ params['j'] = self.params['y']
597
+ del params['x']
598
+ del params['y']
599
+ return params
600
+
601
+ def validate_format(self, image_formats):
602
+ if self.non_strict:
603
+ return
604
+ WMSMapRequest.validate_format(self, image_formats)
605
+
606
+
607
+ class WMSCapabilitiesRequest(WMSRequest):
608
+ request_handler_name = 'capabilities'
609
+ exception_handler = None
610
+ mime_type = 'text/xml'
611
+ fixed_params = {}
612
+
613
+ def __init__(self, param=None, url='', validate=False, non_strict=False, **kw):
614
+ WMSRequest.__init__(self, param=param, url=url, validate=validate, **kw)
615
+
616
+ def adapt_to_111(self):
617
+ pass
618
+
619
+ def validate(self):
620
+ pass
621
+
622
+
623
+ class WMS100CapabilitiesRequest(WMSCapabilitiesRequest):
624
+ version = Version('1.0.0')
625
+ capabilities_template = 'wms100capabilities.xml'
626
+ fixed_params = {'request': 'capabilities', 'wmtver': '1.0.0'}
627
+
628
+ @property
629
+ def exception_handler(self):
630
+ return exception.WMS100ExceptionHandler()
631
+
632
+
633
+ class WMS110CapabilitiesRequest(WMSCapabilitiesRequest):
634
+ version = Version('1.1.0')
635
+ capabilities_template = 'wms110capabilities.xml'
636
+ mime_type = 'application/vnd.ogc.wms_xml'
637
+ fixed_params = {'request': 'GetCapabilities', 'version': '1.1.0', 'service': 'WMS'}
638
+
639
+ @property
640
+ def exception_handler(self):
641
+ return exception.WMS110ExceptionHandler()
642
+
643
+
644
+ class WMS111CapabilitiesRequest(WMSCapabilitiesRequest):
645
+ version = Version('1.1.1')
646
+ capabilities_template = 'wms111capabilities.xml'
647
+ mime_type = 'application/vnd.ogc.wms_xml'
648
+ fixed_params = {'request': 'GetCapabilities', 'version': '1.1.1', 'service': 'WMS'}
649
+
650
+ @property
651
+ def exception_handler(self):
652
+ return exception.WMS111ExceptionHandler()
653
+
654
+
655
+ class WMS130CapabilitiesRequest(WMSCapabilitiesRequest):
656
+ version = Version('1.3.0')
657
+ capabilities_template = 'wms130capabilities.xml'
658
+ fixed_params = {'request': 'GetCapabilities', 'version': '1.3.0', 'service': 'WMS'}
659
+
660
+ @property
661
+ def exception_handler(self):
662
+ return exception.WMS130ExceptionHandler()
663
+
664
+
665
+ request_mapping = {Version('1.0.0'): {'featureinfo': WMS100FeatureInfoRequest,
666
+ 'map': WMS100MapRequest,
667
+ 'capabilities': WMS100CapabilitiesRequest},
668
+ Version('1.1.0'): {'featureinfo': WMS110FeatureInfoRequest,
669
+ 'map': WMS110MapRequest,
670
+ 'capabilities': WMS110CapabilitiesRequest},
671
+ Version('1.1.1'): {'featureinfo': WMS111FeatureInfoRequest,
672
+ 'map': WMS111MapRequest,
673
+ 'capabilities': WMS111CapabilitiesRequest,
674
+ 'legendgraphic': WMS111LegendGraphicRequest},
675
+ Version('1.3.0'): {'featureinfo': WMS130FeatureInfoRequest,
676
+ 'map': WMS130MapRequest,
677
+ 'capabilities': WMS130CapabilitiesRequest,
678
+ 'legendgraphic': WMS130LegendGraphicRequest},
679
+ }
680
+
681
+
682
+ def _parse_version(req):
683
+ if 'version' in req.args:
684
+ return Version(req.args['version'])
685
+ if 'wmtver' in req.args:
686
+ return Version(req.args['wmtver'])
687
+
688
+ return None
689
+
690
+
691
+ def _parse_request_type(req):
692
+ if 'request' in req.args:
693
+ request_type = req.args['request'].lower()
694
+ if request_type in ('getmap', 'map'):
695
+ return 'map'
696
+ elif request_type in ('getfeatureinfo', 'feature_info'):
697
+ return 'featureinfo'
698
+ elif request_type in ('getcapabilities', 'capabilities'):
699
+ return 'capabilities'
700
+ elif request_type in ('getlegendgraphic',):
701
+ return 'legendgraphic'
702
+ else:
703
+ return request_type
704
+ else:
705
+ return None
706
+
707
+
708
+ def negotiate_version(version, supported_versions=None):
709
+ """
710
+ >>> negotiate_version(Version('0.9.0'))
711
+ Version('1.0.0')
712
+ >>> negotiate_version(Version('2.0.0'))
713
+ Version('1.3.0')
714
+ >>> negotiate_version(Version('1.1.1'))
715
+ Version('1.1.1')
716
+ >>> negotiate_version(Version('1.1.0'))
717
+ Version('1.1.0')
718
+ >>> negotiate_version(Version('1.1.0'), [Version('1.0.0')])
719
+ Version('1.0.0')
720
+ >>> negotiate_version(Version('1.3.0'), sorted([Version('1.1.0'), Version('1.1.1')]))
721
+ Version('1.1.1')
722
+ """
723
+ if not supported_versions:
724
+ supported_versions = list(request_mapping.keys())
725
+ supported_versions.sort()
726
+
727
+ if version < supported_versions[0]:
728
+ return supported_versions[0] # smallest version we support
729
+
730
+ if version > supported_versions[-1]:
731
+ return supported_versions[-1] # highest version we support
732
+
733
+ while True:
734
+ next_highest_version = supported_versions.pop()
735
+ if version >= next_highest_version:
736
+ return next_highest_version
737
+
738
+
739
+ def wms_request(req, validate=True, strict=True, versions=None):
740
+ version = _parse_version(req)
741
+ req_type = _parse_request_type(req)
742
+
743
+ if versions is None:
744
+ versions = sorted([
745
+ Version(v) for v in ('1.0.0', '1.1.0', '1.1.1', '1.3.0')])
746
+
747
+ if version is None:
748
+ # If no version number is specified in the request,
749
+ # the server shall respond with the highest version.
750
+ version = max(versions)
751
+
752
+ if version not in versions:
753
+ version_requests = None
754
+ else:
755
+ version_requests = request_mapping.get(version, None)
756
+
757
+ if version_requests is None:
758
+ negotiated_version = negotiate_version(version, supported_versions=versions)
759
+ version_requests = request_mapping[negotiated_version]
760
+ req_class = version_requests.get(req_type, None)
761
+ if req_class is None:
762
+ # use map request to get an exception handler for the requested version
763
+ dummy_req = version_requests['map'](param=req.args, url=req.base_url,
764
+ validate=False)
765
+ raise RequestError("unknown WMS request type '%s'" % req_type, request=dummy_req)
766
+ return req_class(param=req.args, url=req.base_url, validate=True,
767
+ non_strict=not strict, http=req)
768
+
769
+
770
+ def create_request(req_data, param, req_type='map', version='1.1.1', abspath=None):
771
+ url = req_data['url']
772
+ req_data = req_data.copy()
773
+ del req_data['url']
774
+ if 'request_format' in param:
775
+ req_data['format'] = param['request_format']
776
+ elif 'format' in param:
777
+ req_data['format'] = param['format']
778
+
779
+ if 'info_format' in param:
780
+ req_data['info_format'] = param['info_format']
781
+
782
+ if 'transparent' in req_data:
783
+ # we don't want a boolean
784
+ req_data['transparent'] = str(req_data['transparent'])
785
+
786
+ if req_data.get('sld', '').startswith('file://'):
787
+ sld_path = req_data['sld'][len('file://'):]
788
+ if abspath:
789
+ sld_path = abspath(sld_path)
790
+ with codecs.open(sld_path, 'r', 'utf-8') as f:
791
+ req_data['sld_body'] = f.read()
792
+ del req_data['sld']
793
+
794
+ return request_mapping[Version(version)][req_type](url=url, param=req_data)
795
+
796
+
797
+ info_formats = {
798
+ Version('1.3.0'): (('text', 'text/plain'),
799
+ ('html', 'text/html'),
800
+ ('xml', 'text/xml'),
801
+ ('json', 'application/json'),
802
+ ),
803
+ None: (('text', 'text/plain'),
804
+ ('html', 'text/html'),
805
+ ('xml', 'application/vnd.ogc.gml'),
806
+ ('json', 'application/json'),
807
+ )
808
+ }
809
+
810
+
811
+ def infotype_from_mimetype(version, mime_type):
812
+ if version in info_formats:
813
+ formats = info_formats[version]
814
+ else:
815
+ formats = info_formats[None] # default
816
+ for t, m in formats:
817
+ if m == mime_type:
818
+ return t
819
+
820
+
821
+ def mimetype_from_infotype(version, info_type):
822
+ if version in info_formats:
823
+ formats = info_formats[version]
824
+ else:
825
+ formats = info_formats[None] # default
826
+ for t, m in formats:
827
+ if t == info_type:
828
+ return m
829
+ return 'text/plain'