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
@@ -0,0 +1,187 @@
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
+ from __future__ import print_function
17
+
18
+ import os
19
+ from mapproxy.compat.itertools import izip_longest
20
+ from mapproxy.seed.util import format_cleanup_task
21
+ from mapproxy.util.fs import cleanup_directory
22
+ from mapproxy.seed.seeder import (
23
+ TileWorkerPool, TileWalker, TileCleanupWorker,
24
+ SeedProgress,
25
+ )
26
+ from mapproxy.seed.util import ProgressLog
27
+
28
+ def cleanup(tasks, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0,
29
+ verbose=True, progress_logger=None):
30
+ for task in tasks:
31
+ print(format_cleanup_task(task))
32
+
33
+ if task.coverage is False:
34
+ continue
35
+
36
+ # seed_progress for tilewalker cleanup
37
+ seed_progress = None
38
+ # cleanup_progress for os.walk based cleanup
39
+ cleanup_progress = None
40
+ if progress_logger and progress_logger.progress_store:
41
+ progress_logger.current_task_id = task.id
42
+ start_progress = progress_logger.progress_store.get(task.id)
43
+ seed_progress = SeedProgress(old_progress_identifier=start_progress)
44
+ cleanup_progress = DirectoryCleanupProgress(old_dir=start_progress)
45
+
46
+ if task.complete_extent:
47
+ if callable(getattr(task.tile_manager.cache, 'level_location', None)):
48
+ simple_cleanup(task, dry_run=dry_run, progress_logger=progress_logger,
49
+ cleanup_progress=cleanup_progress)
50
+ task.tile_manager.cleanup()
51
+ continue
52
+ elif callable(getattr(task.tile_manager.cache, 'remove_level_tiles_before', None)):
53
+ cache_cleanup(task, dry_run=dry_run, progress_logger=progress_logger)
54
+ task.tile_manager.cleanup()
55
+ continue
56
+
57
+ tilewalker_cleanup(task, dry_run=dry_run, concurrency=concurrency,
58
+ skip_geoms_for_last_levels=skip_geoms_for_last_levels,
59
+ progress_logger=progress_logger,
60
+ seed_progress=seed_progress,
61
+ )
62
+ task.tile_manager.cleanup()
63
+
64
+
65
+ def simple_cleanup(task, dry_run, progress_logger=None, cleanup_progress=None):
66
+ """
67
+ Cleanup cache level on file system level.
68
+ """
69
+
70
+ for level in task.levels:
71
+ level_dir = task.tile_manager.cache.level_location(level)
72
+ if dry_run:
73
+ def file_handler(filename):
74
+ print('removing ' + filename)
75
+ else:
76
+ file_handler = None
77
+ if progress_logger:
78
+ progress_logger.log_message('removing old tiles in ' + normpath(level_dir))
79
+ if progress_logger.progress_store:
80
+ cleanup_progress.step_dir(level_dir)
81
+ if cleanup_progress.already_processed():
82
+ continue
83
+ progress_logger.progress_store.add(
84
+ task.id,
85
+ cleanup_progress.current_progress_identifier(),
86
+ )
87
+ progress_logger.progress_store.write()
88
+
89
+ cleanup_directory(level_dir, task.remove_timestamp,
90
+ file_handler=file_handler, remove_empty_dirs=True)
91
+
92
+ def cache_cleanup(task, dry_run, progress_logger=None):
93
+ for level in task.levels:
94
+ if progress_logger:
95
+ progress_logger.log_message('removing old tiles for level %s' % level)
96
+ if not dry_run:
97
+ task.tile_manager.cache.remove_level_tiles_before(level, task.remove_timestamp)
98
+ task.tile_manager.cleanup()
99
+
100
+ def normpath(path):
101
+ # relpath doesn't support UNC
102
+ if path.startswith('\\'):
103
+ return path
104
+
105
+ path = os.path.relpath(path)
106
+
107
+ if path.startswith('../../'):
108
+ path = os.path.abspath(path)
109
+ return path
110
+
111
+ def tilewalker_cleanup(task, dry_run, concurrency, skip_geoms_for_last_levels,
112
+ progress_logger=None, seed_progress=None):
113
+ """
114
+ Cleanup tiles with tile traversal.
115
+ """
116
+ task.tile_manager._expire_timestamp = task.remove_timestamp
117
+ task.tile_manager.minimize_meta_requests = False
118
+ tile_worker_pool = TileWorkerPool(task, TileCleanupWorker, progress_logger=progress_logger,
119
+ dry_run=dry_run, size=concurrency)
120
+ tile_walker = TileWalker(task, tile_worker_pool, handle_stale=True,
121
+ work_on_metatiles=False, progress_logger=progress_logger,
122
+ skip_geoms_for_last_levels=skip_geoms_for_last_levels,
123
+ seed_progress=seed_progress)
124
+ try:
125
+ tile_walker.walk()
126
+ except KeyboardInterrupt:
127
+ tile_worker_pool.stop(force=True)
128
+ raise
129
+ finally:
130
+ tile_worker_pool.stop()
131
+
132
+
133
+ class DirectoryCleanupProgress(object):
134
+ def __init__(self, old_dir=None):
135
+ self.old_dir = old_dir
136
+ self.current_dir = None
137
+
138
+ def step_dir(self, dir):
139
+ self.current_dir = dir
140
+
141
+ def already_processed(self):
142
+ return self.can_skip(self.old_dir, self.current_dir)
143
+
144
+ def current_progress_identifier(self):
145
+ if self.already_processed() or self.current_dir is None:
146
+ return self.old_dir
147
+ return self.current_dir
148
+
149
+ @staticmethod
150
+ def can_skip(old_dir, current_dir):
151
+ """
152
+ Return True if the `current_dir` is before `old_dir` when compared
153
+ lexicographic.
154
+
155
+ >>> DirectoryCleanupProgress.can_skip(None, '/00')
156
+ False
157
+ >>> DirectoryCleanupProgress.can_skip(None, '/00/000/000')
158
+ False
159
+
160
+ >>> DirectoryCleanupProgress.can_skip('/01/000/001', '/00')
161
+ True
162
+ >>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/000')
163
+ True
164
+ >>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/000/000')
165
+ True
166
+ >>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/001')
167
+ False
168
+ >>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/001/000')
169
+ False
170
+ """
171
+ if old_dir is None:
172
+ return False
173
+ if current_dir is None:
174
+ return False
175
+ for old, current in izip_longest(old_dir.split(os.path.sep), current_dir.split(os.path.sep), fillvalue=None):
176
+ if old is None:
177
+ return False
178
+ if current is None:
179
+ return False
180
+ if old < current:
181
+ return False
182
+ if old > current:
183
+ return True
184
+ return False
185
+
186
+ def running(self):
187
+ return True
@@ -0,0 +1,469 @@
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 __future__ import print_function
17
+
18
+ import os
19
+ import sys
20
+ import time
21
+ import operator
22
+ from functools import reduce
23
+
24
+ from mapproxy.cache.dummy import DummyCache
25
+ from mapproxy.compat import iteritems, itervalues, iterkeys
26
+ from mapproxy.config import abspath
27
+ from mapproxy.config.loader import ConfigurationError
28
+ from mapproxy.config.coverage import load_coverage
29
+ from mapproxy.srs import SRS, TransformationError
30
+ from mapproxy.util.py import memoize
31
+ from mapproxy.util.times import timestamp_from_isodate, timestamp_before
32
+ from mapproxy.util.coverage import MultiCoverage, BBOXCoverage, GeomCoverage
33
+ from mapproxy.util.geom import GeometryError, EmptyGeometryError, CoverageReadError
34
+ from mapproxy.util.yaml import load_yaml_file, YAMLError
35
+ from mapproxy.seed.util import bidict
36
+ from mapproxy.seed.seeder import SeedTask, CleanupTask
37
+ from mapproxy.seed.spec import validate_seed_conf
38
+
39
+ class SeedConfigurationError(ConfigurationError):
40
+ pass
41
+
42
+ class EmptyCoverageError(Exception):
43
+ pass
44
+
45
+
46
+ import logging
47
+ log = logging.getLogger('mapproxy.seed.config')
48
+
49
+ def load_seed_tasks_conf(seed_conf_filename, mapproxy_conf):
50
+ try:
51
+ conf = load_yaml_file(seed_conf_filename)
52
+ except YAMLError as ex:
53
+ raise SeedConfigurationError(ex)
54
+
55
+ if 'views' in conf:
56
+ # TODO: deprecate old config
57
+ seed_conf = LegacySeedingConfiguration(conf, mapproxy_conf=mapproxy_conf)
58
+ else:
59
+ errors, informal_only = validate_seed_conf(conf)
60
+ for error in errors:
61
+ log.warning(error)
62
+ if not informal_only:
63
+ raise SeedConfigurationError('invalid configuration')
64
+ seed_conf = SeedingConfiguration(conf, mapproxy_conf=mapproxy_conf)
65
+ return seed_conf
66
+
67
+ class LegacySeedingConfiguration(object):
68
+ """
69
+ Read old seed.yaml configuration (with seed and views).
70
+ """
71
+ def __init__(self, seed_conf, mapproxy_conf):
72
+ self.conf = seed_conf
73
+ self.mapproxy_conf = mapproxy_conf
74
+ self.grids = bidict((name, grid_conf.tile_grid()) for name, grid_conf in iteritems(self.mapproxy_conf.grids))
75
+ self.seed_tasks = []
76
+ self.cleanup_tasks = []
77
+ self._init_tasks()
78
+
79
+ def _init_tasks(self):
80
+ for cache_name, options in iteritems(self.conf['seeds']):
81
+ remove_before = None
82
+ if 'remove_before' in options:
83
+ remove_before = before_timestamp_from_options(options['remove_before'])
84
+ try:
85
+ caches = self.mapproxy_conf.caches[cache_name].caches()
86
+ except KeyError:
87
+ print('error: cache %s not found. available caches: %s' % (
88
+ cache_name, ','.join(self.mapproxy_conf.caches.keys())), file=sys.stderr)
89
+ return
90
+ caches = dict((grid, tile_mgr) for grid, extent, tile_mgr in caches)
91
+ for view in options['views']:
92
+ view_conf = self.conf['views'][view]
93
+ coverage = load_coverage(view_conf)
94
+
95
+ cache_srs = view_conf.get('srs', None)
96
+ if cache_srs is not None:
97
+ cache_srs = [SRS(s) for s in cache_srs]
98
+
99
+ level = view_conf.get('level', None)
100
+ assert len(level) == 2
101
+
102
+ for grid, tile_mgr in iteritems(caches):
103
+ if cache_srs and grid.srs not in cache_srs: continue
104
+ md = dict(name=view, cache_name=cache_name, grid_name=self.grids[grid])
105
+ levels = list(range(level[0], level[1]+1))
106
+ if coverage:
107
+ if isinstance(coverage, GeomCoverage) and coverage.geom.is_empty:
108
+ continue
109
+ seed_coverage = coverage.transform_to(grid.srs)
110
+ else:
111
+ seed_coverage = BBOXCoverage(grid.bbox, grid.srs)
112
+
113
+ self.seed_tasks.append(SeedTask(md, tile_mgr, levels, remove_before, seed_coverage))
114
+
115
+ if remove_before:
116
+ levels = list(range(grid.levels))
117
+ complete_extent = bool(coverage)
118
+ self.cleanup_tasks.append(CleanupTask(md, tile_mgr, levels, remove_before,
119
+ seed_coverage, complete_extent=complete_extent))
120
+
121
+ def seed_tasks_names(self):
122
+ return self.conf['seeds'].keys()
123
+
124
+ def cleanup_tasks_names(self):
125
+ return self.conf['seeds'].keys()
126
+
127
+ def seeds(self, names=None):
128
+ if names is None:
129
+ return self.seed_tasks
130
+ else:
131
+ return [t for t in self.seed_tasks if t.md['name'] in names]
132
+
133
+ def cleanups(self, names=None):
134
+ if names is None:
135
+ return self.cleanup_tasks
136
+ else:
137
+ return [t for t in self.cleanup_tasks if t.md['name'] in names]
138
+
139
+ class SeedingConfiguration(object):
140
+ def __init__(self, seed_conf, mapproxy_conf):
141
+ self.conf = seed_conf
142
+ self.mapproxy_conf = mapproxy_conf
143
+ self.grids = bidict((name, grid_conf.tile_grid()) for name, grid_conf in iteritems(self.mapproxy_conf.grids))
144
+
145
+ @memoize
146
+ def coverage(self, name):
147
+ coverage_conf = (self.conf.get('coverages') or {}).get(name)
148
+ if coverage_conf is None:
149
+ raise SeedConfigurationError('coverage %s not found. available coverages: %s' % (
150
+ name, ','.join((self.conf.get('coverages') or {}).keys())))
151
+
152
+ try:
153
+ coverage = load_coverage(coverage_conf)
154
+ except CoverageReadError as ex:
155
+ raise SeedConfigurationError("can't load coverage '%s'. %s" % (name, ex))
156
+ except GeometryError as ex:
157
+ raise SeedConfigurationError("invalid geometry in coverage '%s'. %s" % (name, ex))
158
+ except EmptyGeometryError as ex:
159
+ raise EmptyCoverageError("coverage '%s' contains no geometries. %s" % (name, ex))
160
+
161
+ # without extend we have an empty coverage
162
+ if not coverage.extent.llbbox:
163
+ raise EmptyCoverageError("coverage '%s' contains no geometries." % name)
164
+ return coverage
165
+
166
+ def cache(self, cache_name):
167
+ cache = {}
168
+ if cache_name not in self.mapproxy_conf.caches:
169
+ raise SeedConfigurationError('cache %s not found. available caches: %s' % (
170
+ cache_name, ','.join(self.mapproxy_conf.caches.keys())))
171
+ for tile_grid, extent, tile_mgr in self.mapproxy_conf.caches[cache_name].caches():
172
+ if isinstance(tile_mgr.cache, DummyCache):
173
+ raise SeedConfigurationError('can\'t seed cache %s (disable_storage: true)' %
174
+ cache_name)
175
+ grid_name = self.grids[tile_grid]
176
+ cache[grid_name] = tile_mgr
177
+ return cache
178
+
179
+ def seed_tasks_names(self):
180
+ seeds = self.conf.get('seeds') or {}
181
+ if seeds:
182
+ return seeds.keys()
183
+ return []
184
+
185
+ def cleanup_tasks_names(self):
186
+ cleanups = self.conf.get('cleanups') or {}
187
+ if cleanups:
188
+ return cleanups.keys()
189
+ return []
190
+
191
+ def seeds(self, names=None):
192
+ """
193
+ Return seed tasks.
194
+ """
195
+ tasks = []
196
+ if names is None:
197
+ names = (self.conf.get('seeds') or {}).keys()
198
+
199
+ for seed_name in names:
200
+ seed_conf = self.conf['seeds'][seed_name]
201
+ seed_conf = SeedConfiguration(seed_name, seed_conf, self)
202
+ for task in seed_conf.seed_tasks():
203
+ tasks.append(task)
204
+ return tasks
205
+
206
+ def cleanups(self, names=None):
207
+ """
208
+ Return cleanup tasks.
209
+ """
210
+ tasks = []
211
+ if names is None:
212
+ names = (self.conf.get('cleanups') or {}).keys()
213
+
214
+ for cleanup_name in names:
215
+ cleanup_conf = self.conf['cleanups'][cleanup_name]
216
+ cleanup_conf = CleanupConfiguration(cleanup_name, cleanup_conf, self)
217
+ for task in cleanup_conf.cleanup_tasks():
218
+ tasks.append(task)
219
+ return tasks
220
+
221
+
222
+ class ConfigurationBase(object):
223
+ def __init__(self, name, conf, seeding_conf):
224
+ self.name = name
225
+ self.conf = conf
226
+ self.seeding_conf = seeding_conf
227
+
228
+ self.coverage = self._coverages()
229
+ self.caches = self._caches()
230
+ self.grids = self._grids(self.caches)
231
+ self.levels = levels_from_options(conf)
232
+
233
+ def _coverages(self):
234
+ coverage = None
235
+ if 'coverages' in self.conf:
236
+ try:
237
+ coverages = [self.seeding_conf.coverage(c) for c in self.conf.get('coverages', {})]
238
+ except EmptyCoverageError:
239
+ return False
240
+ if len(coverages) == 1:
241
+ coverage = coverages[0]
242
+ else:
243
+ coverage = MultiCoverage(coverages)
244
+ return coverage
245
+
246
+ def _grids(self, caches):
247
+ grids = []
248
+
249
+ if 'grids' in self.conf:
250
+ # grids available for all caches
251
+ available_grids = reduce(operator.and_, (set(cache) for cache in caches.values()))
252
+ for grid_name in self.conf['grids']:
253
+ if grid_name not in available_grids:
254
+ raise SeedConfigurationError('%s not defined for caches' % grid_name)
255
+ grids.append(grid_name)
256
+ else:
257
+ # check that all caches have the same grids configured
258
+ last = []
259
+ for cache_grids in (set(iterkeys(cache)) for cache in itervalues(caches)):
260
+ if not last:
261
+ last = cache_grids
262
+ else:
263
+ if last != cache_grids:
264
+ raise SeedConfigurationError('caches in same seed task require identical grids')
265
+ grids = list(last or [])
266
+ return grids
267
+
268
+ def _caches(self):
269
+ """
270
+ Returns a dictionary with all caches for this seed.
271
+
272
+ e.g.: {'seed1': {'grid1': tilemanager1, 'grid2': tilemanager2}}
273
+ """
274
+ caches = {}
275
+ for cache_name in self.conf.get('caches', []):
276
+ caches[cache_name] = self.seeding_conf.cache(cache_name)
277
+ return caches
278
+
279
+
280
+ class SeedConfiguration(ConfigurationBase):
281
+ def __init__(self, name, conf, seeding_conf):
282
+ ConfigurationBase.__init__(self, name, conf, seeding_conf)
283
+
284
+ self.refresh_timestamp = None
285
+ if 'refresh_before' in self.conf:
286
+ self.refresh_timestamp = before_timestamp_from_options(self.conf['refresh_before'])
287
+
288
+ def seed_tasks(self):
289
+ for grid_name in self.grids:
290
+ for cache_name, cache in iteritems(self.caches):
291
+ tile_manager = cache[grid_name]
292
+ grid = self.seeding_conf.grids[grid_name]
293
+ if self.coverage is False:
294
+ coverage = False
295
+ elif self.coverage:
296
+ coverage = self.coverage.transform_to(grid.srs)
297
+ else:
298
+ coverage = BBOXCoverage(grid.bbox, grid.srs)
299
+
300
+ try:
301
+ if coverage is not False:
302
+ coverage.extent.llbbox
303
+ except TransformationError:
304
+ raise SeedConfigurationError('%s: coverage transformation error' % self.name)
305
+
306
+ if self.levels:
307
+ levels = self.levels.for_grid(grid)
308
+ else:
309
+ levels = list(range(0, grid.levels))
310
+
311
+ if not tile_manager.cache.supports_timestamp:
312
+ if self.refresh_timestamp:
313
+ # remove everything
314
+ self.refresh_timestamp = 0
315
+
316
+ md = dict(name=self.name, cache_name=cache_name, grid_name=grid_name)
317
+
318
+ if tile_manager.rescale_tiles:
319
+ if tile_manager.rescale_tiles > 0:
320
+ levels = levels[::-1]
321
+ for l in levels:
322
+ yield SeedTask(md, tile_manager, [l], self.refresh_timestamp, coverage)
323
+ else:
324
+ yield SeedTask(md, tile_manager, levels, self.refresh_timestamp, coverage)
325
+
326
+ class CleanupConfiguration(ConfigurationBase):
327
+ def __init__(self, name, conf, seeding_conf):
328
+ ConfigurationBase.__init__(self, name, conf, seeding_conf)
329
+ self.init_time = time.time()
330
+
331
+ if self.conf.get('remove_all') == True:
332
+ self.remove_timestamp = 0
333
+ elif 'remove_before' in self.conf:
334
+ self.remove_timestamp = before_timestamp_from_options(self.conf['remove_before'])
335
+ else:
336
+ # use now as remove_before date. this should not remove
337
+ # fresh seeded tiles, since this should be configured before seeding
338
+ self.remove_timestamp = self.init_time
339
+
340
+ def cleanup_tasks(self):
341
+ for grid_name in self.grids:
342
+ for cache_name, cache in iteritems(self.caches):
343
+ tile_manager = cache[grid_name]
344
+ grid = self.seeding_conf.grids[grid_name]
345
+ if self.coverage is False:
346
+ coverage = False
347
+ complete_extent = False
348
+ elif self.coverage:
349
+ coverage = self.coverage.transform_to(grid.srs)
350
+ complete_extent = False
351
+ else:
352
+ coverage = BBOXCoverage(grid.bbox, grid.srs)
353
+ complete_extent = True
354
+
355
+ try:
356
+ if coverage is not False:
357
+ coverage.extent.llbbox
358
+ except TransformationError:
359
+ raise SeedConfigurationError('%s: coverage transformation error' % self.name)
360
+
361
+ if self.levels:
362
+ levels = self.levels.for_grid(grid)
363
+ else:
364
+ levels = list(range(0, grid.levels))
365
+
366
+ if not tile_manager.cache.supports_timestamp:
367
+ # for caches without timestamp support (like MBTiles)
368
+ if self.remove_timestamp is self.init_time or self.remove_timestamp == 0:
369
+ # remove everything
370
+ self.remove_timestamp = 0
371
+ else:
372
+ raise SeedConfigurationError("cleanup does not support remove_before for '%s'"
373
+ " because cache '%s' does not support timestamps" % (self.name, cache_name))
374
+ md = dict(name=self.name, cache_name=cache_name, grid_name=grid_name)
375
+ yield CleanupTask(md, tile_manager, levels, self.remove_timestamp,
376
+ coverage=coverage, complete_extent=complete_extent)
377
+
378
+
379
+ def levels_from_options(conf):
380
+ levels = conf.get('levels')
381
+ if levels:
382
+ if isinstance(levels, list):
383
+ return LevelsList(levels)
384
+ from_level = levels.get('from')
385
+ to_level = levels.get('to')
386
+ return LevelsRange((from_level, to_level))
387
+ resolutions = conf.get('resolutions')
388
+ if resolutions:
389
+ if isinstance(resolutions, list):
390
+ return LevelsResolutionList(resolutions)
391
+ from_res = resolutions.get('from')
392
+ to_res = resolutions.get('to')
393
+ return LevelsResolutionRange((from_res, to_res))
394
+ return None
395
+
396
+ def before_timestamp_from_options(conf):
397
+ """
398
+ >>> import time
399
+ >>> t = before_timestamp_from_options({'hours': 4})
400
+ >>> time.time() - t - 4 * 60 * 60 < 1
401
+ True
402
+ """
403
+ if 'time' in conf:
404
+ try:
405
+ return timestamp_from_isodate(conf['time'])
406
+ except ValueError:
407
+ raise SeedConfigurationError(
408
+ "can't parse time '%s'. should be ISO time string" % (conf["time"], ))
409
+ if 'mtime' in conf:
410
+ datasource = abspath(conf['mtime'])
411
+ try:
412
+ return os.path.getmtime(datasource)
413
+ except OSError as ex:
414
+ raise SeedConfigurationError(
415
+ "can't parse last modified time from file '%s'." % (datasource, ), ex)
416
+ deltas = {}
417
+ for delta_type in ('weeks', 'days', 'hours', 'minutes', 'seconds'):
418
+ deltas[delta_type] = conf.get(delta_type, 0)
419
+ return timestamp_before(**deltas)
420
+
421
+
422
+ class LevelsList(object):
423
+ def __init__(self, levels=None):
424
+ self.levels = levels
425
+
426
+ def for_grid(self, grid):
427
+ uniqe_valid_levels = set(l for l in self.levels if 0 <= l <= (grid.levels-1))
428
+ return sorted(uniqe_valid_levels)
429
+
430
+ class LevelsRange(object):
431
+ def __init__(self, level_range=None):
432
+ self.level_range = level_range
433
+
434
+ def for_grid(self, grid):
435
+ start, stop = self.level_range
436
+ if start is None:
437
+ start = 0
438
+ if stop is None:
439
+ stop = 999
440
+
441
+ stop = min(stop, grid.levels-1)
442
+
443
+ return list(range(start, stop+1))
444
+
445
+ class LevelsResolutionRange(object):
446
+ def __init__(self, res_range=None):
447
+ self.res_range = res_range
448
+ def for_grid(self, grid):
449
+ start, stop = self.res_range
450
+ if start is None:
451
+ start = 0
452
+ else:
453
+ start = grid.closest_level(start)
454
+
455
+ if stop is None:
456
+ stop = grid.levels-1
457
+ else:
458
+ stop = grid.closest_level(stop)
459
+
460
+ return list(range(start, stop+1))
461
+
462
+ class LevelsResolutionList(object):
463
+ def __init__(self, resolutions=None):
464
+ self.resolutions = resolutions
465
+
466
+ def for_grid(self, grid):
467
+ levels = set(grid.closest_level(res) for res in self.resolutions)
468
+ return sorted(levels)
469
+