Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-MapProxy for openSUSE:Factory checked in at 2022-01-17 22:34:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-MapProxy (Old) and /work/SRC/openSUSE:Factory/.python-MapProxy.new.1892 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-MapProxy" Mon Jan 17 22:34:28 2022 rev:4 rq:947029 version:1.14.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-MapProxy/python-MapProxy.changes 2021-07-28 19:21:39.687507893 +0200 +++ /work/SRC/openSUSE:Factory/.python-MapProxy.new.1892/python-MapProxy.changes 2022-01-17 22:35:27.070299566 +0100 @@ -1,0 +2,14 @@ +Thu Jan 13 10:09:56 UTC 2022 - Ben Greiner <c...@bnavigator.de> + +- Update to 1.14.0 + * Refresh while serving (#518). + * Enabled commandline option skip uncached (#515) + * Several dependencies updated + * Support for python 3.5 has been dropped because of its EOL, 3.9 + has been added + * Several minor bugfixes + * Security fix to avoid potential web cache poisoning. +- Remove -devel and pkgconfig build dependencies: This is a pure + python package not using any headers + +------------------------------------------------------------------- Old: ---- MapProxy-1.13.2.tar.gz New: ---- MapProxy-1.14.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-MapProxy.spec ++++++ --- /var/tmp/diff_new_pack.C3pm91/_old 2022-01-17 22:35:27.430299805 +0100 +++ /var/tmp/diff_new_pack.C3pm91/_new 2022-01-17 22:35:27.434299807 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-MapProxy # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -21,7 +21,7 @@ %{?!python_module:%define python_module() python3-%{**}} %define pythons python3 Name: python-MapProxy -Version: 1.13.2 +Version: 1.14.0 Release: 0 Summary: Proxy for geospatial data License: Apache-2.0 @@ -36,11 +36,7 @@ BuildRequires: %{python_module PyYAML} BuildRequires: %{python_module setuptools} BuildRequires: fdupes -BuildRequires: geos-devel -BuildRequires: hdf5-devel BuildRequires: python-rpm-macros -BuildRequires: pkgconfig(gdal) -BuildRequires: pkgconfig(proj) %if %{with test} BuildRequires: %{python_module Paste} BuildRequires: %{python_module Shapely} @@ -66,6 +62,7 @@ Requires: python-Shapely Requires: python-gdal Requires: python-lxml +Requires: (python3-pyproj if proj > 5) Recommends: python-Paste Recommends: python-Werkzeug Recommends: python-boto3 @@ -77,10 +74,6 @@ Recommends: python-requests Recommends: python-riak BuildArch: noarch -%ifpython2 -Obsoletes: %{oldpython}-mapproxy < %{version} -Provides: %{oldpython}-mapproxy = %{version} -%endif Requires(post): update-alternatives Requires(postun):update-alternatives %python_subpackages @@ -124,8 +117,6 @@ donttest+=" or test_https_" # off by one error capturing the execptions donttest+=" or test_bad_config_geopackage_" -# new geotif and jpeg are bogue -donttest+=" or test_geotiff_tags" %pytest mapproxy -ra -k "not ($donttest)" %files %{python_files} ++++++ MapProxy-1.13.2.tar.gz -> MapProxy-1.14.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/CHANGES.txt new/MapProxy-1.14.0/CHANGES.txt --- old/MapProxy-1.13.2/CHANGES.txt 2021-07-14 16:07:42.000000000 +0200 +++ new/MapProxy-1.14.0/CHANGES.txt 2021-11-24 14:19:19.000000000 +0100 @@ -1,6 +1,21 @@ Nightly ~~~~~~~~~~~~~~~~~ +1.14.0 2021-11-24 +~~~~~~~~~~~~~~~~~ + +Improvements: + +- Refresh while serving (#518). +- Enabled commandline option `skip uncached` (#515) +- Several dependencies updated +- Support for python 3.5 has been dropped because of its EOL, 3.9 has been added + +Fixes: + +- Several minor bugfixes +- Security fix to avoid potential web cache poisoning. + 1.13.2 2021-07-14 ~~~~~~~~~~~~~~~~~ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/MapProxy.egg-info/PKG-INFO new/MapProxy-1.14.0/MapProxy.egg-info/PKG-INFO --- old/MapProxy-1.13.2/MapProxy.egg-info/PKG-INFO 2021-07-14 16:11:28.000000000 +0200 +++ new/MapProxy-1.14.0/MapProxy.egg-info/PKG-INFO 2021-11-24 14:30:25.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: MapProxy -Version: 1.13.2 +Version: 1.14.0 Summary: An accelerating proxy for tile and web map services Home-page: https://mapproxy.org Author: Oliver Tonnhofer @@ -23,6 +23,21 @@ Nightly ~~~~~~~~~~~~~~~~~ + 1.14.0 2021-11-24 + ~~~~~~~~~~~~~~~~~ + + Improvements: + + - Refresh while serving (#518). + - Enabled commandline option `skip uncached` (#515) + - Several dependencies updated + - Support for python 3.5 has been dropped because of its EOL, 3.9 has been added + + Fixes: + + - Several minor bugfixes + - Security fix to avoid potential web cache poisoning. + 1.13.2 2021-07-14 ~~~~~~~~~~~~~~~~~ @@ -135,17 +150,6 @@ - Remove support for Python 2.6 - 1.10.4 2017-08-17 - ~~~~~~~~~~~~~~~~~ - - Fixes: - - - Fix Cross Site Scripting (XSS) issue in demo service (#322). - A targeted attack could be used for information disclosure. For - example: Session cookies of a third party application running on - the same domain. - - Older changes ------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/MapProxy.egg-info/SOURCES.txt new/MapProxy-1.14.0/MapProxy.egg-info/SOURCES.txt --- old/MapProxy-1.13.2/MapProxy.egg-info/SOURCES.txt 2021-07-14 16:11:29.000000000 +0200 +++ new/MapProxy-1.14.0/MapProxy.egg-info/SOURCES.txt 2021-11-24 14:30:25.000000000 +0100 @@ -328,7 +328,9 @@ mapproxy/test/system/test_mixed_mode_format.py mapproxy/test/system/test_multi_cache_layers.py mapproxy/test/system/test_multiapp.py +mapproxy/test/system/test_refresh.py mapproxy/test/system/test_renderd_client.py +mapproxy/test/system/test_response_headers.py mapproxy/test/system/test_scalehints.py mapproxy/test/system/test_seed.py mapproxy/test/system/test_seed_only.py @@ -392,6 +394,7 @@ mapproxy/test/system/fixture/source_errors.yaml mapproxy/test/system/fixture/source_errors_raise.yaml mapproxy/test/system/fixture/tileservice_origin.yaml +mapproxy/test/system/fixture/tileservice_refresh.yaml mapproxy/test/system/fixture/tilesource_minmax_res.yaml mapproxy/test/system/fixture/util-conf-base-grids.yaml mapproxy/test/system/fixture/util-conf-overwrite.yaml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/MapProxy.egg-info/requires.txt new/MapProxy-1.14.0/MapProxy.egg-info/requires.txt --- old/MapProxy-1.13.2/MapProxy.egg-info/requires.txt 2021-07-14 16:11:28.000000000 +0200 +++ new/MapProxy-1.14.0/MapProxy.egg-info/requires.txt 2021-11-24 14:30:25.000000000 +0100 @@ -1,2 +1,2 @@ -Pillow!=2.4.0 +Pillow!=2.4.0,!=8.3.0,!=8.3.1 PyYAML>=3.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/PKG-INFO new/MapProxy-1.14.0/PKG-INFO --- old/MapProxy-1.13.2/PKG-INFO 2021-07-14 16:11:29.088878400 +0200 +++ new/MapProxy-1.14.0/PKG-INFO 2021-11-24 14:30:25.250494000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: MapProxy -Version: 1.13.2 +Version: 1.14.0 Summary: An accelerating proxy for tile and web map services Home-page: https://mapproxy.org Author: Oliver Tonnhofer @@ -23,6 +23,21 @@ Nightly ~~~~~~~~~~~~~~~~~ + 1.14.0 2021-11-24 + ~~~~~~~~~~~~~~~~~ + + Improvements: + + - Refresh while serving (#518). + - Enabled commandline option `skip uncached` (#515) + - Several dependencies updated + - Support for python 3.5 has been dropped because of its EOL, 3.9 has been added + + Fixes: + + - Several minor bugfixes + - Security fix to avoid potential web cache poisoning. + 1.13.2 2021-07-14 ~~~~~~~~~~~~~~~~~ @@ -135,17 +150,6 @@ - Remove support for Python 2.6 - 1.10.4 2017-08-17 - ~~~~~~~~~~~~~~~~~ - - Fixes: - - - Fix Cross Site Scripting (XSS) issue in demo service (#322). - A targeted attack could be used for information disclosure. For - example: Session cookies of a third party application running on - the same domain. - - Older changes ------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/doc/conf.py new/MapProxy-1.14.0/doc/conf.py --- old/MapProxy-1.13.2/doc/conf.py 2021-07-14 16:08:05.000000000 +0200 +++ new/MapProxy-1.14.0/doc/conf.py 2021-11-24 14:20:00.000000000 +0100 @@ -49,9 +49,9 @@ # built documents. # # The short X.Y version. -version = '1.13' +version = '1.14' # The full version, including alpha/beta/rc tags. -release = '1.13.2' +release = '1.14.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/doc/configuration.rst new/MapProxy-1.14.0/doc/configuration.rst --- old/MapProxy-1.13.2/doc/configuration.rst 2021-05-21 10:47:37.000000000 +0200 +++ new/MapProxy-1.14.0/doc/configuration.rst 2021-11-23 16:34:08.000000000 +0100 @@ -513,6 +513,43 @@ Tiles created by the ``upscale_tiles`` or ``downscale_tiles`` option are only stored in the cache if this option is set to true. +``refresh_before`` +""""""""""""""""""" + +Here you can force MapProxy to refresh tiles from the source while serving if they are found to be expired. +The validity conditions are the same as for seeding: + +Explanation:: + + # absolute as ISO time + refresh_before: + time: 2010-10-21T12:35:00 + + # relative from the time of the tile request + refresh_before: + weeks: 1 + days: 7 + hours: 4 + minutes: 15 + + # modification time of a given file + refresh_before: + mtime: path/to/file + +Example +~~~~~~~~ + +:: + + caches: + osm_cache: + grids: ['osm_grid'] + sources: [OSM] + disable_storage: false + refresh_before: + days: 1 + + ``disable_storage`` """""""""""""""""""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/doc/mapproxy_util.rst new/MapProxy-1.14.0/doc/mapproxy_util.rst --- old/MapProxy-1.13.2/doc/mapproxy_util.rst 2020-05-27 13:37:56.000000000 +0200 +++ new/MapProxy-1.14.0/doc/mapproxy_util.rst 2021-11-05 12:12:41.000000000 +0100 @@ -73,7 +73,7 @@ log-ini: - Creates an example logging configuration. You need to pass the target filename to the command. + Creates an example logging configuration. You need to pass the target filename to the command (i.e. `my-app/log.ini`). wsgi-app: Creates an example server script for the given MapProxy configuration (:option:`--f/--mapproxy-conf<mapproxy-util create -f>`) . You need to pass the target filename to the command. @@ -105,6 +105,10 @@ The server address where the HTTP server should listen for incomming connections. Can be a port (``:8080``), a host (``localhost``) or both (``localhost:8081``). The default is ``localhost:8080``. You need to use ``0.0.0.0`` to be able to connect to the server from external clients. +.. cmdoption:: --debug + + The server outputs debug logging information to the console. + Example ------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/doc/seed.rst new/MapProxy-1.14.0/doc/seed.rst --- old/MapProxy-1.13.2/doc/seed.rst 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/doc/seed.rst 2021-11-23 16:34:08.000000000 +0100 @@ -69,6 +69,16 @@ This will simulate the seed/cleanup process without requesting, creating or removing any tiles. +.. option:: -l N, --skip-geoms-for-last-levels N + + This will skip checking the intersections between tiles and seed geometries on the last N levels. + +.. option:: --skip-uncached + + This will seed only tiles which are already in the cache. This option is interesting in combination with + the configuration entry `refresh_before`_ to refresh regularly the existing tiles and to avoid loading + all available tiles. + .. option:: --summary Print a summary of all seeding and cleanup tasks and exit. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/doc/sources.rst new/MapProxy-1.14.0/doc/sources.rst --- old/MapProxy-1.13.2/doc/sources.rst 2021-05-21 10:47:37.000000000 +0200 +++ new/MapProxy-1.14.0/doc/sources.rst 2021-11-23 16:34:08.000000000 +0100 @@ -242,6 +242,12 @@ You need to enable ``transparent`` for your source, if you use ``on_error`` responses with transparency. +``authorize_stale`` + + Set this to ``True`` if MapProxy should serve in priority stale tiles present in cache. If the specified source error occurs, MapProxy will serve a stale tile which is still in cache instead of the error reponse, even if the tile in cache should be refreshed according to refresh_before date. Otherwise (``False``) MapProxy will serve the unicolor error response defined by the error handler if the source is faulty and the tile is not in cache, or is stale. + +You need to enable ``transparent`` for your source, if you use ``on_error`` responses with transparency. + :: my_tile_source: @@ -250,6 +256,10 @@ url: http://localhost:8080/service? layers: base on_error: + 404: + response: 'transparent' + cache: False + authorize_stale: True 500: response: '#ede9e3' cache: False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/cache/tile.py new/MapProxy-1.14.0/mapproxy/cache/tile.py --- old/MapProxy-1.13.2/mapproxy/cache/tile.py 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/cache/tile.py 2021-11-23 16:34:09.000000000 +0100 @@ -44,8 +44,10 @@ from mapproxy.image.merge import merge_images from mapproxy.image.tile import TileSplitter, TiledImage from mapproxy.layer import MapQuery, BlankImage +from mapproxy.source import SourceError from mapproxy.util import async_ -from mapproxy.util.py import reraise +from mapproxy.util.py import reraise, reraise_exception +import sys class TileManager(object): @@ -76,6 +78,7 @@ self.sources = sources self.minimize_meta_requests = minimize_meta_requests self._expire_timestamp = None + self._refresh_before = {} self.pre_store_filter = pre_store_filter or [] self.concurrent_tile_creators = concurrent_tile_creators self.tile_creator_class = tile_creator_class or TileCreator @@ -202,7 +205,9 @@ max_mtime = self.expire_timestamp(tile) if cached and max_mtime is not None: self.cache.load_tile_metadata(tile) - stale = tile.timestamp < max_mtime + # file time stamp must be rounded to integer since time conversion functions + # mktime and timetuple strip decimals from seconds + stale = int(tile.timestamp) <= max_mtime if stale: cached = False return cached @@ -228,6 +233,9 @@ :note: Returns _expire_timestamp by default. """ + if self._refresh_before: + from mapproxy.seed.config import before_timestamp_from_options + return before_timestamp_from_options(self._refresh_before) return self._expire_timestamp def apply_tile_filter(self, tile): @@ -318,6 +326,12 @@ """ return self.tile_mgr.is_cached(tile) + def is_stale(self, tile): + """ + Return True if the tile exists in cache and is expired. + """ + return self.tile_mgr.is_stale(tile) + def create_tiles(self, tiles): if not self.sources: return [] @@ -362,8 +376,20 @@ self.tile_mgr.request_format, dimensions=self.dimensions) with self.tile_mgr.lock(tile): if not self.is_cached(tile): - source = self._query_sources(query) + try: + source = self._query_sources(query) + # if source is not available, try to serve tile in cache + except SourceError as e: + if self.is_stale(tile): + self.cache.load_tile(tile) + else: + reraise_exception(e, sys.exc_info()) if not source: return [] + if source.authorize_stale and self.is_stale(tile): + # The configuration authorises blank tiles generated by the error_handler + # to be replaced by stale tiles from cache. + self.cache.load_tile(tile) + return [tile] if self.tile_mgr.image_opts != source.image_opts: # call as_buffer to force conversion into cache format source.as_buffer(self.tile_mgr.image_opts) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/config/loader.py new/MapProxy-1.14.0/mapproxy/config/loader.py --- old/MapProxy-1.13.2/mapproxy/config/loader.py 2021-05-21 10:47:37.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/config/loader.py 2021-11-23 16:34:09.000000000 +0100 @@ -611,11 +611,12 @@ raise ConfigurationError("invalid error code %r in on_error", status_code) cacheable = response_conf.get('cache', False) color = response_conf.get('response', 'transparent') + authorize_stale = response_conf.get('authorize_stale', False) if color == 'transparent': color = (255, 255, 255, 0) else: color = parse_color(color) - error_handler.add_handler(status_code, color, cacheable) + error_handler.add_handler(status_code, color, cacheable, authorize_stale) return error_handler @@ -1574,6 +1575,8 @@ cache_rescaled_tiles=cache_rescaled_tiles, rescale_tiles=rescale_tiles, ) + if self.conf['name'] in self.context.caches: + mgr._refresh_before = self.context.caches[self.conf['name']].conf.get('refresh_before', {}) extent = merge_layer_extents(sources) if extent.is_default: extent = map_extent_from_grid(tile_grid) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/config/spec.py new/MapProxy-1.14.0/mapproxy/config/spec.py --- old/MapProxy-1.13.2/mapproxy/config/spec.py 2021-05-21 10:47:37.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/config/spec.py 2021-11-23 16:34:09.000000000 +0100 @@ -36,6 +36,16 @@ else: return [], True +time_spec = { + 'seconds': number(), + 'minutes': number(), + 'hours': number(), + 'days': number(), + 'weeks': number(), + 'time': anything(), + 'mtime': str(), +} + coverage = recursive({ 'polygons': str(), 'polygons_srs': str(), @@ -179,6 +189,7 @@ anything(): { required('response'): one_of([int], str), 'cache': bool, + 'authorize_stale': bool } } @@ -419,6 +430,7 @@ 'cache_rescaled_tiles': bool(), 'upscale_tiles': int(), 'downscale_tiles': int(), + 'refresh_before': time_spec, 'watermark': { 'text': string_type, 'font_size': number(), @@ -588,8 +600,7 @@ } })]) ), - # `parts` can be used for partial configurations that are referenced - # from other sections (e.g. coverages, dimensions, etc.) + # `parts` can be used for partial configurations that are referenced + # from other sections (e.g. coverages, dimensions, etc.) 'parts': anything(), } - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/image/__init__.py new/MapProxy-1.14.0/mapproxy/image/__init__.py --- old/MapProxy-1.13.2/mapproxy/image/__init__.py 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/image/__init__.py 2021-11-23 16:34:09.000000000 +0100 @@ -89,7 +89,24 @@ return tags -class ImageSource(object): +class BaseImageSource(object): + """ + Virtual parent class for ImageSource and BlankImageSource + """ + def __init__(self): + raise Exception("Virtual class BaseImageSource, cannot be instanciated.") + + def as_image(self): + raise Exception("Virtual class BaseImageSource, method as_image cannot be called.") + + def as_buffer(self, image_opts=None, format=None, seekable=False): + raise Exception("Virtual class BaseImageSource, method as_buffer cannot be called.") + + def close_buffers(self): + pass + + +class ImageSource(BaseImageSource): """ This class wraps either a PIL image, a file-like object, or a file name. You can access the result as an image (`as_image` ) or a file-like buffer @@ -111,6 +128,7 @@ self._size = size self.cacheable = cacheable self.georef = georef + self.authorize_stale = False @property def source(self): @@ -238,7 +256,7 @@ img.paste(subimg, offset) return ImageSource(img, size=size, image_opts=new_image_opts, cacheable=cacheable) -class BlankImageSource(object): +class BlankImageSource(BaseImageSource): """ ImageSource for transparent or solid-color images. Implements optimized as_buffer() method. @@ -249,6 +267,7 @@ self._buf = None self._img = None self.cacheable = cacheable + self.authorize_stale = False def as_image(self): if not self._img: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/response.py new/MapProxy-1.14.0/mapproxy/response.py --- old/MapProxy-1.13.2/mapproxy/response.py 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/response.py 2021-11-24 14:26:54.000000000 +0100 @@ -42,6 +42,12 @@ content_type = self.default_content_type self.headers['Content-type'] = content_type + if content_type.startswith(('text/', 'application/')): + # Capability documents can be dependent on the value of a few X-headers. + # Tell this caching proxies via the Vary HTTP header. This also prevents + # malicious cache poisoning. + self.headers['Vary'] = 'X-Script-Name, X-Forwarded-Host, X-Forwarded-Proto' + def _status_set(self, status): if isinstance(status, int): status = status_code(status) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/script/conf/app.py new/MapProxy-1.14.0/mapproxy/script/conf/app.py --- old/MapProxy-1.13.2/mapproxy/script/conf/app.py 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/script/conf/app.py 2021-11-23 16:34:09.000000000 +0100 @@ -71,7 +71,10 @@ @contextmanager def file_or_stdout(name): if name == '-': - yield codecs.getwriter('utf-8')(sys.stdout) + if hasattr(sys.stdout, 'buffer'): + yield codecs.getwriter('utf-8')(sys.stdout.buffer) + else: + yield codecs.getwriter('utf-8')(sys.stdout) else: with open(name, 'wb') as f: yield codecs.getwriter('utf-8')(f) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/seed/script.py new/MapProxy-1.14.0/mapproxy/seed/script.py --- old/MapProxy-1.13.2/mapproxy/seed/script.py 2020-05-27 13:37:56.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/seed/script.py 2021-11-23 16:34:09.000000000 +0100 @@ -105,6 +105,11 @@ metavar="N", help="do not check for intersections between tiles" " and seed geometries on the last N levels") + parser.add_option("--skip-uncached", + action="store_true", dest="skip_uncached", default=False, + help="only treat tiles which are already present in the cache." + " This can be used with the configuration entry `refresh_before`" + " to refresh only the existing cache.") parser.add_option("--summary", action="store_true", dest="summary", default=False, help="print summary with all seeding tasks and exit." @@ -243,7 +248,8 @@ progress_store=progress) seed(seed_tasks, progress_logger=logger, dry_run=options.dry_run, concurrency=options.concurrency, cache_locker=cache_locker, - skip_geoms_for_last_levels=options.geom_levels) + skip_geoms_for_last_levels=options.geom_levels, + skip_uncached=options.skip_uncached) if cleanup_tasks: print('========== Cleanup tasks ==========') print('Start cleanup process (%d task%s)' % ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/seed/seeder.py new/MapProxy-1.14.0/mapproxy/seed/seeder.py --- old/MapProxy-1.13.2/mapproxy/seed/seeder.py 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/seed/seeder.py 2021-11-23 16:34:09.000000000 +0100 @@ -477,7 +477,7 @@ return NONE def seed(tasks, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0, - progress_logger=None, cache_locker=None): + progress_logger=None, cache_locker=None, skip_uncached=False): if cache_locker is None: cache_locker = DummyCacheLocker() @@ -496,7 +496,7 @@ start_progress = None seed_progress = SeedProgress(old_progress_identifier=start_progress) seed_task(task, concurrency, dry_run, skip_geoms_for_last_levels, progress_logger, - seed_progress=seed_progress) + seed_progress=seed_progress, skip_uncached=skip_uncached) except CacheLockedError: print(' ...cache is locked, skipping') active_tasks = [task] + active_tasks[:-1] @@ -505,7 +505,7 @@ def seed_task(task, concurrency=2, dry_run=False, skip_geoms_for_last_levels=0, - progress_logger=None, seed_progress=None): + progress_logger=None, seed_progress=None, skip_uncached=False): if task.coverage is False: return if task.refresh_timestamp is not None: @@ -518,7 +518,11 @@ tile_worker_pool = TileWorkerPool(task, TileSeedWorker, dry_run=dry_run, size=concurrency, progress_logger=progress_logger) - tile_walker = TileWalker(task, tile_worker_pool, handle_uncached=True, + # If the configuration requests to only refresh tiles which are already in cache, + # tile walker parameters shall be adapted + handle_stale = skip_uncached + handle_uncached = not skip_uncached + tile_walker = TileWalker(task, tile_worker_pool, handle_uncached=handle_uncached, handle_stale=handle_stale, skip_geoms_for_last_levels=skip_geoms_for_last_levels, progress_logger=progress_logger, seed_progress=seed_progress, work_on_metatiles=work_on_metatiles, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/seed/spec.py new/MapProxy-1.14.0/mapproxy/seed/spec.py --- old/MapProxy-1.13.2/mapproxy/seed/spec.py 2020-05-27 13:37:56.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/seed/spec.py 2021-11-23 16:34:09.000000000 +0100 @@ -17,7 +17,7 @@ from mapproxy.util.ext.dictspec.spec import one_off, anything, number from mapproxy.util.ext.dictspec.spec import required -from mapproxy.config.spec import coverage +from mapproxy.config.spec import coverage, time_spec def validate_seed_conf(conf_dict): """ @@ -31,16 +31,6 @@ else: return [], True -time_spec = { - 'seconds': number(), - 'minutes': number(), - 'hours': number(), - 'days': number(), - 'weeks': number(), - 'time': anything(), - 'mtime': str(), -} - from_to_spec = { 'from': number(), 'to': number(), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/source/error.py new/MapProxy-1.14.0/mapproxy/source/error.py --- old/MapProxy-1.13.2/mapproxy/source/error.py 2020-05-27 13:37:56.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/source/error.py 2021-11-23 16:34:09.000000000 +0100 @@ -20,19 +20,20 @@ def __init__(self): self.response_error_codes = {} - def add_handler(self, http_code, color, cacheable=False): - self.response_error_codes[http_code] = (color, cacheable) + def add_handler(self, http_code, color, cacheable=False, authorize_stale=False): + self.response_error_codes[http_code] = (color, cacheable, authorize_stale) def handle(self, status_code, query): color = cacheable = None if status_code in self.response_error_codes: - color, cacheable = self.response_error_codes[status_code] + color, cacheable, authorize_stale = self.response_error_codes[status_code] elif 'other' in self.response_error_codes: - color, cacheable = self.response_error_codes['other'] + color, cacheable, authorize_stale = self.response_error_codes['other'] else: return None transparent = len(color) == 4 image_opts = ImageOptions(bgcolor=color, transparent=transparent) img_source = BlankImageSource(query.size, image_opts, cacheable=cacheable) - return img_source \ No newline at end of file + img_source.authorize_stale = authorize_stale + return img_source diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/test/system/fixture/tileservice_refresh.yaml new/MapProxy-1.14.0/mapproxy/test/system/fixture/tileservice_refresh.yaml --- old/MapProxy-1.13.2/mapproxy/test/system/fixture/tileservice_refresh.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/MapProxy-1.14.0/mapproxy/test/system/fixture/tileservice_refresh.yaml 2021-11-23 16:34:09.000000000 +0100 @@ -0,0 +1,59 @@ +globals: + cache: + base_dir: cache_data/ + meta_size: [1, 1] + meta_buffer: 0 + +services: + tms: + # origin: 'nw' + +layers: + - name: wms_cache + title: Direct Layer + sources: [wms_cache] + + - name: wms_cache_isotime + title: Direct Layer + sources: [wms_cache_isotime] + + - name: wms_cache_png + title: Direct Layer + sources: [wms_cache_png] + +caches: + wms_cache: + format: image/jpeg + sources: [wms_source] + refresh_before: + seconds: 1 + + wms_cache_isotime: + format: image/jpeg + sources: [wms_source] + refresh_before: + time: "2009-02-15T23:31:30" + + wms_cache_png: + format: image/png + sources: [wms_source] + refresh_before: + seconds: 1 + +sources: + wms_source: + type: wms + req: + url: http://localhost:42423/service + layers: bar + on_error: + 404: + response: 'transparent' + cache: False + 405: + response: '#ff0000' + cache: False + 406: + response: 'transparent' + cache: False + authorize_stale: True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/test/system/test_refresh.py new/MapProxy-1.14.0/mapproxy/test/system/test_refresh.py --- old/MapProxy-1.13.2/mapproxy/test/system/test_refresh.py 1970-01-01 01:00:00.000000000 +0100 +++ new/MapProxy-1.14.0/mapproxy/test/system/test_refresh.py 2021-11-23 16:34:09.000000000 +0100 @@ -0,0 +1,207 @@ +# This file is part of the MapProxy project. +# Copyright (C) 2010-2012 Omniscale <http://omniscale.de> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import time +import hashlib + +from io import BytesIO +import pytest + +from mapproxy.compat.image import Image +from mapproxy.test.image import is_jpeg, tmp_image +from mapproxy.test.http import mock_httpd +from mapproxy.test.system import SysTest +from mapproxy.util.times import timestamp_from_isodate + +@pytest.fixture(scope="module") +def config_file(): + return "tileservice_refresh.yaml" + + +class TestRefresh(SysTest): + + def test_refresh_tile_1s(self, app, cache_dir): + with tmp_image((256, 256), format="jpeg") as img: + expected_req = ( + { + "path": r"/service?LAYERs=bar&SERVICE=WMS&FORMAT=image%2Fjpeg" + "&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles=" + "&VERSION=1.1.1&BBOX=-20037508.3428,-20037508.3428,0.0,0.0" + "&WIDTH=256" + }, + {"body": img.read(), "headers": {"content-type": "image/jpeg"}}, + ) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + file_path = cache_dir.join( + "wms_cache_EPSG900913/01/000/000/000/000/000/000.jpeg" + ) + assert file_path.check() + t1 = file_path.mtime() + # file_path.remove() + # assert not file_path.check() + resp = app.get("/tiles/wms_cache/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + assert file_path.check() + t2 = file_path.mtime() + # tile is expired after 1 sec, so it will be fetched again from mock server + time.sleep(1.2) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + assert file_path.check() + t3 = file_path.mtime() + assert t2 == t1 + assert t3 > t2 + + def test_refresh_tile_mtime(self, app, cache_dir): + with tmp_image((256, 256), format="jpeg") as img: + expected_req = ( + { + "path": r"/service?LAYERs=bar&SERVICE=WMS&FORMAT=image%2Fjpeg" + "&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles=" + "&VERSION=1.1.1&BBOX=-20037508.3428,-20037508.3428,0.0,0.0" + "&WIDTH=256" + }, + {"body": img.read(), "headers": {"content-type": "image/jpeg"}}, + ) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache_isotime/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + file_path = cache_dir.join( + "wms_cache_isotime_EPSG900913/01/000/000/000/000/000/000.jpeg" + ) + assert file_path.check() + timestamp = timestamp_from_isodate("2009-02-15T23:31:30") + file_path.setmtime(timestamp + 1.2) + t1 = file_path.mtime() + resp = app.get("/tiles/wms_cache_isotime/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + t2 = file_path.mtime() + file_path.setmtime(timestamp - 1.2) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache_isotime/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + assert file_path.check() + t3 = file_path.mtime() + assert t2 == t1 + assert t3 > t2 + + def test_refresh_tile_source_error_no_stale(self, app, cache_dir): + source_request = { + "path": r"/service?LAYERs=bar&SERVICE=WMS&FORMAT=image%2Fpng" + "&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles=" + "&VERSION=1.1.1&BBOX=-20037508.3428,-20037508.3428,0.0,0.0" + "&WIDTH=256" + } + with tmp_image((256, 256), format="png") as img: + expected_req = ( + source_request, + {"body": img.read(), "headers": {"content-type": "image/png"}}, + ) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache_png/1/0/0.png") + assert resp.content_type == "image/png" + img.seek(0) + assert resp.body == img.read() + resp = app.get("/tiles/wms_cache_png/1/0/0.png") + assert resp.content_type == "image/png" + img.seek(0) + assert resp.body == img.read() + # tile is expired after 1 sec, so it will be requested again from mock server + time.sleep(1.2) + expected_req = ( + source_request, + {"body": "", "status": 404}, + ) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache_png/1/0/0.png") + assert resp.content_type == "image/png" + # error handler for 404 does not authorise stale tiles, so transparent tile will be rendered + resp_img = Image.open(BytesIO(resp.body)) + # check response transparency + assert resp_img.getbands() == ('R', 'G', 'B', 'A') + assert resp_img.getextrema()[3] == (0, 0) + + expected_req = ( + source_request, + {"body": "", "status": 405}, + ) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache_png/1/0/0.png") + assert resp.content_type == "image/png" + # error handler for 405 does not authorise stale tiles, so red tile will be rendered + resp_img = Image.open(BytesIO(resp.body)) + # check response red color + assert resp_img.getbands() == ('R', 'G', 'B') + assert resp_img.getextrema() == ((255, 255), (0, 0), (0, 0)) + + def test_refresh_tile_source_error_stale(self, app, cache_dir): + with tmp_image((256, 256), format="jpeg") as img: + expected_req = ( + { + "path": r"/service?LAYERs=bar&SERVICE=WMS&FORMAT=image%2Fjpeg" + "&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles=" + "&VERSION=1.1.1&BBOX=-20037508.3428,-20037508.3428,0.0,0.0" + "&WIDTH=256" + }, + {"body": img.read(), "headers": {"content-type": "image/jpeg"}}, + ) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + img.seek(0) + assert resp.body == img.read() + resp = app.get("/tiles/wms_cache/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + img.seek(0) + assert resp.body == img.read() + # tile is expired after 1 sec, so it will be fetched again from mock server + time.sleep(1.2) + expected_req = ( + { + "path": r"/service?LAYERs=bar&SERVICE=WMS&FORMAT=image%2Fjpeg" + "&REQUEST=GetMap&HEIGHT=256&SRS=EPSG%3A900913&styles=" + "&VERSION=1.1.1&BBOX=-20037508.3428,-20037508.3428,0.0,0.0" + "&WIDTH=256" + }, + {"body": "", "status": 406}, + ) + with mock_httpd( + ("localhost", 42423), [expected_req], bbox_aware_query_comparator=True + ): + resp = app.get("/tiles/wms_cache/1/0/0.jpeg") + assert resp.content_type == "image/jpeg" + # Check that initial non empty img is served as a stale tile + img.seek(0) + assert resp.body == img.read() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/test/system/test_response_headers.py new/MapProxy-1.14.0/mapproxy/test/system/test_response_headers.py --- old/MapProxy-1.13.2/mapproxy/test/system/test_response_headers.py 1970-01-01 01:00:00.000000000 +0100 +++ new/MapProxy-1.14.0/mapproxy/test/system/test_response_headers.py 2021-11-24 14:26:54.000000000 +0100 @@ -0,0 +1,54 @@ +# This file is part of the MapProxy project. +# Copyright (C) 2011 Omniscale <http://omniscale.de> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import division + +import pytest + +from mapproxy.test.system import SysTest + + +class TestResponseHeaders(SysTest): + """ + Check if the vary header is set for text / xml content like capabilities + """ + @pytest.fixture(scope='class') + def config_file(self): + return 'auth.yaml' + + def test_tms(self, app): + resp = app.get('http://localhost/tms') + assert resp.vary == ('X-Script-Name', 'X-Forwarded-Host', 'X-Forwarded-Proto') + + def test_wms(self, app): + resp = app.get('http://localhost/service?SERVICE=WMS&REQUEST=GetCapabilities' + '&VERSION=1.1.0') + assert resp.vary == ('X-Script-Name', 'X-Forwarded-Host', 'X-Forwarded-Proto') + + def test_wmts(self, app): + resp = app.get('http://localhost/service?SERVICE=WMTS&REQUEST=GetCapabilities') + assert resp.vary == ('X-Script-Name', 'X-Forwarded-Host', 'X-Forwarded-Proto') + + def test_restful_wmts(self, app): + resp = app.get('http://localhost/wmts/1.0.0/WMTSCapabilities.xml') + assert resp.vary == ('X-Script-Name', 'X-Forwarded-Host', 'X-Forwarded-Proto') + + def test_no_endpoint(self, app): + resp = app.get('http://localhost/service?') + assert resp.vary == ('X-Script-Name', 'X-Forwarded-Host', 'X-Forwarded-Proto') + + def test_image_response(self, app): + resp = app.get('http://localhost/tms/1.0.0/layer1a/EPSG900913/0/0/0.png') + assert resp.vary == None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/test/system/test_seed.py new/MapProxy-1.14.0/mapproxy/test/system/test_seed.py --- old/MapProxy-1.13.2/mapproxy/test/system/test_seed.py 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/test/system/test_seed.py 2021-11-23 16:34:09.000000000 +0100 @@ -86,11 +86,42 @@ {'body': img_data, 'headers': {'content-type': 'image/png'}}) with mock_httpd(('localhost', 42423), [expected_req]): with local_base_config(self.mapproxy_conf.base_config): - seed_conf = load_seed_tasks_conf(self.seed_conf_file, self.mapproxy_conf) + seed_conf = load_seed_tasks_conf(self.seed_conf_file, self.mapproxy_conf) tasks, cleanup_tasks = seed_conf.seeds(['one']), seed_conf.cleanups() seed(tasks, dry_run=False) cleanup(cleanup_tasks, verbose=False, dry_run=False) + def test_seed_skip_uncached(self): + with tmp_image((256, 256), format='png') as img: + img_data = img.read() + with local_base_config(self.mapproxy_conf.base_config): + expected_req = ({'path': r'/service?LAYERS=foo&SERVICE=WMS&FORMAT=image%2Fpng' + '&REQUEST=GetMap&VERSION=1.1.1&bbox=-180.0,-90.0,180.0,90.0' + '&width=256&height=128&srs=EPSG:4326'}, + {'body': img_data, 'headers': {'content-type': 'image/png'}}) + seed_conf = load_seed_tasks_conf(self.seed_conf_file, self.mapproxy_conf) + tasks, cleanup_tasks = seed_conf.seeds(['one']), seed_conf.cleanups() + + # tile not in cache => skipped by seeder + seed(tasks, dry_run=False, skip_uncached=True) + assert not self.tile_exists((0, 0, 0)) + + with mock_httpd(('localhost', 42423), [expected_req]): + # force tile generation in cache (via skip_uncached=False) + seed(tasks, dry_run=False, skip_uncached=False) + assert self.tile_exists((0, 0, 0)) + + # no refresh since tile is not older than 1 day (cf. config seed.yaml) + seed(tasks, dry_run=False, skip_uncached=True) + + # create stale tile (older than 1 day) + self.make_tile((0, 0, 0), timestamp=time.time() - (60*60*25)) + with mock_httpd(('localhost', 42423), [expected_req]): + # check that old tile in cache is refreshed + seed(tasks, dry_run=False, skip_uncached=True) + assert self.tile_exists((0, 0, 0)) + cleanup(cleanup_tasks, verbose=False, dry_run=False) + def test_reseed_uptodate(self): # tile already there. self.make_tile((0, 0, 0)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/mapproxy/util/times.py new/MapProxy-1.14.0/mapproxy/util/times.py --- old/MapProxy-1.13.2/mapproxy/util/times.py 2020-05-27 13:37:56.000000000 +0200 +++ new/MapProxy-1.14.0/mapproxy/util/times.py 2021-11-23 16:34:09.000000000 +0100 @@ -72,4 +72,4 @@ date = isodate else: date = datetime.datetime.strptime(isodate, "%Y-%m-%dT%H:%M:%S") - return mktime(date.timetuple()) \ No newline at end of file + return mktime(date.timetuple()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/requirements-tests.txt new/MapProxy-1.14.0/requirements-tests.txt --- old/MapProxy-1.13.2/requirements-tests.txt 2021-05-21 10:47:33.000000000 +0200 +++ new/MapProxy-1.14.0/requirements-tests.txt 2021-11-23 15:59:05.000000000 +0100 @@ -1,8 +1,8 @@ -Jinja2==2.11.2 +Jinja2==2.11.3 MarkupSafe==1.1.1 Pillow==6.2.2;python_version<"3.0" -Pillow==7.2.0;python_version>="3.0" -PyYAML==5.3.1 +Pillow==8.2.0;python_version>="3.0" +PyYAML==5.4 Shapely==1.7.0 WebOb==1.8.6 WebTest==2.0.35 @@ -17,7 +17,7 @@ cffi==1.14.2 cfn-lint==0.35.0 chardet==3.0.4 -cryptography==3.0 +cryptography==3.3.2 decorator==4.4.2 docker==4.3.0 docutils==0.15.2 @@ -33,7 +33,7 @@ jsonpointer==2.0 jsonschema==3.2.0 junit-xml==1.9 -lxml==4.5.2 +lxml==4.6.3 mock==3.0.5;python_version<"3.6" mock==4.0.2;python_version>="3.6" more-itertools==5.0.0;python_version<"3.0" @@ -43,7 +43,7 @@ networkx==2.4;python_version>="3.0" packaging==20.4 pluggy==0.13.1 -py==1.9.0 +py==1.10.0 pyasn1==0.4.8 pycparser==2.20 pyparsing==2.2.2;python_version<"3.0" @@ -61,7 +61,7 @@ responses==0.10.16 riak==2.7.0 rsa==4.5;python_version<"3.0" -rsa==4.6;python_version>="3.0" +rsa==4.7;python_version>="3.0" s3transfer==0.3.3 six==1.15.0 soupsieve==1.9.6;python_version<"3.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/MapProxy-1.13.2/setup.py new/MapProxy-1.14.0/setup.py --- old/MapProxy-1.13.2/setup.py 2021-07-14 16:07:51.000000000 +0200 +++ new/MapProxy-1.14.0/setup.py 2021-11-24 14:19:37.000000000 +0100 @@ -21,11 +21,11 @@ # depend on PIL if it is installed, otherwise # require Pillow if package_installed('Pillow'): - install_requires.append('Pillow !=2.4.0') + install_requires.append('Pillow !=2.4.0,!=8.3.0,!=8.3.1') elif package_installed('PIL'): install_requires.append('PIL>=1.1.6,<1.2.99') else: - install_requires.append('Pillow !=2.4.0') + install_requires.append('Pillow !=2.4.0,!=8.3.0,!=8.3.1') if platform.python_version_tuple() < ('2', '6'): # for mapproxy-seed @@ -54,7 +54,7 @@ setup( name='MapProxy', - version="1.13.2", + version="1.14.0", description='An accelerating proxy for tile and web map services', long_description=long_description(7), author='Oliver Tonnhofer',