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,491 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ WSGI server code for `mapproxy-util serve-develop`.
4
+ Supports automatic reloading and proper ^C handling.
5
+
6
+ Stripped down version of werkzeug.serving.
7
+
8
+ :copyright: (c) 2013 by the Werkzeug Team, see AUTHORS for more details.
9
+ :license: BSD, see LICENSE for more details.
10
+ """
11
+
12
+ import os
13
+ import socket
14
+ import sys
15
+ import time
16
+ import signal
17
+ import subprocess
18
+ from itertools import chain
19
+ from urllib.parse import urlparse, unquote
20
+
21
+ from werkzeug.exceptions import InternalServerError
22
+
23
+ try:
24
+ import thread
25
+ except ImportError:
26
+ import _thread as thread
27
+
28
+ try:
29
+ from SocketServer import ThreadingMixIn
30
+ from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
31
+ except ImportError:
32
+ from socketserver import ThreadingMixIn
33
+ from http.server import HTTPServer, BaseHTTPRequestHandler
34
+
35
+ from mapproxy.util.py import reraise
36
+ import mapproxy.version
37
+
38
+
39
+ def wsgi_encoding_dance(s, charset='utf-8', errors='replace'):
40
+ if isinstance(s, str):
41
+ s = s.encode(charset)
42
+ return s.decode('latin1', errors)
43
+
44
+ # from werkzeug.exceptions import InternalServerError, BadRequest
45
+
46
+
47
+ def _log(type, message, *args):
48
+ if args:
49
+ message = message % args
50
+ sys.stderr.write('[%s] %s\n' % (type, message.rstrip()))
51
+ sys.stderr.flush()
52
+
53
+
54
+ class WSGIRequestHandler(BaseHTTPRequestHandler, object):
55
+ """A request handler that implements WSGI dispatching."""
56
+
57
+ @property
58
+ def server_version(self):
59
+ return 'MapProxy/' + mapproxy.version.__version__ + ' (Werkzeug based)'
60
+
61
+ def make_environ(self):
62
+ request_url = urlparse(self.path)
63
+
64
+ def shutdown_server():
65
+ self.server.shutdown_signal = True
66
+
67
+ url_scheme = 'http'
68
+ path_info = unquote(request_url.path)
69
+
70
+ environ = {
71
+ 'wsgi.version': (1, 0),
72
+ 'wsgi.url_scheme': url_scheme,
73
+ 'wsgi.input': self.rfile,
74
+ 'wsgi.errors': sys.stderr,
75
+ 'wsgi.multithread': self.server.multithread,
76
+ 'wsgi.multiprocess': self.server.multiprocess,
77
+ 'wsgi.run_once': False,
78
+ 'werkzeug.server.shutdown': shutdown_server,
79
+ 'SERVER_SOFTWARE': self.server_version,
80
+ 'REQUEST_METHOD': self.command,
81
+ 'SCRIPT_NAME': '',
82
+ 'PATH_INFO': wsgi_encoding_dance(path_info),
83
+ 'QUERY_STRING': wsgi_encoding_dance(request_url.query),
84
+ 'CONTENT_TYPE': self.headers.get('Content-Type', ''),
85
+ 'CONTENT_LENGTH': self.headers.get('Content-Length', ''),
86
+ 'REMOTE_ADDR': self.client_address[0],
87
+ 'REMOTE_PORT': self.client_address[1],
88
+ 'SERVER_NAME': self.server.server_address[0],
89
+ 'SERVER_PORT': str(self.server.server_address[1]),
90
+ 'SERVER_PROTOCOL': self.request_version
91
+ }
92
+
93
+ for key, value in self.headers.items():
94
+ key = 'HTTP_' + key.upper().replace('-', '_')
95
+ if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
96
+ environ[key] = value
97
+
98
+ if request_url.netloc:
99
+ environ['HTTP_HOST'] = request_url.netloc
100
+
101
+ return environ
102
+
103
+ def run_wsgi(self):
104
+ if self.headers.get('Expect', '').lower().strip() == '100-continue':
105
+ self.wfile.write(b'HTTP/1.1 100 Continue\r\n\r\n')
106
+
107
+ environ = self.make_environ()
108
+ headers_set = []
109
+ headers_sent = []
110
+
111
+ def write(data):
112
+ assert headers_set, 'write() before start_response'
113
+ if not headers_sent:
114
+ status, response_headers = headers_sent[:] = headers_set
115
+ try:
116
+ code, msg = status.split(None, 1)
117
+ except ValueError:
118
+ code, msg = status, ""
119
+ self.send_response(int(code), msg)
120
+ header_keys = set()
121
+ for key, value in response_headers:
122
+ self.send_header(key, value)
123
+ key = key.lower()
124
+ header_keys.add(key)
125
+ if 'content-length' not in header_keys:
126
+ self.close_connection = True
127
+ self.send_header('Connection', 'close')
128
+ if 'server' not in header_keys:
129
+ self.send_header('Server', self.version_string())
130
+ if 'date' not in header_keys:
131
+ self.send_header('Date', self.date_time_string())
132
+ self.end_headers()
133
+
134
+ assert type(data) is bytes, 'applications must write bytes'
135
+ self.wfile.write(data)
136
+ self.wfile.flush()
137
+
138
+ def start_response(status, response_headers, exc_info=None):
139
+ if exc_info:
140
+ try:
141
+ if headers_sent:
142
+ reraise(*exc_info)
143
+ finally:
144
+ exc_info = None
145
+ elif headers_set:
146
+ raise AssertionError('Headers already set')
147
+ headers_set[:] = [status, response_headers]
148
+ return write
149
+
150
+ def execute(app):
151
+ application_iter = app(environ, start_response)
152
+ try:
153
+ for data in application_iter:
154
+ write(data)
155
+ if not headers_sent:
156
+ write(b'')
157
+ finally:
158
+ if hasattr(application_iter, 'close'):
159
+ application_iter.close()
160
+ application_iter = None
161
+
162
+ try:
163
+ execute(self.server.app)
164
+ except (socket.error, socket.timeout) as e:
165
+ self.connection_dropped(e, environ)
166
+ except Exception:
167
+ if self.server.passthrough_errors:
168
+ raise
169
+ from werkzeug.debug.tbtools import get_current_traceback
170
+ traceback = get_current_traceback(ignore_system_exceptions=True)
171
+ try:
172
+ # if we haven't yet sent the headers but they are set
173
+ # we roll back to be able to set them again.
174
+ if not headers_sent:
175
+ del headers_set[:]
176
+ execute(InternalServerError())
177
+ except Exception:
178
+ pass
179
+ self.server.log('error', 'Error on request:\n%s',
180
+ traceback.plaintext)
181
+
182
+ def handle(self):
183
+ """Handles a request ignoring dropped connections."""
184
+ rv = None
185
+ try:
186
+ rv = BaseHTTPRequestHandler.handle(self)
187
+ except (socket.error, socket.timeout) as e:
188
+ self.connection_dropped(e)
189
+ except Exception:
190
+ raise
191
+ if self.server.shutdown_signal:
192
+ self.initiate_shutdown()
193
+ return rv
194
+
195
+ def initiate_shutdown(self):
196
+ """A horrible, horrible way to kill the server for Python 2.6 and
197
+ later. It's the best we can do.
198
+ """
199
+ # Windows does not provide SIGKILL, go with SIGTERM then.
200
+ sig = getattr(signal, 'SIGKILL', signal.SIGTERM)
201
+ # reloader active
202
+ if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
203
+ os.kill(os.getpid(), sig)
204
+ # python 2.7
205
+ self.server._BaseServer__shutdown_request = True
206
+ # python 2.6
207
+ self.server._BaseServer__serving = False
208
+
209
+ def connection_dropped(self, error, environ=None):
210
+ """Called if the connection was closed by the client. By default
211
+ nothing happens.
212
+ """
213
+
214
+ def handle_one_request(self):
215
+ """Handle a single HTTP request."""
216
+ self.raw_requestline = self.rfile.readline()
217
+ if not self.raw_requestline:
218
+ self.close_connection = 1
219
+ elif self.parse_request():
220
+ return self.run_wsgi()
221
+
222
+ def send_response(self, code, message=None):
223
+ """Send the response header and log the response code."""
224
+ self.log_request(code)
225
+ if message is None:
226
+ message = code in self.responses and self.responses[code][0] or ''
227
+ if self.request_version != 'HTTP/0.9':
228
+ hdr = "%s %d %s\r\n" % (self.protocol_version, code, message)
229
+ self.wfile.write(hdr.encode('ascii'))
230
+
231
+ def version_string(self):
232
+ return BaseHTTPRequestHandler.version_string(self).strip()
233
+
234
+ def address_string(self):
235
+ return self.client_address[0]
236
+
237
+ def log_request(self, code='-', size='-'):
238
+ self.log('info', '"%s" %s %s', self.requestline, code, size)
239
+
240
+ def log_error(self, *args):
241
+ self.log('error', *args)
242
+
243
+ def log_message(self, format, *args):
244
+ self.log('info', format, *args)
245
+
246
+ def log(self, type, message, *args):
247
+ _log(type, '%s - - [%s] %s\n' % (self.address_string(),
248
+ self.log_date_time_string(),
249
+ message % args))
250
+
251
+
252
+ #: backwards compatible name if someone is subclassing it
253
+ BaseRequestHandler = WSGIRequestHandler
254
+
255
+
256
+ def select_ip_version(host, port):
257
+ """Returns AF_INET4 or AF_INET6 depending on where to connect to."""
258
+ # disabled due to problems with current ipv6 implementations
259
+ # and various operating systems. Probably this code also is
260
+ # not supposed to work, but I can't come up with any other
261
+ # ways to implement this.
262
+ # try:
263
+ # info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
264
+ # socket.SOCK_STREAM, 0,
265
+ # socket.AI_PASSIVE)
266
+ # if info:
267
+ # return info[0][0]
268
+ # except socket.gaierror:
269
+ # pass
270
+ if ':' in host and hasattr(socket, 'AF_INET6'):
271
+ return socket.AF_INET6
272
+ return socket.AF_INET
273
+
274
+
275
+ class BaseWSGIServer(HTTPServer, object):
276
+ """Simple single-threaded, single-process WSGI server."""
277
+ multithread = False
278
+ multiprocess = False
279
+ request_queue_size = 128
280
+
281
+ def __init__(self, host, port, app, handler=None,
282
+ passthrough_errors=False):
283
+ if handler is None:
284
+ handler = WSGIRequestHandler
285
+ self.address_family = select_ip_version(host, port)
286
+ HTTPServer.__init__(self, (host, int(port)), handler)
287
+ self.app = app
288
+ self.passthrough_errors = passthrough_errors
289
+ self.shutdown_signal = False
290
+
291
+ def log(self, type, message, *args):
292
+ _log(type, message, *args)
293
+
294
+ def serve_forever(self):
295
+ self.shutdown_signal = False
296
+ try:
297
+ HTTPServer.serve_forever(self)
298
+ except KeyboardInterrupt:
299
+ pass
300
+
301
+ def handle_error(self, request, client_address):
302
+ if self.passthrough_errors:
303
+ raise
304
+ else:
305
+ return HTTPServer.handle_error(self, request, client_address)
306
+
307
+ def get_request(self):
308
+ con, info = self.socket.accept()
309
+ return con, info
310
+
311
+
312
+ class ThreadedWSGIServer(ThreadingMixIn, BaseWSGIServer):
313
+ """A WSGI server that does threading."""
314
+ multithread = True
315
+
316
+
317
+ def _iter_module_files():
318
+ # The list call is necessary on Python 3 in case the module
319
+ # dictionary modifies during iteration.
320
+ for module in list(sys.modules.values()):
321
+ filename = getattr(module, '__file__', None)
322
+ if filename:
323
+ old = None
324
+ while not os.path.isfile(filename):
325
+ old = filename
326
+ filename = os.path.dirname(filename)
327
+ if filename == old:
328
+ break
329
+ else:
330
+ if filename[-4:] in ('.pyc', '.pyo'):
331
+ filename = filename[:-1]
332
+ yield filename
333
+
334
+
335
+ def _reloader_stat_loop(extra_files=None, interval=1):
336
+ """When this function is run from the main thread, it will force other
337
+ threads to exit when any modules currently loaded change.
338
+
339
+ Copyright notice. This function is based on the autoreload.py from
340
+ the CherryPy trac which originated from WSGIKit which is now dead.
341
+
342
+ :param extra_files: a list of additional files it should watch.
343
+ """
344
+ mtimes = {}
345
+ while 1:
346
+ for filename in chain(_iter_module_files(), extra_files or ()):
347
+ try:
348
+ mtime = os.stat(filename).st_mtime
349
+ except OSError:
350
+ continue
351
+
352
+ old_time = mtimes.get(filename)
353
+ if old_time is None:
354
+ mtimes[filename] = mtime
355
+ continue
356
+ elif mtime > old_time:
357
+ _log('info', ' * Detected change in %r, reloading' % filename)
358
+ sys.exit(3)
359
+ time.sleep(interval)
360
+
361
+
362
+ # currently we always use the stat loop reloader for the simple reason
363
+ # that the inotify one does not respond to added files properly. Also
364
+ # it's quite buggy and the API is a mess.
365
+ reloader_loop = _reloader_stat_loop
366
+
367
+
368
+ def restart_with_reloader():
369
+ """Spawn a new Python interpreter with the same arguments as this one,
370
+ but running the reloader thread.
371
+ """
372
+ while 1:
373
+ _log('info', ' * Restarting with reloader')
374
+
375
+ args = [sys.executable] + sys.argv
376
+ if os.name == 'nt':
377
+ # pip installs commands as .exe, but sys.argv[0]
378
+ # can miss the prefix.
379
+ # Add .exe to avoid file-not-found in subprocess call.
380
+ # Also, recent pip versions create .exe commands that are not
381
+ # executable by Python, but there is a -script.py which
382
+ # we need to call in this case. Check for this first.
383
+ if os.path.exists(args[1] + '-script.py'):
384
+ args[1] = args[1] + '-script.py'
385
+ elif not args[1].endswith('.exe'):
386
+ args[1] = args[1] + '.exe'
387
+ new_environ = os.environ.copy()
388
+ new_environ['WERKZEUG_RUN_MAIN'] = 'true'
389
+
390
+ exit_code = subprocess.call(args, env=new_environ)
391
+ if exit_code != 3:
392
+ return exit_code
393
+
394
+
395
+ def run_with_reloader(main_func, extra_files=None, interval=1):
396
+ """Run the given function in an independent python interpreter."""
397
+ import signal
398
+ signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
399
+ if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
400
+ thread.start_new_thread(main_func, ())
401
+ try:
402
+ reloader_loop(extra_files, interval)
403
+ except KeyboardInterrupt:
404
+ return
405
+ try:
406
+ sys.exit(restart_with_reloader())
407
+ except KeyboardInterrupt:
408
+ pass
409
+
410
+
411
+ def run_simple(hostname, port, application, use_reloader=False,
412
+ use_debugger=False, use_evalex=True,
413
+ extra_files=None, reloader_interval=1, threaded=False,
414
+ processes=1, request_handler=None, static_files=None,
415
+ passthrough_errors=False):
416
+ """Start an application using wsgiref and with an optional reloader. This
417
+ wraps `wsgiref` to fix the wrong default reporting of the multithreaded
418
+ WSGI variable and adds optional multithreading and fork support.
419
+
420
+ This function has a command-line interface too::
421
+
422
+ python -m werkzeug.serving --help
423
+
424
+ .. versionadded:: 0.5
425
+ `static_files` was added to simplify serving of static files as well
426
+ as `passthrough_errors`.
427
+
428
+ .. versionadded:: 0.6
429
+ support for SSL was added.
430
+
431
+ .. versionadded:: 0.8
432
+ Added support for automatically loading a SSL context from certificate
433
+ file and private key.
434
+
435
+ .. versionadded:: 0.9
436
+ Added command-line interface.
437
+
438
+ :param hostname: The host for the application. eg: ``'localhost'``
439
+ :param port: The port for the server. eg: ``8080``
440
+ :param application: the WSGI application to execute
441
+ :param use_reloader: should the server automatically restart the python
442
+ process if modules were changed?
443
+ :param use_debugger: should the werkzeug debugging system be used?
444
+ :param use_evalex: should the exception evaluation feature be enabled?
445
+ :param extra_files: a list of files the reloader should watch
446
+ additionally to the modules. For example configuration
447
+ files.
448
+ :param reloader_interval: the interval for the reloader in seconds.
449
+ :param threaded: should the process handle each request in a separate
450
+ thread?
451
+ :param processes: if greater than 1 then handle each request in a new process
452
+ up to this maximum number of concurrent processes.
453
+ :param request_handler: optional parameter that can be used to replace
454
+ the default one. You can use this to replace it
455
+ with a different
456
+ :class:`~BaseHTTPServer.BaseHTTPRequestHandler`
457
+ subclass.
458
+ :param static_files: a dict of paths for static files. This works exactly
459
+ like :class:`SharedDataMiddleware`, it's actually
460
+ just wrapping the application in that middleware before
461
+ serving.
462
+ :param passthrough_errors: set this to `True` to disable the error catching.
463
+ This means that the server will die on errors but
464
+ it can be useful to hook debuggers in (pdb etc.)
465
+ """
466
+ if use_debugger:
467
+ from werkzeug.debug import DebuggedApplication
468
+ application = DebuggedApplication(application, use_evalex)
469
+
470
+ def inner():
471
+ ThreadedWSGIServer(hostname, port, application, request_handler,
472
+ passthrough_errors).serve_forever()
473
+
474
+ if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
475
+ display_hostname = hostname != '*' and hostname or 'localhost'
476
+ if ':' in display_hostname:
477
+ display_hostname = '[%s]' % display_hostname
478
+ quit_msg = '(Press CTRL+C to quit)'
479
+ _log('info', ' * Running on http://%s:%d/ %s',
480
+ display_hostname, port, quit_msg)
481
+ if use_reloader:
482
+ # Create and destroy a socket so that any exceptions are raised before
483
+ # we spawn a separate Python interpreter and lose this ability.
484
+ address_family = select_ip_version(hostname, port)
485
+ test_socket = socket.socket(address_family, socket.SOCK_STREAM)
486
+ test_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
487
+ test_socket.bind((hostname, port))
488
+ test_socket.close()
489
+ run_with_reloader(inner, extra_files, reloader_interval)
490
+ else:
491
+ inner()