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,1174 @@
1
+ """
2
+ A small templating language
3
+
4
+ This implements a small templating language. This language implements
5
+ if/elif/else, for/continue/break, expressions, and blocks of Python
6
+ code. The syntax is::
7
+
8
+ {{any expression (function calls etc)}}
9
+ {{any expression | filter}}
10
+ {{for x in y}}...{{endfor}}
11
+ {{if x}}x{{elif y}}y{{else}}z{{endif}}
12
+ {{py:x=1}}
13
+ {{py:
14
+ def foo(bar):
15
+ return 'baz'
16
+ }}
17
+ {{default var = default_value}}
18
+ {{# comment}}
19
+
20
+ You use this with the ``Template`` class or the ``sub`` shortcut.
21
+ The ``Template`` class takes the template string and the name of
22
+ the template (for errors) and a default namespace. Then (like
23
+ ``string.Template``) you can call the ``tmpl.substitute(**kw)``
24
+ method to make a substitution (or ``tmpl.substitute(a_dict)``).
25
+
26
+ ``sub(content, **kw)`` substitutes the template immediately. You
27
+ can use ``__name='tmpl.html'`` to set the name of the template.
28
+
29
+ If there are syntax errors ``TemplateError`` will be raised.
30
+ """
31
+ from __future__ import print_function
32
+
33
+ import re
34
+ import sys
35
+ import os
36
+ import tokenize
37
+ from io import StringIO, BytesIO
38
+ from mapproxy.compat import iteritems, PY2, text_type
39
+ from mapproxy.compat.modules import escape
40
+ from mapproxy.util.py import reraise
41
+ from mapproxy.util.ext.tempita._looper import looper
42
+ from mapproxy.util.ext.tempita.compat3 import bytes, basestring_, next, is_unicode, coerce_text
43
+
44
+ if PY2:
45
+ from urllib import quote as url_quote
46
+ else:
47
+ from urllib.parse import quote as url_quote
48
+
49
+ __all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate',
50
+ 'sub_html', 'html', 'bunch']
51
+
52
+ token_re = re.compile(r'\{\{|\}\}')
53
+ in_re = re.compile(r'\s+in\s+')
54
+ var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
55
+
56
+
57
+ class TemplateError(Exception):
58
+ """Exception raised while parsing a template
59
+ """
60
+
61
+ def __init__(self, message, position, name=None):
62
+ Exception.__init__(self, message)
63
+ self.position = position
64
+ self.name = name
65
+
66
+ def __str__(self):
67
+ msg = ' '.join(self.args)
68
+ if self.position:
69
+ msg = '%s at line %s column %s' % (
70
+ msg, self.position[0], self.position[1])
71
+ if self.name:
72
+ msg += ' in %s' % self.name
73
+ return msg
74
+
75
+
76
+ class _TemplateContinue(Exception):
77
+ pass
78
+
79
+
80
+ class _TemplateBreak(Exception):
81
+ pass
82
+
83
+
84
+ def get_file_template(name, from_template):
85
+ path = os.path.join(os.path.dirname(from_template.name), name)
86
+ return from_template.__class__.from_filename(
87
+ path, namespace=from_template.namespace,
88
+ get_template=from_template.get_template)
89
+
90
+
91
+ class Template(object):
92
+
93
+ default_namespace = {
94
+ 'start_braces': '{{',
95
+ 'end_braces': '}}',
96
+ 'looper': looper,
97
+ }
98
+
99
+ default_encoding = 'utf8'
100
+ default_inherit = None
101
+
102
+ def __init__(self, content, name=None, namespace=None, stacklevel=None,
103
+ get_template=None, default_inherit=None, line_offset=0):
104
+ self.content = content
105
+ self._unicode = is_unicode(content)
106
+ if name is None and stacklevel is not None:
107
+ try:
108
+ caller = sys._getframe(stacklevel)
109
+ except ValueError:
110
+ pass
111
+ else:
112
+ globals = caller.f_globals
113
+ lineno = caller.f_lineno
114
+ if '__file__' in globals:
115
+ name = globals['__file__']
116
+ if name.endswith('.pyc') or name.endswith('.pyo'):
117
+ name = name[:-1]
118
+ elif '__name__' in globals:
119
+ name = globals['__name__']
120
+ else:
121
+ name = '<string>'
122
+ if lineno:
123
+ name += ':%s' % lineno
124
+ self.name = name
125
+ self._parsed = parse(content, name=name, line_offset=line_offset)
126
+ if namespace is None:
127
+ namespace = {}
128
+ self.namespace = namespace
129
+ self.get_template = get_template
130
+ if default_inherit is not None:
131
+ self.default_inherit = default_inherit
132
+
133
+ def from_filename(cls, filename, namespace=None, encoding=None,
134
+ default_inherit=None, get_template=get_file_template):
135
+ f = open(filename, 'rb')
136
+ c = f.read()
137
+ f.close()
138
+ if encoding:
139
+ c = c.decode(encoding)
140
+ return cls(content=c, name=filename, namespace=namespace,
141
+ default_inherit=default_inherit, get_template=get_template)
142
+
143
+ from_filename = classmethod(from_filename)
144
+
145
+ def __repr__(self):
146
+ return '<%s %s name=%r>' % (
147
+ self.__class__.__name__,
148
+ hex(id(self))[2:], self.name)
149
+
150
+ def substitute(self, *args, **kw):
151
+ if args:
152
+ if kw:
153
+ raise TypeError(
154
+ "You can only give positional *or* keyword arguments")
155
+ if len(args) > 1:
156
+ raise TypeError(
157
+ "You can only give one positional argument")
158
+ if not hasattr(args[0], 'items'):
159
+ raise TypeError(
160
+ "If you pass in a single argument, you must pass in a dictionary-like object (with a .items() method); you gave %r"
161
+ % (args[0],))
162
+ kw = args[0]
163
+ ns = kw
164
+ ns['__template_name__'] = self.name
165
+ if self.namespace:
166
+ ns.update(self.namespace)
167
+ result, defs, inherit = self._interpret(ns)
168
+ if not inherit:
169
+ inherit = self.default_inherit
170
+ if inherit:
171
+ result = self._interpret_inherit(result, defs, inherit, ns)
172
+ return result
173
+
174
+ def _interpret(self, ns):
175
+ __traceback_hide__ = True
176
+ parts = []
177
+ defs = {}
178
+ self._interpret_codes(self._parsed, ns, out=parts, defs=defs)
179
+ if '__inherit__' in defs:
180
+ inherit = defs.pop('__inherit__')
181
+ else:
182
+ inherit = None
183
+ return ''.join(parts), defs, inherit
184
+
185
+ def _interpret_inherit(self, body, defs, inherit_template, ns):
186
+ __traceback_hide__ = True
187
+ if not self.get_template:
188
+ raise TemplateError(
189
+ 'You cannot use inheritance without passing in get_template',
190
+ position=None, name=self.name)
191
+ templ = self.get_template(inherit_template, self)
192
+ self_ = TemplateObject(self.name)
193
+ for name, value in iteritems(defs):
194
+ setattr(self_, name, value)
195
+ self_.body = body
196
+ ns = ns.copy()
197
+ ns['self'] = self_
198
+ return templ.substitute(ns)
199
+
200
+ def _interpret_codes(self, codes, ns, out, defs):
201
+ __traceback_hide__ = True
202
+ for item in codes:
203
+ if isinstance(item, basestring_):
204
+ out.append(item)
205
+ else:
206
+ self._interpret_code(item, ns, out, defs)
207
+
208
+ def _interpret_code(self, code, ns, out, defs):
209
+ __traceback_hide__ = True
210
+ name, pos = code[0], code[1]
211
+ if name == 'py':
212
+ self._exec(code[2], ns, pos)
213
+ elif name == 'continue':
214
+ raise _TemplateContinue()
215
+ elif name == 'break':
216
+ raise _TemplateBreak()
217
+ elif name == 'for':
218
+ vars, expr, content = code[2], code[3], code[4]
219
+ expr = self._eval(expr, ns, pos)
220
+ self._interpret_for(vars, expr, content, ns, out, defs)
221
+ elif name == 'cond':
222
+ parts = code[2:]
223
+ self._interpret_if(parts, ns, out, defs)
224
+ elif name == 'expr':
225
+ parts = code[2].split('|')
226
+ base = self._eval(parts[0], ns, pos)
227
+ for part in parts[1:]:
228
+ func = self._eval(part, ns, pos)
229
+ base = func(base)
230
+ out.append(self._repr(base, pos))
231
+ elif name == 'default':
232
+ var, expr = code[2], code[3]
233
+ if var not in ns:
234
+ result = self._eval(expr, ns, pos)
235
+ ns[var] = result
236
+ elif name == 'inherit':
237
+ expr = code[2]
238
+ value = self._eval(expr, ns, pos)
239
+ defs['__inherit__'] = value
240
+ elif name == 'def':
241
+ name = code[2]
242
+ signature = code[3]
243
+ parts = code[4]
244
+ ns[name] = defs[name] = TemplateDef(self, name, signature, body=parts, ns=ns,
245
+ pos=pos)
246
+ elif name == 'comment':
247
+ return
248
+ else:
249
+ assert 0, "Unknown code: %r" % name
250
+
251
+ def _interpret_for(self, vars, expr, content, ns, out, defs):
252
+ __traceback_hide__ = True
253
+ if expr is None:
254
+ return
255
+ for item in expr:
256
+ if len(vars) == 1:
257
+ ns[vars[0]] = item
258
+ else:
259
+ if len(vars) != len(item):
260
+ raise ValueError(
261
+ 'Need %i items to unpack (got %i items)'
262
+ % (len(vars), len(item)))
263
+ for name, value in zip(vars, item):
264
+ ns[name] = value
265
+ try:
266
+ self._interpret_codes(content, ns, out, defs)
267
+ except _TemplateContinue:
268
+ continue
269
+ except _TemplateBreak:
270
+ break
271
+
272
+ def _interpret_if(self, parts, ns, out, defs):
273
+ __traceback_hide__ = True
274
+ # @@: if/else/else gets through
275
+ for part in parts:
276
+ assert not isinstance(part, basestring_)
277
+ name, pos = part[0], part[1]
278
+ if name == 'else':
279
+ result = True
280
+ else:
281
+ result = self._eval(part[2], ns, pos)
282
+ if result:
283
+ self._interpret_codes(part[3], ns, out, defs)
284
+ break
285
+
286
+ def _eval(self, code, ns, pos):
287
+ __traceback_hide__ = True
288
+ try:
289
+ try:
290
+ value = eval(code, self.default_namespace, ns)
291
+ except SyntaxError as e:
292
+ raise SyntaxError(
293
+ 'invalid syntax in expression: %s' % code)
294
+ return value
295
+ except:
296
+ exc_info = sys.exc_info()
297
+ e = exc_info[1]
298
+ if getattr(e, 'args', None):
299
+ arg0 = e.args[0]
300
+ else:
301
+ arg0 = coerce_text(e)
302
+ e.args = (self._add_line_info(arg0, pos),)
303
+ reraise((exc_info[0], e, exc_info[2]))
304
+
305
+ def _exec(self, code, ns, pos):
306
+ __traceback_hide__ = True
307
+ try:
308
+ exec(code, self.default_namespace, ns)
309
+ except:
310
+ exc_info = sys.exc_info()
311
+ e = exc_info[1]
312
+ if e.args:
313
+ e.args = (self._add_line_info(e.args[0], pos),)
314
+ else:
315
+ e.args = (self._add_line_info(None, pos),)
316
+ reraise((exc_info[0], e, exc_info[2]))
317
+
318
+ def _repr(self, value, pos):
319
+ __traceback_hide__ = True
320
+ try:
321
+ if value is None:
322
+ return ''
323
+ if self._unicode:
324
+ try:
325
+ value = text_type(value)
326
+ except UnicodeDecodeError:
327
+ value = bytes(value)
328
+ else:
329
+ if not isinstance(value, basestring_):
330
+ value = coerce_text(value)
331
+ if (is_unicode(value)
332
+ and self.default_encoding):
333
+ value = value.encode(self.default_encoding)
334
+ except:
335
+ exc_info = sys.exc_info()
336
+ e = exc_info[1]
337
+ e.args = (self._add_line_info(e.args[0], pos),)
338
+ reraise((exc_info[0], e, exc_info[2]))
339
+ else:
340
+ if self._unicode and isinstance(value, bytes):
341
+ if not self.default_encoding:
342
+ raise UnicodeDecodeError(
343
+ 'Cannot decode bytes value %r into unicode '
344
+ '(no default_encoding provided)' % value)
345
+ try:
346
+ value = value.decode(self.default_encoding)
347
+ except UnicodeDecodeError as e:
348
+ raise UnicodeDecodeError(
349
+ e.encoding,
350
+ e.object,
351
+ e.start,
352
+ e.end,
353
+ e.reason + ' in string %r' % value)
354
+ elif not self._unicode and is_unicode(value):
355
+ if not self.default_encoding:
356
+ raise UnicodeEncodeError(
357
+ 'Cannot encode unicode value %r into bytes '
358
+ '(no default_encoding provided)' % value)
359
+ value = value.encode(self.default_encoding)
360
+ return value
361
+
362
+ def _add_line_info(self, msg, pos):
363
+ msg = "%s at line %s column %s" % (
364
+ msg, pos[0], pos[1])
365
+ if self.name:
366
+ msg += " in file %s" % self.name
367
+ return msg
368
+
369
+
370
+ def sub(content, **kw):
371
+ name = kw.get('__name')
372
+ tmpl = Template(content, name=name)
373
+ return tmpl.substitute(kw)
374
+
375
+
376
+ def paste_script_template_renderer(content, vars, filename=None):
377
+ tmpl = Template(content, name=filename)
378
+ return tmpl.substitute(vars)
379
+
380
+
381
+ class bunch(dict):
382
+
383
+ def __init__(self, **kw):
384
+ for name, value in iteritems(kw):
385
+ setattr(self, name, value)
386
+
387
+ def __setattr__(self, name, value):
388
+ self[name] = value
389
+
390
+ def __getattr__(self, name):
391
+ try:
392
+ return self[name]
393
+ except KeyError:
394
+ raise AttributeError(name)
395
+
396
+ def __getitem__(self, key):
397
+ if 'default' in self:
398
+ try:
399
+ return dict.__getitem__(self, key)
400
+ except KeyError:
401
+ return dict.__getitem__(self, 'default')
402
+ else:
403
+ return dict.__getitem__(self, key)
404
+
405
+ def __repr__(self):
406
+ items = [
407
+ (k, v) for k, v in iteritems(self)]
408
+ items.sort()
409
+ return '<%s %s>' % (
410
+ self.__class__.__name__,
411
+ ' '.join(['%s=%r' % (k, v) for k, v in items]))
412
+
413
+ ############################################################
414
+ ## HTML Templating
415
+ ############################################################
416
+
417
+
418
+ class html(object):
419
+
420
+ def __init__(self, value):
421
+ self.value = value
422
+
423
+ def __str__(self):
424
+ return self.value
425
+
426
+ def __html__(self):
427
+ return self.value
428
+
429
+ def __repr__(self):
430
+ return '<%s %r>' % (
431
+ self.__class__.__name__, self.value)
432
+
433
+
434
+ def html_quote(value, force=True):
435
+ if not force and hasattr(value, '__html__'):
436
+ return value.__html__()
437
+ if value is None:
438
+ return ''
439
+ if not isinstance(value, basestring_):
440
+ value = coerce_text(value)
441
+ if sys.version >= "3" and isinstance(value, bytes):
442
+ value = escape(value.decode('latin1'), 1)
443
+ value = value.encode('latin1')
444
+ else:
445
+ value = escape(value, 1)
446
+ if sys.version < "3":
447
+ if is_unicode(value):
448
+ value = value.encode('ascii', 'xmlcharrefreplace')
449
+ return value
450
+
451
+
452
+ def url(v):
453
+ v = coerce_text(v)
454
+ if is_unicode(v):
455
+ v = v.encode('utf8')
456
+ return url_quote(v)
457
+
458
+
459
+ def attr(**kw):
460
+ kw = list(kw.iteritems())
461
+ kw.sort()
462
+ parts = []
463
+ for name, value in kw:
464
+ if value is None:
465
+ continue
466
+ if name.endswith('_'):
467
+ name = name[:-1]
468
+ parts.append('%s="%s"' % (html_quote(name), html_quote(value)))
469
+ return html(' '.join(parts))
470
+
471
+
472
+ class HTMLTemplate(Template):
473
+
474
+ default_namespace = Template.default_namespace.copy()
475
+ default_namespace.update(dict(
476
+ html=html,
477
+ attr=attr,
478
+ url=url,
479
+ html_quote=html_quote,
480
+ ))
481
+
482
+ def _repr(self, value, pos):
483
+ if hasattr(value, '__html__'):
484
+ value = value.__html__()
485
+ quote = False
486
+ else:
487
+ quote = True
488
+ plain = Template._repr(self, value, pos)
489
+ if quote:
490
+ return html_quote(plain)
491
+ else:
492
+ return plain
493
+
494
+
495
+ def sub_html(content, **kw):
496
+ name = kw.get('__name')
497
+ tmpl = HTMLTemplate(content, name=name)
498
+ return tmpl.substitute(kw)
499
+
500
+
501
+ class TemplateDef(object):
502
+ def __init__(self, template, func_name, func_signature,
503
+ body, ns, pos, bound_self=None):
504
+ self._template = template
505
+ self._func_name = func_name
506
+ self._func_signature = func_signature
507
+ self._body = body
508
+ self._ns = ns
509
+ self._pos = pos
510
+ self._bound_self = bound_self
511
+
512
+ def __repr__(self):
513
+ return '<tempita function %s(%s) at %s:%s>' % (
514
+ self._func_name, self._func_signature,
515
+ self._template.name, self._pos)
516
+
517
+ def __str__(self):
518
+ return self()
519
+
520
+ def __call__(self, *args, **kw):
521
+ values = self._parse_signature(args, kw)
522
+ ns = self._ns.copy()
523
+ ns.update(values)
524
+ if self._bound_self is not None:
525
+ ns['self'] = self._bound_self
526
+ out = []
527
+ subdefs = {}
528
+ self._template._interpret_codes(self._body, ns, out, subdefs)
529
+ return ''.join(out)
530
+
531
+ def __get__(self, obj, type=None):
532
+ if obj is None:
533
+ return self
534
+ return self.__class__(
535
+ self._template, self._func_name, self._func_signature,
536
+ self._body, self._ns, self._pos, bound_self=obj)
537
+
538
+ def _parse_signature(self, args, kw):
539
+ values = {}
540
+ sig_args, var_args, var_kw, defaults = self._func_signature
541
+ extra_kw = {}
542
+ for name, value in iteritems(kw):
543
+ if not var_kw and name not in sig_args:
544
+ raise TypeError(
545
+ 'Unexpected argument %s' % name)
546
+ if name in sig_args:
547
+ values[sig_args] = value
548
+ else:
549
+ extra_kw[name] = value
550
+ args = list(args)
551
+ sig_args = list(sig_args)
552
+ while args:
553
+ while sig_args and sig_args[0] in values:
554
+ sig_args.pop(0)
555
+ if sig_args:
556
+ name = sig_args.pop(0)
557
+ values[name] = args.pop(0)
558
+ elif var_args:
559
+ values[var_args] = tuple(args)
560
+ break
561
+ else:
562
+ raise TypeError(
563
+ 'Extra position arguments: %s'
564
+ % ', '.join(repr(v) for v in args))
565
+ for name, value_expr in iteritems(defaults):
566
+ if name not in values:
567
+ values[name] = self._template._eval(
568
+ value_expr, self._ns, self._pos)
569
+ for name in sig_args:
570
+ if name not in values:
571
+ raise TypeError(
572
+ 'Missing argument: %s' % name)
573
+ if var_kw:
574
+ values[var_kw] = extra_kw
575
+ return values
576
+
577
+
578
+ class TemplateObject(object):
579
+
580
+ def __init__(self, name):
581
+ self.__name = name
582
+ self.get = TemplateObjectGetter(self)
583
+
584
+ def __repr__(self):
585
+ return '<%s %s>' % (self.__class__.__name__, self.__name)
586
+
587
+
588
+ class TemplateObjectGetter(object):
589
+
590
+ def __init__(self, template_obj):
591
+ self.__template_obj = template_obj
592
+
593
+ def __getattr__(self, attr):
594
+ return getattr(self.__template_obj, attr, Empty)
595
+
596
+ def __repr__(self):
597
+ return '<%s around %r>' % (self.__class__.__name__, self.__template_obj)
598
+
599
+
600
+ class _Empty(object):
601
+ def __call__(self, *args, **kw):
602
+ return self
603
+
604
+ def __str__(self):
605
+ return ''
606
+
607
+ def __repr__(self):
608
+ return 'Empty'
609
+
610
+ def __unicode__(self):
611
+ return u''
612
+
613
+ def __iter__(self):
614
+ return iter(())
615
+
616
+ def __bool__(self):
617
+ return False
618
+
619
+ if sys.version < "3":
620
+ __nonzero__ = __bool__
621
+
622
+ Empty = _Empty()
623
+ del _Empty
624
+
625
+ ############################################################
626
+ ## Lexing and Parsing
627
+ ############################################################
628
+
629
+
630
+ def lex(s, name=None, trim_whitespace=True, line_offset=0):
631
+ """
632
+ Lex a string into chunks:
633
+
634
+ >>> lex('hey')
635
+ ['hey']
636
+ >>> lex('hey {{you}}')
637
+ ['hey ', ('you', (1, 7))]
638
+ >>> lex('hey {{') # doctest: +IGNORE_EXCEPTION_DETAIL
639
+ Traceback (most recent call last):
640
+ ...
641
+ TemplateError: No }} to finish last expression at line 1 column 7
642
+ >>> lex('hey }}') # doctest: +IGNORE_EXCEPTION_DETAIL
643
+ Traceback (most recent call last):
644
+ ...
645
+ TemplateError: }} outside expression at line 1 column 7
646
+ >>> lex('hey {{ {{') # doctest: +IGNORE_EXCEPTION_DETAIL
647
+ Traceback (most recent call last):
648
+ ...
649
+ TemplateError: {{ inside expression at line 1 column 10
650
+
651
+ """
652
+ in_expr = False
653
+ chunks = []
654
+ last = 0
655
+ last_pos = (1, 1)
656
+ for match in token_re.finditer(s):
657
+ expr = match.group(0)
658
+ pos = find_position(s, match.end(), line_offset)
659
+ if expr == '{{' and in_expr:
660
+ raise TemplateError('{{ inside expression', position=pos,
661
+ name=name)
662
+ elif expr == '}}' and not in_expr:
663
+ raise TemplateError('}} outside expression', position=pos,
664
+ name=name)
665
+ if expr == '{{':
666
+ part = s[last:match.start()]
667
+ if part:
668
+ chunks.append(part)
669
+ in_expr = True
670
+ else:
671
+ chunks.append((s[last:match.start()], last_pos))
672
+ in_expr = False
673
+ last = match.end()
674
+ last_pos = pos
675
+ if in_expr:
676
+ raise TemplateError('No }} to finish last expression',
677
+ name=name, position=last_pos)
678
+ part = s[last:]
679
+ if part:
680
+ chunks.append(part)
681
+ if trim_whitespace:
682
+ chunks = trim_lex(chunks)
683
+ return chunks
684
+
685
+ statement_re = re.compile(r'^(?:if |elif |for |def |inherit |default |py:)')
686
+ single_statements = ['else', 'endif', 'endfor', 'enddef', 'continue', 'break']
687
+ trail_whitespace_re = re.compile(r'\n\r?[\t ]*$')
688
+ lead_whitespace_re = re.compile(r'^[\t ]*\n')
689
+
690
+
691
+ def trim_lex(tokens):
692
+ r"""
693
+ Takes a lexed set of tokens, and removes whitespace when there is
694
+ a directive on a line by itself:
695
+
696
+ >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False)
697
+ >>> tokens
698
+ [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny']
699
+ >>> trim_lex(tokens)
700
+ [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y']
701
+ """
702
+ last_trim = None
703
+ for i in range(len(tokens)):
704
+ current = tokens[i]
705
+ if isinstance(tokens[i], basestring_):
706
+ # we don't trim this
707
+ continue
708
+ item = current[0]
709
+ if not statement_re.search(item) and item not in single_statements:
710
+ continue
711
+ if not i:
712
+ prev = ''
713
+ else:
714
+ prev = tokens[i - 1]
715
+ if i + 1 >= len(tokens):
716
+ next_chunk = ''
717
+ else:
718
+ next_chunk = tokens[i + 1]
719
+ if (not isinstance(next_chunk, basestring_)
720
+ or not isinstance(prev, basestring_)):
721
+ continue
722
+ prev_ok = not prev or trail_whitespace_re.search(prev)
723
+ if i == 1 and not prev.strip():
724
+ prev_ok = True
725
+ if last_trim is not None and last_trim + 2 == i and not prev.strip():
726
+ prev_ok = 'last'
727
+ if (prev_ok
728
+ and (not next_chunk or lead_whitespace_re.search(next_chunk)
729
+ or (i == len(tokens) - 2 and not next_chunk.strip()))):
730
+ if prev:
731
+ if ((i == 1 and not prev.strip())
732
+ or prev_ok == 'last'):
733
+ tokens[i - 1] = ''
734
+ else:
735
+ m = trail_whitespace_re.search(prev)
736
+ # +1 to leave the leading \n on:
737
+ prev = prev[:m.start() + 1]
738
+ tokens[i - 1] = prev
739
+ if next_chunk:
740
+ last_trim = i
741
+ if i == len(tokens) - 2 and not next_chunk.strip():
742
+ tokens[i + 1] = ''
743
+ else:
744
+ m = lead_whitespace_re.search(next_chunk)
745
+ next_chunk = next_chunk[m.end():]
746
+ tokens[i + 1] = next_chunk
747
+ return tokens
748
+
749
+
750
+ def find_position(string, index, line_offset):
751
+ """Given a string and index, return (line, column)"""
752
+ leading = string[:index].splitlines()
753
+ return (len(leading) + line_offset, len(leading[-1]) + 1)
754
+
755
+
756
+ def parse(s, name=None, line_offset=0):
757
+ r"""
758
+ Parses a string into a kind of AST
759
+
760
+ >>> parse('{{x}}')
761
+ [('expr', (1, 3), 'x')]
762
+ >>> parse('foo')
763
+ ['foo']
764
+ >>> parse('{{if x}}test{{endif}}')
765
+ [('cond', (1, 3), ('if', (1, 3), 'x', ['test']))]
766
+ >>> parse('series->{{for x in y}}x={{x}}{{endfor}}')
767
+ ['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])]
768
+ >>> parse('{{for x, y in z:}}{{continue}}{{endfor}}')
769
+ [('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])]
770
+ >>> parse('{{py:x=1}}')
771
+ [('py', (1, 3), 'x=1')]
772
+ >>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}')
773
+ [('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))]
774
+
775
+ Some exceptions::
776
+
777
+ >>> parse('{{continue}}') # doctest: +IGNORE_EXCEPTION_DETAIL
778
+ Traceback (most recent call last):
779
+ ...
780
+ TemplateError: continue outside of for loop at line 1 column 3
781
+ >>> parse('{{if x}}foo') # doctest: +IGNORE_EXCEPTION_DETAIL
782
+ Traceback (most recent call last):
783
+ ...
784
+ TemplateError: No {{endif}} at line 1 column 3
785
+ >>> parse('{{else}}') # doctest: +IGNORE_EXCEPTION_DETAIL
786
+ Traceback (most recent call last):
787
+ ...
788
+ TemplateError: else outside of an if block at line 1 column 3
789
+ >>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}') # doctest: +IGNORE_EXCEPTION_DETAIL
790
+ Traceback (most recent call last):
791
+ ...
792
+ TemplateError: Unexpected endif at line 1 column 25
793
+ >>> parse('{{if}}{{endif}}') # doctest: +IGNORE_EXCEPTION_DETAIL
794
+ Traceback (most recent call last):
795
+ ...
796
+ TemplateError: if with no expression at line 1 column 3
797
+ >>> parse('{{for x y}}{{endfor}}') # doctest: +IGNORE_EXCEPTION_DETAIL
798
+ Traceback (most recent call last):
799
+ ...
800
+ TemplateError: Bad for (no "in") in 'x y' at line 1 column 3
801
+ >>> parse('{{py:x=1\ny=2}}') # doctest: +IGNORE_EXCEPTION_DETAIL
802
+ Traceback (most recent call last):
803
+ ...
804
+ TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
805
+ """
806
+ tokens = lex(s, name=name, line_offset=line_offset)
807
+ result = []
808
+ while tokens:
809
+ next_chunk, tokens = parse_expr(tokens, name)
810
+ result.append(next_chunk)
811
+ return result
812
+
813
+
814
+ def parse_expr(tokens, name, context=()):
815
+ if isinstance(tokens[0], basestring_):
816
+ return tokens[0], tokens[1:]
817
+ expr, pos = tokens[0]
818
+ expr = expr.strip()
819
+ if expr.startswith('py:'):
820
+ expr = expr[3:].lstrip(' \t')
821
+ if expr.startswith('\n') or expr.startswith('\r'):
822
+ expr = expr.lstrip('\r\n')
823
+ if '\r' in expr:
824
+ expr = expr.replace('\r\n', '\n')
825
+ expr = expr.replace('\r', '')
826
+ expr += '\n'
827
+ else:
828
+ if '\n' in expr:
829
+ raise TemplateError(
830
+ 'Multi-line py blocks must start with a newline',
831
+ position=pos, name=name)
832
+ return ('py', pos, expr), tokens[1:]
833
+ elif expr in ('continue', 'break'):
834
+ if 'for' not in context:
835
+ raise TemplateError(
836
+ 'continue outside of for loop',
837
+ position=pos, name=name)
838
+ return (expr, pos), tokens[1:]
839
+ elif expr.startswith('if '):
840
+ return parse_cond(tokens, name, context)
841
+ elif (expr.startswith('elif ')
842
+ or expr == 'else'):
843
+ raise TemplateError(
844
+ '%s outside of an if block' % expr.split()[0],
845
+ position=pos, name=name)
846
+ elif expr in ('if', 'elif', 'for'):
847
+ raise TemplateError(
848
+ '%s with no expression' % expr,
849
+ position=pos, name=name)
850
+ elif expr in ('endif', 'endfor', 'enddef'):
851
+ raise TemplateError(
852
+ 'Unexpected %s' % expr,
853
+ position=pos, name=name)
854
+ elif expr.startswith('for '):
855
+ return parse_for(tokens, name, context)
856
+ elif expr.startswith('default '):
857
+ return parse_default(tokens, name, context)
858
+ elif expr.startswith('inherit '):
859
+ return parse_inherit(tokens, name, context)
860
+ elif expr.startswith('def '):
861
+ return parse_def(tokens, name, context)
862
+ elif expr.startswith('#'):
863
+ return ('comment', pos, tokens[0][0]), tokens[1:]
864
+ return ('expr', pos, tokens[0][0]), tokens[1:]
865
+
866
+
867
+ def parse_cond(tokens, name, context):
868
+ start = tokens[0][1]
869
+ pieces = []
870
+ context = context + ('if',)
871
+ while 1:
872
+ if not tokens:
873
+ raise TemplateError(
874
+ 'Missing {{endif}}',
875
+ position=start, name=name)
876
+ if (isinstance(tokens[0], tuple)
877
+ and tokens[0][0] == 'endif'):
878
+ return ('cond', start) + tuple(pieces), tokens[1:]
879
+ next_chunk, tokens = parse_one_cond(tokens, name, context)
880
+ pieces.append(next_chunk)
881
+
882
+
883
+ def parse_one_cond(tokens, name, context):
884
+ (first, pos), tokens = tokens[0], tokens[1:]
885
+ content = []
886
+ if first.endswith(':'):
887
+ first = first[:-1]
888
+ if first.startswith('if '):
889
+ part = ('if', pos, first[3:].lstrip(), content)
890
+ elif first.startswith('elif '):
891
+ part = ('elif', pos, first[5:].lstrip(), content)
892
+ elif first == 'else':
893
+ part = ('else', pos, None, content)
894
+ else:
895
+ assert 0, "Unexpected token %r at %s" % (first, pos)
896
+ while 1:
897
+ if not tokens:
898
+ raise TemplateError(
899
+ 'No {{endif}}',
900
+ position=pos, name=name)
901
+ if (isinstance(tokens[0], tuple)
902
+ and (tokens[0][0] == 'endif'
903
+ or tokens[0][0].startswith('elif ')
904
+ or tokens[0][0] == 'else')):
905
+ return part, tokens
906
+ next_chunk, tokens = parse_expr(tokens, name, context)
907
+ content.append(next_chunk)
908
+
909
+
910
+ def parse_for(tokens, name, context):
911
+ first, pos = tokens[0]
912
+ tokens = tokens[1:]
913
+ context = ('for',) + context
914
+ content = []
915
+ assert first.startswith('for ')
916
+ if first.endswith(':'):
917
+ first = first[:-1]
918
+ first = first[3:].strip()
919
+ match = in_re.search(first)
920
+ if not match:
921
+ raise TemplateError(
922
+ 'Bad for (no "in") in %r' % first,
923
+ position=pos, name=name)
924
+ vars = first[:match.start()]
925
+ if '(' in vars:
926
+ raise TemplateError(
927
+ 'You cannot have () in the variable section of a for loop (%r)'
928
+ % vars, position=pos, name=name)
929
+ vars = tuple([
930
+ v.strip() for v in first[:match.start()].split(',')
931
+ if v.strip()])
932
+ expr = first[match.end():]
933
+ while 1:
934
+ if not tokens:
935
+ raise TemplateError(
936
+ 'No {{endfor}}',
937
+ position=pos, name=name)
938
+ if (isinstance(tokens[0], tuple)
939
+ and tokens[0][0] == 'endfor'):
940
+ return ('for', pos, vars, expr, content), tokens[1:]
941
+ next_chunk, tokens = parse_expr(tokens, name, context)
942
+ content.append(next_chunk)
943
+
944
+
945
+ def parse_default(tokens, name, context):
946
+ first, pos = tokens[0]
947
+ assert first.startswith('default ')
948
+ first = first.split(None, 1)[1]
949
+ parts = first.split('=', 1)
950
+ if len(parts) == 1:
951
+ raise TemplateError(
952
+ "Expression must be {{default var=value}}; no = found in %r" % first,
953
+ position=pos, name=name)
954
+ var = parts[0].strip()
955
+ if ',' in var:
956
+ raise TemplateError(
957
+ "{{default x, y = ...}} is not supported",
958
+ position=pos, name=name)
959
+ if not var_re.search(var):
960
+ raise TemplateError(
961
+ "Not a valid variable name for {{default}}: %r"
962
+ % var, position=pos, name=name)
963
+ expr = parts[1].strip()
964
+ return ('default', pos, var, expr), tokens[1:]
965
+
966
+
967
+ def parse_inherit(tokens, name, context):
968
+ first, pos = tokens[0]
969
+ assert first.startswith('inherit ')
970
+ expr = first.split(None, 1)[1]
971
+ return ('inherit', pos, expr), tokens[1:]
972
+
973
+
974
+ def parse_def(tokens, name, context):
975
+ first, start = tokens[0]
976
+ tokens = tokens[1:]
977
+ assert first.startswith('def ')
978
+ first = first.split(None, 1)[1]
979
+ if first.endswith(':'):
980
+ first = first[:-1]
981
+ if '(' not in first:
982
+ func_name = first
983
+ sig = ((), None, None, {})
984
+ elif not first.endswith(')'):
985
+ raise TemplateError("Function definition doesn't end with ): %s" % first,
986
+ position=start, name=name)
987
+ else:
988
+ first = first[:-1]
989
+ func_name, sig_text = first.split('(', 1)
990
+ sig = parse_signature(sig_text, name, start)
991
+ context = context + ('def',)
992
+ content = []
993
+ while 1:
994
+ if not tokens:
995
+ raise TemplateError(
996
+ 'Missing {{enddef}}',
997
+ position=start, name=name)
998
+ if (isinstance(tokens[0], tuple)
999
+ and tokens[0][0] == 'enddef'):
1000
+ return ('def', start, func_name, sig, content), tokens[1:]
1001
+ next_chunk, tokens = parse_expr(tokens, name, context)
1002
+ content.append(next_chunk)
1003
+
1004
+
1005
+ def parse_signature(sig_text, name, pos):
1006
+ if PY2 and isinstance(sig_text, str):
1007
+ lines = BytesIO(sig_text).readline
1008
+ else:
1009
+ lines = StringIO(sig_text).readline
1010
+
1011
+ tokens = tokenize.generate_tokens(lines)
1012
+ sig_args = []
1013
+ var_arg = None
1014
+ var_kw = None
1015
+ defaults = {}
1016
+
1017
+ def get_token(pos=False):
1018
+ try:
1019
+ tok_type, tok_string, (srow, scol), (erow, ecol), line = next(tokens)
1020
+ except StopIteration:
1021
+ return tokenize.ENDMARKER, ''
1022
+ if pos:
1023
+ return tok_type, tok_string, (srow, scol), (erow, ecol)
1024
+ else:
1025
+ return tok_type, tok_string
1026
+ while 1:
1027
+ var_arg_type = None
1028
+ tok_type, tok_string = get_token()
1029
+ if tok_type == tokenize.ENDMARKER:
1030
+ break
1031
+ if tok_type == tokenize.OP and (tok_string == '*' or tok_string == '**'):
1032
+ var_arg_type = tok_string
1033
+ tok_type, tok_string = get_token()
1034
+ if tok_type != tokenize.NAME:
1035
+ raise TemplateError('Invalid signature: (%s)' % sig_text,
1036
+ position=pos, name=name)
1037
+ var_name = tok_string
1038
+ tok_type, tok_string = get_token()
1039
+ if tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','):
1040
+ if var_arg_type == '*':
1041
+ var_arg = var_name
1042
+ elif var_arg_type == '**':
1043
+ var_kw = var_name
1044
+ else:
1045
+ sig_args.append(var_name)
1046
+ if tok_type == tokenize.ENDMARKER:
1047
+ break
1048
+ continue
1049
+ if var_arg_type is not None:
1050
+ raise TemplateError('Invalid signature: (%s)' % sig_text,
1051
+ position=pos, name=name)
1052
+ if tok_type == tokenize.OP and tok_string == '=':
1053
+ nest_type = None
1054
+ unnest_type = None
1055
+ nest_count = 0
1056
+ start_pos = end_pos = None
1057
+ parts = []
1058
+ while 1:
1059
+ tok_type, tok_string, s, e = get_token(True)
1060
+ if start_pos is None:
1061
+ start_pos = s
1062
+ end_pos = e
1063
+ if tok_type == tokenize.ENDMARKER and nest_count:
1064
+ raise TemplateError('Invalid signature: (%s)' % sig_text,
1065
+ position=pos, name=name)
1066
+ if (not nest_count and
1067
+ (tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','))):
1068
+ default_expr = isolate_expression(sig_text, start_pos, end_pos)
1069
+ defaults[var_name] = default_expr
1070
+ sig_args.append(var_name)
1071
+ break
1072
+ parts.append((tok_type, tok_string))
1073
+ if nest_count and tok_type == tokenize.OP and tok_string == nest_type:
1074
+ nest_count += 1
1075
+ elif nest_count and tok_type == tokenize.OP and tok_string == unnest_type:
1076
+ nest_count -= 1
1077
+ if not nest_count:
1078
+ nest_type = unnest_type = None
1079
+ elif not nest_count and tok_type == tokenize.OP and tok_string in ('(', '[', '{'):
1080
+ nest_type = tok_string
1081
+ nest_count = 1
1082
+ unnest_type = {'(': ')', '[': ']', '{': '}'}[nest_type]
1083
+ return sig_args, var_arg, var_kw, defaults
1084
+
1085
+
1086
+ def isolate_expression(string, start_pos, end_pos):
1087
+ srow, scol = start_pos
1088
+ srow -= 1
1089
+ erow, ecol = end_pos
1090
+ erow -= 1
1091
+ lines = string.splitlines(True)
1092
+ if srow == erow:
1093
+ return lines[srow][scol:ecol]
1094
+ parts = [lines[srow][scol:]]
1095
+ parts.extend(lines[srow+1:erow])
1096
+ if erow < len(lines):
1097
+ # It'll sometimes give (end_row_past_finish, 0)
1098
+ parts.append(lines[erow][:ecol])
1099
+ return ''.join(parts)
1100
+
1101
+ _fill_command_usage = """\
1102
+ %prog [OPTIONS] TEMPLATE arg=value
1103
+
1104
+ Use py:arg=value to set a Python value; otherwise all values are
1105
+ strings.
1106
+ """
1107
+
1108
+
1109
+ def fill_command(args=None):
1110
+ import sys
1111
+ import optparse
1112
+ import pkg_resources
1113
+ import os
1114
+ if args is None:
1115
+ args = sys.argv[1:]
1116
+ dist = pkg_resources.get_distribution('Paste')
1117
+ parser = optparse.OptionParser(
1118
+ version=coerce_text(dist),
1119
+ usage=_fill_command_usage)
1120
+ parser.add_option(
1121
+ '-o', '--output',
1122
+ dest='output',
1123
+ metavar="FILENAME",
1124
+ help="File to write output to (default stdout)")
1125
+ parser.add_option(
1126
+ '--html',
1127
+ dest='use_html',
1128
+ action='store_true',
1129
+ help="Use HTML style filling (including automatic HTML quoting)")
1130
+ parser.add_option(
1131
+ '--env',
1132
+ dest='use_env',
1133
+ action='store_true',
1134
+ help="Put the environment in as top-level variables")
1135
+ options, args = parser.parse_args(args)
1136
+ if len(args) < 1:
1137
+ print('You must give a template filename')
1138
+ sys.exit(2)
1139
+ template_name = args[0]
1140
+ args = args[1:]
1141
+ vars = {}
1142
+ if options.use_env:
1143
+ vars.update(os.environ)
1144
+ for value in args:
1145
+ if '=' not in value:
1146
+ print(('Bad argument: %r' % value))
1147
+ sys.exit(2)
1148
+ name, value = value.split('=', 1)
1149
+ if name.startswith('py:'):
1150
+ name = name[:3]
1151
+ value = eval(value)
1152
+ vars[name] = value
1153
+ if template_name == '-':
1154
+ template_content = sys.stdin.read()
1155
+ template_name = '<stdin>'
1156
+ else:
1157
+ f = open(template_name, 'rb')
1158
+ template_content = f.read()
1159
+ f.close()
1160
+ if options.use_html:
1161
+ TemplateClass = HTMLTemplate
1162
+ else:
1163
+ TemplateClass = Template
1164
+ template = TemplateClass(template_content, name=template_name)
1165
+ result = template.substitute(vars)
1166
+ if options.output:
1167
+ f = open(options.output, 'wb')
1168
+ f.write(result)
1169
+ f.close()
1170
+ else:
1171
+ sys.stdout.write(result)
1172
+
1173
+ if __name__ == '__main__':
1174
+ fill_command()