MapProxy 1.16.1__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 (458) hide show
  1. mapproxy/__init__.py +0 -0
  2. mapproxy/cache/__init__.py +36 -0
  3. mapproxy/cache/azureblob.py +145 -0
  4. mapproxy/cache/base.py +111 -0
  5. mapproxy/cache/compact.py +664 -0
  6. mapproxy/cache/couchdb.py +295 -0
  7. mapproxy/cache/dummy.py +34 -0
  8. mapproxy/cache/file.py +185 -0
  9. mapproxy/cache/geopackage.py +609 -0
  10. mapproxy/cache/legend.py +83 -0
  11. mapproxy/cache/mbtiles.py +392 -0
  12. mapproxy/cache/meta.py +78 -0
  13. mapproxy/cache/path.py +250 -0
  14. mapproxy/cache/redis.py +88 -0
  15. mapproxy/cache/renderd.py +95 -0
  16. mapproxy/cache/riak.py +202 -0
  17. mapproxy/cache/s3.py +177 -0
  18. mapproxy/cache/tile.py +699 -0
  19. mapproxy/client/__init__.py +0 -0
  20. mapproxy/client/arcgis.py +79 -0
  21. mapproxy/client/cgi.py +139 -0
  22. mapproxy/client/http.py +315 -0
  23. mapproxy/client/log.py +33 -0
  24. mapproxy/client/tile.py +150 -0
  25. mapproxy/client/wms.py +254 -0
  26. mapproxy/compat/__init__.py +46 -0
  27. mapproxy/compat/image.py +79 -0
  28. mapproxy/compat/itertools.py +29 -0
  29. mapproxy/compat/modules.py +13 -0
  30. mapproxy/config/__init__.py +22 -0
  31. mapproxy/config/config.py +201 -0
  32. mapproxy/config/coverage.py +107 -0
  33. mapproxy/config/defaults.py +98 -0
  34. mapproxy/config/loader.py +2286 -0
  35. mapproxy/config/spec.py +644 -0
  36. mapproxy/config/validator.py +239 -0
  37. mapproxy/config_template/__init__.py +0 -0
  38. mapproxy/config_template/base_config/config.wsgi +10 -0
  39. mapproxy/config_template/base_config/full_example.yaml +593 -0
  40. mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
  41. mapproxy/config_template/base_config/log.ini +35 -0
  42. mapproxy/config_template/base_config/mapproxy.yaml +60 -0
  43. mapproxy/config_template/base_config/seed.yaml +27 -0
  44. mapproxy/exception.py +142 -0
  45. mapproxy/featureinfo.py +252 -0
  46. mapproxy/grid.py +1170 -0
  47. mapproxy/image/__init__.py +536 -0
  48. mapproxy/image/fonts/DejaVuSans.ttf +0 -0
  49. mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
  50. mapproxy/image/fonts/LICENSE +99 -0
  51. mapproxy/image/fonts/__init__.py +0 -0
  52. mapproxy/image/mask.py +75 -0
  53. mapproxy/image/merge.py +316 -0
  54. mapproxy/image/message.py +347 -0
  55. mapproxy/image/opts.py +182 -0
  56. mapproxy/image/tile.py +167 -0
  57. mapproxy/image/transform.py +350 -0
  58. mapproxy/layer.py +470 -0
  59. mapproxy/multiapp.py +231 -0
  60. mapproxy/proj.py +302 -0
  61. mapproxy/request/__init__.py +18 -0
  62. mapproxy/request/arcgis.py +259 -0
  63. mapproxy/request/base.py +476 -0
  64. mapproxy/request/tile.py +128 -0
  65. mapproxy/request/wms/__init__.py +793 -0
  66. mapproxy/request/wms/exception.py +99 -0
  67. mapproxy/request/wmts.py +436 -0
  68. mapproxy/response.py +237 -0
  69. mapproxy/script/__init__.py +0 -0
  70. mapproxy/script/conf/__init__.py +0 -0
  71. mapproxy/script/conf/app.py +195 -0
  72. mapproxy/script/conf/caches.py +45 -0
  73. mapproxy/script/conf/layers.py +54 -0
  74. mapproxy/script/conf/seeds.py +37 -0
  75. mapproxy/script/conf/sources.py +86 -0
  76. mapproxy/script/conf/utils.py +143 -0
  77. mapproxy/script/defrag.py +184 -0
  78. mapproxy/script/export.py +333 -0
  79. mapproxy/script/grids.py +188 -0
  80. mapproxy/script/scales.py +126 -0
  81. mapproxy/script/util.py +406 -0
  82. mapproxy/script/wms_capabilities.py +152 -0
  83. mapproxy/seed/__init__.py +0 -0
  84. mapproxy/seed/cachelock.py +121 -0
  85. mapproxy/seed/cleanup.py +187 -0
  86. mapproxy/seed/config.py +469 -0
  87. mapproxy/seed/script.py +388 -0
  88. mapproxy/seed/seeder.py +538 -0
  89. mapproxy/seed/spec.py +64 -0
  90. mapproxy/seed/util.py +254 -0
  91. mapproxy/service/__init__.py +14 -0
  92. mapproxy/service/base.py +46 -0
  93. mapproxy/service/demo.py +356 -0
  94. mapproxy/service/kml.py +331 -0
  95. mapproxy/service/ows.py +38 -0
  96. mapproxy/service/template_helper.py +53 -0
  97. mapproxy/service/templates/demo/capabilities_demo.html +16 -0
  98. mapproxy/service/templates/demo/demo.html +181 -0
  99. mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
  100. mapproxy/service/templates/demo/static/img/blank.gif +0 -0
  101. mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
  102. mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
  103. mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
  104. mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
  105. mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
  106. mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
  107. mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
  108. mapproxy/service/templates/demo/static/logo.png +0 -0
  109. mapproxy/service/templates/demo/static/ol.css +345 -0
  110. mapproxy/service/templates/demo/static/ol.js +4 -0
  111. mapproxy/service/templates/demo/static/proj4.min.js +1 -0
  112. mapproxy/service/templates/demo/static/proj4defs.js +1 -0
  113. mapproxy/service/templates/demo/static/site.css +137 -0
  114. mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
  115. mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
  116. mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
  117. mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
  118. mapproxy/service/templates/demo/static.html +34 -0
  119. mapproxy/service/templates/demo/tms_demo.html +103 -0
  120. mapproxy/service/templates/demo/wms_demo.html +140 -0
  121. mapproxy/service/templates/demo/wmts_demo.html +110 -0
  122. mapproxy/service/templates/tms_capabilities.xml +13 -0
  123. mapproxy/service/templates/tms_exception.xml +4 -0
  124. mapproxy/service/templates/tms_root_resource.xml +7 -0
  125. mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
  126. mapproxy/service/templates/wms100capabilities.xml +112 -0
  127. mapproxy/service/templates/wms100exception.xml +4 -0
  128. mapproxy/service/templates/wms110capabilities.xml +152 -0
  129. mapproxy/service/templates/wms110exception.xml +5 -0
  130. mapproxy/service/templates/wms111capabilities.xml +183 -0
  131. mapproxy/service/templates/wms111exception.xml +5 -0
  132. mapproxy/service/templates/wms130capabilities.xml +326 -0
  133. mapproxy/service/templates/wms130exception.xml +8 -0
  134. mapproxy/service/templates/wmts100capabilities.xml +155 -0
  135. mapproxy/service/templates/wmts100exception.xml +9 -0
  136. mapproxy/service/tile.py +536 -0
  137. mapproxy/service/wms.py +851 -0
  138. mapproxy/service/wmts.py +381 -0
  139. mapproxy/source/__init__.py +75 -0
  140. mapproxy/source/arcgis.py +39 -0
  141. mapproxy/source/error.py +39 -0
  142. mapproxy/source/mapnik.py +259 -0
  143. mapproxy/source/tile.py +96 -0
  144. mapproxy/source/wms.py +270 -0
  145. mapproxy/srs.py +726 -0
  146. mapproxy/template.py +54 -0
  147. mapproxy/test/__init__.py +0 -0
  148. mapproxy/test/conftest.py +7 -0
  149. mapproxy/test/helper.py +247 -0
  150. mapproxy/test/http.py +494 -0
  151. mapproxy/test/image.py +210 -0
  152. mapproxy/test/mocker.py +2268 -0
  153. mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
  154. mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
  155. mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
  156. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
  157. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
  158. mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
  159. mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
  160. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
  161. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
  162. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
  163. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
  164. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
  165. mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
  166. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
  167. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
  168. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
  169. mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
  170. mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
  171. mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
  172. mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
  173. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
  174. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
  175. mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
  176. mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
  177. mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
  178. mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
  179. mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
  180. mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
  181. mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
  182. mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
  183. mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
  184. mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
  185. mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
  186. mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
  187. mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
  188. mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
  189. mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
  190. mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
  191. mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
  192. mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
  193. mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
  194. mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
  195. mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
  196. mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
  197. mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
  198. mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
  199. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
  200. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
  201. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
  202. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
  203. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
  204. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
  205. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
  206. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
  207. mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
  208. mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  209. mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
  210. mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  211. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
  212. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
  213. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
  214. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
  215. mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
  216. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
  217. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
  218. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
  219. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
  220. mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
  221. mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  222. mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
  223. mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  224. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
  225. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
  226. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
  227. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
  228. mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
  229. mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
  230. mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
  231. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
  232. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
  233. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
  234. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
  235. mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
  236. mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
  237. mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
  238. mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
  239. mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
  240. mapproxy/test/schemas/xml.xsd +287 -0
  241. mapproxy/test/system/__init__.py +98 -0
  242. mapproxy/test/system/fixture/arcgis.yaml +57 -0
  243. mapproxy/test/system/fixture/auth.yaml +70 -0
  244. mapproxy/test/system/fixture/cache.mbtiles +0 -0
  245. mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
  246. mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
  247. mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
  248. mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
  249. mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
  250. mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
  251. mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
  252. mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
  253. mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
  254. mapproxy/test/system/fixture/cache_s3.yaml +58 -0
  255. mapproxy/test/system/fixture/cache_source.yaml +81 -0
  256. mapproxy/test/system/fixture/combined_sources.yaml +130 -0
  257. mapproxy/test/system/fixture/coverage.yaml +77 -0
  258. mapproxy/test/system/fixture/demo.yaml +135 -0
  259. mapproxy/test/system/fixture/dimension.yaml +59 -0
  260. mapproxy/test/system/fixture/disable_storage.yaml +25 -0
  261. mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
  262. mapproxy/test/system/fixture/formats.yaml +72 -0
  263. mapproxy/test/system/fixture/inspire.yaml +101 -0
  264. mapproxy/test/system/fixture/inspire_full.yaml +124 -0
  265. mapproxy/test/system/fixture/kml_layer.yaml +66 -0
  266. mapproxy/test/system/fixture/layer.yaml +260 -0
  267. mapproxy/test/system/fixture/layergroups.yaml +57 -0
  268. mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
  269. mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
  270. mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
  271. mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
  272. mapproxy/test/system/fixture/mapserver.yaml +23 -0
  273. mapproxy/test/system/fixture/minimal_cgi.py +16 -0
  274. mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
  275. mapproxy/test/system/fixture/multi_cache_layers.yaml +100 -0
  276. mapproxy/test/system/fixture/multiapp1.yaml +20 -0
  277. mapproxy/test/system/fixture/multiapp2.yaml +19 -0
  278. mapproxy/test/system/fixture/renderd_client.yaml +55 -0
  279. mapproxy/test/system/fixture/scalehints.yaml +70 -0
  280. mapproxy/test/system/fixture/seed.yaml +94 -0
  281. mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
  282. mapproxy/test/system/fixture/seed_old.yaml +12 -0
  283. mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
  284. mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
  285. mapproxy/test/system/fixture/seedonly.yaml +51 -0
  286. mapproxy/test/system/fixture/sld.yaml +35 -0
  287. mapproxy/test/system/fixture/source_errors.yaml +84 -0
  288. mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
  289. mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
  290. mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
  291. mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
  292. mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
  293. mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
  294. mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
  295. mapproxy/test/system/fixture/util_grids.yaml +30 -0
  296. mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
  297. mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
  298. mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
  299. mapproxy/test/system/fixture/watermark.yaml +50 -0
  300. mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
  301. mapproxy/test/system/fixture/wms_versions.yaml +38 -0
  302. mapproxy/test/system/fixture/wmts.yaml +134 -0
  303. mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
  304. mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
  305. mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
  306. mapproxy/test/system/test_arcgis.py +156 -0
  307. mapproxy/test/system/test_auth.py +1134 -0
  308. mapproxy/test/system/test_behind_proxy.py +75 -0
  309. mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
  310. mapproxy/test/system/test_cache_azureblob.py +127 -0
  311. mapproxy/test/system/test_cache_band_merge.py +103 -0
  312. mapproxy/test/system/test_cache_geopackage.py +144 -0
  313. mapproxy/test/system/test_cache_grid_names.py +89 -0
  314. mapproxy/test/system/test_cache_mbtiles.py +85 -0
  315. mapproxy/test/system/test_cache_s3.py +115 -0
  316. mapproxy/test/system/test_cache_source.py +146 -0
  317. mapproxy/test/system/test_combined_sources.py +335 -0
  318. mapproxy/test/system/test_coverage.py +140 -0
  319. mapproxy/test/system/test_decorate_img.py +214 -0
  320. mapproxy/test/system/test_demo.py +106 -0
  321. mapproxy/test/system/test_demo_with_extra_service.py +53 -0
  322. mapproxy/test/system/test_dimensions.py +278 -0
  323. mapproxy/test/system/test_disable_storage.py +42 -0
  324. mapproxy/test/system/test_formats.py +219 -0
  325. mapproxy/test/system/test_inspire_vs.py +173 -0
  326. mapproxy/test/system/test_kml.py +262 -0
  327. mapproxy/test/system/test_layergroups.py +160 -0
  328. mapproxy/test/system/test_legendgraphic.py +308 -0
  329. mapproxy/test/system/test_mapnik.py +161 -0
  330. mapproxy/test/system/test_mapserver.py +81 -0
  331. mapproxy/test/system/test_mixed_mode_format.py +195 -0
  332. mapproxy/test/system/test_multi_cache_layers.py +167 -0
  333. mapproxy/test/system/test_multiapp.py +92 -0
  334. mapproxy/test/system/test_refresh.py +207 -0
  335. mapproxy/test/system/test_renderd_client.py +304 -0
  336. mapproxy/test/system/test_response_headers.py +54 -0
  337. mapproxy/test/system/test_scalehints.py +140 -0
  338. mapproxy/test/system/test_seed.py +422 -0
  339. mapproxy/test/system/test_seed_only.py +93 -0
  340. mapproxy/test/system/test_sld.py +120 -0
  341. mapproxy/test/system/test_source_errors.py +377 -0
  342. mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
  343. mapproxy/test/system/test_tms.py +276 -0
  344. mapproxy/test/system/test_tms_origin.py +46 -0
  345. mapproxy/test/system/test_util_conf.py +304 -0
  346. mapproxy/test/system/test_util_export.py +210 -0
  347. mapproxy/test/system/test_util_grids.py +88 -0
  348. mapproxy/test/system/test_util_wms_capabilities.py +182 -0
  349. mapproxy/test/system/test_watermark.py +91 -0
  350. mapproxy/test/system/test_wms.py +1611 -0
  351. mapproxy/test/system/test_wms_srs_extent.py +165 -0
  352. mapproxy/test/system/test_wms_version.py +85 -0
  353. mapproxy/test/system/test_wmsc.py +116 -0
  354. mapproxy/test/system/test_wmts.py +334 -0
  355. mapproxy/test/system/test_wmts_dimensions.py +206 -0
  356. mapproxy/test/system/test_wmts_restful.py +198 -0
  357. mapproxy/test/system/test_xslt_featureinfo.py +425 -0
  358. mapproxy/test/test_http_helper.py +219 -0
  359. mapproxy/test/unit/__init__.py +0 -0
  360. mapproxy/test/unit/epsg +2 -0
  361. mapproxy/test/unit/polygons/polygons.dbf +0 -0
  362. mapproxy/test/unit/polygons/polygons.shp +0 -0
  363. mapproxy/test/unit/polygons/polygons.shx +0 -0
  364. mapproxy/test/unit/test_async.py +245 -0
  365. mapproxy/test/unit/test_auth.py +419 -0
  366. mapproxy/test/unit/test_cache.py +1193 -0
  367. mapproxy/test/unit/test_cache_azureblob.py +94 -0
  368. mapproxy/test/unit/test_cache_compact.py +319 -0
  369. mapproxy/test/unit/test_cache_couchdb.py +114 -0
  370. mapproxy/test/unit/test_cache_geopackage.py +221 -0
  371. mapproxy/test/unit/test_cache_redis.py +67 -0
  372. mapproxy/test/unit/test_cache_riak.py +76 -0
  373. mapproxy/test/unit/test_cache_s3.py +84 -0
  374. mapproxy/test/unit/test_cache_tile.py +427 -0
  375. mapproxy/test/unit/test_client.py +479 -0
  376. mapproxy/test/unit/test_client_arcgis.py +73 -0
  377. mapproxy/test/unit/test_client_cgi.py +136 -0
  378. mapproxy/test/unit/test_collections.py +116 -0
  379. mapproxy/test/unit/test_concat_legends.py +37 -0
  380. mapproxy/test/unit/test_conf_loader.py +1061 -0
  381. mapproxy/test/unit/test_conf_validator.py +416 -0
  382. mapproxy/test/unit/test_config.py +117 -0
  383. mapproxy/test/unit/test_decorate_img.py +185 -0
  384. mapproxy/test/unit/test_exceptions.py +258 -0
  385. mapproxy/test/unit/test_featureinfo.py +291 -0
  386. mapproxy/test/unit/test_file_lock_load.py +49 -0
  387. mapproxy/test/unit/test_geom.py +503 -0
  388. mapproxy/test/unit/test_grid.py +1258 -0
  389. mapproxy/test/unit/test_image.py +1053 -0
  390. mapproxy/test/unit/test_image_mask.py +181 -0
  391. mapproxy/test/unit/test_image_messages.py +197 -0
  392. mapproxy/test/unit/test_image_options.py +160 -0
  393. mapproxy/test/unit/test_isodate.py +122 -0
  394. mapproxy/test/unit/test_multiapp.py +163 -0
  395. mapproxy/test/unit/test_ogr_reader.py +50 -0
  396. mapproxy/test/unit/test_request.py +745 -0
  397. mapproxy/test/unit/test_request_wmts.py +178 -0
  398. mapproxy/test/unit/test_response.py +79 -0
  399. mapproxy/test/unit/test_seed.py +365 -0
  400. mapproxy/test/unit/test_seed_cachelock.py +90 -0
  401. mapproxy/test/unit/test_srs.py +215 -0
  402. mapproxy/test/unit/test_tiled_source.py +122 -0
  403. mapproxy/test/unit/test_tilefilter.py +31 -0
  404. mapproxy/test/unit/test_times.py +25 -0
  405. mapproxy/test/unit/test_timeutils.py +50 -0
  406. mapproxy/test/unit/test_util_conf_utils.py +75 -0
  407. mapproxy/test/unit/test_utils.py +476 -0
  408. mapproxy/test/unit/test_wms_capabilities.py +44 -0
  409. mapproxy/test/unit/test_wms_layer.py +113 -0
  410. mapproxy/test/unit/test_yaml.py +69 -0
  411. mapproxy/tilefilter.py +59 -0
  412. mapproxy/util/__init__.py +0 -0
  413. mapproxy/util/async_.py +227 -0
  414. mapproxy/util/collections.py +132 -0
  415. mapproxy/util/coverage.py +329 -0
  416. mapproxy/util/escape.py +10 -0
  417. mapproxy/util/ext/__init__.py +14 -0
  418. mapproxy/util/ext/dictspec/__init__.py +1 -0
  419. mapproxy/util/ext/dictspec/spec.py +124 -0
  420. mapproxy/util/ext/dictspec/test/__init__.py +0 -0
  421. mapproxy/util/ext/dictspec/test/test_validator.py +274 -0
  422. mapproxy/util/ext/dictspec/validator.py +189 -0
  423. mapproxy/util/ext/local.py +196 -0
  424. mapproxy/util/ext/lockfile.py +138 -0
  425. mapproxy/util/ext/odict.py +330 -0
  426. mapproxy/util/ext/serving.py +508 -0
  427. mapproxy/util/ext/tempita/__init__.py +1174 -0
  428. mapproxy/util/ext/tempita/_looper.py +163 -0
  429. mapproxy/util/ext/tempita/compat3.py +46 -0
  430. mapproxy/util/ext/wmsparse/__init__.py +3 -0
  431. mapproxy/util/ext/wmsparse/duration.py +597 -0
  432. mapproxy/util/ext/wmsparse/parse.py +305 -0
  433. mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
  434. mapproxy/util/ext/wmsparse/test/test_parse.py +162 -0
  435. mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
  436. mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
  437. mapproxy/util/ext/wmsparse/test/wms-omniscale-111.xml +90 -0
  438. mapproxy/util/ext/wmsparse/test/wms-omniscale-130.xml +120 -0
  439. mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
  440. mapproxy/util/ext/wmsparse/util.py +187 -0
  441. mapproxy/util/fs.py +156 -0
  442. mapproxy/util/geom.py +295 -0
  443. mapproxy/util/lib.py +115 -0
  444. mapproxy/util/lock.py +163 -0
  445. mapproxy/util/ogr.py +231 -0
  446. mapproxy/util/py.py +81 -0
  447. mapproxy/util/times.py +75 -0
  448. mapproxy/util/yaml.py +56 -0
  449. mapproxy/version.py +31 -0
  450. mapproxy/wsgiapp.py +164 -0
  451. mapproxy-1.16.1.dist-info/METADATA +151 -0
  452. mapproxy-1.16.1.dist-info/RECORD +458 -0
  453. mapproxy-1.16.1.dist-info/WHEEL +5 -0
  454. mapproxy-1.16.1.dist-info/entry_points.txt +3 -0
  455. mapproxy-1.16.1.dist-info/licenses/AUTHORS.txt +33 -0
  456. mapproxy-1.16.1.dist-info/licenses/COPYING.txt +60 -0
  457. mapproxy-1.16.1.dist-info/licenses/LICENSE.txt +202 -0
  458. mapproxy-1.16.1.dist-info/top_level.txt +1 -0
