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/util/fs.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2010-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
|
+
File system related utility functions.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import absolute_import
|
|
20
|
+
import time
|
|
21
|
+
import os
|
|
22
|
+
import sys
|
|
23
|
+
import random
|
|
24
|
+
import errno
|
|
25
|
+
import shutil
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def swap_dir(src_dir, dst_dir, keep_old=False, backup_ext='.tmp'):
|
|
29
|
+
"""
|
|
30
|
+
Rename `src_dir` to `dst_dir`. The `dst_dir` is first renamed to
|
|
31
|
+
`dst_dir` + `backup_ext` to keep the interruption short.
|
|
32
|
+
Then the `src_dir` is renamed. If `keep_old` is False, the old content
|
|
33
|
+
of `dst_dir` will be removed.
|
|
34
|
+
"""
|
|
35
|
+
tmp_dir = dst_dir + backup_ext
|
|
36
|
+
if os.path.exists(dst_dir):
|
|
37
|
+
os.rename(dst_dir, tmp_dir)
|
|
38
|
+
|
|
39
|
+
_force_rename_dir(src_dir, dst_dir)
|
|
40
|
+
|
|
41
|
+
if os.path.exists(tmp_dir) and not keep_old:
|
|
42
|
+
shutil.rmtree(tmp_dir)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _force_rename_dir(src_dir, dst_dir):
|
|
46
|
+
"""
|
|
47
|
+
Rename `src_dir` to `dst_dir`. If `dst_dir` exists, it will be removed.
|
|
48
|
+
"""
|
|
49
|
+
# someone might recreate the directory between rmtree and rename,
|
|
50
|
+
# so we try to remove it until we can rename our new directory
|
|
51
|
+
rename_tries = 0
|
|
52
|
+
while rename_tries < 10:
|
|
53
|
+
try:
|
|
54
|
+
os.rename(src_dir, dst_dir)
|
|
55
|
+
except OSError as ex:
|
|
56
|
+
if ex.errno == errno.ENOTEMPTY or ex.errno == errno.EEXIST:
|
|
57
|
+
if rename_tries > 0:
|
|
58
|
+
time.sleep(2**rename_tries / 100.0) # from 10ms to 5s
|
|
59
|
+
rename_tries += 1
|
|
60
|
+
shutil.rmtree(dst_dir)
|
|
61
|
+
else:
|
|
62
|
+
raise
|
|
63
|
+
else:
|
|
64
|
+
break # on success
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def cleanup_directory(directory, before_timestamp, remove_empty_dirs=True,
|
|
68
|
+
file_handler=None):
|
|
69
|
+
if file_handler is None:
|
|
70
|
+
if before_timestamp == 0 and remove_empty_dirs is True and os.path.exists(directory):
|
|
71
|
+
shutil.rmtree(directory, ignore_errors=True)
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
file_handler = os.remove
|
|
75
|
+
|
|
76
|
+
if os.path.exists(directory):
|
|
77
|
+
for dirpath, dirnames, filenames in os.walk(directory, topdown=False):
|
|
78
|
+
if not filenames:
|
|
79
|
+
if (remove_empty_dirs and not os.listdir(dirpath)
|
|
80
|
+
and dirpath != directory):
|
|
81
|
+
os.rmdir(dirpath)
|
|
82
|
+
continue
|
|
83
|
+
for filename in filenames:
|
|
84
|
+
filename = os.path.join(dirpath, filename)
|
|
85
|
+
try:
|
|
86
|
+
if before_timestamp == 0:
|
|
87
|
+
file_handler(filename)
|
|
88
|
+
if os.lstat(filename).st_mtime < before_timestamp:
|
|
89
|
+
file_handler(filename)
|
|
90
|
+
except OSError as ex:
|
|
91
|
+
if ex.errno != errno.ENOENT:
|
|
92
|
+
raise
|
|
93
|
+
|
|
94
|
+
if remove_empty_dirs:
|
|
95
|
+
remove_dir_if_emtpy(dirpath)
|
|
96
|
+
|
|
97
|
+
if remove_empty_dirs:
|
|
98
|
+
remove_dir_if_emtpy(directory)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def remove_dir_if_emtpy(directory):
|
|
102
|
+
try:
|
|
103
|
+
os.rmdir(directory)
|
|
104
|
+
except OSError as ex:
|
|
105
|
+
if ex.errno != errno.ENOENT and ex.errno != errno.ENOTEMPTY:
|
|
106
|
+
raise
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def ensure_directory(file_name):
|
|
110
|
+
"""
|
|
111
|
+
Create directory if it does not exist, else do nothing.
|
|
112
|
+
"""
|
|
113
|
+
dir_name = os.path.dirname(file_name)
|
|
114
|
+
if not os.path.exists(dir_name):
|
|
115
|
+
try:
|
|
116
|
+
os.makedirs(dir_name)
|
|
117
|
+
except OSError as e:
|
|
118
|
+
if e.errno != errno.EEXIST:
|
|
119
|
+
raise e
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def write_atomic(filename, data):
|
|
123
|
+
"""
|
|
124
|
+
write_atomic writes `data` to a random file in filename's directory
|
|
125
|
+
first and renames that file to the target filename afterwards.
|
|
126
|
+
Rename is atomic on all POSIX platforms.
|
|
127
|
+
|
|
128
|
+
Falls back to normal write on Windows.
|
|
129
|
+
"""
|
|
130
|
+
if not sys.platform.startswith('win'):
|
|
131
|
+
# write to random filename to prevent concurrent writes in cases
|
|
132
|
+
# where file locking does not work (network fs)
|
|
133
|
+
path_tmp = filename + '.tmp-' + str(random.randint(0, 99999999))
|
|
134
|
+
try:
|
|
135
|
+
fd = os.open(path_tmp, os.O_EXCL | os.O_CREAT | os.O_WRONLY, 0o664)
|
|
136
|
+
with os.fdopen(fd, 'wb') as f:
|
|
137
|
+
f.write(data)
|
|
138
|
+
os.rename(path_tmp, filename)
|
|
139
|
+
except OSError as ex:
|
|
140
|
+
try:
|
|
141
|
+
os.unlink(path_tmp)
|
|
142
|
+
except OSError:
|
|
143
|
+
pass
|
|
144
|
+
raise ex
|
|
145
|
+
else:
|
|
146
|
+
fd = os.open(filename, os.O_CREAT | os.O_WRONLY, 0o664)
|
|
147
|
+
with os.fdopen(fd, 'wb') as f:
|
|
148
|
+
f.write(data)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def find_exec(executable):
|
|
152
|
+
"""
|
|
153
|
+
Search executable in PATH environment. Return path if found, None if not.
|
|
154
|
+
"""
|
|
155
|
+
path = os.environ.get('PATH')
|
|
156
|
+
if not path:
|
|
157
|
+
return
|
|
158
|
+
for p in path.split(os.path.pathsep):
|
|
159
|
+
p = os.path.join(p, executable)
|
|
160
|
+
if os.path.exists(p):
|
|
161
|
+
return p
|
|
162
|
+
p += '.exe'
|
|
163
|
+
if os.path.exists(p):
|
|
164
|
+
return p
|
mapproxy/util/geom.py
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2010 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from __future__ import division
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import json
|
|
20
|
+
import codecs
|
|
21
|
+
from functools import partial
|
|
22
|
+
from contextlib import closing
|
|
23
|
+
|
|
24
|
+
from mapproxy.grid import tile_grid
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
log_config = logging.getLogger('mapproxy.config.coverage')
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
import shapely.wkt
|
|
31
|
+
import shapely.geometry
|
|
32
|
+
import shapely.ops
|
|
33
|
+
import shapely.prepared
|
|
34
|
+
from shapely.errors import ShapelyError
|
|
35
|
+
geom_support = True
|
|
36
|
+
except ImportError:
|
|
37
|
+
geom_support = False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class GeometryError(Exception):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class EmptyGeometryError(Exception):
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CoverageReadError(Exception):
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def require_geom_support():
|
|
53
|
+
if not geom_support:
|
|
54
|
+
raise ImportError('Shapely required for geometry support')
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def load_datasource(datasource, where=None):
|
|
58
|
+
"""
|
|
59
|
+
Loads polygons from WKT text files or OGR datasources.
|
|
60
|
+
|
|
61
|
+
Returns a list of Shapely Polygons.
|
|
62
|
+
"""
|
|
63
|
+
# check if it is a wkt or geojson file
|
|
64
|
+
if os.path.exists(os.path.abspath(datasource)):
|
|
65
|
+
with open(os.path.abspath(datasource), 'rb') as fp:
|
|
66
|
+
data = fp.read(50)
|
|
67
|
+
if data.lower().lstrip().startswith((b'polygon', b'multipolygon')):
|
|
68
|
+
return load_polygons(datasource)
|
|
69
|
+
# only load geojson directly if we don't have a filter
|
|
70
|
+
if where is None and data and data.startswith(b'{'):
|
|
71
|
+
return load_geojson(datasource)
|
|
72
|
+
# otherwise pass to OGR
|
|
73
|
+
return load_ogr_datasource(datasource, where=where)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def load_ogr_datasource(datasource, where=None):
|
|
77
|
+
"""
|
|
78
|
+
Loads polygons from any OGR datasource.
|
|
79
|
+
|
|
80
|
+
Returns a list of Shapely Polygons.
|
|
81
|
+
"""
|
|
82
|
+
from mapproxy.util.ogr import OGRShapeReader, OGRShapeReaderError
|
|
83
|
+
|
|
84
|
+
polygons = []
|
|
85
|
+
try:
|
|
86
|
+
with closing(OGRShapeReader(datasource)) as reader:
|
|
87
|
+
for wkt in reader.wkts(where):
|
|
88
|
+
if not isinstance(wkt, str):
|
|
89
|
+
wkt = wkt.decode()
|
|
90
|
+
try:
|
|
91
|
+
geom = shapely.wkt.loads(wkt)
|
|
92
|
+
except ShapelyError as ex:
|
|
93
|
+
raise GeometryError(ex)
|
|
94
|
+
if geom.geom_type == 'Polygon':
|
|
95
|
+
polygons.append(geom)
|
|
96
|
+
elif geom.geom_type == 'MultiPolygon':
|
|
97
|
+
for p in geom.geoms:
|
|
98
|
+
polygons.append(p)
|
|
99
|
+
else:
|
|
100
|
+
log_config.warning('skipping %s geometry from %s: not a Polygon/MultiPolygon',
|
|
101
|
+
geom.geom_type, datasource)
|
|
102
|
+
except OGRShapeReaderError as ex:
|
|
103
|
+
raise CoverageReadError(ex)
|
|
104
|
+
|
|
105
|
+
return polygons
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def load_polygons(geom_files):
|
|
109
|
+
"""
|
|
110
|
+
Loads WKT polygons from one or more text files.
|
|
111
|
+
|
|
112
|
+
Returns a list of Shapely Polygons.
|
|
113
|
+
"""
|
|
114
|
+
polygons = []
|
|
115
|
+
if isinstance(geom_files, str):
|
|
116
|
+
geom_files = [geom_files]
|
|
117
|
+
|
|
118
|
+
for geom_file in geom_files:
|
|
119
|
+
# open with utf-8-sig encoding to get rid of UTF8 BOM from MS Notepad
|
|
120
|
+
with codecs.open(geom_file, encoding='utf-8-sig') as f:
|
|
121
|
+
polygons.extend(load_polygon_lines(f, source=geom_files))
|
|
122
|
+
|
|
123
|
+
return polygons
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def load_geojson(datasource):
|
|
127
|
+
with open(datasource) as f:
|
|
128
|
+
geojson = json.load(f)
|
|
129
|
+
t = geojson.get('type')
|
|
130
|
+
if not t:
|
|
131
|
+
raise CoverageReadError("not a GeoJSON")
|
|
132
|
+
geometries = []
|
|
133
|
+
if t == 'FeatureCollection':
|
|
134
|
+
for f in geojson.get('features'):
|
|
135
|
+
geom = f.get('geometry')
|
|
136
|
+
if geom:
|
|
137
|
+
geometries.append(geom)
|
|
138
|
+
elif t == 'Feature':
|
|
139
|
+
if 'geometry' in geojson:
|
|
140
|
+
geometries.append(geojson['geometry'])
|
|
141
|
+
elif t in ('Polygon', 'MultiPolygon'):
|
|
142
|
+
geometries.append(geojson)
|
|
143
|
+
else:
|
|
144
|
+
log_config.warning('skipping feature of type %s from %s: not a Polygon/MultiPolygon',
|
|
145
|
+
t, datasource)
|
|
146
|
+
|
|
147
|
+
polygons = []
|
|
148
|
+
for geom in geometries:
|
|
149
|
+
geom = shapely.geometry.shape(geom)
|
|
150
|
+
if geom.geom_type == 'Polygon':
|
|
151
|
+
polygons.append(geom)
|
|
152
|
+
elif geom.geom_type == 'MultiPolygon':
|
|
153
|
+
for p in geom.geoms:
|
|
154
|
+
polygons.append(p)
|
|
155
|
+
else:
|
|
156
|
+
log_config.warning('ignoring non-polygon geometry (%s) from %s',
|
|
157
|
+
geom.geom_type, datasource)
|
|
158
|
+
|
|
159
|
+
return polygons
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def load_polygon_lines(line_iter, source='<string>'):
|
|
163
|
+
polygons = []
|
|
164
|
+
for line in line_iter:
|
|
165
|
+
if not line.strip():
|
|
166
|
+
continue
|
|
167
|
+
geom = shapely.wkt.loads(line)
|
|
168
|
+
if geom.geom_type == 'Polygon':
|
|
169
|
+
polygons.append(geom)
|
|
170
|
+
elif geom.geom_type == 'MultiPolygon':
|
|
171
|
+
for p in geom.geoms:
|
|
172
|
+
polygons.append(p)
|
|
173
|
+
else:
|
|
174
|
+
log_config.warning('ignoring non-polygon geometry (%s) from %s',
|
|
175
|
+
geom.geom_type, source)
|
|
176
|
+
|
|
177
|
+
return polygons
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def build_multipolygon(polygons, simplify=False):
|
|
181
|
+
if not polygons:
|
|
182
|
+
raise EmptyGeometryError('no polygons')
|
|
183
|
+
|
|
184
|
+
if len(polygons) == 1:
|
|
185
|
+
geom = polygons[0]
|
|
186
|
+
if simplify:
|
|
187
|
+
geom = simplify_geom(geom)
|
|
188
|
+
return geom.bounds, geom
|
|
189
|
+
|
|
190
|
+
if simplify:
|
|
191
|
+
polygons = [simplify_geom(g) for g in polygons]
|
|
192
|
+
|
|
193
|
+
# eliminate any self-overlaps
|
|
194
|
+
mp = shapely.ops.unary_union(polygons)
|
|
195
|
+
|
|
196
|
+
return mp.bounds, mp
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def simplify_geom(geom):
|
|
200
|
+
bounds = geom.bounds
|
|
201
|
+
if not bounds:
|
|
202
|
+
raise EmptyGeometryError('Empty geometry given')
|
|
203
|
+
w, h = bounds[2] - bounds[0], bounds[3] - bounds[1]
|
|
204
|
+
tolerance = min((w/1e6, h/1e6))
|
|
205
|
+
geom = geom.simplify(tolerance, preserve_topology=True)
|
|
206
|
+
if not geom.is_valid:
|
|
207
|
+
geom = geom.buffer(0)
|
|
208
|
+
return geom
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def bbox_polygon(bbox):
|
|
212
|
+
"""
|
|
213
|
+
Create Polygon that covers the given bbox.
|
|
214
|
+
"""
|
|
215
|
+
return shapely.geometry.Polygon((
|
|
216
|
+
(bbox[0], bbox[1]),
|
|
217
|
+
(bbox[2], bbox[1]),
|
|
218
|
+
(bbox[2], bbox[3]),
|
|
219
|
+
(bbox[0], bbox[3]),
|
|
220
|
+
))
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def transform_geometry(from_srs, to_srs, geometry):
|
|
224
|
+
transf = partial(transform_xy, from_srs, to_srs)
|
|
225
|
+
|
|
226
|
+
if geometry.geom_type == 'Polygon':
|
|
227
|
+
result = transform_polygon(transf, geometry)
|
|
228
|
+
elif geometry.geom_type == 'MultiPolygon':
|
|
229
|
+
result = transform_multipolygon(transf, geometry)
|
|
230
|
+
else:
|
|
231
|
+
raise ValueError('cannot transform %s' % geometry.geom_type)
|
|
232
|
+
|
|
233
|
+
if not result.is_valid:
|
|
234
|
+
result = result.buffer(0)
|
|
235
|
+
return result
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def transform_polygon(transf, polygon):
|
|
239
|
+
ext = transf(polygon.exterior.xy)
|
|
240
|
+
ints = [transf(ring.xy) for ring in polygon.interiors]
|
|
241
|
+
return shapely.geometry.Polygon(ext, ints)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def transform_multipolygon(transf, multipolygon):
|
|
245
|
+
transformed_polygons = []
|
|
246
|
+
for polygon in multipolygon.geoms:
|
|
247
|
+
transformed_polygons.append(transform_polygon(transf, polygon))
|
|
248
|
+
return shapely.geometry.MultiPolygon(transformed_polygons)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def transform_xy(from_srs, to_srs, xy):
|
|
252
|
+
return list(from_srs.transform_to(to_srs, list(zip(*xy))))
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def flatten_to_polygons(geometry):
|
|
256
|
+
"""
|
|
257
|
+
Return a list of all polygons of this (multi)`geometry`.
|
|
258
|
+
"""
|
|
259
|
+
if geometry.geom_type == 'Polygon':
|
|
260
|
+
return [geometry]
|
|
261
|
+
|
|
262
|
+
if geometry.geom_type == 'MultiPolygon':
|
|
263
|
+
return list(geometry.geoms)
|
|
264
|
+
|
|
265
|
+
if hasattr(geometry, 'geoms'):
|
|
266
|
+
# GeometryCollection or MultiLineString? return list of all polygons
|
|
267
|
+
geoms = []
|
|
268
|
+
for part in geometry.geoms:
|
|
269
|
+
if part.type == 'Polygon':
|
|
270
|
+
geoms.append(part)
|
|
271
|
+
|
|
272
|
+
if geoms:
|
|
273
|
+
return geoms
|
|
274
|
+
|
|
275
|
+
return []
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def load_expire_tiles(expire_dir, grid=None):
|
|
279
|
+
if grid is None:
|
|
280
|
+
grid = tile_grid(3857, origin='nw')
|
|
281
|
+
tiles = set()
|
|
282
|
+
|
|
283
|
+
def parse(filename):
|
|
284
|
+
with open(filename) as f:
|
|
285
|
+
try:
|
|
286
|
+
for line in f:
|
|
287
|
+
if not line:
|
|
288
|
+
continue
|
|
289
|
+
tile = tuple(map(int, line.split('/')))
|
|
290
|
+
tiles.add(tile)
|
|
291
|
+
except Exception:
|
|
292
|
+
log_config.warning('found error in %s, skipping rest of file', filename)
|
|
293
|
+
|
|
294
|
+
if os.path.isdir(expire_dir):
|
|
295
|
+
for root, dirs, files in os.walk(expire_dir):
|
|
296
|
+
for name in files:
|
|
297
|
+
filename = os.path.join(root, name)
|
|
298
|
+
parse(filename)
|
|
299
|
+
else:
|
|
300
|
+
parse(expire_dir)
|
|
301
|
+
|
|
302
|
+
boxes = []
|
|
303
|
+
for tile in tiles:
|
|
304
|
+
z, x, y = tile
|
|
305
|
+
boxes.append(shapely.geometry.box(*grid.tile_bbox((x, y, z))))
|
|
306
|
+
|
|
307
|
+
return boxes
|
mapproxy/util/lib.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
ctypes utilities.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import print_function
|
|
20
|
+
|
|
21
|
+
import sys
|
|
22
|
+
import os
|
|
23
|
+
|
|
24
|
+
from ctypes import CDLL
|
|
25
|
+
from ctypes.util import find_library as _find_library
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
default_locations = dict(
|
|
29
|
+
darwin=dict(
|
|
30
|
+
paths=['/opt/local/lib'],
|
|
31
|
+
exts=['.dylib'],
|
|
32
|
+
),
|
|
33
|
+
win32=dict(
|
|
34
|
+
paths=[os.path.dirname(os.__file__) + '/../../../DLLs'],
|
|
35
|
+
exts=['.dll']
|
|
36
|
+
),
|
|
37
|
+
other=dict(
|
|
38
|
+
paths=[], # MAPPROXY_LIB_PATH will add paths here
|
|
39
|
+
exts=['.so']
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
additional_lib_path = os.environ.get('MAPPROXY_LIB_PATH')
|
|
44
|
+
if additional_lib_path:
|
|
45
|
+
additional_lib_path = additional_lib_path.split(os.pathsep)
|
|
46
|
+
additional_lib_path.reverse()
|
|
47
|
+
for locs in default_locations.values():
|
|
48
|
+
for path in additional_lib_path:
|
|
49
|
+
locs['paths'].insert(0, path)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def load_library(lib_names, locations_conf=default_locations):
|
|
53
|
+
"""
|
|
54
|
+
Load the `lib_name` library with ctypes.
|
|
55
|
+
If ctypes.util.find_library does not find the library,
|
|
56
|
+
different path and filename extensions will be tried.
|
|
57
|
+
|
|
58
|
+
Retruns the loaded library or None.
|
|
59
|
+
"""
|
|
60
|
+
if isinstance(lib_names, str):
|
|
61
|
+
lib_names = [lib_names]
|
|
62
|
+
|
|
63
|
+
for lib_name in lib_names:
|
|
64
|
+
lib = load_library_(lib_name, locations_conf)
|
|
65
|
+
if lib is not None:
|
|
66
|
+
return lib
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def load_library_(lib_name, locations_conf=default_locations):
|
|
70
|
+
lib_path = find_library(lib_name)
|
|
71
|
+
|
|
72
|
+
if lib_path:
|
|
73
|
+
return CDLL(lib_path)
|
|
74
|
+
|
|
75
|
+
if sys.platform in locations_conf:
|
|
76
|
+
paths = locations_conf[sys.platform]['paths']
|
|
77
|
+
exts = locations_conf[sys.platform]['exts']
|
|
78
|
+
lib_path = find_library(lib_name, paths, exts)
|
|
79
|
+
else:
|
|
80
|
+
paths = locations_conf['other']['paths']
|
|
81
|
+
exts = locations_conf['other']['exts']
|
|
82
|
+
lib_path = find_library(lib_name, paths, exts)
|
|
83
|
+
|
|
84
|
+
if lib_path:
|
|
85
|
+
return CDLL(lib_path)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def find_library(lib_name, paths=None, exts=None):
|
|
89
|
+
"""
|
|
90
|
+
Search for library in all permutations of `paths` and `exts`.
|
|
91
|
+
If nothing is found None is returned.
|
|
92
|
+
"""
|
|
93
|
+
if not paths or not exts:
|
|
94
|
+
lib = None
|
|
95
|
+
try:
|
|
96
|
+
lib = _find_library(lib_name)
|
|
97
|
+
except FileNotFoundError:
|
|
98
|
+
pass
|
|
99
|
+
if lib is None and lib_name.startswith('lib'):
|
|
100
|
+
try:
|
|
101
|
+
lib = _find_library(lib_name[3:])
|
|
102
|
+
except FileNotFoundError:
|
|
103
|
+
pass
|
|
104
|
+
return lib
|
|
105
|
+
|
|
106
|
+
for lib_name in [lib_name] + ([lib_name[3:]] if lib_name.startswith('lib') else []):
|
|
107
|
+
for path in paths:
|
|
108
|
+
for ext in exts:
|
|
109
|
+
lib_path = os.path.join(path, lib_name + ext)
|
|
110
|
+
if os.path.exists(lib_path):
|
|
111
|
+
return lib_path
|
|
112
|
+
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == '__main__':
|
|
117
|
+
print(load_library(sys.argv[1]))
|