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.
- mapproxy/__init__.py +0 -0
- mapproxy/cache/__init__.py +36 -0
- mapproxy/cache/azureblob.py +145 -0
- mapproxy/cache/base.py +111 -0
- mapproxy/cache/compact.py +664 -0
- mapproxy/cache/couchdb.py +295 -0
- mapproxy/cache/dummy.py +34 -0
- mapproxy/cache/file.py +185 -0
- mapproxy/cache/geopackage.py +609 -0
- mapproxy/cache/legend.py +83 -0
- mapproxy/cache/mbtiles.py +392 -0
- mapproxy/cache/meta.py +78 -0
- mapproxy/cache/path.py +250 -0
- mapproxy/cache/redis.py +88 -0
- mapproxy/cache/renderd.py +95 -0
- mapproxy/cache/riak.py +202 -0
- mapproxy/cache/s3.py +177 -0
- mapproxy/cache/tile.py +699 -0
- mapproxy/client/__init__.py +0 -0
- mapproxy/client/arcgis.py +79 -0
- mapproxy/client/cgi.py +139 -0
- mapproxy/client/http.py +315 -0
- mapproxy/client/log.py +33 -0
- mapproxy/client/tile.py +150 -0
- mapproxy/client/wms.py +254 -0
- mapproxy/compat/__init__.py +46 -0
- mapproxy/compat/image.py +79 -0
- mapproxy/compat/itertools.py +29 -0
- mapproxy/compat/modules.py +13 -0
- mapproxy/config/__init__.py +22 -0
- mapproxy/config/config.py +201 -0
- mapproxy/config/coverage.py +107 -0
- mapproxy/config/defaults.py +98 -0
- mapproxy/config/loader.py +2286 -0
- mapproxy/config/spec.py +644 -0
- mapproxy/config/validator.py +239 -0
- mapproxy/config_template/__init__.py +0 -0
- mapproxy/config_template/base_config/config.wsgi +10 -0
- mapproxy/config_template/base_config/full_example.yaml +593 -0
- mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
- mapproxy/config_template/base_config/log.ini +35 -0
- mapproxy/config_template/base_config/mapproxy.yaml +60 -0
- mapproxy/config_template/base_config/seed.yaml +27 -0
- mapproxy/exception.py +142 -0
- mapproxy/featureinfo.py +252 -0
- mapproxy/grid.py +1170 -0
- mapproxy/image/__init__.py +536 -0
- mapproxy/image/fonts/DejaVuSans.ttf +0 -0
- mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
- mapproxy/image/fonts/LICENSE +99 -0
- mapproxy/image/fonts/__init__.py +0 -0
- mapproxy/image/mask.py +75 -0
- mapproxy/image/merge.py +316 -0
- mapproxy/image/message.py +347 -0
- mapproxy/image/opts.py +182 -0
- mapproxy/image/tile.py +167 -0
- mapproxy/image/transform.py +350 -0
- mapproxy/layer.py +470 -0
- mapproxy/multiapp.py +231 -0
- mapproxy/proj.py +302 -0
- mapproxy/request/__init__.py +18 -0
- mapproxy/request/arcgis.py +259 -0
- mapproxy/request/base.py +476 -0
- mapproxy/request/tile.py +128 -0
- mapproxy/request/wms/__init__.py +793 -0
- mapproxy/request/wms/exception.py +99 -0
- mapproxy/request/wmts.py +436 -0
- mapproxy/response.py +237 -0
- mapproxy/script/__init__.py +0 -0
- mapproxy/script/conf/__init__.py +0 -0
- mapproxy/script/conf/app.py +195 -0
- mapproxy/script/conf/caches.py +45 -0
- mapproxy/script/conf/layers.py +54 -0
- mapproxy/script/conf/seeds.py +37 -0
- mapproxy/script/conf/sources.py +86 -0
- mapproxy/script/conf/utils.py +143 -0
- mapproxy/script/defrag.py +184 -0
- mapproxy/script/export.py +333 -0
- mapproxy/script/grids.py +188 -0
- mapproxy/script/scales.py +126 -0
- mapproxy/script/util.py +406 -0
- mapproxy/script/wms_capabilities.py +152 -0
- mapproxy/seed/__init__.py +0 -0
- mapproxy/seed/cachelock.py +121 -0
- mapproxy/seed/cleanup.py +187 -0
- mapproxy/seed/config.py +469 -0
- mapproxy/seed/script.py +388 -0
- mapproxy/seed/seeder.py +538 -0
- mapproxy/seed/spec.py +64 -0
- mapproxy/seed/util.py +254 -0
- mapproxy/service/__init__.py +14 -0
- mapproxy/service/base.py +46 -0
- mapproxy/service/demo.py +356 -0
- mapproxy/service/kml.py +331 -0
- mapproxy/service/ows.py +38 -0
- mapproxy/service/template_helper.py +53 -0
- mapproxy/service/templates/demo/capabilities_demo.html +16 -0
- mapproxy/service/templates/demo/demo.html +181 -0
- mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
- mapproxy/service/templates/demo/static/img/blank.gif +0 -0
- mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
- mapproxy/service/templates/demo/static/logo.png +0 -0
- mapproxy/service/templates/demo/static/ol.css +345 -0
- mapproxy/service/templates/demo/static/ol.js +4 -0
- mapproxy/service/templates/demo/static/proj4.min.js +1 -0
- mapproxy/service/templates/demo/static/proj4defs.js +1 -0
- mapproxy/service/templates/demo/static/site.css +137 -0
- mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
- mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
- mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
- mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
- mapproxy/service/templates/demo/static.html +34 -0
- mapproxy/service/templates/demo/tms_demo.html +103 -0
- mapproxy/service/templates/demo/wms_demo.html +140 -0
- mapproxy/service/templates/demo/wmts_demo.html +110 -0
- mapproxy/service/templates/tms_capabilities.xml +13 -0
- mapproxy/service/templates/tms_exception.xml +4 -0
- mapproxy/service/templates/tms_root_resource.xml +7 -0
- mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
- mapproxy/service/templates/wms100capabilities.xml +112 -0
- mapproxy/service/templates/wms100exception.xml +4 -0
- mapproxy/service/templates/wms110capabilities.xml +152 -0
- mapproxy/service/templates/wms110exception.xml +5 -0
- mapproxy/service/templates/wms111capabilities.xml +183 -0
- mapproxy/service/templates/wms111exception.xml +5 -0
- mapproxy/service/templates/wms130capabilities.xml +326 -0
- mapproxy/service/templates/wms130exception.xml +8 -0
- mapproxy/service/templates/wmts100capabilities.xml +155 -0
- mapproxy/service/templates/wmts100exception.xml +9 -0
- mapproxy/service/tile.py +536 -0
- mapproxy/service/wms.py +851 -0
- mapproxy/service/wmts.py +381 -0
- mapproxy/source/__init__.py +75 -0
- mapproxy/source/arcgis.py +39 -0
- mapproxy/source/error.py +39 -0
- mapproxy/source/mapnik.py +259 -0
- mapproxy/source/tile.py +96 -0
- mapproxy/source/wms.py +270 -0
- mapproxy/srs.py +726 -0
- mapproxy/template.py +54 -0
- mapproxy/test/__init__.py +0 -0
- mapproxy/test/conftest.py +7 -0
- mapproxy/test/helper.py +247 -0
- mapproxy/test/http.py +494 -0
- mapproxy/test/image.py +210 -0
- mapproxy/test/mocker.py +2268 -0
- mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
- mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
- mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
- mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
- mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
- mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
- mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
- mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
- mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
- mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
- mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
- mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
- mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
- mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
- mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
- mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
- mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
- mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
- mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
- mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
- mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
- mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
- mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
- mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
- mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
- mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
- mapproxy/test/schemas/xml.xsd +287 -0
- mapproxy/test/system/__init__.py +98 -0
- mapproxy/test/system/fixture/arcgis.yaml +57 -0
- mapproxy/test/system/fixture/auth.yaml +70 -0
- mapproxy/test/system/fixture/cache.mbtiles +0 -0
- mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
- mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
- mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
- mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
- mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
- mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
- mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
- mapproxy/test/system/fixture/cache_s3.yaml +58 -0
- mapproxy/test/system/fixture/cache_source.yaml +81 -0
- mapproxy/test/system/fixture/combined_sources.yaml +130 -0
- mapproxy/test/system/fixture/coverage.yaml +77 -0
- mapproxy/test/system/fixture/demo.yaml +135 -0
- mapproxy/test/system/fixture/dimension.yaml +59 -0
- mapproxy/test/system/fixture/disable_storage.yaml +25 -0
- mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
- mapproxy/test/system/fixture/formats.yaml +72 -0
- mapproxy/test/system/fixture/inspire.yaml +101 -0
- mapproxy/test/system/fixture/inspire_full.yaml +124 -0
- mapproxy/test/system/fixture/kml_layer.yaml +66 -0
- mapproxy/test/system/fixture/layer.yaml +260 -0
- mapproxy/test/system/fixture/layergroups.yaml +57 -0
- mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
- mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
- mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
- mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
- mapproxy/test/system/fixture/mapserver.yaml +23 -0
- mapproxy/test/system/fixture/minimal_cgi.py +16 -0
- mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
- mapproxy/test/system/fixture/multi_cache_layers.yaml +100 -0
- mapproxy/test/system/fixture/multiapp1.yaml +20 -0
- mapproxy/test/system/fixture/multiapp2.yaml +19 -0
- mapproxy/test/system/fixture/renderd_client.yaml +55 -0
- mapproxy/test/system/fixture/scalehints.yaml +70 -0
- mapproxy/test/system/fixture/seed.yaml +94 -0
- mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
- mapproxy/test/system/fixture/seed_old.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
- mapproxy/test/system/fixture/seedonly.yaml +51 -0
- mapproxy/test/system/fixture/sld.yaml +35 -0
- mapproxy/test/system/fixture/source_errors.yaml +84 -0
- mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
- mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
- mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
- mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
- mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
- mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
- mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
- mapproxy/test/system/fixture/util_grids.yaml +30 -0
- mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
- mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
- mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
- mapproxy/test/system/fixture/watermark.yaml +50 -0
- mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
- mapproxy/test/system/fixture/wms_versions.yaml +38 -0
- mapproxy/test/system/fixture/wmts.yaml +134 -0
- mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
- mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
- mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
- mapproxy/test/system/test_arcgis.py +156 -0
- mapproxy/test/system/test_auth.py +1134 -0
- mapproxy/test/system/test_behind_proxy.py +75 -0
- mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
- mapproxy/test/system/test_cache_azureblob.py +127 -0
- mapproxy/test/system/test_cache_band_merge.py +103 -0
- mapproxy/test/system/test_cache_geopackage.py +144 -0
- mapproxy/test/system/test_cache_grid_names.py +89 -0
- mapproxy/test/system/test_cache_mbtiles.py +85 -0
- mapproxy/test/system/test_cache_s3.py +115 -0
- mapproxy/test/system/test_cache_source.py +146 -0
- mapproxy/test/system/test_combined_sources.py +335 -0
- mapproxy/test/system/test_coverage.py +140 -0
- mapproxy/test/system/test_decorate_img.py +214 -0
- mapproxy/test/system/test_demo.py +106 -0
- mapproxy/test/system/test_demo_with_extra_service.py +53 -0
- mapproxy/test/system/test_dimensions.py +278 -0
- mapproxy/test/system/test_disable_storage.py +42 -0
- mapproxy/test/system/test_formats.py +219 -0
- mapproxy/test/system/test_inspire_vs.py +173 -0
- mapproxy/test/system/test_kml.py +262 -0
- mapproxy/test/system/test_layergroups.py +160 -0
- mapproxy/test/system/test_legendgraphic.py +308 -0
- mapproxy/test/system/test_mapnik.py +161 -0
- mapproxy/test/system/test_mapserver.py +81 -0
- mapproxy/test/system/test_mixed_mode_format.py +195 -0
- mapproxy/test/system/test_multi_cache_layers.py +167 -0
- mapproxy/test/system/test_multiapp.py +92 -0
- mapproxy/test/system/test_refresh.py +207 -0
- mapproxy/test/system/test_renderd_client.py +304 -0
- mapproxy/test/system/test_response_headers.py +54 -0
- mapproxy/test/system/test_scalehints.py +140 -0
- mapproxy/test/system/test_seed.py +422 -0
- mapproxy/test/system/test_seed_only.py +93 -0
- mapproxy/test/system/test_sld.py +120 -0
- mapproxy/test/system/test_source_errors.py +377 -0
- mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
- mapproxy/test/system/test_tms.py +276 -0
- mapproxy/test/system/test_tms_origin.py +46 -0
- mapproxy/test/system/test_util_conf.py +304 -0
- mapproxy/test/system/test_util_export.py +210 -0
- mapproxy/test/system/test_util_grids.py +88 -0
- mapproxy/test/system/test_util_wms_capabilities.py +182 -0
- mapproxy/test/system/test_watermark.py +91 -0
- mapproxy/test/system/test_wms.py +1611 -0
- mapproxy/test/system/test_wms_srs_extent.py +165 -0
- mapproxy/test/system/test_wms_version.py +85 -0
- mapproxy/test/system/test_wmsc.py +116 -0
- mapproxy/test/system/test_wmts.py +334 -0
- mapproxy/test/system/test_wmts_dimensions.py +206 -0
- mapproxy/test/system/test_wmts_restful.py +198 -0
- mapproxy/test/system/test_xslt_featureinfo.py +425 -0
- mapproxy/test/test_http_helper.py +219 -0
- mapproxy/test/unit/__init__.py +0 -0
- mapproxy/test/unit/epsg +2 -0
- mapproxy/test/unit/polygons/polygons.dbf +0 -0
- mapproxy/test/unit/polygons/polygons.shp +0 -0
- mapproxy/test/unit/polygons/polygons.shx +0 -0
- mapproxy/test/unit/test_async.py +245 -0
- mapproxy/test/unit/test_auth.py +419 -0
- mapproxy/test/unit/test_cache.py +1193 -0
- mapproxy/test/unit/test_cache_azureblob.py +94 -0
- mapproxy/test/unit/test_cache_compact.py +319 -0
- mapproxy/test/unit/test_cache_couchdb.py +114 -0
- mapproxy/test/unit/test_cache_geopackage.py +221 -0
- mapproxy/test/unit/test_cache_redis.py +67 -0
- mapproxy/test/unit/test_cache_riak.py +76 -0
- mapproxy/test/unit/test_cache_s3.py +84 -0
- mapproxy/test/unit/test_cache_tile.py +427 -0
- mapproxy/test/unit/test_client.py +479 -0
- mapproxy/test/unit/test_client_arcgis.py +73 -0
- mapproxy/test/unit/test_client_cgi.py +136 -0
- mapproxy/test/unit/test_collections.py +116 -0
- mapproxy/test/unit/test_concat_legends.py +37 -0
- mapproxy/test/unit/test_conf_loader.py +1061 -0
- mapproxy/test/unit/test_conf_validator.py +416 -0
- mapproxy/test/unit/test_config.py +117 -0
- mapproxy/test/unit/test_decorate_img.py +185 -0
- mapproxy/test/unit/test_exceptions.py +258 -0
- mapproxy/test/unit/test_featureinfo.py +291 -0
- mapproxy/test/unit/test_file_lock_load.py +49 -0
- mapproxy/test/unit/test_geom.py +503 -0
- mapproxy/test/unit/test_grid.py +1258 -0
- mapproxy/test/unit/test_image.py +1053 -0
- mapproxy/test/unit/test_image_mask.py +181 -0
- mapproxy/test/unit/test_image_messages.py +197 -0
- mapproxy/test/unit/test_image_options.py +160 -0
- mapproxy/test/unit/test_isodate.py +122 -0
- mapproxy/test/unit/test_multiapp.py +163 -0
- mapproxy/test/unit/test_ogr_reader.py +50 -0
- mapproxy/test/unit/test_request.py +745 -0
- mapproxy/test/unit/test_request_wmts.py +178 -0
- mapproxy/test/unit/test_response.py +79 -0
- mapproxy/test/unit/test_seed.py +365 -0
- mapproxy/test/unit/test_seed_cachelock.py +90 -0
- mapproxy/test/unit/test_srs.py +215 -0
- mapproxy/test/unit/test_tiled_source.py +122 -0
- mapproxy/test/unit/test_tilefilter.py +31 -0
- mapproxy/test/unit/test_times.py +25 -0
- mapproxy/test/unit/test_timeutils.py +50 -0
- mapproxy/test/unit/test_util_conf_utils.py +75 -0
- mapproxy/test/unit/test_utils.py +476 -0
- mapproxy/test/unit/test_wms_capabilities.py +44 -0
- mapproxy/test/unit/test_wms_layer.py +113 -0
- mapproxy/test/unit/test_yaml.py +69 -0
- mapproxy/tilefilter.py +59 -0
- mapproxy/util/__init__.py +0 -0
- mapproxy/util/async_.py +227 -0
- mapproxy/util/collections.py +132 -0
- mapproxy/util/coverage.py +329 -0
- mapproxy/util/escape.py +10 -0
- mapproxy/util/ext/__init__.py +14 -0
- mapproxy/util/ext/dictspec/__init__.py +1 -0
- mapproxy/util/ext/dictspec/spec.py +124 -0
- mapproxy/util/ext/dictspec/test/__init__.py +0 -0
- mapproxy/util/ext/dictspec/test/test_validator.py +274 -0
- mapproxy/util/ext/dictspec/validator.py +189 -0
- mapproxy/util/ext/local.py +196 -0
- mapproxy/util/ext/lockfile.py +138 -0
- mapproxy/util/ext/odict.py +330 -0
- mapproxy/util/ext/serving.py +508 -0
- mapproxy/util/ext/tempita/__init__.py +1174 -0
- mapproxy/util/ext/tempita/_looper.py +163 -0
- mapproxy/util/ext/tempita/compat3.py +46 -0
- mapproxy/util/ext/wmsparse/__init__.py +3 -0
- mapproxy/util/ext/wmsparse/duration.py +597 -0
- mapproxy/util/ext/wmsparse/parse.py +305 -0
- mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
- mapproxy/util/ext/wmsparse/test/test_parse.py +162 -0
- mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
- mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
- mapproxy/util/ext/wmsparse/test/wms-omniscale-111.xml +90 -0
- mapproxy/util/ext/wmsparse/test/wms-omniscale-130.xml +120 -0
- mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
- mapproxy/util/ext/wmsparse/util.py +187 -0
- mapproxy/util/fs.py +156 -0
- mapproxy/util/geom.py +295 -0
- mapproxy/util/lib.py +115 -0
- mapproxy/util/lock.py +163 -0
- mapproxy/util/ogr.py +231 -0
- mapproxy/util/py.py +81 -0
- mapproxy/util/times.py +75 -0
- mapproxy/util/yaml.py +56 -0
- mapproxy/version.py +31 -0
- mapproxy/wsgiapp.py +164 -0
- mapproxy-1.16.1.dist-info/METADATA +151 -0
- mapproxy-1.16.1.dist-info/RECORD +458 -0
- mapproxy-1.16.1.dist-info/WHEEL +5 -0
- mapproxy-1.16.1.dist-info/entry_points.txt +3 -0
- mapproxy-1.16.1.dist-info/licenses/AUTHORS.txt +33 -0
- mapproxy-1.16.1.dist-info/licenses/COPYING.txt +60 -0
- mapproxy-1.16.1.dist-info/licenses/LICENSE.txt +202 -0
- mapproxy-1.16.1.dist-info/top_level.txt +1 -0
mapproxy/request/base.py
ADDED
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2010 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
Service requests (parsing, handling, etc).
|
|
18
|
+
"""
|
|
19
|
+
from mapproxy.compat import PY2, iteritems, text_type
|
|
20
|
+
from mapproxy.compat.modules import parse_qsl, urlparse, quote
|
|
21
|
+
from mapproxy.util.py import cached_property
|
|
22
|
+
|
|
23
|
+
class NoCaseMultiDict(dict):
|
|
24
|
+
"""
|
|
25
|
+
This is a dictionary that allows case insensitive access to values.
|
|
26
|
+
|
|
27
|
+
>>> d = NoCaseMultiDict([('A', 'b'), ('a', 'c'), ('B', 'f'), ('c', 'x'), ('c', 'y'), ('c', 'z')])
|
|
28
|
+
>>> d['a']
|
|
29
|
+
'b'
|
|
30
|
+
>>> d.get_all('a')
|
|
31
|
+
['b', 'c']
|
|
32
|
+
>>> 'a' in d and 'b' in d
|
|
33
|
+
True
|
|
34
|
+
"""
|
|
35
|
+
def _gen_dict(self, mapping=()):
|
|
36
|
+
"""A `NoCaseMultiDict` can be constructed from an iterable of
|
|
37
|
+
``(key, value)`` tuples or a dict.
|
|
38
|
+
"""
|
|
39
|
+
tmp = {}
|
|
40
|
+
if isinstance(mapping, NoCaseMultiDict):
|
|
41
|
+
for key, value in mapping.iteritems(): #pylint: disable-msg=E1103
|
|
42
|
+
tmp.setdefault(key.lower(), (key, []))[1].extend(value)
|
|
43
|
+
else:
|
|
44
|
+
if isinstance(mapping, dict):
|
|
45
|
+
itr = iteritems(mapping)
|
|
46
|
+
else:
|
|
47
|
+
itr = iter(mapping)
|
|
48
|
+
for key, value in itr:
|
|
49
|
+
tmp.setdefault(key.lower(), (key, []))[1].append(value)
|
|
50
|
+
return tmp
|
|
51
|
+
|
|
52
|
+
def __init__(self, mapping=()):
|
|
53
|
+
"""A `NoCaseMultiDict` can be constructed from an iterable of
|
|
54
|
+
``(key, value)`` tuples or a dict.
|
|
55
|
+
"""
|
|
56
|
+
dict.__init__(self, self._gen_dict(mapping))
|
|
57
|
+
|
|
58
|
+
def update(self, mapping=(), append=False):
|
|
59
|
+
"""A `NoCaseMultiDict` can be updated from an iterable of
|
|
60
|
+
``(key, value)`` tuples or a dict.
|
|
61
|
+
"""
|
|
62
|
+
for _, (key, values) in iteritems(self._gen_dict(mapping)):
|
|
63
|
+
self.set(key, values, append=append, unpack=True)
|
|
64
|
+
|
|
65
|
+
def __getitem__(self, key):
|
|
66
|
+
"""
|
|
67
|
+
Return the first data value for this key.
|
|
68
|
+
|
|
69
|
+
:raise KeyError: if the key does not exist
|
|
70
|
+
"""
|
|
71
|
+
if key in self:
|
|
72
|
+
return dict.__getitem__(self, key.lower())[1][0]
|
|
73
|
+
raise KeyError(key)
|
|
74
|
+
|
|
75
|
+
def __setitem__(self, key, value):
|
|
76
|
+
dict.setdefault(self, key.lower(), (key, []))[1][:] = [value]
|
|
77
|
+
|
|
78
|
+
def __delitem__(self, key):
|
|
79
|
+
dict.__delitem__(self, key.lower())
|
|
80
|
+
|
|
81
|
+
def __contains__(self, key):
|
|
82
|
+
return dict.__contains__(self, key.lower())
|
|
83
|
+
|
|
84
|
+
def __getstate__(self):
|
|
85
|
+
data = []
|
|
86
|
+
for key, values in self.iteritems():
|
|
87
|
+
for v in values:
|
|
88
|
+
data.append((key, v))
|
|
89
|
+
return data
|
|
90
|
+
|
|
91
|
+
def __setstate__(self, data):
|
|
92
|
+
self.__init__(data)
|
|
93
|
+
|
|
94
|
+
def get(self, key, default=None, type_func=None):
|
|
95
|
+
"""Return the default value if the requested data doesn't exist.
|
|
96
|
+
If `type_func` is provided and is a callable it should convert the value,
|
|
97
|
+
return it or raise a `ValueError` if that is not possible. In this
|
|
98
|
+
case the function will return the default as if the value was not
|
|
99
|
+
found.
|
|
100
|
+
|
|
101
|
+
Example:
|
|
102
|
+
|
|
103
|
+
>>> d = NoCaseMultiDict(dict(foo='42', bar='blub'))
|
|
104
|
+
>>> d.get('foo', type_func=int)
|
|
105
|
+
42
|
|
106
|
+
>>> d.get('bar', -1, type_func=int)
|
|
107
|
+
-1
|
|
108
|
+
"""
|
|
109
|
+
try:
|
|
110
|
+
rv = self[key]
|
|
111
|
+
if type_func is not None:
|
|
112
|
+
rv = type_func(rv)
|
|
113
|
+
except (KeyError, ValueError):
|
|
114
|
+
rv = default
|
|
115
|
+
return rv
|
|
116
|
+
|
|
117
|
+
def get_all(self, key):
|
|
118
|
+
"""
|
|
119
|
+
Return all values for the key as a list. Returns an empty list, if
|
|
120
|
+
the key doesn't exist.
|
|
121
|
+
"""
|
|
122
|
+
if key in self:
|
|
123
|
+
return dict.__getitem__(self, key.lower())[1]
|
|
124
|
+
else:
|
|
125
|
+
return []
|
|
126
|
+
|
|
127
|
+
def set(self, key, value, append=False, unpack=False):
|
|
128
|
+
"""
|
|
129
|
+
Set a `value` for the `key`. If `append` is ``True`` the value will be added
|
|
130
|
+
to other values for this `key`.
|
|
131
|
+
|
|
132
|
+
If `unpack` is True, `value` will be unpacked and each item will be added.
|
|
133
|
+
"""
|
|
134
|
+
if key in self:
|
|
135
|
+
if not append:
|
|
136
|
+
dict.__getitem__(self, key.lower())[1][:] = []
|
|
137
|
+
else:
|
|
138
|
+
dict.__setitem__(self, key.lower(), (key, []))
|
|
139
|
+
if unpack:
|
|
140
|
+
for v in value:
|
|
141
|
+
dict.__getitem__(self, key.lower())[1].append(v)
|
|
142
|
+
else:
|
|
143
|
+
dict.__getitem__(self, key.lower())[1].append(value)
|
|
144
|
+
|
|
145
|
+
def iteritems(self):
|
|
146
|
+
"""
|
|
147
|
+
Iterates over all keys and values.
|
|
148
|
+
"""
|
|
149
|
+
if PY2:
|
|
150
|
+
for _, (key, values) in dict.iteritems(self):
|
|
151
|
+
yield key, values
|
|
152
|
+
else:
|
|
153
|
+
for _, (key, values) in dict.items(self):
|
|
154
|
+
yield key, values
|
|
155
|
+
|
|
156
|
+
def copy(self):
|
|
157
|
+
"""
|
|
158
|
+
Returns a copy of this object.
|
|
159
|
+
"""
|
|
160
|
+
return self.__class__(self)
|
|
161
|
+
|
|
162
|
+
def __repr__(self):
|
|
163
|
+
tmp = []
|
|
164
|
+
for key, values in self.iteritems():
|
|
165
|
+
tmp.append((key, values))
|
|
166
|
+
return '%s(%r)' % (self.__class__.__name__, tmp)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def url_decode(qs, charset='utf-8', decode_keys=False, include_empty=True,
|
|
170
|
+
errors='ignore'):
|
|
171
|
+
"""
|
|
172
|
+
Parse query string `qs` and return a `NoCaseMultiDict`.
|
|
173
|
+
"""
|
|
174
|
+
tmp = []
|
|
175
|
+
for key, value in parse_qsl(qs, include_empty):
|
|
176
|
+
if PY2:
|
|
177
|
+
if decode_keys:
|
|
178
|
+
key = key.decode(charset, errors)
|
|
179
|
+
tmp.append((key, value.decode(charset, errors)))
|
|
180
|
+
else:
|
|
181
|
+
if not isinstance(key, text_type):
|
|
182
|
+
key = key.decode(charset, errors)
|
|
183
|
+
if not isinstance(value, text_type):
|
|
184
|
+
value = value.decode(charset, errors)
|
|
185
|
+
tmp.append((key, value))
|
|
186
|
+
return NoCaseMultiDict(tmp)
|
|
187
|
+
|
|
188
|
+
class Request(object):
|
|
189
|
+
charset = 'utf8'
|
|
190
|
+
|
|
191
|
+
def __init__(self, environ):
|
|
192
|
+
self.environ = environ
|
|
193
|
+
self.environ['mapproxy.request'] = self
|
|
194
|
+
|
|
195
|
+
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
|
|
196
|
+
if script_name:
|
|
197
|
+
del environ['HTTP_X_SCRIPT_NAME']
|
|
198
|
+
environ['SCRIPT_NAME'] = script_name
|
|
199
|
+
path_info = environ['PATH_INFO']
|
|
200
|
+
if path_info.startswith(script_name):
|
|
201
|
+
environ['PATH_INFO'] = path_info[len(script_name):]
|
|
202
|
+
|
|
203
|
+
@cached_property
|
|
204
|
+
def args(self):
|
|
205
|
+
if self.environ.get('QUERY_STRING'):
|
|
206
|
+
return url_decode(self.environ['QUERY_STRING'], self.charset)
|
|
207
|
+
else:
|
|
208
|
+
return {}
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def path(self):
|
|
212
|
+
path = self.environ.get('PATH_INFO', '')
|
|
213
|
+
if PY2:
|
|
214
|
+
return path
|
|
215
|
+
if path and isinstance(path, bytes):
|
|
216
|
+
path = path.decode('utf-8')
|
|
217
|
+
return path
|
|
218
|
+
|
|
219
|
+
def pop_path(self):
|
|
220
|
+
path = self.path.lstrip('/')
|
|
221
|
+
if '/' in path:
|
|
222
|
+
result, rest = path.split('/', 1)
|
|
223
|
+
self.environ['PATH_INFO'] = '/' + rest
|
|
224
|
+
else:
|
|
225
|
+
self.environ['PATH_INFO'] = ''
|
|
226
|
+
result = path
|
|
227
|
+
if result:
|
|
228
|
+
self.environ['SCRIPT_NAME'] = self.environ['SCRIPT_NAME'] + '/' + result
|
|
229
|
+
return result
|
|
230
|
+
|
|
231
|
+
@cached_property
|
|
232
|
+
def host(self):
|
|
233
|
+
if 'HTTP_X_FORWARDED_HOST' in self.environ:
|
|
234
|
+
# might be a list, return first host only
|
|
235
|
+
host = self.environ['HTTP_X_FORWARDED_HOST']
|
|
236
|
+
host = host.split(',', 1)[0].strip()
|
|
237
|
+
return host
|
|
238
|
+
elif 'HTTP_HOST' in self.environ:
|
|
239
|
+
host = self.environ['HTTP_HOST']
|
|
240
|
+
if ':' in host:
|
|
241
|
+
port = host.split(':')[1]
|
|
242
|
+
if ((self.url_scheme, port) in (('https', '443'), ('http', '80'))):
|
|
243
|
+
host = host.split(':')[0]
|
|
244
|
+
return host
|
|
245
|
+
result = self.environ['SERVER_NAME']
|
|
246
|
+
if ((self.url_scheme, self.environ['SERVER_PORT'])
|
|
247
|
+
not in (('https', '443'), ('http', '80'))):
|
|
248
|
+
result += ':' + self.environ['SERVER_PORT']
|
|
249
|
+
return result
|
|
250
|
+
|
|
251
|
+
@cached_property
|
|
252
|
+
def url_scheme(self):
|
|
253
|
+
scheme = self.environ.get('HTTP_X_FORWARDED_PROTO')
|
|
254
|
+
if not scheme:
|
|
255
|
+
scheme = self.environ['wsgi.url_scheme']
|
|
256
|
+
return scheme
|
|
257
|
+
|
|
258
|
+
@cached_property
|
|
259
|
+
def host_url(self):
|
|
260
|
+
return '%s://%s/' % (self.url_scheme, self.host)
|
|
261
|
+
|
|
262
|
+
@cached_property
|
|
263
|
+
def server_url(self):
|
|
264
|
+
return 'http://%s:%s/' % (
|
|
265
|
+
self.environ['SERVER_NAME'],
|
|
266
|
+
self.environ['SERVER_PORT']
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def script_url(self):
|
|
271
|
+
"Full script URL without trailing /"
|
|
272
|
+
return (self.host_url.rstrip('/') +
|
|
273
|
+
quote(self.environ.get('SCRIPT_NAME', '/').rstrip('/'))
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def server_script_url(self):
|
|
278
|
+
"Internal script URL"
|
|
279
|
+
return self.script_url.replace(
|
|
280
|
+
self.host_url.rstrip('/'),
|
|
281
|
+
self.server_url.rstrip('/')
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
@property
|
|
285
|
+
def base_url(self):
|
|
286
|
+
return (self.host_url.rstrip('/')
|
|
287
|
+
+ quote(self.environ.get('SCRIPT_NAME', '').rstrip('/'))
|
|
288
|
+
+ quote(self.environ.get('PATH_INFO', ''))
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
class RequestParams(object):
|
|
292
|
+
"""
|
|
293
|
+
This class represents key-value request parameters. It allows case-insensitive
|
|
294
|
+
access to all keys. Multiple values for a single key will be concatenated
|
|
295
|
+
(eg. to ``layers=foo&layers=bar`` becomes ``layers: foo,bar``).
|
|
296
|
+
|
|
297
|
+
All values can be accessed as a property.
|
|
298
|
+
|
|
299
|
+
:param param: A dict or ``NoCaseMultiDict``.
|
|
300
|
+
"""
|
|
301
|
+
params = None
|
|
302
|
+
def __init__(self, param=None):
|
|
303
|
+
self.delimiter = ','
|
|
304
|
+
|
|
305
|
+
if param is None:
|
|
306
|
+
self.params = NoCaseMultiDict()
|
|
307
|
+
else:
|
|
308
|
+
self.params = NoCaseMultiDict(param)
|
|
309
|
+
|
|
310
|
+
def __str__(self):
|
|
311
|
+
return self.query_string
|
|
312
|
+
|
|
313
|
+
def get(self, key, default=None, type_func=None):
|
|
314
|
+
"""
|
|
315
|
+
Returns the value for `key` or the `default`. `type_func` is called on the
|
|
316
|
+
value to alter the value (e.g. use ``type_func=int`` to get ints).
|
|
317
|
+
"""
|
|
318
|
+
return self.params.get(key, default, type_func)
|
|
319
|
+
|
|
320
|
+
def set(self, key, value, append=False, unpack=False):
|
|
321
|
+
"""
|
|
322
|
+
Set a `value` for the `key`. If `append` is ``True`` the value will be added
|
|
323
|
+
to other values for this `key`.
|
|
324
|
+
|
|
325
|
+
If `unpack` is True, `value` will be unpacked and each item will be added.
|
|
326
|
+
"""
|
|
327
|
+
self.params.set(key, value, append=append, unpack=unpack)
|
|
328
|
+
|
|
329
|
+
def update(self, mapping=(), append=False):
|
|
330
|
+
"""
|
|
331
|
+
Update internal request parameters from an iterable of ``(key, value)``
|
|
332
|
+
tuples or a dict.
|
|
333
|
+
|
|
334
|
+
If `append` is ``True`` the value will be added to other values for
|
|
335
|
+
this `key`.
|
|
336
|
+
"""
|
|
337
|
+
self.params.update(mapping, append=append)
|
|
338
|
+
|
|
339
|
+
def __getattr__(self, name):
|
|
340
|
+
if name in self:
|
|
341
|
+
return self[name]
|
|
342
|
+
else:
|
|
343
|
+
raise AttributeError("'%s' object has no attribute '%s" %
|
|
344
|
+
(self.__class__.__name__, name))
|
|
345
|
+
|
|
346
|
+
def __getitem__(self, key):
|
|
347
|
+
return self.delimiter.join(map(text_type, self.params.get_all(key)))
|
|
348
|
+
|
|
349
|
+
def __setitem__(self, key, value):
|
|
350
|
+
"""
|
|
351
|
+
Set `value` for the `key`. Does not append values (see ``MapRequest.set``).
|
|
352
|
+
"""
|
|
353
|
+
self.set(key, value)
|
|
354
|
+
|
|
355
|
+
def __delitem__(self, key):
|
|
356
|
+
if key in self:
|
|
357
|
+
del self.params[key]
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def iteritems(self):
|
|
361
|
+
for key, values in self.params.iteritems():
|
|
362
|
+
yield key, self.delimiter.join((text_type(x) for x in values))
|
|
363
|
+
|
|
364
|
+
def __contains__(self, key):
|
|
365
|
+
return self.params and key in self.params
|
|
366
|
+
|
|
367
|
+
def copy(self):
|
|
368
|
+
return self.__class__(self.params)
|
|
369
|
+
|
|
370
|
+
@property
|
|
371
|
+
def query_string(self):
|
|
372
|
+
"""
|
|
373
|
+
The map request as a query string (the order is not guaranteed).
|
|
374
|
+
|
|
375
|
+
>>> qs = RequestParams(dict(foo='egg', bar='ham%eggs', baz=100)).query_string
|
|
376
|
+
>>> sorted(qs.split('&'))
|
|
377
|
+
['bar=ham%25eggs', 'baz=100', 'foo=egg']
|
|
378
|
+
"""
|
|
379
|
+
kv_pairs = []
|
|
380
|
+
for key, values in self.params.iteritems():
|
|
381
|
+
value = ','.join(text_type(v) for v in values)
|
|
382
|
+
kv_pairs.append(key + '=' + quote(value.encode('utf-8'), safe=','))
|
|
383
|
+
return '&'.join(kv_pairs)
|
|
384
|
+
|
|
385
|
+
def with_defaults(self, defaults):
|
|
386
|
+
"""
|
|
387
|
+
Return this MapRequest with all values from `defaults` overwritten.
|
|
388
|
+
"""
|
|
389
|
+
new = self.copy()
|
|
390
|
+
for key, value in defaults.params.iteritems():
|
|
391
|
+
if value != [None]:
|
|
392
|
+
new.set(key, value, unpack=True)
|
|
393
|
+
return new
|
|
394
|
+
|
|
395
|
+
class BaseRequest(object):
|
|
396
|
+
"""
|
|
397
|
+
This class represents a request with a URL and key-value parameters.
|
|
398
|
+
|
|
399
|
+
:param param: A dict, `NoCaseMultiDict` or ``RequestParams``.
|
|
400
|
+
:param url: The service URL for the request.
|
|
401
|
+
:param validate: True if the request should be validated after initialization.
|
|
402
|
+
"""
|
|
403
|
+
request_params = RequestParams
|
|
404
|
+
|
|
405
|
+
def __init__(self, param=None, url='', validate=False, http=None, dimensions=None):
|
|
406
|
+
self.delimiter = ','
|
|
407
|
+
self.http = http
|
|
408
|
+
|
|
409
|
+
if param is None:
|
|
410
|
+
self.params = self.request_params(NoCaseMultiDict())
|
|
411
|
+
else:
|
|
412
|
+
if isinstance(param, RequestParams):
|
|
413
|
+
self.params = self.request_params(param.params)
|
|
414
|
+
else:
|
|
415
|
+
self.params = self.request_params(NoCaseMultiDict(param))
|
|
416
|
+
self.url = url
|
|
417
|
+
if validate:
|
|
418
|
+
self.validate()
|
|
419
|
+
|
|
420
|
+
def __str__(self):
|
|
421
|
+
return self.complete_url
|
|
422
|
+
|
|
423
|
+
def validate(self):
|
|
424
|
+
pass
|
|
425
|
+
|
|
426
|
+
@property
|
|
427
|
+
def raw_params(self):
|
|
428
|
+
params = {}
|
|
429
|
+
for key, value in iteritems(self.params):
|
|
430
|
+
params[key] = value
|
|
431
|
+
return params
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
@property
|
|
435
|
+
def query_string(self):
|
|
436
|
+
return self.params.query_string
|
|
437
|
+
|
|
438
|
+
@property
|
|
439
|
+
def complete_url(self):
|
|
440
|
+
"""
|
|
441
|
+
The complete MapRequest as URL.
|
|
442
|
+
"""
|
|
443
|
+
if not self.url:
|
|
444
|
+
return self.query_string
|
|
445
|
+
delimiter = '?'
|
|
446
|
+
if '?' in self.url:
|
|
447
|
+
delimiter = '&'
|
|
448
|
+
if self.url[-1] == '?':
|
|
449
|
+
delimiter = ''
|
|
450
|
+
return self.url + delimiter + self.query_string
|
|
451
|
+
|
|
452
|
+
def copy_with_request_params(self, req):
|
|
453
|
+
"""
|
|
454
|
+
Return a copy of this request ond overwrite all param values from `req`.
|
|
455
|
+
Use this method for templates
|
|
456
|
+
(``req_template.copy_with_request_params(actual_values)``).
|
|
457
|
+
"""
|
|
458
|
+
new_params = req.params.with_defaults(self.params)
|
|
459
|
+
return self.__class__(param=new_params, url=self.url)
|
|
460
|
+
|
|
461
|
+
def __repr__(self):
|
|
462
|
+
return '%s(param=%r, url=%r)' % (self.__class__.__name__, self.params, self.url)
|
|
463
|
+
|
|
464
|
+
def split_mime_type(mime_type):
|
|
465
|
+
"""
|
|
466
|
+
>>> split_mime_type('text/xml; charset=utf-8')
|
|
467
|
+
('text', 'xml', 'charset=utf-8')
|
|
468
|
+
"""
|
|
469
|
+
options = None
|
|
470
|
+
mime_class = None
|
|
471
|
+
if '/' in mime_type:
|
|
472
|
+
mime_class, mime_type = mime_type.split('/', 1)
|
|
473
|
+
if ';' in mime_type:
|
|
474
|
+
mime_type, options = [part.strip() for part in mime_type.split(';', 2)]
|
|
475
|
+
return mime_class, mime_type, options
|
|
476
|
+
|
mapproxy/request/tile.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2010 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import re
|
|
17
|
+
|
|
18
|
+
from mapproxy.exception import (
|
|
19
|
+
RequestError,
|
|
20
|
+
XMLExceptionHandler,
|
|
21
|
+
PlainExceptionHandler, )
|
|
22
|
+
|
|
23
|
+
import mapproxy.service
|
|
24
|
+
from mapproxy.template import template_loader
|
|
25
|
+
get_template = template_loader(mapproxy.service.__name__, 'templates')
|
|
26
|
+
|
|
27
|
+
class TileRequest(object):
|
|
28
|
+
"""
|
|
29
|
+
Class for tile requests.
|
|
30
|
+
"""
|
|
31
|
+
request_handler_name = 'map'
|
|
32
|
+
tile_req_re = re.compile(r'''^(?P<begin>/[^/]+)/
|
|
33
|
+
((?P<version>1\.0\.0)/)?
|
|
34
|
+
(?P<layer>[^/]+)/
|
|
35
|
+
((?P<layer_spec>[^/]+)/)?
|
|
36
|
+
(?P<z>-?\d+)/
|
|
37
|
+
(?P<x>-?\d+)/
|
|
38
|
+
(?P<y>-?\d+)\.(?P<format>\w+)''', re.VERBOSE)
|
|
39
|
+
use_profiles = False
|
|
40
|
+
req_prefix = '/tiles'
|
|
41
|
+
origin = None
|
|
42
|
+
dimensions = {}
|
|
43
|
+
|
|
44
|
+
def __init__(self, request):
|
|
45
|
+
self.tile = None
|
|
46
|
+
self.format = None
|
|
47
|
+
self.http = request
|
|
48
|
+
self._init_request()
|
|
49
|
+
self.origin = self.http.args.get('origin')
|
|
50
|
+
if self.origin not in ('sw', 'nw', None):
|
|
51
|
+
self.origin = None
|
|
52
|
+
|
|
53
|
+
def _init_request(self):
|
|
54
|
+
"""
|
|
55
|
+
Initialize tile request. Sets ``tile`` and ``layer``.
|
|
56
|
+
:raise RequestError: if the format is not ``/layer/z/x/y.format``
|
|
57
|
+
"""
|
|
58
|
+
match = self.tile_req_re.search(self.http.path)
|
|
59
|
+
if not match or match.group('begin') != self.req_prefix:
|
|
60
|
+
raise RequestError('invalid request (%s)' % (self.http.path), request=self)
|
|
61
|
+
|
|
62
|
+
self.layer = match.group('layer')
|
|
63
|
+
self.dimensions = {}
|
|
64
|
+
if match.group('layer_spec') is not None:
|
|
65
|
+
self.dimensions['_layer_spec'] = match.group('layer_spec')
|
|
66
|
+
if not self.tile:
|
|
67
|
+
self.tile = tuple([int(match.group(v)) for v in ['x', 'y', 'z']])
|
|
68
|
+
if not self.format:
|
|
69
|
+
self.format = match.group('format')
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def exception_handler(self):
|
|
73
|
+
return PlainExceptionHandler()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TMSRequest(TileRequest):
|
|
77
|
+
"""
|
|
78
|
+
Class for TMS 1.0.0 requests.
|
|
79
|
+
"""
|
|
80
|
+
request_handler_name = 'map'
|
|
81
|
+
req_prefix = '/tms'
|
|
82
|
+
capabilities_re = re.compile(r'''
|
|
83
|
+
^.*/1\.0\.0/?
|
|
84
|
+
(/(?P<layer>[^/]+))?
|
|
85
|
+
(/(?P<layer_spec>[^/]+))?
|
|
86
|
+
$''', re.VERBOSE)
|
|
87
|
+
root_request_re = re.compile(r'/tms/?$')
|
|
88
|
+
use_profiles = True
|
|
89
|
+
origin = 'sw'
|
|
90
|
+
|
|
91
|
+
def __init__(self, request):
|
|
92
|
+
self.tile = None
|
|
93
|
+
self.format = None
|
|
94
|
+
self.http = request
|
|
95
|
+
cap_match = self.capabilities_re.match(request.path)
|
|
96
|
+
root_match = self.root_request_re.match(request.path)
|
|
97
|
+
if cap_match:
|
|
98
|
+
if cap_match.group('layer') is not None:
|
|
99
|
+
self.layer = cap_match.group('layer')
|
|
100
|
+
self.dimensions = {}
|
|
101
|
+
if cap_match.group('layer_spec') is not None:
|
|
102
|
+
self.dimensions['_layer_spec'] = cap_match.group('layer_spec')
|
|
103
|
+
self.request_handler_name = 'tms_capabilities'
|
|
104
|
+
elif root_match:
|
|
105
|
+
self.request_handler_name = 'tms_root_resource'
|
|
106
|
+
else:
|
|
107
|
+
self._init_request()
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def exception_handler(self):
|
|
111
|
+
return TMSExceptionHandler()
|
|
112
|
+
|
|
113
|
+
def tile_request(req):
|
|
114
|
+
if req.path.startswith('/tms'):
|
|
115
|
+
return TMSRequest(req)
|
|
116
|
+
else:
|
|
117
|
+
return TileRequest(req)
|
|
118
|
+
|
|
119
|
+
class TMSExceptionHandler(XMLExceptionHandler):
|
|
120
|
+
template_file = 'tms_exception.xml'
|
|
121
|
+
template_func = get_template
|
|
122
|
+
mimetype = 'text/xml'
|
|
123
|
+
status_code = 404
|
|
124
|
+
|
|
125
|
+
def render(self, request_error):
|
|
126
|
+
if request_error.internal:
|
|
127
|
+
self.status_code = 500
|
|
128
|
+
return XMLExceptionHandler.render(self, request_error)
|