MapProxy 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. MapProxy-2.1.0.dist-info/AUTHORS.txt +33 -0
  2. MapProxy-2.1.0.dist-info/COPYING.txt +60 -0
  3. MapProxy-2.1.0.dist-info/LICENSE.txt +202 -0
  4. MapProxy-2.1.0.dist-info/METADATA +165 -0
  5. MapProxy-2.1.0.dist-info/RECORD +459 -0
  6. MapProxy-2.1.0.dist-info/WHEEL +5 -0
  7. MapProxy-2.1.0.dist-info/entry_points.txt +4 -0
  8. MapProxy-2.1.0.dist-info/top_level.txt +1 -0
  9. mapproxy/__init__.py +0 -0
  10. mapproxy/cache/__init__.py +36 -0
  11. mapproxy/cache/azureblob.py +145 -0
  12. mapproxy/cache/base.py +120 -0
  13. mapproxy/cache/compact.py +665 -0
  14. mapproxy/cache/couchdb.py +301 -0
  15. mapproxy/cache/dummy.py +36 -0
  16. mapproxy/cache/file.py +200 -0
  17. mapproxy/cache/geopackage.py +647 -0
  18. mapproxy/cache/legend.py +87 -0
  19. mapproxy/cache/mbtiles.py +411 -0
  20. mapproxy/cache/meta.py +80 -0
  21. mapproxy/cache/path.py +261 -0
  22. mapproxy/cache/redis.py +152 -0
  23. mapproxy/cache/renderd.py +100 -0
  24. mapproxy/cache/riak.py +206 -0
  25. mapproxy/cache/s3.py +209 -0
  26. mapproxy/cache/tile.py +736 -0
  27. mapproxy/client/__init__.py +0 -0
  28. mapproxy/client/arcgis.py +82 -0
  29. mapproxy/client/cgi.py +141 -0
  30. mapproxy/client/http.py +295 -0
  31. mapproxy/client/log.py +33 -0
  32. mapproxy/client/tile.py +158 -0
  33. mapproxy/client/wms.py +255 -0
  34. mapproxy/compat/__init__.py +0 -0
  35. mapproxy/compat/image.py +86 -0
  36. mapproxy/config/__init__.py +22 -0
  37. mapproxy/config/config-schema.json +813 -0
  38. mapproxy/config/config.py +213 -0
  39. mapproxy/config/coverage.py +108 -0
  40. mapproxy/config/defaults.py +102 -0
  41. mapproxy/config/loader.py +2399 -0
  42. mapproxy/config/spec.py +657 -0
  43. mapproxy/config/validator.py +242 -0
  44. mapproxy/config_template/__init__.py +0 -0
  45. mapproxy/config_template/base_config/config.wsgi +10 -0
  46. mapproxy/config_template/base_config/full_example.yaml +598 -0
  47. mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
  48. mapproxy/config_template/base_config/log.ini +35 -0
  49. mapproxy/config_template/base_config/mapproxy.yaml +60 -0
  50. mapproxy/config_template/base_config/seed.yaml +27 -0
  51. mapproxy/exception.py +149 -0
  52. mapproxy/featureinfo.py +251 -0
  53. mapproxy/grid.py +1199 -0
  54. mapproxy/image/__init__.py +549 -0
  55. mapproxy/image/fonts/DejaVuSans.ttf +0 -0
  56. mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
  57. mapproxy/image/fonts/LICENSE +99 -0
  58. mapproxy/image/fonts/__init__.py +0 -0
  59. mapproxy/image/mask.py +79 -0
  60. mapproxy/image/merge.py +323 -0
  61. mapproxy/image/message.py +357 -0
  62. mapproxy/image/opts.py +185 -0
  63. mapproxy/image/tile.py +171 -0
  64. mapproxy/image/transform.py +350 -0
  65. mapproxy/layer.py +489 -0
  66. mapproxy/multiapp.py +230 -0
  67. mapproxy/proj.py +309 -0
  68. mapproxy/request/__init__.py +18 -0
  69. mapproxy/request/arcgis.py +268 -0
  70. mapproxy/request/base.py +466 -0
  71. mapproxy/request/tile.py +131 -0
  72. mapproxy/request/wms/__init__.py +829 -0
  73. mapproxy/request/wms/exception.py +107 -0
  74. mapproxy/request/wmts.py +442 -0
  75. mapproxy/response.py +237 -0
  76. mapproxy/script/__init__.py +0 -0
  77. mapproxy/script/conf/__init__.py +0 -0
  78. mapproxy/script/conf/app.py +222 -0
  79. mapproxy/script/conf/caches.py +44 -0
  80. mapproxy/script/conf/geopackage.py +136 -0
  81. mapproxy/script/conf/layers.py +54 -0
  82. mapproxy/script/conf/seeds.py +36 -0
  83. mapproxy/script/conf/sources.py +88 -0
  84. mapproxy/script/conf/utils.py +148 -0
  85. mapproxy/script/defrag.py +187 -0
  86. mapproxy/script/export.py +337 -0
  87. mapproxy/script/grids.py +198 -0
  88. mapproxy/script/scales.py +134 -0
  89. mapproxy/script/util.py +410 -0
  90. mapproxy/script/wms_capabilities.py +160 -0
  91. mapproxy/seed/__init__.py +0 -0
  92. mapproxy/seed/cachelock.py +127 -0
  93. mapproxy/seed/cleanup.py +191 -0
  94. mapproxy/seed/config.py +481 -0
  95. mapproxy/seed/script.py +391 -0
  96. mapproxy/seed/seeder.py +551 -0
  97. mapproxy/seed/spec.py +66 -0
  98. mapproxy/seed/util.py +266 -0
  99. mapproxy/service/__init__.py +14 -0
  100. mapproxy/service/base.py +45 -0
  101. mapproxy/service/demo.py +364 -0
  102. mapproxy/service/kml.py +333 -0
  103. mapproxy/service/ows.py +39 -0
  104. mapproxy/service/template_helper.py +55 -0
  105. mapproxy/service/templates/demo/capabilities_demo.html +18 -0
  106. mapproxy/service/templates/demo/demo.html +181 -0
  107. mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
  108. mapproxy/service/templates/demo/static/img/blank.gif +0 -0
  109. mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
  110. mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
  111. mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
  112. mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
  113. mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
  114. mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
  115. mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
  116. mapproxy/service/templates/demo/static/logo.png +0 -0
  117. mapproxy/service/templates/demo/static/ol.css +345 -0
  118. mapproxy/service/templates/demo/static/ol.js +4 -0
  119. mapproxy/service/templates/demo/static/proj4.min.js +1 -0
  120. mapproxy/service/templates/demo/static/proj4defs.js +1 -0
  121. mapproxy/service/templates/demo/static/site.css +137 -0
  122. mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
  123. mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
  124. mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
  125. mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
  126. mapproxy/service/templates/demo/static.html +34 -0
  127. mapproxy/service/templates/demo/tms_demo.html +117 -0
  128. mapproxy/service/templates/demo/wms_demo.html +144 -0
  129. mapproxy/service/templates/demo/wmts_demo.html +118 -0
  130. mapproxy/service/templates/tms_capabilities.xml +13 -0
  131. mapproxy/service/templates/tms_exception.xml +4 -0
  132. mapproxy/service/templates/tms_root_resource.xml +7 -0
  133. mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
  134. mapproxy/service/templates/wms100capabilities.xml +112 -0
  135. mapproxy/service/templates/wms100exception.xml +4 -0
  136. mapproxy/service/templates/wms110capabilities.xml +152 -0
  137. mapproxy/service/templates/wms110exception.xml +5 -0
  138. mapproxy/service/templates/wms111capabilities.xml +183 -0
  139. mapproxy/service/templates/wms111exception.xml +5 -0
  140. mapproxy/service/templates/wms130capabilities.xml +326 -0
  141. mapproxy/service/templates/wms130exception.xml +8 -0
  142. mapproxy/service/templates/wmts100capabilities.xml +155 -0
  143. mapproxy/service/templates/wmts100exception.xml +9 -0
  144. mapproxy/service/tile.py +540 -0
  145. mapproxy/service/wms.py +868 -0
  146. mapproxy/service/wmts.py +387 -0
  147. mapproxy/source/__init__.py +83 -0
  148. mapproxy/source/arcgis.py +39 -0
  149. mapproxy/source/error.py +40 -0
  150. mapproxy/source/mapnik.py +262 -0
  151. mapproxy/source/tile.py +97 -0
  152. mapproxy/source/wms.py +273 -0
  153. mapproxy/srs.py +734 -0
  154. mapproxy/template.py +54 -0
  155. mapproxy/test/__init__.py +0 -0
  156. mapproxy/test/conftest.py +8 -0
  157. mapproxy/test/helper.py +255 -0
  158. mapproxy/test/http.py +511 -0
  159. mapproxy/test/image.py +219 -0
  160. mapproxy/test/mocker.py +2291 -0
  161. mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
  162. mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
  163. mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
  164. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
  165. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
  166. mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
  167. mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
  168. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
  169. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
  170. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
  171. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
  172. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
  173. mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
  174. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
  175. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
  176. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
  177. mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
  178. mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
  179. mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
  180. mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
  181. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
  182. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
  183. mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
  184. mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
  185. mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
  186. mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
  187. mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
  188. mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
  189. mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
  190. mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
  191. mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
  192. mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
  193. mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
  194. mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
  195. mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
  196. mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
  197. mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
  198. mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
  199. mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
  200. mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
  201. mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
  202. mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
  203. mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
  204. mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
  205. mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
  206. mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
  207. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
  208. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
  209. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
  210. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
  211. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
  212. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
  213. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
  214. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
  215. mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
  216. mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  217. mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
  218. mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  219. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
  220. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
  221. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
  222. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
  223. mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
  224. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
  225. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
  226. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
  227. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
  228. mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
  229. mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  230. mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
  231. mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  232. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
  233. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
  234. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
  235. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
  236. mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
  237. mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
  238. mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
  239. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
  240. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
  241. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
  242. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
  243. mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
  244. mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
  245. mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
  246. mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
  247. mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
  248. mapproxy/test/schemas/xml.xsd +287 -0
  249. mapproxy/test/system/__init__.py +98 -0
  250. mapproxy/test/system/fixture/arcgis.yaml +57 -0
  251. mapproxy/test/system/fixture/auth.yaml +70 -0
  252. mapproxy/test/system/fixture/cache.mbtiles +0 -0
  253. mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
  254. mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
  255. mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
  256. mapproxy/test/system/fixture/cache_coverage.yaml +84 -0
  257. mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
  258. mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
  259. mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
  260. mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
  261. mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
  262. mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
  263. mapproxy/test/system/fixture/cache_s3.yaml +58 -0
  264. mapproxy/test/system/fixture/cache_source.yaml +81 -0
  265. mapproxy/test/system/fixture/combined_sources.yaml +130 -0
  266. mapproxy/test/system/fixture/coverage.yaml +77 -0
  267. mapproxy/test/system/fixture/demo.yaml +135 -0
  268. mapproxy/test/system/fixture/dimension.yaml +59 -0
  269. mapproxy/test/system/fixture/disable_storage.yaml +25 -0
  270. mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
  271. mapproxy/test/system/fixture/formats.yaml +72 -0
  272. mapproxy/test/system/fixture/inspire.yaml +101 -0
  273. mapproxy/test/system/fixture/inspire_full.yaml +124 -0
  274. mapproxy/test/system/fixture/kml_layer.yaml +66 -0
  275. mapproxy/test/system/fixture/layer.yaml +260 -0
  276. mapproxy/test/system/fixture/layergroups.yaml +57 -0
  277. mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
  278. mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
  279. mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
  280. mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
  281. mapproxy/test/system/fixture/mapserver.yaml +23 -0
  282. mapproxy/test/system/fixture/minimal_cgi.py +16 -0
  283. mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
  284. mapproxy/test/system/fixture/multi_cache_layers.yaml +111 -0
  285. mapproxy/test/system/fixture/multiapp1.yaml +20 -0
  286. mapproxy/test/system/fixture/multiapp2.yaml +19 -0
  287. mapproxy/test/system/fixture/renderd_client.yaml +55 -0
  288. mapproxy/test/system/fixture/scalehints.yaml +70 -0
  289. mapproxy/test/system/fixture/seed.yaml +94 -0
  290. mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
  291. mapproxy/test/system/fixture/seed_old.yaml +12 -0
  292. mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
  293. mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
  294. mapproxy/test/system/fixture/seedonly.yaml +51 -0
  295. mapproxy/test/system/fixture/sld.yaml +35 -0
  296. mapproxy/test/system/fixture/source_errors.yaml +84 -0
  297. mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
  298. mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
  299. mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
  300. mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
  301. mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
  302. mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
  303. mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
  304. mapproxy/test/system/fixture/util_grids.yaml +29 -0
  305. mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
  306. mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
  307. mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
  308. mapproxy/test/system/fixture/watermark.yaml +50 -0
  309. mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
  310. mapproxy/test/system/fixture/wms_versions.yaml +38 -0
  311. mapproxy/test/system/fixture/wmts.yaml +134 -0
  312. mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
  313. mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
  314. mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
  315. mapproxy/test/system/test_arcgis.py +156 -0
  316. mapproxy/test/system/test_auth.py +1133 -0
  317. mapproxy/test/system/test_behind_proxy.py +75 -0
  318. mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
  319. mapproxy/test/system/test_cache_azureblob.py +127 -0
  320. mapproxy/test/system/test_cache_band_merge.py +103 -0
  321. mapproxy/test/system/test_cache_coverage.py +168 -0
  322. mapproxy/test/system/test_cache_geopackage.py +144 -0
  323. mapproxy/test/system/test_cache_grid_names.py +89 -0
  324. mapproxy/test/system/test_cache_mbtiles.py +85 -0
  325. mapproxy/test/system/test_cache_s3.py +115 -0
  326. mapproxy/test/system/test_cache_source.py +146 -0
  327. mapproxy/test/system/test_combined_sources.py +335 -0
  328. mapproxy/test/system/test_coverage.py +140 -0
  329. mapproxy/test/system/test_decorate_img.py +214 -0
  330. mapproxy/test/system/test_demo.py +56 -0
  331. mapproxy/test/system/test_demo_with_extra_service.py +57 -0
  332. mapproxy/test/system/test_dimensions.py +279 -0
  333. mapproxy/test/system/test_disable_storage.py +42 -0
  334. mapproxy/test/system/test_formats.py +219 -0
  335. mapproxy/test/system/test_inspire_vs.py +173 -0
  336. mapproxy/test/system/test_kml.py +264 -0
  337. mapproxy/test/system/test_layergroups.py +160 -0
  338. mapproxy/test/system/test_legendgraphic.py +308 -0
  339. mapproxy/test/system/test_mapnik.py +162 -0
  340. mapproxy/test/system/test_mapserver.py +83 -0
  341. mapproxy/test/system/test_mixed_mode_format.py +201 -0
  342. mapproxy/test/system/test_multi_cache_layers.py +169 -0
  343. mapproxy/test/system/test_multiapp.py +92 -0
  344. mapproxy/test/system/test_refresh.py +206 -0
  345. mapproxy/test/system/test_renderd_client.py +304 -0
  346. mapproxy/test/system/test_response_headers.py +54 -0
  347. mapproxy/test/system/test_scalehints.py +140 -0
  348. mapproxy/test/system/test_seed.py +425 -0
  349. mapproxy/test/system/test_seed_only.py +93 -0
  350. mapproxy/test/system/test_sld.py +120 -0
  351. mapproxy/test/system/test_source_errors.py +377 -0
  352. mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
  353. mapproxy/test/system/test_tms.py +277 -0
  354. mapproxy/test/system/test_tms_origin.py +46 -0
  355. mapproxy/test/system/test_util_conf.py +434 -0
  356. mapproxy/test/system/test_util_export.py +210 -0
  357. mapproxy/test/system/test_util_grids.py +88 -0
  358. mapproxy/test/system/test_util_wms_capabilities.py +182 -0
  359. mapproxy/test/system/test_watermark.py +91 -0
  360. mapproxy/test/system/test_wms.py +1616 -0
  361. mapproxy/test/system/test_wms_srs_extent.py +165 -0
  362. mapproxy/test/system/test_wms_version.py +85 -0
  363. mapproxy/test/system/test_wmsc.py +116 -0
  364. mapproxy/test/system/test_wmts.py +334 -0
  365. mapproxy/test/system/test_wmts_dimensions.py +206 -0
  366. mapproxy/test/system/test_wmts_restful.py +198 -0
  367. mapproxy/test/system/test_xslt_featureinfo.py +423 -0
  368. mapproxy/test/test_http_helper.py +217 -0
  369. mapproxy/test/unit/__init__.py +0 -0
  370. mapproxy/test/unit/epsg +2 -0
  371. mapproxy/test/unit/polygons/polygons.dbf +0 -0
  372. mapproxy/test/unit/polygons/polygons.shp +0 -0
  373. mapproxy/test/unit/polygons/polygons.shx +0 -0
  374. mapproxy/test/unit/test_async.py +242 -0
  375. mapproxy/test/unit/test_auth.py +430 -0
  376. mapproxy/test/unit/test_cache.py +1356 -0
  377. mapproxy/test/unit/test_cache_azureblob.py +97 -0
  378. mapproxy/test/unit/test_cache_compact.py +324 -0
  379. mapproxy/test/unit/test_cache_couchdb.py +118 -0
  380. mapproxy/test/unit/test_cache_geopackage.py +256 -0
  381. mapproxy/test/unit/test_cache_redis.py +123 -0
  382. mapproxy/test/unit/test_cache_riak.py +80 -0
  383. mapproxy/test/unit/test_cache_s3.py +93 -0
  384. mapproxy/test/unit/test_cache_tile.py +477 -0
  385. mapproxy/test/unit/test_client.py +488 -0
  386. mapproxy/test/unit/test_client_arcgis.py +74 -0
  387. mapproxy/test/unit/test_client_cgi.py +140 -0
  388. mapproxy/test/unit/test_collections.py +116 -0
  389. mapproxy/test/unit/test_concat_legends.py +37 -0
  390. mapproxy/test/unit/test_conf_loader.py +1267 -0
  391. mapproxy/test/unit/test_conf_validator.py +427 -0
  392. mapproxy/test/unit/test_config.py +118 -0
  393. mapproxy/test/unit/test_decorate_img.py +185 -0
  394. mapproxy/test/unit/test_exceptions.py +270 -0
  395. mapproxy/test/unit/test_featureinfo.py +313 -0
  396. mapproxy/test/unit/test_file_lock_load.py +49 -0
  397. mapproxy/test/unit/test_geom.py +512 -0
  398. mapproxy/test/unit/test_grid.py +1279 -0
  399. mapproxy/test/unit/test_image.py +1051 -0
  400. mapproxy/test/unit/test_image_mask.py +181 -0
  401. mapproxy/test/unit/test_image_messages.py +209 -0
  402. mapproxy/test/unit/test_image_options.py +160 -0
  403. mapproxy/test/unit/test_isodate.py +118 -0
  404. mapproxy/test/unit/test_multiapp.py +163 -0
  405. mapproxy/test/unit/test_ogr_reader.py +51 -0
  406. mapproxy/test/unit/test_request.py +745 -0
  407. mapproxy/test/unit/test_request_wmts.py +178 -0
  408. mapproxy/test/unit/test_response.py +78 -0
  409. mapproxy/test/unit/test_seed.py +365 -0
  410. mapproxy/test/unit/test_seed_cachelock.py +91 -0
  411. mapproxy/test/unit/test_srs.py +215 -0
  412. mapproxy/test/unit/test_tiled_source.py +122 -0
  413. mapproxy/test/unit/test_tilefilter.py +31 -0
  414. mapproxy/test/unit/test_times.py +25 -0
  415. mapproxy/test/unit/test_timeutils.py +50 -0
  416. mapproxy/test/unit/test_util_conf_utils.py +75 -0
  417. mapproxy/test/unit/test_utils.py +476 -0
  418. mapproxy/test/unit/test_wms_capabilities.py +44 -0
  419. mapproxy/test/unit/test_wms_layer.py +113 -0
  420. mapproxy/test/unit/test_yaml.py +68 -0
  421. mapproxy/tilefilter.py +61 -0
  422. mapproxy/util/__init__.py +0 -0
  423. mapproxy/util/async_.py +229 -0
  424. mapproxy/util/collections.py +134 -0
  425. mapproxy/util/coverage.py +337 -0
  426. mapproxy/util/ext/__init__.py +14 -0
  427. mapproxy/util/ext/dictspec/__init__.py +1 -0
  428. mapproxy/util/ext/dictspec/spec.py +131 -0
  429. mapproxy/util/ext/dictspec/test/__init__.py +0 -0
  430. mapproxy/util/ext/dictspec/test/test_validator.py +278 -0
  431. mapproxy/util/ext/dictspec/validator.py +194 -0
  432. mapproxy/util/ext/local.py +198 -0
  433. mapproxy/util/ext/lockfile.py +140 -0
  434. mapproxy/util/ext/odict.py +321 -0
  435. mapproxy/util/ext/serving.py +491 -0
  436. mapproxy/util/ext/tempita/__init__.py +1093 -0
  437. mapproxy/util/ext/tempita/_looper.py +163 -0
  438. mapproxy/util/ext/tempita/string_utils.py +24 -0
  439. mapproxy/util/ext/wmsparse/__init__.py +3 -0
  440. mapproxy/util/ext/wmsparse/duration.py +600 -0
  441. mapproxy/util/ext/wmsparse/parse.py +307 -0
  442. mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
  443. mapproxy/util/ext/wmsparse/test/test_parse.py +111 -0
  444. mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
  445. mapproxy/util/ext/wmsparse/test/wms-example-111.xml +90 -0
  446. mapproxy/util/ext/wmsparse/test/wms-example-130.xml +120 -0
  447. mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
  448. mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
  449. mapproxy/util/ext/wmsparse/util.py +189 -0
  450. mapproxy/util/fs.py +164 -0
  451. mapproxy/util/geom.py +307 -0
  452. mapproxy/util/lib.py +117 -0
  453. mapproxy/util/lock.py +171 -0
  454. mapproxy/util/ogr.py +247 -0
  455. mapproxy/util/py.py +75 -0
  456. mapproxy/util/times.py +78 -0
  457. mapproxy/util/yaml.py +58 -0
  458. mapproxy/version.py +33 -0
  459. mapproxy/wsgiapp.py +167 -0
