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/seed/cleanup.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
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
|
+
from __future__ import print_function
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
from itertools import zip_longest
|
|
20
|
+
|
|
21
|
+
from mapproxy.seed.util import format_cleanup_task
|
|
22
|
+
from mapproxy.util.fs import cleanup_directory
|
|
23
|
+
from mapproxy.seed.seeder import (
|
|
24
|
+
TileWorkerPool, TileWalker, TileCleanupWorker,
|
|
25
|
+
SeedProgress,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def cleanup(tasks, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0,
|
|
30
|
+
verbose=True, progress_logger=None):
|
|
31
|
+
for task in tasks:
|
|
32
|
+
print(format_cleanup_task(task))
|
|
33
|
+
|
|
34
|
+
if task.coverage is False:
|
|
35
|
+
continue
|
|
36
|
+
|
|
37
|
+
# seed_progress for tilewalker cleanup
|
|
38
|
+
seed_progress = None
|
|
39
|
+
# cleanup_progress for os.walk based cleanup
|
|
40
|
+
cleanup_progress = None
|
|
41
|
+
if progress_logger and progress_logger.progress_store:
|
|
42
|
+
progress_logger.current_task_id = task.id
|
|
43
|
+
start_progress = progress_logger.progress_store.get(task.id)
|
|
44
|
+
seed_progress = SeedProgress(old_progress_identifier=start_progress)
|
|
45
|
+
cleanup_progress = DirectoryCleanupProgress(old_dir=start_progress)
|
|
46
|
+
|
|
47
|
+
if task.complete_extent:
|
|
48
|
+
if callable(getattr(task.tile_manager.cache, 'level_location', None)):
|
|
49
|
+
simple_cleanup(task, dry_run=dry_run, progress_logger=progress_logger,
|
|
50
|
+
cleanup_progress=cleanup_progress)
|
|
51
|
+
task.tile_manager.cleanup()
|
|
52
|
+
continue
|
|
53
|
+
elif callable(getattr(task.tile_manager.cache, 'remove_level_tiles_before', None)):
|
|
54
|
+
cache_cleanup(task, dry_run=dry_run, progress_logger=progress_logger)
|
|
55
|
+
task.tile_manager.cleanup()
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
tilewalker_cleanup(task, dry_run=dry_run, concurrency=concurrency,
|
|
59
|
+
skip_geoms_for_last_levels=skip_geoms_for_last_levels,
|
|
60
|
+
progress_logger=progress_logger,
|
|
61
|
+
seed_progress=seed_progress,
|
|
62
|
+
)
|
|
63
|
+
task.tile_manager.cleanup()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def simple_cleanup(task, dry_run, progress_logger=None, cleanup_progress=None):
|
|
67
|
+
"""
|
|
68
|
+
Cleanup cache level on file system level.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
for level in task.levels:
|
|
72
|
+
level_dir = task.tile_manager.cache.level_location(level)
|
|
73
|
+
if dry_run:
|
|
74
|
+
def file_handler(filename):
|
|
75
|
+
print('removing ' + filename)
|
|
76
|
+
else:
|
|
77
|
+
file_handler = None
|
|
78
|
+
if progress_logger:
|
|
79
|
+
progress_logger.log_message('removing old tiles in ' + normpath(level_dir))
|
|
80
|
+
if progress_logger.progress_store:
|
|
81
|
+
cleanup_progress.step_dir(level_dir)
|
|
82
|
+
if cleanup_progress.already_processed():
|
|
83
|
+
continue
|
|
84
|
+
progress_logger.progress_store.add(
|
|
85
|
+
task.id,
|
|
86
|
+
cleanup_progress.current_progress_identifier(),
|
|
87
|
+
)
|
|
88
|
+
progress_logger.progress_store.write()
|
|
89
|
+
|
|
90
|
+
cleanup_directory(level_dir, task.remove_timestamp,
|
|
91
|
+
file_handler=file_handler, remove_empty_dirs=True)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def cache_cleanup(task, dry_run, progress_logger=None):
|
|
95
|
+
for level in task.levels:
|
|
96
|
+
if progress_logger:
|
|
97
|
+
progress_logger.log_message('removing old tiles for level %s' % level)
|
|
98
|
+
if not dry_run:
|
|
99
|
+
task.tile_manager.cache.remove_level_tiles_before(level, task.remove_timestamp)
|
|
100
|
+
task.tile_manager.cleanup()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def normpath(path):
|
|
104
|
+
# relpath doesn't support UNC
|
|
105
|
+
if path.startswith('\\'):
|
|
106
|
+
return path
|
|
107
|
+
|
|
108
|
+
path = os.path.relpath(path)
|
|
109
|
+
|
|
110
|
+
if path.startswith('../../'):
|
|
111
|
+
path = os.path.abspath(path)
|
|
112
|
+
return path
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def tilewalker_cleanup(task, dry_run, concurrency, skip_geoms_for_last_levels,
|
|
116
|
+
progress_logger=None, seed_progress=None):
|
|
117
|
+
"""
|
|
118
|
+
Cleanup tiles with tile traversal.
|
|
119
|
+
"""
|
|
120
|
+
task.tile_manager._expire_timestamp = task.remove_timestamp
|
|
121
|
+
task.tile_manager.minimize_meta_requests = False
|
|
122
|
+
tile_worker_pool = TileWorkerPool(task, TileCleanupWorker, progress_logger=progress_logger,
|
|
123
|
+
dry_run=dry_run, size=concurrency)
|
|
124
|
+
tile_walker = TileWalker(task, tile_worker_pool, handle_stale=True,
|
|
125
|
+
work_on_metatiles=False, progress_logger=progress_logger,
|
|
126
|
+
skip_geoms_for_last_levels=skip_geoms_for_last_levels,
|
|
127
|
+
seed_progress=seed_progress)
|
|
128
|
+
try:
|
|
129
|
+
tile_walker.walk()
|
|
130
|
+
except KeyboardInterrupt:
|
|
131
|
+
tile_worker_pool.stop(force=True)
|
|
132
|
+
raise
|
|
133
|
+
finally:
|
|
134
|
+
tile_worker_pool.stop()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class DirectoryCleanupProgress(object):
|
|
138
|
+
def __init__(self, old_dir=None):
|
|
139
|
+
self.old_dir = old_dir
|
|
140
|
+
self.current_dir = None
|
|
141
|
+
|
|
142
|
+
def step_dir(self, dir):
|
|
143
|
+
self.current_dir = dir
|
|
144
|
+
|
|
145
|
+
def already_processed(self):
|
|
146
|
+
return self.can_skip(self.old_dir, self.current_dir)
|
|
147
|
+
|
|
148
|
+
def current_progress_identifier(self):
|
|
149
|
+
if self.already_processed() or self.current_dir is None:
|
|
150
|
+
return self.old_dir
|
|
151
|
+
return self.current_dir
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def can_skip(old_dir, current_dir):
|
|
155
|
+
"""
|
|
156
|
+
Return True if the `current_dir` is before `old_dir` when compared
|
|
157
|
+
lexicographic.
|
|
158
|
+
|
|
159
|
+
>>> DirectoryCleanupProgress.can_skip(None, '/00')
|
|
160
|
+
False
|
|
161
|
+
>>> DirectoryCleanupProgress.can_skip(None, '/00/000/000')
|
|
162
|
+
False
|
|
163
|
+
|
|
164
|
+
>>> DirectoryCleanupProgress.can_skip('/01/000/001', '/00')
|
|
165
|
+
True
|
|
166
|
+
>>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/000')
|
|
167
|
+
True
|
|
168
|
+
>>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/000/000')
|
|
169
|
+
True
|
|
170
|
+
>>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/001')
|
|
171
|
+
False
|
|
172
|
+
>>> DirectoryCleanupProgress.can_skip('/01/000/001', '/01/000/001/000')
|
|
173
|
+
False
|
|
174
|
+
"""
|
|
175
|
+
if old_dir is None:
|
|
176
|
+
return False
|
|
177
|
+
if current_dir is None:
|
|
178
|
+
return False
|
|
179
|
+
for old, current in zip_longest(old_dir.split(os.path.sep), current_dir.split(os.path.sep), fillvalue=None):
|
|
180
|
+
if old is None:
|
|
181
|
+
return False
|
|
182
|
+
if current is None:
|
|
183
|
+
return False
|
|
184
|
+
if old < current:
|
|
185
|
+
return False
|
|
186
|
+
if old > current:
|
|
187
|
+
return True
|
|
188
|
+
return False
|
|
189
|
+
|
|
190
|
+
def running(self):
|
|
191
|
+
return True
|
mapproxy/seed/config.py
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2011 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
|
+
from __future__ import print_function
|
|
17
|
+
import logging
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
import time
|
|
22
|
+
import operator
|
|
23
|
+
from functools import reduce
|
|
24
|
+
|
|
25
|
+
from mapproxy.cache.dummy import DummyCache
|
|
26
|
+
from mapproxy.config import abspath
|
|
27
|
+
from mapproxy.config.loader import ConfigurationError
|
|
28
|
+
from mapproxy.config.coverage import load_coverage
|
|
29
|
+
from mapproxy.srs import SRS, TransformationError
|
|
30
|
+
from mapproxy.util.py import memoize
|
|
31
|
+
from mapproxy.util.times import timestamp_from_isodate, timestamp_before
|
|
32
|
+
from mapproxy.util.coverage import MultiCoverage, BBOXCoverage, GeomCoverage
|
|
33
|
+
from mapproxy.util.geom import GeometryError, EmptyGeometryError, CoverageReadError
|
|
34
|
+
from mapproxy.util.yaml import load_yaml_file, YAMLError
|
|
35
|
+
from mapproxy.seed.util import bidict
|
|
36
|
+
from mapproxy.seed.seeder import SeedTask, CleanupTask
|
|
37
|
+
from mapproxy.seed.spec import validate_seed_conf
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class SeedConfigurationError(ConfigurationError):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class EmptyCoverageError(Exception):
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
log = logging.getLogger('mapproxy.seed.config')
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def load_seed_tasks_conf(seed_conf_filename, mapproxy_conf):
|
|
52
|
+
try:
|
|
53
|
+
conf = load_yaml_file(seed_conf_filename)
|
|
54
|
+
except YAMLError as ex:
|
|
55
|
+
raise SeedConfigurationError(ex)
|
|
56
|
+
|
|
57
|
+
if 'views' in conf:
|
|
58
|
+
# TODO: deprecate old config
|
|
59
|
+
seed_conf = LegacySeedingConfiguration(conf, mapproxy_conf=mapproxy_conf)
|
|
60
|
+
else:
|
|
61
|
+
errors, informal_only = validate_seed_conf(conf)
|
|
62
|
+
for error in errors:
|
|
63
|
+
log.warning(error)
|
|
64
|
+
if not informal_only:
|
|
65
|
+
raise SeedConfigurationError('invalid configuration')
|
|
66
|
+
seed_conf = SeedingConfiguration(conf, mapproxy_conf=mapproxy_conf)
|
|
67
|
+
return seed_conf
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class LegacySeedingConfiguration(object):
|
|
71
|
+
"""
|
|
72
|
+
Read old seed.yaml configuration (with seed and views).
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def __init__(self, seed_conf, mapproxy_conf):
|
|
76
|
+
self.conf = seed_conf
|
|
77
|
+
self.mapproxy_conf = mapproxy_conf
|
|
78
|
+
self.grids = bidict((name, grid_conf.tile_grid()) for name, grid_conf in self.mapproxy_conf.grids.items())
|
|
79
|
+
self.seed_tasks = []
|
|
80
|
+
self.cleanup_tasks = []
|
|
81
|
+
self._init_tasks()
|
|
82
|
+
|
|
83
|
+
def _init_tasks(self):
|
|
84
|
+
for cache_name, options in self.conf['seeds'].items():
|
|
85
|
+
remove_before = None
|
|
86
|
+
if 'remove_before' in options:
|
|
87
|
+
remove_before = before_timestamp_from_options(options['remove_before'])
|
|
88
|
+
try:
|
|
89
|
+
caches = self.mapproxy_conf.caches[cache_name].caches()
|
|
90
|
+
except KeyError:
|
|
91
|
+
print('error: cache %s not found. available caches: %s' % (
|
|
92
|
+
cache_name, ','.join(self.mapproxy_conf.caches.keys())), file=sys.stderr)
|
|
93
|
+
return
|
|
94
|
+
caches = dict((grid, tile_mgr) for grid, extent, tile_mgr in caches)
|
|
95
|
+
for view in options['views']:
|
|
96
|
+
view_conf = self.conf['views'][view]
|
|
97
|
+
coverage = load_coverage(view_conf)
|
|
98
|
+
|
|
99
|
+
cache_srs = view_conf.get('srs', None)
|
|
100
|
+
if cache_srs is not None:
|
|
101
|
+
cache_srs = [SRS(s) for s in cache_srs]
|
|
102
|
+
|
|
103
|
+
level = view_conf.get('level', None)
|
|
104
|
+
assert len(level) == 2
|
|
105
|
+
|
|
106
|
+
for grid, tile_mgr in caches.items():
|
|
107
|
+
if cache_srs and grid.srs not in cache_srs:
|
|
108
|
+
continue
|
|
109
|
+
md = dict(name=view, cache_name=cache_name, grid_name=self.grids[grid])
|
|
110
|
+
levels = list(range(level[0], level[1]+1))
|
|
111
|
+
if coverage:
|
|
112
|
+
if isinstance(coverage, GeomCoverage) and coverage.geom.is_empty:
|
|
113
|
+
continue
|
|
114
|
+
seed_coverage = coverage.transform_to(grid.srs)
|
|
115
|
+
else:
|
|
116
|
+
seed_coverage = BBOXCoverage(grid.bbox, grid.srs)
|
|
117
|
+
|
|
118
|
+
self.seed_tasks.append(SeedTask(md, tile_mgr, levels, remove_before, seed_coverage))
|
|
119
|
+
|
|
120
|
+
if remove_before:
|
|
121
|
+
levels = list(range(grid.levels))
|
|
122
|
+
complete_extent = bool(coverage)
|
|
123
|
+
self.cleanup_tasks.append(CleanupTask(md, tile_mgr, levels, remove_before,
|
|
124
|
+
seed_coverage, complete_extent=complete_extent))
|
|
125
|
+
|
|
126
|
+
def seed_tasks_names(self):
|
|
127
|
+
return self.conf['seeds'].keys()
|
|
128
|
+
|
|
129
|
+
def cleanup_tasks_names(self):
|
|
130
|
+
return self.conf['seeds'].keys()
|
|
131
|
+
|
|
132
|
+
def seeds(self, names=None):
|
|
133
|
+
if names is None:
|
|
134
|
+
return self.seed_tasks
|
|
135
|
+
else:
|
|
136
|
+
return [t for t in self.seed_tasks if t.md['name'] in names]
|
|
137
|
+
|
|
138
|
+
def cleanups(self, names=None):
|
|
139
|
+
if names is None:
|
|
140
|
+
return self.cleanup_tasks
|
|
141
|
+
else:
|
|
142
|
+
return [t for t in self.cleanup_tasks if t.md['name'] in names]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class SeedingConfiguration(object):
|
|
146
|
+
def __init__(self, seed_conf, mapproxy_conf):
|
|
147
|
+
self.conf = seed_conf
|
|
148
|
+
self.mapproxy_conf = mapproxy_conf
|
|
149
|
+
self.grids = bidict((name, grid_conf.tile_grid()) for name, grid_conf in self.mapproxy_conf.grids.items())
|
|
150
|
+
|
|
151
|
+
@memoize
|
|
152
|
+
def coverage(self, name):
|
|
153
|
+
coverage_conf = (self.conf.get('coverages') or {}).get(name)
|
|
154
|
+
if coverage_conf is None:
|
|
155
|
+
raise SeedConfigurationError('coverage %s not found. available coverages: %s' % (
|
|
156
|
+
name, ','.join((self.conf.get('coverages') or {}).keys())))
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
coverage = load_coverage(coverage_conf)
|
|
160
|
+
except CoverageReadError as ex:
|
|
161
|
+
raise SeedConfigurationError("can't load coverage '%s'. %s" % (name, ex))
|
|
162
|
+
except GeometryError as ex:
|
|
163
|
+
raise SeedConfigurationError("invalid geometry in coverage '%s'. %s" % (name, ex))
|
|
164
|
+
except EmptyGeometryError as ex:
|
|
165
|
+
raise EmptyCoverageError("coverage '%s' contains no geometries. %s" % (name, ex))
|
|
166
|
+
|
|
167
|
+
# without extend we have an empty coverage
|
|
168
|
+
if not coverage.extent.llbbox:
|
|
169
|
+
raise EmptyCoverageError("coverage '%s' contains no geometries." % name)
|
|
170
|
+
return coverage
|
|
171
|
+
|
|
172
|
+
def cache(self, cache_name):
|
|
173
|
+
cache = {}
|
|
174
|
+
if cache_name not in self.mapproxy_conf.caches:
|
|
175
|
+
raise SeedConfigurationError('cache %s not found. available caches: %s' % (
|
|
176
|
+
cache_name, ','.join(self.mapproxy_conf.caches.keys())))
|
|
177
|
+
for tile_grid, extent, tile_mgr in self.mapproxy_conf.caches[cache_name].caches():
|
|
178
|
+
if isinstance(tile_mgr.cache, DummyCache):
|
|
179
|
+
raise SeedConfigurationError('can\'t seed cache %s (disable_storage: true)' %
|
|
180
|
+
cache_name)
|
|
181
|
+
grid_name = self.grids[tile_grid]
|
|
182
|
+
cache[grid_name] = tile_mgr
|
|
183
|
+
return cache
|
|
184
|
+
|
|
185
|
+
def seed_tasks_names(self):
|
|
186
|
+
seeds = self.conf.get('seeds') or {}
|
|
187
|
+
if seeds:
|
|
188
|
+
return seeds.keys()
|
|
189
|
+
return []
|
|
190
|
+
|
|
191
|
+
def cleanup_tasks_names(self):
|
|
192
|
+
cleanups = self.conf.get('cleanups') or {}
|
|
193
|
+
if cleanups:
|
|
194
|
+
return cleanups.keys()
|
|
195
|
+
return []
|
|
196
|
+
|
|
197
|
+
def seeds(self, names=None):
|
|
198
|
+
"""
|
|
199
|
+
Return seed tasks.
|
|
200
|
+
"""
|
|
201
|
+
tasks = []
|
|
202
|
+
if names is None:
|
|
203
|
+
names = (self.conf.get('seeds') or {}).keys()
|
|
204
|
+
|
|
205
|
+
for seed_name in names:
|
|
206
|
+
seed_conf = self.conf['seeds'][seed_name]
|
|
207
|
+
seed_conf = SeedConfiguration(seed_name, seed_conf, self)
|
|
208
|
+
for task in seed_conf.seed_tasks():
|
|
209
|
+
tasks.append(task)
|
|
210
|
+
return tasks
|
|
211
|
+
|
|
212
|
+
def cleanups(self, names=None):
|
|
213
|
+
"""
|
|
214
|
+
Return cleanup tasks.
|
|
215
|
+
"""
|
|
216
|
+
tasks = []
|
|
217
|
+
if names is None:
|
|
218
|
+
names = (self.conf.get('cleanups') or {}).keys()
|
|
219
|
+
|
|
220
|
+
for cleanup_name in names:
|
|
221
|
+
cleanup_conf = self.conf['cleanups'][cleanup_name]
|
|
222
|
+
cleanup_conf = CleanupConfiguration(cleanup_name, cleanup_conf, self)
|
|
223
|
+
for task in cleanup_conf.cleanup_tasks():
|
|
224
|
+
tasks.append(task)
|
|
225
|
+
return tasks
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class ConfigurationBase(object):
|
|
229
|
+
def __init__(self, name, conf, seeding_conf):
|
|
230
|
+
self.name = name
|
|
231
|
+
self.conf = conf
|
|
232
|
+
self.seeding_conf = seeding_conf
|
|
233
|
+
|
|
234
|
+
self.coverage = self._coverages()
|
|
235
|
+
self.caches = self._caches()
|
|
236
|
+
self.grids = self._grids(self.caches)
|
|
237
|
+
self.levels = levels_from_options(conf)
|
|
238
|
+
|
|
239
|
+
def _coverages(self):
|
|
240
|
+
coverage = None
|
|
241
|
+
if 'coverages' in self.conf:
|
|
242
|
+
try:
|
|
243
|
+
coverages = [self.seeding_conf.coverage(c) for c in self.conf.get('coverages', {})]
|
|
244
|
+
except EmptyCoverageError:
|
|
245
|
+
return False
|
|
246
|
+
if len(coverages) == 1:
|
|
247
|
+
coverage = coverages[0]
|
|
248
|
+
else:
|
|
249
|
+
coverage = MultiCoverage(coverages)
|
|
250
|
+
return coverage
|
|
251
|
+
|
|
252
|
+
def _grids(self, caches):
|
|
253
|
+
grids = []
|
|
254
|
+
|
|
255
|
+
if 'grids' in self.conf:
|
|
256
|
+
# grids available for all caches
|
|
257
|
+
available_grids = reduce(operator.and_, (set(cache) for cache in caches.values()))
|
|
258
|
+
for grid_name in self.conf['grids']:
|
|
259
|
+
if grid_name not in available_grids:
|
|
260
|
+
raise SeedConfigurationError('%s not defined for caches' % grid_name)
|
|
261
|
+
grids.append(grid_name)
|
|
262
|
+
else:
|
|
263
|
+
# check that all caches have the same grids configured
|
|
264
|
+
last = []
|
|
265
|
+
for cache_grids in {cache.keys() for cache in caches.values()}:
|
|
266
|
+
if not last:
|
|
267
|
+
last = cache_grids
|
|
268
|
+
else:
|
|
269
|
+
if last != cache_grids:
|
|
270
|
+
raise SeedConfigurationError('caches in same seed task require identical grids')
|
|
271
|
+
grids = list(last or [])
|
|
272
|
+
return grids
|
|
273
|
+
|
|
274
|
+
def _caches(self):
|
|
275
|
+
"""
|
|
276
|
+
Returns a dictionary with all caches for this seed.
|
|
277
|
+
|
|
278
|
+
e.g.: {'seed1': {'grid1': tilemanager1, 'grid2': tilemanager2}}
|
|
279
|
+
"""
|
|
280
|
+
caches = {}
|
|
281
|
+
for cache_name in self.conf.get('caches', []):
|
|
282
|
+
caches[cache_name] = self.seeding_conf.cache(cache_name)
|
|
283
|
+
return caches
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class SeedConfiguration(ConfigurationBase):
|
|
287
|
+
def __init__(self, name, conf, seeding_conf):
|
|
288
|
+
ConfigurationBase.__init__(self, name, conf, seeding_conf)
|
|
289
|
+
|
|
290
|
+
self.refresh_timestamp = None
|
|
291
|
+
if 'refresh_before' in self.conf:
|
|
292
|
+
self.refresh_timestamp = before_timestamp_from_options(self.conf['refresh_before'])
|
|
293
|
+
|
|
294
|
+
def seed_tasks(self):
|
|
295
|
+
for grid_name in self.grids:
|
|
296
|
+
for cache_name, cache in self.caches.items():
|
|
297
|
+
tile_manager = cache[grid_name]
|
|
298
|
+
grid = self.seeding_conf.grids[grid_name]
|
|
299
|
+
if self.coverage is False:
|
|
300
|
+
coverage = False
|
|
301
|
+
elif self.coverage:
|
|
302
|
+
coverage = self.coverage.transform_to(grid.srs)
|
|
303
|
+
else:
|
|
304
|
+
coverage = BBOXCoverage(grid.bbox, grid.srs)
|
|
305
|
+
|
|
306
|
+
try:
|
|
307
|
+
if coverage is not False:
|
|
308
|
+
coverage.extent.llbbox
|
|
309
|
+
except TransformationError:
|
|
310
|
+
raise SeedConfigurationError('%s: coverage transformation error' % self.name)
|
|
311
|
+
|
|
312
|
+
if self.levels:
|
|
313
|
+
levels = self.levels.for_grid(grid)
|
|
314
|
+
else:
|
|
315
|
+
levels = list(range(0, grid.levels))
|
|
316
|
+
|
|
317
|
+
if not tile_manager.cache.supports_timestamp:
|
|
318
|
+
if self.refresh_timestamp:
|
|
319
|
+
# remove everything
|
|
320
|
+
self.refresh_timestamp = 0
|
|
321
|
+
|
|
322
|
+
md = dict(name=self.name, cache_name=cache_name, grid_name=grid_name)
|
|
323
|
+
|
|
324
|
+
if tile_manager.rescale_tiles:
|
|
325
|
+
if tile_manager.rescale_tiles > 0:
|
|
326
|
+
levels = levels[::-1]
|
|
327
|
+
for level in levels:
|
|
328
|
+
yield SeedTask(md, tile_manager, [level], self.refresh_timestamp, coverage)
|
|
329
|
+
else:
|
|
330
|
+
yield SeedTask(md, tile_manager, levels, self.refresh_timestamp, coverage)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class CleanupConfiguration(ConfigurationBase):
|
|
334
|
+
def __init__(self, name, conf, seeding_conf):
|
|
335
|
+
ConfigurationBase.__init__(self, name, conf, seeding_conf)
|
|
336
|
+
self.init_time = time.time()
|
|
337
|
+
|
|
338
|
+
if self.conf.get('remove_all') is True:
|
|
339
|
+
self.remove_timestamp = 0
|
|
340
|
+
elif 'remove_before' in self.conf:
|
|
341
|
+
self.remove_timestamp = before_timestamp_from_options(self.conf['remove_before'])
|
|
342
|
+
else:
|
|
343
|
+
# use now as remove_before date. this should not remove
|
|
344
|
+
# fresh seeded tiles, since this should be configured before seeding
|
|
345
|
+
self.remove_timestamp = self.init_time
|
|
346
|
+
|
|
347
|
+
def cleanup_tasks(self):
|
|
348
|
+
for grid_name in self.grids:
|
|
349
|
+
for cache_name, cache in self.caches.items():
|
|
350
|
+
tile_manager = cache[grid_name]
|
|
351
|
+
grid = self.seeding_conf.grids[grid_name]
|
|
352
|
+
if self.coverage is False:
|
|
353
|
+
coverage = False
|
|
354
|
+
complete_extent = False
|
|
355
|
+
elif self.coverage:
|
|
356
|
+
coverage = self.coverage.transform_to(grid.srs)
|
|
357
|
+
complete_extent = False
|
|
358
|
+
else:
|
|
359
|
+
coverage = BBOXCoverage(grid.bbox, grid.srs)
|
|
360
|
+
complete_extent = True
|
|
361
|
+
|
|
362
|
+
try:
|
|
363
|
+
if coverage is not False:
|
|
364
|
+
coverage.extent.llbbox
|
|
365
|
+
except TransformationError:
|
|
366
|
+
raise SeedConfigurationError('%s: coverage transformation error' % self.name)
|
|
367
|
+
|
|
368
|
+
if self.levels:
|
|
369
|
+
levels = self.levels.for_grid(grid)
|
|
370
|
+
else:
|
|
371
|
+
levels = list(range(0, grid.levels))
|
|
372
|
+
|
|
373
|
+
if not tile_manager.cache.supports_timestamp:
|
|
374
|
+
# for caches without timestamp support (like MBTiles)
|
|
375
|
+
if self.remove_timestamp is self.init_time or self.remove_timestamp == 0:
|
|
376
|
+
# remove everything
|
|
377
|
+
self.remove_timestamp = 0
|
|
378
|
+
else:
|
|
379
|
+
raise SeedConfigurationError(
|
|
380
|
+
"cleanup does not support remove_before for '%s'"
|
|
381
|
+
" because cache '%s' does not support timestamps" % (self.name, cache_name))
|
|
382
|
+
md = dict(name=self.name, cache_name=cache_name, grid_name=grid_name)
|
|
383
|
+
yield CleanupTask(md, tile_manager, levels, self.remove_timestamp,
|
|
384
|
+
coverage=coverage, complete_extent=complete_extent)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def levels_from_options(conf):
|
|
388
|
+
levels = conf.get('levels')
|
|
389
|
+
if levels:
|
|
390
|
+
if isinstance(levels, list):
|
|
391
|
+
return LevelsList(levels)
|
|
392
|
+
from_level = levels.get('from')
|
|
393
|
+
to_level = levels.get('to')
|
|
394
|
+
return LevelsRange((from_level, to_level))
|
|
395
|
+
resolutions = conf.get('resolutions')
|
|
396
|
+
if resolutions:
|
|
397
|
+
if isinstance(resolutions, list):
|
|
398
|
+
return LevelsResolutionList(resolutions)
|
|
399
|
+
from_res = resolutions.get('from')
|
|
400
|
+
to_res = resolutions.get('to')
|
|
401
|
+
return LevelsResolutionRange((from_res, to_res))
|
|
402
|
+
return None
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def before_timestamp_from_options(conf):
|
|
406
|
+
"""
|
|
407
|
+
>>> import time
|
|
408
|
+
>>> t = before_timestamp_from_options({'hours': 4})
|
|
409
|
+
>>> time.time() - t - 4 * 60 * 60 < 1
|
|
410
|
+
True
|
|
411
|
+
"""
|
|
412
|
+
if 'time' in conf:
|
|
413
|
+
try:
|
|
414
|
+
return timestamp_from_isodate(conf['time'])
|
|
415
|
+
except ValueError:
|
|
416
|
+
raise SeedConfigurationError(
|
|
417
|
+
"can't parse time '%s'. should be ISO time string" % (conf["time"], ))
|
|
418
|
+
if 'mtime' in conf:
|
|
419
|
+
datasource = abspath(conf['mtime'])
|
|
420
|
+
try:
|
|
421
|
+
return os.path.getmtime(datasource)
|
|
422
|
+
except OSError as ex:
|
|
423
|
+
raise SeedConfigurationError(
|
|
424
|
+
"can't parse last modified time from file '%s'." % (datasource, ), ex)
|
|
425
|
+
deltas = {}
|
|
426
|
+
for delta_type in ('weeks', 'days', 'hours', 'minutes', 'seconds'):
|
|
427
|
+
deltas[delta_type] = conf.get(delta_type, 0)
|
|
428
|
+
return timestamp_before(**deltas)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class LevelsList(object):
|
|
432
|
+
def __init__(self, levels=None):
|
|
433
|
+
self.levels = levels
|
|
434
|
+
|
|
435
|
+
def for_grid(self, grid):
|
|
436
|
+
uniqe_valid_levels = set(x for x in self.levels if 0 <= x <= (grid.levels-1))
|
|
437
|
+
return sorted(uniqe_valid_levels)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
class LevelsRange(object):
|
|
441
|
+
def __init__(self, level_range=None):
|
|
442
|
+
self.level_range = level_range
|
|
443
|
+
|
|
444
|
+
def for_grid(self, grid):
|
|
445
|
+
start, stop = self.level_range
|
|
446
|
+
if start is None:
|
|
447
|
+
start = 0
|
|
448
|
+
if stop is None:
|
|
449
|
+
stop = 999
|
|
450
|
+
|
|
451
|
+
stop = min(stop, grid.levels-1)
|
|
452
|
+
|
|
453
|
+
return list(range(start, stop+1))
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class LevelsResolutionRange(object):
|
|
457
|
+
def __init__(self, res_range=None):
|
|
458
|
+
self.res_range = res_range
|
|
459
|
+
|
|
460
|
+
def for_grid(self, grid):
|
|
461
|
+
start, stop = self.res_range
|
|
462
|
+
if start is None:
|
|
463
|
+
start = 0
|
|
464
|
+
else:
|
|
465
|
+
start = grid.closest_level(start)
|
|
466
|
+
|
|
467
|
+
if stop is None:
|
|
468
|
+
stop = grid.levels-1
|
|
469
|
+
else:
|
|
470
|
+
stop = grid.closest_level(stop)
|
|
471
|
+
|
|
472
|
+
return list(range(start, stop+1))
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
class LevelsResolutionList(object):
|
|
476
|
+
def __init__(self, resolutions=None):
|
|
477
|
+
self.resolutions = resolutions
|
|
478
|
+
|
|
479
|
+
def for_grid(self, grid):
|
|
480
|
+
levels = set(grid.closest_level(res) for res in self.resolutions)
|
|
481
|
+
return sorted(levels)
|