MapProxy 1.16.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mapproxy/__init__.py +0 -0
- mapproxy/cache/__init__.py +36 -0
- mapproxy/cache/azureblob.py +145 -0
- mapproxy/cache/base.py +111 -0
- mapproxy/cache/compact.py +664 -0
- mapproxy/cache/couchdb.py +295 -0
- mapproxy/cache/dummy.py +34 -0
- mapproxy/cache/file.py +185 -0
- mapproxy/cache/geopackage.py +609 -0
- mapproxy/cache/legend.py +83 -0
- mapproxy/cache/mbtiles.py +392 -0
- mapproxy/cache/meta.py +78 -0
- mapproxy/cache/path.py +250 -0
- mapproxy/cache/redis.py +88 -0
- mapproxy/cache/renderd.py +95 -0
- mapproxy/cache/riak.py +202 -0
- mapproxy/cache/s3.py +177 -0
- mapproxy/cache/tile.py +699 -0
- mapproxy/client/__init__.py +0 -0
- mapproxy/client/arcgis.py +79 -0
- mapproxy/client/cgi.py +139 -0
- mapproxy/client/http.py +315 -0
- mapproxy/client/log.py +33 -0
- mapproxy/client/tile.py +150 -0
- mapproxy/client/wms.py +254 -0
- mapproxy/compat/__init__.py +46 -0
- mapproxy/compat/image.py +79 -0
- mapproxy/compat/itertools.py +29 -0
- mapproxy/compat/modules.py +13 -0
- mapproxy/config/__init__.py +22 -0
- mapproxy/config/config.py +201 -0
- mapproxy/config/coverage.py +107 -0
- mapproxy/config/defaults.py +98 -0
- mapproxy/config/loader.py +2286 -0
- mapproxy/config/spec.py +644 -0
- mapproxy/config/validator.py +239 -0
- mapproxy/config_template/__init__.py +0 -0
- mapproxy/config_template/base_config/config.wsgi +10 -0
- mapproxy/config_template/base_config/full_example.yaml +593 -0
- mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
- mapproxy/config_template/base_config/log.ini +35 -0
- mapproxy/config_template/base_config/mapproxy.yaml +60 -0
- mapproxy/config_template/base_config/seed.yaml +27 -0
- mapproxy/exception.py +142 -0
- mapproxy/featureinfo.py +252 -0
- mapproxy/grid.py +1170 -0
- mapproxy/image/__init__.py +536 -0
- mapproxy/image/fonts/DejaVuSans.ttf +0 -0
- mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
- mapproxy/image/fonts/LICENSE +99 -0
- mapproxy/image/fonts/__init__.py +0 -0
- mapproxy/image/mask.py +75 -0
- mapproxy/image/merge.py +316 -0
- mapproxy/image/message.py +347 -0
- mapproxy/image/opts.py +182 -0
- mapproxy/image/tile.py +167 -0
- mapproxy/image/transform.py +350 -0
- mapproxy/layer.py +470 -0
- mapproxy/multiapp.py +231 -0
- mapproxy/proj.py +302 -0
- mapproxy/request/__init__.py +18 -0
- mapproxy/request/arcgis.py +259 -0
- mapproxy/request/base.py +476 -0
- mapproxy/request/tile.py +128 -0
- mapproxy/request/wms/__init__.py +793 -0
- mapproxy/request/wms/exception.py +99 -0
- mapproxy/request/wmts.py +436 -0
- mapproxy/response.py +237 -0
- mapproxy/script/__init__.py +0 -0
- mapproxy/script/conf/__init__.py +0 -0
- mapproxy/script/conf/app.py +195 -0
- mapproxy/script/conf/caches.py +45 -0
- mapproxy/script/conf/layers.py +54 -0
- mapproxy/script/conf/seeds.py +37 -0
- mapproxy/script/conf/sources.py +86 -0
- mapproxy/script/conf/utils.py +143 -0
- mapproxy/script/defrag.py +184 -0
- mapproxy/script/export.py +333 -0
- mapproxy/script/grids.py +188 -0
- mapproxy/script/scales.py +126 -0
- mapproxy/script/util.py +406 -0
- mapproxy/script/wms_capabilities.py +152 -0
- mapproxy/seed/__init__.py +0 -0
- mapproxy/seed/cachelock.py +121 -0
- mapproxy/seed/cleanup.py +187 -0
- mapproxy/seed/config.py +469 -0
- mapproxy/seed/script.py +388 -0
- mapproxy/seed/seeder.py +538 -0
- mapproxy/seed/spec.py +64 -0
- mapproxy/seed/util.py +254 -0
- mapproxy/service/__init__.py +14 -0
- mapproxy/service/base.py +46 -0
- mapproxy/service/demo.py +356 -0
- mapproxy/service/kml.py +331 -0
- mapproxy/service/ows.py +38 -0
- mapproxy/service/template_helper.py +53 -0
- mapproxy/service/templates/demo/capabilities_demo.html +16 -0
- mapproxy/service/templates/demo/demo.html +181 -0
- mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
- mapproxy/service/templates/demo/static/img/blank.gif +0 -0
- mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
- mapproxy/service/templates/demo/static/logo.png +0 -0
- mapproxy/service/templates/demo/static/ol.css +345 -0
- mapproxy/service/templates/demo/static/ol.js +4 -0
- mapproxy/service/templates/demo/static/proj4.min.js +1 -0
- mapproxy/service/templates/demo/static/proj4defs.js +1 -0
- mapproxy/service/templates/demo/static/site.css +137 -0
- mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
- mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
- mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
- mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
- mapproxy/service/templates/demo/static.html +34 -0
- mapproxy/service/templates/demo/tms_demo.html +103 -0
- mapproxy/service/templates/demo/wms_demo.html +140 -0
- mapproxy/service/templates/demo/wmts_demo.html +110 -0
- mapproxy/service/templates/tms_capabilities.xml +13 -0
- mapproxy/service/templates/tms_exception.xml +4 -0
- mapproxy/service/templates/tms_root_resource.xml +7 -0
- mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
- mapproxy/service/templates/wms100capabilities.xml +112 -0
- mapproxy/service/templates/wms100exception.xml +4 -0
- mapproxy/service/templates/wms110capabilities.xml +152 -0
- mapproxy/service/templates/wms110exception.xml +5 -0
- mapproxy/service/templates/wms111capabilities.xml +183 -0
- mapproxy/service/templates/wms111exception.xml +5 -0
- mapproxy/service/templates/wms130capabilities.xml +326 -0
- mapproxy/service/templates/wms130exception.xml +8 -0
- mapproxy/service/templates/wmts100capabilities.xml +155 -0
- mapproxy/service/templates/wmts100exception.xml +9 -0
- mapproxy/service/tile.py +536 -0
- mapproxy/service/wms.py +851 -0
- mapproxy/service/wmts.py +381 -0
- mapproxy/source/__init__.py +75 -0
- mapproxy/source/arcgis.py +39 -0
- mapproxy/source/error.py +39 -0
- mapproxy/source/mapnik.py +259 -0
- mapproxy/source/tile.py +96 -0
- mapproxy/source/wms.py +270 -0
- mapproxy/srs.py +726 -0
- mapproxy/template.py +54 -0
- mapproxy/test/__init__.py +0 -0
- mapproxy/test/conftest.py +7 -0
- mapproxy/test/helper.py +247 -0
- mapproxy/test/http.py +494 -0
- mapproxy/test/image.py +210 -0
- mapproxy/test/mocker.py +2268 -0
- mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
- mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
- mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
- mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
- mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
- mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
- mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
- mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
- mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
- mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
- mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
- mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
- mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
- mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
- mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
- mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
- mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
- mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
- mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
- mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
- mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
- mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
- mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
- mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
- mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
- mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
- mapproxy/test/schemas/xml.xsd +287 -0
- mapproxy/test/system/__init__.py +98 -0
- mapproxy/test/system/fixture/arcgis.yaml +57 -0
- mapproxy/test/system/fixture/auth.yaml +70 -0
- mapproxy/test/system/fixture/cache.mbtiles +0 -0
- mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
- mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
- mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
- mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
- mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
- mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
- mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
- mapproxy/test/system/fixture/cache_s3.yaml +58 -0
- mapproxy/test/system/fixture/cache_source.yaml +81 -0
- mapproxy/test/system/fixture/combined_sources.yaml +130 -0
- mapproxy/test/system/fixture/coverage.yaml +77 -0
- mapproxy/test/system/fixture/demo.yaml +135 -0
- mapproxy/test/system/fixture/dimension.yaml +59 -0
- mapproxy/test/system/fixture/disable_storage.yaml +25 -0
- mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
- mapproxy/test/system/fixture/formats.yaml +72 -0
- mapproxy/test/system/fixture/inspire.yaml +101 -0
- mapproxy/test/system/fixture/inspire_full.yaml +124 -0
- mapproxy/test/system/fixture/kml_layer.yaml +66 -0
- mapproxy/test/system/fixture/layer.yaml +260 -0
- mapproxy/test/system/fixture/layergroups.yaml +57 -0
- mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
- mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
- mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
- mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
- mapproxy/test/system/fixture/mapserver.yaml +23 -0
- mapproxy/test/system/fixture/minimal_cgi.py +16 -0
- mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
- mapproxy/test/system/fixture/multi_cache_layers.yaml +100 -0
- mapproxy/test/system/fixture/multiapp1.yaml +20 -0
- mapproxy/test/system/fixture/multiapp2.yaml +19 -0
- mapproxy/test/system/fixture/renderd_client.yaml +55 -0
- mapproxy/test/system/fixture/scalehints.yaml +70 -0
- mapproxy/test/system/fixture/seed.yaml +94 -0
- mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
- mapproxy/test/system/fixture/seed_old.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
- mapproxy/test/system/fixture/seedonly.yaml +51 -0
- mapproxy/test/system/fixture/sld.yaml +35 -0
- mapproxy/test/system/fixture/source_errors.yaml +84 -0
- mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
- mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
- mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
- mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
- mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
- mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
- mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
- mapproxy/test/system/fixture/util_grids.yaml +30 -0
- mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
- mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
- mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
- mapproxy/test/system/fixture/watermark.yaml +50 -0
- mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
- mapproxy/test/system/fixture/wms_versions.yaml +38 -0
- mapproxy/test/system/fixture/wmts.yaml +134 -0
- mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
- mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
- mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
- mapproxy/test/system/test_arcgis.py +156 -0
- mapproxy/test/system/test_auth.py +1134 -0
- mapproxy/test/system/test_behind_proxy.py +75 -0
- mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
- mapproxy/test/system/test_cache_azureblob.py +127 -0
- mapproxy/test/system/test_cache_band_merge.py +103 -0
- mapproxy/test/system/test_cache_geopackage.py +144 -0
- mapproxy/test/system/test_cache_grid_names.py +89 -0
- mapproxy/test/system/test_cache_mbtiles.py +85 -0
- mapproxy/test/system/test_cache_s3.py +115 -0
- mapproxy/test/system/test_cache_source.py +146 -0
- mapproxy/test/system/test_combined_sources.py +335 -0
- mapproxy/test/system/test_coverage.py +140 -0
- mapproxy/test/system/test_decorate_img.py +214 -0
- mapproxy/test/system/test_demo.py +106 -0
- mapproxy/test/system/test_demo_with_extra_service.py +53 -0
- mapproxy/test/system/test_dimensions.py +278 -0
- mapproxy/test/system/test_disable_storage.py +42 -0
- mapproxy/test/system/test_formats.py +219 -0
- mapproxy/test/system/test_inspire_vs.py +173 -0
- mapproxy/test/system/test_kml.py +262 -0
- mapproxy/test/system/test_layergroups.py +160 -0
- mapproxy/test/system/test_legendgraphic.py +308 -0
- mapproxy/test/system/test_mapnik.py +161 -0
- mapproxy/test/system/test_mapserver.py +81 -0
- mapproxy/test/system/test_mixed_mode_format.py +195 -0
- mapproxy/test/system/test_multi_cache_layers.py +167 -0
- mapproxy/test/system/test_multiapp.py +92 -0
- mapproxy/test/system/test_refresh.py +207 -0
- mapproxy/test/system/test_renderd_client.py +304 -0
- mapproxy/test/system/test_response_headers.py +54 -0
- mapproxy/test/system/test_scalehints.py +140 -0
- mapproxy/test/system/test_seed.py +422 -0
- mapproxy/test/system/test_seed_only.py +93 -0
- mapproxy/test/system/test_sld.py +120 -0
- mapproxy/test/system/test_source_errors.py +377 -0
- mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
- mapproxy/test/system/test_tms.py +276 -0
- mapproxy/test/system/test_tms_origin.py +46 -0
- mapproxy/test/system/test_util_conf.py +304 -0
- mapproxy/test/system/test_util_export.py +210 -0
- mapproxy/test/system/test_util_grids.py +88 -0
- mapproxy/test/system/test_util_wms_capabilities.py +182 -0
- mapproxy/test/system/test_watermark.py +91 -0
- mapproxy/test/system/test_wms.py +1611 -0
- mapproxy/test/system/test_wms_srs_extent.py +165 -0
- mapproxy/test/system/test_wms_version.py +85 -0
- mapproxy/test/system/test_wmsc.py +116 -0
- mapproxy/test/system/test_wmts.py +334 -0
- mapproxy/test/system/test_wmts_dimensions.py +206 -0
- mapproxy/test/system/test_wmts_restful.py +198 -0
- mapproxy/test/system/test_xslt_featureinfo.py +425 -0
- mapproxy/test/test_http_helper.py +219 -0
- mapproxy/test/unit/__init__.py +0 -0
- mapproxy/test/unit/epsg +2 -0
- mapproxy/test/unit/polygons/polygons.dbf +0 -0
- mapproxy/test/unit/polygons/polygons.shp +0 -0
- mapproxy/test/unit/polygons/polygons.shx +0 -0
- mapproxy/test/unit/test_async.py +245 -0
- mapproxy/test/unit/test_auth.py +419 -0
- mapproxy/test/unit/test_cache.py +1193 -0
- mapproxy/test/unit/test_cache_azureblob.py +94 -0
- mapproxy/test/unit/test_cache_compact.py +319 -0
- mapproxy/test/unit/test_cache_couchdb.py +114 -0
- mapproxy/test/unit/test_cache_geopackage.py +221 -0
- mapproxy/test/unit/test_cache_redis.py +67 -0
- mapproxy/test/unit/test_cache_riak.py +76 -0
- mapproxy/test/unit/test_cache_s3.py +84 -0
- mapproxy/test/unit/test_cache_tile.py +427 -0
- mapproxy/test/unit/test_client.py +479 -0
- mapproxy/test/unit/test_client_arcgis.py +73 -0
- mapproxy/test/unit/test_client_cgi.py +136 -0
- mapproxy/test/unit/test_collections.py +116 -0
- mapproxy/test/unit/test_concat_legends.py +37 -0
- mapproxy/test/unit/test_conf_loader.py +1061 -0
- mapproxy/test/unit/test_conf_validator.py +416 -0
- mapproxy/test/unit/test_config.py +117 -0
- mapproxy/test/unit/test_decorate_img.py +185 -0
- mapproxy/test/unit/test_exceptions.py +258 -0
- mapproxy/test/unit/test_featureinfo.py +291 -0
- mapproxy/test/unit/test_file_lock_load.py +49 -0
- mapproxy/test/unit/test_geom.py +503 -0
- mapproxy/test/unit/test_grid.py +1258 -0
- mapproxy/test/unit/test_image.py +1053 -0
- mapproxy/test/unit/test_image_mask.py +181 -0
- mapproxy/test/unit/test_image_messages.py +197 -0
- mapproxy/test/unit/test_image_options.py +160 -0
- mapproxy/test/unit/test_isodate.py +122 -0
- mapproxy/test/unit/test_multiapp.py +163 -0
- mapproxy/test/unit/test_ogr_reader.py +50 -0
- mapproxy/test/unit/test_request.py +745 -0
- mapproxy/test/unit/test_request_wmts.py +178 -0
- mapproxy/test/unit/test_response.py +79 -0
- mapproxy/test/unit/test_seed.py +365 -0
- mapproxy/test/unit/test_seed_cachelock.py +90 -0
- mapproxy/test/unit/test_srs.py +215 -0
- mapproxy/test/unit/test_tiled_source.py +122 -0
- mapproxy/test/unit/test_tilefilter.py +31 -0
- mapproxy/test/unit/test_times.py +25 -0
- mapproxy/test/unit/test_timeutils.py +50 -0
- mapproxy/test/unit/test_util_conf_utils.py +75 -0
- mapproxy/test/unit/test_utils.py +476 -0
- mapproxy/test/unit/test_wms_capabilities.py +44 -0
- mapproxy/test/unit/test_wms_layer.py +113 -0
- mapproxy/test/unit/test_yaml.py +69 -0
- mapproxy/tilefilter.py +59 -0
- mapproxy/util/__init__.py +0 -0
- mapproxy/util/async_.py +227 -0
- mapproxy/util/collections.py +132 -0
- mapproxy/util/coverage.py +329 -0
- mapproxy/util/escape.py +10 -0
- mapproxy/util/ext/__init__.py +14 -0
- mapproxy/util/ext/dictspec/__init__.py +1 -0
- mapproxy/util/ext/dictspec/spec.py +124 -0
- mapproxy/util/ext/dictspec/test/__init__.py +0 -0
- mapproxy/util/ext/dictspec/test/test_validator.py +274 -0
- mapproxy/util/ext/dictspec/validator.py +189 -0
- mapproxy/util/ext/local.py +196 -0
- mapproxy/util/ext/lockfile.py +138 -0
- mapproxy/util/ext/odict.py +330 -0
- mapproxy/util/ext/serving.py +508 -0
- mapproxy/util/ext/tempita/__init__.py +1174 -0
- mapproxy/util/ext/tempita/_looper.py +163 -0
- mapproxy/util/ext/tempita/compat3.py +46 -0
- mapproxy/util/ext/wmsparse/__init__.py +3 -0
- mapproxy/util/ext/wmsparse/duration.py +597 -0
- mapproxy/util/ext/wmsparse/parse.py +305 -0
- mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
- mapproxy/util/ext/wmsparse/test/test_parse.py +162 -0
- mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
- mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
- mapproxy/util/ext/wmsparse/test/wms-omniscale-111.xml +90 -0
- mapproxy/util/ext/wmsparse/test/wms-omniscale-130.xml +120 -0
- mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
- mapproxy/util/ext/wmsparse/util.py +187 -0
- mapproxy/util/fs.py +156 -0
- mapproxy/util/geom.py +295 -0
- mapproxy/util/lib.py +115 -0
- mapproxy/util/lock.py +163 -0
- mapproxy/util/ogr.py +231 -0
- mapproxy/util/py.py +81 -0
- mapproxy/util/times.py +75 -0
- mapproxy/util/yaml.py +56 -0
- mapproxy/version.py +31 -0
- mapproxy/wsgiapp.py +164 -0
- mapproxy-1.16.1.dist-info/METADATA +151 -0
- mapproxy-1.16.1.dist-info/RECORD +458 -0
- mapproxy-1.16.1.dist-info/WHEEL +5 -0
- mapproxy-1.16.1.dist-info/entry_points.txt +3 -0
- mapproxy-1.16.1.dist-info/licenses/AUTHORS.txt +33 -0
- mapproxy-1.16.1.dist-info/licenses/COPYING.txt +60 -0
- mapproxy-1.16.1.dist-info/licenses/LICENSE.txt +202 -0
- mapproxy-1.16.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,609 @@
|
|
|
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
|
+
|
|
17
|
+
import hashlib
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
import re
|
|
21
|
+
import sqlite3
|
|
22
|
+
import threading
|
|
23
|
+
|
|
24
|
+
from mapproxy.cache.base import TileCacheBase, tile_buffer, REMOVE_ON_UNLOCK
|
|
25
|
+
from mapproxy.compat import BytesIO, PY2, itertools
|
|
26
|
+
from mapproxy.image import ImageSource
|
|
27
|
+
from mapproxy.srs import get_epsg_num
|
|
28
|
+
from mapproxy.util.fs import ensure_directory
|
|
29
|
+
from mapproxy.util.lock import FileLock
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
log = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
class GeopackageCache(TileCacheBase):
|
|
35
|
+
supports_timestamp = False
|
|
36
|
+
|
|
37
|
+
def __init__(self, geopackage_file, tile_grid, table_name, with_timestamps=False, timeout=30, wal=False):
|
|
38
|
+
self.tile_grid = tile_grid
|
|
39
|
+
self.table_name = self._check_table_name(table_name)
|
|
40
|
+
self.lock_cache_id = 'gpkg' + hashlib.md5(geopackage_file.encode('utf-8')).hexdigest()
|
|
41
|
+
self.geopackage_file = geopackage_file
|
|
42
|
+
# XXX timestamps not implemented
|
|
43
|
+
self.supports_timestamp = with_timestamps
|
|
44
|
+
self.timeout = timeout
|
|
45
|
+
self.wal = wal
|
|
46
|
+
self.ensure_gpkg()
|
|
47
|
+
self._db_conn_cache = threading.local()
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def db(self):
|
|
51
|
+
if not getattr(self._db_conn_cache, 'db', None):
|
|
52
|
+
self.ensure_gpkg()
|
|
53
|
+
self._db_conn_cache.db = sqlite3.connect(self.geopackage_file, timeout=self.timeout)
|
|
54
|
+
return self._db_conn_cache.db
|
|
55
|
+
|
|
56
|
+
def cleanup(self):
|
|
57
|
+
"""
|
|
58
|
+
Close all open connection and remove them from cache.
|
|
59
|
+
"""
|
|
60
|
+
if getattr(self._db_conn_cache, 'db', None):
|
|
61
|
+
self._db_conn_cache.db.close()
|
|
62
|
+
self._db_conn_cache.db = None
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def _check_table_name(table_name):
|
|
66
|
+
"""
|
|
67
|
+
>>> GeopackageCache._check_table_name("test")
|
|
68
|
+
'test'
|
|
69
|
+
>>> GeopackageCache._check_table_name("test_2")
|
|
70
|
+
'test_2'
|
|
71
|
+
>>> GeopackageCache._check_table_name("test-2")
|
|
72
|
+
'test-2'
|
|
73
|
+
>>> GeopackageCache._check_table_name("test3;")
|
|
74
|
+
Traceback (most recent call last):
|
|
75
|
+
...
|
|
76
|
+
ValueError: The table_name test3; contains unsupported characters.
|
|
77
|
+
>>> GeopackageCache._check_table_name("table name")
|
|
78
|
+
Traceback (most recent call last):
|
|
79
|
+
...
|
|
80
|
+
ValueError: The table_name table name contains unsupported characters.
|
|
81
|
+
|
|
82
|
+
@param table_name: A desired name for an geopackage table.
|
|
83
|
+
@return: The name of the table if it is good, otherwise an exception.
|
|
84
|
+
"""
|
|
85
|
+
# Regex string indicating table names which will be accepted.
|
|
86
|
+
regex_str = '^[a-zA-Z0-9_-]+$'
|
|
87
|
+
if re.match(regex_str, table_name):
|
|
88
|
+
return table_name
|
|
89
|
+
else:
|
|
90
|
+
msg = ("The table name may only contain alphanumeric characters, an underscore, "
|
|
91
|
+
"or a dash: {}".format(regex_str))
|
|
92
|
+
log.info(msg)
|
|
93
|
+
raise ValueError("The table_name {0} contains unsupported characters.".format(table_name))
|
|
94
|
+
|
|
95
|
+
def ensure_gpkg(self):
|
|
96
|
+
if not os.path.isfile(self.geopackage_file):
|
|
97
|
+
with FileLock(self.geopackage_file + '.init.lck',
|
|
98
|
+
remove_on_unlock=REMOVE_ON_UNLOCK):
|
|
99
|
+
ensure_directory(self.geopackage_file)
|
|
100
|
+
self._initialize_gpkg()
|
|
101
|
+
else:
|
|
102
|
+
if not self.check_gpkg():
|
|
103
|
+
ensure_directory(self.geopackage_file)
|
|
104
|
+
self._initialize_gpkg()
|
|
105
|
+
|
|
106
|
+
def check_gpkg(self):
|
|
107
|
+
if not self._verify_table():
|
|
108
|
+
return False
|
|
109
|
+
if not self._verify_gpkg_contents():
|
|
110
|
+
return False
|
|
111
|
+
if not self._verify_tile_size():
|
|
112
|
+
return False
|
|
113
|
+
return True
|
|
114
|
+
|
|
115
|
+
def _verify_table(self):
|
|
116
|
+
with sqlite3.connect(self.geopackage_file) as db:
|
|
117
|
+
cur = db.execute("""SELECT name FROM sqlite_master WHERE type='table' AND name=?""",
|
|
118
|
+
(self.table_name,))
|
|
119
|
+
content = cur.fetchone()
|
|
120
|
+
if not content:
|
|
121
|
+
# Table doesn't exist _initialize_gpkg will create a new one.
|
|
122
|
+
return False
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
def _verify_gpkg_contents(self):
|
|
126
|
+
with sqlite3.connect(self.geopackage_file) as db:
|
|
127
|
+
cur = db.execute("""SELECT * FROM gpkg_contents WHERE table_name = ?"""
|
|
128
|
+
, (self.table_name,))
|
|
129
|
+
|
|
130
|
+
results = cur.fetchone()
|
|
131
|
+
if not results:
|
|
132
|
+
# Table doesn't exist in gpkg_contents _initialize_gpkg will add it.
|
|
133
|
+
return False
|
|
134
|
+
gpkg_data_type = results[1]
|
|
135
|
+
gpkg_srs_id = results[9]
|
|
136
|
+
cur = db.execute("""SELECT * FROM gpkg_spatial_ref_sys WHERE srs_id = ?"""
|
|
137
|
+
, (gpkg_srs_id,))
|
|
138
|
+
|
|
139
|
+
gpkg_coordsys_id = cur.fetchone()[3]
|
|
140
|
+
if gpkg_data_type.lower() != "tiles":
|
|
141
|
+
log.info("The geopackage table name already exists for a data type other than tiles.")
|
|
142
|
+
raise ValueError("table_name is improperly configured.")
|
|
143
|
+
if gpkg_coordsys_id != get_epsg_num(self.tile_grid.srs.srs_code):
|
|
144
|
+
log.info(
|
|
145
|
+
"The geopackage {0} table name {1} already exists and has an SRS of {2}, which does not match the configured" \
|
|
146
|
+
" Mapproxy SRS of {3}.".format(self.geopackage_file, self.table_name, gpkg_coordsys_id,
|
|
147
|
+
get_epsg_num(self.tile_grid.srs.srs_code)))
|
|
148
|
+
raise ValueError("srs is improperly configured.")
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
def _verify_tile_size(self):
|
|
152
|
+
with sqlite3.connect(self.geopackage_file) as db:
|
|
153
|
+
cur = db.execute(
|
|
154
|
+
"""SELECT * FROM gpkg_tile_matrix WHERE table_name = ?""",
|
|
155
|
+
(self.table_name,))
|
|
156
|
+
|
|
157
|
+
results = cur.fetchall()
|
|
158
|
+
results = results[0]
|
|
159
|
+
tile_size = self.tile_grid.tile_size
|
|
160
|
+
|
|
161
|
+
if not results:
|
|
162
|
+
# There is no tile conflict. Return to allow the creation of new tiles.
|
|
163
|
+
return True
|
|
164
|
+
|
|
165
|
+
gpkg_table_name, gpkg_zoom_level, gpkg_matrix_width, gpkg_matrix_height, gpkg_tile_width, gpkg_tile_height, \
|
|
166
|
+
gpkg_pixel_x_size, gpkg_pixel_y_size = results
|
|
167
|
+
resolution = self.tile_grid.resolution(gpkg_zoom_level)
|
|
168
|
+
if gpkg_tile_width != tile_size[0] or gpkg_tile_height != tile_size[1]:
|
|
169
|
+
log.info(
|
|
170
|
+
"The geopackage {0} table name {1} already exists and has tile sizes of ({2},{3})"
|
|
171
|
+
" which is different than the configure tile sizes of ({4},{5}).".format(self.geopackage_file,
|
|
172
|
+
self.table_name,
|
|
173
|
+
gpkg_tile_width,
|
|
174
|
+
gpkg_tile_height,
|
|
175
|
+
tile_size[0],
|
|
176
|
+
tile_size[1]))
|
|
177
|
+
log.info("The current mapproxy configuration is invalid for this geopackage.")
|
|
178
|
+
raise ValueError("tile_size is improperly configured.")
|
|
179
|
+
if not is_close(gpkg_pixel_x_size, resolution) or not is_close(gpkg_pixel_y_size, resolution):
|
|
180
|
+
log.info(
|
|
181
|
+
"The geopackage {0} table name {1} already exists and level {2} a resolution of ({3:.13f},{4:.13f})"
|
|
182
|
+
" which is different than the configured resolution of ({5:.13f},{6:.13f}).".format(self.geopackage_file,
|
|
183
|
+
self.table_name,
|
|
184
|
+
gpkg_zoom_level,
|
|
185
|
+
gpkg_pixel_x_size,
|
|
186
|
+
gpkg_pixel_y_size,
|
|
187
|
+
resolution,
|
|
188
|
+
resolution))
|
|
189
|
+
log.info("The current mapproxy configuration is invalid for this geopackage.")
|
|
190
|
+
raise ValueError("res is improperly configured.")
|
|
191
|
+
return True
|
|
192
|
+
|
|
193
|
+
def _initialize_gpkg(self):
|
|
194
|
+
log.info('initializing Geopackage file %s', self.geopackage_file)
|
|
195
|
+
db = sqlite3.connect(self.geopackage_file)
|
|
196
|
+
|
|
197
|
+
if self.wal:
|
|
198
|
+
db.execute('PRAGMA journal_mode=wal')
|
|
199
|
+
|
|
200
|
+
proj = get_epsg_num(self.tile_grid.srs.srs_code)
|
|
201
|
+
stmts = ["""
|
|
202
|
+
CREATE TABLE IF NOT EXISTS gpkg_contents
|
|
203
|
+
(table_name TEXT NOT NULL PRIMARY KEY, -- The name of the tiles, or feature table
|
|
204
|
+
data_type TEXT NOT NULL, -- Type of data stored in the table: "features" per clause Features (http://www.geopackage.org/spec/#features), "tiles" per clause Tiles (http://www.geopackage.org/spec/#tiles), or an implementer-defined value for other data tables per clause in an Extended GeoPackage
|
|
205
|
+
identifier TEXT UNIQUE, -- A human-readable identifier (e.g. short name) for the table_name content
|
|
206
|
+
description TEXT DEFAULT '', -- A human-readable description for the table_name content
|
|
207
|
+
last_change DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), -- Timestamp value in ISO 8601 format as defined by the strftime function %Y-%m-%dT%H:%M:%fZ format string applied to the current time
|
|
208
|
+
min_x DOUBLE, -- Bounding box minimum easting or longitude for all content in table_name
|
|
209
|
+
min_y DOUBLE, -- Bounding box minimum northing or latitude for all content in table_name
|
|
210
|
+
max_x DOUBLE, -- Bounding box maximum easting or longitude for all content in table_name
|
|
211
|
+
max_y DOUBLE, -- Bounding box maximum northing or latitude for all content in table_name
|
|
212
|
+
srs_id INTEGER, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id; when data_type is features, SHALL also match gpkg_geometry_columns.srs_id; When data_type is tiles, SHALL also match gpkg_tile_matrix_set.srs.id
|
|
213
|
+
CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id))
|
|
214
|
+
""",
|
|
215
|
+
"""
|
|
216
|
+
CREATE TABLE IF NOT EXISTS gpkg_spatial_ref_sys
|
|
217
|
+
(srs_name TEXT NOT NULL, -- Human readable name of this SRS (Spatial Reference System)
|
|
218
|
+
srs_id INTEGER NOT NULL PRIMARY KEY, -- Unique identifier for each Spatial Reference System within a GeoPackage
|
|
219
|
+
organization TEXT NOT NULL, -- Case-insensitive name of the defining organization e.g. EPSG or epsg
|
|
220
|
+
organization_coordsys_id INTEGER NOT NULL, -- Numeric ID of the Spatial Reference System assigned by the organization
|
|
221
|
+
definition TEXT NOT NULL, -- Well-known Text representation of the Spatial Reference System
|
|
222
|
+
description TEXT)
|
|
223
|
+
""",
|
|
224
|
+
"""
|
|
225
|
+
CREATE TABLE IF NOT EXISTS gpkg_tile_matrix
|
|
226
|
+
(table_name TEXT NOT NULL, -- Tile Pyramid User Data Table Name
|
|
227
|
+
zoom_level INTEGER NOT NULL, -- 0 <= zoom_level <= max_level for table_name
|
|
228
|
+
matrix_width INTEGER NOT NULL, -- Number of columns (>= 1) in tile matrix at this zoom level
|
|
229
|
+
matrix_height INTEGER NOT NULL, -- Number of rows (>= 1) in tile matrix at this zoom level
|
|
230
|
+
tile_width INTEGER NOT NULL, -- Tile width in pixels (>= 1) for this zoom level
|
|
231
|
+
tile_height INTEGER NOT NULL, -- Tile height in pixels (>= 1) for this zoom level
|
|
232
|
+
pixel_x_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0)
|
|
233
|
+
pixel_y_size DOUBLE NOT NULL, -- In t_table_name srid units or default meters for srid 0 (>0)
|
|
234
|
+
CONSTRAINT pk_ttm PRIMARY KEY (table_name, zoom_level), CONSTRAINT fk_tmm_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name))
|
|
235
|
+
""",
|
|
236
|
+
"""
|
|
237
|
+
CREATE TABLE IF NOT EXISTS gpkg_tile_matrix_set
|
|
238
|
+
(table_name TEXT NOT NULL PRIMARY KEY, -- Tile Pyramid User Data Table Name
|
|
239
|
+
srs_id INTEGER NOT NULL, -- Spatial Reference System ID: gpkg_spatial_ref_sys.srs_id
|
|
240
|
+
min_x DOUBLE NOT NULL, -- Bounding box minimum easting or longitude for all content in table_name
|
|
241
|
+
min_y DOUBLE NOT NULL, -- Bounding box minimum northing or latitude for all content in table_name
|
|
242
|
+
max_x DOUBLE NOT NULL, -- Bounding box maximum easting or longitude for all content in table_name
|
|
243
|
+
max_y DOUBLE NOT NULL, -- Bounding box maximum northing or latitude for all content in table_name
|
|
244
|
+
CONSTRAINT fk_gtms_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name), CONSTRAINT fk_gtms_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id))
|
|
245
|
+
""",
|
|
246
|
+
"""
|
|
247
|
+
CREATE TABLE IF NOT EXISTS [{0}]
|
|
248
|
+
(id INTEGER PRIMARY KEY AUTOINCREMENT, -- Autoincrement primary key
|
|
249
|
+
zoom_level INTEGER NOT NULL, -- min(zoom_level) <= zoom_level <= max(zoom_level) for t_table_name
|
|
250
|
+
tile_column INTEGER NOT NULL, -- 0 to tile_matrix matrix_width - 1
|
|
251
|
+
tile_row INTEGER NOT NULL, -- 0 to tile_matrix matrix_height - 1
|
|
252
|
+
tile_data BLOB NOT NULL, -- Of an image MIME type specified in clauses Tile Encoding PNG, Tile Encoding JPEG, Tile Encoding WEBP
|
|
253
|
+
UNIQUE (zoom_level, tile_column, tile_row))
|
|
254
|
+
""".format(self.table_name)
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
for stmt in stmts:
|
|
258
|
+
db.execute(stmt)
|
|
259
|
+
|
|
260
|
+
db.execute("PRAGMA foreign_keys = 1;")
|
|
261
|
+
|
|
262
|
+
# List of WKT execute statements and data.("""
|
|
263
|
+
wkt_statement = """
|
|
264
|
+
INSERT OR REPLACE INTO gpkg_spatial_ref_sys (
|
|
265
|
+
srs_id,
|
|
266
|
+
organization,
|
|
267
|
+
organization_coordsys_id,
|
|
268
|
+
srs_name,
|
|
269
|
+
definition)
|
|
270
|
+
VALUES (?, ?, ?, ?, ?)
|
|
271
|
+
"""
|
|
272
|
+
wkt_entries = [(3857, 'epsg', 3857, 'WGS 84 / Pseudo-Mercator',
|
|
273
|
+
"""
|
|
274
|
+
PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,\
|
|
275
|
+
AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],\
|
|
276
|
+
UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],\
|
|
277
|
+
PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],\
|
|
278
|
+
PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],\
|
|
279
|
+
AUTHORITY["EPSG","3857"]]\
|
|
280
|
+
"""
|
|
281
|
+
),
|
|
282
|
+
(4326, 'epsg', 4326, 'WGS 84',
|
|
283
|
+
"""
|
|
284
|
+
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],\
|
|
285
|
+
AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,\
|
|
286
|
+
AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]\
|
|
287
|
+
"""
|
|
288
|
+
),
|
|
289
|
+
(-1, 'NONE', -1, ' ', 'undefined'),
|
|
290
|
+
(0, 'NONE', 0, ' ', 'undefined')
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
if get_epsg_num(self.tile_grid.srs.srs_code) not in [4326, 3857]:
|
|
294
|
+
wkt_entries.append((proj, 'epsg', proj, 'Not provided', "Added via Mapproxy."))
|
|
295
|
+
db.commit()
|
|
296
|
+
|
|
297
|
+
# Add geopackage version to the header (1.0)
|
|
298
|
+
db.execute("PRAGMA application_id = 1196437808;")
|
|
299
|
+
db.commit()
|
|
300
|
+
|
|
301
|
+
for wkt_entry in wkt_entries:
|
|
302
|
+
try:
|
|
303
|
+
db.execute(wkt_statement, (wkt_entry[0], wkt_entry[1], wkt_entry[2], wkt_entry[3], wkt_entry[4]))
|
|
304
|
+
except sqlite3.IntegrityError:
|
|
305
|
+
log.info("srs_id already exists.".format(wkt_entry[0]))
|
|
306
|
+
db.commit()
|
|
307
|
+
|
|
308
|
+
# Ensure that tile table exists here, don't overwrite a valid entry.
|
|
309
|
+
try:
|
|
310
|
+
db.execute("""
|
|
311
|
+
INSERT INTO gpkg_contents (
|
|
312
|
+
table_name,
|
|
313
|
+
data_type,
|
|
314
|
+
identifier,
|
|
315
|
+
description,
|
|
316
|
+
min_x,
|
|
317
|
+
max_x,
|
|
318
|
+
min_y,
|
|
319
|
+
max_y,
|
|
320
|
+
srs_id)
|
|
321
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
|
|
322
|
+
""", (self.table_name,
|
|
323
|
+
"tiles",
|
|
324
|
+
self.table_name,
|
|
325
|
+
"Created with Mapproxy.",
|
|
326
|
+
self.tile_grid.bbox[0],
|
|
327
|
+
self.tile_grid.bbox[2],
|
|
328
|
+
self.tile_grid.bbox[1],
|
|
329
|
+
self.tile_grid.bbox[3],
|
|
330
|
+
proj))
|
|
331
|
+
except sqlite3.IntegrityError:
|
|
332
|
+
pass
|
|
333
|
+
db.commit()
|
|
334
|
+
|
|
335
|
+
# Ensure that tile set exists here, don't overwrite a valid entry.
|
|
336
|
+
try:
|
|
337
|
+
db.execute("""
|
|
338
|
+
INSERT INTO gpkg_tile_matrix_set (table_name, srs_id, min_x, max_x, min_y, max_y)
|
|
339
|
+
VALUES (?, ?, ?, ?, ?, ?);
|
|
340
|
+
""", (
|
|
341
|
+
self.table_name, proj, self.tile_grid.bbox[0], self.tile_grid.bbox[2], self.tile_grid.bbox[1],
|
|
342
|
+
self.tile_grid.bbox[3]))
|
|
343
|
+
except sqlite3.IntegrityError:
|
|
344
|
+
pass
|
|
345
|
+
db.commit()
|
|
346
|
+
|
|
347
|
+
tile_size = self.tile_grid.tile_size
|
|
348
|
+
for grid, resolution, level in zip(self.tile_grid.grid_sizes,
|
|
349
|
+
self.tile_grid.resolutions, range(20)):
|
|
350
|
+
db.execute("""INSERT OR REPLACE INTO gpkg_tile_matrix
|
|
351
|
+
(table_name, zoom_level, matrix_width, matrix_height, tile_width, tile_height, pixel_x_size, pixel_y_size)
|
|
352
|
+
VALUES(?, ?, ?, ?, ?, ?, ?, ?)
|
|
353
|
+
""",
|
|
354
|
+
(self.table_name, level, grid[0], grid[1], tile_size[0], tile_size[1], resolution, resolution))
|
|
355
|
+
db.commit()
|
|
356
|
+
db.close()
|
|
357
|
+
|
|
358
|
+
def is_cached(self, tile, dimensions=None):
|
|
359
|
+
if tile.coord is None:
|
|
360
|
+
return True
|
|
361
|
+
if tile.source:
|
|
362
|
+
return True
|
|
363
|
+
|
|
364
|
+
return self.load_tile(tile, dimensions=dimensions)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def store_tile(self, tile, dimensions=None):
|
|
368
|
+
if tile.stored:
|
|
369
|
+
return True
|
|
370
|
+
return self._store_bulk([tile])
|
|
371
|
+
|
|
372
|
+
def store_tiles(self, tiles, dimensions=None):
|
|
373
|
+
tiles = [t for t in tiles if not t.stored]
|
|
374
|
+
return self._store_bulk(tiles)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def _store_bulk(self, tiles):
|
|
378
|
+
records = []
|
|
379
|
+
# tile_buffer (as_buffer) will encode the tile to the target format
|
|
380
|
+
# we collect all tiles before, to avoid having the db transaction
|
|
381
|
+
# open during this slow encoding
|
|
382
|
+
for tile in tiles:
|
|
383
|
+
with tile_buffer(tile) as buf:
|
|
384
|
+
if PY2:
|
|
385
|
+
content = buffer(buf.read())
|
|
386
|
+
else:
|
|
387
|
+
content = buf.read()
|
|
388
|
+
x, y, level = tile.coord
|
|
389
|
+
records.append((level, x, y, content))
|
|
390
|
+
|
|
391
|
+
cursor = self.db.cursor()
|
|
392
|
+
try:
|
|
393
|
+
stmt = "INSERT OR REPLACE INTO [{0}] (zoom_level, tile_column, tile_row, tile_data) VALUES (?,?,?,?)".format(
|
|
394
|
+
self.table_name)
|
|
395
|
+
cursor.executemany(stmt, records)
|
|
396
|
+
self.db.commit()
|
|
397
|
+
except sqlite3.OperationalError as ex:
|
|
398
|
+
log.warning('unable to store tile: %s', ex)
|
|
399
|
+
return False
|
|
400
|
+
return True
|
|
401
|
+
|
|
402
|
+
def load_tile(self, tile, with_metadata=False, dimensions=None):
|
|
403
|
+
if tile.source or tile.coord is None:
|
|
404
|
+
return True
|
|
405
|
+
|
|
406
|
+
cur = self.db.cursor()
|
|
407
|
+
cur.execute("""SELECT tile_data FROM [{0}]
|
|
408
|
+
WHERE tile_column = ? AND
|
|
409
|
+
tile_row = ? AND
|
|
410
|
+
zoom_level = ?""".format(self.table_name), tile.coord)
|
|
411
|
+
|
|
412
|
+
content = cur.fetchone()
|
|
413
|
+
if content:
|
|
414
|
+
tile.source = ImageSource(BytesIO(content[0]))
|
|
415
|
+
return True
|
|
416
|
+
else:
|
|
417
|
+
return False
|
|
418
|
+
|
|
419
|
+
def load_tiles(self, tiles, with_metadata=False, dimensions=None):
|
|
420
|
+
# associate the right tiles with the cursor
|
|
421
|
+
tile_dict = {}
|
|
422
|
+
coords = []
|
|
423
|
+
for tile in tiles:
|
|
424
|
+
if tile.source or tile.coord is None:
|
|
425
|
+
continue
|
|
426
|
+
x, y, level = tile.coord
|
|
427
|
+
coords.append(x)
|
|
428
|
+
coords.append(y)
|
|
429
|
+
coords.append(level)
|
|
430
|
+
tile_dict[(x, y)] = tile
|
|
431
|
+
|
|
432
|
+
if not tile_dict:
|
|
433
|
+
# all tiles loaded or coords are None
|
|
434
|
+
return True
|
|
435
|
+
|
|
436
|
+
stmt_base = "SELECT tile_column, tile_row, tile_data FROM [{0}] WHERE ".format(self.table_name)
|
|
437
|
+
|
|
438
|
+
loaded_tiles = 0
|
|
439
|
+
|
|
440
|
+
# SQLite is limited to 1000 args -> split into multiple requests if more arguments are needed
|
|
441
|
+
while coords:
|
|
442
|
+
cur_coords = coords[:999]
|
|
443
|
+
|
|
444
|
+
stmt = stmt_base + ' OR '.join(
|
|
445
|
+
['(tile_column = ? AND tile_row = ? AND zoom_level = ?)'] * (len(cur_coords) // 3))
|
|
446
|
+
|
|
447
|
+
cursor = self.db.cursor()
|
|
448
|
+
cursor.execute(stmt, cur_coords)
|
|
449
|
+
|
|
450
|
+
for row in cursor:
|
|
451
|
+
loaded_tiles += 1
|
|
452
|
+
tile = tile_dict[(row[0], row[1])]
|
|
453
|
+
data = row[2]
|
|
454
|
+
tile.size = len(data)
|
|
455
|
+
tile.source = ImageSource(BytesIO(data))
|
|
456
|
+
cursor.close()
|
|
457
|
+
|
|
458
|
+
coords = coords[999:]
|
|
459
|
+
|
|
460
|
+
return loaded_tiles == len(tile_dict)
|
|
461
|
+
|
|
462
|
+
def remove_tile(self, tile, dimensions=None):
|
|
463
|
+
cursor = self.db.cursor()
|
|
464
|
+
cursor.execute(
|
|
465
|
+
"DELETE FROM [{0}] WHERE (tile_column = ? AND tile_row = ? AND zoom_level = ?)".format(self.table_name),
|
|
466
|
+
tile.coord)
|
|
467
|
+
self.db.commit()
|
|
468
|
+
if cursor.rowcount:
|
|
469
|
+
return True
|
|
470
|
+
return False
|
|
471
|
+
|
|
472
|
+
def remove_level_tiles_before(self, level, timestamp):
|
|
473
|
+
if timestamp == 0:
|
|
474
|
+
cursor = self.db.cursor()
|
|
475
|
+
cursor.execute(
|
|
476
|
+
"DELETE FROM [{0}] WHERE (zoom_level = ?)".format(self.table_name), (level,))
|
|
477
|
+
self.db.commit()
|
|
478
|
+
log.info("Cursor rowcount = {0}".format(cursor.rowcount))
|
|
479
|
+
if cursor.rowcount:
|
|
480
|
+
return True
|
|
481
|
+
return False
|
|
482
|
+
|
|
483
|
+
def load_tile_metadata(self, tile, dimensions=None):
|
|
484
|
+
if not self.supports_timestamp:
|
|
485
|
+
# GPKG specification does not include tile timestamps.
|
|
486
|
+
# This sets the timestamp of the tile to epoch (1970s)
|
|
487
|
+
tile.timestamp = -1
|
|
488
|
+
else:
|
|
489
|
+
self.load_tile(tile, dimensions=dimensions)
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class GeopackageLevelCache(TileCacheBase):
|
|
493
|
+
|
|
494
|
+
def __init__(self, geopackage_dir, tile_grid, table_name, timeout=30, wal=False):
|
|
495
|
+
self.lock_cache_id = 'gpkg-' + hashlib.md5(geopackage_dir.encode('utf-8')).hexdigest()
|
|
496
|
+
self.cache_dir = geopackage_dir
|
|
497
|
+
self.tile_grid = tile_grid
|
|
498
|
+
self.table_name = table_name
|
|
499
|
+
self.timeout = timeout
|
|
500
|
+
self.wal = wal
|
|
501
|
+
self._geopackage = {}
|
|
502
|
+
self._geopackage_lock = threading.Lock()
|
|
503
|
+
|
|
504
|
+
def _get_level(self, level):
|
|
505
|
+
if level in self._geopackage:
|
|
506
|
+
return self._geopackage[level]
|
|
507
|
+
|
|
508
|
+
with self._geopackage_lock:
|
|
509
|
+
if level not in self._geopackage:
|
|
510
|
+
geopackage_filename = os.path.join(self.cache_dir, '%s.gpkg' % level)
|
|
511
|
+
self._geopackage[level] = GeopackageCache(
|
|
512
|
+
geopackage_filename,
|
|
513
|
+
self.tile_grid,
|
|
514
|
+
self.table_name,
|
|
515
|
+
with_timestamps=False,
|
|
516
|
+
timeout=self.timeout,
|
|
517
|
+
wal=self.wal,
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
return self._geopackage[level]
|
|
521
|
+
|
|
522
|
+
def cleanup(self):
|
|
523
|
+
"""
|
|
524
|
+
Close all open connection and remove them from cache.
|
|
525
|
+
"""
|
|
526
|
+
with self._geopackage_lock:
|
|
527
|
+
for gp in self._geopackage.values():
|
|
528
|
+
gp.cleanup()
|
|
529
|
+
|
|
530
|
+
def is_cached(self, tile, dimensions=None):
|
|
531
|
+
if tile.coord is None:
|
|
532
|
+
return True
|
|
533
|
+
if tile.source:
|
|
534
|
+
return True
|
|
535
|
+
|
|
536
|
+
return self._get_level(tile.coord[2]).is_cached(tile, dimensions=dimensions)
|
|
537
|
+
|
|
538
|
+
def store_tile(self, tile, dimensions=None):
|
|
539
|
+
if tile.stored:
|
|
540
|
+
return True
|
|
541
|
+
|
|
542
|
+
return self._get_level(tile.coord[2]).store_tile(tile, dimensions=dimensions)
|
|
543
|
+
|
|
544
|
+
def store_tiles(self, tiles, dimensions=None):
|
|
545
|
+
failed = False
|
|
546
|
+
for level, tiles in itertools.groupby(tiles, key=lambda t: t.coord[2]):
|
|
547
|
+
tiles = [t for t in tiles if not t.stored]
|
|
548
|
+
res = self._get_level(level).store_tiles(tiles, dimensions=dimensions)
|
|
549
|
+
if not res: failed = True
|
|
550
|
+
return failed
|
|
551
|
+
|
|
552
|
+
def load_tile(self, tile, with_metadata=False,dimensions=None):
|
|
553
|
+
if tile.source or tile.coord is None:
|
|
554
|
+
return True
|
|
555
|
+
|
|
556
|
+
return self._get_level(tile.coord[2]).load_tile(tile, with_metadata=with_metadata, dimensions=dimensions)
|
|
557
|
+
|
|
558
|
+
def load_tiles(self, tiles, with_metadata=False, dimensions=None):
|
|
559
|
+
level = None
|
|
560
|
+
for tile in tiles:
|
|
561
|
+
if tile.source or tile.coord is None:
|
|
562
|
+
continue
|
|
563
|
+
level = tile.coord[2]
|
|
564
|
+
break
|
|
565
|
+
|
|
566
|
+
if not level:
|
|
567
|
+
return True
|
|
568
|
+
|
|
569
|
+
return self._get_level(level).load_tiles(tiles, with_metadata=with_metadata, dimensions=dimensions)
|
|
570
|
+
|
|
571
|
+
def remove_tile(self, tile, dimensions=None):
|
|
572
|
+
if tile.coord is None:
|
|
573
|
+
return True
|
|
574
|
+
|
|
575
|
+
return self._get_level(tile.coord[2]).remove_tile(tile, dimensions=dimensions)
|
|
576
|
+
|
|
577
|
+
def remove_level_tiles_before(self, level, timestamp):
|
|
578
|
+
level_cache = self._get_level(level)
|
|
579
|
+
if timestamp == 0:
|
|
580
|
+
level_cache.cleanup()
|
|
581
|
+
os.unlink(level_cache.geopackage_file)
|
|
582
|
+
return True
|
|
583
|
+
else:
|
|
584
|
+
return level_cache.remove_level_tiles_before(level, timestamp)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def is_close(a, b, rel_tol=1e-09, abs_tol=0.0):
|
|
588
|
+
"""
|
|
589
|
+
See PEP 485, added here for legacy versions.
|
|
590
|
+
|
|
591
|
+
>>> is_close(0.0, 0.0)
|
|
592
|
+
True
|
|
593
|
+
>>> is_close(1, 1.0)
|
|
594
|
+
True
|
|
595
|
+
>>> is_close(0.01, 0.001)
|
|
596
|
+
False
|
|
597
|
+
>>> is_close(0.0001001, 0.0001, rel_tol=1e-02)
|
|
598
|
+
True
|
|
599
|
+
>>> is_close(0.0001001, 0.0001)
|
|
600
|
+
False
|
|
601
|
+
|
|
602
|
+
@param a: An int or float.
|
|
603
|
+
@param b: An int or float.
|
|
604
|
+
@param rel_tol: Relative tolerance - maximumed allow difference between two numbers.
|
|
605
|
+
@param abs_tol: Absolute tolerance - minimum absolute tolerance.
|
|
606
|
+
@return: True if the values a and b are close.
|
|
607
|
+
|
|
608
|
+
"""
|
|
609
|
+
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
|