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,609 @@
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
+
17
+ import hashlib
18
+ import logging
19
+ import os
20
+ import re
21
+ import sqlite3
22
+ import threading
23
+
24
+ from mapproxy.cache.base import TileCacheBase, tile_buffer, REMOVE_ON_UNLOCK
25
+ from mapproxy.compat import BytesIO, PY2, itertools
26
+ from mapproxy.image import ImageSource
27
+ from mapproxy.srs import get_epsg_num
28
+ from mapproxy.util.fs import ensure_directory
29
+ from mapproxy.util.lock import FileLock
30
+
31
+
32
+ log = logging.getLogger(__name__)
33
+
34
+ class GeopackageCache(TileCacheBase):
35
+ supports_timestamp = False
36
+
37
+ def __init__(self, geopackage_file, tile_grid, table_name, with_timestamps=False, timeout=30, wal=False):
38
+ self.tile_grid = tile_grid
39
+ self.table_name = self._check_table_name(table_name)
40
+ self.lock_cache_id = 'gpkg' + hashlib.md5(geopackage_file.encode('utf-8')).hexdigest()
41
+ self.geopackage_file = geopackage_file
42
+ # XXX timestamps not implemented
43
+ self.supports_timestamp = with_timestamps
44
+ self.timeout = timeout
45
+ self.wal = wal
46
+ self.ensure_gpkg()
47
+ self._db_conn_cache = threading.local()
48
+
49
+ @property
50
+ def db(self):
51
+ if not getattr(self._db_conn_cache, 'db', None):
52
+ self.ensure_gpkg()
53
+ self._db_conn_cache.db = sqlite3.connect(self.geopackage_file, timeout=self.timeout)
54
+ return self._db_conn_cache.db
55
+
56
+ def cleanup(self):
57
+ """
58
+ Close all open connection and remove them from cache.
59
+ """
60
+ if getattr(self._db_conn_cache, 'db', None):
61
+ self._db_conn_cache.db.close()
62
+ self._db_conn_cache.db = None
63
+
64
+ @staticmethod
65
+ def _check_table_name(table_name):
66
+ """
67
+ >>> GeopackageCache._check_table_name("test")
68
+ 'test'
69
+ >>> GeopackageCache._check_table_name("test_2")
70
+ 'test_2'
71
+ >>> GeopackageCache._check_table_name("test-2")
72
+ 'test-2'
73
+ >>> GeopackageCache._check_table_name("test3;")
74
+ Traceback (most recent call last):
75
+ ...
76
+ ValueError: The table_name test3; contains unsupported characters.
77
+ >>> GeopackageCache._check_table_name("table name")
78
+ Traceback (most recent call last):
79
+ ...
80
+ ValueError: The table_name table name contains unsupported characters.
81
+
82
+ @param table_name: A desired name for an geopackage table.
83
+ @return: The name of the table if it is good, otherwise an exception.
84
+ """
85
+ # Regex string indicating table names which will be accepted.
86
+ regex_str = '^[a-zA-Z0-9_-]+$'
87
+ if re.match(regex_str, table_name):
88
+ return table_name
89
+ else:
90
+ msg = ("The table name may only contain alphanumeric characters, an underscore, "
91
+ "or a dash: {}".format(regex_str))
92
+ log.info(msg)
93
+ raise ValueError("The table_name {0} contains unsupported characters.".format(table_name))
94
+
95
+ def ensure_gpkg(self):
96
+ if not os.path.isfile(self.geopackage_file):
97
+ with FileLock(self.geopackage_file + '.init.lck',
98
+ remove_on_unlock=REMOVE_ON_UNLOCK):
99
+ ensure_directory(self.geopackage_file)
100
+ self._initialize_gpkg()
101
+ else:
102
+ if not self.check_gpkg():
103
+ ensure_directory(self.geopackage_file)
104
+ self._initialize_gpkg()
105
+
106
+ def check_gpkg(self):
107
+ if not self._verify_table():
108
+ return False
109
+ if not self._verify_gpkg_contents():
110
+ return False
111
+ if not self._verify_tile_size():
112
+ return False
113
+ return True
114
+
115
+ def _verify_table(self):
116
+ with sqlite3.connect(self.geopackage_file) as db:
117
+ cur = db.execute("""SELECT name FROM sqlite_master WHERE type='table' AND name=?""",
118
+ (self.table_name,))
119
+ content = cur.fetchone()
120
+ if not content:
121
+ # Table doesn't exist _initialize_gpkg will create a new one.
122
+ return False
123
+ return True
124
+
125
+ def _verify_gpkg_contents(self):
126
+ with sqlite3.connect(self.geopackage_file) as db:
127
+ cur = db.execute("""SELECT * FROM gpkg_contents WHERE table_name = ?"""
128
+ , (self.table_name,))
129
+
130
+ results = cur.fetchone()
131
+ if not results:
132
+ # Table doesn't exist in gpkg_contents _initialize_gpkg will add it.
133
+ return False
134
+ gpkg_data_type = results[1]
135
+ gpkg_srs_id = results[9]
136
+ cur = db.execute("""SELECT * FROM gpkg_spatial_ref_sys WHERE srs_id = ?"""
137
+ , (gpkg_srs_id,))
138
+
139
+ gpkg_coordsys_id = cur.fetchone()[3]
140
+ if gpkg_data_type.lower() != "tiles":
141
+ log.info("The geopackage table name already exists for a data type other than tiles.")
142
+ raise ValueError("table_name is improperly configured.")
143
+ if gpkg_coordsys_id != get_epsg_num(self.tile_grid.srs.srs_code):
144
+ log.info(
145
+ "The geopackage {0} table name {1} already exists and has an SRS of {2}, which does not match the configured" \
146
+ " Mapproxy SRS of {3}.".format(self.geopackage_file, self.table_name, gpkg_coordsys_id,
147
+ get_epsg_num(self.tile_grid.srs.srs_code)))
148
+ raise ValueError("srs is improperly configured.")
149
+ return True
150
+
151
+ def _verify_tile_size(self):
152
+ with sqlite3.connect(self.geopackage_file) as db:
153
+ cur = db.execute(
154
+ """SELECT * FROM gpkg_tile_matrix WHERE table_name = ?""",
155
+ (self.table_name,))
156
+
157
+ results = cur.fetchall()
158
+ results = results[0]
159
+ tile_size = self.tile_grid.tile_size
160
+
161
+ if not results:
162
+ # There is no tile conflict. Return to allow the creation of new tiles.
163
+ return True
164
+
165
+ gpkg_table_name, gpkg_zoom_level, gpkg_matrix_width, gpkg_matrix_height, gpkg_tile_width, gpkg_tile_height, \
166
+ gpkg_pixel_x_size, gpkg_pixel_y_size = results
167
+ resolution = self.tile_grid.resolution(gpkg_zoom_level)
168
+ if gpkg_tile_width != tile_size[0] or gpkg_tile_height != tile_size[1]:
169
+ log.info(
170
+ "The geopackage {0} table name {1} already exists and has tile sizes of ({2},{3})"
171
+ " which is different than the configure tile sizes of ({4},{5}).".format(self.geopackage_file,
172
+ self.table_name,
173
+ gpkg_tile_width,
174
+ gpkg_tile_height,
175
+ tile_size[0],
176
+ tile_size[1]))
177
+ log.info("The current mapproxy configuration is invalid for this geopackage.")
178
+ raise ValueError("tile_size is improperly configured.")
179
+ if not is_close(gpkg_pixel_x_size, resolution) or not is_close(gpkg_pixel_y_size, resolution):
180
+ log.info(
181
+ "The geopackage {0} table name {1} already exists and level {2} a resolution of ({3:.13f},{4:.13f})"
182
+ " which is different than the configured resolution of ({5:.13f},{6:.13f}).".format(self.geopackage_file,
183
+ self.table_name,
184
+ gpkg_zoom_level,
185
+ gpkg_pixel_x_size,
186
+ gpkg_pixel_y_size,
187
+ resolution,
188
+ resolution))
189
+ log.info("The current mapproxy configuration is invalid for this geopackage.")
190
+ raise ValueError("res is improperly configured.")
191
+ return True
192
+
193
+ def _initialize_gpkg(self):
194
+ log.info('initializing Geopackage file %s', self.geopackage_file)
195
+ db = sqlite3.connect(self.geopackage_file)
196
+
197
+ if self.wal:
198
+ db.execute('PRAGMA journal_mode=wal')
199
+
200
+ proj = get_epsg_num(self.tile_grid.srs.srs_code)
201
+ stmts = ["""
202
+ CREATE TABLE IF NOT EXISTS gpkg_contents
203
+ (table_name TEXT NOT NULL PRIMARY KEY, -- The name of the tiles, or feature table
204
+ data_type TEXT NOT NULL, -- Type of data stored in the table: "features" per clause Features (http://www.geopackage.org/spec/#features), "tiles" per clause Tiles (http://www.geopackage.org/spec/#tiles), or an implementer-defined value for other data tables per clause in an Extended GeoPackage
205
+ identifier TEXT UNIQUE, -- A human-readable identifier (e.g. short name) for the table_name content
206
+ description TEXT DEFAULT '', -- A human-readable description for the table_name content
207
+ last_change DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), -- Timestamp value in ISO 8601 format as defined by the strftime function %Y-%m-%dT%H:%M:%fZ format string applied to the current time
208
+ min_x DOUBLE, -- Bounding box minimum easting or longitude for all content in table_name
209
+ min_y DOUBLE, -- Bounding box minimum northing or latitude for all content in table_name
210
+ max_x DOUBLE, -- Bounding box maximum easting or longitude for all content in table_name
211
+ max_y DOUBLE, -- Bounding box maximum northing or latitude for all content in table_name
212
+ srs_id INTEGER, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id; when data_type is features, SHALL also match gpkg_geometry_columns.srs_id; When data_type is tiles, SHALL also match gpkg_tile_matrix_set.srs.id
213
+ CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id))
214
+ """,
215
+ """
216
+ CREATE TABLE IF NOT EXISTS gpkg_spatial_ref_sys
217
+ (srs_name TEXT NOT NULL, -- Human readable name of this SRS (Spatial Reference System)
218
+ srs_id INTEGER NOT NULL PRIMARY KEY, -- Unique identifier for each Spatial Reference System within a GeoPackage
219
+ organization TEXT NOT NULL, -- Case-insensitive name of the defining organization e.g. EPSG or epsg
220
+ organization_coordsys_id INTEGER NOT NULL, -- Numeric ID of the Spatial Reference System assigned by the organization
221
+ definition TEXT NOT NULL, -- Well-known Text representation of the Spatial Reference System
222
+ description TEXT)
223
+ """,
224
+ """
225
+ CREATE TABLE IF NOT EXISTS gpkg_tile_matrix
226
+ (table_name TEXT NOT NULL, -- Tile Pyramid User Data Table Name
227
+ zoom_level INTEGER NOT NULL, -- 0 <= zoom_level <= max_level for table_name
228
+ matrix_width INTEGER NOT NULL, -- Number of columns (>= 1) in tile matrix at this zoom level
229
+ matrix_height INTEGER NOT NULL, -- Number of rows (>= 1) in tile matrix at this zoom level
230
+ tile_width INTEGER NOT NULL, -- Tile width in pixels (>= 1) for this zoom level
231
+ tile_height INTEGER NOT NULL, -- Tile height in pixels (>= 1) for this zoom level
232
+ pixel_x_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0)
233
+ pixel_y_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0)
234
+ CONSTRAINT pk_ttm PRIMARY KEY (table_name, zoom_level), CONSTRAINT fk_tmm_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name))
235
+ """,
236
+ """
237
+ CREATE TABLE IF NOT EXISTS gpkg_tile_matrix_set
238
+ (table_name TEXT NOT NULL PRIMARY KEY, -- Tile Pyramid User Data Table Name
239
+ srs_id INTEGER NOT NULL, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id
240
+ min_x DOUBLE NOT NULL, -- Bounding box minimum easting or longitude for all content in table_name
241
+ min_y DOUBLE NOT NULL, -- Bounding box minimum northing or latitude for all content in table_name
242
+ max_x DOUBLE NOT NULL, -- Bounding box maximum easting or longitude for all content in table_name
243
+ max_y DOUBLE NOT NULL, -- Bounding box maximum northing or latitude for all content in table_name
244
+ CONSTRAINT fk_gtms_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name), CONSTRAINT fk_gtms_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id))
245
+ """,
246
+ """
247
+ CREATE TABLE IF NOT EXISTS [{0}]
248
+ (id INTEGER PRIMARY KEY AUTOINCREMENT, -- Autoincrement primary key
249
+ zoom_level INTEGER NOT NULL, -- min(zoom_level) <= zoom_level <= max(zoom_level) for t_table_name
250
+ tile_column INTEGER NOT NULL, -- 0 to tile_matrix matrix_width - 1
251
+ tile_row INTEGER NOT NULL, -- 0 to tile_matrix matrix_height - 1
252
+ tile_data BLOB NOT NULL, -- Of an image MIME type specified in clauses Tile Encoding PNG, Tile Encoding JPEG, Tile Encoding WEBP
253
+ UNIQUE (zoom_level, tile_column, tile_row))
254
+ """.format(self.table_name)
255
+ ]
256
+
257
+ for stmt in stmts:
258
+ db.execute(stmt)
259
+
260
+ db.execute("PRAGMA foreign_keys = 1;")
261
+
262
+ # List of WKT execute statements and data.("""
263
+ wkt_statement = """
264
+ INSERT OR REPLACE INTO gpkg_spatial_ref_sys (
265
+ srs_id,
266
+ organization,
267
+ organization_coordsys_id,
268
+ srs_name,
269
+ definition)
270
+ VALUES (?, ?, ?, ?, ?)
271
+ """
272
+ wkt_entries = [(3857, 'epsg', 3857, 'WGS 84 / Pseudo-Mercator',
273
+ """
274
+ PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,\
275
+ AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],\
276
+ UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],\
277
+ PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],\
278
+ PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],\
279
+ AUTHORITY["EPSG","3857"]]\
280
+ """
281
+ ),
282
+ (4326, 'epsg', 4326, 'WGS 84',
283
+ """
284
+ GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],\
285
+ AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,\
286
+ AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]\
287
+ """
288
+ ),
289
+ (-1, 'NONE', -1, ' ', 'undefined'),
290
+ (0, 'NONE', 0, ' ', 'undefined')
291
+ ]
292
+
293
+ if get_epsg_num(self.tile_grid.srs.srs_code) not in [4326, 3857]:
294
+ wkt_entries.append((proj, 'epsg', proj, 'Not provided', "Added via Mapproxy."))
295
+ db.commit()
296
+
297
+ # Add geopackage version to the header (1.0)
298
+ db.execute("PRAGMA application_id = 1196437808;")
299
+ db.commit()
300
+
301
+ for wkt_entry in wkt_entries:
302
+ try:
303
+ db.execute(wkt_statement, (wkt_entry[0], wkt_entry[1], wkt_entry[2], wkt_entry[3], wkt_entry[4]))
304
+ except sqlite3.IntegrityError:
305
+ log.info("srs_id already exists.".format(wkt_entry[0]))
306
+ db.commit()
307
+
308
+ # Ensure that tile table exists here, don't overwrite a valid entry.
309
+ try:
310
+ db.execute("""
311
+ INSERT INTO gpkg_contents (
312
+ table_name,
313
+ data_type,
314
+ identifier,
315
+ description,
316
+ min_x,
317
+ max_x,
318
+ min_y,
319
+ max_y,
320
+ srs_id)
321
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
322
+ """, (self.table_name,
323
+ "tiles",
324
+ self.table_name,
325
+ "Created with Mapproxy.",
326
+ self.tile_grid.bbox[0],
327
+ self.tile_grid.bbox[2],
328
+ self.tile_grid.bbox[1],
329
+ self.tile_grid.bbox[3],
330
+ proj))
331
+ except sqlite3.IntegrityError:
332
+ pass
333
+ db.commit()
334
+
335
+ # Ensure that tile set exists here, don't overwrite a valid entry.
336
+ try:
337
+ db.execute("""
338
+ INSERT INTO gpkg_tile_matrix_set (table_name, srs_id, min_x, max_x, min_y, max_y)
339
+ VALUES (?, ?, ?, ?, ?, ?);
340
+ """, (
341
+ self.table_name, proj, self.tile_grid.bbox[0], self.tile_grid.bbox[2], self.tile_grid.bbox[1],
342
+ self.tile_grid.bbox[3]))
343
+ except sqlite3.IntegrityError:
344
+ pass
345
+ db.commit()
346
+
347
+ tile_size = self.tile_grid.tile_size
348
+ for grid, resolution, level in zip(self.tile_grid.grid_sizes,
349
+ self.tile_grid.resolutions, range(20)):
350
+ db.execute("""INSERT OR REPLACE INTO gpkg_tile_matrix
351
+ (table_name, zoom_level, matrix_width, matrix_height, tile_width, tile_height, pixel_x_size, pixel_y_size)
352
+ VALUES(?, ?, ?, ?, ?, ?, ?, ?)
353
+ """,
354
+ (self.table_name, level, grid[0], grid[1], tile_size[0], tile_size[1], resolution, resolution))
355
+ db.commit()
356
+ db.close()
357
+
358
+ def is_cached(self, tile, dimensions=None):
359
+ if tile.coord is None:
360
+ return True
361
+ if tile.source:
362
+ return True
363
+
364
+ return self.load_tile(tile, dimensions=dimensions)
365
+
366
+
367
+ def store_tile(self, tile, dimensions=None):
368
+ if tile.stored:
369
+ return True
370
+ return self._store_bulk([tile])
371
+
372
+ def store_tiles(self, tiles, dimensions=None):
373
+ tiles = [t for t in tiles if not t.stored]
374
+ return self._store_bulk(tiles)
375
+
376
+
377
+ def _store_bulk(self, tiles):
378
+ records = []
379
+ # tile_buffer (as_buffer) will encode the tile to the target format
380
+ # we collect all tiles before, to avoid having the db transaction
381
+ # open during this slow encoding
382
+ for tile in tiles:
383
+ with tile_buffer(tile) as buf:
384
+ if PY2:
385
+ content = buffer(buf.read())
386
+ else:
387
+ content = buf.read()
388
+ x, y, level = tile.coord
389
+ records.append((level, x, y, content))
390
+
391
+ cursor = self.db.cursor()
392
+ try:
393
+ stmt = "INSERT OR REPLACE INTO [{0}] (zoom_level, tile_column, tile_row, tile_data) VALUES (?,?,?,?)".format(
394
+ self.table_name)
395
+ cursor.executemany(stmt, records)
396
+ self.db.commit()
397
+ except sqlite3.OperationalError as ex:
398
+ log.warning('unable to store tile: %s', ex)
399
+ return False
400
+ return True
401
+
402
+ def load_tile(self, tile, with_metadata=False, dimensions=None):
403
+ if tile.source or tile.coord is None:
404
+ return True
405
+
406
+ cur = self.db.cursor()
407
+ cur.execute("""SELECT tile_data FROM [{0}]
408
+ WHERE tile_column = ? AND
409
+ tile_row = ? AND
410
+ zoom_level = ?""".format(self.table_name), tile.coord)
411
+
412
+ content = cur.fetchone()
413
+ if content:
414
+ tile.source = ImageSource(BytesIO(content[0]))
415
+ return True
416
+ else:
417
+ return False
418
+
419
+ def load_tiles(self, tiles, with_metadata=False, dimensions=None):
420
+ # associate the right tiles with the cursor
421
+ tile_dict = {}
422
+ coords = []
423
+ for tile in tiles:
424
+ if tile.source or tile.coord is None:
425
+ continue
426
+ x, y, level = tile.coord
427
+ coords.append(x)
428
+ coords.append(y)
429
+ coords.append(level)
430
+ tile_dict[(x, y)] = tile
431
+
432
+ if not tile_dict:
433
+ # all tiles loaded or coords are None
434
+ return True
435
+
436
+ stmt_base = "SELECT tile_column, tile_row, tile_data FROM [{0}] WHERE ".format(self.table_name)
437
+
438
+ loaded_tiles = 0
439
+
440
+ # SQLite is limited to 1000 args -> split into multiple requests if more arguments are needed
441
+ while coords:
442
+ cur_coords = coords[:999]
443
+
444
+ stmt = stmt_base + ' OR '.join(
445
+ ['(tile_column = ? AND tile_row = ? AND zoom_level = ?)'] * (len(cur_coords) // 3))
446
+
447
+ cursor = self.db.cursor()
448
+ cursor.execute(stmt, cur_coords)
449
+
450
+ for row in cursor:
451
+ loaded_tiles += 1
452
+ tile = tile_dict[(row[0], row[1])]
453
+ data = row[2]
454
+ tile.size = len(data)
455
+ tile.source = ImageSource(BytesIO(data))
456
+ cursor.close()
457
+
458
+ coords = coords[999:]
459
+
460
+ return loaded_tiles == len(tile_dict)
461
+
462
+ def remove_tile(self, tile, dimensions=None):
463
+ cursor = self.db.cursor()
464
+ cursor.execute(
465
+ "DELETE FROM [{0}] WHERE (tile_column = ? AND tile_row = ? AND zoom_level = ?)".format(self.table_name),
466
+ tile.coord)
467
+ self.db.commit()
468
+ if cursor.rowcount:
469
+ return True
470
+ return False
471
+
472
+ def remove_level_tiles_before(self, level, timestamp):
473
+ if timestamp == 0:
474
+ cursor = self.db.cursor()
475
+ cursor.execute(
476
+ "DELETE FROM [{0}] WHERE (zoom_level = ?)".format(self.table_name), (level,))
477
+ self.db.commit()
478
+ log.info("Cursor rowcount = {0}".format(cursor.rowcount))
479
+ if cursor.rowcount:
480
+ return True
481
+ return False
482
+
483
+ def load_tile_metadata(self, tile, dimensions=None):
484
+ if not self.supports_timestamp:
485
+ # GPKG specification does not include tile timestamps.
486
+ # This sets the timestamp of the tile to epoch (1970s)
487
+ tile.timestamp = -1
488
+ else:
489
+ self.load_tile(tile, dimensions=dimensions)
490
+
491
+
492
+ class GeopackageLevelCache(TileCacheBase):
493
+
494
+ def __init__(self, geopackage_dir, tile_grid, table_name, timeout=30, wal=False):
495
+ self.lock_cache_id = 'gpkg-' + hashlib.md5(geopackage_dir.encode('utf-8')).hexdigest()
496
+ self.cache_dir = geopackage_dir
497
+ self.tile_grid = tile_grid
498
+ self.table_name = table_name
499
+ self.timeout = timeout
500
+ self.wal = wal
501
+ self._geopackage = {}
502
+ self._geopackage_lock = threading.Lock()
503
+
504
+ def _get_level(self, level):
505
+ if level in self._geopackage:
506
+ return self._geopackage[level]
507
+
508
+ with self._geopackage_lock:
509
+ if level not in self._geopackage:
510
+ geopackage_filename = os.path.join(self.cache_dir, '%s.gpkg' % level)
511
+ self._geopackage[level] = GeopackageCache(
512
+ geopackage_filename,
513
+ self.tile_grid,
514
+ self.table_name,
515
+ with_timestamps=False,
516
+ timeout=self.timeout,
517
+ wal=self.wal,
518
+ )
519
+
520
+ return self._geopackage[level]
521
+
522
+ def cleanup(self):
523
+ """
524
+ Close all open connection and remove them from cache.
525
+ """
526
+ with self._geopackage_lock:
527
+ for gp in self._geopackage.values():
528
+ gp.cleanup()
529
+
530
+ def is_cached(self, tile, dimensions=None):
531
+ if tile.coord is None:
532
+ return True
533
+ if tile.source:
534
+ return True
535
+
536
+ return self._get_level(tile.coord[2]).is_cached(tile, dimensions=dimensions)
537
+
538
+ def store_tile(self, tile, dimensions=None):
539
+ if tile.stored:
540
+ return True
541
+
542
+ return self._get_level(tile.coord[2]).store_tile(tile, dimensions=dimensions)
543
+
544
+ def store_tiles(self, tiles, dimensions=None):
545
+ failed = False
546
+ for level, tiles in itertools.groupby(tiles, key=lambda t: t.coord[2]):
547
+ tiles = [t for t in tiles if not t.stored]
548
+ res = self._get_level(level).store_tiles(tiles, dimensions=dimensions)
549
+ if not res: failed = True
550
+ return failed
551
+
552
+ def load_tile(self, tile, with_metadata=False,dimensions=None):
553
+ if tile.source or tile.coord is None:
554
+ return True
555
+
556
+ return self._get_level(tile.coord[2]).load_tile(tile, with_metadata=with_metadata, dimensions=dimensions)
557
+
558
+ def load_tiles(self, tiles, with_metadata=False, dimensions=None):
559
+ level = None
560
+ for tile in tiles:
561
+ if tile.source or tile.coord is None:
562
+ continue
563
+ level = tile.coord[2]
564
+ break
565
+
566
+ if not level:
567
+ return True
568
+
569
+ return self._get_level(level).load_tiles(tiles, with_metadata=with_metadata, dimensions=dimensions)
570
+
571
+ def remove_tile(self, tile, dimensions=None):
572
+ if tile.coord is None:
573
+ return True
574
+
575
+ return self._get_level(tile.coord[2]).remove_tile(tile, dimensions=dimensions)
576
+
577
+ def remove_level_tiles_before(self, level, timestamp):
578
+ level_cache = self._get_level(level)
579
+ if timestamp == 0:
580
+ level_cache.cleanup()
581
+ os.unlink(level_cache.geopackage_file)
582
+ return True
583
+ else:
584
+ return level_cache.remove_level_tiles_before(level, timestamp)
585
+
586
+
587
+ def is_close(a, b, rel_tol=1e-09, abs_tol=0.0):
588
+ """
589
+ See PEP 485, added here for legacy versions.
590
+
591
+ >>> is_close(0.0, 0.0)
592
+ True
593
+ >>> is_close(1, 1.0)
594
+ True
595
+ >>> is_close(0.01, 0.001)
596
+ False
597
+ >>> is_close(0.0001001, 0.0001, rel_tol=1e-02)
598
+ True
599
+ >>> is_close(0.0001001, 0.0001)
600
+ False
601
+
602
+ @param a: An int or float.
603
+ @param b: An int or float.
604
+ @param rel_tol: Relative tolerance - maximumed allow difference between two numbers.
605
+ @param abs_tol: Absolute tolerance - minimum absolute tolerance.
606
+ @return: True if the values a and b are close.
607
+
608
+ """
609
+ return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)