mapproxy/seed/util.py ADDED
@@ -0,0 +1,254 @@
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
+ class bidict(dict):
37
+ """
38
+ Simplest bi-directional dictionary.
39
+ """
40
+ def __init__(self, iterator):
41
+ for key, val in iterator:
42
+ dict.__setitem__(self, key, val)
43
+ dict.__setitem__(self, val, key)
44
+
45
+ class ProgressStore(object):
46
+ """
47
+ Reads and stores seed progresses to a file.
48
+ """
49
+ def __init__(self, filename=None, continue_seed=True):
50
+ self.filename = filename
51
+ if continue_seed:
52
+ self.status = self.load()
53
+ else:
54
+ self.status = {}
55
+
56
+ def load(self):
57
+ if not os.path.exists(self.filename):
58
+ pass
59
+ elif os.stat(self.filename).st_mode & stat.S_IWOTH:
60
+ log.error('progress file (%s) is world writable, ignoring file',
61
+ self.filename)
62
+ else:
63
+ with open(self.filename, 'rb') as f:
64
+ try:
65
+ return pickle.load(f)
66
+ except (pickle.UnpicklingError, AttributeError,
67
+ EOFError, ImportError, IndexError):
68
+ log.error('unable to read progress file (%s), ignoring file',
69
+ self.filename)
70
+
71
+ return {}
72
+
73
+ def write(self):
74
+ try:
75
+ write_atomic(self.filename, pickle.dumps(self.status))
76
+ except (IOError, OSError) as ex:
77
+ log.error('unable to write seed progress: %s', ex)
78
+
79
+ def remove(self):
80
+ self.status = {}
81
+ if os.path.exists(self.filename):
82
+ os.remove(self.filename)
83
+
84
+ def get(self, task_identifier):
85
+ return self.status.get(task_identifier, None)
86
+
87
+ def add(self, task_identifier, progress_identifier):
88
+ self.status[task_identifier] = progress_identifier
89
+
90
+ class ProgressLog(object):
91
+ def __init__(self, out=None, silent=False, verbose=True, progress_store=None):
92
+ if not out:
93
+ out = sys.stdout
94
+ self.out = out
95
+ self._laststep = time.time()
96
+ self._lastprogress = 0
97
+
98
+ self.verbose = verbose
99
+ self.silent = silent
100
+ self.current_task_id = None
101
+ self.progress_store = progress_store
102
+
103
+ def log_message(self, msg):
104
+ self.out.write('[%s] %s\n' % (
105
+ timestamp(), msg,
106
+ ))
107
+ self.out.flush()
108
+
109
+ def log_step(self, progress):
110
+ if not self.verbose:
111
+ return
112
+ if (self._laststep + .5) < time.time():
113
+ # log progress at most every 500ms
114
+ self.out.write('[%s] %6.2f%%\t%-20s \r' % (
115
+ timestamp(), progress.progress*100, progress.progress_str,
116
+ ))
117
+ self.out.flush()
118
+ self._laststep = time.time()
119
+
120
+ def log_progress(self, progress, level, bbox, tiles):
121
+ progress_interval = 1
122
+ if not self.verbose:
123
+ progress_interval = 30
124
+
125
+ log_progess = False
126
+ if progress.progress == 1.0 or (self._lastprogress + progress_interval) < time.time():
127
+ self._lastprogress = time.time()
128
+ log_progess = True
129
+
130
+ if log_progess:
131
+ if self.progress_store and self.current_task_id:
132
+ self.progress_store.add(self.current_task_id,
133
+ progress.current_progress_identifier())
134
+ self.progress_store.write()
135
+
136
+ if self.silent:
137
+ return
138
+
139
+ if log_progess:
140
+ self.out.write('[%s] %2s %6.2f%% %s (%d tiles)\n' % (
141
+ timestamp(), level, progress.progress*100,
142
+ format_bbox(bbox), tiles))
143
+ self.out.flush()
144
+
145
+
146
+ def limit_sub_bbox(bbox, sub_bbox):
147
+ """
148
+ >>> limit_sub_bbox((0, 1, 10, 11), (-1, -1, 9, 8))
149
+ (0, 1, 9, 8)
150
+ >>> limit_sub_bbox((0, 0, 10, 10), (5, 2, 18, 18))
151
+ (5, 2, 10, 10)
152
+ """
153
+ minx = max(bbox[0], sub_bbox[0])
154
+ miny = max(bbox[1], sub_bbox[1])
155
+ maxx = min(bbox[2], sub_bbox[2])
156
+ maxy = min(bbox[3], sub_bbox[3])
157
+ return minx, miny, maxx, maxy
158
+
159
+ def timestamp():
160
+ return datetime.now().strftime('%H:%M:%S')
161
+
162
+ def format_bbox(bbox):
163
+ return ('%.5f, %.5f, %.5f, %.5f') % tuple(bbox)
164
+
165
+ def status_symbol(i, total):
166
+ """
167
+ >>> status_symbol(0, 1)
168
+ '0'
169
+ >>> [status_symbol(i, 4) for i in range(5)]
170
+ ['.', 'o', 'O', '0', 'X']
171
+ >>> [status_symbol(i, 10) for i in range(11)]
172
+ ['.', '.', 'o', 'o', 'o', 'O', 'O', '0', '0', '0', 'X']
173
+ """
174
+ symbols = list(' .oO0')
175
+ i += 1
176
+ if 0 < i > total:
177
+ return 'X'
178
+ else:
179
+ return symbols[int(math.ceil(i/(total/4)))]
180
+
181
+ class BackoffError(Exception):
182
+ pass
183
+
184
+ def exp_backoff(func, args=(), kw={}, max_repeat=10, start_backoff_sec=2,
185
+ exceptions=(Exception,), ignore_exceptions=tuple(), max_backoff=60):
186
+ n = 0
187
+ while True:
188
+ try:
189
+ result = func(*args, **kw)
190
+ except ignore_exceptions:
191
+ time.sleep(0.01)
192
+ except exceptions as ex:
193
+ if n >= max_repeat:
194
+ print("An error occured. Giving up", file=sys.stderr)
195
+ raise BackoffError
196
+ wait_for = start_backoff_sec * 2**n
197
+ if wait_for > max_backoff:
198
+ wait_for = max_backoff
199
+ print("An error occured. Retry in %d seconds: %r. Retries left: %d" %
200
+ (wait_for, ex, (max_repeat - n)), file=sys.stderr)
201
+ time.sleep(wait_for)
202
+ n += 1
203
+ else:
204
+ return result
205
+
206
+ def format_seed_task(task):
207
+ info = []
208
+ info.append(' %s:' % (task.md['name'], ))
209
+ if task.coverage is False:
210
+ info.append(" Empty coverage given for this task")
211
+ info.append(" Skipped")
212
+ return '\n'.join(info)
213
+
214
+ info.append(" Seeding cache '%s' with grid '%s' in %s" % (
215
+ task.md['cache_name'], task.md['grid_name'], task.grid.srs.srs_code))
216
+ if task.coverage:
217
+ info.append(' Limited to coverage in: %s (EPSG:4326)' % (format_bbox(task.coverage.extent.llbbox), ))
218
+ else:
219
+ info.append(' Complete grid: %s (EPSG:4326)' % (format_bbox(map_extent_from_grid(task.grid).llbbox), ))
220
+ info.append(' Levels: %s' % (task.levels, ))
221
+
222
+ if task.refresh_timestamp:
223
+ info.append(' Overwriting: tiles older than %s' %
224
+ datetime.fromtimestamp(task.refresh_timestamp))
225
+ elif task.refresh_timestamp == 0:
226
+ info.append(' Overwriting: all tiles')
227
+ else:
228
+ info.append(' Overwriting: no tiles')
229
+
230
+ return '\n'.join(info)
231
+
232
+ def format_cleanup_task(task):
233
+ info = []
234
+ info.append(' %s:' % (task.md['name'], ))
235
+ if task.coverage is False:
236
+ info.append(" Empty coverage given for this task")
237
+ info.append(" Skipped")
238
+ return '\n'.join(info)
239
+
240
+ info.append(" Cleaning up cache '%s' with grid '%s' in %s" % (
241
+ task.md['cache_name'], task.md['grid_name'], task.grid.srs.srs_code))
242
+ if task.coverage:
243
+ info.append(' Limited to coverage in: %s (EPSG:4326)' % (format_bbox(task.coverage.extent.llbbox), ))
244
+ else:
245
+ info.append(' Complete grid: %s (EPSG:4326)' % (format_bbox(map_extent_from_grid(task.grid).llbbox), ))
246
+ info.append(' Levels: %s' % (task.levels, ))
247
+
248
+ if task.remove_timestamp:
249
+ info.append(' Remove: tiles older than %s' %
250
+ datetime.fromtimestamp(task.remove_timestamp))
251
+ else:
252
+ info.append(' Remove: all tiles')
253
+
254
+ 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,46 @@
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
+ class Server(object):
22
+ names = tuple()
23
+ request_parser = lambda x: None
24
+ request_methods = ()
25
+
26
+ def handle(self, req):
27
+ try:
28
+ parsed_req = self.parse_request(req)
29
+ handler = getattr(self, parsed_req.request_handler_name)
30
+ return handler(parsed_req)
31
+ except RequestError as e:
32
+ return e.render()
33
+
34
+ def parse_request(self, req):
35
+ return self.request_parser(req)
36
+
37
+ def decorate_img(self, image, service, layers, environ, query_extent):
38
+ """ Callback that allows the ImageSource associated with a response to
39
+ be modified before it is returned. The callback is passed the
40
+ ImageSource instance and must return a valid ImageSource """
41
+ if 'mapproxy.decorate_img' in environ:
42
+ image = environ['mapproxy.decorate_img'](
43
+ image, service, layers, environ=environ, query_extent=query_extent)
44
+ return image
45
+
46
+
@@ -0,0 +1,356 @@
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 logging
22
+ import re
23
+
24
+ import os
25
+ import pkg_resources
26
+ import mimetypes
27
+ from collections import defaultdict
28
+
29
+ from mapproxy.config.config import base_config
30
+ from mapproxy.compat import PY2
31
+ from mapproxy.exception import RequestError
32
+ from mapproxy.service.base import Server
33
+ from mapproxy.response import Response
34
+ from mapproxy.srs import SRS, get_epsg_num
35
+ from mapproxy.layer import SRSConditional, CacheMapLayer, ResolutionConditional
36
+ from mapproxy.source.wms import WMSSource
37
+ from mapproxy.util.escape import escape_html
38
+
39
+ if PY2:
40
+ import urllib2
41
+ else:
42
+ from urllib import request as urllib2
43
+
44
+ from mapproxy.template import template_loader, bunch
45
+ env = {'bunch': bunch}
46
+ get_template = template_loader(__name__, 'templates', namespace=env)
47
+
48
+ # Used by plugins
49
+ extra_demo_server_handlers = set()
50
+
51
+ logger = logging.getLogger("demo")
52
+
53
+
54
+ def register_extra_demo_server_handler(handler):
55
+ """ Method used by plugins to register a new handler for the demo service.
56
+ The handler passed to this method is invoked by the DemoServer.handle()
57
+ method when receiving an incoming request, and let a chance to the
58
+ handler to process it, if it is relevant to it.
59
+
60
+ :param handler: New handler for incoming requests
61
+ :type handler: function that takes 2 arguments (DemoServer instance and req) and
62
+ returns a string with HTML content or None
63
+ """
64
+
65
+ extra_demo_server_handlers.add(handler)
66
+
67
+
68
+ extra_substitution_handlers = set()
69
+
70
+
71
+ def register_extra_demo_substitution_handler(handler):
72
+ """ Method used by plugins to register a new handler for doing substitutions
73
+ to the HTML template used by the demo service.
74
+ The handler passed to this method is invoked by the DemoServer._render_template()
75
+ method. The handler may modify the passed substitutions dictionary
76
+ argument. Keys of particular interest are 'extra_services_html_beginning'
77
+ and 'extra_services_html_end' to add HTML content before/after built-in
78
+ services.
79
+
80
+ :param handler: New handler for incoming requests
81
+ :type handler: function that takes 3 arguments(DemoServer instance, req and a substitutions dictionary argument).
82
+ """
83
+
84
+ extra_substitution_handlers.add(handler)
85
+
86
+
87
+ def static_filename(name):
88
+ if base_config().template_dir:
89
+ return os.path.join(base_config().template_dir, name)
90
+ else:
91
+ return pkg_resources.resource_filename(__name__, os.path.join('templates', name))
92
+
93
+ class DemoServer(Server):
94
+ names = ('demo',)
95
+
96
+ def __init__(self, layers, md, request_parser=None, tile_layers=None,
97
+ srs=None, image_formats=None, services=None, restful_template=None):
98
+ Server.__init__(self)
99
+ self.layers = layers
100
+ self.tile_layers = tile_layers or {}
101
+ self.md = md
102
+ self.image_formats = image_formats
103
+ filter_image_format = []
104
+ for format in self.image_formats:
105
+ if 'image/jpeg' == format or 'image/png' == format:
106
+ filter_image_format.append(format)
107
+ self.image_formats = filter_image_format
108
+ self.srs = srs
109
+ self.services = services or []
110
+ self.restful_template = restful_template
111
+
112
+ @staticmethod
113
+ def get_capabilities_url(service_path, req):
114
+ if 'type' in req.args and req.args['type'] == 'external':
115
+ url = escape_html(req.script_url) + service_path
116
+ else:
117
+ url = req.server_script_url + service_path
118
+ return url
119
+
120
+ @staticmethod
121
+ def valid_url(url):
122
+ pattern = re.compile("^https?://")
123
+ if pattern.match(url):
124
+ return True
125
+ else:
126
+ logging.warn(f"A request was blocked that was trying to access a non-http resource: {url}")
127
+ return False
128
+
129
+ @staticmethod
130
+ def read_capabilities(url):
131
+ resp = urllib2.urlopen(url)
132
+ return escape_html(resp.read().decode())
133
+
134
+ def handle(self, req):
135
+ if req.path.startswith('/demo/static/'):
136
+ if '..' in req.path:
137
+ return Response('file not found', content_type='text/plain', status=404)
138
+ filename = req.path.lstrip('/')
139
+ filename = static_filename(filename)
140
+ if not os.path.isfile(filename):
141
+ return Response('file not found', content_type='text/plain', status=404)
142
+ type, encoding = mimetypes.guess_type(filename)
143
+ return Response(open(filename, 'rb'), content_type=type)
144
+
145
+ # we don't authorize the static files (css, js)
146
+ # since they are not confidential
147
+ try:
148
+ authorized = self.authorized_demo(req.environ)
149
+ except RequestError as ex:
150
+ return ex.render()
151
+ if not authorized:
152
+ return Response('forbidden', content_type='text/plain', status=403)
153
+
154
+ for handler in extra_demo_server_handlers:
155
+ demo = handler(self, req)
156
+ if demo is not None:
157
+ return Response(demo, content_type='text/html')
158
+
159
+ if 'wms_layer' in req.args:
160
+ demo = self._render_wms_template('demo/wms_demo.html', req)
161
+ elif 'tms_layer' in req.args:
162
+ demo = self._render_tms_template('demo/tms_demo.html', req)
163
+ elif 'wmts_layer' in req.args:
164
+ demo = self._render_wmts_template('demo/wmts_demo.html', req)
165
+ elif 'wms_capabilities' in req.args:
166
+ url = self.get_capabilities_url('/service?REQUEST=GetCapabilities&SERVICE=WMS', req)
167
+ if not self.valid_url(url):
168
+ return Response('bad request', content_type='text/plain', status=400)
169
+ capabilities = self.read_capabilities(url)
170
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMS', url)
171
+ elif 'wmsc_capabilities' in req.args:
172
+ url = self.get_capabilities_url('/service?REQUEST=GetCapabilities&SERVICE=WMS&tiled=true', req)
173
+ if not self.valid_url(url):
174
+ return Response('bad request', content_type='text/plain', status=400)
175
+ capabilities = self.read_capabilities(url)
176
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMS-C', url)
177
+ elif 'wmts_capabilities_kvp' in req.args:
178
+ url = self.get_capabilities_url('/service?REQUEST=GetCapabilities&SERVICE=WMTS', req)
179
+ if not self.valid_url(url):
180
+ return Response('bad request', content_type='text/plain', status=400)
181
+ capabilities = self.read_capabilities(url)
182
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMTS', url)
183
+ elif 'wmts_capabilities' in req.args:
184
+ url = self.get_capabilities_url('/wmts/1.0.0/WMTSCapabilities.xml', req)
185
+ if not self.valid_url(url):
186
+ return Response('bad request', content_type='text/plain', status=400)
187
+ capabilities = self.read_capabilities(url)
188
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'WMTS', url)
189
+ elif 'tms_capabilities' in req.args:
190
+ if 'layer' in req.args and 'srs' in req.args:
191
+ # prevent dir traversal (seems it's not possible with urllib2, but better safe than sorry)
192
+ layer = escape_html(req.args['layer'].replace('..', ''))
193
+ srs = escape_html(req.args['srs'].replace('..', ''))
194
+ service_path = f'/tms/1.0.0/{layer}/{srs}'
195
+ else:
196
+ service_path = '/tms/1.0.0/'
197
+ url = self.get_capabilities_url(service_path, req)
198
+ if not self.valid_url(url):
199
+ return Response('bad request', content_type='text/plain', status=400)
200
+ capabilities = self.read_capabilities(url)
201
+ demo = self._render_capabilities_template('demo/capabilities_demo.html', capabilities, 'TMS', url)
202
+ elif req.path == '/demo/':
203
+ demo = self._render_template(req, 'demo/demo.html')
204
+ else:
205
+ resp = Response('', status=301)
206
+ resp.headers['Location'] = escape_html(req.script_url).rstrip('/') + '/demo/'
207
+ return resp
208
+ return Response(demo, content_type='text/html')
209
+
210
+ def layer_srs(self, layer):
211
+ """
212
+ Return a list tuples with title and name of all SRS for the layer.
213
+ The title of SRS that are native to the layer are suffixed with a '*'.
214
+ """
215
+ cached_srs = []
216
+ for map_layer in layer.map_layers:
217
+ # TODO unify map_layers interface
218
+ if isinstance(map_layer, SRSConditional):
219
+ for srs_key in map_layer.srs_map.keys():
220
+ cached_srs.append(srs_key.srs_code)
221
+ elif isinstance(map_layer, CacheMapLayer):
222
+ cached_srs.append(map_layer.grid.srs.srs_code)
223
+ elif isinstance(map_layer, ResolutionConditional):
224
+ cached_srs.append(map_layer.srs.srs_code)
225
+ elif isinstance(map_layer, WMSSource):
226
+ if map_layer.supported_srs:
227
+ for supported_srs in map_layer.supported_srs:
228
+ cached_srs.append(supported_srs.srs_code)
229
+
230
+ uncached_srs = []
231
+
232
+ for srs_code in self.srs:
233
+ if srs_code not in cached_srs:
234
+ uncached_srs.append(srs_code)
235
+
236
+ def get_srs_key(srs):
237
+ epsg_num = get_epsg_num(srs)
238
+ return str(epsg_num if epsg_num else srs)
239
+
240
+ sorted_cached_srs = sorted(cached_srs, key=lambda srs: get_srs_key(srs))
241
+ sorted_uncached_srs = sorted(uncached_srs, key=lambda srs: get_srs_key(srs))
242
+ sorted_cached_srs = [(s + '*', s) for s in sorted_cached_srs]
243
+ sorted_uncached_srs = [(s, s) for s in sorted_uncached_srs]
244
+ return sorted_cached_srs + sorted_uncached_srs
245
+
246
+ def _render_template(self, req, template):
247
+ template = get_template(template, default_inherit="demo/static.html")
248
+ tms_tile_layers = defaultdict(list)
249
+ for layer in self.tile_layers:
250
+ name = self.tile_layers[layer].md.get('name')
251
+ tms_tile_layers[name].append(self.tile_layers[layer])
252
+ wmts_layers = tms_tile_layers.copy()
253
+
254
+ substitutions = dict(
255
+ extra_services_html_beginning='',
256
+ extra_services_html_end='',
257
+ layers=self.layers,
258
+ formats=self.image_formats,
259
+ srs=self.srs,
260
+ layer_srs=self.layer_srs,
261
+ tms_layers=tms_tile_layers,
262
+ wmts_layers=wmts_layers,
263
+ services=self.services
264
+ )
265
+
266
+ for add_substitution in extra_substitution_handlers:
267
+ add_substitution(self, req, substitutions)
268
+
269
+ return template.substitute(substitutions)
270
+
271
+ def _render_wms_template(self, template, req):
272
+ template = get_template(template, default_inherit="demo/static.html")
273
+ layer = self.layers[req.args['wms_layer']]
274
+ srs = escape_html(req.args['srs'])
275
+ bbox = layer.extent.bbox_for(SRS(srs))
276
+ width = bbox[2] - bbox[0]
277
+ height = bbox[3] - bbox[1]
278
+ min_res = max(width/256, height/256)
279
+ return template.substitute(layer=layer,
280
+ image_formats=self.image_formats,
281
+ format=escape_html(req.args['format']),
282
+ srs=srs,
283
+ layer_srs=self.layer_srs,
284
+ bbox=bbox,
285
+ res=min_res)
286
+
287
+ def _render_tms_template(self, template, req):
288
+ template = get_template(template, default_inherit="demo/static.html")
289
+ for layer in self.tile_layers.values():
290
+ if (layer.name == req.args['tms_layer'] and
291
+ layer.grid.srs.srs_code == req.args['srs']):
292
+ tile_layer = layer
293
+ break
294
+
295
+ resolutions = tile_layer.grid.tile_sets
296
+ res = []
297
+ for level, resolution in resolutions:
298
+ res.append(resolution)
299
+
300
+ if tile_layer.grid.srs.is_latlong:
301
+ units = 'degree'
302
+ else:
303
+ units = 'm'
304
+
305
+ if tile_layer.grid.profile == 'local':
306
+ add_res_to_options = True
307
+ else:
308
+ add_res_to_options = False
309
+ return template.substitute(layer=tile_layer,
310
+ srs=escape_html(req.args['srs']),
311
+ format=escape_html(req.args['format']),
312
+ resolutions=res,
313
+ units=units,
314
+ add_res_to_options=add_res_to_options,
315
+ all_tile_layers=self.tile_layers)
316
+
317
+ def _render_wmts_template(self, template, req):
318
+ template = get_template(template, default_inherit="demo/static.html")
319
+ for layer in self.tile_layers.values():
320
+ if (layer.name == req.args['wmts_layer'] and
321
+ layer.grid.srs.srs_code == req.args['srs']):
322
+ wmts_layer = layer
323
+ break
324
+
325
+ restful_url = self.restful_template.replace('{Layer}', wmts_layer.name, 1)
326
+ if '{Format}' in restful_url:
327
+ restful_url = restful_url.replace('{Format}', wmts_layer.format)
328
+
329
+ if wmts_layer.grid.srs.is_latlong:
330
+ units = 'degree'
331
+ else:
332
+ units = 'm'
333
+ return template.substitute(layer=wmts_layer,
334
+ matrix_set=wmts_layer.grid.name,
335
+ format=escape_html(req.args['format']),
336
+ srs=escape_html(req.args['srs']),
337
+ resolutions=wmts_layer.grid.resolutions,
338
+ units=units,
339
+ all_tile_layers=self.tile_layers,
340
+ restful_url=restful_url)
341
+
342
+ def _render_capabilities_template(self, template, xmlfile, service, url):
343
+ template = get_template(template, default_inherit="demo/static.html")
344
+ return template.substitute(capabilities = xmlfile,
345
+ service = service,
346
+ url = url)
347
+
348
+ def authorized_demo(self, environ):
349
+ if 'mapproxy.authorize' in environ:
350
+ result = environ['mapproxy.authorize']('demo', [], environ=environ)
351
+ if result['authorized'] == 'unauthenticated':
352
+ raise RequestError('unauthorized', status=401)
353
+ if result['authorized'] == 'full':
354
+ return True
355
+ return False
356
+ return True