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,536 @@
1
+ # -:- encoding: utf-8 -:-
2
+ # This file is part of the MapProxy project.
3
+ # Copyright (C) 2010 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 __future__ import division
18
+
19
+ import math
20
+ import time
21
+
22
+ from mapproxy.compat import iteritems, itervalues
23
+ from mapproxy.response import Response
24
+ from mapproxy.exception import RequestError
25
+ from mapproxy.service.base import Server
26
+ from mapproxy.request.tile import tile_request
27
+ from mapproxy.request.base import split_mime_type
28
+ from mapproxy.layer import map_extent_from_grid
29
+ from mapproxy.source import SourceError
30
+ from mapproxy.srs import SRS
31
+ from mapproxy.grid import default_bboxs
32
+ from mapproxy.image import BlankImageSource
33
+ from mapproxy.image.opts import ImageOptions
34
+ from mapproxy.image.mask import mask_image_source_from_coverage
35
+ from mapproxy.util.ext.odict import odict
36
+ from mapproxy.util.coverage import load_limited_to
37
+
38
+ import logging
39
+ log = logging.getLogger(__name__)
40
+
41
+
42
+ from mapproxy.template import template_loader, bunch
43
+ get_template = template_loader(__name__, 'templates')
44
+
45
+ class TileServer(Server):
46
+ """
47
+ A Tile Server. Supports strict TMS and non-TMS requests. The difference is the
48
+ support for profiles. The our internal tile cache starts with one tile at the
49
+ first level (like KML, etc.), but the global-geodetic and global-mercator
50
+ start with two and four tiles. The ``tile_request`` should set ``use_profiles``
51
+ accordingly (eg. False if first level is one tile)
52
+ """
53
+ names = ('tiles', 'tms')
54
+ request_parser = staticmethod(tile_request)
55
+ request_methods = ('map', 'tms_capabilities, tms_root_resource')
56
+ template_file = 'tms_capabilities.xml'
57
+ layer_template_file = 'tms_tilemap_capabilities.xml'
58
+ root_resource_template_file = 'tms_root_resource.xml'
59
+
60
+ def __init__(self, layers, md, max_tile_age=None, use_dimension_layers=False, origin=None):
61
+ Server.__init__(self)
62
+ self.layers = layers
63
+ self.md = md
64
+ self.max_tile_age = max_tile_age
65
+ self.use_dimension_layers = use_dimension_layers
66
+ self.origin = origin
67
+
68
+ def map(self, tile_request):
69
+ """
70
+ :return: the requested tile
71
+ :rtype: Response
72
+ """
73
+ if self.origin and not tile_request.origin:
74
+ tile_request.origin = self.origin
75
+ layer, limit_to = self.layer(tile_request)
76
+
77
+ def decorate_img(image):
78
+ query_extent = (layer.grid.srs.srs_code,
79
+ layer.tile_bbox(tile_request, use_profiles=tile_request.use_profiles))
80
+ return self.decorate_img(image, 'tms', [layer.name], tile_request.http.environ, query_extent)
81
+
82
+ tile = layer.render(tile_request, use_profiles=tile_request.use_profiles, coverage=limit_to, decorate_img=decorate_img)
83
+
84
+ tile_format = getattr(tile, 'format', tile_request.format)
85
+ resp = Response(tile.as_buffer(), content_type='image/' + tile_format)
86
+ if tile.cacheable:
87
+ resp.cache_headers(tile.timestamp, etag_data=(tile.timestamp, tile.size),
88
+ max_age=self.max_tile_age)
89
+ else:
90
+ resp.cache_headers(no_cache=True)
91
+ resp.make_conditional(tile_request.http)
92
+ return resp
93
+
94
+ def _internal_layer(self, tile_request):
95
+ if '_layer_spec' in tile_request.dimensions:
96
+ name = tile_request.layer + '_' + tile_request.dimensions['_layer_spec']
97
+ else:
98
+ name = tile_request.layer
99
+ if name in self.layers:
100
+ return self.layers[name]
101
+ if name + '_EPSG900913' in self.layers:
102
+ return self.layers[name + '_EPSG900913']
103
+ if name + '_EPSG4326' in self.layers:
104
+ return self.layers[name + '_EPSG4326']
105
+ return None
106
+
107
+ def _internal_dimension_layer(self, tile_request):
108
+ key = (tile_request.layer, tile_request.dimensions.get('_layer_spec'))
109
+ return self.layers.get(key)
110
+
111
+ def layer(self, tile_request):
112
+ if self.use_dimension_layers:
113
+ internal_layer = self._internal_dimension_layer(tile_request)
114
+ else:
115
+ internal_layer = self._internal_layer(tile_request)
116
+ if internal_layer is None:
117
+ raise RequestError('unknown layer: ' + tile_request.layer, request=tile_request)
118
+
119
+ limit_to = self.authorize_tile_layer(internal_layer, tile_request)
120
+ return internal_layer, limit_to
121
+
122
+ def authorize_tile_layer(self, tile_layer, request):
123
+ if 'mapproxy.authorize' in request.http.environ:
124
+ if request.tile:
125
+ query_extent = (tile_layer.grid.srs.srs_code,
126
+ tile_layer.tile_bbox(request, use_profiles=request.use_profiles))
127
+ else:
128
+ query_extent = None # for layer capabilities
129
+ result = request.http.environ['mapproxy.authorize']('tms', [tile_layer.name],
130
+ query_extent=query_extent, environ=request.http.environ)
131
+ if result['authorized'] == 'unauthenticated':
132
+ raise RequestError('unauthorized', status=401)
133
+ if result['authorized'] == 'full':
134
+ return
135
+ if result['authorized'] == 'partial':
136
+ if result['layers'].get(tile_layer.name, {}).get('tile', False) == True:
137
+ limited_to = result['layers'][tile_layer.name].get('limited_to')
138
+ if not limited_to:
139
+ limited_to = result.get('limited_to')
140
+ if limited_to:
141
+ return load_limited_to(limited_to)
142
+ else:
143
+ return None
144
+ raise RequestError('forbidden', status=403)
145
+
146
+ def authorized_tile_layers(self, env):
147
+ if 'mapproxy.authorize' in env:
148
+ result = env['mapproxy.authorize']('tms', [l for l in self.layers],
149
+ query_extent=None, environ=env)
150
+ if result['authorized'] == 'unauthenticated':
151
+ raise RequestError('unauthorized', status=401)
152
+ if result['authorized'] == 'full':
153
+ return self.layers
154
+ if result['authorized'] == 'none':
155
+ raise RequestError('forbidden', status=403)
156
+ allowed_layers = odict()
157
+ for layer in itervalues(self.layers):
158
+ if result['layers'].get(layer.name, {}).get('tile', False) == True:
159
+ allowed_layers[layer.name] = layer
160
+ return allowed_layers
161
+ else:
162
+ return self.layers
163
+
164
+ def tms_capabilities(self, tms_request):
165
+ """
166
+ :return: the rendered tms capabilities
167
+ :rtype: Response
168
+ """
169
+ service = self._service_md(tms_request)
170
+ if hasattr(tms_request, 'layer'):
171
+ layer, limit_to = self.layer(tms_request)
172
+ result = self._render_layer_template(layer, service)
173
+ else:
174
+ layers = self.authorized_tile_layers(tms_request.http.environ)
175
+ result = self._render_template(layers, service)
176
+
177
+ return Response(result, mimetype='text/xml')
178
+
179
+ def tms_root_resource(self, tms_request):
180
+ """
181
+ :return: root resource with all available versions of the service
182
+ :rtype: Response
183
+ """
184
+ service = self._service_md(tms_request)
185
+ result = self._render_root_resource_template(service)
186
+ return Response(result, mimetype='text/xml')
187
+
188
+ def _service_md(self, map_request):
189
+ md = dict(self.md)
190
+ md['url'] = map_request.http.base_url
191
+ return md
192
+
193
+ def _render_template(self, layers, service):
194
+ template = get_template(self.template_file)
195
+ return template.substitute(service=bunch(default='', **service), layers=layers)
196
+
197
+ def _render_layer_template(self, layer, service):
198
+ template = get_template(self.layer_template_file)
199
+ return template.substitute(service=bunch(default='', **service), layer=layer)
200
+
201
+ def _render_root_resource_template(self, service):
202
+ template = get_template(self.root_resource_template_file)
203
+ return template.substitute(service=bunch(default='', **service))
204
+
205
+ class TileLayer(object):
206
+ def __init__(self, name, title, md, tile_manager, info_sources=[], dimensions=None):
207
+ """
208
+ :param md: the layer metadata
209
+ :param tile_manager: the layer tile manager
210
+ """
211
+ self.name = name
212
+ self.title = title
213
+ self.md = md
214
+ self.tile_manager = tile_manager
215
+ self.info_sources = info_sources
216
+ self.dimensions = dimensions
217
+ self.grid = TileServiceGrid(tile_manager.grid)
218
+ self.extent = map_extent_from_grid(self.grid)
219
+ self._empty_tile = None
220
+ self._mixed_format = True if self.md.get('format', False) == 'mixed' else False
221
+ self.empty_response_as_png = True
222
+
223
+ @property
224
+ def bbox(self):
225
+ return self.grid.bbox
226
+
227
+ @property
228
+ def srs(self):
229
+ return self.grid.srs
230
+
231
+ @property
232
+ def format(self):
233
+ _mime_class, format, _options = split_mime_type(self.format_mime_type)
234
+ return format
235
+
236
+ @property
237
+ def queryable(self):
238
+ return bool(self.info_sources)
239
+
240
+ @property
241
+ def format_mime_type(self):
242
+ # force png format for capabilities & requests if mixed format
243
+ if self._mixed_format:
244
+ return 'image/png'
245
+ return self.md.get('format', 'image/png')
246
+
247
+ def _internal_tile_coord(self, tile_request, use_profiles=False):
248
+ tile_coord = self.grid.internal_tile_coord(tile_request.tile, use_profiles)
249
+ if tile_coord is None:
250
+ raise RequestError('The requested tile is outside the bounding box'
251
+ ' of the tile map.', request=tile_request,
252
+ code='TileOutOfRange')
253
+ if tile_request.origin == 'nw' and self.grid.origin not in ('ul', 'nw'):
254
+ tile_coord = self.grid.flip_tile_coord(tile_coord)
255
+ elif tile_request.origin == 'sw' and self.grid.origin not in ('ll', 'sw', None):
256
+ tile_coord = self.grid.flip_tile_coord(tile_coord)
257
+
258
+ return tile_coord
259
+
260
+ def empty_response(self):
261
+ if self.empty_response_as_png:
262
+ format = 'png'
263
+ else:
264
+ format = self.format
265
+ if not self._empty_tile:
266
+ img = BlankImageSource(size=self.grid.tile_size,
267
+ image_opts=ImageOptions(format=format, transparent=True))
268
+ self._empty_tile = img.as_buffer().read()
269
+ return ImageResponse(self._empty_tile, format=format, timestamp=time.time())
270
+
271
+ def tile_bbox(self, tile_request, use_profiles=False, limit=False):
272
+ tile_coord = self._internal_tile_coord(tile_request, use_profiles=use_profiles)
273
+ return self.grid.tile_bbox(tile_coord, limit=limit)
274
+
275
+ def checked_dimensions(self, tile_request):
276
+ dimensions = {}
277
+
278
+ for dimension, values in iteritems(self.dimensions):
279
+ value = tile_request.dimensions.get(dimension)
280
+ if value in values:
281
+ dimensions[dimension] = value
282
+ elif not value or value == 'default':
283
+ dimensions[dimension] = values.default
284
+ else:
285
+ raise RequestError('invalid dimension value (%s=%s).'
286
+ % (dimension, value), request=tile_request,
287
+ code='InvalidParameterValue')
288
+ return dimensions
289
+
290
+ def render(self, tile_request, use_profiles=False, coverage=None, decorate_img=None):
291
+ if tile_request.format != self.format:
292
+ raise RequestError('invalid format (%s). this tile set only supports (%s)'
293
+ % (tile_request.format, self.format), request=tile_request,
294
+ code='InvalidParameterValue')
295
+
296
+ tile_coord = self._internal_tile_coord(tile_request, use_profiles=use_profiles)
297
+
298
+ coverage_intersects = False
299
+ if coverage:
300
+ tile_bbox = self.grid.tile_bbox(tile_coord)
301
+ if coverage.contains(tile_bbox, self.grid.srs):
302
+ pass
303
+ elif coverage.intersects(tile_bbox, self.grid.srs):
304
+ coverage_intersects = True
305
+ else:
306
+ return self.empty_response()
307
+
308
+ dimensions = self.checked_dimensions(tile_request)
309
+
310
+ try:
311
+ with self.tile_manager.session():
312
+ tile = self.tile_manager.load_tile_coord(tile_coord,
313
+ dimensions=dimensions, with_metadata=True)
314
+ if tile.source is None:
315
+ return self.empty_response()
316
+
317
+ # Provide the wrapping WSGI app or filter the opportunity to process the
318
+ # image before it's wrapped up in a response
319
+ if decorate_img:
320
+ tile.source = decorate_img(tile.source)
321
+
322
+ if coverage_intersects:
323
+ if self.empty_response_as_png:
324
+ format = 'png'
325
+ image_opts = ImageOptions(transparent=True, format='png')
326
+ else:
327
+ format = self.format
328
+ image_opts = tile.source.image_opts
329
+
330
+ tile.source = mask_image_source_from_coverage(
331
+ tile.source, tile_bbox, self.grid.srs, coverage, image_opts)
332
+
333
+ return TileResponse(tile, format=format, image_opts=image_opts)
334
+
335
+ format = None if self._mixed_format else tile_request.format
336
+ return TileResponse(tile, format=format, image_opts=self.tile_manager.image_opts)
337
+ except SourceError as e:
338
+ raise RequestError(e.args[0], request=tile_request, internal=True)
339
+
340
+ def get_info(self, info_request):
341
+ if info_request.format != self.format:
342
+ raise RequestError('invalid format (%s). this tile set only supports (%s)'
343
+ % (info_request.format, self.format), request=info_request,
344
+ code='InvalidParameterValue')
345
+
346
+ tile_coord = self._internal_tile_coord(info_request)
347
+
348
+ coverage_intersects = False
349
+ if coverage:
350
+ tile_bbox = self.grid.tile_bbox(tile_coord)
351
+ if coverage.contains(tile_bbox, self.grid.srs):
352
+ pass
353
+ elif coverage.intersects(tile_bbox, self.grid.srs):
354
+ coverage_intersects = True
355
+ else:
356
+ return self.empty_response()
357
+
358
+ dimensions = self.checked_dimensions(info_request)
359
+
360
+ try:
361
+ with self.tile_manager.session():
362
+ tile = self.tile_manager.load_tile_coord(tile_coord,
363
+ dimensions=dimensions, with_metadata=True)
364
+ if tile.source is None:
365
+ return self.empty_response()
366
+
367
+ # Provide the wrapping WSGI app or filter the opportunity to process the
368
+ # image before it's wrapped up in a response
369
+ if decorate_img:
370
+ tile.source = decorate_img(tile.source)
371
+
372
+ if coverage_intersects:
373
+ if self.empty_response_as_png:
374
+ format = 'png'
375
+ image_opts = ImageOptions(transparent=True, format='png')
376
+ else:
377
+ format = self.format
378
+ image_opts = tile.source.image_opts
379
+
380
+ tile.source = mask_image_source_from_coverage(
381
+ tile.source, tile_bbox, self.grid.srs, coverage, image_opts)
382
+
383
+ return TileResponse(tile, format=format, image_opts=image_opts)
384
+
385
+ format = None if self._mixed_format else info_request.format
386
+ return TileResponse(tile, format=format, image_opts=self.tile_manager.image_opts)
387
+ except SourceError as e:
388
+ raise RequestError(e.args[0], request=info_request, internal=True)
389
+
390
+
391
+
392
+ class ImageResponse(object):
393
+ """
394
+ Response from an image.
395
+ """
396
+ def __init__(self, img, format, timestamp):
397
+ self.img = img
398
+ self.timestamp = timestamp
399
+ self.format = format
400
+ self.size = 0
401
+ self.cacheable = True
402
+
403
+ def as_buffer(self):
404
+ return self.img
405
+
406
+
407
+ class TileResponse(object):
408
+ """
409
+ Response from a Tile.
410
+ """
411
+ def __init__(self, tile, format=None, timestamp=None, image_opts=None):
412
+ self.tile = tile
413
+ self.timestamp = tile.timestamp
414
+ self.size = tile.size
415
+ self.cacheable = tile.cacheable
416
+ self._buf = self.tile.source_buffer(format=format, image_opts=image_opts)
417
+ self.format = format or self._format_from_magic_bytes()
418
+
419
+ def as_buffer(self):
420
+ return self._buf
421
+
422
+ def _format_from_magic_bytes(self):
423
+ #read the 2 magic bytes from the buffer
424
+ magic_bytes = self._buf.read(2)
425
+ self._buf.seek(0)
426
+ if magic_bytes == b'\xFF\xD8':
427
+ return 'jpeg'
428
+ return 'png'
429
+
430
+ class TileServiceGrid(object):
431
+ """
432
+ Wraps a `TileGrid` and adds some ``TileService`` specific methods.
433
+ """
434
+ def __init__(self, grid):
435
+ self.grid = grid
436
+ self.profile = None
437
+
438
+ if self.grid.srs == SRS(900913) and self.grid.bbox == default_bboxs[SRS((900913))]:
439
+ self.profile = 'global-mercator'
440
+ self.srs_name = 'OSGEO:41001' # as required by TMS 1.0.0
441
+ self._skip_first_level = True
442
+
443
+ elif self.grid.srs == SRS(4326) and self.grid.bbox == default_bboxs[SRS((4326))]:
444
+ self.profile = 'global-geodetic'
445
+ self.srs_name = 'EPSG:4326'
446
+ self._skip_first_level = True
447
+ else:
448
+ self.profile = 'local'
449
+ self.srs_name = self.grid.srs.srs_code
450
+ self._skip_first_level = False
451
+
452
+ self._skip_odd_level = False
453
+
454
+ res_factor = self.grid.resolutions[0]/self.grid.resolutions[1]
455
+ if res_factor == math.sqrt(2):
456
+ self._skip_odd_level = True
457
+
458
+ def internal_level(self, level):
459
+ """
460
+ :return: the internal level
461
+ """
462
+ if self._skip_first_level:
463
+ level += 1
464
+ if self._skip_odd_level:
465
+ level += 1
466
+ if self._skip_odd_level:
467
+ level *= 2
468
+ return level
469
+
470
+ @property
471
+ def bbox(self):
472
+ """
473
+ :return: the bbox of all tiles of the first level
474
+ """
475
+ first_level = self.internal_level(0)
476
+ grid_size = self.grid.grid_sizes[first_level]
477
+ return self.grid._get_bbox([(0, 0, first_level),
478
+ (grid_size[0]-1, grid_size[1]-1, first_level)])
479
+
480
+ def __getattr__(self, key):
481
+ return getattr(self.grid, key)
482
+
483
+ @property
484
+ def tile_sets(self):
485
+ """
486
+ Get all public tile sets for this layer.
487
+ :return: the order and resolution of each tile set
488
+ """
489
+ tile_sets = []
490
+ num_levels = self.grid.levels
491
+ start = 0
492
+ step = 1
493
+ if self._skip_first_level:
494
+ if self._skip_odd_level:
495
+ start = 2
496
+ else:
497
+ start = 1
498
+ if self._skip_odd_level:
499
+ step = 2
500
+ for order, level in enumerate(range(start, num_levels, step)):
501
+ tile_sets.append((order, self.grid.resolutions[level]))
502
+ return tile_sets
503
+
504
+ def internal_tile_coord(self, tile_coord, use_profiles):
505
+ """
506
+ Converts public tile coords to internal tile coords.
507
+
508
+ :param tile_coord: the public tile coord
509
+ :param use_profiles: True if the tile service supports global
510
+ profiles (see `mapproxy.core.server.TileServer`)
511
+ """
512
+ x, y, z = tile_coord
513
+ if int(z) < 0:
514
+ return None
515
+ if use_profiles and self._skip_first_level:
516
+ z += 1
517
+ if self._skip_odd_level:
518
+ z *= 2
519
+ return self.grid.limit_tile((x, y, z))
520
+
521
+ def external_tile_coord(self, tile_coord, use_profiles):
522
+ """
523
+ Converts internal tile coords to external tile coords.
524
+
525
+ :param tile_coord: the internal tile coord
526
+ :param use_profiles: True if the tile service supports global
527
+ profiles (see `mapproxy.core.server.TileServer`)
528
+ """
529
+ x, y, z = tile_coord
530
+ if z < 0:
531
+ return None
532
+ if use_profiles and self._skip_first_level:
533
+ z -= 1
534
+ if self._skip_odd_level:
535
+ z //= 2
536
+ return (x, y, z)