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
|
@@ -0,0 +1,476 @@
|
|
|
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
|
+
import glob
|
|
17
|
+
import multiprocessing
|
|
18
|
+
import os
|
|
19
|
+
import random
|
|
20
|
+
import shutil
|
|
21
|
+
import sys
|
|
22
|
+
import tempfile
|
|
23
|
+
import threading
|
|
24
|
+
import time
|
|
25
|
+
|
|
26
|
+
from mapproxy.util.lock import FileLock, SemLock, cleanup_lockdir, LockTimeout
|
|
27
|
+
from mapproxy.util.fs import (
|
|
28
|
+
_force_rename_dir,
|
|
29
|
+
swap_dir,
|
|
30
|
+
cleanup_directory,
|
|
31
|
+
write_atomic,
|
|
32
|
+
)
|
|
33
|
+
from mapproxy.util.py import reraise_exception
|
|
34
|
+
from mapproxy.util.times import timestamp_before
|
|
35
|
+
from mapproxy.test.helper import Mocker
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
is_win = sys.platform == "win32"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TestFileLock(Mocker):
|
|
42
|
+
|
|
43
|
+
def setup_method(self):
|
|
44
|
+
Mocker.setup_method(self)
|
|
45
|
+
self.lock_dir = tempfile.mkdtemp()
|
|
46
|
+
self.lock_file = os.path.join(self.lock_dir, "lock.lck")
|
|
47
|
+
|
|
48
|
+
def teardown_method(self):
|
|
49
|
+
shutil.rmtree(self.lock_dir)
|
|
50
|
+
Mocker.teardown_method(self)
|
|
51
|
+
|
|
52
|
+
def test_file_lock_timeout(self):
|
|
53
|
+
lock = self._create_lock()
|
|
54
|
+
assert_locked(self.lock_file)
|
|
55
|
+
lock # prevent lint warnings
|
|
56
|
+
|
|
57
|
+
def test_file_lock(self):
|
|
58
|
+
# Test a lock that becomes free during a waiting lock() call.
|
|
59
|
+
class Lock(threading.Thread):
|
|
60
|
+
|
|
61
|
+
def __init__(self, lock_file):
|
|
62
|
+
threading.Thread.__init__(self)
|
|
63
|
+
self.lock_file = lock_file
|
|
64
|
+
self.lock = FileLock(self.lock_file)
|
|
65
|
+
|
|
66
|
+
def run(self):
|
|
67
|
+
self.lock.lock()
|
|
68
|
+
time.sleep(0.2)
|
|
69
|
+
self.lock.unlock()
|
|
70
|
+
|
|
71
|
+
lock_thread = Lock(self.lock_file)
|
|
72
|
+
start_time = time.time()
|
|
73
|
+
lock_thread.start()
|
|
74
|
+
|
|
75
|
+
# wait until thread got the locked
|
|
76
|
+
while not lock_thread.lock._locked:
|
|
77
|
+
time.sleep(0.001)
|
|
78
|
+
|
|
79
|
+
# one lock that times out
|
|
80
|
+
assert_locked(self.lock_file)
|
|
81
|
+
|
|
82
|
+
# one lock that will get it after some time
|
|
83
|
+
x = FileLock(self.lock_file, timeout=0.3, step=0.001)
|
|
84
|
+
x.lock()
|
|
85
|
+
|
|
86
|
+
locked_for = time.time() - start_time
|
|
87
|
+
assert locked_for - 0.2 <= 0.1, "locking took to long?! (rerun if not sure)"
|
|
88
|
+
|
|
89
|
+
# cleanup
|
|
90
|
+
x.unlock()
|
|
91
|
+
lock_thread.join()
|
|
92
|
+
|
|
93
|
+
def test_lock_cleanup(self):
|
|
94
|
+
old_lock_file = os.path.join(self.lock_dir, "lock_old.lck")
|
|
95
|
+
x = FileLock(old_lock_file)
|
|
96
|
+
x.lock()
|
|
97
|
+
x.unlock()
|
|
98
|
+
mtime = os.stat(old_lock_file).st_mtime
|
|
99
|
+
mtime -= 7 * 60
|
|
100
|
+
os.utime(old_lock_file, (mtime, mtime))
|
|
101
|
+
|
|
102
|
+
x = self._create_lock()
|
|
103
|
+
x.unlock()
|
|
104
|
+
assert os.path.exists(old_lock_file)
|
|
105
|
+
assert os.path.exists(self.lock_file)
|
|
106
|
+
cleanup_lockdir(self.lock_dir)
|
|
107
|
+
|
|
108
|
+
assert not os.path.exists(old_lock_file)
|
|
109
|
+
assert os.path.exists(self.lock_file)
|
|
110
|
+
|
|
111
|
+
def test_concurrent_access(self):
|
|
112
|
+
count_file = os.path.join(self.lock_dir, "count.txt")
|
|
113
|
+
with open(count_file, "wb") as f:
|
|
114
|
+
f.write(b"0")
|
|
115
|
+
|
|
116
|
+
def count_up():
|
|
117
|
+
with FileLock(self.lock_file, timeout=60):
|
|
118
|
+
with open(count_file, "r+b") as f:
|
|
119
|
+
counter = int(f.read().strip())
|
|
120
|
+
f.seek(0)
|
|
121
|
+
f.write(str(counter + 1).encode("utf-8"))
|
|
122
|
+
|
|
123
|
+
def do_it():
|
|
124
|
+
for x in range(20):
|
|
125
|
+
time.sleep(0.002)
|
|
126
|
+
count_up()
|
|
127
|
+
|
|
128
|
+
threads = [threading.Thread(target=do_it) for _ in range(20)]
|
|
129
|
+
[t.start() for t in threads]
|
|
130
|
+
[t.join() for t in threads]
|
|
131
|
+
|
|
132
|
+
with open(count_file, "r+b") as f:
|
|
133
|
+
counter = int(f.read().strip())
|
|
134
|
+
|
|
135
|
+
assert counter == 400, counter
|
|
136
|
+
|
|
137
|
+
def test_remove_on_unlock(self):
|
|
138
|
+
x = FileLock(self.lock_file, remove_on_unlock=True)
|
|
139
|
+
x.lock()
|
|
140
|
+
assert os.path.exists(self.lock_file)
|
|
141
|
+
x.unlock()
|
|
142
|
+
if is_win: # not removed on windows
|
|
143
|
+
assert os.path.exists(self.lock_file)
|
|
144
|
+
else:
|
|
145
|
+
assert not os.path.exists(self.lock_file)
|
|
146
|
+
|
|
147
|
+
if is_win:
|
|
148
|
+
# not possible to remove lock file when lock is held
|
|
149
|
+
pass
|
|
150
|
+
else:
|
|
151
|
+
x.lock()
|
|
152
|
+
assert os.path.exists(self.lock_file)
|
|
153
|
+
os.remove(self.lock_file)
|
|
154
|
+
assert not os.path.exists(self.lock_file)
|
|
155
|
+
# ignore removed lock
|
|
156
|
+
x.unlock()
|
|
157
|
+
assert not os.path.exists(self.lock_file)
|
|
158
|
+
|
|
159
|
+
def _create_lock(self):
|
|
160
|
+
lock = FileLock(self.lock_file)
|
|
161
|
+
lock.lock()
|
|
162
|
+
return lock
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def assert_locked(lock_file, timeout=0.02, step=0.001):
|
|
166
|
+
assert os.path.exists(lock_file)
|
|
167
|
+
x = FileLock(lock_file, timeout=timeout, step=step)
|
|
168
|
+
try:
|
|
169
|
+
x.lock()
|
|
170
|
+
assert False, "file was not locked"
|
|
171
|
+
except LockTimeout:
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class TestSemLock(object):
|
|
176
|
+
|
|
177
|
+
def setup_method(self):
|
|
178
|
+
self.lock_dir = tempfile.mkdtemp()
|
|
179
|
+
self.lock_file = os.path.join(self.lock_dir, "lock.lck")
|
|
180
|
+
|
|
181
|
+
def teardown_method(self):
|
|
182
|
+
shutil.rmtree(self.lock_dir)
|
|
183
|
+
|
|
184
|
+
def count_lockfiles(self):
|
|
185
|
+
return len(glob.glob(self.lock_file + "*"))
|
|
186
|
+
|
|
187
|
+
def test_single(self):
|
|
188
|
+
locks = [SemLock(self.lock_file, 1, timeout=0.01) for _ in range(2)]
|
|
189
|
+
locks[0].lock()
|
|
190
|
+
try:
|
|
191
|
+
locks[1].lock()
|
|
192
|
+
except LockTimeout:
|
|
193
|
+
pass
|
|
194
|
+
else:
|
|
195
|
+
assert False, "expected LockTimeout"
|
|
196
|
+
|
|
197
|
+
def test_creating(self):
|
|
198
|
+
locks = [SemLock(self.lock_file, 2) for _ in range(3)]
|
|
199
|
+
|
|
200
|
+
assert self.count_lockfiles() == 0
|
|
201
|
+
locks[0].lock()
|
|
202
|
+
assert self.count_lockfiles() == 1
|
|
203
|
+
locks[1].lock()
|
|
204
|
+
assert self.count_lockfiles() == 2
|
|
205
|
+
assert os.path.exists(locks[0]._lock._path)
|
|
206
|
+
assert os.path.exists(locks[1]._lock._path)
|
|
207
|
+
locks[0].unlock()
|
|
208
|
+
locks[2].lock()
|
|
209
|
+
locks[2].unlock()
|
|
210
|
+
locks[1].unlock()
|
|
211
|
+
|
|
212
|
+
def test_timeout(self):
|
|
213
|
+
locks = [SemLock(self.lock_file, 2, timeout=0.1) for _ in range(3)]
|
|
214
|
+
|
|
215
|
+
assert self.count_lockfiles() == 0
|
|
216
|
+
locks[0].lock()
|
|
217
|
+
assert self.count_lockfiles() == 1
|
|
218
|
+
locks[1].lock()
|
|
219
|
+
assert self.count_lockfiles() == 2
|
|
220
|
+
try:
|
|
221
|
+
locks[2].lock()
|
|
222
|
+
except LockTimeout:
|
|
223
|
+
pass
|
|
224
|
+
else:
|
|
225
|
+
assert False, "expected LockTimeout"
|
|
226
|
+
locks[0].unlock()
|
|
227
|
+
locks[2].unlock()
|
|
228
|
+
|
|
229
|
+
def test_load(self):
|
|
230
|
+
locks = [SemLock(self.lock_file, 8, timeout=1) for _ in range(20)]
|
|
231
|
+
|
|
232
|
+
new_locks = random.sample([x for x in locks if not x._locked], 5)
|
|
233
|
+
for x in new_locks:
|
|
234
|
+
x.lock()
|
|
235
|
+
|
|
236
|
+
for _ in range(20):
|
|
237
|
+
old_locks = random.sample([x for x in locks if x._locked], 3)
|
|
238
|
+
for x in old_locks:
|
|
239
|
+
x.unlock()
|
|
240
|
+
assert len([x for x in locks if x._locked]) == 2
|
|
241
|
+
assert len([x for x in locks if not x._locked]) == 18
|
|
242
|
+
|
|
243
|
+
new_locks = random.sample([x for x in locks if not x._locked], 3)
|
|
244
|
+
for x in new_locks:
|
|
245
|
+
x.lock()
|
|
246
|
+
|
|
247
|
+
assert len([x for x in locks if x._locked]) == 5
|
|
248
|
+
assert len([x for x in locks if not x._locked]) == 15
|
|
249
|
+
|
|
250
|
+
assert self.count_lockfiles() == 8
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class DirTest(object):
|
|
254
|
+
|
|
255
|
+
def setup_method(self):
|
|
256
|
+
self.tmpdir = tempfile.mkdtemp()
|
|
257
|
+
|
|
258
|
+
def teardown_method(self):
|
|
259
|
+
if os.path.exists(self.tmpdir):
|
|
260
|
+
shutil.rmtree(self.tmpdir)
|
|
261
|
+
|
|
262
|
+
def mkdir(self, name):
|
|
263
|
+
dirname = os.path.join(self.tmpdir, name)
|
|
264
|
+
os.mkdir(dirname)
|
|
265
|
+
self.mkfile(name, dirname=dirname)
|
|
266
|
+
return dirname
|
|
267
|
+
|
|
268
|
+
def mkfile(self, name, dirname=None):
|
|
269
|
+
if dirname is None:
|
|
270
|
+
dirname = self.mkdir(name)
|
|
271
|
+
filename = os.path.join(dirname, name + ".txt")
|
|
272
|
+
open(filename, "wb").close()
|
|
273
|
+
return filename
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class TestForceRenameDir(DirTest):
|
|
277
|
+
|
|
278
|
+
def test_rename(self):
|
|
279
|
+
src_dir = self.mkdir("bar")
|
|
280
|
+
dst_dir = os.path.join(self.tmpdir, "baz")
|
|
281
|
+
_force_rename_dir(src_dir, dst_dir)
|
|
282
|
+
assert os.path.exists(dst_dir)
|
|
283
|
+
assert os.path.exists(os.path.join(dst_dir, "bar.txt"))
|
|
284
|
+
assert not os.path.exists(src_dir)
|
|
285
|
+
|
|
286
|
+
def test_rename_overwrite(self):
|
|
287
|
+
src_dir = self.mkdir("bar")
|
|
288
|
+
dst_dir = self.mkdir("baz")
|
|
289
|
+
_force_rename_dir(src_dir, dst_dir)
|
|
290
|
+
assert os.path.exists(dst_dir)
|
|
291
|
+
assert os.path.exists(os.path.join(dst_dir, "bar.txt"))
|
|
292
|
+
assert not os.path.exists(src_dir)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class TestSwapDir(DirTest):
|
|
296
|
+
|
|
297
|
+
def test_swap_dir(self):
|
|
298
|
+
src_dir = self.mkdir("bar")
|
|
299
|
+
dst_dir = os.path.join(self.tmpdir, "baz")
|
|
300
|
+
|
|
301
|
+
swap_dir(src_dir, dst_dir)
|
|
302
|
+
assert os.path.exists(dst_dir)
|
|
303
|
+
assert os.path.exists(os.path.join(dst_dir, "bar.txt"))
|
|
304
|
+
assert not os.path.exists(src_dir)
|
|
305
|
+
|
|
306
|
+
def test_swap_dir_w_old(self):
|
|
307
|
+
src_dir = self.mkdir("bar")
|
|
308
|
+
dst_dir = self.mkdir("baz")
|
|
309
|
+
|
|
310
|
+
swap_dir(src_dir, dst_dir)
|
|
311
|
+
assert os.path.exists(dst_dir)
|
|
312
|
+
assert os.path.exists(os.path.join(dst_dir, "bar.txt"))
|
|
313
|
+
assert not os.path.exists(src_dir)
|
|
314
|
+
|
|
315
|
+
def test_swap_dir_keep_old(self):
|
|
316
|
+
src_dir = self.mkdir("bar")
|
|
317
|
+
dst_dir = self.mkdir("baz")
|
|
318
|
+
|
|
319
|
+
swap_dir(src_dir, dst_dir, keep_old=True, backup_ext=".bak")
|
|
320
|
+
assert os.path.exists(dst_dir)
|
|
321
|
+
assert os.path.exists(os.path.join(dst_dir, "bar.txt"))
|
|
322
|
+
assert os.path.exists(dst_dir + ".bak")
|
|
323
|
+
assert os.path.exists(os.path.join(dst_dir + ".bak", "baz.txt"))
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class TestCleanupDirectory(DirTest):
|
|
327
|
+
|
|
328
|
+
def test_no_remove(self):
|
|
329
|
+
dirs = [self.mkdir("dir" + str(n)) for n in range(10)]
|
|
330
|
+
for d in dirs:
|
|
331
|
+
assert os.path.exists(d), d
|
|
332
|
+
cleanup_directory(self.tmpdir, timestamp_before(minutes=1))
|
|
333
|
+
for d in dirs:
|
|
334
|
+
assert os.path.exists(d), d
|
|
335
|
+
|
|
336
|
+
def test_file_handler(self):
|
|
337
|
+
files = []
|
|
338
|
+
file_handler_calls = []
|
|
339
|
+
|
|
340
|
+
def file_handler(filename):
|
|
341
|
+
file_handler_calls.append(filename)
|
|
342
|
+
|
|
343
|
+
new_date = timestamp_before(weeks=1)
|
|
344
|
+
for n in range(10):
|
|
345
|
+
fname = "foo" + str(n)
|
|
346
|
+
filename = self.mkfile(fname)
|
|
347
|
+
os.utime(filename, (new_date, new_date))
|
|
348
|
+
files.append(filename)
|
|
349
|
+
|
|
350
|
+
for filename in files:
|
|
351
|
+
assert os.path.exists(filename), filename
|
|
352
|
+
cleanup_directory(self.tmpdir, timestamp_before(), file_handler=file_handler)
|
|
353
|
+
for filename in files:
|
|
354
|
+
assert os.path.exists(filename), filename
|
|
355
|
+
|
|
356
|
+
assert set(files) == set(file_handler_calls)
|
|
357
|
+
|
|
358
|
+
def test_no_directory(self):
|
|
359
|
+
cleanup_directory(os.path.join(self.tmpdir, "invalid"), timestamp_before())
|
|
360
|
+
# nothing should happen
|
|
361
|
+
|
|
362
|
+
def test_remove_all(self):
|
|
363
|
+
files = []
|
|
364
|
+
new_date = timestamp_before(weeks=1)
|
|
365
|
+
for n in range(10):
|
|
366
|
+
fname = "foo" + str(n)
|
|
367
|
+
filename = self.mkfile(fname)
|
|
368
|
+
os.utime(filename, (new_date, new_date))
|
|
369
|
+
files.append(filename)
|
|
370
|
+
|
|
371
|
+
for filename in files:
|
|
372
|
+
assert os.path.exists(filename), filename
|
|
373
|
+
cleanup_directory(self.tmpdir, timestamp_before())
|
|
374
|
+
for filename in files:
|
|
375
|
+
assert not os.path.exists(filename), filename
|
|
376
|
+
assert not os.path.exists(os.path.dirname(filename)), filename
|
|
377
|
+
|
|
378
|
+
def test_remove_empty_dirs(self):
|
|
379
|
+
os.makedirs(os.path.join(self.tmpdir, "foo", "bar", "baz"))
|
|
380
|
+
cleanup_directory(self.tmpdir, timestamp_before(minutes=-1))
|
|
381
|
+
assert not os.path.exists(os.path.join(self.tmpdir, "foo"))
|
|
382
|
+
|
|
383
|
+
def test_remove_some(self):
|
|
384
|
+
files = []
|
|
385
|
+
# create a few files, every other file is one week old
|
|
386
|
+
new_date = timestamp_before(weeks=1)
|
|
387
|
+
for n in range(10):
|
|
388
|
+
fname = "foo" + str(n)
|
|
389
|
+
filename = self.mkfile(fname)
|
|
390
|
+
if n % 2 == 0:
|
|
391
|
+
os.utime(filename, (new_date, new_date))
|
|
392
|
+
files.append(filename)
|
|
393
|
+
|
|
394
|
+
# check all files are present
|
|
395
|
+
for filename in files:
|
|
396
|
+
assert os.path.exists(filename), filename
|
|
397
|
+
|
|
398
|
+
# cleanup_directory for all files older then one minute
|
|
399
|
+
cleanup_directory(self.tmpdir, timestamp_before(minutes=1))
|
|
400
|
+
|
|
401
|
+
# check old files and dirs are removed
|
|
402
|
+
for filename in files[::2]:
|
|
403
|
+
assert not os.path.exists(filename), filename
|
|
404
|
+
assert not os.path.exists(os.path.dirname(filename)), filename
|
|
405
|
+
|
|
406
|
+
# check new files are still present
|
|
407
|
+
for filename in files[1::2]:
|
|
408
|
+
assert os.path.exists(filename), filename
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def _write_atomic_data(i_filename):
|
|
412
|
+
(i, filename) = i_filename
|
|
413
|
+
data = str(i) + "\n" + "x" * 10000
|
|
414
|
+
write_atomic(filename, data.encode("utf-8"))
|
|
415
|
+
time.sleep(0.001)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
class TestWriteAtomic(object):
|
|
419
|
+
|
|
420
|
+
def setup_method(self):
|
|
421
|
+
self.dirname = tempfile.mkdtemp()
|
|
422
|
+
|
|
423
|
+
def teardown_method(self):
|
|
424
|
+
if self.dirname:
|
|
425
|
+
shutil.rmtree(self.dirname)
|
|
426
|
+
|
|
427
|
+
def test_concurrent_write(self):
|
|
428
|
+
filename = os.path.join(self.dirname, "tmpfile")
|
|
429
|
+
|
|
430
|
+
num_writes = 800
|
|
431
|
+
concurrent_writes = 8
|
|
432
|
+
|
|
433
|
+
p = multiprocessing.Pool(concurrent_writes)
|
|
434
|
+
p.map(_write_atomic_data, ((i, filename) for i in range(num_writes)))
|
|
435
|
+
p.close()
|
|
436
|
+
p.join()
|
|
437
|
+
|
|
438
|
+
assert os.path.exists(filename)
|
|
439
|
+
last_i = int(open(filename).readline())
|
|
440
|
+
assert last_i > (num_writes / 2), (
|
|
441
|
+
"file should contain content from "
|
|
442
|
+
"later writes, got content from write %d" % (last_i + 1)
|
|
443
|
+
)
|
|
444
|
+
os.unlink(filename)
|
|
445
|
+
assert os.listdir(self.dirname) == []
|
|
446
|
+
|
|
447
|
+
def test_not_a_file(self):
|
|
448
|
+
# check that expected errors are not hidden
|
|
449
|
+
filename = os.path.join(self.dirname, "tmpfile")
|
|
450
|
+
os.mkdir(filename)
|
|
451
|
+
|
|
452
|
+
try:
|
|
453
|
+
write_atomic(filename, b"12345")
|
|
454
|
+
except (OSError, IOError):
|
|
455
|
+
pass
|
|
456
|
+
else:
|
|
457
|
+
assert False, "expected exception"
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def test_reraise_exception():
|
|
461
|
+
|
|
462
|
+
def valueerror_raiser():
|
|
463
|
+
raise ValueError()
|
|
464
|
+
|
|
465
|
+
def reraiser():
|
|
466
|
+
try:
|
|
467
|
+
valueerror_raiser()
|
|
468
|
+
except ValueError:
|
|
469
|
+
reraise_exception(TypeError(), sys.exc_info())
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
reraiser()
|
|
473
|
+
except TypeError as ex:
|
|
474
|
+
assert ex
|
|
475
|
+
else:
|
|
476
|
+
assert False, "expected exception"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2014 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from mapproxy.service.wms import limit_srs_extents
|
|
17
|
+
from mapproxy.layer import DefaultMapExtent, MapExtent
|
|
18
|
+
from mapproxy.srs import SRS
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestLimitSRSExtents(object):
|
|
22
|
+
|
|
23
|
+
def test_defaults(self):
|
|
24
|
+
assert limit_srs_extents({}, ["EPSG:4326", "EPSG:3857"]) == {
|
|
25
|
+
"EPSG:4326": DefaultMapExtent(),
|
|
26
|
+
"EPSG:3857": DefaultMapExtent(),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
def test_unsupported(self):
|
|
30
|
+
assert (
|
|
31
|
+
limit_srs_extents(
|
|
32
|
+
{"EPSG:9999": DefaultMapExtent()}, ["EPSG:4326", "EPSG:3857"]
|
|
33
|
+
)
|
|
34
|
+
== {}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def test_limited_unsupported(self):
|
|
38
|
+
assert limit_srs_extents(
|
|
39
|
+
{
|
|
40
|
+
"EPSG:9999": DefaultMapExtent(),
|
|
41
|
+
"EPSG:4326": MapExtent([0, 0, 10, 10], SRS(4326)),
|
|
42
|
+
},
|
|
43
|
+
["EPSG:4326", "EPSG:3857"],
|
|
44
|
+
) == {"EPSG:4326": MapExtent([0, 0, 10, 10], SRS(4326))}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 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
|
+
from __future__ import division
|
|
17
|
+
|
|
18
|
+
from mapproxy.layer import MapQuery, InfoQuery
|
|
19
|
+
from mapproxy.srs import SRS
|
|
20
|
+
from mapproxy.service.wms import combined_layers
|
|
21
|
+
from mapproxy.source.wms import WMSSource
|
|
22
|
+
from mapproxy.client.wms import WMSClient
|
|
23
|
+
from mapproxy.request.wms import create_request
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TestCombinedLayers(object):
|
|
27
|
+
q = MapQuery((0, 0, 10000, 10000), (100, 100), SRS(3857))
|
|
28
|
+
|
|
29
|
+
def test_empty(self):
|
|
30
|
+
assert combined_layers([], self.q) == []
|
|
31
|
+
|
|
32
|
+
def test_same_source(self):
|
|
33
|
+
layers = [
|
|
34
|
+
WMSSource(
|
|
35
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "a"}, {}))
|
|
36
|
+
),
|
|
37
|
+
WMSSource(
|
|
38
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "b"}, {}))
|
|
39
|
+
),
|
|
40
|
+
]
|
|
41
|
+
combined = combined_layers(layers, self.q)
|
|
42
|
+
assert len(combined) == 1
|
|
43
|
+
assert combined[0].client.request_template.params.layers == ["a", "b"]
|
|
44
|
+
|
|
45
|
+
def test_mixed_hosts(self):
|
|
46
|
+
layers = [
|
|
47
|
+
WMSSource(
|
|
48
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "a"}, {}))
|
|
49
|
+
),
|
|
50
|
+
WMSSource(
|
|
51
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "b"}, {}))
|
|
52
|
+
),
|
|
53
|
+
WMSSource(
|
|
54
|
+
WMSClient(create_request({"url": "http://bar/", "layers": "c"}, {}))
|
|
55
|
+
),
|
|
56
|
+
WMSSource(
|
|
57
|
+
WMSClient(create_request({"url": "http://bar/", "layers": "d"}, {}))
|
|
58
|
+
),
|
|
59
|
+
WMSSource(
|
|
60
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "e"}, {}))
|
|
61
|
+
),
|
|
62
|
+
WMSSource(
|
|
63
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "f"}, {}))
|
|
64
|
+
),
|
|
65
|
+
]
|
|
66
|
+
combined = combined_layers(layers, self.q)
|
|
67
|
+
assert len(combined) == 3
|
|
68
|
+
assert combined[0].client.request_template.params.layers == ["a", "b"]
|
|
69
|
+
assert combined[1].client.request_template.params.layers == ["c", "d"]
|
|
70
|
+
assert combined[2].client.request_template.params.layers == ["e", "f"]
|
|
71
|
+
|
|
72
|
+
def test_mixed_params(self):
|
|
73
|
+
layers = [
|
|
74
|
+
WMSSource(
|
|
75
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "a"}, {}))
|
|
76
|
+
),
|
|
77
|
+
WMSSource(
|
|
78
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "b"}, {}))
|
|
79
|
+
),
|
|
80
|
+
WMSSource(
|
|
81
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "c"}, {}))
|
|
82
|
+
),
|
|
83
|
+
WMSSource(
|
|
84
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "d"}, {}))
|
|
85
|
+
),
|
|
86
|
+
WMSSource(
|
|
87
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "e"}, {}))
|
|
88
|
+
),
|
|
89
|
+
WMSSource(
|
|
90
|
+
WMSClient(create_request({"url": "http://foo/", "layers": "f"}, {}))
|
|
91
|
+
),
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
layers[0].supported_srs = ["EPSG:4326"]
|
|
95
|
+
layers[1].supported_srs = ["EPSG:4326"]
|
|
96
|
+
|
|
97
|
+
layers[2].supported_formats = ["image/png"]
|
|
98
|
+
layers[3].supported_formats = ["image/png"]
|
|
99
|
+
|
|
100
|
+
combined = combined_layers(layers, self.q)
|
|
101
|
+
assert len(combined) == 3
|
|
102
|
+
assert combined[0].client.request_template.params.layers == ["a", "b"]
|
|
103
|
+
assert combined[1].client.request_template.params.layers == ["c", "d"]
|
|
104
|
+
assert combined[2].client.request_template.params.layers == ["e", "f"]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TestInfoQuery(object):
|
|
108
|
+
|
|
109
|
+
def test_coord(self):
|
|
110
|
+
query = InfoQuery(
|
|
111
|
+
(8, 50, 9, 51), (400, 1000), SRS(4326), (100, 600), "text/plain"
|
|
112
|
+
)
|
|
113
|
+
assert query.coord == (8.25, 50.4)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Copyright (C) 2011 Omniscale <http://omniscale.de>
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import tempfile
|
|
18
|
+
|
|
19
|
+
from mapproxy.util.yaml import load_yaml, load_yaml_file, YAMLError
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestLoadYAMLFile(object):
|
|
23
|
+
|
|
24
|
+
def setup_method(self):
|
|
25
|
+
self.tmp_files = []
|
|
26
|
+
|
|
27
|
+
def teardown_method(self):
|
|
28
|
+
for f in self.tmp_files:
|
|
29
|
+
os.unlink(f)
|
|
30
|
+
|
|
31
|
+
def yaml_file(self, content):
|
|
32
|
+
fd, fname = tempfile.mkstemp()
|
|
33
|
+
f = os.fdopen(fd, "w")
|
|
34
|
+
f.write(content)
|
|
35
|
+
self.tmp_files.append(fname)
|
|
36
|
+
return fname
|
|
37
|
+
|
|
38
|
+
def test_load_yaml_file(self):
|
|
39
|
+
f = self.yaml_file("hello:\n - 1\n - 2")
|
|
40
|
+
doc = load_yaml_file(open(f))
|
|
41
|
+
assert doc == {"hello": [1, 2]}
|
|
42
|
+
|
|
43
|
+
def test_load_yaml_file_filename(self):
|
|
44
|
+
f = self.yaml_file("hello:\n - 1\n - 2")
|
|
45
|
+
assert isinstance(f, str)
|
|
46
|
+
doc = load_yaml_file(f)
|
|
47
|
+
assert doc == {"hello": [1, 2]}
|
|
48
|
+
|
|
49
|
+
def test_load_yaml(self):
|
|
50
|
+
doc = load_yaml("hello:\n - 1\n - 2")
|
|
51
|
+
assert doc == {"hello": [1, 2]}
|
|
52
|
+
|
|
53
|
+
def test_load_yaml_with_tabs(self):
|
|
54
|
+
try:
|
|
55
|
+
f = self.yaml_file("hello:\n\t- world")
|
|
56
|
+
load_yaml_file(f)
|
|
57
|
+
except YAMLError as ex:
|
|
58
|
+
assert "line 2" in str(ex)
|
|
59
|
+
else:
|
|
60
|
+
assert False, "expected YAMLError"
|
|
61
|
+
|
|
62
|
+
def test_load_yaml_string_error(self):
|
|
63
|
+
try:
|
|
64
|
+
load_yaml('only a string')
|
|
65
|
+
except YAMLError as ex:
|
|
66
|
+
assert "not a YAML dict" in str(ex)
|
|
67
|
+
else:
|
|
68
|
+
assert False, "expected YAMLError"
|