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/seeder.py
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2010, 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, division
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
from collections import deque
|
|
20
|
+
from contextlib import contextmanager
|
|
21
|
+
from itertools import zip_longest
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
import Queue
|
|
25
|
+
except ImportError:
|
|
26
|
+
import queue as Queue
|
|
27
|
+
|
|
28
|
+
from mapproxy.config import base_config
|
|
29
|
+
from mapproxy.grid import MetaGrid
|
|
30
|
+
from mapproxy.source import SourceError
|
|
31
|
+
from mapproxy.config import local_base_config
|
|
32
|
+
from mapproxy.util.lock import LockTimeout
|
|
33
|
+
from mapproxy.seed.util import format_seed_task
|
|
34
|
+
from mapproxy.seed.cachelock import DummyCacheLocker, CacheLockedError
|
|
35
|
+
|
|
36
|
+
from mapproxy.seed.util import (exp_backoff, limit_sub_bbox,
|
|
37
|
+
status_symbol, BackoffError)
|
|
38
|
+
|
|
39
|
+
import logging
|
|
40
|
+
log = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
NONE = 0
|
|
43
|
+
CONTAINS = -1
|
|
44
|
+
INTERSECTS = 1
|
|
45
|
+
|
|
46
|
+
# Decide whether to use multiprocessing or threading. multiprocessing should be faster but
|
|
47
|
+
# it is not well supported on all platforms. Especially regarding lambdas and anonymous
|
|
48
|
+
# function/classes which are used in proj.py for example.
|
|
49
|
+
#
|
|
50
|
+
# Since Python 3.8, MacOS uses a non-forking start method for multiprocessing which
|
|
51
|
+
# inhibits similar restrictions to Windows.
|
|
52
|
+
if sys.platform == 'win32' or (sys.platform == 'darwin' and sys.version_info >= (3, 8)):
|
|
53
|
+
import threading
|
|
54
|
+
proc_class = threading.Thread
|
|
55
|
+
queue_class = Queue.Queue
|
|
56
|
+
else:
|
|
57
|
+
import multiprocessing
|
|
58
|
+
proc_class = multiprocessing.Process
|
|
59
|
+
queue_class = multiprocessing.Queue
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TileWorkerPool(object):
|
|
63
|
+
"""
|
|
64
|
+
Manages multiple TileWorker.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def __init__(self, task, worker_class, size=2, dry_run=False, progress_logger=None):
|
|
68
|
+
self.tiles_queue = queue_class(size)
|
|
69
|
+
self.task = task
|
|
70
|
+
self.dry_run = dry_run
|
|
71
|
+
self.procs = []
|
|
72
|
+
self.progress_logger = progress_logger
|
|
73
|
+
conf = base_config()
|
|
74
|
+
for _ in range(size):
|
|
75
|
+
worker = worker_class(self.task, self.tiles_queue, conf)
|
|
76
|
+
worker.start()
|
|
77
|
+
self.procs.append(worker)
|
|
78
|
+
|
|
79
|
+
def process(self, tiles, progress):
|
|
80
|
+
if not self.dry_run:
|
|
81
|
+
while True:
|
|
82
|
+
try:
|
|
83
|
+
self.tiles_queue.put(tiles, timeout=5)
|
|
84
|
+
except Queue.Full:
|
|
85
|
+
alive = False
|
|
86
|
+
for proc in self.procs:
|
|
87
|
+
if proc.is_alive():
|
|
88
|
+
alive = True
|
|
89
|
+
break
|
|
90
|
+
if not alive:
|
|
91
|
+
log.warning('no workers left, stopping')
|
|
92
|
+
raise SeedInterrupted
|
|
93
|
+
continue
|
|
94
|
+
else:
|
|
95
|
+
break
|
|
96
|
+
|
|
97
|
+
if self.progress_logger:
|
|
98
|
+
self.progress_logger.log_step(progress)
|
|
99
|
+
|
|
100
|
+
def stop(self, force=False):
|
|
101
|
+
"""
|
|
102
|
+
Stop seed workers by sending None-sentinel and joining the workers.
|
|
103
|
+
|
|
104
|
+
:param force: Skip sending None-sentinel and join with a timeout.
|
|
105
|
+
For use when workers might be shutdown already by KeyboardInterrupt.
|
|
106
|
+
"""
|
|
107
|
+
if not force:
|
|
108
|
+
alives = 0
|
|
109
|
+
for proc in self.procs:
|
|
110
|
+
if proc.is_alive():
|
|
111
|
+
alives += 1
|
|
112
|
+
|
|
113
|
+
while alives:
|
|
114
|
+
# put None-sentinels to queue as long as we have workers alive
|
|
115
|
+
try:
|
|
116
|
+
self.tiles_queue.put(None, timeout=1)
|
|
117
|
+
alives -= 1
|
|
118
|
+
except Queue.Full:
|
|
119
|
+
alives = 0
|
|
120
|
+
for proc in self.procs:
|
|
121
|
+
if proc.is_alive():
|
|
122
|
+
alives += 1
|
|
123
|
+
|
|
124
|
+
if force:
|
|
125
|
+
timeout = 1.0
|
|
126
|
+
else:
|
|
127
|
+
timeout = None
|
|
128
|
+
for proc in self.procs:
|
|
129
|
+
proc.join(timeout)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class TileWorker(proc_class):
|
|
133
|
+
def __init__(self, task, tiles_queue, conf):
|
|
134
|
+
proc_class.__init__(self)
|
|
135
|
+
proc_class.daemon = True
|
|
136
|
+
self.task = task
|
|
137
|
+
self.tile_mgr = task.tile_manager
|
|
138
|
+
self.tiles_queue = tiles_queue
|
|
139
|
+
self.conf = conf
|
|
140
|
+
|
|
141
|
+
def run(self):
|
|
142
|
+
with local_base_config(self.conf):
|
|
143
|
+
try:
|
|
144
|
+
self.work_loop()
|
|
145
|
+
except KeyboardInterrupt:
|
|
146
|
+
return
|
|
147
|
+
except BackoffError:
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class TileSeedWorker(TileWorker):
|
|
152
|
+
def work_loop(self):
|
|
153
|
+
while True:
|
|
154
|
+
tiles = self.tiles_queue.get()
|
|
155
|
+
if tiles is None:
|
|
156
|
+
return
|
|
157
|
+
with self.tile_mgr.session():
|
|
158
|
+
exp_backoff(self.tile_mgr.load_tile_coords, args=(tiles,),
|
|
159
|
+
max_repeat=100, max_backoff=600,
|
|
160
|
+
exceptions=(SourceError, IOError), ignore_exceptions=(LockTimeout, ))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class TileCleanupWorker(TileWorker):
|
|
164
|
+
def work_loop(self):
|
|
165
|
+
while True:
|
|
166
|
+
tiles = self.tiles_queue.get()
|
|
167
|
+
if tiles is None:
|
|
168
|
+
return
|
|
169
|
+
with self.tile_mgr.session():
|
|
170
|
+
self.tile_mgr.remove_tile_coords(tiles)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class SeedProgress(object):
|
|
174
|
+
def __init__(self, old_progress_identifier=None):
|
|
175
|
+
self.progress = 0.0
|
|
176
|
+
self.level_progress_percentages = [1.0]
|
|
177
|
+
self.level_progresses = None
|
|
178
|
+
self.level_progresses_level = 0
|
|
179
|
+
self.progress_str_parts = []
|
|
180
|
+
self.old_level_progresses = old_progress_identifier
|
|
181
|
+
|
|
182
|
+
def step_forward(self, subtiles=1):
|
|
183
|
+
self.progress += self.level_progress_percentages[-1] / subtiles
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def progress_str(self):
|
|
187
|
+
return ''.join(self.progress_str_parts)
|
|
188
|
+
|
|
189
|
+
@contextmanager
|
|
190
|
+
def step_down(self, i, subtiles):
|
|
191
|
+
if self.level_progresses is None:
|
|
192
|
+
self.level_progresses = []
|
|
193
|
+
self.level_progresses = self.level_progresses[:self.level_progresses_level]
|
|
194
|
+
self.level_progresses.append((i, subtiles))
|
|
195
|
+
self.level_progresses_level += 1
|
|
196
|
+
self.progress_str_parts.append(status_symbol(i, subtiles))
|
|
197
|
+
self.level_progress_percentages.append(self.level_progress_percentages[-1] / subtiles)
|
|
198
|
+
|
|
199
|
+
yield
|
|
200
|
+
|
|
201
|
+
self.level_progress_percentages.pop()
|
|
202
|
+
self.progress_str_parts.pop()
|
|
203
|
+
|
|
204
|
+
self.level_progresses_level -= 1
|
|
205
|
+
if self.level_progresses_level == 0:
|
|
206
|
+
self.level_progresses = []
|
|
207
|
+
|
|
208
|
+
def already_processed(self):
|
|
209
|
+
return self.can_skip(self.old_level_progresses, self.level_progresses)
|
|
210
|
+
|
|
211
|
+
def current_progress_identifier(self):
|
|
212
|
+
if self.already_processed() or self.level_progresses is None:
|
|
213
|
+
return self.old_level_progresses
|
|
214
|
+
return self.level_progresses[:]
|
|
215
|
+
|
|
216
|
+
@staticmethod
|
|
217
|
+
def can_skip(old_progress, current_progress):
|
|
218
|
+
"""
|
|
219
|
+
Return True if the `current_progress` is behind the `old_progress` -
|
|
220
|
+
when it isn't as far as the old progress.
|
|
221
|
+
|
|
222
|
+
>>> SeedProgress.can_skip(None, [(0, 4)])
|
|
223
|
+
False
|
|
224
|
+
>>> SeedProgress.can_skip([], [(0, 4)])
|
|
225
|
+
True
|
|
226
|
+
>>> SeedProgress.can_skip([(0, 4)], None)
|
|
227
|
+
False
|
|
228
|
+
>>> SeedProgress.can_skip([(0, 4)], [(0, 4)])
|
|
229
|
+
False
|
|
230
|
+
>>> SeedProgress.can_skip([(1, 4)], [(0, 4)])
|
|
231
|
+
True
|
|
232
|
+
>>> SeedProgress.can_skip([(0, 4)], [(0, 4), (0, 4)])
|
|
233
|
+
False
|
|
234
|
+
|
|
235
|
+
>>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4)])
|
|
236
|
+
False
|
|
237
|
+
>>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4), (1, 4)])
|
|
238
|
+
True
|
|
239
|
+
>>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4), (2, 4)])
|
|
240
|
+
False
|
|
241
|
+
>>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (0, 4), (3, 4)])
|
|
242
|
+
False
|
|
243
|
+
>>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (1, 4)])
|
|
244
|
+
False
|
|
245
|
+
>>> SeedProgress.can_skip([(0, 4), (0, 4), (2, 4)], [(0, 4), (1, 4), (0, 4)])
|
|
246
|
+
False
|
|
247
|
+
"""
|
|
248
|
+
if current_progress is None:
|
|
249
|
+
return False
|
|
250
|
+
if old_progress is None:
|
|
251
|
+
return False
|
|
252
|
+
if old_progress == []:
|
|
253
|
+
return True
|
|
254
|
+
for old, current in zip_longest(old_progress, current_progress, fillvalue=None):
|
|
255
|
+
if old is None:
|
|
256
|
+
return False
|
|
257
|
+
if current is None:
|
|
258
|
+
return False
|
|
259
|
+
if old < current:
|
|
260
|
+
return False
|
|
261
|
+
if old > current:
|
|
262
|
+
return True
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
def running(self):
|
|
266
|
+
return True
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class StopProcess(Exception):
|
|
270
|
+
pass
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class SeedInterrupted(Exception):
|
|
274
|
+
pass
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class TileWalker(object):
|
|
278
|
+
"""
|
|
279
|
+
TileWalker traverses through all tiles in a tile grid and calls worker_pool.process
|
|
280
|
+
for each (meta) tile. It traverses the tile grid (pyramid) depth-first.
|
|
281
|
+
Intersection with coverages are checked before handling subtiles in the next level,
|
|
282
|
+
allowing to determine if all subtiles should be seeded or skipped.
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
def __init__(self, task, worker_pool, handle_stale=False, handle_uncached=False,
|
|
286
|
+
work_on_metatiles=True, skip_geoms_for_last_levels=0, progress_logger=None,
|
|
287
|
+
seed_progress=None):
|
|
288
|
+
self.tile_mgr = task.tile_manager
|
|
289
|
+
self.task = task
|
|
290
|
+
self.worker_pool = worker_pool
|
|
291
|
+
self.handle_stale = handle_stale
|
|
292
|
+
self.handle_uncached = handle_uncached
|
|
293
|
+
self.work_on_metatiles = work_on_metatiles
|
|
294
|
+
self.skip_geoms_for_last_levels = skip_geoms_for_last_levels
|
|
295
|
+
self.progress_logger = progress_logger
|
|
296
|
+
|
|
297
|
+
num_seed_levels = len(task.levels)
|
|
298
|
+
if num_seed_levels >= 4:
|
|
299
|
+
self.report_till_level = task.levels[num_seed_levels-2]
|
|
300
|
+
else:
|
|
301
|
+
self.report_till_level = task.levels[num_seed_levels-1]
|
|
302
|
+
meta_size = self.tile_mgr.meta_grid.meta_size if self.tile_mgr.meta_grid else (1, 1)
|
|
303
|
+
self.tiles_per_metatile = meta_size[0] * meta_size[1]
|
|
304
|
+
self.grid = MetaGrid(self.tile_mgr.grid, meta_size=meta_size, meta_buffer=0)
|
|
305
|
+
self.count = 0
|
|
306
|
+
self.seed_progress = seed_progress or SeedProgress()
|
|
307
|
+
|
|
308
|
+
# It is possible that we 'walk' through the same tile multiple times
|
|
309
|
+
# when seeding irregular tile grids[0]. limit_sub_bbox prevents that we
|
|
310
|
+
# recurse into the same area multiple times, but it is still possible
|
|
311
|
+
# that a tile is processed multiple times. Locking prevents that a tile
|
|
312
|
+
# is seeded multiple times, but it is possible that we count the same tile
|
|
313
|
+
# multiple times (in dry-mode, or while the tile is in the process queue).
|
|
314
|
+
|
|
315
|
+
# Tile counts can be off by 280% with sqrt2 grids.
|
|
316
|
+
# We keep a small cache of already processed tiles to skip most duplicates.
|
|
317
|
+
# A simple cache of 64 tile coordinates for each level already brings the
|
|
318
|
+
# difference down to ~8%, which is good enough and faster than a more
|
|
319
|
+
# sophisticated FIFO cache with O(1) lookup, or even caching all tiles.
|
|
320
|
+
|
|
321
|
+
# [0] irregular tile grids: where one tile does not have exactly 4 subtiles
|
|
322
|
+
# Typically when you use res_factor, or a custom res list.
|
|
323
|
+
self.seeded_tiles = {x: deque(maxlen=64) for x in task.levels}
|
|
324
|
+
|
|
325
|
+
def walk(self):
|
|
326
|
+
assert self.handle_stale or self.handle_uncached
|
|
327
|
+
bbox = self.task.coverage.extent.bbox_for(self.tile_mgr.grid.srs)
|
|
328
|
+
if self.seed_progress.already_processed():
|
|
329
|
+
# nothing to seed
|
|
330
|
+
self.seed_progress.step_forward()
|
|
331
|
+
else:
|
|
332
|
+
try:
|
|
333
|
+
self._walk(bbox, self.task.levels)
|
|
334
|
+
except StopProcess:
|
|
335
|
+
pass
|
|
336
|
+
self.report_progress(self.task.levels[0], self.task.coverage.bbox)
|
|
337
|
+
|
|
338
|
+
def _walk(self, cur_bbox, levels, current_level=0, all_subtiles=False):
|
|
339
|
+
"""
|
|
340
|
+
:param cur_bbox: the bbox to seed in this call
|
|
341
|
+
:param levels: list of levels to seed
|
|
342
|
+
:param all_subtiles: seed all subtiles and do not check for
|
|
343
|
+
intersections with bbox/geom
|
|
344
|
+
"""
|
|
345
|
+
bbox_, tiles, subtiles = self.grid.get_affected_level_tiles(cur_bbox, current_level)
|
|
346
|
+
total_subtiles = tiles[0] * tiles[1]
|
|
347
|
+
if len(levels) < self.skip_geoms_for_last_levels:
|
|
348
|
+
# do not filter in last levels
|
|
349
|
+
all_subtiles = True
|
|
350
|
+
subtiles = self._filter_subtiles(subtiles, all_subtiles)
|
|
351
|
+
|
|
352
|
+
if current_level in levels and current_level <= self.report_till_level:
|
|
353
|
+
self.report_progress(current_level, cur_bbox)
|
|
354
|
+
|
|
355
|
+
if not self.seed_progress.running():
|
|
356
|
+
if current_level in levels:
|
|
357
|
+
self.report_progress(current_level, cur_bbox)
|
|
358
|
+
self.tile_mgr.cleanup()
|
|
359
|
+
raise StopProcess()
|
|
360
|
+
|
|
361
|
+
process = False
|
|
362
|
+
if current_level in levels:
|
|
363
|
+
levels = levels[1:]
|
|
364
|
+
process = True
|
|
365
|
+
|
|
366
|
+
for i, (subtile, sub_bbox, intersection) in enumerate(subtiles):
|
|
367
|
+
if subtile is None: # no intersection
|
|
368
|
+
self.seed_progress.step_forward(total_subtiles)
|
|
369
|
+
continue
|
|
370
|
+
if levels: # recurse to next level
|
|
371
|
+
sub_bbox = limit_sub_bbox(cur_bbox, sub_bbox)
|
|
372
|
+
if intersection == CONTAINS:
|
|
373
|
+
all_subtiles = True
|
|
374
|
+
else:
|
|
375
|
+
all_subtiles = False
|
|
376
|
+
|
|
377
|
+
with self.seed_progress.step_down(i, total_subtiles):
|
|
378
|
+
if self.seed_progress.already_processed():
|
|
379
|
+
self.seed_progress.step_forward()
|
|
380
|
+
else:
|
|
381
|
+
self._walk(sub_bbox, levels, current_level=current_level+1,
|
|
382
|
+
all_subtiles=all_subtiles)
|
|
383
|
+
|
|
384
|
+
if not process:
|
|
385
|
+
continue
|
|
386
|
+
|
|
387
|
+
# check if subtile was already processed. see comment in __init__
|
|
388
|
+
if subtile in self.seeded_tiles[current_level]:
|
|
389
|
+
if not levels:
|
|
390
|
+
self.seed_progress.step_forward(total_subtiles)
|
|
391
|
+
continue
|
|
392
|
+
self.seeded_tiles[current_level].appendleft(subtile)
|
|
393
|
+
|
|
394
|
+
if not self.work_on_metatiles:
|
|
395
|
+
# collect actual tiles
|
|
396
|
+
handle_tiles = self.grid.tile_list(subtile)
|
|
397
|
+
else:
|
|
398
|
+
handle_tiles = [subtile]
|
|
399
|
+
|
|
400
|
+
if self.handle_uncached:
|
|
401
|
+
handle_tiles = [t for t in handle_tiles if
|
|
402
|
+
t is not None and
|
|
403
|
+
not self.tile_mgr.is_cached(t)]
|
|
404
|
+
elif self.handle_stale:
|
|
405
|
+
handle_tiles = [t for t in handle_tiles if
|
|
406
|
+
t is not None and
|
|
407
|
+
self.tile_mgr.is_stale(t)]
|
|
408
|
+
if handle_tiles:
|
|
409
|
+
self.count += 1
|
|
410
|
+
self.worker_pool.process(handle_tiles, self.seed_progress)
|
|
411
|
+
|
|
412
|
+
if not levels:
|
|
413
|
+
self.seed_progress.step_forward(total_subtiles)
|
|
414
|
+
|
|
415
|
+
if len(levels) >= 4:
|
|
416
|
+
# call cleanup to close open caches
|
|
417
|
+
# for connection based caches
|
|
418
|
+
self.tile_mgr.cleanup()
|
|
419
|
+
|
|
420
|
+
def report_progress(self, level, bbox):
|
|
421
|
+
if self.progress_logger:
|
|
422
|
+
self.progress_logger.log_progress(self.seed_progress, level, bbox,
|
|
423
|
+
self.count * self.tiles_per_metatile)
|
|
424
|
+
|
|
425
|
+
def _filter_subtiles(self, subtiles, all_subtiles):
|
|
426
|
+
"""
|
|
427
|
+
Return an iterator with all sub tiles.
|
|
428
|
+
Yields (None, None, None) for non-intersecting tiles,
|
|
429
|
+
otherwise (subtile, subtile_bbox, intersection).
|
|
430
|
+
"""
|
|
431
|
+
for subtile in subtiles:
|
|
432
|
+
if subtile is None:
|
|
433
|
+
yield None, None, None
|
|
434
|
+
else:
|
|
435
|
+
sub_bbox = self.grid.meta_tile(subtile).bbox
|
|
436
|
+
if all_subtiles:
|
|
437
|
+
intersection = CONTAINS
|
|
438
|
+
else:
|
|
439
|
+
intersection = self.task.intersects(sub_bbox)
|
|
440
|
+
if intersection:
|
|
441
|
+
yield subtile, sub_bbox, intersection
|
|
442
|
+
else:
|
|
443
|
+
yield None, None, None
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
class SeedTask(object):
|
|
447
|
+
def __init__(self, md, tile_manager, levels, refresh_timestamp, coverage):
|
|
448
|
+
self.md = md
|
|
449
|
+
self.tile_manager = tile_manager
|
|
450
|
+
self.grid = tile_manager.grid
|
|
451
|
+
self.levels = levels
|
|
452
|
+
self.refresh_timestamp = refresh_timestamp
|
|
453
|
+
self.coverage = coverage
|
|
454
|
+
|
|
455
|
+
@property
|
|
456
|
+
def id(self):
|
|
457
|
+
return self.md['name'], self.md['cache_name'], self.md['grid_name'], tuple(self.levels)
|
|
458
|
+
|
|
459
|
+
def intersects(self, bbox):
|
|
460
|
+
if self.coverage.contains(bbox, self.grid.srs):
|
|
461
|
+
return CONTAINS
|
|
462
|
+
if self.coverage.intersects(bbox, self.grid.srs):
|
|
463
|
+
return INTERSECTS
|
|
464
|
+
return NONE
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
class CleanupTask(object):
|
|
468
|
+
"""
|
|
469
|
+
:param coverage: area for the cleanup
|
|
470
|
+
:param complete_extent: ``True`` if `coverage` equals the extent of the grid
|
|
471
|
+
"""
|
|
472
|
+
|
|
473
|
+
def __init__(self, md, tile_manager, levels, remove_timestamp, coverage, complete_extent=False):
|
|
474
|
+
self.md = md
|
|
475
|
+
self.tile_manager = tile_manager
|
|
476
|
+
self.grid = tile_manager.grid
|
|
477
|
+
self.levels = levels
|
|
478
|
+
self.remove_timestamp = remove_timestamp
|
|
479
|
+
self.coverage = coverage
|
|
480
|
+
self.complete_extent = complete_extent
|
|
481
|
+
|
|
482
|
+
@property
|
|
483
|
+
def id(self):
|
|
484
|
+
return 'cleanup', self.md['name'], self.md['cache_name'], self.md['grid_name']
|
|
485
|
+
|
|
486
|
+
def intersects(self, bbox):
|
|
487
|
+
if self.coverage.contains(bbox, self.grid.srs):
|
|
488
|
+
return CONTAINS
|
|
489
|
+
if self.coverage.intersects(bbox, self.grid.srs):
|
|
490
|
+
return INTERSECTS
|
|
491
|
+
return NONE
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def seed(tasks, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0,
|
|
495
|
+
progress_logger=None, cache_locker=None, skip_uncached=False):
|
|
496
|
+
if cache_locker is None:
|
|
497
|
+
cache_locker = DummyCacheLocker()
|
|
498
|
+
|
|
499
|
+
active_tasks = tasks[::-1]
|
|
500
|
+
while active_tasks:
|
|
501
|
+
task = active_tasks[-1]
|
|
502
|
+
print(format_seed_task(task))
|
|
503
|
+
|
|
504
|
+
wait = len(active_tasks) == 1
|
|
505
|
+
try:
|
|
506
|
+
with cache_locker.lock(task.md['cache_name'], no_block=not wait):
|
|
507
|
+
if progress_logger and progress_logger.progress_store:
|
|
508
|
+
progress_logger.current_task_id = task.id
|
|
509
|
+
start_progress = progress_logger.progress_store.get(task.id)
|
|
510
|
+
else:
|
|
511
|
+
start_progress = None
|
|
512
|
+
seed_progress = SeedProgress(old_progress_identifier=start_progress)
|
|
513
|
+
seed_task(task, concurrency, dry_run, skip_geoms_for_last_levels, progress_logger,
|
|
514
|
+
seed_progress=seed_progress, skip_uncached=skip_uncached)
|
|
515
|
+
except CacheLockedError:
|
|
516
|
+
print(' ...cache is locked, skipping')
|
|
517
|
+
active_tasks = [task] + active_tasks[:-1]
|
|
518
|
+
else:
|
|
519
|
+
active_tasks.pop()
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def seed_task(task, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0,
|
|
523
|
+
progress_logger=None, seed_progress=None, skip_uncached=False):
|
|
524
|
+
if task.coverage is False:
|
|
525
|
+
return
|
|
526
|
+
if task.refresh_timestamp is not None:
|
|
527
|
+
task.tile_manager._expire_timestamp = task.refresh_timestamp
|
|
528
|
+
task.tile_manager.minimize_meta_requests = False
|
|
529
|
+
|
|
530
|
+
work_on_metatiles = True
|
|
531
|
+
if task.tile_manager.rescale_tiles:
|
|
532
|
+
work_on_metatiles = False
|
|
533
|
+
|
|
534
|
+
tile_worker_pool = TileWorkerPool(task, TileSeedWorker, dry_run=dry_run,
|
|
535
|
+
size=concurrency, progress_logger=progress_logger)
|
|
536
|
+
# If the configuration requests to only refresh tiles which are already in cache,
|
|
537
|
+
# tile walker parameters shall be adapted
|
|
538
|
+
handle_stale = skip_uncached
|
|
539
|
+
handle_uncached = not skip_uncached
|
|
540
|
+
tile_walker = TileWalker(task, tile_worker_pool, handle_uncached=handle_uncached, handle_stale=handle_stale,
|
|
541
|
+
skip_geoms_for_last_levels=skip_geoms_for_last_levels, progress_logger=progress_logger,
|
|
542
|
+
seed_progress=seed_progress,
|
|
543
|
+
work_on_metatiles=work_on_metatiles,
|
|
544
|
+
)
|
|
545
|
+
try:
|
|
546
|
+
tile_walker.walk()
|
|
547
|
+
except KeyboardInterrupt:
|
|
548
|
+
tile_worker_pool.stop(force=True)
|
|
549
|
+
raise
|
|
550
|
+
finally:
|
|
551
|
+
tile_worker_pool.stop()
|
mapproxy/seed/spec.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
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 mapproxy.util.ext.dictspec.validator import validate, ValidationError
|
|
17
|
+
from mapproxy.util.ext.dictspec.spec import one_off, anything, number
|
|
18
|
+
from mapproxy.util.ext.dictspec.spec import required
|
|
19
|
+
|
|
20
|
+
from mapproxy.config.spec import coverage, time_spec
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def validate_seed_conf(conf_dict):
|
|
24
|
+
"""
|
|
25
|
+
Validate `conf_dict` agains seed.yaml spec.
|
|
26
|
+
Returns lists with errors. List is empty when no errors where found.
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
validate(seed_yaml_spec, conf_dict)
|
|
30
|
+
except ValidationError as ex:
|
|
31
|
+
return ex.errors, ex.informal_only
|
|
32
|
+
else:
|
|
33
|
+
return [], True
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
from_to_spec = {
|
|
37
|
+
'from': number(),
|
|
38
|
+
'to': number(),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
seed_yaml_spec = {
|
|
42
|
+
'coverages': {
|
|
43
|
+
anything(): coverage,
|
|
44
|
+
},
|
|
45
|
+
'seeds': {
|
|
46
|
+
anything(): {
|
|
47
|
+
required('caches'): [str()],
|
|
48
|
+
'grids': [str()],
|
|
49
|
+
'coverages': [str()],
|
|
50
|
+
'refresh_before': time_spec,
|
|
51
|
+
'levels': one_off([int()], from_to_spec),
|
|
52
|
+
'resolutions': one_off([int()], from_to_spec),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
'cleanups': {
|
|
56
|
+
anything(): {
|
|
57
|
+
required('caches'): [str()],
|
|
58
|
+
'grids': [str()],
|
|
59
|
+
'coverages': [str()],
|
|
60
|
+
'remove_before': time_spec,
|
|
61
|
+
'remove_all': bool(),
|
|
62
|
+
'levels': one_off([int()], from_to_spec),
|
|
63
|
+
'resolutions': one_off([int()], from_to_spec),
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
}
|