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,143 @@
1
+ # -:- encoding: utf-8 -:-
2
+ # This file is part of the MapProxy project.
3
+ # Copyright (C) 2013 Omniscale <http://omniscale.de>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ from copy import copy
18
+ from mapproxy.compat import iteritems
19
+
20
+ __all__ = ['update_config', 'MapProxyYAMLDumper']
21
+
22
+ def update_config(conf, overwrites):
23
+ wildcard_keys = []
24
+ for k, v in iteritems(overwrites):
25
+ if k == '__all__':
26
+ continue
27
+ if k.startswith('___') or k.endswith('___'):
28
+ wildcard_keys.append(k)
29
+ continue
30
+
31
+ if k.endswith('__extend__'):
32
+ k = k[:-len('__extend__')]
33
+ if k not in conf:
34
+ conf[k] = v
35
+ elif isinstance(v, list):
36
+ conf[k].extend(v)
37
+ else:
38
+ raise ValueError('cannot extend non-list:', v)
39
+ elif k not in conf:
40
+ conf[k] = copy(v)
41
+ else:
42
+ if isinstance(conf[k], dict) and isinstance(v, dict):
43
+ conf[k] = update_config(conf[k], v)
44
+ else:
45
+ conf[k] = copy(v)
46
+
47
+ if '__all__' in overwrites:
48
+ v = overwrites['__all__']
49
+ for conf_k, conf_v in iteritems(conf):
50
+ if isinstance(conf_v, dict):
51
+ conf[conf_k] = update_config(conf_v, v)
52
+ else:
53
+ conf[conf_k] = v
54
+
55
+ if wildcard_keys:
56
+ for key in wildcard_keys:
57
+ v = overwrites[key]
58
+ if key.startswith('___'):
59
+ key = key[3:]
60
+ key_check = lambda x: x.endswith(key)
61
+ else:
62
+ key = key[:-3]
63
+ key_check = lambda x: x.startswith(key)
64
+ for conf_k, conf_v in iteritems(conf):
65
+ if not key_check(conf_k):
66
+ continue
67
+ if isinstance(conf_v, dict):
68
+ conf[conf_k] = update_config(conf_v, v)
69
+ else:
70
+ conf[conf_k] = v
71
+
72
+ return conf
73
+
74
+
75
+ from yaml.serializer import Serializer
76
+ from yaml.nodes import ScalarNode, SequenceNode, MappingNode
77
+ from yaml.emitter import Emitter
78
+ from yaml.representer import SafeRepresenter
79
+ from yaml.resolver import Resolver
80
+
81
+ class _MixedFlowSortedSerializer(Serializer):
82
+ def serialize_node(self, node, parent, index):
83
+ # reset any anchors
84
+ if parent is None:
85
+ for k in self.anchors:
86
+ self.anchors[k] = None
87
+ self.serialized_nodes = {}
88
+
89
+ if isinstance(node, SequenceNode) and all(isinstance(item, ScalarNode) for item in node.value):
90
+ node.flow_style = True
91
+ elif isinstance(node, MappingNode):
92
+ node.value.sort(key=lambda x: x[0].value)
93
+ return Serializer.serialize_node(self, node, parent, index)
94
+
95
+ class _EmptyNoneRepresenter(SafeRepresenter):
96
+ def represent_none(self, data):
97
+ return self.represent_scalar(u'tag:yaml.org,2002:null',
98
+ u'')
99
+ _EmptyNoneRepresenter.add_representer(type(None), _EmptyNoneRepresenter.represent_none)
100
+
101
+ class MapProxyYAMLDumper(Emitter, _MixedFlowSortedSerializer, _EmptyNoneRepresenter, Resolver):
102
+ """
103
+ YAML dumper that uses block style by default, except for
104
+ node-only sequences. Also sorts dicts by key, prevents `none`
105
+ for empty entries and prevents any anchors.
106
+ """
107
+ def __init__(self, stream,
108
+ default_style=None, default_flow_style=False,
109
+ canonical=None, indent=None, width=None,
110
+ allow_unicode=None, line_break=None,
111
+ encoding=None, explicit_start=None, explicit_end=None,
112
+ version=None, tags=None, sort_keys=None):
113
+ Emitter.__init__(self, stream, canonical=canonical,
114
+ indent=indent, width=width,
115
+ allow_unicode=allow_unicode, line_break=line_break)
116
+ Serializer.__init__(self, encoding=encoding,
117
+ explicit_start=explicit_start, explicit_end=explicit_end,
118
+ version=version, tags=tags)
119
+ _EmptyNoneRepresenter.__init__(self, default_style=default_style,
120
+ default_flow_style=default_flow_style)
121
+ Resolver.__init__(self)
122
+
123
+ from mapproxy.request.base import BaseRequest, url_decode
124
+ from mapproxy.client.http import open_url
125
+ from mapproxy.compat.modules import urlparse
126
+
127
+ def wms_capapilities_url(url):
128
+ parsed_url = urlparse.urlparse(url)
129
+ base_req = BaseRequest(
130
+ url=url.split('?', 1)[0],
131
+ param=url_decode(parsed_url.query),
132
+ )
133
+
134
+ base_req.params['service'] = 'WMS'
135
+ if not base_req.params['version']:
136
+ base_req.params['version'] = '1.1.1'
137
+ base_req.params['request'] = 'GetCapabilities'
138
+ return base_req.complete_url
139
+
140
+ def download_capabilities(url):
141
+ capabilities_url = wms_capapilities_url(url)
142
+ return open_url(capabilities_url)
143
+
@@ -0,0 +1,184 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2017 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from __future__ import print_function
17
+
18
+ import glob
19
+ import optparse
20
+ import os.path
21
+ import re
22
+ import sys
23
+ from collections import OrderedDict
24
+
25
+ from mapproxy.cache.compact import CompactCacheV1, CompactCacheV2
26
+ from mapproxy.cache.tile import Tile
27
+ from mapproxy.config import local_base_config
28
+ from mapproxy.config.loader import load_configuration, ConfigurationError
29
+
30
+ import logging
31
+ log = logging.getLogger('mapproxy.defrag')
32
+
33
+ def defrag_command(args=None):
34
+ parser = optparse.OptionParser("%prog defrag-compact [options] -f mapproxy_conf")
35
+ parser.add_option("-f", "--mapproxy-conf", dest="mapproxy_conf",
36
+ help="MapProxy configuration.")
37
+
38
+ parser.add_option("--min-percent", type=float, default=10.0,
39
+ help="Only defrag if fragmentation is larger (10 means at least 10% of the file does not have to be used)")
40
+
41
+ parser.add_option("--min-mb", type=float, default=1.0,
42
+ help="Only defrag if fragmentation is larger (2 means at least 2MB the file does not have to be used)")
43
+
44
+ parser.add_option("--dry-run", "-n", action="store_true",
45
+ help="Do not de-fragment, only print output")
46
+
47
+ parser.add_option("--caches", dest="cache_names", metavar='cache1,cache2,...',
48
+ help="only defragment the named caches")
49
+
50
+
51
+ from mapproxy.script.util import setup_logging
52
+ import logging
53
+ setup_logging(logging.INFO, format="[%(asctime)s] %(msg)s")
54
+
55
+ if args:
56
+ args = args[1:] # remove script name
57
+
58
+ (options, args) = parser.parse_args(args)
59
+ if not options.mapproxy_conf:
60
+ parser.print_help()
61
+ sys.exit(1)
62
+
63
+ try:
64
+ proxy_configuration = load_configuration(options.mapproxy_conf)
65
+ except IOError as e:
66
+ print('ERROR: ', "%s: '%s'" % (e.strerror, e.filename), file=sys.stderr)
67
+ sys.exit(2)
68
+ except ConfigurationError as e:
69
+ print(e, file=sys.stderr)
70
+ print('ERROR: invalid configuration (see above)', file=sys.stderr)
71
+ sys.exit(2)
72
+
73
+
74
+ with local_base_config(proxy_configuration.base_config):
75
+ available_caches = OrderedDict()
76
+ for name, cache_conf in proxy_configuration.caches.items():
77
+ for grid, extent, tile_mgr in cache_conf.caches():
78
+ if isinstance(tile_mgr.cache, (CompactCacheV1, CompactCacheV2)):
79
+ available_caches.setdefault(name, []).append(tile_mgr.cache)
80
+
81
+ if options.cache_names:
82
+ defrag_caches = options.cache_names.split(',')
83
+ missing = set(defrag_caches).difference(available_caches.keys())
84
+ if missing:
85
+ print('unknown caches: %s' % (', '.join(missing), ))
86
+ print('available compact caches: %s' %
87
+ (', '.join(available_caches.keys()), ))
88
+ sys.exit(1)
89
+ else:
90
+ defrag_caches = None
91
+
92
+ for name, caches in available_caches.items():
93
+ if defrag_caches and name not in defrag_caches:
94
+ continue
95
+ for cache in caches:
96
+ logger = DefragLog(name)
97
+ defrag_compact_cache(cache,
98
+ min_percent=options.min_percent/100,
99
+ min_bytes=options.min_mb*1024*1024,
100
+ dry_run=options.dry_run,
101
+ log_progress=logger,
102
+ )
103
+
104
+ def bundle_offset(fname):
105
+ """
106
+ >>> bundle_offset("path/to/R0000C0000.bundle")
107
+ (0, 0)
108
+ >>> bundle_offset("path/to/R0380C1380.bundle")
109
+ (4992, 896)
110
+ """
111
+ match = re.search(r'R([A-F0-9]{4,})C([A-F0-9]{4,}).bundle$', fname, re.IGNORECASE)
112
+ if match:
113
+ r = int(match.group(1), 16)
114
+ c = int(match.group(2), 16)
115
+ return c, r
116
+
117
+ class DefragLog(object):
118
+ def __init__(self, cache_name):
119
+ self.cache_name = cache_name
120
+ def log(self, fname, fragmentation, fragmentation_bytes, num, total, defrag):
121
+ msg = "%s: %3d/%d (%s) fragmentation is %.1f%% (%dkb)" % (
122
+ self.cache_name, num, total, fname, fragmentation, fragmentation_bytes/1024
123
+ )
124
+ if defrag:
125
+ msg += " - defragmenting"
126
+ else:
127
+ msg += " - skipping"
128
+ log.info(msg)
129
+
130
+ def defrag_compact_cache(cache, min_percent=0.1, min_bytes=1024*1024, log_progress=None, dry_run=False):
131
+ bundles = glob.glob(os.path.join(cache.cache_dir, 'L??', 'R????C????.bundle'))
132
+
133
+ for i, bundle_file in enumerate(bundles):
134
+ offset = bundle_offset(bundle_file)
135
+ b = cache.bundle_class(bundle_file.rstrip('.bundle'), offset)
136
+ size, file_size = b.size()
137
+
138
+ defrag = 1 - float(size) / file_size
139
+ defrag_bytes = file_size - size
140
+
141
+
142
+ skip = False
143
+ if defrag < min_percent or defrag_bytes < min_bytes:
144
+ skip = True
145
+
146
+ if log_progress:
147
+ log_progress.log(
148
+ fname=bundle_file,
149
+ fragmentation=defrag * 100,
150
+ fragmentation_bytes=defrag_bytes,
151
+ num=i+1, total=len(bundles),
152
+ defrag=not skip,
153
+ )
154
+
155
+ if skip or dry_run:
156
+ continue
157
+
158
+ tmp_bundle = os.path.join(cache.cache_dir, 'tmp_defrag')
159
+ defb = cache.bundle_class(tmp_bundle, offset)
160
+ stored_tiles = False
161
+
162
+ for y in range(128):
163
+ tiles = [Tile((x, y, 0)) for x in range(128)]
164
+ b.load_tiles(tiles)
165
+ tiles = [t for t in tiles if t.source]
166
+ if tiles:
167
+ stored_tiles = True
168
+ defb.store_tiles(tiles)
169
+
170
+ # remove first
171
+ # - in case bundle is empty
172
+ # - windows does not support rename to existing files
173
+ if os.path.exists(bundle_file):
174
+ os.remove(bundle_file)
175
+ if os.path.exists(bundle_file[:-1] + 'x'):
176
+ os.remove(bundle_file[:-1] + 'x')
177
+
178
+ if stored_tiles:
179
+ os.rename(tmp_bundle + '.bundle', bundle_file)
180
+ if os.path.exists(tmp_bundle + '.bundlx'):
181
+ os.rename(tmp_bundle + '.bundlx', bundle_file[:-1] + 'x')
182
+ if os.path.exists(tmp_bundle + '.lck'):
183
+ os.unlink(tmp_bundle + '.lck')
184
+
@@ -0,0 +1,333 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2012 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from __future__ import print_function, division
17
+
18
+ import os
19
+ import re
20
+ import shlex
21
+ import sys
22
+ import optparse
23
+
24
+ import yaml
25
+
26
+ from mapproxy.srs import SRS
27
+ from mapproxy.config.coverage import load_coverage
28
+ from mapproxy.config.loader import (
29
+ load_configuration, ConfigurationError,
30
+ CacheConfiguration, GridConfiguration,
31
+ ProxyConfiguration,
32
+ )
33
+ from mapproxy.util.coverage import BBOXCoverage
34
+ from mapproxy.seed.util import ProgressLog, format_bbox
35
+ from mapproxy.seed.seeder import SeedTask, seed_task
36
+ from mapproxy.config import spec as conf_spec
37
+ from mapproxy.util.ext.dictspec.validator import validate, ValidationError
38
+
39
+
40
+ def parse_levels(level_str):
41
+ """
42
+ >>> parse_levels('1,2,3,6')
43
+ [1, 2, 3, 6]
44
+ >>> parse_levels('1..6')
45
+ [1, 2, 3, 4, 5, 6]
46
+ >>> parse_levels('1..6, 8, 9, 13..14')
47
+ [1, 2, 3, 4, 5, 6, 8, 9, 13, 14]
48
+ """
49
+ levels = set()
50
+ for part in level_str.split(','):
51
+ part = part.strip()
52
+ if re.match(r'\d+..\d+', part):
53
+ from_level, to_level = part.split('..')
54
+ levels.update(list(range(int(from_level), int(to_level) + 1)))
55
+ else:
56
+ levels.add(int(part))
57
+
58
+ return sorted(levels)
59
+
60
+
61
+ def resolve_source(source_name, conf):
62
+ """
63
+ Resolves the source with the given name.
64
+
65
+ >>> config = ProxyConfiguration({'sources': {'mysource': {'type': 'wms'}}})
66
+ >>> resolve_source('mysource', config)
67
+ (<mapproxy.config.loader.WMSSourceConfiguration object at 0x...>, False)
68
+
69
+ >>> config = ProxyConfiguration({'caches': {'mysource': {}}})
70
+ >>> resolve_source('mysource', config)
71
+ (<mapproxy.config.loader.CacheConfiguration object at 0x...>, True)
72
+
73
+ >>> config = ProxyConfiguration({'caches': {'mysource': {'type': 'foo'}}})
74
+ >>> resolve_source('nonexistingsource', config)
75
+ (None, None)
76
+
77
+ :param source_name: The name of the source to resolve.
78
+ :param conf: The mapproxy config to resolve from.
79
+ :rtype: (dict, bool) A tuple containing the resolved source and a boolean
80
+ indicating if the resolved source is a cache (True), or a source (False).
81
+ """
82
+ resolved_source = conf.sources.get(source_name)
83
+ if resolved_source is not None:
84
+ return resolved_source, False
85
+ resolved_source = conf.caches.get(source_name)
86
+ if resolved_source is not None:
87
+ return resolved_source, True
88
+ return None, None
89
+
90
+
91
+ def parse_grid_definition(definition):
92
+ """
93
+ >>> sorted(parse_grid_definition("res=[10000,1000,100,10] srs=EPSG:4326 bbox=5,50,10,60").items())
94
+ [('bbox', '5,50,10,60'), ('res', [10000, 1000, 100, 10]), ('srs', 'EPSG:4326')]
95
+ """
96
+ args = shlex.split(definition)
97
+ grid_conf = {}
98
+ for arg in args:
99
+ key, value = arg.split('=')
100
+ value = yaml.safe_load(value)
101
+ grid_conf[key] = value
102
+
103
+ validate(conf_spec.grid_opts, grid_conf)
104
+ return grid_conf
105
+
106
+ def supports_tiled_access(mgr):
107
+ if len(mgr.sources) == 1 and getattr(mgr.sources[0], 'supports_meta_tiles') == False:
108
+ return True
109
+ return False
110
+
111
+
112
+ def format_export_task(task, custom_grid):
113
+ info = []
114
+ if custom_grid:
115
+ grid = "custom grid"
116
+ else:
117
+ grid = "grid '%s'" % task.md['grid_name']
118
+
119
+ info.append("Exporting cache '%s' to '%s' with %s in %s" % (
120
+ task.md['cache_name'], task.md['dest'], grid, task.grid.srs.srs_code))
121
+ if task.coverage:
122
+ info.append(' Limited to: %s (EPSG:4326)' % (format_bbox(task.coverage.extent.llbbox), ))
123
+ info.append(' Levels: %s' % (task.levels, ))
124
+
125
+ return '\n'.join(info)
126
+
127
+ def export_command(args=None):
128
+ parser = optparse.OptionParser("%prog export [options] mapproxy_conf")
129
+ parser.add_option("-f", "--mapproxy-conf", dest="mapproxy_conf",
130
+ help="MapProxy configuration")
131
+
132
+ parser.add_option("-q", "--quiet",
133
+ action="count", dest="quiet", default=0,
134
+ help="reduce number of messages to stdout, repeat to disable progress output")
135
+
136
+ parser.add_option("--source", dest="source",
137
+ help="source to export (source or cache)")
138
+
139
+ parser.add_option("--grid",
140
+ help="grid for export. either the name of an existing grid or "
141
+ "the grid definition as a string")
142
+
143
+ parser.add_option("--dest",
144
+ help="destination of the export (directory or filename)")
145
+
146
+ parser.add_option("--type",
147
+ help="type of the export format")
148
+
149
+ parser.add_option("--levels",
150
+ help="levels to export: e.g 1,2,3 or 1..10")
151
+
152
+ parser.add_option("--fetch-missing-tiles", dest="fetch_missing_tiles",
153
+ action='store_true', default=False,
154
+ help="if missing tiles should be fetched from the sources")
155
+
156
+ parser.add_option("--force",
157
+ action='store_true', default=False,
158
+ help="overwrite/append to existing --dest files/directories")
159
+
160
+ parser.add_option("-n", "--dry-run",
161
+ action="store_true", default=False,
162
+ help="do not export, just print output")
163
+
164
+ parser.add_option("-c", "--concurrency", type="int",
165
+ dest="concurrency", default=1,
166
+ help="number of parallel export processes")
167
+
168
+ parser.add_option("--coverage",
169
+ help="the coverage for the export as a BBOX string, WKT file "
170
+ "or OGR datasource")
171
+ parser.add_option("--srs",
172
+ help="the SRS of the coverage")
173
+ parser.add_option("--where",
174
+ help="filter for OGR coverages")
175
+
176
+ from mapproxy.script.util import setup_logging
177
+ import logging
178
+ setup_logging(logging.WARN)
179
+
180
+ if args:
181
+ args = args[1:] # remove script name
182
+
183
+ (options, args) = parser.parse_args(args)
184
+
185
+ if not options.mapproxy_conf:
186
+ if len(args) != 1:
187
+ parser.print_help()
188
+ sys.exit(1)
189
+ else:
190
+ options.mapproxy_conf = args[0]
191
+
192
+ required_options = ['mapproxy_conf', 'grid', 'source', 'dest', 'levels']
193
+ for required in required_options:
194
+ if not getattr(options, required):
195
+ print('ERROR: missing required option --%s' % required.replace('_', '-'), file=sys.stderr)
196
+ parser.print_help()
197
+ sys.exit(1)
198
+
199
+ try:
200
+ conf = load_configuration(options.mapproxy_conf)
201
+ except IOError as e:
202
+ print('ERROR: ', "%s: '%s'" % (e.strerror, e.filename), file=sys.stderr)
203
+ sys.exit(2)
204
+ except ConfigurationError as e:
205
+ print(e, file=sys.stderr)
206
+ print('ERROR: invalid configuration (see above)', file=sys.stderr)
207
+ sys.exit(2)
208
+
209
+
210
+ if '=' in options.grid:
211
+ try:
212
+ grid_conf = parse_grid_definition(options.grid)
213
+ except ValidationError as ex:
214
+ print('ERROR: invalid grid configuration', file=sys.stderr)
215
+ for error in ex.errors:
216
+ print(' ', error, file=sys.stderr)
217
+ sys.exit(2)
218
+ except ValueError:
219
+ print('ERROR: invalid grid configuration', file=sys.stderr)
220
+ sys.exit(2)
221
+ options.grid = 'tmp_mapproxy_export_grid'
222
+ grid_conf['name'] = options.grid
223
+ custom_grid = True
224
+ conf.grids[options.grid] = GridConfiguration(grid_conf, conf)
225
+ else:
226
+ custom_grid = False
227
+
228
+ if os.path.exists(options.dest) and not options.force:
229
+ print('ERROR: destination exists, remove first or use --force', file=sys.stderr)
230
+ sys.exit(2)
231
+
232
+ cache_conf = {
233
+ 'name': 'export',
234
+ 'grids': [options.grid],
235
+ 'sources': [options.source],
236
+ }
237
+
238
+ resolved_source, source_is_cache = resolve_source(options.source, conf)
239
+ if source_is_cache:
240
+ image_format = resolved_source.conf.get('format') or resolved_source.defaults.get('format')
241
+ if image_format is not None:
242
+ cache_conf['format'] = image_format
243
+ if image_format == 'mixed':
244
+ request_format = resolved_source.conf.get('request_format') or 'image/png'
245
+ cache_conf['request_format'] = request_format
246
+
247
+ if options.type == 'mbtile':
248
+ cache_conf['cache'] = {
249
+ 'type': 'mbtiles',
250
+ 'filename': options.dest,
251
+ }
252
+ elif options.type == 'sqlite':
253
+ cache_conf['cache'] = {
254
+ 'type': 'sqlite',
255
+ 'directory': options.dest,
256
+ }
257
+ elif options.type == 'geopackage':
258
+ cache_conf['cache'] = {
259
+ 'type': 'geopackage',
260
+ 'filename': options.dest,
261
+ }
262
+ elif options.type == 'compact-v1':
263
+ cache_conf['cache'] = {
264
+ 'type': 'compact',
265
+ 'version': 1,
266
+ 'directory': options.dest,
267
+ }
268
+ elif options.type == 'compact-v2':
269
+ cache_conf['cache'] = {
270
+ 'type': 'compact',
271
+ 'version': 2,
272
+ 'directory': options.dest,
273
+ }
274
+ elif options.type in ('tc', 'mapproxy'):
275
+ cache_conf['cache'] = {
276
+ 'type': 'file',
277
+ 'directory': options.dest,
278
+ }
279
+ elif options.type == 'arcgis':
280
+ cache_conf['cache'] = {
281
+ 'type': 'file',
282
+ 'directory_layout': 'arcgis',
283
+ 'directory': options.dest,
284
+ }
285
+ elif options.type in ('tms', None): # default
286
+ cache_conf['cache'] = {
287
+ 'type': 'file',
288
+ 'directory_layout': 'tms',
289
+ 'directory': options.dest,
290
+ }
291
+ else:
292
+ print('ERROR: unsupported --type %s' % (options.type, ), file=sys.stderr)
293
+ sys.exit(2)
294
+
295
+ if not options.fetch_missing_tiles:
296
+ for source in conf.sources.values():
297
+ source.conf['seed_only'] = True
298
+
299
+ tile_grid, extent, mgr = CacheConfiguration(cache_conf, conf).caches()[0]
300
+
301
+ levels = parse_levels(options.levels)
302
+ if levels[-1] >= tile_grid.levels:
303
+ print('ERROR: destination grid only has %d levels' % tile_grid.levels, file=sys.stderr)
304
+ sys.exit(2)
305
+
306
+ if options.srs:
307
+ srs = SRS(options.srs)
308
+ else:
309
+ srs = tile_grid.srs
310
+
311
+ if options.coverage:
312
+ seed_coverage = load_coverage(
313
+ {'datasource': options.coverage, 'srs': srs, 'where': options.where},
314
+ base_path=os.getcwd())
315
+ else:
316
+ seed_coverage = BBOXCoverage(tile_grid.bbox, tile_grid.srs)
317
+
318
+ if not supports_tiled_access(mgr):
319
+ print('WARN: grids are incompatible. needs to scale/reproject tiles for export.', file=sys.stderr)
320
+
321
+ md = dict(name='export', cache_name='cache', grid_name=options.grid, dest=options.dest)
322
+ task = SeedTask(md, mgr, levels, 1, seed_coverage)
323
+
324
+ print(format_export_task(task, custom_grid=custom_grid))
325
+
326
+ logger = ProgressLog(verbose=options.quiet==0, silent=options.quiet>=2)
327
+ try:
328
+ seed_task(task, progress_logger=logger, dry_run=options.dry_run,
329
+ concurrency=options.concurrency)
330
+ except KeyboardInterrupt:
331
+ print('stopping...', file=sys.stderr)
332
+ sys.exit(2)
333
+