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/cache/tile.py ADDED
@@ -0,0 +1,699 @@
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
+ Tile caching (creation, caching and retrieval of tiles).
18
+
19
+ .. digraph:: Schematic Call Graph
20
+
21
+ ranksep = 0.1;
22
+ node [shape="box", height="0", width="0"]
23
+
24
+ cl [label="CacheMapLayer" href="<mapproxy.core.layer.CacheMapLayer>"]
25
+ tm [label="TileManager", href="<TileManager>"];
26
+ fc [label="FileCache", href="<FileCache>"];
27
+ s [label="Source", href="<mapproxy.core.source.Source>"];
28
+
29
+ {
30
+ cl -> tm [label="load_tile_coords"];
31
+ tm -> fc [label="load\\nstore\\nis_cached"];
32
+ tm -> s [label="get_map"]
33
+ }
34
+
35
+
36
+ """
37
+ from functools import partial
38
+ from contextlib import contextmanager
39
+ from mapproxy.grid import MetaGrid
40
+ from mapproxy.image import BlankImageSource
41
+ from mapproxy.image.opts import ImageOptions
42
+ from mapproxy.image.merge import merge_images
43
+ from mapproxy.image.tile import TileSplitter, TiledImage
44
+ from mapproxy.layer import MapQuery, BlankImage
45
+ from mapproxy.source import SourceError
46
+ from mapproxy.util import async_
47
+ from mapproxy.util.py import reraise, reraise_exception
48
+ import sys
49
+ import logging
50
+ log = logging.getLogger('mapproxy.cache.tile')
51
+
52
+
53
+ class TileManager(object):
54
+ """
55
+ Manages tiles for a single grid.
56
+ Loads tiles from the cache, creates new tiles from sources and stores them
57
+ into the cache, or removes tiles.
58
+
59
+ :param pre_store_filter: a list with filter. each filter will be called
60
+ with a tile before it will be stored to disc. the filter should
61
+ return this or a new tile object.
62
+ """
63
+ def __init__(self, grid, cache, sources, format, locker, image_opts=None, request_format=None,
64
+ meta_buffer=None, meta_size=None, minimize_meta_requests=False, identifier=None,
65
+ pre_store_filter=None, concurrent_tile_creators=1, tile_creator_class=None,
66
+ bulk_meta_tiles=False,
67
+ rescale_tiles=0,
68
+ cache_rescaled_tiles=False,
69
+ dimensions=None
70
+ ):
71
+ self.grid = grid
72
+ self.cache = cache
73
+ self.locker = locker
74
+ self.identifier = identifier
75
+ self.meta_grid = None
76
+ self.format = format
77
+ self.image_opts = image_opts
78
+ self.request_format = request_format or format
79
+ self.sources = sources
80
+ self.minimize_meta_requests = minimize_meta_requests
81
+ self._expire_timestamp = None
82
+ self._refresh_before = {}
83
+ self.pre_store_filter = pre_store_filter or []
84
+ self.concurrent_tile_creators = concurrent_tile_creators
85
+ self.tile_creator_class = tile_creator_class or TileCreator
86
+ self.dimensions = dimensions
87
+
88
+ self.rescale_tiles = rescale_tiles
89
+ self.cache_rescaled_tiles = cache_rescaled_tiles
90
+
91
+ if meta_buffer or (meta_size and not meta_size == [1, 1]):
92
+ if all(source.supports_meta_tiles for source in sources):
93
+ self.meta_grid = MetaGrid(grid, meta_size=meta_size, meta_buffer=meta_buffer)
94
+ elif any(source.supports_meta_tiles for source in sources):
95
+ raise ValueError('meta tiling configured but not supported by all sources')
96
+ elif meta_size and not meta_size == [1, 1] and bulk_meta_tiles:
97
+ # meta tiles configured but all sources are tiled
98
+ # use bulk_meta_tile mode that download tiles in parallel
99
+ self.meta_grid = MetaGrid(grid, meta_size=meta_size, meta_buffer=0)
100
+ self.tile_creator_class = partial(self.tile_creator_class, bulk_meta_tiles=True)
101
+
102
+ @contextmanager
103
+ def session(self):
104
+ """
105
+ Context manager for access to the cache. Cleans up after usage
106
+ for connection based caches.
107
+
108
+ >>> with tile_manager.session(): #doctest: +SKIP
109
+ ... tile_manager.load_tile_coords(tile_coords)
110
+
111
+ """
112
+ yield
113
+ self.cleanup()
114
+
115
+ def cleanup(self):
116
+ if hasattr(self.cache, 'cleanup'):
117
+ self.cache.cleanup()
118
+
119
+ def load_tile_coord(self, tile_coord, dimensions=None, with_metadata=False):
120
+ return self.load_tile_coords(
121
+ [tile_coord], dimensions=dimensions, with_metadata=with_metadata,
122
+ )[0]
123
+
124
+
125
+ def load_tile_coords(self, tile_coords, dimensions=None, with_metadata=False):
126
+ tiles = TileCollection(tile_coords)
127
+ rescale_till_zoom = 0
128
+ if self.rescale_tiles:
129
+ rescaled_tiles = {}
130
+
131
+ for t in tiles.tiles:
132
+ # Use zoom level from first None tile.
133
+ if t.coord is not None:
134
+ rescale_till_zoom = t.coord[2] + self.rescale_tiles
135
+ break
136
+ else:
137
+ return tiles
138
+
139
+ if rescale_till_zoom < 0:
140
+ rescale_till_zoom = 0
141
+ if rescale_till_zoom > self.grid.levels:
142
+ rescale_till_zoom = self.grid.levels
143
+
144
+ tiles = self._load_tile_coords(
145
+ tiles, dimensions=dimensions, with_metadata=with_metadata,
146
+ rescale_till_zoom=rescale_till_zoom, rescaled_tiles={},
147
+ )
148
+
149
+ for t in tiles.tiles:
150
+ # Remove our internal marker source, for missing tiles.
151
+ if t.source is RESCALE_TILE_MISSING:
152
+ t.source = None
153
+
154
+ return tiles
155
+
156
+ def _load_tile_coords(self, tiles, dimensions=None, with_metadata=False,
157
+ rescale_till_zoom=None, rescaled_tiles=None
158
+ ):
159
+ uncached_tiles = []
160
+
161
+ if rescaled_tiles:
162
+ for t in tiles:
163
+ if t.coord in rescaled_tiles:
164
+ t.source = rescaled_tiles[t.coord].source
165
+
166
+ # load all in batch
167
+ self.cache.load_tiles(tiles, with_metadata, dimensions=dimensions)
168
+
169
+ for tile in tiles:
170
+ if tile.coord is not None and not self.is_cached(tile, dimensions=dimensions):
171
+ # missing or staled
172
+ uncached_tiles.append(tile)
173
+
174
+ if uncached_tiles:
175
+ creator = self.creator(dimensions=dimensions)
176
+ created_tiles = creator.create_tiles(uncached_tiles)
177
+ if not created_tiles and self.rescale_tiles:
178
+ created_tiles = [self._scaled_tile(t, rescale_till_zoom, rescaled_tiles) for t in uncached_tiles]
179
+
180
+ for created_tile in created_tiles:
181
+ if created_tile.coord in tiles:
182
+ tiles[created_tile.coord].source = created_tile.source
183
+
184
+ return tiles
185
+
186
+ def remove_tile_coords(self, tile_coords, dimensions=None):
187
+ tiles = TileCollection(tile_coords)
188
+ self.cache.remove_tiles(tiles)
189
+
190
+ def creator(self, dimensions=None):
191
+ return self.tile_creator_class(self, dimensions=dimensions)
192
+
193
+ def lock(self, tile):
194
+ if self.meta_grid:
195
+ tile = Tile(self.meta_grid.main_tile(tile.coord))
196
+ return self.locker.lock(tile)
197
+
198
+ def is_cached(self, tile, dimensions=None):
199
+ """
200
+ Return True if the tile is cached.
201
+ """
202
+ if isinstance(tile, tuple):
203
+ tile = Tile(tile)
204
+ if tile.coord is None:
205
+ return True
206
+ cached = self.cache.is_cached(tile, dimensions=dimensions)
207
+ max_mtime = self.expire_timestamp(tile)
208
+ if cached and max_mtime is not None:
209
+ self.cache.load_tile_metadata(tile)
210
+ # file time stamp must be rounded to integer since time conversion functions
211
+ # mktime and timetuple strip decimals from seconds
212
+ stale = int(tile.timestamp) <= max_mtime
213
+ if stale:
214
+ cached = False
215
+ return cached
216
+
217
+ def is_stale(self, tile, dimensions=None):
218
+ """
219
+ Return True if tile exists _and_ is expired.
220
+ """
221
+ if isinstance(tile, tuple):
222
+ tile = Tile(tile)
223
+ if self.cache.is_cached(tile, dimensions=dimensions):
224
+ # tile exists
225
+ if not self.is_cached(tile, dimensions=dimensions):
226
+ # expired
227
+ return True
228
+ return False
229
+ return False
230
+
231
+ def expire_timestamp(self, tile=None):
232
+ """
233
+ Return the timestamp until which a tile should be accepted as up-to-date,
234
+ or ``None`` if the tiles should not expire.
235
+
236
+ :note: Returns _expire_timestamp by default.
237
+ """
238
+ if self._refresh_before:
239
+ from mapproxy.seed.config import before_timestamp_from_options
240
+ return before_timestamp_from_options(self._refresh_before)
241
+ return self._expire_timestamp
242
+
243
+ def apply_tile_filter(self, tile):
244
+ """
245
+ Apply all `pre_store_filter` to this tile.
246
+ Returns filtered tile.
247
+ """
248
+ if tile.stored:
249
+ return tile
250
+
251
+ for img_filter in self.pre_store_filter:
252
+ tile = img_filter(tile)
253
+ return tile
254
+
255
+ def _scaled_tile(self, tile, stop_zoom, rescaled_tiles):
256
+ """
257
+ Try to load tile by loading, scaling and clipping tiles from zoom levels above or
258
+ below. stop_zoom determines if tiles from above should be scaled up, or if tiles
259
+ from below should be scaled down.
260
+ Returns an empty Tile if tile zoom level is stop_zoom.
261
+ """
262
+ if tile.coord in rescaled_tiles:
263
+ return rescaled_tiles[tile.coord]
264
+
265
+ # Cache tile in rescaled_tiles. We initially set source to a fixed
266
+ # BlankImageSource and overwrite it if we actually rescaled the tile.
267
+ tile.source = RESCALE_TILE_MISSING
268
+ rescaled_tiles[tile.coord] = tile
269
+
270
+ tile_bbox = self.grid.tile_bbox(tile.coord)
271
+ current_zoom = tile.coord[2]
272
+ if stop_zoom == current_zoom:
273
+ return tile
274
+ if stop_zoom > current_zoom:
275
+ src_level = current_zoom + 1
276
+ else:
277
+ src_level = current_zoom - 1
278
+
279
+ src_bbox, src_tile_grid, affected_tile_coords = self.grid.get_affected_level_tiles(tile_bbox, src_level)
280
+
281
+ affected_tiles = TileCollection(affected_tile_coords)
282
+ for t in affected_tiles:
283
+ # Add sources of cached tiles, to avoid loading same tile multiple times
284
+ # loading recursive.
285
+ if t.coord in rescaled_tiles:
286
+ t.source = rescaled_tiles[t.coord].source
287
+
288
+ tile_collection = self._load_tile_coords(
289
+ affected_tiles,
290
+ rescale_till_zoom=stop_zoom,
291
+ rescaled_tiles=rescaled_tiles,
292
+ )
293
+
294
+ if tile_collection.blank:
295
+ return tile
296
+
297
+ tile_sources = []
298
+ for t in tile_collection:
299
+ # Replace RESCALE_TILE_MISSING with None, before transforming tiles.
300
+ tile_sources.append(t.source if t.source is not RESCALE_TILE_MISSING else None)
301
+
302
+ tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs,
303
+ tile_grid=src_tile_grid, tile_size=self.grid.tile_size)
304
+ tile.source = tiled_image.transform(tile_bbox, self.grid.srs, self.grid.tile_size, self.image_opts)
305
+
306
+ if self.cache_rescaled_tiles:
307
+ self.cache.store_tile(tile)
308
+ return tile
309
+
310
+ # RESCALE_TILE_MISSING is a dummy source to prevent a tile cache from loading
311
+ # a tile that we already found out is missing.
312
+ RESCALE_TILE_MISSING = BlankImageSource((256, 256), ImageOptions())
313
+
314
+ class TileCreator(object):
315
+ def __init__(self, tile_mgr, dimensions=None, image_merger=None, bulk_meta_tiles=False):
316
+ self.cache = tile_mgr.cache
317
+ self.sources = tile_mgr.sources
318
+ self.grid = tile_mgr.grid
319
+ self.meta_grid = tile_mgr.meta_grid
320
+ self.bulk_meta_tiles = bulk_meta_tiles
321
+ self.tile_mgr = tile_mgr
322
+ self.dimensions = dimensions
323
+ self.image_merger = image_merger
324
+
325
+ def is_cached(self, tile, dimensions=None):
326
+ """
327
+ Return True if the tile is cached.
328
+ """
329
+ return self.tile_mgr.is_cached(tile, dimensions=dimensions)
330
+
331
+ def is_stale(self, tile):
332
+ """
333
+ Return True if the tile exists in cache and is expired.
334
+ """
335
+ return self.tile_mgr.is_stale(tile)
336
+
337
+ def create_tiles(self, tiles):
338
+ if not self.sources:
339
+ return []
340
+ if not self.meta_grid:
341
+ created_tiles = self._create_single_tiles(tiles)
342
+ elif self.tile_mgr.minimize_meta_requests and len(tiles) > 1:
343
+ # use minimal requests only for mulitple tile requests (ie not for TMS)
344
+ meta_tile = self.meta_grid.minimal_meta_tile([t.coord for t in tiles])
345
+ created_tiles = self._create_meta_tile(meta_tile)
346
+ else:
347
+ meta_tiles = []
348
+ meta_bboxes = set()
349
+ for tile in tiles:
350
+ meta_tile = self.meta_grid.meta_tile(tile.coord)
351
+ if meta_tile.bbox not in meta_bboxes:
352
+ meta_tiles.append(meta_tile)
353
+ meta_bboxes.add(meta_tile.bbox)
354
+
355
+ created_tiles = self._create_meta_tiles(meta_tiles)
356
+
357
+ return created_tiles
358
+
359
+ def _create_single_tiles(self, tiles):
360
+ if self.tile_mgr.concurrent_tile_creators > 1 and len(tiles) > 1:
361
+ return self._create_threaded(self._create_single_tile, tiles)
362
+
363
+ created_tiles = []
364
+ for tile in tiles:
365
+ created_tiles.extend(self._create_single_tile(tile))
366
+ return created_tiles
367
+
368
+ def _create_threaded(self, create_func, tiles):
369
+ result = []
370
+ async_pool = async_.Pool(self.tile_mgr.concurrent_tile_creators)
371
+ for new_tiles in async_pool.imap(create_func, tiles):
372
+ result.extend(new_tiles)
373
+ return result
374
+
375
+ def _create_single_tile(self, tile, dimensions=None):
376
+ tile_bbox = self.grid.tile_bbox(tile.coord)
377
+ query = MapQuery(tile_bbox, self.grid.tile_size, self.grid.srs,
378
+ self.tile_mgr.request_format, dimensions=self.dimensions)
379
+ with self.tile_mgr.lock(tile):
380
+ if not self.is_cached(tile, dimensions=dimensions):
381
+ source = None
382
+ try:
383
+ source = self._query_sources(query)
384
+ # if source is not available, try to serve tile in cache
385
+ except SourceError as e:
386
+ if self.is_stale(tile):
387
+ self.cache.load_tile(tile)
388
+ else:
389
+ reraise_exception(e, sys.exc_info())
390
+ if not source: return []
391
+ if source.authorize_stale and self.is_stale(tile):
392
+ # The configuration authorises blank tiles generated by the error_handler
393
+ # to be replaced by stale tiles from cache.
394
+ self.cache.load_tile(tile)
395
+ return [tile]
396
+ if self.tile_mgr.image_opts != source.image_opts:
397
+ # call as_buffer to force conversion into cache format
398
+ source.as_buffer(self.tile_mgr.image_opts)
399
+ source.image_opts = self.tile_mgr.image_opts
400
+ tile.source = source
401
+ tile.cacheable = source.cacheable
402
+ tile = self.tile_mgr.apply_tile_filter(tile)
403
+ if source.cacheable:
404
+ self.cache.store_tile(tile)
405
+ else:
406
+ self.cache.load_tile(tile)
407
+ return [tile]
408
+
409
+ def _query_sources(self, query):
410
+ """
411
+ Query all sources and return the results as a single ImageSource.
412
+ Multiple sources will be merged into a single image.
413
+ """
414
+
415
+ # directly return get_map without merge if ...
416
+ if (len(self.sources) == 1 and
417
+ not self.image_merger and # no special image_merger (like BandMerger)
418
+ not (self.sources[0].coverage and # no clipping coverage
419
+ self.sources[0].coverage.clip and
420
+ self.sources[0].coverage.intersects(query.bbox, query.srs))
421
+ ):
422
+ try:
423
+ return self.sources[0].get_map(query)
424
+ except BlankImage:
425
+ return None
426
+
427
+ def get_map_from_source(source):
428
+ try:
429
+ img = source.get_map(query)
430
+ except BlankImage:
431
+ return None, None
432
+ else:
433
+ return (img, source.coverage)
434
+
435
+ layers = []
436
+ for layer in async_.imap(get_map_from_source, self.sources):
437
+ if layer[0] is not None:
438
+ layers.append(layer)
439
+
440
+ return merge_images(layers, size=query.size, bbox=query.bbox, bbox_srs=query.srs,
441
+ image_opts=self.tile_mgr.image_opts, merger=self.image_merger)
442
+
443
+ def _create_meta_tiles(self, meta_tiles):
444
+ if self.bulk_meta_tiles:
445
+ created_tiles = []
446
+ for meta_tile in meta_tiles:
447
+ created_tiles.extend(self._create_bulk_meta_tile(meta_tile))
448
+ return created_tiles
449
+
450
+ if self.tile_mgr.concurrent_tile_creators > 1 and len(meta_tiles) > 1:
451
+ return self._create_threaded(self._create_meta_tile, meta_tiles)
452
+
453
+ created_tiles = []
454
+ for meta_tile in meta_tiles:
455
+ created_tiles.extend(self._create_meta_tile(meta_tile))
456
+ return created_tiles
457
+
458
+ def _create_meta_tile(self, meta_tile):
459
+ """
460
+ _create_meta_tile queries a single meta tile and splits it into
461
+ tiles.
462
+ """
463
+ tile_size = self.grid.tile_size
464
+ query = MapQuery(meta_tile.bbox, meta_tile.size, self.grid.srs, self.tile_mgr.request_format,
465
+ dimensions=self.dimensions)
466
+ main_tile = Tile(meta_tile.main_tile_coord)
467
+ with self.tile_mgr.lock(main_tile):
468
+ if not all(self.is_cached(t, dimensions=self.dimensions) for t in meta_tile.tiles if t is not None):
469
+ meta_tile_image = self._query_sources(query)
470
+ if not meta_tile_image: return []
471
+ splitted_tiles = split_meta_tiles(meta_tile_image, meta_tile.tile_patterns,
472
+ tile_size, self.tile_mgr.image_opts)
473
+ splitted_tiles = [self.tile_mgr.apply_tile_filter(t) for t in splitted_tiles]
474
+ if meta_tile_image.cacheable:
475
+ self.cache.store_tiles(splitted_tiles,dimensions=self.dimensions)
476
+ return splitted_tiles
477
+ # else
478
+ tiles = [Tile(coord) for coord in meta_tile.tiles]
479
+ self.cache.load_tiles(tiles, dimensions=self.dimensions)
480
+ return tiles
481
+
482
+ def _create_bulk_meta_tile(self, meta_tile):
483
+ """
484
+ _create_bulk_meta_tile queries each tile of the meta tile in parallel
485
+ (using concurrent_tile_creators).
486
+ """
487
+ tile_size = self.grid.tile_size
488
+ main_tile = Tile(meta_tile.main_tile_coord)
489
+ with self.tile_mgr.lock(main_tile):
490
+ if not all(self.is_cached(t, dimensions=self.dimensions) for t in meta_tile.tiles if t is not None):
491
+ async_pool = async_.Pool(self.tile_mgr.concurrent_tile_creators)
492
+ def query_tile(coord):
493
+ try:
494
+ query = MapQuery(self.grid.tile_bbox(coord), tile_size, self.grid.srs, self.tile_mgr.request_format,
495
+ dimensions=self.dimensions)
496
+ tile_image = self._query_sources(query)
497
+ if tile_image is None:
498
+ return None
499
+
500
+ if self.tile_mgr.image_opts != tile_image.image_opts:
501
+ # call as_buffer to force conversion into cache format
502
+ tile_image.as_buffer(self.tile_mgr.image_opts)
503
+
504
+ tile = Tile(coord, cacheable=tile_image.cacheable)
505
+ tile.source = tile_image
506
+ tile = self.tile_mgr.apply_tile_filter(tile)
507
+ except BlankImage:
508
+ return None
509
+ else:
510
+ return tile
511
+
512
+ tiles = []
513
+ for tile_task in async_pool.imap(query_tile,
514
+ [t for t in meta_tile.tiles if t is not None],
515
+ use_result_objects=True,
516
+ ):
517
+ if tile_task.exception is None:
518
+ tile = tile_task.result
519
+ if tile is not None:
520
+ tiles.append(tile)
521
+ else:
522
+ ex = tile_task.exception
523
+ async_pool.shutdown(True)
524
+ reraise(ex)
525
+
526
+ self.cache.store_tiles([t for t in tiles if t.cacheable])
527
+ return tiles
528
+
529
+ # else
530
+ tiles = [Tile(coord) for coord in meta_tile.tiles]
531
+ self.cache.load_tiles(tiles, dimensions=self.dimensions)
532
+ return tiles
533
+
534
+
535
+ class Tile(object):
536
+ """
537
+ Internal data object for all tiles. Stores the tile-``coord`` and the tile data.
538
+
539
+ :ivar source: the data of this tile
540
+ :type source: ImageSource
541
+ """
542
+ def __init__(self, coord, source=None, cacheable=True):
543
+ self.coord = coord
544
+ self.source = source
545
+ self.location = None
546
+ self.stored = False
547
+ self._cacheable = cacheable
548
+ self.size = None
549
+ self.timestamp = None
550
+
551
+ def _cacheable_get(self):
552
+ return CacheInfo(cacheable=self._cacheable, timestamp=self.timestamp,
553
+ size=self.size)
554
+
555
+ def _cacheable_set(self, cacheable):
556
+ if isinstance(cacheable, bool):
557
+ self._cacheable = cacheable
558
+ else: # assume cacheable is CacheInfo
559
+ self._cacheable = cacheable.cacheable
560
+ self.timestamp = cacheable.timestamp
561
+ self.size = cacheable.size
562
+
563
+ cacheable = property(_cacheable_get, _cacheable_set)
564
+
565
+ def source_buffer(self, *args, **kw):
566
+ if self.source is not None:
567
+ return self.source.as_buffer(*args, **kw)
568
+ else:
569
+ return None
570
+
571
+ def source_image(self, *args, **kw):
572
+ if self.source is not None:
573
+ return self.source.as_image(*args, **kw)
574
+ else:
575
+ return None
576
+
577
+ def is_missing(self):
578
+ """
579
+ Returns ``True`` when the tile has no ``data``, except when the ``coord``
580
+ is ``None``. It doesn't check if the tile exists.
581
+
582
+ >>> Tile((1, 2, 3)).is_missing()
583
+ True
584
+ >>> Tile((1, 2, 3), './tmp/foo').is_missing()
585
+ False
586
+ >>> Tile(None).is_missing()
587
+ False
588
+ """
589
+ if self.coord is None:
590
+ return False
591
+ return self.source is None
592
+
593
+ def __eq__(self, other):
594
+ """
595
+ >>> Tile((0, 0, 1)) == Tile((0, 0, 1))
596
+ True
597
+ >>> Tile((0, 0, 1)) == Tile((1, 0, 1))
598
+ False
599
+ >>> Tile((0, 0, 1)) == None
600
+ False
601
+ """
602
+ if isinstance(other, Tile):
603
+ return (self.coord == other.coord and
604
+ self.source == other.source)
605
+ else:
606
+ return NotImplemented
607
+ def __ne__(self, other):
608
+ """
609
+ >>> Tile((0, 0, 1)) != Tile((0, 0, 1))
610
+ False
611
+ >>> Tile((0, 0, 1)) != Tile((1, 0, 1))
612
+ True
613
+ >>> Tile((0, 0, 1)) != None
614
+ True
615
+ """
616
+ equal_result = self.__eq__(other)
617
+ if equal_result is NotImplemented:
618
+ return NotImplemented
619
+ else:
620
+ return not equal_result
621
+
622
+ def __repr__(self):
623
+ return 'Tile(%r, source=%r)' % (self.coord, self.source)
624
+
625
+ class CacheInfo(object):
626
+ def __init__(self, cacheable=True, timestamp=None, size=None):
627
+ self.cacheable = cacheable
628
+ self.timestamp = timestamp
629
+ self.size = size
630
+
631
+ def __bool__(self):
632
+ return self.cacheable
633
+
634
+ # PY2 compat
635
+ __nonzero__ = __bool__
636
+
637
+ class TileCollection(object):
638
+ def __init__(self, tile_coords):
639
+ self.tiles = [Tile(coord) for coord in tile_coords]
640
+ self.tiles_dict = {}
641
+ for tile in self.tiles:
642
+ self.tiles_dict[tile.coord] = tile
643
+
644
+ def __getitem__(self, idx_or_coord):
645
+ if isinstance(idx_or_coord, int):
646
+ return self.tiles[idx_or_coord]
647
+ if idx_or_coord in self.tiles_dict:
648
+ return self.tiles_dict[idx_or_coord]
649
+ return Tile(idx_or_coord)
650
+
651
+ def __contains__(self, tile_or_coord):
652
+ if isinstance(tile_or_coord, tuple):
653
+ return tile_or_coord in self.tiles_dict
654
+ if hasattr(tile_or_coord, 'coord'):
655
+ return tile_or_coord.coord in self.tiles_dict
656
+ return False
657
+
658
+ def __len__(self):
659
+ return len(self.tiles)
660
+
661
+ def __iter__(self):
662
+ return iter(self.tiles)
663
+
664
+ @property
665
+ def empty(self):
666
+ """
667
+ Returns True if no tile in this collection contains a source.
668
+ """
669
+ return all((t.source is None for t in self.tiles))
670
+
671
+ @property
672
+ def blank(self):
673
+ """
674
+ Returns True if all sources collection are BlankImageSources or have not source at all.
675
+ """
676
+ return all((t.source is None or isinstance(t.source, BlankImageSource) for t in self.tiles))
677
+
678
+ def __repr__(self):
679
+ return 'TileCollection(%r)' % self.tiles
680
+
681
+
682
+ def split_meta_tiles(meta_tile, tiles, tile_size, image_opts):
683
+ try:
684
+ # TODO png8
685
+ # if not self.transparent and format == 'png':
686
+ # format = 'png8'
687
+ splitter = TileSplitter(meta_tile, image_opts)
688
+ except IOError:
689
+ # TODO
690
+ raise
691
+ split_tiles = []
692
+ for tile in tiles:
693
+ tile_coord, crop_coord = tile
694
+ if tile_coord is None: continue
695
+ data = splitter.get_tile(crop_coord, tile_size)
696
+ new_tile = Tile(tile_coord, cacheable=meta_tile.cacheable)
697
+ new_tile.source = data
698
+ split_tiles.append(new_tile)
699
+ return split_tiles
File without changes