MapProxy 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. MapProxy-2.1.0.dist-info/AUTHORS.txt +33 -0
  2. MapProxy-2.1.0.dist-info/COPYING.txt +60 -0
  3. MapProxy-2.1.0.dist-info/LICENSE.txt +202 -0
  4. MapProxy-2.1.0.dist-info/METADATA +165 -0
  5. MapProxy-2.1.0.dist-info/RECORD +459 -0
  6. MapProxy-2.1.0.dist-info/WHEEL +5 -0
  7. MapProxy-2.1.0.dist-info/entry_points.txt +4 -0
  8. MapProxy-2.1.0.dist-info/top_level.txt +1 -0
  9. mapproxy/__init__.py +0 -0
  10. mapproxy/cache/__init__.py +36 -0
  11. mapproxy/cache/azureblob.py +145 -0
  12. mapproxy/cache/base.py +120 -0
  13. mapproxy/cache/compact.py +665 -0
  14. mapproxy/cache/couchdb.py +301 -0
  15. mapproxy/cache/dummy.py +36 -0
  16. mapproxy/cache/file.py +200 -0
  17. mapproxy/cache/geopackage.py +647 -0
  18. mapproxy/cache/legend.py +87 -0
  19. mapproxy/cache/mbtiles.py +411 -0
  20. mapproxy/cache/meta.py +80 -0
  21. mapproxy/cache/path.py +261 -0
  22. mapproxy/cache/redis.py +152 -0
  23. mapproxy/cache/renderd.py +100 -0
  24. mapproxy/cache/riak.py +206 -0
  25. mapproxy/cache/s3.py +209 -0
  26. mapproxy/cache/tile.py +736 -0
  27. mapproxy/client/__init__.py +0 -0
  28. mapproxy/client/arcgis.py +82 -0
  29. mapproxy/client/cgi.py +141 -0
  30. mapproxy/client/http.py +295 -0
  31. mapproxy/client/log.py +33 -0
  32. mapproxy/client/tile.py +158 -0
  33. mapproxy/client/wms.py +255 -0
  34. mapproxy/compat/__init__.py +0 -0
  35. mapproxy/compat/image.py +86 -0
  36. mapproxy/config/__init__.py +22 -0
  37. mapproxy/config/config-schema.json +813 -0
  38. mapproxy/config/config.py +213 -0
  39. mapproxy/config/coverage.py +108 -0
  40. mapproxy/config/defaults.py +102 -0
  41. mapproxy/config/loader.py +2399 -0
  42. mapproxy/config/spec.py +657 -0
  43. mapproxy/config/validator.py +242 -0
  44. mapproxy/config_template/__init__.py +0 -0
  45. mapproxy/config_template/base_config/config.wsgi +10 -0
  46. mapproxy/config_template/base_config/full_example.yaml +598 -0
  47. mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
  48. mapproxy/config_template/base_config/log.ini +35 -0
  49. mapproxy/config_template/base_config/mapproxy.yaml +60 -0
  50. mapproxy/config_template/base_config/seed.yaml +27 -0
  51. mapproxy/exception.py +149 -0
  52. mapproxy/featureinfo.py +251 -0
  53. mapproxy/grid.py +1199 -0
  54. mapproxy/image/__init__.py +549 -0
  55. mapproxy/image/fonts/DejaVuSans.ttf +0 -0
  56. mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
  57. mapproxy/image/fonts/LICENSE +99 -0
  58. mapproxy/image/fonts/__init__.py +0 -0
  59. mapproxy/image/mask.py +79 -0
  60. mapproxy/image/merge.py +323 -0
  61. mapproxy/image/message.py +357 -0
  62. mapproxy/image/opts.py +185 -0
  63. mapproxy/image/tile.py +171 -0
  64. mapproxy/image/transform.py +350 -0
  65. mapproxy/layer.py +489 -0
  66. mapproxy/multiapp.py +230 -0
  67. mapproxy/proj.py +309 -0
  68. mapproxy/request/__init__.py +18 -0
  69. mapproxy/request/arcgis.py +268 -0
  70. mapproxy/request/base.py +466 -0
  71. mapproxy/request/tile.py +131 -0
  72. mapproxy/request/wms/__init__.py +829 -0
  73. mapproxy/request/wms/exception.py +107 -0
  74. mapproxy/request/wmts.py +442 -0
  75. mapproxy/response.py +237 -0
  76. mapproxy/script/__init__.py +0 -0
  77. mapproxy/script/conf/__init__.py +0 -0
  78. mapproxy/script/conf/app.py +222 -0
  79. mapproxy/script/conf/caches.py +44 -0
  80. mapproxy/script/conf/geopackage.py +136 -0
  81. mapproxy/script/conf/layers.py +54 -0
  82. mapproxy/script/conf/seeds.py +36 -0
  83. mapproxy/script/conf/sources.py +88 -0
  84. mapproxy/script/conf/utils.py +148 -0
  85. mapproxy/script/defrag.py +187 -0
  86. mapproxy/script/export.py +337 -0
  87. mapproxy/script/grids.py +198 -0
  88. mapproxy/script/scales.py +134 -0
  89. mapproxy/script/util.py +410 -0
  90. mapproxy/script/wms_capabilities.py +160 -0
  91. mapproxy/seed/__init__.py +0 -0
  92. mapproxy/seed/cachelock.py +127 -0
  93. mapproxy/seed/cleanup.py +191 -0
  94. mapproxy/seed/config.py +481 -0
  95. mapproxy/seed/script.py +391 -0
  96. mapproxy/seed/seeder.py +551 -0
  97. mapproxy/seed/spec.py +66 -0
  98. mapproxy/seed/util.py +266 -0
  99. mapproxy/service/__init__.py +14 -0
  100. mapproxy/service/base.py +45 -0
  101. mapproxy/service/demo.py +364 -0
  102. mapproxy/service/kml.py +333 -0
  103. mapproxy/service/ows.py +39 -0
  104. mapproxy/service/template_helper.py +55 -0
  105. mapproxy/service/templates/demo/capabilities_demo.html +18 -0
  106. mapproxy/service/templates/demo/demo.html +181 -0
  107. mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
  108. mapproxy/service/templates/demo/static/img/blank.gif +0 -0
  109. mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
  110. mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
  111. mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
  112. mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
  113. mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
  114. mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
  115. mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
  116. mapproxy/service/templates/demo/static/logo.png +0 -0
  117. mapproxy/service/templates/demo/static/ol.css +345 -0
  118. mapproxy/service/templates/demo/static/ol.js +4 -0
  119. mapproxy/service/templates/demo/static/proj4.min.js +1 -0
  120. mapproxy/service/templates/demo/static/proj4defs.js +1 -0
  121. mapproxy/service/templates/demo/static/site.css +137 -0
  122. mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
  123. mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
  124. mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
  125. mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
  126. mapproxy/service/templates/demo/static.html +34 -0
  127. mapproxy/service/templates/demo/tms_demo.html +117 -0
  128. mapproxy/service/templates/demo/wms_demo.html +144 -0
  129. mapproxy/service/templates/demo/wmts_demo.html +118 -0
  130. mapproxy/service/templates/tms_capabilities.xml +13 -0
  131. mapproxy/service/templates/tms_exception.xml +4 -0
  132. mapproxy/service/templates/tms_root_resource.xml +7 -0
  133. mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
  134. mapproxy/service/templates/wms100capabilities.xml +112 -0
  135. mapproxy/service/templates/wms100exception.xml +4 -0
  136. mapproxy/service/templates/wms110capabilities.xml +152 -0
  137. mapproxy/service/templates/wms110exception.xml +5 -0
  138. mapproxy/service/templates/wms111capabilities.xml +183 -0
  139. mapproxy/service/templates/wms111exception.xml +5 -0
  140. mapproxy/service/templates/wms130capabilities.xml +326 -0
  141. mapproxy/service/templates/wms130exception.xml +8 -0
  142. mapproxy/service/templates/wmts100capabilities.xml +155 -0
  143. mapproxy/service/templates/wmts100exception.xml +9 -0
  144. mapproxy/service/tile.py +540 -0
  145. mapproxy/service/wms.py +868 -0
  146. mapproxy/service/wmts.py +387 -0
  147. mapproxy/source/__init__.py +83 -0
  148. mapproxy/source/arcgis.py +39 -0
  149. mapproxy/source/error.py +40 -0
  150. mapproxy/source/mapnik.py +262 -0
  151. mapproxy/source/tile.py +97 -0
  152. mapproxy/source/wms.py +273 -0
  153. mapproxy/srs.py +734 -0
  154. mapproxy/template.py +54 -0
  155. mapproxy/test/__init__.py +0 -0
  156. mapproxy/test/conftest.py +8 -0
  157. mapproxy/test/helper.py +255 -0
  158. mapproxy/test/http.py +511 -0
  159. mapproxy/test/image.py +219 -0
  160. mapproxy/test/mocker.py +2291 -0
  161. mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
  162. mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
  163. mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
  164. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
  165. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
  166. mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
  167. mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
  168. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
  169. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
  170. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
  171. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
  172. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
  173. mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
  174. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
  175. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
  176. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
  177. mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
  178. mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
  179. mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
  180. mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
  181. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
  182. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
  183. mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
  184. mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
  185. mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
  186. mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
  187. mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
  188. mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
  189. mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
  190. mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
  191. mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
  192. mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
  193. mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
  194. mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
  195. mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
  196. mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
  197. mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
  198. mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
  199. mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
  200. mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
  201. mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
  202. mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
  203. mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
  204. mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
  205. mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
  206. mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
  207. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
  208. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
  209. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
  210. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
  211. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
  212. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
  213. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
  214. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
  215. mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
  216. mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  217. mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
  218. mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  219. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
  220. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
  221. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
  222. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
  223. mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
  224. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
  225. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
  226. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
  227. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
  228. mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
  229. mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  230. mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
  231. mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  232. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
  233. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
  234. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
  235. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
  236. mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
  237. mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
  238. mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
  239. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
  240. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
  241. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
  242. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
  243. mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
  244. mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
  245. mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
  246. mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
  247. mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
  248. mapproxy/test/schemas/xml.xsd +287 -0
  249. mapproxy/test/system/__init__.py +98 -0
  250. mapproxy/test/system/fixture/arcgis.yaml +57 -0
  251. mapproxy/test/system/fixture/auth.yaml +70 -0
  252. mapproxy/test/system/fixture/cache.mbtiles +0 -0
  253. mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
  254. mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
  255. mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
  256. mapproxy/test/system/fixture/cache_coverage.yaml +84 -0
  257. mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
  258. mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
  259. mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
  260. mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
  261. mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
  262. mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
  263. mapproxy/test/system/fixture/cache_s3.yaml +58 -0
  264. mapproxy/test/system/fixture/cache_source.yaml +81 -0
  265. mapproxy/test/system/fixture/combined_sources.yaml +130 -0
  266. mapproxy/test/system/fixture/coverage.yaml +77 -0
  267. mapproxy/test/system/fixture/demo.yaml +135 -0
  268. mapproxy/test/system/fixture/dimension.yaml +59 -0
  269. mapproxy/test/system/fixture/disable_storage.yaml +25 -0
  270. mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
  271. mapproxy/test/system/fixture/formats.yaml +72 -0
  272. mapproxy/test/system/fixture/inspire.yaml +101 -0
  273. mapproxy/test/system/fixture/inspire_full.yaml +124 -0
  274. mapproxy/test/system/fixture/kml_layer.yaml +66 -0
  275. mapproxy/test/system/fixture/layer.yaml +260 -0
  276. mapproxy/test/system/fixture/layergroups.yaml +57 -0
  277. mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
  278. mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
  279. mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
  280. mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
  281. mapproxy/test/system/fixture/mapserver.yaml +23 -0
  282. mapproxy/test/system/fixture/minimal_cgi.py +16 -0
  283. mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
  284. mapproxy/test/system/fixture/multi_cache_layers.yaml +111 -0
  285. mapproxy/test/system/fixture/multiapp1.yaml +20 -0
  286. mapproxy/test/system/fixture/multiapp2.yaml +19 -0
  287. mapproxy/test/system/fixture/renderd_client.yaml +55 -0
  288. mapproxy/test/system/fixture/scalehints.yaml +70 -0
  289. mapproxy/test/system/fixture/seed.yaml +94 -0
  290. mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
  291. mapproxy/test/system/fixture/seed_old.yaml +12 -0
  292. mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
  293. mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
  294. mapproxy/test/system/fixture/seedonly.yaml +51 -0
  295. mapproxy/test/system/fixture/sld.yaml +35 -0
  296. mapproxy/test/system/fixture/source_errors.yaml +84 -0
  297. mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
  298. mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
  299. mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
  300. mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
  301. mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
  302. mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
  303. mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
  304. mapproxy/test/system/fixture/util_grids.yaml +29 -0
  305. mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
  306. mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
  307. mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
  308. mapproxy/test/system/fixture/watermark.yaml +50 -0
  309. mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
  310. mapproxy/test/system/fixture/wms_versions.yaml +38 -0
  311. mapproxy/test/system/fixture/wmts.yaml +134 -0
  312. mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
  313. mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
  314. mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
  315. mapproxy/test/system/test_arcgis.py +156 -0
  316. mapproxy/test/system/test_auth.py +1133 -0
  317. mapproxy/test/system/test_behind_proxy.py +75 -0
  318. mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
  319. mapproxy/test/system/test_cache_azureblob.py +127 -0
  320. mapproxy/test/system/test_cache_band_merge.py +103 -0
  321. mapproxy/test/system/test_cache_coverage.py +168 -0
  322. mapproxy/test/system/test_cache_geopackage.py +144 -0
  323. mapproxy/test/system/test_cache_grid_names.py +89 -0
  324. mapproxy/test/system/test_cache_mbtiles.py +85 -0
  325. mapproxy/test/system/test_cache_s3.py +115 -0
  326. mapproxy/test/system/test_cache_source.py +146 -0
  327. mapproxy/test/system/test_combined_sources.py +335 -0
  328. mapproxy/test/system/test_coverage.py +140 -0
  329. mapproxy/test/system/test_decorate_img.py +214 -0
  330. mapproxy/test/system/test_demo.py +56 -0
  331. mapproxy/test/system/test_demo_with_extra_service.py +57 -0
  332. mapproxy/test/system/test_dimensions.py +279 -0
  333. mapproxy/test/system/test_disable_storage.py +42 -0
  334. mapproxy/test/system/test_formats.py +219 -0
  335. mapproxy/test/system/test_inspire_vs.py +173 -0
  336. mapproxy/test/system/test_kml.py +264 -0
  337. mapproxy/test/system/test_layergroups.py +160 -0
  338. mapproxy/test/system/test_legendgraphic.py +308 -0
  339. mapproxy/test/system/test_mapnik.py +162 -0
  340. mapproxy/test/system/test_mapserver.py +83 -0
  341. mapproxy/test/system/test_mixed_mode_format.py +201 -0
  342. mapproxy/test/system/test_multi_cache_layers.py +169 -0
  343. mapproxy/test/system/test_multiapp.py +92 -0
  344. mapproxy/test/system/test_refresh.py +206 -0
  345. mapproxy/test/system/test_renderd_client.py +304 -0
  346. mapproxy/test/system/test_response_headers.py +54 -0
  347. mapproxy/test/system/test_scalehints.py +140 -0
  348. mapproxy/test/system/test_seed.py +425 -0
  349. mapproxy/test/system/test_seed_only.py +93 -0
  350. mapproxy/test/system/test_sld.py +120 -0
  351. mapproxy/test/system/test_source_errors.py +377 -0
  352. mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
  353. mapproxy/test/system/test_tms.py +277 -0
  354. mapproxy/test/system/test_tms_origin.py +46 -0
  355. mapproxy/test/system/test_util_conf.py +434 -0
  356. mapproxy/test/system/test_util_export.py +210 -0
  357. mapproxy/test/system/test_util_grids.py +88 -0
  358. mapproxy/test/system/test_util_wms_capabilities.py +182 -0
  359. mapproxy/test/system/test_watermark.py +91 -0
  360. mapproxy/test/system/test_wms.py +1616 -0
  361. mapproxy/test/system/test_wms_srs_extent.py +165 -0
  362. mapproxy/test/system/test_wms_version.py +85 -0
  363. mapproxy/test/system/test_wmsc.py +116 -0
  364. mapproxy/test/system/test_wmts.py +334 -0
  365. mapproxy/test/system/test_wmts_dimensions.py +206 -0
  366. mapproxy/test/system/test_wmts_restful.py +198 -0
  367. mapproxy/test/system/test_xslt_featureinfo.py +423 -0
  368. mapproxy/test/test_http_helper.py +217 -0
  369. mapproxy/test/unit/__init__.py +0 -0
  370. mapproxy/test/unit/epsg +2 -0
  371. mapproxy/test/unit/polygons/polygons.dbf +0 -0
  372. mapproxy/test/unit/polygons/polygons.shp +0 -0
  373. mapproxy/test/unit/polygons/polygons.shx +0 -0
  374. mapproxy/test/unit/test_async.py +242 -0
  375. mapproxy/test/unit/test_auth.py +430 -0
  376. mapproxy/test/unit/test_cache.py +1356 -0
  377. mapproxy/test/unit/test_cache_azureblob.py +97 -0
  378. mapproxy/test/unit/test_cache_compact.py +324 -0
  379. mapproxy/test/unit/test_cache_couchdb.py +118 -0
  380. mapproxy/test/unit/test_cache_geopackage.py +256 -0
  381. mapproxy/test/unit/test_cache_redis.py +123 -0
  382. mapproxy/test/unit/test_cache_riak.py +80 -0
  383. mapproxy/test/unit/test_cache_s3.py +93 -0
  384. mapproxy/test/unit/test_cache_tile.py +477 -0
  385. mapproxy/test/unit/test_client.py +488 -0
  386. mapproxy/test/unit/test_client_arcgis.py +74 -0
  387. mapproxy/test/unit/test_client_cgi.py +140 -0
  388. mapproxy/test/unit/test_collections.py +116 -0
  389. mapproxy/test/unit/test_concat_legends.py +37 -0
  390. mapproxy/test/unit/test_conf_loader.py +1267 -0
  391. mapproxy/test/unit/test_conf_validator.py +427 -0
  392. mapproxy/test/unit/test_config.py +118 -0
  393. mapproxy/test/unit/test_decorate_img.py +185 -0
  394. mapproxy/test/unit/test_exceptions.py +270 -0
  395. mapproxy/test/unit/test_featureinfo.py +313 -0
  396. mapproxy/test/unit/test_file_lock_load.py +49 -0
  397. mapproxy/test/unit/test_geom.py +512 -0
  398. mapproxy/test/unit/test_grid.py +1279 -0
  399. mapproxy/test/unit/test_image.py +1051 -0
  400. mapproxy/test/unit/test_image_mask.py +181 -0
  401. mapproxy/test/unit/test_image_messages.py +209 -0
  402. mapproxy/test/unit/test_image_options.py +160 -0
  403. mapproxy/test/unit/test_isodate.py +118 -0
  404. mapproxy/test/unit/test_multiapp.py +163 -0
  405. mapproxy/test/unit/test_ogr_reader.py +51 -0
  406. mapproxy/test/unit/test_request.py +745 -0
  407. mapproxy/test/unit/test_request_wmts.py +178 -0
  408. mapproxy/test/unit/test_response.py +78 -0
  409. mapproxy/test/unit/test_seed.py +365 -0
  410. mapproxy/test/unit/test_seed_cachelock.py +91 -0
  411. mapproxy/test/unit/test_srs.py +215 -0
  412. mapproxy/test/unit/test_tiled_source.py +122 -0
  413. mapproxy/test/unit/test_tilefilter.py +31 -0
  414. mapproxy/test/unit/test_times.py +25 -0
  415. mapproxy/test/unit/test_timeutils.py +50 -0
  416. mapproxy/test/unit/test_util_conf_utils.py +75 -0
  417. mapproxy/test/unit/test_utils.py +476 -0
  418. mapproxy/test/unit/test_wms_capabilities.py +44 -0
  419. mapproxy/test/unit/test_wms_layer.py +113 -0
  420. mapproxy/test/unit/test_yaml.py +68 -0
  421. mapproxy/tilefilter.py +61 -0
  422. mapproxy/util/__init__.py +0 -0
  423. mapproxy/util/async_.py +229 -0
  424. mapproxy/util/collections.py +134 -0
  425. mapproxy/util/coverage.py +337 -0
  426. mapproxy/util/ext/__init__.py +14 -0
  427. mapproxy/util/ext/dictspec/__init__.py +1 -0
  428. mapproxy/util/ext/dictspec/spec.py +131 -0
  429. mapproxy/util/ext/dictspec/test/__init__.py +0 -0
  430. mapproxy/util/ext/dictspec/test/test_validator.py +278 -0
  431. mapproxy/util/ext/dictspec/validator.py +194 -0
  432. mapproxy/util/ext/local.py +198 -0
  433. mapproxy/util/ext/lockfile.py +140 -0
  434. mapproxy/util/ext/odict.py +321 -0
  435. mapproxy/util/ext/serving.py +491 -0
  436. mapproxy/util/ext/tempita/__init__.py +1093 -0
  437. mapproxy/util/ext/tempita/_looper.py +163 -0
  438. mapproxy/util/ext/tempita/string_utils.py +24 -0
  439. mapproxy/util/ext/wmsparse/__init__.py +3 -0
  440. mapproxy/util/ext/wmsparse/duration.py +600 -0
  441. mapproxy/util/ext/wmsparse/parse.py +307 -0
  442. mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
  443. mapproxy/util/ext/wmsparse/test/test_parse.py +111 -0
  444. mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
  445. mapproxy/util/ext/wmsparse/test/wms-example-111.xml +90 -0
  446. mapproxy/util/ext/wmsparse/test/wms-example-130.xml +120 -0
  447. mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
  448. mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
  449. mapproxy/util/ext/wmsparse/util.py +189 -0
  450. mapproxy/util/fs.py +164 -0
  451. mapproxy/util/geom.py +307 -0
  452. mapproxy/util/lib.py +117 -0
  453. mapproxy/util/lock.py +171 -0
  454. mapproxy/util/ogr.py +247 -0
  455. mapproxy/util/py.py +75 -0
  456. mapproxy/util/times.py +78 -0
  457. mapproxy/util/yaml.py +58 -0
  458. mapproxy/version.py +33 -0
  459. mapproxy/wsgiapp.py +167 -0
