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,600 @@
|
|
|
1
|
+
# This file is part of the MapProxy project.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
# See the License for the specific language governing permissions and
|
|
12
|
+
# limitations under the License.
|
|
13
|
+
|
|
14
|
+
# Disclaimer:
|
|
15
|
+
# This code is based on isodate from: https://github.com/gweis/isodate by 2009, Gerhard Weis
|
|
16
|
+
# Some functions were extracted and modified from original project.
|
|
17
|
+
|
|
18
|
+
from decimal import Decimal, ROUND_FLOOR
|
|
19
|
+
from datetime import timedelta, tzinfo as tz, date, time, datetime
|
|
20
|
+
import re
|
|
21
|
+
|
|
22
|
+
TIME_REGEX_CACHE = []
|
|
23
|
+
# used to cache regular expressions to parse ISO time strings.
|
|
24
|
+
DATE_REGEX_CACHE = {}
|
|
25
|
+
# A dictionary to cache pre-compiled regular expressions.
|
|
26
|
+
# A set of regular expressions is identified, by number of year digits allowed
|
|
27
|
+
# and whether a plus/minus sign is required or not. (This option is changeable
|
|
28
|
+
# only for 4 digit years).
|
|
29
|
+
TZ_REGEX = r"(?P<tzname>(Z|(?P<tzsign>[+-])"\
|
|
30
|
+
r"(?P<tzhour>[0-9]{2})(:?(?P<tzmin>[0-9]{2}))?)?)"
|
|
31
|
+
|
|
32
|
+
TZ_EXT = '%Z'
|
|
33
|
+
ZERO = timedelta(0)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def build_date_regexps(yeardigits=4, expanded=False):
|
|
37
|
+
'''
|
|
38
|
+
Compile set of regular expressions to parse ISO dates. The expressions will
|
|
39
|
+
be created only if they are not already in REGEX_CACHE.
|
|
40
|
+
It is necessary to fix the number of year digits, else it is not possible
|
|
41
|
+
to automatically distinguish between various ISO date formats.
|
|
42
|
+
ISO 8601 allows more than 4 digit years, on prior agreement, but then a +/-
|
|
43
|
+
sign is required (expanded format). To support +/- sign for 4 digit years,
|
|
44
|
+
the expanded parameter needs to be set to True.
|
|
45
|
+
'''
|
|
46
|
+
if yeardigits != 4:
|
|
47
|
+
expanded = True
|
|
48
|
+
if (yeardigits, expanded) not in DATE_REGEX_CACHE:
|
|
49
|
+
cache_entry = []
|
|
50
|
+
# ISO 8601 expanded DATE formats allow an arbitrary number of year
|
|
51
|
+
# digits with a leading +/- sign.
|
|
52
|
+
if expanded:
|
|
53
|
+
sign = 1
|
|
54
|
+
else:
|
|
55
|
+
sign = 0
|
|
56
|
+
# 1. complete dates:
|
|
57
|
+
# YYYY-MM-DD or +- YYYYYY-MM-DD... extended date format
|
|
58
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
59
|
+
r"-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})"
|
|
60
|
+
% (sign, yeardigits)))
|
|
61
|
+
# YYYYMMDD or +- YYYYYYMMDD... basic date format
|
|
62
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
63
|
+
r"(?P<month>[0-9]{2})(?P<day>[0-9]{2})"
|
|
64
|
+
% (sign, yeardigits)))
|
|
65
|
+
# 2. complete week dates:
|
|
66
|
+
# YYYY-Www-D or +-YYYYYY-Www-D ... extended week date
|
|
67
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
68
|
+
r"-W(?P<week>[0-9]{2})-(?P<day>[0-9]{1})"
|
|
69
|
+
% (sign, yeardigits)))
|
|
70
|
+
# YYYYWwwD or +-YYYYYYWwwD ... basic week date
|
|
71
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})W"
|
|
72
|
+
r"(?P<week>[0-9]{2})(?P<day>[0-9]{1})"
|
|
73
|
+
% (sign, yeardigits)))
|
|
74
|
+
# 3. ordinal dates:
|
|
75
|
+
# YYYY-DDD or +-YYYYYY-DDD ... extended format
|
|
76
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
77
|
+
r"-(?P<day>[0-9]{3})"
|
|
78
|
+
% (sign, yeardigits)))
|
|
79
|
+
# YYYYDDD or +-YYYYYYDDD ... basic format
|
|
80
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
81
|
+
r"(?P<day>[0-9]{3})"
|
|
82
|
+
% (sign, yeardigits)))
|
|
83
|
+
# 4. week dates:
|
|
84
|
+
# YYYY-Www or +-YYYYYY-Www ... extended reduced accuracy week date
|
|
85
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
86
|
+
r"-W(?P<week>[0-9]{2})"
|
|
87
|
+
% (sign, yeardigits)))
|
|
88
|
+
# YYYYWww or +-YYYYYYWww ... basic reduced accuracy week date
|
|
89
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})W"
|
|
90
|
+
r"(?P<week>[0-9]{2})"
|
|
91
|
+
% (sign, yeardigits)))
|
|
92
|
+
# 5. month dates:
|
|
93
|
+
# YYY-MM or +-YYYYYY-MM ... reduced accuracy specific month
|
|
94
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
95
|
+
r"-(?P<month>[0-9]{2})"
|
|
96
|
+
% (sign, yeardigits)))
|
|
97
|
+
# YYYMM or +-YYYYYYMM ... basic incomplete month date format
|
|
98
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
99
|
+
r"(?P<month>[0-9]{2})"
|
|
100
|
+
% (sign, yeardigits)))
|
|
101
|
+
# 6. year dates:
|
|
102
|
+
# YYYY or +-YYYYYY ... reduced accuracy specific year
|
|
103
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})"
|
|
104
|
+
% (sign, yeardigits)))
|
|
105
|
+
# 7. century dates:
|
|
106
|
+
# YY or +-YYYY ... reduced accuracy specific century
|
|
107
|
+
cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}"
|
|
108
|
+
r"(?P<century>[0-9]{%d})"
|
|
109
|
+
% (sign, yeardigits - 2)))
|
|
110
|
+
|
|
111
|
+
DATE_REGEX_CACHE[(yeardigits, expanded)] = cache_entry
|
|
112
|
+
return DATE_REGEX_CACHE[(yeardigits, expanded)]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def build_time_regexps():
|
|
116
|
+
'''
|
|
117
|
+
Build regular expressions to parse ISO time string.
|
|
118
|
+
The regular expressions are compiled and stored in TIME_REGEX_CACHE
|
|
119
|
+
for later reuse.
|
|
120
|
+
'''
|
|
121
|
+
if not TIME_REGEX_CACHE:
|
|
122
|
+
# ISO 8601 time representations allow decimal fractions on least
|
|
123
|
+
# significant time component. Command and Full Stop are both valid
|
|
124
|
+
# fraction separators.
|
|
125
|
+
# The letter 'T' is allowed as time designator in front of a time
|
|
126
|
+
# expression.
|
|
127
|
+
# Immediately after a time expression, a time zone definition is
|
|
128
|
+
# allowed.
|
|
129
|
+
# a TZ may be missing (local time), be a 'Z' for UTC or a string of
|
|
130
|
+
# +-hh:mm where the ':mm' part can be skipped.
|
|
131
|
+
# TZ information patterns:
|
|
132
|
+
# ''
|
|
133
|
+
# Z
|
|
134
|
+
# +-hh:mm
|
|
135
|
+
# +-hhmm
|
|
136
|
+
# +-hh =>
|
|
137
|
+
# isotzinfo.TZ_REGEX
|
|
138
|
+
# 1. complete time:
|
|
139
|
+
# hh:mm:ss.ss ... extended format
|
|
140
|
+
TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2}):"
|
|
141
|
+
r"(?P<minute>[0-9]{2}):"
|
|
142
|
+
r"(?P<second>[0-9]{2}"
|
|
143
|
+
r"([,.][0-9]+)?)" + TZ_REGEX))
|
|
144
|
+
# hhmmss.ss ... basic format
|
|
145
|
+
TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2})"
|
|
146
|
+
r"(?P<minute>[0-9]{2})"
|
|
147
|
+
r"(?P<second>[0-9]{2}"
|
|
148
|
+
r"([,.][0-9]+)?)" + TZ_REGEX))
|
|
149
|
+
# 2. reduced accuracy:
|
|
150
|
+
# hh:mm.mm ... extended format
|
|
151
|
+
TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2}):"
|
|
152
|
+
r"(?P<minute>[0-9]{2}"
|
|
153
|
+
r"([,.][0-9]+)?)" + TZ_REGEX))
|
|
154
|
+
# hhmm.mm ... basic format
|
|
155
|
+
TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2})"
|
|
156
|
+
r"(?P<minute>[0-9]{2}"
|
|
157
|
+
r"([,.][0-9]+)?)" + TZ_REGEX))
|
|
158
|
+
# hh.hh ... basic format
|
|
159
|
+
TIME_REGEX_CACHE.append(re.compile(r"T?(?P<hour>[0-9]{2}"
|
|
160
|
+
r"([,.][0-9]+)?)" + TZ_REGEX))
|
|
161
|
+
return TIME_REGEX_CACHE
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class FixedOffset(tz):
|
|
165
|
+
'''
|
|
166
|
+
A class building tzinfo objects for fixed-offset time zones.
|
|
167
|
+
Note that FixedOffset(0, 0, "UTC") or FixedOffset() is a different way to
|
|
168
|
+
build a UTC tzinfo object.
|
|
169
|
+
'''
|
|
170
|
+
|
|
171
|
+
def __init__(self, offset_hours=0, offset_minutes=0, name="UTC"):
|
|
172
|
+
'''
|
|
173
|
+
Initialise an instance with time offset and name.
|
|
174
|
+
The time offset should be positive for time zones east of UTC
|
|
175
|
+
and negate for time zones west of UTC.
|
|
176
|
+
'''
|
|
177
|
+
self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes)
|
|
178
|
+
self.__name = name
|
|
179
|
+
|
|
180
|
+
def utcoffset(self, dt):
|
|
181
|
+
'''
|
|
182
|
+
Return offset from UTC in minutes of UTC.
|
|
183
|
+
'''
|
|
184
|
+
return self.__offset
|
|
185
|
+
|
|
186
|
+
def tzname(self, dt):
|
|
187
|
+
'''
|
|
188
|
+
Return the time zone name corresponding to the datetime object dt, as a
|
|
189
|
+
string.
|
|
190
|
+
'''
|
|
191
|
+
return self.__name
|
|
192
|
+
|
|
193
|
+
def dst(self, dt):
|
|
194
|
+
'''
|
|
195
|
+
Return the daylight saving time (DST) adjustment, in minutes east of
|
|
196
|
+
UTC.
|
|
197
|
+
'''
|
|
198
|
+
return ZERO
|
|
199
|
+
|
|
200
|
+
def __repr__(self):
|
|
201
|
+
'''
|
|
202
|
+
Return nicely formatted repr string.
|
|
203
|
+
'''
|
|
204
|
+
return "<FixedOffset %r>" % self.__name
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class Utc(tz):
|
|
208
|
+
'''UTC
|
|
209
|
+
Universal time coordinated time zone.
|
|
210
|
+
'''
|
|
211
|
+
|
|
212
|
+
def utcoffset(self, dt):
|
|
213
|
+
'''
|
|
214
|
+
Return offset from UTC in minutes east of UTC, which is ZERO for UTC.
|
|
215
|
+
'''
|
|
216
|
+
return ZERO
|
|
217
|
+
|
|
218
|
+
def tzname(self, dt):
|
|
219
|
+
'''
|
|
220
|
+
Return the time zone name corresponding to the datetime object dt,
|
|
221
|
+
as a string.
|
|
222
|
+
'''
|
|
223
|
+
return "UTC"
|
|
224
|
+
|
|
225
|
+
def dst(self, dt):
|
|
226
|
+
'''
|
|
227
|
+
Return the daylight saving time (DST) adjustment, in minutes east
|
|
228
|
+
of UTC.
|
|
229
|
+
'''
|
|
230
|
+
return ZERO
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
UTC = Utc()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def build_tzinfo(tzname, tzsign='+', tzhour=0, tzmin=0):
|
|
237
|
+
'''
|
|
238
|
+
create a tzinfo instance according to given parameters.
|
|
239
|
+
tzname:
|
|
240
|
+
'Z' ... return UTC
|
|
241
|
+
'' | None ... return None
|
|
242
|
+
other ... return FixedOffset
|
|
243
|
+
'''
|
|
244
|
+
if tzname is None or tzname == '':
|
|
245
|
+
return None
|
|
246
|
+
if tzname == 'Z':
|
|
247
|
+
return UTC
|
|
248
|
+
tzsign = ((tzsign == '-') and -1) or 1
|
|
249
|
+
return FixedOffset(tzsign * tzhour, tzsign * tzmin, tzname)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def fquotmod(val, low, high):
|
|
253
|
+
a, b = val - low, high - low
|
|
254
|
+
div = (a / b).to_integral(ROUND_FLOOR)
|
|
255
|
+
mod = a - div * b
|
|
256
|
+
mod += low
|
|
257
|
+
return int(div), mod
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def max_days_in_month(year, month):
|
|
261
|
+
'''
|
|
262
|
+
Determines the number of days of a specific month in a specific year.
|
|
263
|
+
'''
|
|
264
|
+
if month in (1, 3, 5, 7, 8, 10, 12):
|
|
265
|
+
return 31
|
|
266
|
+
if month in (4, 6, 9, 11):
|
|
267
|
+
return 30
|
|
268
|
+
if ((year % 400) == 0) or ((year % 100) != 0) and ((year % 4) == 0):
|
|
269
|
+
return 29
|
|
270
|
+
return 28
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class Duration(object):
|
|
274
|
+
'''
|
|
275
|
+
http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes
|
|
276
|
+
'''
|
|
277
|
+
|
|
278
|
+
def __init__(self, days=0, seconds=0, microseconds=0, milliseconds=0,
|
|
279
|
+
minutes=0, hours=0, weeks=0, months=0, years=0):
|
|
280
|
+
'''
|
|
281
|
+
Initialise this Duration instance with the given parameters.
|
|
282
|
+
'''
|
|
283
|
+
if not isinstance(months, Decimal):
|
|
284
|
+
months = Decimal(str(months))
|
|
285
|
+
if not isinstance(years, Decimal):
|
|
286
|
+
years = Decimal(str(years))
|
|
287
|
+
self.months = months
|
|
288
|
+
self.years = years
|
|
289
|
+
self.tdelta = timedelta(days, seconds, microseconds, milliseconds,
|
|
290
|
+
minutes, hours, weeks)
|
|
291
|
+
|
|
292
|
+
def __getstate__(self):
|
|
293
|
+
return self.__dict__
|
|
294
|
+
|
|
295
|
+
def __setstate__(self, state):
|
|
296
|
+
self.__dict__.update(state)
|
|
297
|
+
|
|
298
|
+
def __getattr__(self, name):
|
|
299
|
+
|
|
300
|
+
return getattr(self.tdelta, name)
|
|
301
|
+
|
|
302
|
+
def __str__(self):
|
|
303
|
+
|
|
304
|
+
params = []
|
|
305
|
+
if self.years:
|
|
306
|
+
params.append('%d years' % self.years)
|
|
307
|
+
if self.months:
|
|
308
|
+
fmt = "%d months"
|
|
309
|
+
if self.months <= 1:
|
|
310
|
+
fmt = "%d month"
|
|
311
|
+
params.append(fmt % self.months)
|
|
312
|
+
params.append(str(self.tdelta))
|
|
313
|
+
return ', '.join(params)
|
|
314
|
+
|
|
315
|
+
def __repr__(self):
|
|
316
|
+
|
|
317
|
+
return "%s.%s(%d, %d, %d, years=%d, months=%d)" % (
|
|
318
|
+
self.__class__.__module__, self.__class__.__name__,
|
|
319
|
+
self.tdelta.days, self.tdelta.seconds,
|
|
320
|
+
self.tdelta.microseconds, self.years, self.months)
|
|
321
|
+
|
|
322
|
+
def __hash__(self):
|
|
323
|
+
|
|
324
|
+
return hash((self.tdelta, self.months, self.years))
|
|
325
|
+
|
|
326
|
+
def __neg__(self):
|
|
327
|
+
|
|
328
|
+
negduration = Duration(years=-self.years, months=-self.months)
|
|
329
|
+
negduration.tdelta = -self.tdelta
|
|
330
|
+
return negduration
|
|
331
|
+
|
|
332
|
+
def __add__(self, other):
|
|
333
|
+
|
|
334
|
+
if isinstance(other, Duration):
|
|
335
|
+
newduration = Duration(years=self.years + other.years,
|
|
336
|
+
months=self.months + other.months)
|
|
337
|
+
newduration.tdelta = self.tdelta + other.tdelta
|
|
338
|
+
return newduration
|
|
339
|
+
try:
|
|
340
|
+
|
|
341
|
+
if (not (float(self.years).is_integer() and
|
|
342
|
+
float(self.months).is_integer())):
|
|
343
|
+
raise ValueError('fractional years or months not supported'
|
|
344
|
+
' for date calculations')
|
|
345
|
+
newmonth = other.month + self.months
|
|
346
|
+
carry, newmonth = fquotmod(newmonth, 1, 13)
|
|
347
|
+
newyear = other.year + self.years + carry
|
|
348
|
+
maxdays = max_days_in_month(newyear, newmonth)
|
|
349
|
+
if other.day > maxdays:
|
|
350
|
+
newday = maxdays
|
|
351
|
+
else:
|
|
352
|
+
newday = other.day
|
|
353
|
+
newdt = other.replace(year=newyear, month=newmonth, day=newday)
|
|
354
|
+
|
|
355
|
+
return self.tdelta + newdt
|
|
356
|
+
except AttributeError:
|
|
357
|
+
|
|
358
|
+
pass
|
|
359
|
+
try:
|
|
360
|
+
|
|
361
|
+
newduration = Duration(years=self.years, months=self.months)
|
|
362
|
+
newduration.tdelta = self.tdelta + other
|
|
363
|
+
return newduration
|
|
364
|
+
except AttributeError:
|
|
365
|
+
|
|
366
|
+
pass
|
|
367
|
+
|
|
368
|
+
return NotImplemented
|
|
369
|
+
|
|
370
|
+
__radd__ = __add__
|
|
371
|
+
|
|
372
|
+
def __mul__(self, other):
|
|
373
|
+
if isinstance(other, int):
|
|
374
|
+
newduration = Duration(
|
|
375
|
+
years=self.years * other,
|
|
376
|
+
months=self.months * other)
|
|
377
|
+
newduration.tdelta = self.tdelta * other
|
|
378
|
+
return newduration
|
|
379
|
+
return NotImplemented
|
|
380
|
+
|
|
381
|
+
__rmul__ = __mul__
|
|
382
|
+
|
|
383
|
+
def __sub__(self, other):
|
|
384
|
+
|
|
385
|
+
if isinstance(other, Duration):
|
|
386
|
+
newduration = Duration(years=self.years - other.years,
|
|
387
|
+
months=self.months - other.months)
|
|
388
|
+
newduration.tdelta = self.tdelta - other.tdelta
|
|
389
|
+
return newduration
|
|
390
|
+
try:
|
|
391
|
+
newduration = Duration(years=self.years, months=self.months)
|
|
392
|
+
newduration.tdelta = self.tdelta - other
|
|
393
|
+
return newduration
|
|
394
|
+
except TypeError:
|
|
395
|
+
pass
|
|
396
|
+
return NotImplemented
|
|
397
|
+
|
|
398
|
+
def __rsub__(self, other):
|
|
399
|
+
if isinstance(other, timedelta):
|
|
400
|
+
tmpdur = Duration()
|
|
401
|
+
tmpdur.tdelta = other
|
|
402
|
+
return tmpdur - self
|
|
403
|
+
try:
|
|
404
|
+
if (not (float(self.years).is_integer() and
|
|
405
|
+
float(self.months).is_integer())):
|
|
406
|
+
raise ValueError('fractional years or months not supported'
|
|
407
|
+
' for date calculations')
|
|
408
|
+
newmonth = other.month - self.months
|
|
409
|
+
carry, newmonth = fquotmod(newmonth, 1, 13)
|
|
410
|
+
newyear = other.year - self.years + carry
|
|
411
|
+
maxdays = max_days_in_month(newyear, newmonth)
|
|
412
|
+
if other.day > maxdays:
|
|
413
|
+
newday = maxdays
|
|
414
|
+
else:
|
|
415
|
+
newday = other.day
|
|
416
|
+
newdt = other.replace(year=newyear, month=newmonth, day=newday)
|
|
417
|
+
return newdt - self.tdelta
|
|
418
|
+
except AttributeError:
|
|
419
|
+
pass
|
|
420
|
+
return NotImplemented
|
|
421
|
+
|
|
422
|
+
def __eq__(self, other):
|
|
423
|
+
|
|
424
|
+
if isinstance(other, Duration):
|
|
425
|
+
if (((self.years * 12 + self.months) ==
|
|
426
|
+
(other.years * 12 + other.months) and
|
|
427
|
+
self.tdelta == other.tdelta)):
|
|
428
|
+
return True
|
|
429
|
+
return False
|
|
430
|
+
if self.years == 0 and self.months == 0:
|
|
431
|
+
return self.tdelta == other
|
|
432
|
+
return False
|
|
433
|
+
|
|
434
|
+
def __ne__(self, other):
|
|
435
|
+
|
|
436
|
+
if isinstance(other, Duration):
|
|
437
|
+
if (((self.years * 12 + self.months) !=
|
|
438
|
+
(other.years * 12 + other.months) or
|
|
439
|
+
self.tdelta != other.tdelta)):
|
|
440
|
+
return True
|
|
441
|
+
return False
|
|
442
|
+
if self.years == 0 and self.months == 0:
|
|
443
|
+
return self.tdelta != other
|
|
444
|
+
return True
|
|
445
|
+
|
|
446
|
+
def totimedelta(self, start=None, end=None):
|
|
447
|
+
if start is None and end is None:
|
|
448
|
+
raise ValueError("start or end required")
|
|
449
|
+
if start is not None and end is not None:
|
|
450
|
+
raise ValueError("only start or end allowed")
|
|
451
|
+
if start is not None:
|
|
452
|
+
return (start + self) - start
|
|
453
|
+
return end - (end - self)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class ISO8601Error(ValueError):
|
|
457
|
+
'''Raised when the given ISO string can not be parsed.'''
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def parse_datetime(datetimestring):
|
|
461
|
+
'''
|
|
462
|
+
Parses ISO 8601 date-times into datetime.datetime objects.
|
|
463
|
+
This function uses parse_date and parse_time to do the job, so it allows
|
|
464
|
+
more combinations of date and time representations, than the actual
|
|
465
|
+
ISO 8601:2004 standard allows.
|
|
466
|
+
'''
|
|
467
|
+
try:
|
|
468
|
+
datestring, timestring = datetimestring.split('T')
|
|
469
|
+
except ValueError:
|
|
470
|
+
raise ISO8601Error("ISO 8601 time designator 'T' missing. Unable to"
|
|
471
|
+
" parse datetime string %r" % datetimestring)
|
|
472
|
+
tmpdate = parse_date(datestring)
|
|
473
|
+
tmptime = parse_time(timestring)
|
|
474
|
+
return datetime.combine(tmpdate, tmptime)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def parse_date(
|
|
478
|
+
datestring,
|
|
479
|
+
yeardigits=4, expanded=False, defaultmonth=1, defaultday=1):
|
|
480
|
+
'''
|
|
481
|
+
Parse an ISO 8601 date string into a datetime.date object.
|
|
482
|
+
As the datetime.date implementation is limited to dates starting from
|
|
483
|
+
0001-01-01, negative dates (BC) and year 0 can not be parsed by this
|
|
484
|
+
method.
|
|
485
|
+
For incomplete dates, this method chooses the first day for it. For
|
|
486
|
+
instance if only a century is given, this method returns the 1st of
|
|
487
|
+
January in year 1 of this century.
|
|
488
|
+
supported formats: (expanded formats are shown with 6 digits for year)
|
|
489
|
+
YYYYMMDD +-YYYYYYMMDD basic complete date
|
|
490
|
+
YYYY-MM-DD +-YYYYYY-MM-DD extended complete date
|
|
491
|
+
YYYYWwwD +-YYYYYYWwwD basic complete week date
|
|
492
|
+
YYYY-Www-D +-YYYYYY-Www-D extended complete week date
|
|
493
|
+
YYYYDDD +-YYYYYYDDD basic ordinal date
|
|
494
|
+
YYYY-DDD +-YYYYYY-DDD extended ordinal date
|
|
495
|
+
YYYYWww +-YYYYYYWww basic incomplete week date
|
|
496
|
+
YYYY-Www +-YYYYYY-Www extended incomplete week date
|
|
497
|
+
YYYMM +-YYYYYYMM basic incomplete month date
|
|
498
|
+
YYY-MM +-YYYYYY-MM incomplete month date
|
|
499
|
+
YYYY +-YYYYYY incomplete year date
|
|
500
|
+
YY +-YYYY incomplete century date
|
|
501
|
+
@param datestring: the ISO date string to parse
|
|
502
|
+
@param yeardigits: how many digits are used to represent a year
|
|
503
|
+
@param expanded: if True then +/- signs are allowed. This parameter
|
|
504
|
+
is forced to True, if yeardigits != 4
|
|
505
|
+
@return: a datetime.date instance represented by datestring
|
|
506
|
+
@raise ISO8601Error: if this function can not parse the datestring
|
|
507
|
+
@raise ValueError: if datestring can not be represented by datetime.date
|
|
508
|
+
'''
|
|
509
|
+
if yeardigits != 4:
|
|
510
|
+
expanded = True
|
|
511
|
+
isodates = build_date_regexps(yeardigits, expanded)
|
|
512
|
+
for pattern in isodates:
|
|
513
|
+
match = pattern.match(datestring)
|
|
514
|
+
if match:
|
|
515
|
+
groups = match.groupdict()
|
|
516
|
+
# sign, century, year, month, week, day,
|
|
517
|
+
# FIXME: negative dates not possible with python standard types
|
|
518
|
+
sign = (groups['sign'] == '-' and -1) or 1
|
|
519
|
+
if 'century' in groups:
|
|
520
|
+
return date(
|
|
521
|
+
sign * (int(groups['century']) * 100 + 1),
|
|
522
|
+
defaultmonth, defaultday)
|
|
523
|
+
if 'month' not in groups: # weekdate or ordinal date
|
|
524
|
+
ret = date(sign * int(groups['year']), 1, 1)
|
|
525
|
+
if 'week' in groups:
|
|
526
|
+
isotuple = ret.isocalendar()
|
|
527
|
+
if 'day' in groups:
|
|
528
|
+
days = int(groups['day'] or 1)
|
|
529
|
+
else:
|
|
530
|
+
days = 1
|
|
531
|
+
# if first week in year, do weeks-1
|
|
532
|
+
return ret + timedelta(weeks=int(groups['week']) -
|
|
533
|
+
(((isotuple[1] == 1) and 1) or 0),
|
|
534
|
+
days=-isotuple[2] + days)
|
|
535
|
+
elif 'day' in groups: # ordinal date
|
|
536
|
+
return ret + timedelta(days=int(groups['day']) - 1)
|
|
537
|
+
else: # year date
|
|
538
|
+
return ret.replace(month=defaultmonth, day=defaultday)
|
|
539
|
+
# year-, month-, or complete date
|
|
540
|
+
if 'day' not in groups or groups['day'] is None:
|
|
541
|
+
day = defaultday
|
|
542
|
+
else:
|
|
543
|
+
day = int(groups['day'])
|
|
544
|
+
return date(sign * int(groups['year']),
|
|
545
|
+
int(groups['month']) or defaultmonth, day)
|
|
546
|
+
raise ISO8601Error('Unrecognised ISO 8601 date format: %r' % datestring)
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def parse_time(timestring):
|
|
550
|
+
'''
|
|
551
|
+
Parses ISO 8601 times into datetime.time objects.
|
|
552
|
+
Following ISO 8601 formats are supported:
|
|
553
|
+
(as decimal separator a ',' or a '.' is allowed)
|
|
554
|
+
hhmmss.ssTZD basic complete time
|
|
555
|
+
hh:mm:ss.ssTZD extended compelte time
|
|
556
|
+
hhmm.mmTZD basic reduced accuracy time
|
|
557
|
+
hh:mm.mmTZD extended reduced accuracy time
|
|
558
|
+
hh.hhTZD basic reduced accuracy time
|
|
559
|
+
TZD is the time zone designator which can be in the following format:
|
|
560
|
+
no designator indicates local time zone
|
|
561
|
+
Z UTC
|
|
562
|
+
+-hhmm basic hours and minutes
|
|
563
|
+
+-hh:mm extended hours and minutes
|
|
564
|
+
+-hh hours
|
|
565
|
+
'''
|
|
566
|
+
isotimes = build_time_regexps()
|
|
567
|
+
for pattern in isotimes:
|
|
568
|
+
match = pattern.match(timestring)
|
|
569
|
+
if match:
|
|
570
|
+
groups = match.groupdict()
|
|
571
|
+
for key, value in groups.items():
|
|
572
|
+
if value is not None:
|
|
573
|
+
groups[key] = value.replace(',', '.')
|
|
574
|
+
Tzinfo = build_tzinfo(groups['tzname'], groups['tzsign'],
|
|
575
|
+
int(groups['tzhour'] or 0),
|
|
576
|
+
int(groups['tzmin'] or 0))
|
|
577
|
+
if 'second' in groups:
|
|
578
|
+
# round to microseconds if fractional seconds are more precise
|
|
579
|
+
second = Decimal(groups['second']).quantize(Decimal('.000001'))
|
|
580
|
+
microsecond = (second - int(second)) * int(1e6)
|
|
581
|
+
# int(...) ... no rounding
|
|
582
|
+
# to_integral() ... rounding
|
|
583
|
+
return time(int(groups['hour']), int(groups['minute']),
|
|
584
|
+
int(second), int(microsecond.to_integral()),
|
|
585
|
+
Tzinfo)
|
|
586
|
+
if 'minute' in groups:
|
|
587
|
+
minute = Decimal(groups['minute'])
|
|
588
|
+
second = (minute - int(minute)) * 60
|
|
589
|
+
microsecond = (second - int(second)) * int(1e6)
|
|
590
|
+
return time(int(groups['hour']), int(minute), int(second),
|
|
591
|
+
int(microsecond.to_integral()), Tzinfo)
|
|
592
|
+
else:
|
|
593
|
+
microsecond, second, minute = 0, 0, 0
|
|
594
|
+
hour = Decimal(groups['hour'])
|
|
595
|
+
minute = (hour - int(hour)) * 60
|
|
596
|
+
second = (minute - int(minute)) * 60
|
|
597
|
+
microsecond = (second - int(second)) * int(1e6)
|
|
598
|
+
return time(int(hour), int(minute), int(second),
|
|
599
|
+
int(microsecond.to_integral()), Tzinfo)
|
|
600
|
+
raise ISO8601Error('Unrecognised ISO 8601 time format: %r' % timestring)
|