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,87 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2010 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+
17
+ import os
18
+ import hashlib
19
+
20
+ from mapproxy.image import ImageSource
21
+ from mapproxy.image.opts import ImageOptions
22
+ from mapproxy.util.fs import ensure_directory, write_atomic
23
+
24
+ import logging
25
+ log = logging.getLogger(__name__)
26
+
27
+
28
+ def legend_identifier(legends):
29
+ """
30
+ >>> legend_identifier([("http://example/?", "foo"), ("http://example/?", "bar")])
31
+ 'http://example/?foohttp://example/?bar'
32
+
33
+ :param legends: list of legend URL and layer tuples
34
+ """
35
+ parts = []
36
+ for url, layer in legends:
37
+ parts.append(url)
38
+ if layer:
39
+ parts.append(layer)
40
+ return ''.join(parts)
41
+
42
+
43
+ def legend_hash(identifier, scale):
44
+ md5 = hashlib.md5()
45
+ md5.update(identifier.encode('utf-8'))
46
+ md5.update(str(scale).encode('ascii'))
47
+ return md5.hexdigest()
48
+
49
+
50
+ class LegendCache(object):
51
+ def __init__(self, cache_dir=None, file_ext='png'):
52
+ self.cache_dir = cache_dir
53
+ self.file_ext = file_ext
54
+
55
+ def store(self, legend):
56
+ if legend.stored:
57
+ return
58
+
59
+ if legend.location is None:
60
+ hash = legend_hash(legend.id, legend.scale)
61
+ legend.location = os.path.join(self.cache_dir, hash) + '.' + self.file_ext
62
+ ensure_directory(legend.location)
63
+
64
+ data = legend.source.as_buffer(ImageOptions(format='image/' + self.file_ext), seekable=True)
65
+ data.seek(0)
66
+ log.debug('writing to %s' % (legend.location))
67
+ write_atomic(legend.location, data.read())
68
+ data.seek(0)
69
+ legend.stored = True
70
+
71
+ def load(self, legend):
72
+ hash = legend_hash(legend.id, legend.scale)
73
+ legend.location = os.path.join(self.cache_dir, hash) + '.' + self.file_ext
74
+
75
+ if os.path.exists(legend.location):
76
+ legend.source = ImageSource(legend.location)
77
+ return True
78
+ return False
79
+
80
+
81
+ class Legend(object):
82
+ def __init__(self, source=None, id=None, scale=None):
83
+ self.source = source
84
+ self.stored = None
85
+ self.location = None
86
+ self.id = id
87
+ self.scale = scale
@@ -0,0 +1,411 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2011-2013 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
+ import glob
17
+ import hashlib
18
+ import os
19
+ import sqlite3
20
+ import threading
21
+ import time
22
+ from io import BytesIO
23
+ from itertools import groupby
24
+
25
+ from mapproxy.image import ImageSource
26
+ from mapproxy.cache.base import TileCacheBase, tile_buffer, REMOVE_ON_UNLOCK
27
+ from mapproxy.util.fs import ensure_directory
28
+ from mapproxy.util.lock import FileLock
29
+
30
+ import logging
31
+ log = logging.getLogger(__name__)
32
+
33
+ if not hasattr(glob, 'escape'):
34
+ import re
35
+ glob.escape = lambda pathname: re.sub(r'([*?[])', r'[\1]', pathname)
36
+
37
+
38
+ def sqlite_datetime_to_timestamp(datetime):
39
+ if datetime is None:
40
+ return None
41
+ d = time.strptime(datetime, "%Y-%m-%d %H:%M:%S")
42
+ return time.mktime(d)
43
+
44
+
45
+ class MBTilesCache(TileCacheBase):
46
+ supports_timestamp = False
47
+
48
+ def __init__(self, mbtile_file, with_timestamps=False, timeout=30, wal=False, ttl=0, coverage=None):
49
+ super(MBTilesCache, self).__init__(coverage)
50
+ md5 = hashlib.new('md5', mbtile_file.encode('utf-8'), usedforsecurity=False)
51
+ self.lock_cache_id = 'mbtiles-' + md5.hexdigest()
52
+ self.mbtile_file = mbtile_file
53
+ self.supports_timestamp = with_timestamps
54
+ self.ttl = with_timestamps and ttl or 0
55
+ self.timeout = timeout
56
+ self.wal = wal
57
+ self.ensure_mbtile()
58
+ self._db_conn_cache = threading.local()
59
+
60
+ @property
61
+ def db(self):
62
+ if not getattr(self._db_conn_cache, 'db', None):
63
+ self.ensure_mbtile()
64
+ self._db_conn_cache.db = sqlite3.connect(self.mbtile_file, self.timeout)
65
+ return self._db_conn_cache.db
66
+
67
+ def cleanup(self):
68
+ """
69
+ Close all open connection and remove them from cache.
70
+ """
71
+ if getattr(self._db_conn_cache, 'db', None):
72
+ self._db_conn_cache.db.close()
73
+ self._db_conn_cache.db = None
74
+
75
+ def ensure_mbtile(self):
76
+ if not os.path.exists(self.mbtile_file):
77
+ with FileLock(self.mbtile_file + '.init.lck',
78
+ remove_on_unlock=REMOVE_ON_UNLOCK):
79
+ if not os.path.exists(self.mbtile_file):
80
+ ensure_directory(self.mbtile_file)
81
+ self._initialize_mbtile()
82
+
83
+ def _initialize_mbtile(self):
84
+ log.info('initializing MBTile file %s', self.mbtile_file)
85
+ db = sqlite3.connect(self.mbtile_file)
86
+
87
+ if self.wal:
88
+ db.execute('PRAGMA journal_mode=wal')
89
+
90
+ stmt = """
91
+ CREATE TABLE tiles (
92
+ zoom_level integer,
93
+ tile_column integer,
94
+ tile_row integer,
95
+ tile_data blob
96
+ """
97
+
98
+ if self.supports_timestamp:
99
+ stmt += """
100
+ , last_modified datetime DEFAULT (datetime('now','localtime'))
101
+ """
102
+ stmt += """
103
+ );
104
+ """
105
+ db.execute(stmt)
106
+
107
+ db.execute("""
108
+ CREATE TABLE metadata (name text, value text);
109
+ """)
110
+ db.execute("""
111
+ CREATE UNIQUE INDEX idx_tile on tiles
112
+ (zoom_level, tile_column, tile_row);
113
+ """)
114
+ db.commit()
115
+ db.close()
116
+
117
+ def update_metadata(self, name='', description='', version=1, overlay=True, format='png'):
118
+ db = sqlite3.connect(self.mbtile_file)
119
+ db.execute("""
120
+ CREATE TABLE IF NOT EXISTS metadata (name text, value text);
121
+ """)
122
+ db.execute("""DELETE FROM metadata;""")
123
+
124
+ if overlay:
125
+ layer_type = 'overlay'
126
+ else:
127
+ layer_type = 'baselayer'
128
+
129
+ db.executemany("""
130
+ INSERT INTO metadata (name, value) VALUES (?,?)
131
+ """,
132
+ (
133
+ ('name', name),
134
+ ('description', description),
135
+ ('version', version),
136
+ ('type', layer_type),
137
+ ('format', format),
138
+ )
139
+ )
140
+ db.commit()
141
+ db.close()
142
+
143
+ def is_cached(self, tile, dimensions=None):
144
+ if tile.coord is None:
145
+ return True
146
+ if tile.source:
147
+ return True
148
+
149
+ return self.load_tile(tile, dimensions=dimensions)
150
+
151
+ def store_tile(self, tile, dimensions=None):
152
+ if tile.stored:
153
+ return True
154
+ return self._store_bulk([tile])
155
+
156
+ def store_tiles(self, tiles, dimensions=None):
157
+ tiles = [t for t in tiles if not t.stored]
158
+ return self._store_bulk(tiles)
159
+
160
+ def _store_bulk(self, tiles):
161
+ records = []
162
+ # tile_buffer (as_buffer) will encode the tile to the target format
163
+ # we collect all tiles before, to avoid having the db transaction
164
+ # open during this slow encoding
165
+ for tile in tiles:
166
+ with tile_buffer(tile) as buf:
167
+ content = buf.read()
168
+ x, y, level = tile.coord
169
+ if self.supports_timestamp:
170
+ records.append((level, x, y, content, time.time()))
171
+ else:
172
+ records.append((level, x, y, content))
173
+
174
+ cursor = self.db.cursor()
175
+ try:
176
+ if self.supports_timestamp:
177
+ stmt = ("INSERT OR REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data, last_modified)"
178
+ " VALUES (?,?,?,?, datetime(?, 'unixepoch', 'localtime'))")
179
+ cursor.executemany(stmt, records)
180
+ else:
181
+ stmt = "INSERT OR REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES (?,?,?,?)"
182
+ cursor.executemany(stmt, records)
183
+ self.db.commit()
184
+ except sqlite3.OperationalError as ex:
185
+ log.warning('unable to store tile: %s', ex)
186
+ return False
187
+ return True
188
+
189
+ def load_tile(self, tile, with_metadata=False, dimensions=None):
190
+ if tile.source or tile.coord is None:
191
+ return True
192
+
193
+ cur = self.db.cursor()
194
+ if self.supports_timestamp:
195
+ stmt = '''SELECT tile_data, last_modified
196
+ FROM tiles
197
+ WHERE tile_column = ? AND
198
+ tile_row = ? AND
199
+ zoom_level = ?'''
200
+ else:
201
+ stmt = '''SELECT tile_data FROM tiles
202
+ WHERE tile_column = ? AND
203
+ tile_row = ? AND
204
+ zoom_level = ?'''
205
+
206
+ if self.ttl:
207
+ stmt += " AND datetime('now', 'localtime', '%d seconds') < last_modified" % -self.ttl
208
+
209
+ cur.execute(stmt, tile.coord)
210
+
211
+ content = cur.fetchone()
212
+ if content:
213
+ tile.source = ImageSource(BytesIO(content[0]))
214
+ if self.supports_timestamp:
215
+ tile.timestamp = sqlite_datetime_to_timestamp(content[1])
216
+ return True
217
+ else:
218
+ return False
219
+
220
+ def load_tiles(self, tiles, with_metadata=False, dimensions=None):
221
+ # associate the right tiles with the cursor
222
+ tile_dict = {}
223
+ coords = []
224
+ for tile in tiles:
225
+ if tile.source or tile.coord is None:
226
+ continue
227
+ x, y, level = tile.coord
228
+ coords.append(x)
229
+ coords.append(y)
230
+ coords.append(level)
231
+ tile_dict[(x, y)] = tile
232
+
233
+ if not tile_dict:
234
+ # all tiles loaded or coords are None
235
+ return True
236
+
237
+ if self.supports_timestamp:
238
+ stmt_base = "SELECT tile_column, tile_row, tile_data, last_modified FROM tiles WHERE "
239
+ if self.ttl:
240
+ ttl_condition = "datetime('now', 'localtime', '%d seconds') < last_modified" % -self.ttl
241
+ stmt_base += ttl_condition + ' AND '
242
+ else:
243
+ stmt_base = "SELECT tile_column, tile_row, tile_data FROM tiles WHERE "
244
+
245
+ loaded_tiles = 0
246
+
247
+ # SQLite is limited to 1000 args -> split into multiple requests if more arguments are needed
248
+ while coords:
249
+ cur_coords = coords[:999]
250
+
251
+ stmt = stmt_base + '(' + ' OR '.join(
252
+ ['(tile_column = ? AND tile_row = ? AND zoom_level = ?)'] * (len(cur_coords) // 3)) + ')'
253
+
254
+ cursor = self.db.cursor()
255
+ cursor.execute(stmt, cur_coords)
256
+
257
+ for row in cursor:
258
+ loaded_tiles += 1
259
+ tile = tile_dict[(row[0], row[1])]
260
+ data = row[2]
261
+ tile.size = len(data)
262
+ tile.source = ImageSource(BytesIO(data))
263
+ if self.supports_timestamp:
264
+ tile.timestamp = sqlite_datetime_to_timestamp(row[3])
265
+ cursor.close()
266
+
267
+ coords = coords[999:]
268
+
269
+ return loaded_tiles == len(tile_dict)
270
+
271
+ def remove_tile(self, tile):
272
+ cursor = self.db.cursor()
273
+ cursor.execute(
274
+ "DELETE FROM tiles WHERE (tile_column = ? AND tile_row = ? AND zoom_level = ?)",
275
+ tile.coord)
276
+ self.db.commit()
277
+ if cursor.rowcount:
278
+ return True
279
+ return False
280
+
281
+ def remove_level_tiles_before(self, level, timestamp):
282
+ if timestamp == 0:
283
+ cursor = self.db.cursor()
284
+ cursor.execute(
285
+ "DELETE FROM tiles WHERE (zoom_level = ?)",
286
+ (level, ))
287
+ self.db.commit()
288
+ if cursor.rowcount:
289
+ return True
290
+ return False
291
+
292
+ if self.supports_timestamp:
293
+ cursor = self.db.cursor()
294
+ cursor.execute(
295
+ "DELETE FROM tiles WHERE (zoom_level = ? AND last_modified < datetime(?, 'unixepoch', 'localtime'))",
296
+ (level, timestamp))
297
+ self.db.commit()
298
+ if cursor.rowcount:
299
+ return True
300
+ return False
301
+
302
+ def load_tile_metadata(self, tile, dimensions=None):
303
+ if not self.supports_timestamp:
304
+ # MBTiles specification does not include timestamps.
305
+ # This sets the timestamp of the tile to epoch (1970s)
306
+ tile.timestamp = -1
307
+ else:
308
+ self.load_tile(tile, dimensions=dimensions)
309
+
310
+
311
+ class MBTilesLevelCache(TileCacheBase):
312
+ supports_timestamp = True
313
+
314
+ def __init__(self, mbtiles_dir, timeout=30, wal=False, ttl=0, coverage=None):
315
+ super(MBTilesLevelCache, self).__init__(coverage)
316
+ md5 = hashlib.new('md5', mbtiles_dir.encode('utf-8'), usedforsecurity=False)
317
+ self.lock_cache_id = 'sqlite-' + md5.hexdigest()
318
+ self.cache_dir = mbtiles_dir
319
+ self._mbtiles = {}
320
+ self.timeout = timeout
321
+ self.wal = wal
322
+ self.ttl = ttl
323
+ self._mbtiles_lock = threading.Lock()
324
+
325
+ def _get_level(self, level):
326
+ if level in self._mbtiles:
327
+ return self._mbtiles[level]
328
+
329
+ with self._mbtiles_lock:
330
+ if level not in self._mbtiles:
331
+ mbtile_filename = os.path.join(self.cache_dir, '%s.mbtile' % level)
332
+ self._mbtiles[level] = MBTilesCache(
333
+ mbtile_filename,
334
+ with_timestamps=True,
335
+ timeout=self.timeout,
336
+ wal=self.wal,
337
+ ttl=self.ttl,
338
+ coverage=self.coverage
339
+ )
340
+
341
+ return self._mbtiles[level]
342
+
343
+ def cleanup(self):
344
+ """
345
+ Close all open connection and remove them from cache.
346
+ """
347
+ with self._mbtiles_lock:
348
+ for mbtile in self._mbtiles.values():
349
+ mbtile.cleanup()
350
+
351
+ def is_cached(self, tile, dimensions=None):
352
+ if tile.coord is None:
353
+ return True
354
+ if tile.source:
355
+ return True
356
+
357
+ return self._get_level(tile.coord[2]).is_cached(tile, dimensions=dimensions)
358
+
359
+ def store_tile(self, tile, dimensions=None):
360
+ if tile.stored:
361
+ return True
362
+
363
+ return self._get_level(tile.coord[2]).store_tile(tile, dimensions=dimensions)
364
+
365
+ def store_tiles(self, tiles, dimensions=None):
366
+ failed = False
367
+ for level, tiles in groupby(tiles, key=lambda t: t.coord[2]):
368
+ tiles = [t for t in tiles if not t.stored]
369
+ res = self._get_level(level).store_tiles(tiles, dimensions=dimensions)
370
+ if not res:
371
+ failed = True
372
+ return failed
373
+
374
+ def load_tile(self, tile, with_metadata=False, dimensions=None):
375
+ if tile.source or tile.coord is None:
376
+ return True
377
+
378
+ return self._get_level(tile.coord[2]).load_tile(tile, with_metadata=with_metadata, dimensions=dimensions)
379
+
380
+ def load_tiles(self, tiles, with_metadata=False, dimensions=None):
381
+ level = None
382
+ for tile in tiles:
383
+ if tile.source or tile.coord is None:
384
+ continue
385
+ level = tile.coord[2]
386
+ break
387
+
388
+ if not level:
389
+ return True
390
+
391
+ return self._get_level(level).load_tiles(tiles, with_metadata=with_metadata, dimensions=dimensions)
392
+
393
+ def remove_tile(self, tile, dimensions=None):
394
+ if tile.coord is None:
395
+ return True
396
+
397
+ return self._get_level(tile.coord[2]).remove_tile(tile)
398
+
399
+ def load_tile_metadata(self, tile, dimensions=None):
400
+ self.load_tile(tile, dimensions=dimensions)
401
+
402
+ def remove_level_tiles_before(self, level, timestamp):
403
+ level_cache = self._get_level(level)
404
+ if timestamp == 0:
405
+ level_cache.cleanup()
406
+ os.unlink(level_cache.mbtile_file)
407
+ for file in glob.glob("%s-*" % glob.escape(level_cache.mbtile_file)):
408
+ os.unlink(file)
409
+ return True
410
+ else:
411
+ return level_cache.remove_level_tiles_before(level, timestamp)
mapproxy/cache/meta.py ADDED
@@ -0,0 +1,80 @@
1
+ from __future__ import print_function
2
+ import struct
3
+ from mapproxy.cache.base import tile_buffer
4
+ from mapproxy.image import ImageSource
5
+
6
+
7
+ class MetaTileFile(object):
8
+ def __init__(self, meta_tile):
9
+ self.meta_tile = meta_tile
10
+
11
+ def write_tiles(self, tiles):
12
+ tile_positions = []
13
+ count = len(tiles) # self.meta_tile.grid_size[0]
14
+ header_size = (
15
+ 4 # META
16
+ + 4 # metasize**2
17
+ + 3*4 # x, y, z
18
+ + count * 8 # offset/size * tiles
19
+ )
20
+ with open('/tmp/foo.metatile', 'wb') as f:
21
+ f.write("META")
22
+ f.write(struct.pack('i', count))
23
+ f.write(struct.pack('iii', *tiles[0].coord))
24
+ offsets_header_pos = f.tell()
25
+ f.seek(header_size, 0)
26
+
27
+ for tile in tiles:
28
+ offset = f.tell()
29
+ with tile_buffer(tile) as buf:
30
+ tile_data = buf.read()
31
+ f.write(tile_data)
32
+ tile_positions.append((offset, len(tile_data)))
33
+
34
+ f.seek(offsets_header_pos, 0)
35
+ for offset, size in tile_positions:
36
+ f.write(struct.pack('ii', offset, size))
37
+
38
+ def _read_header(self, f):
39
+ f.seek(0, 0)
40
+ assert f.read(4) == "META"
41
+ count, x, y, z = struct.unpack('iiii', f.read(4*4))
42
+ tile_positions = []
43
+ for i in range(count):
44
+ offset, size = struct.unpack('ii', f.read(4*2))
45
+ tile_positions.append((offset, size))
46
+
47
+ return tile_positions
48
+
49
+ def read_tiles(self):
50
+ with open('/tmp/foo.metatile', 'rb') as f:
51
+ tile_positions = self._read_header(f)
52
+
53
+ for i, (offset, size) in enumerate(tile_positions):
54
+ f.seek(offset, 0)
55
+ # img = ImageSource(BytesIO(f.read(size)))
56
+ open('/tmp/img-%02d.png' % i, 'wb').write(f.read(size))
57
+
58
+
59
+ if __name__ == '__main__':
60
+ from io import BytesIO
61
+ from mapproxy.cache.tile import Tile
62
+ from mapproxy.test.image import create_tmp_image
63
+
64
+ tiles = []
65
+ img = create_tmp_image((256, 256))
66
+ for x in range(8):
67
+ for y in range(8):
68
+ tiles.append(Tile((x, y, 4), ImageSource(BytesIO(img))))
69
+
70
+ m = MetaTileFile(None)
71
+ print('!')
72
+ m.write_tiles(tiles)
73
+ print('!')
74
+ m.read_tiles()
75
+ print('!')
76
+
77
+ x = y = 0
78
+ METATILE = 8
79
+ for meta in range(METATILE ** 2):
80
+ print(x + (meta / METATILE), y + (meta % METATILE))