@@ -0,0 +1,551 @@
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 sys
19
+ from collections import deque
20
+ from contextlib import contextmanager
21
+ from itertools import zip_longest
22
+
23
+ try:
24
+ import Queue
25
+ except ImportError:
26
+ import queue as Queue
27
+
28
+ from mapproxy.config import base_config
29
+ from mapproxy.grid import MetaGrid
30
+ from mapproxy.source import SourceError
31
+ from mapproxy.config import local_base_config
32
+ from mapproxy.util.lock import LockTimeout
33
+ from mapproxy.seed.util import format_seed_task
34
+ from mapproxy.seed.cachelock import DummyCacheLocker, CacheLockedError
35
+
36
+ from mapproxy.seed.util import (exp_backoff, limit_sub_bbox,
37
+ status_symbol, BackoffError)
38
+
39
+ import logging
40
+ log = logging.getLogger(__name__)
41
+
42
+ NONE = 0
43
+ CONTAINS = -1
44
+ INTERSECTS = 1
45
+
46
+ # Decide whether to use multiprocessing or threading. multiprocessing should be faster but
47
+ # it is not well supported on all platforms. Especially regarding lambdas and anonymous
48
+ # function/classes which are used in proj.py for example.
49
+ #
50
+ # Since Python 3.8, MacOS uses a non-forking start method for multiprocessing which
51
+ # inhibits similar restrictions to Windows.
52
+ if sys.platform == 'win32' or (sys.platform == 'darwin' and sys.version_info >= (3, 8)):
53
+ import threading
54
+ proc_class = threading.Thread
55
+ queue_class = Queue.Queue
56
+ else:
57
+ import multiprocessing
58
+ proc_class = multiprocessing.Process
59
+ queue_class = multiprocessing.Queue
60
+
61
+
62
+ class TileWorkerPool(object):
63
+ """
64
+ Manages multiple TileWorker.
65
+ """
66
+
67
+ def __init__(self, task, worker_class, size=2, dry_run=False, progress_logger=None):
68
+ self.tiles_queue = queue_class(size)
69
+ self.task = task
70
+ self.dry_run = dry_run
71
+ self.procs = []
72
+ self.progress_logger = progress_logger
73
+ conf = base_config()
74
+ for _ in range(size):
75
+ worker = worker_class(self.task, self.tiles_queue, conf)
76
+ worker.start()
77
+ self.procs.append(worker)
78
+
79
+ def process(self, tiles, progress):
80
+ if not self.dry_run:
81
+ while True:
82
+ try:
83
+ self.tiles_queue.put(tiles, timeout=5)
84
+ except Queue.Full:
85
+ alive = False
86
+ for proc in self.procs:
87
+ if proc.is_alive():
88
+ alive = True
89
+ break
90
+ if not alive:
91
+ log.warning('no workers left, stopping')
92
+ raise SeedInterrupted
93
+ continue
94
+ else:
95
+ break
96
+
97
+ if self.progress_logger:
98
+ self.progress_logger.log_step(progress)
99
+
100
+ def stop(self, force=False):
101
+ """
102
+ Stop seed workers by sending None-sentinel and joining the workers.
103
+
104
+ :param force: Skip sending None-sentinel and join with a timeout.
105
+ For use when workers might be shutdown already by KeyboardInterrupt.
106
+ """
107
+ if not force:
108
+ alives = 0
109
+ for proc in self.procs:
110
+ if proc.is_alive():
111
+ alives += 1
112
+
113
+ while alives:
114
+ # put None-sentinels to queue as long as we have workers alive
115
+ try:
116
+ self.tiles_queue.put(None, timeout=1)
117
+ alives -= 1
118
+ except Queue.Full:
119
+ alives = 0
120
+ for proc in self.procs:
121
+ if proc.is_alive():
122
+ alives += 1
123
+
124
+ if force:
125
+ timeout = 1.0
126
+ else:
127
+ timeout = None
128
+ for proc in self.procs:
129
+ proc.join(timeout)
130
+
131
+
132
+ class TileWorker(proc_class):
133
+ def __init__(self, task, tiles_queue, conf):
134
+ proc_class.__init__(self)
135
+ proc_class.daemon = True
136
+ self.task = task
137
+ self.tile_mgr = task.tile_manager
138
+ self.tiles_queue = tiles_queue
139
+ self.conf = conf
140
+
141
+ def run(self):
142
+ with local_base_config(self.conf):
143
+ try:
144
+ self.work_loop()
145
+ except KeyboardInterrupt:
146
+ return
147
+ except BackoffError:
148
+ return
149
+
150
+
151
+ class TileSeedWorker(TileWorker):
152
+ def work_loop(self):
153
+ while True:
154
+ tiles = self.tiles_queue.get()
155
+ if tiles is None:
156
+ return
157
+ with self.tile_mgr.session():
158
+ exp_backoff(self.tile_mgr.load_tile_coords, args=(tiles,),
159
+ max_repeat=100, max_backoff=600,
160
+ exceptions=(SourceError, IOError), ignore_exceptions=(LockTimeout, ))
161
+
162
+
163
+ class TileCleanupWorker(TileWorker):
164
+ def work_loop(self):
165
+ while True:
166
+ tiles = self.tiles_queue.get()
167
+ if tiles is None:
168
+ return
169
+ with self.tile_mgr.session():
170
+ self.tile_mgr.remove_tile_coords(tiles)
171
+
172
+
173
+ class SeedProgress(object):
174
+ def __init__(self, old_progress_identifier=None):
175
+ self.progress = 0.0
176
+ self.level_progress_percentages = [1.0]
177
+ self.level_progresses = None
178
+ self.level_progresses_level = 0
179
+ self.progress_str_parts = []
180
+ self.old_level_progresses = old_progress_identifier
181
+
182
+ def step_forward(self, subtiles=1):
183
+ self.progress += self.level_progress_percentages[-1] / subtiles
184
+
185
+ @property
186
+ def progress_str(self):
187
+ return ''.join(self.progress_str_parts)
188
+
189
+ @contextmanager
190
+ def step_down(self, i, subtiles):
191
+ if self.level_progresses is None:
192
+ self.level_progresses = []
193
+ self.level_progresses = self.level_progresses[:self.level_progresses_level]
194
+ self.level_progresses.append((i, subtiles))
195
+ self.level_progresses_level += 1
196
+ self.progress_str_parts.append(status_symbol(i, subtiles))
197
+ self.level_progress_percentages.append(self.level_progress_percentages[-1] / subtiles)
198
+
199
+ yield
200
+
201
+ self.level_progress_percentages.pop()
202
+ self.progress_str_parts.pop()
203
+
204
+ self.level_progresses_level -= 1
205
+ if self.level_progresses_level == 0:
206
+ self.level_progresses = []
207
+
208
+ def already_processed(self):
209
+ return self.can_skip(self.old_level_progresses, self.level_progresses)
210
+
211
+ def current_progress_identifier(self):
212
+ if self.already_processed() or self.level_progresses is None:
213
+ return self.old_level_progresses
214
+ return self.level_progresses[:]
215
+
216
+ @staticmethod
217
+ def can_skip(old_progress, current_progress):
218
+ """
219
+ Return True if the `current_progress` is behind the `old_progress` -
220
+ when it isn't as far as the old progress.
221
+
222
+ >>> SeedProgress.can_skip(None, [(0, 4)])
223
+ False
224
+ >>> SeedProgress.can_skip([], [(0, 4)])
225
+ True
226
+ >>> SeedProgress.can_skip([(0, 4)], None)
227
+ False
228
+ >>> SeedProgress.can_skip([(0, 4)], [(0, 4)])
229
+ False
230
+ >>> SeedProgress.can_skip([(1, 4)], [(0, 4)])
231
+ True
232
+ >>> SeedProgress.can_skip([(0, 4)], [(0, 4), (0, 4)])
233
+ False
234
+
235
+ >>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4)])
236
+ False
237
+ >>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4), (1, 4)])
238
+ True
239
+ >>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4), (2, 4)])
240
+ False
241
+ >>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4), (3, 4)])
242
+ False
243
+ >>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (1, 4)])
244
+ False
245
+ >>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (1, 4), (0, 4)])
246
+ False
247
+ """
248
+ if current_progress is None:
249
+ return False
250
+ if old_progress is None:
251
+ return False
252
+ if old_progress == []:
253
+ return True
254
+ for old, current in zip_longest(old_progress, current_progress, fillvalue=None):
255
+ if old is None:
256
+ return False
257
+ if current is None:
258
+ return False
259
+ if old < current:
260
+ return False
261
+ if old > current:
262
+ return True
263
+ return False
264
+
265
+ def running(self):
266
+ return True
267
+
268
+
269
+ class StopProcess(Exception):
270
+ pass
271
+
272
+
273
+ class SeedInterrupted(Exception):
274
+ pass
275
+
276
+
277
+ class TileWalker(object):
278
+ """
279
+ TileWalker traverses through all tiles in a tile grid and calls worker_pool.process
280
+ for each (meta) tile. It traverses the tile grid (pyramid) depth-first.
281
+ Intersection with coverages are checked before handling subtiles in the next level,
282
+ allowing to determine if all subtiles should be seeded or skipped.
283
+ """
284
+
285
+ def __init__(self, task, worker_pool, handle_stale=False, handle_uncached=False,
286
+ work_on_metatiles=True, skip_geoms_for_last_levels=0, progress_logger=None,
287
+ seed_progress=None):
288
+ self.tile_mgr = task.tile_manager
289
+ self.task = task
290
+ self.worker_pool = worker_pool
291
+ self.handle_stale = handle_stale
292
+ self.handle_uncached = handle_uncached
293
+ self.work_on_metatiles = work_on_metatiles
294
+ self.skip_geoms_for_last_levels = skip_geoms_for_last_levels
295
+ self.progress_logger = progress_logger
296
+
297
+ num_seed_levels = len(task.levels)
298
+ if num_seed_levels >= 4:
299
+ self.report_till_level = task.levels[num_seed_levels-2]
300
+ else:
301
+ self.report_till_level = task.levels[num_seed_levels-1]
302
+ meta_size = self.tile_mgr.meta_grid.meta_size if self.tile_mgr.meta_grid else (1, 1)
303
+ self.tiles_per_metatile = meta_size[0] * meta_size[1]
304
+ self.grid = MetaGrid(self.tile_mgr.grid, meta_size=meta_size, meta_buffer=0)
305
+ self.count = 0
306
+ self.seed_progress = seed_progress or SeedProgress()
307
+
308
+ # It is possible that we 'walk' through the same tile multiple times
309
+ # when seeding irregular tile grids[0]. limit_sub_bbox prevents that we
310
+ # recurse into the same area multiple times, but it is still possible
311
+ # that a tile is processed multiple times. Locking prevents that a tile
312
+ # is seeded multiple times, but it is possible that we count the same tile
313
+ # multiple times (in dry-mode, or while the tile is in the process queue).
314
+
315
+ # Tile counts can be off by 280% with sqrt2 grids.
316
+ # We keep a small cache of already processed tiles to skip most duplicates.
317
+ # A simple cache of 64 tile coordinates for each level already brings the
318
+ # difference down to ~8%, which is good enough and faster than a more
319
+ # sophisticated FIFO cache with O(1) lookup, or even caching all tiles.
320
+
321
+ # [0] irregular tile grids: where one tile does not have exactly 4 subtiles
322
+ # Typically when you use res_factor, or a custom res list.
323
+ self.seeded_tiles = {x: deque(maxlen=64) for x in task.levels}
324
+
325
+ def walk(self):
326
+ assert self.handle_stale or self.handle_uncached
327
+ bbox = self.task.coverage.extent.bbox_for(self.tile_mgr.grid.srs)
328
+ if self.seed_progress.already_processed():
329
+ # nothing to seed
330
+ self.seed_progress.step_forward()
331
+ else:
332
+ try:
333
+ self._walk(bbox, self.task.levels)
334
+ except StopProcess:
335
+ pass
336
+ self.report_progress(self.task.levels[0], self.task.coverage.bbox)
337
+
338
+ def _walk(self, cur_bbox, levels, current_level=0, all_subtiles=False):
339
+ """
340
+ :param cur_bbox: the bbox to seed in this call
341
+ :param levels: list of levels to seed
342
+ :param all_subtiles: seed all subtiles and do not check for
343
+ intersections with bbox/geom
344
+ """
345
+ bbox_, tiles, subtiles = self.grid.get_affected_level_tiles(cur_bbox, current_level)
346
+ total_subtiles = tiles[0] * tiles[1]
347
+ if len(levels) < self.skip_geoms_for_last_levels:
348
+ # do not filter in last levels
349
+ all_subtiles = True
350
+ subtiles = self._filter_subtiles(subtiles, all_subtiles)
351
+
352
+ if current_level in levels and current_level <= self.report_till_level:
353
+ self.report_progress(current_level, cur_bbox)
354
+
355
+ if not self.seed_progress.running():
356
+ if current_level in levels:
357
+ self.report_progress(current_level, cur_bbox)
358
+ self.tile_mgr.cleanup()
359
+ raise StopProcess()
360
+
361
+ process = False
362
+ if current_level in levels:
363
+ levels = levels[1:]
364
+ process = True
365
+
366
+ for i, (subtile, sub_bbox, intersection) in enumerate(subtiles):
367
+ if subtile is None: # no intersection
368
+ self.seed_progress.step_forward(total_subtiles)
369
+ continue
370
+ if levels: # recurse to next level
371
+ sub_bbox = limit_sub_bbox(cur_bbox, sub_bbox)
372
+ if intersection == CONTAINS:
373
+ all_subtiles = True
374
+ else:
375
+ all_subtiles = False
376
+
377
+ with self.seed_progress.step_down(i, total_subtiles):
378
+ if self.seed_progress.already_processed():
379
+ self.seed_progress.step_forward()
380
+ else:
381
+ self._walk(sub_bbox, levels, current_level=current_level+1,
382
+ all_subtiles=all_subtiles)
383
+
384
+ if not process:
385
+ continue
386
+
387
+ # check if subtile was already processed. see comment in __init__
388
+ if subtile in self.seeded_tiles[current_level]:
389
+ if not levels:
390
+ self.seed_progress.step_forward(total_subtiles)
391
+ continue
392
+ self.seeded_tiles[current_level].appendleft(subtile)
393
+
394
+ if not self.work_on_metatiles:
395
+ # collect actual tiles
396
+ handle_tiles = self.grid.tile_list(subtile)
397
+ else:
398
+ handle_tiles = [subtile]
399
+
400
+ if self.handle_uncached:
401
+ handle_tiles = [t for t in handle_tiles if
402
+ t is not None and
403
+ not self.tile_mgr.is_cached(t)]
404
+ elif self.handle_stale:
405
+ handle_tiles = [t for t in handle_tiles if
406
+ t is not None and
407
+ self.tile_mgr.is_stale(t)]
408
+ if handle_tiles:
409
+ self.count += 1
410
+ self.worker_pool.process(handle_tiles, self.seed_progress)
411
+
412
+ if not levels:
413
+ self.seed_progress.step_forward(total_subtiles)
414
+
415
+ if len(levels) >= 4:
416
+ # call cleanup to close open caches
417
+ # for connection based caches
418
+ self.tile_mgr.cleanup()
419
+
420
+ def report_progress(self, level, bbox):
421
+ if self.progress_logger:
422
+ self.progress_logger.log_progress(self.seed_progress, level, bbox,
423
+ self.count * self.tiles_per_metatile)
424
+
425
+ def _filter_subtiles(self, subtiles, all_subtiles):
426
+ """
427
+ Return an iterator with all sub tiles.
428
+ Yields (None, None, None) for non-intersecting tiles,
429
+ otherwise (subtile, subtile_bbox, intersection).
430
+ """
431
+ for subtile in subtiles:
432
+ if subtile is None:
433
+ yield None, None, None
434
+ else:
435
+ sub_bbox = self.grid.meta_tile(subtile).bbox
436
+ if all_subtiles:
437
+ intersection = CONTAINS
438
+ else:
439
+ intersection = self.task.intersects(sub_bbox)
440
+ if intersection:
441
+ yield subtile, sub_bbox, intersection
442
+ else:
443
+ yield None, None, None
444
+
445
+
446
+ class SeedTask(object):
447
+ def __init__(self, md, tile_manager, levels, refresh_timestamp, coverage):
448
+ self.md = md
449
+ self.tile_manager = tile_manager
450
+ self.grid = tile_manager.grid
451
+ self.levels = levels
452
+ self.refresh_timestamp = refresh_timestamp
453
+ self.coverage = coverage
454
+
455
+ @property
456
+ def id(self):
457
+ return self.md['name'], self.md['cache_name'], self.md['grid_name'], tuple(self.levels)
458
+
459
+ def intersects(self, bbox):
460
+ if self.coverage.contains(bbox, self.grid.srs):
461
+ return CONTAINS
462
+ if self.coverage.intersects(bbox, self.grid.srs):
463
+ return INTERSECTS
464
+ return NONE
465
+
466
+
467
+ class CleanupTask(object):
468
+ """
469
+ :param coverage: area for the cleanup
470
+ :param complete_extent: ``True`` if `coverage` equals the extent of the grid
471
+ """
472
+
473
+ def __init__(self, md, tile_manager, levels, remove_timestamp, coverage, complete_extent=False):
474
+ self.md = md
475
+ self.tile_manager = tile_manager
476
+ self.grid = tile_manager.grid
477
+ self.levels = levels
478
+ self.remove_timestamp = remove_timestamp
479
+ self.coverage = coverage
480
+ self.complete_extent = complete_extent
481
+
482
+ @property
483
+ def id(self):
484
+ return 'cleanup', self.md['name'], self.md['cache_name'], self.md['grid_name']
485
+
486
+ def intersects(self, bbox):
487
+ if self.coverage.contains(bbox, self.grid.srs):
488
+ return CONTAINS
489
+ if self.coverage.intersects(bbox, self.grid.srs):
490
+ return INTERSECTS
491
+ return NONE
492
+
493
+
494
+ def seed(tasks, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0,
495
+ progress_logger=None, cache_locker=None, skip_uncached=False):
496
+ if cache_locker is None:
497
+ cache_locker = DummyCacheLocker()
498
+
499
+ active_tasks = tasks[::-1]
500
+ while active_tasks:
501
+ task = active_tasks[-1]
502
+ print(format_seed_task(task))
503
+
504
+ wait = len(active_tasks) == 1
505
+ try:
506
+ with cache_locker.lock(task.md['cache_name'], no_block=not wait):
507
+ if progress_logger and progress_logger.progress_store:
508
+ progress_logger.current_task_id = task.id
509
+ start_progress = progress_logger.progress_store.get(task.id)
510
+ else:
511
+ start_progress = None
512
+ seed_progress = SeedProgress(old_progress_identifier=start_progress)
513
+ seed_task(task, concurrency, dry_run, skip_geoms_for_last_levels, progress_logger,
514
+ seed_progress=seed_progress, skip_uncached=skip_uncached)
515
+ except CacheLockedError:
516
+ print(' ...cache is locked, skipping')
517
+ active_tasks = [task] + active_tasks[:-1]
518
+ else:
519
+ active_tasks.pop()
520
+
521
+
522
+ def seed_task(task, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0,
523
+ progress_logger=None, seed_progress=None, skip_uncached=False):
524
+ if task.coverage is False:
525
+ return
526
+ if task.refresh_timestamp is not None:
527
+ task.tile_manager._expire_timestamp = task.refresh_timestamp
528
+ task.tile_manager.minimize_meta_requests = False
529
+
530
+ work_on_metatiles = True
531
+ if task.tile_manager.rescale_tiles:
532
+ work_on_metatiles = False
533
+
534
+ tile_worker_pool = TileWorkerPool(task, TileSeedWorker, dry_run=dry_run,
535
+ size=concurrency, progress_logger=progress_logger)
536
+ # If the configuration requests to only refresh tiles which are already in cache,
537
+ # tile walker parameters shall be adapted
538
+ handle_stale = skip_uncached
539
+ handle_uncached = not skip_uncached
540
+ tile_walker = TileWalker(task, tile_worker_pool, handle_uncached=handle_uncached, handle_stale=handle_stale,
541
+ skip_geoms_for_last_levels=skip_geoms_for_last_levels, progress_logger=progress_logger,
542
+ seed_progress=seed_progress,
543
+ work_on_metatiles=work_on_metatiles,
544
+ )
545
+ try:
546
+ tile_walker.walk()
547
+ except KeyboardInterrupt:
548
+ tile_worker_pool.stop(force=True)
549
+ raise
550
+ finally:
551
+ tile_worker_pool.stop()
mapproxy/seed/spec.py ADDED
@@ -0,0 +1,66 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 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 mapproxy.util.ext.dictspec.validator import validate, ValidationError
17
+ from mapproxy.util.ext.dictspec.spec import one_off, anything, number
18
+ from mapproxy.util.ext.dictspec.spec import required
19
+
20
+ from mapproxy.config.spec import coverage, time_spec
21
+
22
+
23
+ def validate_seed_conf(conf_dict):
24
+ """
25
+ Validate `conf_dict` agains seed.yaml spec.
26
+ Returns lists with errors. List is empty when no errors where found.
27
+ """
28
+ try:
29
+ validate(seed_yaml_spec, conf_dict)
30
+ except ValidationError as ex:
31
+ return ex.errors, ex.informal_only
32
+ else:
33
+ return [], True
34
+
35
+
36
+ from_to_spec = {
37
+ 'from': number(),
38
+ 'to': number(),
39
+ }
40
+
41
+ seed_yaml_spec = {
42
+ 'coverages': {
43
+ anything(): coverage,
44
+ },
45
+ 'seeds': {
46
+ anything(): {
47
+ required('caches'): [str()],
48
+ 'grids': [str()],
49
+ 'coverages': [str()],
50
+ 'refresh_before': time_spec,
51
+ 'levels': one_off([int()], from_to_spec),
52
+ 'resolutions': one_off([int()], from_to_spec),
53
+ },
54
+ },
55
+ 'cleanups': {
56
+ anything(): {
57
+ required('caches'): [str()],
58
+ 'grids': [str()],
59
+ 'coverages': [str()],
60
+ 'remove_before': time_spec,
61
+ 'remove_all': bool(),
62
+ 'levels': one_off([int()], from_to_spec),
63
+ 'resolutions': one_off([int()], from_to_spec),
64
+ }
65
+ },
66
+ }