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
mapproxy/seed/util.py ADDED
@@ -0,0 +1,266 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2010, 2011 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
+ from __future__ import print_function, division
17
+
18
+ import os
19
+ import sys
20
+ import stat
21
+ import math
22
+ import time
23
+ from datetime import datetime
24
+
25
+ try:
26
+ import cPickle as pickle
27
+ except ImportError:
28
+ import pickle
29
+
30
+ from mapproxy.layer import map_extent_from_grid
31
+ from mapproxy.util.fs import write_atomic
32
+
33
+ import logging
34
+ log = logging.getLogger(__name__)
35
+
36
+
37
+ class bidict(dict):
38
+ """
39
+ Simplest bi-directional dictionary.
40
+ """
41
+
42
+ def __init__(self, iterator):
43
+ for key, val in iterator:
44
+ dict.__setitem__(self, key, val)
45
+ dict.__setitem__(self, val, key)
46
+
47
+
48
+ class ProgressStore(object):
49
+ """
50
+ Reads and stores seed progresses to a file.
51
+ """
52
+
53
+ def __init__(self, filename=None, continue_seed=True):
54
+ self.filename = filename
55
+ if continue_seed:
56
+ self.status = self.load()
57
+ else:
58
+ self.status = {}
59
+
60
+ def load(self):
61
+ if not os.path.exists(self.filename):
62
+ pass
63
+ elif os.stat(self.filename).st_mode & stat.S_IWOTH:
64
+ log.error('progress file (%s) is world writable, ignoring file',
65
+ self.filename)
66
+ else:
67
+ with open(self.filename, 'rb') as f:
68
+ try:
69
+ return pickle.load(f)
70
+ except (pickle.UnpicklingError, AttributeError,
71
+ EOFError, ImportError, IndexError):
72
+ log.error('unable to read progress file (%s), ignoring file',
73
+ self.filename)
74
+
75
+ return {}
76
+
77
+ def write(self):
78
+ try:
79
+ write_atomic(self.filename, pickle.dumps(self.status))
80
+ except (IOError, OSError) as ex:
81
+ log.error('unable to write seed progress: %s', ex)
82
+
83
+ def remove(self):
84
+ self.status = {}
85
+ if os.path.exists(self.filename):
86
+ os.remove(self.filename)
87
+
88
+ def get(self, task_identifier):
89
+ return self.status.get(task_identifier, None)
90
+
91
+ def add(self, task_identifier, progress_identifier):
92
+ self.status[task_identifier] = progress_identifier
93
+
94
+
95
+ class ProgressLog(object):
96
+ def __init__(self, out=None, silent=False, verbose=True, progress_store=None):
97
+ if not out:
98
+ out = sys.stdout
99
+ self.out = out
100
+ self._laststep = time.time()
101
+ self._lastprogress = 0
102
+
103
+ self.verbose = verbose
104
+ self.silent = silent
105
+ self.current_task_id = None
106
+ self.progress_store = progress_store
107
+
108
+ def log_message(self, msg):
109
+ self.out.write('[%s] %s\n' % (
110
+ timestamp(), msg,
111
+ ))
112
+ self.out.flush()
113
+
114
+ def log_step(self, progress):
115
+ if not self.verbose:
116
+ return
117
+ if (self._laststep + .5) < time.time():
118
+ # log progress at most every 500ms
119
+ self.out.write('[%s] %6.2f%%\t%-20s \r' % (
120
+ timestamp(), progress.progress*100, progress.progress_str,
121
+ ))
122
+ self.out.flush()
123
+ self._laststep = time.time()
124
+
125
+ def log_progress(self, progress, level, bbox, tiles):
126
+ progress_interval = 1
127
+ if not self.verbose:
128
+ progress_interval = 30
129
+
130
+ log_progess = False
131
+ if progress.progress == 1.0 or (self._lastprogress + progress_interval) < time.time():
132
+ self._lastprogress = time.time()
133
+ log_progess = True
134
+
135
+ if log_progess:
136
+ if self.progress_store and self.current_task_id:
137
+ self.progress_store.add(self.current_task_id,
138
+ progress.current_progress_identifier())
139
+ self.progress_store.write()
140
+
141
+ if self.silent:
142
+ return
143
+
144
+ if log_progess:
145
+ self.out.write('[%s] %2s %6.2f%% %s (%d tiles)\n' % (
146
+ timestamp(), level, progress.progress*100,
147
+ format_bbox(bbox), tiles))
148
+ self.out.flush()
149
+
150
+
151
+ def limit_sub_bbox(bbox, sub_bbox):
152
+ """
153
+ >>> limit_sub_bbox((0, 1, 10, 11), (-1, -1, 9, 8))
154
+ (0, 1, 9, 8)
155
+ >>> limit_sub_bbox((0, 0, 10, 10), (5, 2, 18, 18))
156
+ (5, 2, 10, 10)
157
+ """
158
+ minx = max(bbox[0], sub_bbox[0])
159
+ miny = max(bbox[1], sub_bbox[1])
160
+ maxx = min(bbox[2], sub_bbox[2])
161
+ maxy = min(bbox[3], sub_bbox[3])
162
+ return minx, miny, maxx, maxy
163
+
164
+
165
+ def timestamp():
166
+ return datetime.now().strftime('%H:%M:%S')
167
+
168
+
169
+ def format_bbox(bbox):
170
+ return ('%.5f, %.5f, %.5f, %.5f') % tuple(bbox)
171
+
172
+
173
+ def status_symbol(i, total):
174
+ """
175
+ >>> status_symbol(0, 1)
176
+ '0'
177
+ >>> [status_symbol(i, 4) for i in range(5)]
178
+ ['.', 'o', 'O', '0', 'X']
179
+ >>> [status_symbol(i, 10) for i in range(11)]
180
+ ['.', '.', 'o', 'o', 'o', 'O', 'O', '0', '0', '0', 'X']
181
+ """
182
+ symbols = list(' .oO0')
183
+ i += 1
184
+ if 0 < i > total:
185
+ return 'X'
186
+ else:
187
+ return symbols[int(math.ceil(i/(total/4)))]
188
+
189
+
190
+ class BackoffError(Exception):
191
+ pass
192
+
193
+
194
+ def exp_backoff(func, args=(), kw={}, max_repeat=10, start_backoff_sec=2,
195
+ exceptions=(Exception,), ignore_exceptions=tuple(), max_backoff=60):
196
+ n = 0
197
+ while True:
198
+ try:
199
+ result = func(*args, **kw)
200
+ except ignore_exceptions:
201
+ time.sleep(0.01)
202
+ except exceptions as ex:
203
+ if n >= max_repeat:
204
+ print("An error occured. Giving up", file=sys.stderr)
205
+ raise BackoffError
206
+ wait_for = start_backoff_sec * 2**n
207
+ if wait_for > max_backoff:
208
+ wait_for = max_backoff
209
+ print("An error occured. Retry in %d seconds: %r. Retries left: %d" %
210
+ (wait_for, ex, (max_repeat - n)), file=sys.stderr)
211
+ time.sleep(wait_for)
212
+ n += 1
213
+ else:
214
+ return result
215
+
216
+
217
+ def format_seed_task(task):
218
+ info = []
219
+ info.append(' %s:' % (task.md['name'], ))
220
+ if task.coverage is False:
221
+ info.append(" Empty coverage given for this task")
222
+ info.append(" Skipped")
223
+ return '\n'.join(info)
224
+
225
+ info.append(" Seeding cache '%s' with grid '%s' in %s" % (
226
+ task.md['cache_name'], task.md['grid_name'], task.grid.srs.srs_code))
227
+ if task.coverage:
228
+ info.append(' Limited to coverage in: %s (EPSG:4326)' % (format_bbox(task.coverage.extent.llbbox), ))
229
+ else:
230
+ info.append(' Complete grid: %s (EPSG:4326)' % (format_bbox(map_extent_from_grid(task.grid).llbbox), ))
231
+ info.append(' Levels: %s' % (task.levels, ))
232
+
233
+ if task.refresh_timestamp:
234
+ info.append(' Overwriting: tiles older than %s' %
235
+ datetime.fromtimestamp(task.refresh_timestamp))
236
+ elif task.refresh_timestamp == 0:
237
+ info.append(' Overwriting: all tiles')
238
+ else:
239
+ info.append(' Overwriting: no tiles')
240
+
241
+ return '\n'.join(info)
242
+
243
+
244
+ def format_cleanup_task(task):
245
+ info = []
246
+ info.append(' %s:' % (task.md['name'], ))
247
+ if task.coverage is False:
248
+ info.append(" Empty coverage given for this task")
249
+ info.append(" Skipped")
250
+ return '\n'.join(info)
251
+
252
+ info.append(" Cleaning up cache '%s' with grid '%s' in %s" % (
253
+ task.md['cache_name'], task.md['grid_name'], task.grid.srs.srs_code))
254
+ if task.coverage:
255
+ info.append(' Limited to coverage in: %s (EPSG:4326)' % (format_bbox(task.coverage.extent.llbbox), ))
256
+ else:
257
+ info.append(' Complete grid: %s (EPSG:4326)' % (format_bbox(map_extent_from_grid(task.grid).llbbox), ))
258
+ info.append(' Levels: %s' % (task.levels, ))
259
+
260
+ if task.remove_timestamp:
261
+ info.append(' Remove: tiles older than %s' %
262
+ datetime.fromtimestamp(task.remove_timestamp))
263
+ else:
264
+ info.append(' Remove: all tiles')
265
+
266
+ return '\n'.join(info)
@@ -0,0 +1,14 @@
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.
@@ -0,0 +1,45 @@
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 handler (WMS, TMS, etc.).
18
+ """
19
+ from mapproxy.exception import RequestError
20
+
21
+
22
+ class Server(object):
23
+ names = tuple()
24
+ def request_parser(x): return None
25
+ request_methods = ()
26
+
27
+ def handle(self, req):
28
+ try:
29
+ parsed_req = self.parse_request(req)
30
+ handler = getattr(self, parsed_req.request_handler_name)
31
+ return handler(parsed_req)
32
+ except RequestError as e:
33
+ return e.render()
34
+
35
+ def parse_request(self, req):
36
+ return self.request_parser(req)
37
+
38
+ def decorate_img(self, image, service, layers, environ, query_extent):
39
+ """ Callback that allows the ImageSource associated with a response to
40
+ be modified before it is returned. The callback is passed the
41
+ ImageSource instance and must return a valid ImageSource """
42
+ if 'mapproxy.decorate_img' in environ:
43
+ image = environ['mapproxy.decorate_img'](
44
+ image, service, layers, environ=environ, query_extent=query_extent)
45
+ return image
@@ -0,0 +1,364 @@
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
+ Demo service handler
18
+ """
19
+ from __future__ import division
20
+
21
+ import importlib_resources
22
+ import os
23
+ import mimetypes
24
+ from collections import defaultdict
25
+
26
+ from mapproxy.config.config import base_config
27
+ from mapproxy.util.ext.odict import odict
28
+ from mapproxy.exception import RequestError
29
+ from mapproxy.service.base import Server
30
+ from mapproxy.response import Response
31
+ from mapproxy.srs import SRS, get_epsg_num
32
+ from mapproxy.layer import SRSConditional, CacheMapLayer, ResolutionConditional
33
+ from mapproxy.source.wms import WMSSource
34
+
35
+ from urllib import request as urllib2
36
+
37
+ from mapproxy.template import template_loader, bunch
38
+ env = {'bunch': bunch}
39
+ get_template = template_loader(__package__, 'templates', namespace=env)
40
+
41
+ # Used by plugins
42
+ extra_demo_server_handlers = set()
43
+
44
+
45
+ def register_extra_demo_server_handler(handler):
46
+ """ Method used by plugins to register a new handler for the demo service.
47
+ The handler passed to this method is invoked by the DemoServer.handle()
48
+ method when receiving an incoming request, and let a chance to the
49
+ handler to process it, if it is relevant to it.
50
+
51
+ :param handler: New handler for incoming requests
52
+ :type handler: function that takes 2 arguments (DemoServer instance and req) and
53
+ returns a string with HTML content or None
54
+ """
55
+
56
+ extra_demo_server_handlers.add(handler)
57
+
58
+
59
+ extra_substitution_handlers = set()
60
+
61
+
62
+ def register_extra_demo_substitution_handler(handler):
63
+ """ Method used by plugins to register a new handler for doing substitutions
64
+ to the HTML template used by the demo service.
65
+ The handler passed to this method is invoked by the DemoServer._render_template()
66
+ method. The handler may modify the passed substitutions dictionary
67
+ argument. Keys of particular interest are 'extra_services_html_beginning'
68
+ and 'extra_services_html_end' to add HTML content before/after built-in
69
+ services.
70
+
71
+ :param handler: New handler for incoming requests
72
+ :type handler: function that takes 3 arguments(DemoServer instance, req and a substitutions dictionary
73
+ argument).
74
+ """
75
+
76
+ extra_substitution_handlers.add(handler)
77
+
78
+
79
+ def static_filename(name):
80
+ if base_config().template_dir:
81
+ return os.path.join(base_config().template_dir, name)
82
+ else:
83
+ return importlib_resources.files(__package__).joinpath('templates').joinpath(name)
84
+
85
+
86
+ class DemoServer(Server):
87
+ names = ('demo',)
88
+
89
+ def __init__(self, layers, md, request_parser=None, tile_layers=None,
90
+ srs=None, image_formats=None, services=None, restful_template=None, background=None):
91
+ Server.__init__(self)
92
+ self.layers = layers
93
+ self.tile_layers = tile_layers or {}
94
+ self.md = md
95
+ self.image_formats = image_formats
96
+ filter_image_format = []
97
+ for format in self.image_formats:
98
+ if 'image/jpeg' == format or 'image/png' == format:
99
+ filter_image_format.append(format)
100
+ self.image_formats = filter_image_format
101
+ self.srs = srs
102
+ self.services = services or []
103
+ self.restful_template = restful_template
104
+ self.background = background
105
+
106
+ def handle(self, req):
107
+ if req.path.startswith('/demo/static/'):
108
+ if '..' in req.path:
109
+ return Response('file not found', content_type='text/plain', status=404)
110
+ filename = req.path.lstrip('/')
111
+ filename = static_filename(filename)
112
+ if not os.path.isfile(filename):
113
+ return Response('file not found', content_type='text/plain', status=404)
114
+ type, encoding = mimetypes.guess_type(filename)
115
+ return Response(open(filename, 'rb'), content_type=type)
116
+
117
+ # we don't authorize the static files (css, js)
118
+ # since they are not confidential
119
+ try:
120
+ authorized = self.authorized_demo(req.environ)
121
+ except RequestError as ex:
122
+ return ex.render()
123
+ if not authorized:
124
+ return Response('forbidden', content_type='text/plain', status=403)
125
+
126
+ for handler in extra_demo_server_handlers:
127
+ demo = handler(self, req)
128
+ if demo is not None:
129
+ return Response(demo, content_type='text/html')
130
+
131
+ if 'wms_layer' in req.args:
132
+ demo = self._render_wms_template('demo/wms_demo.html', req)
133
+ elif 'tms_layer' in req.args:
134
+ demo = self._render_tms_template('demo/tms_demo.html', req)
135
+ elif 'wmts_layer' in req.args:
136
+ demo = self._render_wmts_template('demo/wmts_demo.html', req)
137
+ elif 'wms_capabilities' in req.args:
138
+ internal_url = '%s/service?REQUEST=GetCapabilities' % (req.server_script_url)
139
+ if 'type' in req.args and req.args['type'] == 'external':
140
+ url = internal_url.replace(req.server_script_url, req.script_url)
141
+ else:
142
+ url = internal_url
143
+ capabilities = urllib2.urlopen(url)
144
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMS', url)
145
+ elif 'wmsc_capabilities' in req.args:
146
+ internal_url = '%s/service?REQUEST=GetCapabilities&tiled=true' % (req.server_script_url)
147
+ if 'type' in req.args and req.args['type'] == 'external':
148
+ url = internal_url.replace(req.server_script_url, req.script_url)
149
+ else:
150
+ url = internal_url
151
+ capabilities = urllib2.urlopen(url)
152
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMS-C', url)
153
+ elif 'wmts_capabilities_kvp' in req.args:
154
+ internal_url = '%s/service?REQUEST=GetCapabilities&SERVICE=WMTS' % (req.server_script_url)
155
+ if 'type' in req.args and req.args['type'] == 'external':
156
+ url = internal_url.replace(req.server_script_url, req.script_url)
157
+ else:
158
+ url = internal_url
159
+ capabilities = urllib2.urlopen(url)
160
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMTS', url)
161
+ elif 'wmts_capabilities' in req.args:
162
+ internal_url = '%s/wmts/1.0.0/WMTSCapabilities.xml' % (req.server_script_url)
163
+ if 'type' in req.args and req.args['type'] == 'external':
164
+ url = internal_url.replace(req.server_script_url, req.script_url)
165
+ else:
166
+ url = internal_url
167
+ capabilities = urllib2.urlopen(url)
168
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMTS', url)
169
+ elif 'tms_capabilities' in req.args:
170
+ if 'layer' in req.args and 'srs' in req.args:
171
+ # prevent dir traversal (seems it's not possible with urllib2, but better safe then sorry)
172
+ layer = req.args['layer'].replace('..', '')
173
+ srs = req.args['srs'].replace('..', '')
174
+ internal_url = '%s/tms/1.0.0/%s/%s' % (req.server_script_url, layer, srs)
175
+ else:
176
+ internal_url = '%s/tms/1.0.0/' % (req.server_script_url)
177
+ if 'type' in req.args and req.args['type'] == 'external':
178
+ url = internal_url.replace(req.server_script_url, req.script_url)
179
+ else:
180
+ url = internal_url
181
+ capabilities = urllib2.urlopen(url)
182
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'TMS', url)
183
+ elif req.path == '/demo/':
184
+ demo = self._render_template(req, 'demo/demo.html')
185
+ else:
186
+ resp = Response('', status=301)
187
+ resp.headers['Location'] = req.script_url.rstrip('/') + '/demo/'
188
+ return resp
189
+ return Response(demo, content_type='text/html')
190
+
191
+ def layer_srs(self, layer):
192
+ """
193
+ Return a list tuples with title and name of all SRS for the layer.
194
+ The title of SRS that are native to the layer are suffixed with a '*'.
195
+ """
196
+ cached_srs = []
197
+ for map_layer in layer.map_layers:
198
+ # TODO unify map_layers interface
199
+ if isinstance(map_layer, SRSConditional):
200
+ for srs_key in map_layer.srs_map.keys():
201
+ cached_srs.append(srs_key.srs_code)
202
+ elif isinstance(map_layer, CacheMapLayer):
203
+ cached_srs.append(map_layer.grid.srs.srs_code)
204
+ elif isinstance(map_layer, ResolutionConditional):
205
+ cached_srs.append(map_layer.srs.srs_code)
206
+ elif isinstance(map_layer, WMSSource):
207
+ if map_layer.supported_srs:
208
+ for supported_srs in map_layer.supported_srs:
209
+ cached_srs.append(supported_srs.srs_code)
210
+
211
+ uncached_srs = []
212
+
213
+ for srs_code in self.srs:
214
+ if srs_code not in cached_srs:
215
+ uncached_srs.append(srs_code)
216
+
217
+ def get_srs_key(srs):
218
+ epsg_num = get_epsg_num(srs)
219
+ return str(epsg_num if epsg_num else srs)
220
+
221
+ sorted_cached_srs = sorted(cached_srs, key=lambda srs: get_srs_key(srs))
222
+ sorted_uncached_srs = sorted(uncached_srs, key=lambda srs: get_srs_key(srs))
223
+ sorted_cached_srs = [(s + '*', s) for s in sorted_cached_srs]
224
+ sorted_uncached_srs = [(s, s) for s in sorted_uncached_srs]
225
+ return sorted_cached_srs + sorted_uncached_srs
226
+
227
+ def _render_template(self, req, template):
228
+ template = get_template(template, default_inherit="demo/static.html")
229
+ tms_tile_layers = defaultdict(list)
230
+ for layer in self.tile_layers:
231
+ name = self.tile_layers[layer].md.get('name')
232
+ tms_tile_layers[name].append(self.tile_layers[layer])
233
+ wmts_layers = tms_tile_layers.copy()
234
+
235
+ wmts_layers = odict(sorted(wmts_layers.items(), key=lambda x: x[0]))
236
+ tms_tile_layers = odict(sorted(tms_tile_layers.items(), key=lambda x: x[0]))
237
+
238
+ substitutions = dict(
239
+ extra_services_html_beginning='',
240
+ extra_services_html_end='',
241
+ layers=self.layers,
242
+ formats=self.image_formats,
243
+ srs=self.srs,
244
+ layer_srs=self.layer_srs,
245
+ tms_layers=tms_tile_layers,
246
+ wmts_layers=wmts_layers,
247
+ services=self.services
248
+ )
249
+
250
+ for add_substitution in extra_substitution_handlers:
251
+ add_substitution(self, req, substitutions)
252
+
253
+ return template.substitute(substitutions)
254
+
255
+ def _render_wms_template(self, template, req):
256
+ template = get_template(template, default_inherit="demo/static.html")
257
+ layer = self.layers[req.args['wms_layer']]
258
+ srs = escape(req.args['srs'])
259
+ bbox = layer.extent.bbox_for(SRS(srs))
260
+ width = bbox[2] - bbox[0]
261
+ height = bbox[3] - bbox[1]
262
+ min_res = max(width/256, height/256)
263
+ background_url = base_config().background.url
264
+ if self.background:
265
+ background_url = self.background["url"]
266
+ return template.substitute(layer=layer,
267
+ image_formats=self.image_formats,
268
+ format=escape(req.args['format']),
269
+ srs=srs,
270
+ layer_srs=self.layer_srs,
271
+ bbox=bbox,
272
+ res=min_res,
273
+ background_url=background_url)
274
+
275
+ def _render_tms_template(self, template, req):
276
+ template = get_template(template, default_inherit="demo/static.html")
277
+ for layer in self.tile_layers.values():
278
+ if (layer.name == req.args['tms_layer'] and
279
+ layer.grid.srs.srs_code == req.args['srs']):
280
+ tile_layer = layer
281
+ break
282
+
283
+ resolutions = tile_layer.grid.tile_sets
284
+ res = []
285
+ for level, resolution in resolutions:
286
+ res.append(resolution)
287
+
288
+ if tile_layer.grid.srs.is_latlong:
289
+ units = 'degree'
290
+ else:
291
+ units = 'm'
292
+
293
+ if tile_layer.grid.profile == 'local':
294
+ add_res_to_options = True
295
+ else:
296
+ add_res_to_options = False
297
+ background_url = base_config().background.url
298
+ if self.background:
299
+ background_url = self.background["url"]
300
+ return template.substitute(layer=tile_layer,
301
+ srs=escape(req.args['srs']),
302
+ format=escape(req.args['format']),
303
+ resolutions=res,
304
+ units=units,
305
+ add_res_to_options=add_res_to_options,
306
+ all_tile_layers=self.tile_layers,
307
+ background_url=background_url)
308
+
309
+ def _render_wmts_template(self, template, req):
310
+ template = get_template(template, default_inherit="demo/static.html")
311
+ for layer in self.tile_layers.values():
312
+ if (layer.name == req.args['wmts_layer'] and
313
+ layer.grid.srs.srs_code == req.args['srs']):
314
+ wmts_layer = layer
315
+ break
316
+
317
+ restful_url = self.restful_template.replace('{Layer}', wmts_layer.name, 1)
318
+ if '{Format}' in restful_url:
319
+ restful_url = restful_url.replace('{Format}', wmts_layer.format)
320
+
321
+ if wmts_layer.grid.srs.is_latlong:
322
+ units = 'degree'
323
+ else:
324
+ units = 'm'
325
+ background_url = base_config().background.url
326
+ if self.background:
327
+ background_url = self.background["url"]
328
+ return template.substitute(layer=wmts_layer,
329
+ matrix_set=wmts_layer.grid.name,
330
+ format=escape(req.args['format']),
331
+ srs=escape(req.args['srs']),
332
+ resolutions=wmts_layer.grid.resolutions,
333
+ units=units,
334
+ all_tile_layers=self.tile_layers,
335
+ restful_url=restful_url,
336
+ background_url=background_url)
337
+
338
+ def _render_capabilities_template(self, template, xmlfile, service, url):
339
+ template = get_template(template, default_inherit="demo/static.html")
340
+ return template.substitute(capabilities=xmlfile,
341
+ service=service,
342
+ url=url)
343
+
344
+ def authorized_demo(self, environ):
345
+ if 'mapproxy.authorize' in environ:
346
+ result = environ['mapproxy.authorize']('demo', [], environ=environ)
347
+ if result['authorized'] == 'unauthenticated':
348
+ raise RequestError('unauthorized', status=401)
349
+ if result['authorized'] == 'full':
350
+ return True
351
+ return False
352
+ return True
353
+
354
+
355
+ def escape(data):
356
+ """
357
+ Escape user-provided input data for safe inclusion in HTML _and_ JS to prevent XSS.
358
+ """
359
+ data = data.replace('&', '&amp;')
360
+ data = data.replace('>', '&gt;')
361
+ data = data.replace('<', '&lt;')
362
+ data = data.replace("'", '')
363
+ data = data.replace('"', '')
364
+ return data