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/cache/legend.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2010 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import hashlib
|
|
19
|
+
|
|
20
|
+
from mapproxy.image import ImageSource
|
|
21
|
+
from mapproxy.image.opts import ImageOptions
|
|
22
|
+
from mapproxy.util.fs import ensure_directory, write_atomic
|
|
23
|
+
|
|
24
|
+
import logging
|
|
25
|
+
log = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def legend_identifier(legends):
|
|
29
|
+
"""
|
|
30
|
+
>>> legend_identifier([("http://example/?", "foo"), ("http://example/?", "bar")])
|
|
31
|
+
'http://example/?foohttp://example/?bar'
|
|
32
|
+
|
|
33
|
+
:param legends: list of legend URL and layer tuples
|
|
34
|
+
"""
|
|
35
|
+
parts = []
|
|
36
|
+
for url, layer in legends:
|
|
37
|
+
parts.append(url)
|
|
38
|
+
if layer:
|
|
39
|
+
parts.append(layer)
|
|
40
|
+
return ''.join(parts)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def legend_hash(identifier, scale):
|
|
44
|
+
md5 = hashlib.md5()
|
|
45
|
+
md5.update(identifier.encode('utf-8'))
|
|
46
|
+
md5.update(str(scale).encode('ascii'))
|
|
47
|
+
return md5.hexdigest()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class LegendCache(object):
|
|
51
|
+
def __init__(self, cache_dir=None, file_ext='png'):
|
|
52
|
+
self.cache_dir = cache_dir
|
|
53
|
+
self.file_ext = file_ext
|
|
54
|
+
|
|
55
|
+
def store(self, legend):
|
|
56
|
+
if legend.stored:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
if legend.location is None:
|
|
60
|
+
hash = legend_hash(legend.id, legend.scale)
|
|
61
|
+
legend.location = os.path.join(self.cache_dir, hash) + '.' + self.file_ext
|
|
62
|
+
ensure_directory(legend.location)
|
|
63
|
+
|
|
64
|
+
data = legend.source.as_buffer(ImageOptions(format='image/' + self.file_ext), seekable=True)
|
|
65
|
+
data.seek(0)
|
|
66
|
+
log.debug('writing to %s' % (legend.location))
|
|
67
|
+
write_atomic(legend.location, data.read())
|
|
68
|
+
data.seek(0)
|
|
69
|
+
legend.stored = True
|
|
70
|
+
|
|
71
|
+
def load(self, legend):
|
|
72
|
+
hash = legend_hash(legend.id, legend.scale)
|
|
73
|
+
legend.location = os.path.join(self.cache_dir, hash) + '.' + self.file_ext
|
|
74
|
+
|
|
75
|
+
if os.path.exists(legend.location):
|
|
76
|
+
legend.source = ImageSource(legend.location)
|
|
77
|
+
return True
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class Legend(object):
|
|
82
|
+
def __init__(self, source=None, id=None, scale=None):
|
|
83
|
+
self.source = source
|
|
84
|
+
self.stored = None
|
|
85
|
+
self.location = None
|
|
86
|
+
self.id = id
|
|
87
|
+
self.scale = scale
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2011-2013 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import glob
|
|
17
|
+
import hashlib
|
|
18
|
+
import os
|
|
19
|
+
import sqlite3
|
|
20
|
+
import threading
|
|
21
|
+
import time
|
|
22
|
+
from io import BytesIO
|
|
23
|
+
from itertools import groupby
|
|
24
|
+
|
|
25
|
+
from mapproxy.image import ImageSource
|
|
26
|
+
from mapproxy.cache.base import TileCacheBase, tile_buffer, REMOVE_ON_UNLOCK
|
|
27
|
+
from mapproxy.util.fs import ensure_directory
|
|
28
|
+
from mapproxy.util.lock import FileLock
|
|
29
|
+
|
|
30
|
+
import logging
|
|
31
|
+
log = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
if not hasattr(glob, 'escape'):
|
|
34
|
+
import re
|
|
35
|
+
glob.escape = lambda pathname: re.sub(r'([*?[])', r'[\1]', pathname)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def sqlite_datetime_to_timestamp(datetime):
|
|
39
|
+
if datetime is None:
|
|
40
|
+
return None
|
|
41
|
+
d = time.strptime(datetime, "%Y-%m-%d %H:%M:%S")
|
|
42
|
+
return time.mktime(d)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MBTilesCache(TileCacheBase):
|
|
46
|
+
supports_timestamp = False
|
|
47
|
+
|
|
48
|
+
def __init__(self, mbtile_file, with_timestamps=False, timeout=30, wal=False, ttl=0, coverage=None):
|
|
49
|
+
super(MBTilesCache, self).__init__(coverage)
|
|
50
|
+
md5 = hashlib.new('md5', mbtile_file.encode('utf-8'), usedforsecurity=False)
|
|
51
|
+
self.lock_cache_id = 'mbtiles-' + md5.hexdigest()
|
|
52
|
+
self.mbtile_file = mbtile_file
|
|
53
|
+
self.supports_timestamp = with_timestamps
|
|
54
|
+
self.ttl = with_timestamps and ttl or 0
|
|
55
|
+
self.timeout = timeout
|
|
56
|
+
self.wal = wal
|
|
57
|
+
self.ensure_mbtile()
|
|
58
|
+
self._db_conn_cache = threading.local()
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def db(self):
|
|
62
|
+
if not getattr(self._db_conn_cache, 'db', None):
|
|
63
|
+
self.ensure_mbtile()
|
|
64
|
+
self._db_conn_cache.db = sqlite3.connect(self.mbtile_file, self.timeout)
|
|
65
|
+
return self._db_conn_cache.db
|
|
66
|
+
|
|
67
|
+
def cleanup(self):
|
|
68
|
+
"""
|
|
69
|
+
Close all open connection and remove them from cache.
|
|
70
|
+
"""
|
|
71
|
+
if getattr(self._db_conn_cache, 'db', None):
|
|
72
|
+
self._db_conn_cache.db.close()
|
|
73
|
+
self._db_conn_cache.db = None
|
|
74
|
+
|
|
75
|
+
def ensure_mbtile(self):
|
|
76
|
+
if not os.path.exists(self.mbtile_file):
|
|
77
|
+
with FileLock(self.mbtile_file + '.init.lck',
|
|
78
|
+
remove_on_unlock=REMOVE_ON_UNLOCK):
|
|
79
|
+
if not os.path.exists(self.mbtile_file):
|
|
80
|
+
ensure_directory(self.mbtile_file)
|
|
81
|
+
self._initialize_mbtile()
|
|
82
|
+
|
|
83
|
+
def _initialize_mbtile(self):
|
|
84
|
+
log.info('initializing MBTile file %s', self.mbtile_file)
|
|
85
|
+
db = sqlite3.connect(self.mbtile_file)
|
|
86
|
+
|
|
87
|
+
if self.wal:
|
|
88
|
+
db.execute('PRAGMA journal_mode=wal')
|
|
89
|
+
|
|
90
|
+
stmt = """
|
|
91
|
+
CREATE TABLE tiles (
|
|
92
|
+
zoom_level integer,
|
|
93
|
+
tile_column integer,
|
|
94
|
+
tile_row integer,
|
|
95
|
+
tile_data blob
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
if self.supports_timestamp:
|
|
99
|
+
stmt += """
|
|
100
|
+
, last_modified datetime DEFAULT (datetime('now','localtime'))
|
|
101
|
+
"""
|
|
102
|
+
stmt += """
|
|
103
|
+
);
|
|
104
|
+
"""
|
|
105
|
+
db.execute(stmt)
|
|
106
|
+
|
|
107
|
+
db.execute("""
|
|
108
|
+
CREATE TABLE metadata (name text, value text);
|
|
109
|
+
""")
|
|
110
|
+
db.execute("""
|
|
111
|
+
CREATE UNIQUE INDEX idx_tile on tiles
|
|
112
|
+
(zoom_level, tile_column, tile_row);
|
|
113
|
+
""")
|
|
114
|
+
db.commit()
|
|
115
|
+
db.close()
|
|
116
|
+
|
|
117
|
+
def update_metadata(self, name='', description='', version=1, overlay=True, format='png'):
|
|
118
|
+
db = sqlite3.connect(self.mbtile_file)
|
|
119
|
+
db.execute("""
|
|
120
|
+
CREATE TABLE IF NOT EXISTS metadata (name text, value text);
|
|
121
|
+
""")
|
|
122
|
+
db.execute("""DELETE FROM metadata;""")
|
|
123
|
+
|
|
124
|
+
if overlay:
|
|
125
|
+
layer_type = 'overlay'
|
|
126
|
+
else:
|
|
127
|
+
layer_type = 'baselayer'
|
|
128
|
+
|
|
129
|
+
db.executemany("""
|
|
130
|
+
INSERT INTO metadata (name, value) VALUES (?,?)
|
|
131
|
+
""",
|
|
132
|
+
(
|
|
133
|
+
('name', name),
|
|
134
|
+
('description', description),
|
|
135
|
+
('version', version),
|
|
136
|
+
('type', layer_type),
|
|
137
|
+
('format', format),
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
db.commit()
|
|
141
|
+
db.close()
|
|
142
|
+
|
|
143
|
+
def is_cached(self, tile, dimensions=None):
|
|
144
|
+
if tile.coord is None:
|
|
145
|
+
return True
|
|
146
|
+
if tile.source:
|
|
147
|
+
return True
|
|
148
|
+
|
|
149
|
+
return self.load_tile(tile, dimensions=dimensions)
|
|
150
|
+
|
|
151
|
+
def store_tile(self, tile, dimensions=None):
|
|
152
|
+
if tile.stored:
|
|
153
|
+
return True
|
|
154
|
+
return self._store_bulk([tile])
|
|
155
|
+
|
|
156
|
+
def store_tiles(self, tiles, dimensions=None):
|
|
157
|
+
tiles = [t for t in tiles if not t.stored]
|
|
158
|
+
return self._store_bulk(tiles)
|
|
159
|
+
|
|
160
|
+
def _store_bulk(self, tiles):
|
|
161
|
+
records = []
|
|
162
|
+
# tile_buffer (as_buffer) will encode the tile to the target format
|
|
163
|
+
# we collect all tiles before, to avoid having the db transaction
|
|
164
|
+
# open during this slow encoding
|
|
165
|
+
for tile in tiles:
|
|
166
|
+
with tile_buffer(tile) as buf:
|
|
167
|
+
content = buf.read()
|
|
168
|
+
x, y, level = tile.coord
|
|
169
|
+
if self.supports_timestamp:
|
|
170
|
+
records.append((level, x, y, content, time.time()))
|
|
171
|
+
else:
|
|
172
|
+
records.append((level, x, y, content))
|
|
173
|
+
|
|
174
|
+
cursor = self.db.cursor()
|
|
175
|
+
try:
|
|
176
|
+
if self.supports_timestamp:
|
|
177
|
+
stmt = ("INSERT OR REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data, last_modified)"
|
|
178
|
+
" VALUES (?,?,?,?, datetime(?, 'unixepoch', 'localtime'))")
|
|
179
|
+
cursor.executemany(stmt, records)
|
|
180
|
+
else:
|
|
181
|
+
stmt = "INSERT OR REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES (?,?,?,?)"
|
|
182
|
+
cursor.executemany(stmt, records)
|
|
183
|
+
self.db.commit()
|
|
184
|
+
except sqlite3.OperationalError as ex:
|
|
185
|
+
log.warning('unable to store tile: %s', ex)
|
|
186
|
+
return False
|
|
187
|
+
return True
|
|
188
|
+
|
|
189
|
+
def load_tile(self, tile, with_metadata=False, dimensions=None):
|
|
190
|
+
if tile.source or tile.coord is None:
|
|
191
|
+
return True
|
|
192
|
+
|
|
193
|
+
cur = self.db.cursor()
|
|
194
|
+
if self.supports_timestamp:
|
|
195
|
+
stmt = '''SELECT tile_data, last_modified
|
|
196
|
+
FROM tiles
|
|
197
|
+
WHERE tile_column = ? AND
|
|
198
|
+
tile_row = ? AND
|
|
199
|
+
zoom_level = ?'''
|
|
200
|
+
else:
|
|
201
|
+
stmt = '''SELECT tile_data FROM tiles
|
|
202
|
+
WHERE tile_column = ? AND
|
|
203
|
+
tile_row = ? AND
|
|
204
|
+
zoom_level = ?'''
|
|
205
|
+
|
|
206
|
+
if self.ttl:
|
|
207
|
+
stmt += " AND datetime('now', 'localtime', '%d seconds') < last_modified" % -self.ttl
|
|
208
|
+
|
|
209
|
+
cur.execute(stmt, tile.coord)
|
|
210
|
+
|
|
211
|
+
content = cur.fetchone()
|
|
212
|
+
if content:
|
|
213
|
+
tile.source = ImageSource(BytesIO(content[0]))
|
|
214
|
+
if self.supports_timestamp:
|
|
215
|
+
tile.timestamp = sqlite_datetime_to_timestamp(content[1])
|
|
216
|
+
return True
|
|
217
|
+
else:
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
def load_tiles(self, tiles, with_metadata=False, dimensions=None):
|
|
221
|
+
# associate the right tiles with the cursor
|
|
222
|
+
tile_dict = {}
|
|
223
|
+
coords = []
|
|
224
|
+
for tile in tiles:
|
|
225
|
+
if tile.source or tile.coord is None:
|
|
226
|
+
continue
|
|
227
|
+
x, y, level = tile.coord
|
|
228
|
+
coords.append(x)
|
|
229
|
+
coords.append(y)
|
|
230
|
+
coords.append(level)
|
|
231
|
+
tile_dict[(x, y)] = tile
|
|
232
|
+
|
|
233
|
+
if not tile_dict:
|
|
234
|
+
# all tiles loaded or coords are None
|
|
235
|
+
return True
|
|
236
|
+
|
|
237
|
+
if self.supports_timestamp:
|
|
238
|
+
stmt_base = "SELECT tile_column, tile_row, tile_data, last_modified FROM tiles WHERE "
|
|
239
|
+
if self.ttl:
|
|
240
|
+
ttl_condition = "datetime('now', 'localtime', '%d seconds') < last_modified" % -self.ttl
|
|
241
|
+
stmt_base += ttl_condition + ' AND '
|
|
242
|
+
else:
|
|
243
|
+
stmt_base = "SELECT tile_column, tile_row, tile_data FROM tiles WHERE "
|
|
244
|
+
|
|
245
|
+
loaded_tiles = 0
|
|
246
|
+
|
|
247
|
+
# SQLite is limited to 1000 args -> split into multiple requests if more arguments are needed
|
|
248
|
+
while coords:
|
|
249
|
+
cur_coords = coords[:999]
|
|
250
|
+
|
|
251
|
+
stmt = stmt_base + '(' + ' OR '.join(
|
|
252
|
+
['(tile_column = ? AND tile_row = ? AND zoom_level = ?)'] * (len(cur_coords) // 3)) + ')'
|
|
253
|
+
|
|
254
|
+
cursor = self.db.cursor()
|
|
255
|
+
cursor.execute(stmt, cur_coords)
|
|
256
|
+
|
|
257
|
+
for row in cursor:
|
|
258
|
+
loaded_tiles += 1
|
|
259
|
+
tile = tile_dict[(row[0], row[1])]
|
|
260
|
+
data = row[2]
|
|
261
|
+
tile.size = len(data)
|
|
262
|
+
tile.source = ImageSource(BytesIO(data))
|
|
263
|
+
if self.supports_timestamp:
|
|
264
|
+
tile.timestamp = sqlite_datetime_to_timestamp(row[3])
|
|
265
|
+
cursor.close()
|
|
266
|
+
|
|
267
|
+
coords = coords[999:]
|
|
268
|
+
|
|
269
|
+
return loaded_tiles == len(tile_dict)
|
|
270
|
+
|
|
271
|
+
def remove_tile(self, tile):
|
|
272
|
+
cursor = self.db.cursor()
|
|
273
|
+
cursor.execute(
|
|
274
|
+
"DELETE FROM tiles WHERE (tile_column = ? AND tile_row = ? AND zoom_level = ?)",
|
|
275
|
+
tile.coord)
|
|
276
|
+
self.db.commit()
|
|
277
|
+
if cursor.rowcount:
|
|
278
|
+
return True
|
|
279
|
+
return False
|
|
280
|
+
|
|
281
|
+
def remove_level_tiles_before(self, level, timestamp):
|
|
282
|
+
if timestamp == 0:
|
|
283
|
+
cursor = self.db.cursor()
|
|
284
|
+
cursor.execute(
|
|
285
|
+
"DELETE FROM tiles WHERE (zoom_level = ?)",
|
|
286
|
+
(level, ))
|
|
287
|
+
self.db.commit()
|
|
288
|
+
if cursor.rowcount:
|
|
289
|
+
return True
|
|
290
|
+
return False
|
|
291
|
+
|
|
292
|
+
if self.supports_timestamp:
|
|
293
|
+
cursor = self.db.cursor()
|
|
294
|
+
cursor.execute(
|
|
295
|
+
"DELETE FROM tiles WHERE (zoom_level = ? AND last_modified < datetime(?, 'unixepoch', 'localtime'))",
|
|
296
|
+
(level, timestamp))
|
|
297
|
+
self.db.commit()
|
|
298
|
+
if cursor.rowcount:
|
|
299
|
+
return True
|
|
300
|
+
return False
|
|
301
|
+
|
|
302
|
+
def load_tile_metadata(self, tile, dimensions=None):
|
|
303
|
+
if not self.supports_timestamp:
|
|
304
|
+
# MBTiles specification does not include timestamps.
|
|
305
|
+
# This sets the timestamp of the tile to epoch (1970s)
|
|
306
|
+
tile.timestamp = -1
|
|
307
|
+
else:
|
|
308
|
+
self.load_tile(tile, dimensions=dimensions)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class MBTilesLevelCache(TileCacheBase):
|
|
312
|
+
supports_timestamp = True
|
|
313
|
+
|
|
314
|
+
def __init__(self, mbtiles_dir, timeout=30, wal=False, ttl=0, coverage=None):
|
|
315
|
+
super(MBTilesLevelCache, self).__init__(coverage)
|
|
316
|
+
md5 = hashlib.new('md5', mbtiles_dir.encode('utf-8'), usedforsecurity=False)
|
|
317
|
+
self.lock_cache_id = 'sqlite-' + md5.hexdigest()
|
|
318
|
+
self.cache_dir = mbtiles_dir
|
|
319
|
+
self._mbtiles = {}
|
|
320
|
+
self.timeout = timeout
|
|
321
|
+
self.wal = wal
|
|
322
|
+
self.ttl = ttl
|
|
323
|
+
self._mbtiles_lock = threading.Lock()
|
|
324
|
+
|
|
325
|
+
def _get_level(self, level):
|
|
326
|
+
if level in self._mbtiles:
|
|
327
|
+
return self._mbtiles[level]
|
|
328
|
+
|
|
329
|
+
with self._mbtiles_lock:
|
|
330
|
+
if level not in self._mbtiles:
|
|
331
|
+
mbtile_filename = os.path.join(self.cache_dir, '%s.mbtile' % level)
|
|
332
|
+
self._mbtiles[level] = MBTilesCache(
|
|
333
|
+
mbtile_filename,
|
|
334
|
+
with_timestamps=True,
|
|
335
|
+
timeout=self.timeout,
|
|
336
|
+
wal=self.wal,
|
|
337
|
+
ttl=self.ttl,
|
|
338
|
+
coverage=self.coverage
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
return self._mbtiles[level]
|
|
342
|
+
|
|
343
|
+
def cleanup(self):
|
|
344
|
+
"""
|
|
345
|
+
Close all open connection and remove them from cache.
|
|
346
|
+
"""
|
|
347
|
+
with self._mbtiles_lock:
|
|
348
|
+
for mbtile in self._mbtiles.values():
|
|
349
|
+
mbtile.cleanup()
|
|
350
|
+
|
|
351
|
+
def is_cached(self, tile, dimensions=None):
|
|
352
|
+
if tile.coord is None:
|
|
353
|
+
return True
|
|
354
|
+
if tile.source:
|
|
355
|
+
return True
|
|
356
|
+
|
|
357
|
+
return self._get_level(tile.coord[2]).is_cached(tile, dimensions=dimensions)
|
|
358
|
+
|
|
359
|
+
def store_tile(self, tile, dimensions=None):
|
|
360
|
+
if tile.stored:
|
|
361
|
+
return True
|
|
362
|
+
|
|
363
|
+
return self._get_level(tile.coord[2]).store_tile(tile, dimensions=dimensions)
|
|
364
|
+
|
|
365
|
+
def store_tiles(self, tiles, dimensions=None):
|
|
366
|
+
failed = False
|
|
367
|
+
for level, tiles in groupby(tiles, key=lambda t: t.coord[2]):
|
|
368
|
+
tiles = [t for t in tiles if not t.stored]
|
|
369
|
+
res = self._get_level(level).store_tiles(tiles, dimensions=dimensions)
|
|
370
|
+
if not res:
|
|
371
|
+
failed = True
|
|
372
|
+
return failed
|
|
373
|
+
|
|
374
|
+
def load_tile(self, tile, with_metadata=False, dimensions=None):
|
|
375
|
+
if tile.source or tile.coord is None:
|
|
376
|
+
return True
|
|
377
|
+
|
|
378
|
+
return self._get_level(tile.coord[2]).load_tile(tile, with_metadata=with_metadata, dimensions=dimensions)
|
|
379
|
+
|
|
380
|
+
def load_tiles(self, tiles, with_metadata=False, dimensions=None):
|
|
381
|
+
level = None
|
|
382
|
+
for tile in tiles:
|
|
383
|
+
if tile.source or tile.coord is None:
|
|
384
|
+
continue
|
|
385
|
+
level = tile.coord[2]
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
if not level:
|
|
389
|
+
return True
|
|
390
|
+
|
|
391
|
+
return self._get_level(level).load_tiles(tiles, with_metadata=with_metadata, dimensions=dimensions)
|
|
392
|
+
|
|
393
|
+
def remove_tile(self, tile, dimensions=None):
|
|
394
|
+
if tile.coord is None:
|
|
395
|
+
return True
|
|
396
|
+
|
|
397
|
+
return self._get_level(tile.coord[2]).remove_tile(tile)
|
|
398
|
+
|
|
399
|
+
def load_tile_metadata(self, tile, dimensions=None):
|
|
400
|
+
self.load_tile(tile, dimensions=dimensions)
|
|
401
|
+
|
|
402
|
+
def remove_level_tiles_before(self, level, timestamp):
|
|
403
|
+
level_cache = self._get_level(level)
|
|
404
|
+
if timestamp == 0:
|
|
405
|
+
level_cache.cleanup()
|
|
406
|
+
os.unlink(level_cache.mbtile_file)
|
|
407
|
+
for file in glob.glob("%s-*" % glob.escape(level_cache.mbtile_file)):
|
|
408
|
+
os.unlink(file)
|
|
409
|
+
return True
|
|
410
|
+
else:
|
|
411
|
+
return level_cache.remove_level_tiles_before(level, timestamp)
|
mapproxy/cache/meta.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
import struct
|
|
3
|
+
from mapproxy.cache.base import tile_buffer
|
|
4
|
+
from mapproxy.image import ImageSource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MetaTileFile(object):
|
|
8
|
+
def __init__(self, meta_tile):
|
|
9
|
+
self.meta_tile = meta_tile
|
|
10
|
+
|
|
11
|
+
def write_tiles(self, tiles):
|
|
12
|
+
tile_positions = []
|
|
13
|
+
count = len(tiles) # self.meta_tile.grid_size[0]
|
|
14
|
+
header_size = (
|
|
15
|
+
4 # META
|
|
16
|
+
+ 4 # metasize**2
|
|
17
|
+
+ 3*4 # x, y, z
|
|
18
|
+
+ count * 8 # offset/size * tiles
|
|
19
|
+
)
|
|
20
|
+
with open('/tmp/foo.metatile', 'wb') as f:
|
|
21
|
+
f.write("META")
|
|
22
|
+
f.write(struct.pack('i', count))
|
|
23
|
+
f.write(struct.pack('iii', *tiles[0].coord))
|
|
24
|
+
offsets_header_pos = f.tell()
|
|
25
|
+
f.seek(header_size, 0)
|
|
26
|
+
|
|
27
|
+
for tile in tiles:
|
|
28
|
+
offset = f.tell()
|
|
29
|
+
with tile_buffer(tile) as buf:
|
|
30
|
+
tile_data = buf.read()
|
|
31
|
+
f.write(tile_data)
|
|
32
|
+
tile_positions.append((offset, len(tile_data)))
|
|
33
|
+
|
|
34
|
+
f.seek(offsets_header_pos, 0)
|
|
35
|
+
for offset, size in tile_positions:
|
|
36
|
+
f.write(struct.pack('ii', offset, size))
|
|
37
|
+
|
|
38
|
+
def _read_header(self, f):
|
|
39
|
+
f.seek(0, 0)
|
|
40
|
+
assert f.read(4) == "META"
|
|
41
|
+
count, x, y, z = struct.unpack('iiii', f.read(4*4))
|
|
42
|
+
tile_positions = []
|
|
43
|
+
for i in range(count):
|
|
44
|
+
offset, size = struct.unpack('ii', f.read(4*2))
|
|
45
|
+
tile_positions.append((offset, size))
|
|
46
|
+
|
|
47
|
+
return tile_positions
|
|
48
|
+
|
|
49
|
+
def read_tiles(self):
|
|
50
|
+
with open('/tmp/foo.metatile', 'rb') as f:
|
|
51
|
+
tile_positions = self._read_header(f)
|
|
52
|
+
|
|
53
|
+
for i, (offset, size) in enumerate(tile_positions):
|
|
54
|
+
f.seek(offset, 0)
|
|
55
|
+
# img = ImageSource(BytesIO(f.read(size)))
|
|
56
|
+
open('/tmp/img-%02d.png' % i, 'wb').write(f.read(size))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == '__main__':
|
|
60
|
+
from io import BytesIO
|
|
61
|
+
from mapproxy.cache.tile import Tile
|
|
62
|
+
from mapproxy.test.image import create_tmp_image
|
|
63
|
+
|
|
64
|
+
tiles = []
|
|
65
|
+
img = create_tmp_image((256, 256))
|
|
66
|
+
for x in range(8):
|
|
67
|
+
for y in range(8):
|
|
68
|
+
tiles.append(Tile((x, y, 4), ImageSource(BytesIO(img))))
|
|
69
|
+
|
|
70
|
+
m = MetaTileFile(None)
|
|
71
|
+
print('!')
|
|
72
|
+
m.write_tiles(tiles)
|
|
73
|
+
print('!')
|
|
74
|
+
m.read_tiles()
|
|
75
|
+
print('!')
|
|
76
|
+
|
|
77
|
+
x = y = 0
|
|
78
|
+
METATILE = 8
|
|
79
|
+
for meta in range(METATILE ** 2):
|
|
80
|
+
print(x + (meta / METATILE), y + (meta % METATILE))
|