@@ -0,0 +1,410 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2011 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from __future__ import print_function
17
+
18
+ import io
19
+ import os
20
+ import optparse
21
+ import re
22
+ import shutil
23
+ import sys
24
+ import textwrap
25
+ import logging
26
+
27
+ from mapproxy.config.loader import load_plugins
28
+ from mapproxy.script.conf.app import config_command
29
+ from mapproxy.script.defrag import defrag_command
30
+ from mapproxy.script.export import export_command
31
+ from mapproxy.script.grids import grids_command
32
+ from mapproxy.script.scales import scales_command
33
+ from mapproxy.script.wms_capabilities import wms_capabilities_command
34
+ from mapproxy.version import version
35
+
36
+
37
+ def setup_logging(level=logging.INFO, format=None):
38
+ mapproxy_log = logging.getLogger('mapproxy')
39
+ mapproxy_log.setLevel(level)
40
+
41
+ ch = logging.StreamHandler(sys.stdout)
42
+ ch.setLevel(level)
43
+ if not format:
44
+ format = "[%(asctime)s] %(name)s - %(levelname)s - %(message)s"
45
+ formatter = logging.Formatter(format)
46
+ ch.setFormatter(formatter)
47
+ mapproxy_log.addHandler(ch)
48
+
49
+
50
+ def serve_develop_command(args):
51
+ parser = optparse.OptionParser("usage: %prog serve-develop [options] mapproxy.yaml")
52
+ parser.add_option("-b", "--bind",
53
+ dest="address", default='127.0.0.1:8080',
54
+ help="Server socket [127.0.0.1:8080]. Use 0.0.0.0 for external access. :1234 to change port.")
55
+ parser.add_option("--debug", default=False, action='store_true',
56
+ dest="debug",
57
+ help="Enable debug mode")
58
+ options, args = parser.parse_args(args)
59
+
60
+ if len(args) != 2:
61
+ parser.print_help()
62
+ print("\nERROR: MapProxy configuration required.")
63
+ sys.exit(1)
64
+
65
+ mapproxy_conf = args[1]
66
+
67
+ host, port = parse_bind_address(options.address)
68
+
69
+ if options.debug and host not in ('localhost', '127.0.0.1'):
70
+ print(textwrap.dedent("""\
71
+ ################# WARNING! ##################
72
+ Running debug mode with non-localhost address
73
+ is a serious security vulnerability.
74
+ #############################################\
75
+ """))
76
+
77
+ if options.debug:
78
+ setup_logging(level=logging.DEBUG)
79
+ else:
80
+ setup_logging()
81
+ from mapproxy.wsgiapp import make_wsgi_app
82
+ from mapproxy.config.loader import ConfigurationError
83
+ from mapproxy.util.ext.serving import run_simple
84
+ try:
85
+ app = make_wsgi_app(mapproxy_conf, debug=options.debug)
86
+ except ConfigurationError:
87
+ sys.exit(2)
88
+
89
+ extra_files = app.config_files.keys()
90
+
91
+ if options.debug:
92
+ try:
93
+ from repoze.profile import ProfileMiddleware
94
+ app = ProfileMiddleware(
95
+ app,
96
+ log_filename='/tmp/mapproxy_profile.log',
97
+ discard_first_request=True,
98
+ flush_at_shutdown=True,
99
+ path='/__profile__',
100
+ unwind=False,
101
+ )
102
+ print('Installed profiler at /__profile__')
103
+ except ImportError:
104
+ pass
105
+
106
+ run_simple(host, port, app, use_reloader=True, processes=1,
107
+ threaded=True, passthrough_errors=True,
108
+ extra_files=extra_files)
109
+
110
+
111
+ def serve_multiapp_develop_command(args):
112
+ parser = optparse.OptionParser("usage: %prog serve-multiapp-develop [options] projects/")
113
+ parser.add_option("-b", "--bind",
114
+ dest="address", default='127.0.0.1:8080',
115
+ help="Server socket [127.0.0.1:8080]")
116
+ parser.add_option("--debug", default=False, action='store_true',
117
+ dest="debug",
118
+ help="Enable debug mode")
119
+ options, args = parser.parse_args(args)
120
+
121
+ if len(args) != 2:
122
+ parser.print_help()
123
+ print("\nERROR: MapProxy projects directory required.")
124
+ sys.exit(1)
125
+
126
+ mapproxy_conf_dir = args[1]
127
+
128
+ host, port = parse_bind_address(options.address)
129
+
130
+ if options.debug and host not in ('localhost', '127.0.0.1'):
131
+ print(textwrap.dedent("""\
132
+ ################# WARNING! ##################
133
+ Running debug mode with non-localhost address
134
+ is a serious security vulnerability.
135
+ #############################################\
136
+ """))
137
+
138
+ setup_logging()
139
+ from mapproxy.multiapp import make_wsgi_app
140
+ from mapproxy.util.ext.serving import run_simple
141
+ app = make_wsgi_app(mapproxy_conf_dir, debug=options.debug)
142
+
143
+ run_simple(host, port, app, use_reloader=True, processes=1,
144
+ threaded=True, passthrough_errors=True)
145
+
146
+
147
+ def parse_bind_address(address, default=('localhost', 8080)):
148
+ """
149
+ >>> parse_bind_address('80')
150
+ ('localhost', 80)
151
+ >>> parse_bind_address('0.0.0.0')
152
+ ('0.0.0.0', 8080)
153
+ >>> parse_bind_address('0.0.0.0:8081')
154
+ ('0.0.0.0', 8081)
155
+ """
156
+ if ':' in address:
157
+ host, port = address.split(':', 1)
158
+ port = int(port)
159
+ elif re.match(r'^\d+$', address):
160
+ host = default[0]
161
+ port = int(address)
162
+ else:
163
+ host = address
164
+ port = default[1]
165
+ return host, port
166
+
167
+
168
+ def create_command(args):
169
+ cmd = CreateCommand(args)
170
+ cmd.run()
171
+
172
+
173
+ class CreateCommand(object):
174
+ templates = {
175
+ 'base-config': {},
176
+ 'wsgi-app': {},
177
+ 'log-ini': {},
178
+ }
179
+
180
+ def __init__(self, args):
181
+ parser = optparse.OptionParser("usage: %prog create [options] [destination]")
182
+ parser.add_option("-t", "--template", dest="template",
183
+ help="Create a configuration from this template.")
184
+ parser.add_option("-l", "--list-templates", dest="list_templates",
185
+ action="store_true", default=False,
186
+ help="List all available configuration templates.")
187
+ parser.add_option("-f", "--mapproxy-conf", dest="mapproxy_conf",
188
+ help="Existing MapProxy configuration (required for some templates).")
189
+ parser.add_option("--force", dest="force", action="store_true",
190
+ default=False, help="Force operation (e.g. overwrite existing files).")
191
+
192
+ self.options, self.args = parser.parse_args(args)
193
+ self.parser = parser
194
+
195
+ def log_error(self, msg, *args):
196
+ print('ERROR:', msg % args, file=sys.stderr)
197
+
198
+ def run(self):
199
+
200
+ if self.options.list_templates:
201
+ print_items(self.templates, title="Available templates")
202
+ sys.exit(1)
203
+ elif self.options.template:
204
+ if self.options.template not in self.templates:
205
+ self.log_error("unknown template " + self.options.template)
206
+ sys.exit(1)
207
+
208
+ if len(self.args) != 2:
209
+ self.log_error("template requires destination argument")
210
+ sys.exit(1)
211
+
212
+ sys.exit(
213
+ getattr(self, 'template_' + self.options.template.replace('-', '_'))()
214
+ )
215
+ else:
216
+ self.parser.print_help()
217
+ sys.exit(1)
218
+
219
+ @property
220
+ def mapproxy_conf(self):
221
+ if not self.options.mapproxy_conf:
222
+ self.parser.print_help()
223
+ self.log_error("template requires --mapproxy-conf option")
224
+ sys.exit(1)
225
+ return os.path.abspath(self.options.mapproxy_conf)
226
+
227
+ def template_dir(self):
228
+ import mapproxy.config_template
229
+ template_dir = os.path.join(
230
+ os.path.dirname(mapproxy.config_template.__file__),
231
+ 'base_config')
232
+ return template_dir
233
+
234
+ def template_wsgi_app(self):
235
+ app_filename = self.args[1]
236
+ if '.' not in os.path.basename(app_filename):
237
+ app_filename += '.py'
238
+ mapproxy_conf = self.mapproxy_conf
239
+ if os.path.exists(app_filename) and not self.options.force:
240
+ self.log_error("%s already exists, use --force", app_filename)
241
+ return 1
242
+
243
+ print("writing MapProxy app to %s" % (app_filename, ))
244
+
245
+ template_dir = self.template_dir()
246
+ app_template = io.open(os.path.join(template_dir, 'config.wsgi'), encoding='utf-8').read()
247
+ with io.open(app_filename, 'w', encoding='utf-8') as f:
248
+ f.write(app_template % {'mapproxy_conf': mapproxy_conf,
249
+ 'here': os.path.dirname(mapproxy_conf)})
250
+
251
+ return 0
252
+
253
+ def template_base_config(self):
254
+ outdir = self.args[1]
255
+ if not os.path.exists(outdir):
256
+ os.makedirs(outdir)
257
+
258
+ template_dir = self.template_dir()
259
+
260
+ for filename in ('mapproxy.yaml', 'seed.yaml',
261
+ 'full_example.yaml', 'full_seed_example.yaml'):
262
+ to = os.path.join(outdir, filename)
263
+ from_ = os.path.join(template_dir, filename)
264
+ if os.path.exists(to) and not self.options.force:
265
+ self.log_error("%s already exists, use --force", to)
266
+ return 1
267
+ print("writing %s" % (to, ))
268
+ shutil.copy(from_, to)
269
+
270
+ return 0
271
+
272
+ def template_log_ini(self):
273
+ log_filename = self.args[1]
274
+
275
+ if os.path.exists(log_filename) and not self.options.force:
276
+ self.log_error("%s already exists, use --force", log_filename)
277
+ return 1
278
+
279
+ template_dir = self.template_dir()
280
+ log_template = io.open(os.path.join(template_dir, 'log.ini'), encoding='utf-8').read()
281
+ with io.open(log_filename, 'w', encoding='utf-8') as f:
282
+ f.write(log_template)
283
+
284
+ return 0
285
+
286
+
287
+ commands = {
288
+ 'serve-develop': {
289
+ 'func': serve_develop_command,
290
+ 'help': 'Run MapProxy development server.'
291
+ },
292
+ 'serve-multiapp-develop': {
293
+ 'func': serve_multiapp_develop_command,
294
+ 'help': 'Run MultiMapProxy development server.'
295
+ },
296
+ 'create': {
297
+ 'func': create_command,
298
+ 'help': 'Create example configurations.'
299
+ },
300
+ 'scales': {
301
+ 'func': scales_command,
302
+ 'help': 'Convert between scales and resolutions.'
303
+ },
304
+ 'wms-capabilities': {
305
+ 'func': wms_capabilities_command,
306
+ 'help': 'Display WMS capabilites.',
307
+ },
308
+ 'grids': {
309
+ 'func': grids_command,
310
+ 'help': 'Display detailed informations for configured grids.'
311
+ },
312
+ 'export': {
313
+ 'func': export_command,
314
+ 'help': 'Export existing caches.'
315
+ },
316
+ 'autoconfig': {
317
+ 'func': config_command,
318
+ 'help': 'Create config from WMS capabilities or a Geopackage file.'
319
+ },
320
+ 'defrag-compact-cache': {
321
+ 'func': defrag_command,
322
+ 'help': 'De-fragmentate compact caches.'
323
+ }
324
+ }
325
+
326
+
327
+ def register_command(command_name, command_spec):
328
+ """ Method used by plugins to register a command.
329
+
330
+ :param command_name: Name of the service
331
+ :type command_name: str
332
+ :param command_spec: Definition of the command. Dictionary with a 'func' and 'help' member
333
+ :type command_spec: dict
334
+ """
335
+
336
+ commands[command_name] = command_spec
337
+
338
+
339
+ class NonStrictOptionParser(optparse.OptionParser):
340
+ def _process_args(self, largs, rargs, values):
341
+ while rargs:
342
+ arg = rargs[0]
343
+ # We handle bare "--" explicitly, and bare "-" is handled by the
344
+ # standard arg handler since the short arg case ensures that the
345
+ # len of the opt string is greater than 1.
346
+ try:
347
+ if arg == "--":
348
+ del rargs[0]
349
+ return
350
+ elif arg[0:2] == "--":
351
+ # process a single long option (possibly with value(s))
352
+ self._process_long_opt(rargs, values)
353
+ elif arg[:1] == "-" and len(arg) > 1:
354
+ # process a cluster of short options (possibly with
355
+ # value(s) for the last one only)
356
+ self._process_short_opts(rargs, values)
357
+ elif self.allow_interspersed_args:
358
+ largs.append(arg)
359
+ del rargs[0]
360
+ else:
361
+ return
362
+ except optparse.BadOptionError:
363
+ largs.append(arg)
364
+
365
+
366
+ def print_items(data, title='Commands'):
367
+ name_len = max(len(name) for name in data)
368
+
369
+ if title:
370
+ print('%s:' % (title, ), file=sys.stdout)
371
+ for name, item in data.items():
372
+ help = item.get('help', '')
373
+ name = ('%%-%ds' % name_len) % name
374
+ if help:
375
+ help = ' ' + help
376
+ print(' %s%s' % (name, help), file=sys.stdout)
377
+
378
+
379
+ def main():
380
+
381
+ load_plugins()
382
+
383
+ parser = NonStrictOptionParser("usage: %prog COMMAND [options]",
384
+ add_help_option=False)
385
+ options, args = parser.parse_args()
386
+
387
+ if len(args) < 1 or args[0] in ('--help', '-h'):
388
+ parser.print_help()
389
+ print()
390
+ print_items(commands)
391
+ sys.exit(1)
392
+
393
+ if len(args) == 1 and args[0] == '--version':
394
+ print('MapProxy ' + version)
395
+ sys.exit(1)
396
+
397
+ command = args[0]
398
+ if command not in commands:
399
+ parser.print_help()
400
+ print()
401
+ print_items(commands)
402
+ print('\nERROR: unknown command %s' % (command,), file=sys.stdout)
403
+ sys.exit(1)
404
+
405
+ args = sys.argv[0:1] + sys.argv[2:]
406
+ commands[command]['func'](args)
407
+
408
+
409
+ if __name__ == '__main__':
410
+ main()
@@ -0,0 +1,160 @@
1
+ # This file is part of the MapProxy project.
2
+ # Copyright (C) 2011 Omniscale <http://omniscale.de>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from __future__ import print_function
17
+
18
+ import sys
19
+ import optparse
20
+ from io import BytesIO
21
+ from urllib.parse import urlparse
22
+
23
+ from xml import etree
24
+
25
+ from mapproxy.client.http import open_url, HTTPClientError
26
+ from mapproxy.request.base import BaseRequest, url_decode
27
+ from mapproxy.util.ext import wmsparse
28
+
29
+
30
+ class PrettyPrinter(object):
31
+ def __init__(self, indent=4, version='1.1.1'):
32
+ self.indent = indent
33
+ self.print_order = ['name', 'title', 'url', 'srs', 'llbbox', 'bbox']
34
+ self.marker = '- '
35
+ self.version = version
36
+
37
+ def print_line(self, indent, key, value=None, mark_first=False):
38
+ marker = ''
39
+ if value is None:
40
+ value = ''
41
+ if mark_first:
42
+ indent = indent - len(self.marker)
43
+ marker = self.marker
44
+ print(("%s%s%s: %s" % (' '*indent, marker, key, value)))
45
+
46
+ def _format_output(self, key, value, indent, mark_first=False):
47
+ if key == 'bbox':
48
+ self.print_line(indent, key)
49
+ for srs_code, bbox in value.items():
50
+ self.print_line(indent+self.indent, srs_code, value=bbox, mark_first=mark_first)
51
+ else:
52
+ if isinstance(value, set):
53
+ value = list(value)
54
+ self.print_line(indent, key, value=value, mark_first=mark_first)
55
+
56
+ def print_layers(self, capabilities, indent=None, root=False):
57
+ if root:
58
+ print("# Note: This is not a valid MapProxy configuration!")
59
+ print('Capabilities Document Version %s' % (self.version,))
60
+ print('Root-Layer:')
61
+ layer_list = capabilities.layers()['layers']
62
+ else:
63
+ layer_list = capabilities['layers']
64
+
65
+ indent = indent or self.indent
66
+ for layer in layer_list:
67
+ marked_first = False
68
+ # print ordered items first
69
+ for item in self.print_order:
70
+ if layer.get(item, False):
71
+ if not marked_first:
72
+ marked_first = True
73
+ self._format_output(item, layer[item], indent, mark_first=marked_first)
74
+ else:
75
+ self._format_output(item, layer[item], indent)
76
+ # print remaining items except sublayers
77
+ for key, value in layer.items():
78
+ if key in self.print_order or key == 'layers':
79
+ continue
80
+ self._format_output(key, value, indent)
81
+ # print the sublayers now
82
+ if layer.get('layers', False):
83
+ self.print_line(indent, 'layers')
84
+ self.print_layers(layer, indent=indent+self.indent)
85
+
86
+
87
+ def log_error(msg, *args):
88
+ print(msg % args, file=sys.stderr)
89
+
90
+
91
+ def wms_capapilities_url(url, version):
92
+ parsed_url = urlparse(url)
93
+ base_req = BaseRequest(
94
+ url=url.split('?', 1)[0],
95
+ param=url_decode(parsed_url.query),
96
+ )
97
+
98
+ base_req.params['service'] = 'WMS'
99
+ base_req.params['version'] = version
100
+ base_req.params['request'] = 'GetCapabilities'
101
+ return base_req.complete_url
102
+
103
+
104
+ def parse_capabilities(fileobj, version='1.1.1'):
105
+ try:
106
+ return wmsparse.parse_capabilities(fileobj)
107
+ except ValueError as ex:
108
+ log_error('%s\n%s\n%s\n%s\nNot a capabilities document: %s',
109
+ 'Recieved document:', '-'*80, fileobj.getvalue(), '-'*80, ex.args[0])
110
+ sys.exit(1)
111
+ except etree.ElementTree.ParseError as ex:
112
+ log_error('%s\n%s\n%s\n%s\nCould not parse the document: %s',
113
+ 'Recieved document:', '-'*80, fileobj.getvalue(), '-'*80, ex.args[0])
114
+ sys.exit(1)
115
+
116
+
117
+ def parse_capabilities_url(url, version='1.1.1'):
118
+ try:
119
+ capabilities_url = wms_capapilities_url(url, version)
120
+ capabilities_response = open_url(capabilities_url)
121
+ except HTTPClientError as ex:
122
+ log_error('ERROR: %s', ex.args[0])
123
+ sys.exit(1)
124
+
125
+ # after parsing capabilities_response will be empty, therefore cache it
126
+ capabilities = BytesIO(capabilities_response.read())
127
+ return parse_capabilities(capabilities, version=version)
128
+
129
+
130
+ def wms_capabilities_command(args=None):
131
+ parser = optparse.OptionParser("%prog wms-capabilities [options] URL",
132
+ description="Read and parse WMS 1.1.1 capabilities and print out"
133
+ " information about each layer. It does _not_ return a valid"
134
+ " MapProxy configuration.")
135
+ parser.add_option("--host", dest="capabilities_url",
136
+ help="WMS Capabilites URL")
137
+ parser.add_option(
138
+ "--version", dest="version", choices=['1.1.1', '1.3.0'], default='1.1.1',
139
+ help="Request GetCapabilities-document in version 1.1.1 or 1.3.0", metavar="<1.1.1 or 1.3.0>")
140
+
141
+ if args:
142
+ args = args[1:] # remove script name
143
+
144
+ (options, args) = parser.parse_args(args)
145
+ if not options.capabilities_url:
146
+ if len(args) != 1:
147
+ parser.print_help()
148
+ sys.exit(2)
149
+ else:
150
+ options.capabilities_url = args[0]
151
+
152
+ try:
153
+ service = parse_capabilities_url(options.capabilities_url, version=options.version)
154
+
155
+ printer = PrettyPrinter(indent=4, version=options.version)
156
+ printer.print_layers(service, root=True)
157
+
158
+ except KeyError as ex:
159
+ log_error('XML-Element has no such attribute (%s).' % (ex.args[0],))
160
+ sys.exit(1)
File without changes
@@ -0,0 +1,127 @@
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
+
17
+ import errno
18
+ import os
19
+ import sqlite3
20
+ import time
21
+ from contextlib import contextmanager
22
+
23
+
24
+ class CacheLockedError(Exception):
25
+ pass
26
+
27
+
28
+ class CacheLocker(object):
29
+ def __init__(self, lockfile, polltime=0.1):
30
+ self.lockfile = lockfile
31
+ self.polltime = polltime
32
+ self._initialize_lockfile()
33
+
34
+ def _initialize_lockfile(self):
35
+ db = sqlite3.connect(self.lockfile)
36
+ db.execute("""
37
+ CREATE TABLE IF NOT EXISTS cache_locks (
38
+ cache_name TEXT NOT NULL,
39
+ created REAL NOT NULL,
40
+ pid INTEGER NUT NULL
41
+ );
42
+ """)
43
+ db.commit()
44
+ db.close()
45
+
46
+ @contextmanager
47
+ def _exclusive_db_cursor(self):
48
+ db = sqlite3.connect(self.lockfile, isolation_level="EXCLUSIVE")
49
+ db.row_factory = sqlite3.Row
50
+ cur = db.cursor()
51
+
52
+ try:
53
+ yield cur
54
+ finally:
55
+ db.commit()
56
+ db.close()
57
+
58
+ @contextmanager
59
+ def lock(self, cache_name, no_block=False):
60
+
61
+ pid = os.getpid()
62
+
63
+ while True:
64
+ with self._exclusive_db_cursor() as cur:
65
+ self._add_lock(cur, cache_name, pid)
66
+ if self._poll(cur, cache_name, pid):
67
+ break
68
+ elif no_block:
69
+ raise CacheLockedError()
70
+ time.sleep(self.polltime)
71
+
72
+ try:
73
+ yield
74
+ finally:
75
+ with self._exclusive_db_cursor() as cur:
76
+ self._remove_lock(cur, cache_name, pid)
77
+
78
+ def _poll(self, cur, cache_name, pid):
79
+ active_locks = False
80
+ cur.execute("SELECT * from cache_locks where cache_name = ? ORDER BY created", (cache_name, ))
81
+
82
+ for lock in cur:
83
+ if not active_locks and lock['cache_name'] == cache_name and lock['pid'] == pid:
84
+ # we are waiting and it is out turn
85
+ return True
86
+
87
+ if not is_running(lock['pid']):
88
+ self._remove_lock(cur, lock['cache_name'], lock['pid'])
89
+ else:
90
+ active_locks = True
91
+
92
+ return not active_locks
93
+
94
+ def _add_lock(self, cur, cache_name, pid):
95
+ cur.execute("SELECT count(*) from cache_locks WHERE cache_name = ? AND pid = ?", (cache_name, pid))
96
+ if cur.fetchone()[0] == 0:
97
+ cur.execute("INSERT INTO cache_locks (cache_name, pid, created) VALUES (?, ?, ?)",
98
+ (cache_name, pid, time.time()))
99
+
100
+ def _remove_lock(self, cur, cache_name, pid):
101
+ cur.execute("DELETE FROM cache_locks WHERE cache_name = ? AND pid = ?", (cache_name, pid))
102
+
103
+
104
+ class DummyCacheLocker(object):
105
+ @contextmanager
106
+ def lock(self, cache_name, no_block=False):
107
+ yield
108
+
109
+
110
+ def is_running(pid):
111
+ try:
112
+ os.kill(pid, 0)
113
+ except OSError as err:
114
+ if err.errno == errno.ESRCH:
115
+ return False
116
+ elif err.errno == errno.EPERM:
117
+ return True
118
+ else:
119
+ raise err
120
+ else:
121
+ return True
122
+
123
+
124
+ if __name__ == '__main__':
125
+ locker = CacheLocker('/tmp/cachelock_test')
126
+ with locker.lock('foo'):
127
+ pass