MapProxy 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- MapProxy-2.1.0.dist-info/AUTHORS.txt +33 -0
- MapProxy-2.1.0.dist-info/COPYING.txt +60 -0
- MapProxy-2.1.0.dist-info/LICENSE.txt +202 -0
- MapProxy-2.1.0.dist-info/METADATA +165 -0
- MapProxy-2.1.0.dist-info/RECORD +459 -0
- MapProxy-2.1.0.dist-info/WHEEL +5 -0
- MapProxy-2.1.0.dist-info/entry_points.txt +4 -0
- MapProxy-2.1.0.dist-info/top_level.txt +1 -0
- mapproxy/__init__.py +0 -0
- mapproxy/cache/__init__.py +36 -0
- mapproxy/cache/azureblob.py +145 -0
- mapproxy/cache/base.py +120 -0
- mapproxy/cache/compact.py +665 -0
- mapproxy/cache/couchdb.py +301 -0
- mapproxy/cache/dummy.py +36 -0
- mapproxy/cache/file.py +200 -0
- mapproxy/cache/geopackage.py +647 -0
- mapproxy/cache/legend.py +87 -0
- mapproxy/cache/mbtiles.py +411 -0
- mapproxy/cache/meta.py +80 -0
- mapproxy/cache/path.py +261 -0
- mapproxy/cache/redis.py +152 -0
- mapproxy/cache/renderd.py +100 -0
- mapproxy/cache/riak.py +206 -0
- mapproxy/cache/s3.py +209 -0
- mapproxy/cache/tile.py +736 -0
- mapproxy/client/__init__.py +0 -0
- mapproxy/client/arcgis.py +82 -0
- mapproxy/client/cgi.py +141 -0
- mapproxy/client/http.py +295 -0
- mapproxy/client/log.py +33 -0
- mapproxy/client/tile.py +158 -0
- mapproxy/client/wms.py +255 -0
- mapproxy/compat/__init__.py +0 -0
- mapproxy/compat/image.py +86 -0
- mapproxy/config/__init__.py +22 -0
- mapproxy/config/config-schema.json +813 -0
- mapproxy/config/config.py +213 -0
- mapproxy/config/coverage.py +108 -0
- mapproxy/config/defaults.py +102 -0
- mapproxy/config/loader.py +2399 -0
- mapproxy/config/spec.py +657 -0
- mapproxy/config/validator.py +242 -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 +598 -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 +149 -0
- mapproxy/featureinfo.py +251 -0
- mapproxy/grid.py +1199 -0
- mapproxy/image/__init__.py +549 -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 +79 -0
- mapproxy/image/merge.py +323 -0
- mapproxy/image/message.py +357 -0
- mapproxy/image/opts.py +185 -0
- mapproxy/image/tile.py +171 -0
- mapproxy/image/transform.py +350 -0
- mapproxy/layer.py +489 -0
- mapproxy/multiapp.py +230 -0
- mapproxy/proj.py +309 -0
- mapproxy/request/__init__.py +18 -0
- mapproxy/request/arcgis.py +268 -0
- mapproxy/request/base.py +466 -0
- mapproxy/request/tile.py +131 -0
- mapproxy/request/wms/__init__.py +829 -0
- mapproxy/request/wms/exception.py +107 -0
- mapproxy/request/wmts.py +442 -0
- mapproxy/response.py +237 -0
- mapproxy/script/__init__.py +0 -0
- mapproxy/script/conf/__init__.py +0 -0
- mapproxy/script/conf/app.py +222 -0
- mapproxy/script/conf/caches.py +44 -0
- mapproxy/script/conf/geopackage.py +136 -0
- mapproxy/script/conf/layers.py +54 -0
- mapproxy/script/conf/seeds.py +36 -0
- mapproxy/script/conf/sources.py +88 -0
- mapproxy/script/conf/utils.py +148 -0
- mapproxy/script/defrag.py +187 -0
- mapproxy/script/export.py +337 -0
- mapproxy/script/grids.py +198 -0
- mapproxy/script/scales.py +134 -0
- mapproxy/script/util.py +410 -0
- mapproxy/script/wms_capabilities.py +160 -0
- mapproxy/seed/__init__.py +0 -0
- mapproxy/seed/cachelock.py +127 -0
- mapproxy/seed/cleanup.py +191 -0
- mapproxy/seed/config.py +481 -0
- mapproxy/seed/script.py +391 -0
- mapproxy/seed/seeder.py +551 -0
- mapproxy/seed/spec.py +66 -0
- mapproxy/seed/util.py +266 -0
- mapproxy/service/__init__.py +14 -0
- mapproxy/service/base.py +45 -0
- mapproxy/service/demo.py +364 -0
- mapproxy/service/kml.py +333 -0
- mapproxy/service/ows.py +39 -0
- mapproxy/service/template_helper.py +55 -0
- mapproxy/service/templates/demo/capabilities_demo.html +18 -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 +117 -0
- mapproxy/service/templates/demo/wms_demo.html +144 -0
- mapproxy/service/templates/demo/wmts_demo.html +118 -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 +540 -0
- mapproxy/service/wms.py +868 -0
- mapproxy/service/wmts.py +387 -0
- mapproxy/source/__init__.py +83 -0
- mapproxy/source/arcgis.py +39 -0
- mapproxy/source/error.py +40 -0
- mapproxy/source/mapnik.py +262 -0
- mapproxy/source/tile.py +97 -0
- mapproxy/source/wms.py +273 -0
- mapproxy/srs.py +734 -0
- mapproxy/template.py +54 -0
- mapproxy/test/__init__.py +0 -0
- mapproxy/test/conftest.py +8 -0
- mapproxy/test/helper.py +255 -0
- mapproxy/test/http.py +511 -0
- mapproxy/test/image.py +219 -0
- mapproxy/test/mocker.py +2291 -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_coverage.yaml +84 -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 +111 -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 +29 -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 +1133 -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_coverage.py +168 -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 +56 -0
- mapproxy/test/system/test_demo_with_extra_service.py +57 -0
- mapproxy/test/system/test_dimensions.py +279 -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 +264 -0
- mapproxy/test/system/test_layergroups.py +160 -0
- mapproxy/test/system/test_legendgraphic.py +308 -0
- mapproxy/test/system/test_mapnik.py +162 -0
- mapproxy/test/system/test_mapserver.py +83 -0
- mapproxy/test/system/test_mixed_mode_format.py +201 -0
- mapproxy/test/system/test_multi_cache_layers.py +169 -0
- mapproxy/test/system/test_multiapp.py +92 -0
- mapproxy/test/system/test_refresh.py +206 -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 +425 -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 +277 -0
- mapproxy/test/system/test_tms_origin.py +46 -0
- mapproxy/test/system/test_util_conf.py +434 -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 +1616 -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 +423 -0
- mapproxy/test/test_http_helper.py +217 -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 +242 -0
- mapproxy/test/unit/test_auth.py +430 -0
- mapproxy/test/unit/test_cache.py +1356 -0
- mapproxy/test/unit/test_cache_azureblob.py +97 -0
- mapproxy/test/unit/test_cache_compact.py +324 -0
- mapproxy/test/unit/test_cache_couchdb.py +118 -0
- mapproxy/test/unit/test_cache_geopackage.py +256 -0
- mapproxy/test/unit/test_cache_redis.py +123 -0
- mapproxy/test/unit/test_cache_riak.py +80 -0
- mapproxy/test/unit/test_cache_s3.py +93 -0
- mapproxy/test/unit/test_cache_tile.py +477 -0
- mapproxy/test/unit/test_client.py +488 -0
- mapproxy/test/unit/test_client_arcgis.py +74 -0
- mapproxy/test/unit/test_client_cgi.py +140 -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 +1267 -0
- mapproxy/test/unit/test_conf_validator.py +427 -0
- mapproxy/test/unit/test_config.py +118 -0
- mapproxy/test/unit/test_decorate_img.py +185 -0
- mapproxy/test/unit/test_exceptions.py +270 -0
- mapproxy/test/unit/test_featureinfo.py +313 -0
- mapproxy/test/unit/test_file_lock_load.py +49 -0
- mapproxy/test/unit/test_geom.py +512 -0
- mapproxy/test/unit/test_grid.py +1279 -0
- mapproxy/test/unit/test_image.py +1051 -0
- mapproxy/test/unit/test_image_mask.py +181 -0
- mapproxy/test/unit/test_image_messages.py +209 -0
- mapproxy/test/unit/test_image_options.py +160 -0
- mapproxy/test/unit/test_isodate.py +118 -0
- mapproxy/test/unit/test_multiapp.py +163 -0
- mapproxy/test/unit/test_ogr_reader.py +51 -0
- mapproxy/test/unit/test_request.py +745 -0
- mapproxy/test/unit/test_request_wmts.py +178 -0
- mapproxy/test/unit/test_response.py +78 -0
- mapproxy/test/unit/test_seed.py +365 -0
- mapproxy/test/unit/test_seed_cachelock.py +91 -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 +68 -0
- mapproxy/tilefilter.py +61 -0
- mapproxy/util/__init__.py +0 -0
- mapproxy/util/async_.py +229 -0
- mapproxy/util/collections.py +134 -0
- mapproxy/util/coverage.py +337 -0
- mapproxy/util/ext/__init__.py +14 -0
- mapproxy/util/ext/dictspec/__init__.py +1 -0
- mapproxy/util/ext/dictspec/spec.py +131 -0
- mapproxy/util/ext/dictspec/test/__init__.py +0 -0
- mapproxy/util/ext/dictspec/test/test_validator.py +278 -0
- mapproxy/util/ext/dictspec/validator.py +194 -0
- mapproxy/util/ext/local.py +198 -0
- mapproxy/util/ext/lockfile.py +140 -0
- mapproxy/util/ext/odict.py +321 -0
- mapproxy/util/ext/serving.py +491 -0
- mapproxy/util/ext/tempita/__init__.py +1093 -0
- mapproxy/util/ext/tempita/_looper.py +163 -0
- mapproxy/util/ext/tempita/string_utils.py +24 -0
- mapproxy/util/ext/wmsparse/__init__.py +3 -0
- mapproxy/util/ext/wmsparse/duration.py +600 -0
- mapproxy/util/ext/wmsparse/parse.py +307 -0
- mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
- mapproxy/util/ext/wmsparse/test/test_parse.py +111 -0
- mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
- mapproxy/util/ext/wmsparse/test/wms-example-111.xml +90 -0
- mapproxy/util/ext/wmsparse/test/wms-example-130.xml +120 -0
- mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
- mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
- mapproxy/util/ext/wmsparse/util.py +189 -0
- mapproxy/util/fs.py +164 -0
- mapproxy/util/geom.py +307 -0
- mapproxy/util/lib.py +117 -0
- mapproxy/util/lock.py +171 -0
- mapproxy/util/ogr.py +247 -0
- mapproxy/util/py.py +75 -0
- mapproxy/util/times.py +78 -0
- mapproxy/util/yaml.py +58 -0
- mapproxy/version.py +33 -0
- mapproxy/wsgiapp.py +167 -0
mapproxy/response.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
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 responses.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import hashlib
|
|
21
|
+
from mapproxy.util.times import format_httpdate, parse_httpdate, timestamp
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Response(object):
|
|
25
|
+
charset = 'utf-8'
|
|
26
|
+
default_content_type = 'text/plain'
|
|
27
|
+
block_size = 1024 * 32
|
|
28
|
+
|
|
29
|
+
def __init__(self, response, status=None, content_type=None, mimetype=None):
|
|
30
|
+
self.response = response
|
|
31
|
+
if status is None:
|
|
32
|
+
status = 200
|
|
33
|
+
self.status = status
|
|
34
|
+
self._timestamp = None
|
|
35
|
+
self.headers = {}
|
|
36
|
+
if mimetype:
|
|
37
|
+
if mimetype.startswith('text/'):
|
|
38
|
+
content_type = mimetype + '; charset=' + self.charset
|
|
39
|
+
else:
|
|
40
|
+
content_type = mimetype
|
|
41
|
+
if content_type is None:
|
|
42
|
+
content_type = self.default_content_type
|
|
43
|
+
self.headers['Content-type'] = content_type
|
|
44
|
+
|
|
45
|
+
if content_type.startswith(('text/', 'application/')):
|
|
46
|
+
# Capability documents can be dependent on the value of a few X-headers.
|
|
47
|
+
# Tell this caching proxies via the Vary HTTP header. This also prevents
|
|
48
|
+
# malicious cache poisoning.
|
|
49
|
+
self.headers['Vary'] = 'X-Script-Name, X-Forwarded-Host, X-Forwarded-Proto'
|
|
50
|
+
|
|
51
|
+
def _status_set(self, status):
|
|
52
|
+
if isinstance(status, int):
|
|
53
|
+
status = status_code(status)
|
|
54
|
+
self._status = status
|
|
55
|
+
|
|
56
|
+
def _status_get(self):
|
|
57
|
+
return self._status
|
|
58
|
+
|
|
59
|
+
status = property(_status_get, _status_set)
|
|
60
|
+
|
|
61
|
+
def _last_modified_set(self, date):
|
|
62
|
+
if not date:
|
|
63
|
+
return
|
|
64
|
+
self._timestamp = timestamp(date)
|
|
65
|
+
self.headers['Last-modified'] = format_httpdate(self._timestamp)
|
|
66
|
+
|
|
67
|
+
def _last_modified_get(self):
|
|
68
|
+
return self.headers.get('Last-modified', None)
|
|
69
|
+
|
|
70
|
+
last_modified = property(_last_modified_get, _last_modified_set)
|
|
71
|
+
|
|
72
|
+
def _etag_set(self, value):
|
|
73
|
+
self.headers['ETag'] = value
|
|
74
|
+
|
|
75
|
+
def _etag_get(self):
|
|
76
|
+
return self.headers.get('ETag', None)
|
|
77
|
+
|
|
78
|
+
etag = property(_etag_get, _etag_set)
|
|
79
|
+
|
|
80
|
+
def cache_headers(self, timestamp=None, etag_data=None, max_age=None, no_cache=False):
|
|
81
|
+
"""
|
|
82
|
+
Set cache-related headers.
|
|
83
|
+
|
|
84
|
+
:param timestamp: local timestamp of the last modification of the
|
|
85
|
+
response content
|
|
86
|
+
:param etag_data: list that will be used to build an ETag hash.
|
|
87
|
+
calls the str function on each item.
|
|
88
|
+
:param max_age: the maximum cache age in seconds
|
|
89
|
+
"""
|
|
90
|
+
if etag_data:
|
|
91
|
+
hash_src = ''.join((str(x) for x in etag_data)).encode('ascii')
|
|
92
|
+
self.etag = hashlib.new('md5', hash_src, usedforsecurity=False).hexdigest()
|
|
93
|
+
|
|
94
|
+
if no_cache:
|
|
95
|
+
assert not timestamp and not max_age
|
|
96
|
+
self.headers['Cache-Control'] = 'no-cache, no-store'
|
|
97
|
+
self.headers['Pragma'] = 'no-cache'
|
|
98
|
+
self.headers['Expires'] = '-1'
|
|
99
|
+
|
|
100
|
+
self.last_modified = timestamp
|
|
101
|
+
if (timestamp or etag_data) and max_age is not None:
|
|
102
|
+
self.headers['Cache-control'] = 'public, max-age=%d, s-maxage=%d' % (max_age, max_age)
|
|
103
|
+
|
|
104
|
+
def make_conditional(self, req):
|
|
105
|
+
"""
|
|
106
|
+
Make the response conditional to the HTTP headers in the CGI/WSGI `environ`.
|
|
107
|
+
Checks for ``If-none-match`` and ``If-modified-since`` headers and compares
|
|
108
|
+
to the etag and timestamp of this response. If the content was not modified
|
|
109
|
+
the repsonse will changed to HTTP 304 Not Modified.
|
|
110
|
+
"""
|
|
111
|
+
if req is None:
|
|
112
|
+
return
|
|
113
|
+
environ = req.environ
|
|
114
|
+
|
|
115
|
+
not_modified = False
|
|
116
|
+
|
|
117
|
+
if self.etag == environ.get('HTTP_IF_NONE_MATCH', -1):
|
|
118
|
+
not_modified = True
|
|
119
|
+
elif self._timestamp is not None:
|
|
120
|
+
date = environ.get('HTTP_IF_MODIFIED_SINCE', None)
|
|
121
|
+
timestamp = parse_httpdate(date)
|
|
122
|
+
if timestamp is not None and self._timestamp <= timestamp:
|
|
123
|
+
not_modified = True
|
|
124
|
+
|
|
125
|
+
if not_modified:
|
|
126
|
+
self.status = 304
|
|
127
|
+
self.response = []
|
|
128
|
+
if 'Content-type' in self.headers:
|
|
129
|
+
del self.headers['Content-type']
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def content_length(self):
|
|
133
|
+
return int(self.headers.get('Content-length', 0))
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def content_type(self):
|
|
137
|
+
return self.headers['Content-type']
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def data(self):
|
|
141
|
+
if hasattr(self.response, 'read'):
|
|
142
|
+
return self.response.read()
|
|
143
|
+
else:
|
|
144
|
+
return b''.join(chunk.encode() for chunk in self.response)
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def fixed_headers(self):
|
|
148
|
+
headers = []
|
|
149
|
+
for key, value in self.headers.items():
|
|
150
|
+
if type(value) is not str:
|
|
151
|
+
# for str subclasses like ImageFormat
|
|
152
|
+
value = str(value)
|
|
153
|
+
headers.append((key, value))
|
|
154
|
+
return headers
|
|
155
|
+
|
|
156
|
+
def __call__(self, environ, start_response):
|
|
157
|
+
if hasattr(self.response, 'read'):
|
|
158
|
+
if ((not hasattr(self.response, 'ok_to_seek') or
|
|
159
|
+
self.response.ok_to_seek) and
|
|
160
|
+
(hasattr(self.response, 'seek') and
|
|
161
|
+
hasattr(self.response, 'tell'))):
|
|
162
|
+
self.response.seek(0, 2) # to EOF
|
|
163
|
+
self.headers['Content-length'] = str(self.response.tell())
|
|
164
|
+
self.response.seek(0)
|
|
165
|
+
if 'wsgi.file_wrapper' in environ:
|
|
166
|
+
resp_iter = environ['wsgi.file_wrapper'](self.response, self.block_size)
|
|
167
|
+
else:
|
|
168
|
+
resp_iter = iter(lambda: self.response.read(self.block_size), b'')
|
|
169
|
+
elif not self.response:
|
|
170
|
+
resp_iter = iter([])
|
|
171
|
+
elif isinstance(self.response, str):
|
|
172
|
+
self.response = self.response.encode(self.charset)
|
|
173
|
+
self.headers['Content-length'] = str(len(self.response))
|
|
174
|
+
resp_iter = iter([self.response])
|
|
175
|
+
elif isinstance(self.response, bytes):
|
|
176
|
+
self.headers['Content-length'] = str(len(self.response))
|
|
177
|
+
resp_iter = iter([self.response])
|
|
178
|
+
else:
|
|
179
|
+
resp_iter = self.response
|
|
180
|
+
|
|
181
|
+
start_response(self.status, self.fixed_headers)
|
|
182
|
+
return resp_iter
|
|
183
|
+
|
|
184
|
+
def iter_encode(self, chunks):
|
|
185
|
+
for chunk in chunks:
|
|
186
|
+
if isinstance(chunk, str):
|
|
187
|
+
chunk = chunk.encode(self.charset)
|
|
188
|
+
yield chunk
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# http://www.faqs.org/rfcs/rfc2616.html
|
|
192
|
+
_status_codes = {
|
|
193
|
+
100: 'Continue',
|
|
194
|
+
101: 'Switching Protocols',
|
|
195
|
+
200: 'OK',
|
|
196
|
+
201: 'Created',
|
|
197
|
+
202: 'Accepted',
|
|
198
|
+
203: 'Non-Authoritative Information',
|
|
199
|
+
204: 'No Content',
|
|
200
|
+
205: 'Reset Content',
|
|
201
|
+
206: 'Partial Content',
|
|
202
|
+
300: 'Multiple Choices',
|
|
203
|
+
301: 'Moved Permanently',
|
|
204
|
+
302: 'Found',
|
|
205
|
+
303: 'See Other',
|
|
206
|
+
304: 'Not Modified',
|
|
207
|
+
305: 'Use Proxy',
|
|
208
|
+
307: 'Temporary Redirect',
|
|
209
|
+
400: 'Bad Request',
|
|
210
|
+
401: 'Unauthorized',
|
|
211
|
+
402: 'Payment Required',
|
|
212
|
+
403: 'Forbidden',
|
|
213
|
+
404: 'Not Found',
|
|
214
|
+
405: 'Method Not Allowed',
|
|
215
|
+
406: 'Not Acceptable',
|
|
216
|
+
407: 'Proxy Authentication Required',
|
|
217
|
+
408: 'Request Time-out',
|
|
218
|
+
409: 'Conflict',
|
|
219
|
+
410: 'Gone',
|
|
220
|
+
411: 'Length Required',
|
|
221
|
+
412: 'Precondition Failed',
|
|
222
|
+
413: 'Request Entity Too Large',
|
|
223
|
+
414: 'Request-URI Too Large',
|
|
224
|
+
415: 'Unsupported Media Type',
|
|
225
|
+
416: 'Requested range not satisfiable',
|
|
226
|
+
417: 'Expectation Failed',
|
|
227
|
+
500: 'Internal Server Error',
|
|
228
|
+
501: 'Not Implemented',
|
|
229
|
+
502: 'Bad Gateway',
|
|
230
|
+
503: 'Service Unavailable',
|
|
231
|
+
504: 'Gateway Time-out',
|
|
232
|
+
505: 'HTTP Version not supported',
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def status_code(code):
|
|
237
|
+
return str(code) + ' ' + _status_codes[code]
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# -:- encoding: utf-8 -:-
|
|
2
|
+
# This file is part of the MapProxy project.
|
|
3
|
+
# Copyright (C) 2013 Omniscale <http://omniscale.de>
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
from __future__ import print_function
|
|
18
|
+
|
|
19
|
+
import codecs
|
|
20
|
+
import sys
|
|
21
|
+
import os
|
|
22
|
+
import optparse
|
|
23
|
+
import logging
|
|
24
|
+
import textwrap
|
|
25
|
+
import datetime
|
|
26
|
+
import xml.etree.ElementTree
|
|
27
|
+
import yaml
|
|
28
|
+
|
|
29
|
+
from contextlib import contextmanager
|
|
30
|
+
from io import BytesIO
|
|
31
|
+
|
|
32
|
+
from .sources import sources
|
|
33
|
+
from .layers import layers
|
|
34
|
+
from .caches import caches
|
|
35
|
+
from .seeds import seeds
|
|
36
|
+
from .utils import update_config, MapProxyYAMLDumper, download_capabilities
|
|
37
|
+
from .geopackage import get_geopackage_configuration_dict
|
|
38
|
+
|
|
39
|
+
from mapproxy.config.loader import load_configuration
|
|
40
|
+
from mapproxy.util.ext.wmsparse import parse_capabilities
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def setup_logging(level=logging.INFO):
|
|
44
|
+
mapproxy_log = logging.getLogger('mapproxy')
|
|
45
|
+
mapproxy_log.setLevel(level)
|
|
46
|
+
|
|
47
|
+
# do not init logging when stdout is captured
|
|
48
|
+
# eg. when running in tests
|
|
49
|
+
if isinstance(sys.stdout, BytesIO):
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
ch = logging.StreamHandler(sys.stdout)
|
|
53
|
+
ch.setLevel(logging.DEBUG)
|
|
54
|
+
formatter = logging.Formatter(
|
|
55
|
+
"[%(asctime)s] %(name)s - %(levelname)s - %(message)s")
|
|
56
|
+
ch.setFormatter(formatter)
|
|
57
|
+
mapproxy_log.addHandler(ch)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def write_header(f, capabilities):
|
|
61
|
+
print('# MapProxy configuration automatically generated from:', file=f)
|
|
62
|
+
print('# %s' % capabilities, file=f)
|
|
63
|
+
print('#', file=f)
|
|
64
|
+
print('# NOTE: The generated configuration can be highly inefficient,', file=f)
|
|
65
|
+
print('# especially when multiple layers and caches are requested at once.', file=f)
|
|
66
|
+
print('# Make sure you understand the generated configuration!', file=f)
|
|
67
|
+
print('#', file=f)
|
|
68
|
+
print('# Created on %s with:' % datetime.datetime.now(), file=f)
|
|
69
|
+
print(' \\\n'.join(textwrap.wrap(' '.join(sys.argv), initial_indent='# ', subsequent_indent='# ')), file=f)
|
|
70
|
+
print('', file=f)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@contextmanager
|
|
74
|
+
def file_or_stdout(name):
|
|
75
|
+
if name == '-':
|
|
76
|
+
if hasattr(sys.stdout, 'buffer'):
|
|
77
|
+
yield codecs.getwriter('utf-8')(sys.stdout.buffer)
|
|
78
|
+
else:
|
|
79
|
+
yield codecs.getwriter('utf-8')(sys.stdout)
|
|
80
|
+
else:
|
|
81
|
+
with open(name, 'wb') as f:
|
|
82
|
+
yield codecs.getwriter('utf-8')(f)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def config_command(args):
|
|
86
|
+
parser = optparse.OptionParser("usage: %prog autoconfig [options]")
|
|
87
|
+
|
|
88
|
+
parser.add_option('--capabilities',
|
|
89
|
+
help="URL or filename of WMS 1.1.1/1.3.0 capabilities document")
|
|
90
|
+
parser.add_option('--geopackage',
|
|
91
|
+
help="Filename of a geopackage file")
|
|
92
|
+
parser.add_option('--output', help="filename for created MapProxy config [default: -]", default="-")
|
|
93
|
+
parser.add_option('--output-seed', help="filename for created seeding config")
|
|
94
|
+
|
|
95
|
+
parser.add_option('--base', help='base config to include in created MapProxy config')
|
|
96
|
+
|
|
97
|
+
parser.add_option('--overwrite',
|
|
98
|
+
help='YAML file with overwrites for the created MapProxy config')
|
|
99
|
+
parser.add_option('--overwrite-seed',
|
|
100
|
+
help='YAML file with overwrites for the created seeding config')
|
|
101
|
+
|
|
102
|
+
parser.add_option('--force', default=False, action='store_true',
|
|
103
|
+
help="overwrite existing files")
|
|
104
|
+
|
|
105
|
+
options, args = parser.parse_args(args)
|
|
106
|
+
|
|
107
|
+
if not (bool(options.capabilities) ^ bool(options.geopackage)):
|
|
108
|
+
parser.print_help()
|
|
109
|
+
print("\nERROR: --capabilities required or --geopackage required", file=sys.stderr)
|
|
110
|
+
return 2
|
|
111
|
+
|
|
112
|
+
if not options.output and not options.output_seed:
|
|
113
|
+
parser.print_help()
|
|
114
|
+
print("\nERROR: --output and/or --output-seed required", file=sys.stderr)
|
|
115
|
+
return 2
|
|
116
|
+
|
|
117
|
+
if not options.force:
|
|
118
|
+
if options.output and options.output != '-' and os.path.exists(options.output):
|
|
119
|
+
print("\nERROR: %s already exists, use --force to overwrite" % options.output, file=sys.stderr)
|
|
120
|
+
return 2
|
|
121
|
+
if options.output_seed and options.output_seed != '-' and os.path.exists(options.output_seed):
|
|
122
|
+
print("\nERROR: %s already exists, use --force to overwrite" % options.output_seed, file=sys.stderr)
|
|
123
|
+
return 2
|
|
124
|
+
|
|
125
|
+
log = logging.getLogger('mapproxy_conf_cmd')
|
|
126
|
+
log.addHandler(logging.StreamHandler())
|
|
127
|
+
|
|
128
|
+
setup_logging(logging.WARNING)
|
|
129
|
+
|
|
130
|
+
srs_grids = {}
|
|
131
|
+
if options.base:
|
|
132
|
+
base = load_configuration(options.base)
|
|
133
|
+
for name, grid_conf in base.grids.items():
|
|
134
|
+
if name.startswith('GLOBAL_'):
|
|
135
|
+
continue
|
|
136
|
+
srs_grids[grid_conf.tile_grid().srs.srs_code] = name
|
|
137
|
+
|
|
138
|
+
cap_doc = options.capabilities
|
|
139
|
+
gpkg = options.geopackage
|
|
140
|
+
if cap_doc:
|
|
141
|
+
if cap_doc.startswith(('http://', 'https://')):
|
|
142
|
+
cap_doc = download_capabilities(options.capabilities).read()
|
|
143
|
+
else:
|
|
144
|
+
cap_doc = open(cap_doc, 'rb').read()
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
cap = parse_capabilities(BytesIO(cap_doc))
|
|
148
|
+
except (xml.etree.ElementTree.ParseError, ValueError) as ex:
|
|
149
|
+
print(ex, file=sys.stderr)
|
|
150
|
+
print(f"{cap_doc[:1000]} {'...' if len(cap_doc) > 1000 else ''}", file=sys.stderr)
|
|
151
|
+
return 3
|
|
152
|
+
elif gpkg:
|
|
153
|
+
if os.path.isfile(gpkg):
|
|
154
|
+
gpkg_dict = get_geopackage_configuration_dict(gpkg)
|
|
155
|
+
else:
|
|
156
|
+
print("ERROR: No file {} exists.".format(gpkg))
|
|
157
|
+
return 2
|
|
158
|
+
|
|
159
|
+
overwrite = None
|
|
160
|
+
if options.overwrite:
|
|
161
|
+
with open(options.overwrite, 'rb') as f:
|
|
162
|
+
overwrite = yaml.safe_load(f)
|
|
163
|
+
|
|
164
|
+
overwrite_seed = None
|
|
165
|
+
if options.overwrite_seed:
|
|
166
|
+
with open(options.overwrite_seed, 'rb') as f:
|
|
167
|
+
overwrite_seed = yaml.safe_load(f)
|
|
168
|
+
|
|
169
|
+
conf = {}
|
|
170
|
+
|
|
171
|
+
if options.base:
|
|
172
|
+
conf['base'] = os.path.abspath(options.base)
|
|
173
|
+
if cap_doc:
|
|
174
|
+
conf['services'] = {'wms': {'md': {'title': cap.metadata()['title']}}}
|
|
175
|
+
if gpkg:
|
|
176
|
+
conf['services'] = gpkg_dict['services']
|
|
177
|
+
if overwrite:
|
|
178
|
+
conf['services'] = update_config(conf['services'], overwrite.pop('service', {}))
|
|
179
|
+
|
|
180
|
+
if cap_doc:
|
|
181
|
+
conf['sources'] = sources(cap)
|
|
182
|
+
if overwrite:
|
|
183
|
+
conf['sources'] = update_config(conf['sources'], overwrite.pop('sources', {}))
|
|
184
|
+
|
|
185
|
+
if cap_doc:
|
|
186
|
+
conf['caches'] = caches(cap, conf['sources'], srs_grids=srs_grids)
|
|
187
|
+
if gpkg:
|
|
188
|
+
conf['caches'] = gpkg_dict['caches']
|
|
189
|
+
if overwrite:
|
|
190
|
+
conf['caches'] = update_config(conf['caches'], overwrite.pop('caches', {}))
|
|
191
|
+
|
|
192
|
+
if cap_doc:
|
|
193
|
+
conf['layers'] = layers(cap, conf['caches'])
|
|
194
|
+
if gpkg:
|
|
195
|
+
conf['layers'] = gpkg_dict['layers']
|
|
196
|
+
if overwrite:
|
|
197
|
+
conf['layers'] = update_config(conf['layers'], overwrite.pop('layers', {}))
|
|
198
|
+
|
|
199
|
+
if gpkg:
|
|
200
|
+
conf['grids'] = gpkg_dict['grids']
|
|
201
|
+
if overwrite:
|
|
202
|
+
conf = update_config(conf, overwrite)
|
|
203
|
+
|
|
204
|
+
seed_conf = {}
|
|
205
|
+
if cap_doc:
|
|
206
|
+
seed_conf['seeds'], seed_conf['cleanups'] = seeds(cap, conf['caches'])
|
|
207
|
+
if gpkg:
|
|
208
|
+
cap = None
|
|
209
|
+
seed_conf['seeds'], seed_conf['cleanups'] = seeds(cap, conf['caches'])
|
|
210
|
+
if overwrite_seed:
|
|
211
|
+
seed_conf = update_config(seed_conf, overwrite_seed)
|
|
212
|
+
|
|
213
|
+
if options.output:
|
|
214
|
+
with file_or_stdout(options.output) as f:
|
|
215
|
+
write_header(f, options.capabilities or options.geopackage)
|
|
216
|
+
yaml.dump(conf, f, default_flow_style=False, Dumper=MapProxyYAMLDumper)
|
|
217
|
+
if options.output_seed:
|
|
218
|
+
with file_or_stdout(options.output_seed) as f:
|
|
219
|
+
write_header(f, options.capabilities or options.geopackage)
|
|
220
|
+
yaml.dump(seed_conf, f, default_flow_style=False, Dumper=MapProxyYAMLDumper)
|
|
221
|
+
|
|
222
|
+
return 0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -:- encoding: utf-8 -:-
|
|
2
|
+
# This file is part of the MapProxy project.
|
|
3
|
+
# Copyright (C) 2013 Omniscale <http://omniscale.de>
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def caches(cap, sources, srs_grids):
|
|
19
|
+
caches = {}
|
|
20
|
+
for name, source in sources.items():
|
|
21
|
+
conf = for_source(name, source, srs_grids)
|
|
22
|
+
if not conf:
|
|
23
|
+
continue
|
|
24
|
+
caches[name[:-len('_wms')] + '_cache'] = conf
|
|
25
|
+
|
|
26
|
+
return caches
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def for_source(name, source, srs_grids):
|
|
30
|
+
cache = {
|
|
31
|
+
'sources': [name]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
grids = []
|
|
35
|
+
for srs in source['supported_srs']:
|
|
36
|
+
if srs in srs_grids:
|
|
37
|
+
grids.append(srs_grids[srs])
|
|
38
|
+
|
|
39
|
+
if not grids:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
cache['grids'] = grids
|
|
43
|
+
|
|
44
|
+
return cache
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import yaml
|
|
2
|
+
import sqlite3
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def conf_from_geopackage(geopackage_file, output_file=None):
|
|
7
|
+
conf = get_geopackage_configuration_dict(geopackage_file)
|
|
8
|
+
yaml.SafeDumper.add_representer(
|
|
9
|
+
type(None),
|
|
10
|
+
lambda dumper, value: dumper.represent_scalar(u'tag:yaml.org,2002:null', '')
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
if output_file:
|
|
14
|
+
with open('data.yml', 'w') as outfile:
|
|
15
|
+
outfile.write(yaml.safe_dump(conf, default_flow_style=False))
|
|
16
|
+
else:
|
|
17
|
+
print(yaml.safe_dump(get_geopackage_configuration_dict(geopackage_file), default_flow_style=False))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_gpkg_contents(geopackage_file, data_type='tiles'):
|
|
21
|
+
"""
|
|
22
|
+
:param geopackage_file: Path to the geopackage file.
|
|
23
|
+
:param data_type: The type of layer to return tiles or features.
|
|
24
|
+
:return: One or more tuples with the table_name, min_x, min_y, max_x, max_y, srs_id for each layer in the
|
|
25
|
+
geopackage.
|
|
26
|
+
"""
|
|
27
|
+
with sqlite3.connect(geopackage_file) as db:
|
|
28
|
+
cur = db.execute(
|
|
29
|
+
"SELECT table_name, data_type, identifier, description, last_change, min_x, min_y, max_x, "
|
|
30
|
+
"max_y, srs_id FROM gpkg_contents WHERE data_type = ?", (data_type,))
|
|
31
|
+
return cur.fetchall()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_table_organization_coordsys_id(geopackage_file, srs_id):
|
|
35
|
+
"""
|
|
36
|
+
:param geopackage_file: Path to the geopackage file.
|
|
37
|
+
:param srs_id: The srs_id which is the key value in the organization_coordsys_id.
|
|
38
|
+
:return: An integer representing the organization_coordsys_id as an EPSG code.
|
|
39
|
+
"""
|
|
40
|
+
with sqlite3.connect(geopackage_file) as db:
|
|
41
|
+
cur = db.execute("SELECT organization_coordsys_id FROM gpkg_spatial_ref_sys WHERE srs_id = ?", (srs_id,))
|
|
42
|
+
results = cur.fetchone()
|
|
43
|
+
if results:
|
|
44
|
+
return results[0]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_table_tile_matrix(geopackage_file, table_name):
|
|
48
|
+
"""
|
|
49
|
+
:param geopackage_file: Path to the geopackage file.
|
|
50
|
+
:param table_name: The table_name associated with the tile_matrix data.
|
|
51
|
+
:return: A tuple of tuple containing zoom_level, matrix_width, matrix_height, tile_width, tile_height, pixel_x_size,
|
|
52
|
+
pixel_y_size for each zoom_level.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
with sqlite3.connect(geopackage_file) as db:
|
|
56
|
+
cur = db.execute("SELECT zoom_level,"
|
|
57
|
+
"matrix_width, "
|
|
58
|
+
"matrix_height, "
|
|
59
|
+
"tile_width, "
|
|
60
|
+
"tile_height, "
|
|
61
|
+
"pixel_x_size, "
|
|
62
|
+
"pixel_y_size "
|
|
63
|
+
"FROM gpkg_tile_matrix WHERE table_name = ?"
|
|
64
|
+
"ORDER BY zoom_level", (table_name,))
|
|
65
|
+
return cur.fetchall()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_estimated_tile_res_ratio(tile_matrix):
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
:param tile_matrix: A tuple of tuples representing the geopackage tile matrix (without the table name included).
|
|
72
|
+
:return: The rate at which the resolution increases between levels.
|
|
73
|
+
"""
|
|
74
|
+
default_res_factor = 2
|
|
75
|
+
if len(tile_matrix) < 2:
|
|
76
|
+
return default_res_factor
|
|
77
|
+
layer = tile_matrix[0]
|
|
78
|
+
next_layer = tile_matrix[1]
|
|
79
|
+
return (layer[6]/next_layer[6])/(next_layer[0]-layer[0])
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_res_table(tile_matrix):
|
|
83
|
+
res_ratio = get_estimated_tile_res_ratio(tile_matrix)
|
|
84
|
+
res_table = []
|
|
85
|
+
if tile_matrix[0][0] == 0:
|
|
86
|
+
first_level_res = tile_matrix[0][5]
|
|
87
|
+
else:
|
|
88
|
+
first_level_res = tile_matrix[0][5]*(res_ratio**tile_matrix[0][0])
|
|
89
|
+
tile_matrix_set = {}
|
|
90
|
+
for level in tile_matrix:
|
|
91
|
+
tile_matrix_set[level[0]] = level
|
|
92
|
+
if not tile_matrix_set.get(0):
|
|
93
|
+
res_table += [first_level_res]
|
|
94
|
+
else:
|
|
95
|
+
res_table += [tile_matrix_set.get(0)[5]]
|
|
96
|
+
for level in range(1, 19):
|
|
97
|
+
res = tile_matrix_set.get(level)
|
|
98
|
+
if not res:
|
|
99
|
+
res_table += [first_level_res/(res_ratio**level)]
|
|
100
|
+
else:
|
|
101
|
+
res_table += [res[5]]
|
|
102
|
+
return res_table
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_geopackage_configuration_dict(geopackage_file):
|
|
106
|
+
gpkg_contents = get_gpkg_contents(geopackage_file, data_type='tiles')
|
|
107
|
+
conf = {'grids': {},
|
|
108
|
+
'caches': {},
|
|
109
|
+
'layers': [],
|
|
110
|
+
'services': {'demo': None,
|
|
111
|
+
'tms': {'use_grid_names': True, 'origin': 'nw'},
|
|
112
|
+
'kml': {'use_grid_names': True},
|
|
113
|
+
'wmts': None,
|
|
114
|
+
'wms': None}}
|
|
115
|
+
|
|
116
|
+
for gpkg_content in gpkg_contents:
|
|
117
|
+
table_name = str(gpkg_content[0])
|
|
118
|
+
tile_matrix = get_table_tile_matrix(geopackage_file, table_name)
|
|
119
|
+
srs = get_table_organization_coordsys_id(geopackage_file, gpkg_content[9])
|
|
120
|
+
if not tile_matrix or not srs:
|
|
121
|
+
continue
|
|
122
|
+
conf['grids']['{0}_{1}'.format(table_name, srs)] = {'srs': 'EPSG:{0}'.format(srs),
|
|
123
|
+
'tile_size': [tile_matrix[0][3], tile_matrix[0][4]],
|
|
124
|
+
'bbox': [gpkg_content[5],
|
|
125
|
+
gpkg_content[6],
|
|
126
|
+
gpkg_content[7],
|
|
127
|
+
gpkg_content[8]],
|
|
128
|
+
'res': get_res_table(tile_matrix),
|
|
129
|
+
'origin': 'nw'}
|
|
130
|
+
conf['caches']['{0}_cache'.format(table_name)] = {'sources': [],
|
|
131
|
+
'grids': ['{0}_{1}'.format(table_name, srs)],
|
|
132
|
+
'cache': {'type': 'geopackage',
|
|
133
|
+
'filename': os.path.abspath(geopackage_file),
|
|
134
|
+
'table_name': table_name}}
|
|
135
|
+
conf['layers'] += [{'name': table_name, 'title': table_name, 'sources': ['{0}_cache'.format(table_name)]}]
|
|
136
|
+
return conf
|