[Git][debian-gis-team/mapproxy][master] 6 commits: New upstream version 7.0.0+dfsg

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Fri Jul 17 14:22:45 BST 2026



Bas Couwenberg pushed to branch master at Debian GIS Project / mapproxy


Commits:
4fe6e8e9 by Bas Couwenberg at 2026-07-17T15:15:19+02:00
New upstream version 7.0.0+dfsg
- - - - -
d2f13916 by Bas Couwenberg at 2026-07-17T15:15:24+02:00
Update upstream source from tag 'upstream/7.0.0+dfsg'

Update to upstream version '7.0.0+dfsg'
with Debian dir a6d0eadeed35d6fc685b27f65da362b32efd4e78
- - - - -
d3bd6b39 by Bas Couwenberg at 2026-07-17T15:15:36+02:00
New upstream release.

- - - - -
9b4d4659 by Bas Couwenberg at 2026-07-17T15:17:34+02:00
Add python3-multiprocess to build dependencies.

- - - - -
ea7f149d by Bas Couwenberg at 2026-07-17T15:17:56+02:00
Refresh patches.

- - - - -
a3c6623d by Bas Couwenberg at 2026-07-17T15:18:07+02:00
Set distribution to unstable.

- - - - -


26 changed files:

- .github/workflows/docker-update.yml
- .github/workflows/dockerbuild.yml
- .github/workflows/ghpages.yml
- .github/workflows/release.yml
- .github/workflows/test.yml
- .python-version
- CHANGES.txt
- Dockerfile
- Dockerfile-alpine
- debian/changelog
- debian/control
- debian/patches/xfail.patch
- doc/install_docker.rst
- docker/run-nginx.sh
- docker/uwsgi.conf
- mapproxy/cache/path.py
- mapproxy/image/__init__.py
- mapproxy/seed/seeder.py
- mapproxy/source/mapnik.py
- mapproxy/test/unit/test_cache.py
- mapproxy/test/unit/test_file_lock_load.py
- mapproxy/test/unit/test_image.py
- mapproxy/test/unit/test_seed_cachelock.py
- mapproxy/test/unit/test_utils.py
- requirements-tests.txt
- setup.py


Changes:

=====================================
.github/workflows/docker-update.yml
=====================================
@@ -22,7 +22,7 @@ jobs:
 
     steps:
       - name: Checkout code
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
         with:
           fetch-depth: 0
 
@@ -82,7 +82,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout code
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
         with:
           fetch-depth: 0
 


=====================================
.github/workflows/dockerbuild.yml
=====================================
@@ -15,7 +15,7 @@ jobs:
       version: ${{ fromJSON(steps.meta.outputs.json).tags[0] }}
     steps:
       - name: Checkout
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
 
       - name: Docker meta
         id: meta
@@ -33,7 +33,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
 
       - name: Set up QEMU
         uses: docker/setup-qemu-action at v4
@@ -80,7 +80,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
 
       - name: Set up QEMU
         uses: docker/setup-qemu-action at v4


=====================================
.github/workflows/ghpages.yml
=====================================
@@ -14,7 +14,7 @@ jobs:
 
     steps:
     - name: Checkout sources
-      uses: actions/checkout at v6
+      uses: actions/checkout at v7
 
     - name: Install dependencies ⏬
       run: pip install sphinx sphinx-book-theme sphinx-copybutton


=====================================
.github/workflows/release.yml
=====================================
@@ -21,7 +21,7 @@ jobs:
           sudo apt -y install --no-install-recommends python3-pil python3-yaml python3-pyproj libgeos-dev python3-lxml libgdal-dev python3-shapely libxml2-dev libxslt-dev
 
       - name: Checkout
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
 
       - name: Setup python
         uses: actions/setup-python at v6


=====================================
.github/workflows/test.yml
=====================================
@@ -34,7 +34,7 @@ jobs:
 
     strategy:
       matrix:
-        python-version: ["3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
         pillow-version: ["12.1.0"]
         include:
           - python-version: "3.10"
@@ -55,7 +55,7 @@ jobs:
         sudo apt install proj-bin libgeos-dev libgdal-dev libxslt-dev libxml2-dev build-essential libjpeg-dev zlib1g-dev libfreetype6-dev protobuf-compiler libprotoc-dev -y
 
     - name: Checkout sources
-      uses: actions/checkout at v6
+      uses: actions/checkout at v7
 
     - name: Use python ${{ matrix.python-version }}
       uses: actions/setup-python at v6
@@ -106,7 +106,7 @@ jobs:
           sudo apt install proj-bin libgeos-dev libgdal-dev libxslt-dev libxml2-dev build-essential libjpeg-dev zlib1g-dev libfreetype6-dev protobuf-compiler libprotoc-dev -y
 
       - name: Checkout sources
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
 
       - name: Use python ${{ matrix.python-version }}
         uses: actions/setup-python at v6
@@ -144,7 +144,7 @@ jobs:
 
     steps:
     - name: Checkout sources
-      uses: actions/checkout at v6
+      uses: actions/checkout at v7
 
     - name: Install doc dependencies ⏬
       run: pip install sphinx sphinx-book-theme sphinx-copybutton
@@ -157,12 +157,12 @@ jobs:
 
     steps:
       - name: Checkout sources
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
 
-      - name: Use python 3.12
+      - name: Use python 3.14
         uses: actions/setup-python at v6
         with:
-          python-version: 3.12
+          python-version: 3.14
 
       - name: Install requirements
         run: |
@@ -177,12 +177,12 @@ jobs:
 
     steps:
       - name: Checkout sources
-        uses: actions/checkout at v6
+        uses: actions/checkout at v7
 
-      - name: Use python 3.12
+      - name: Use python 3.14
         uses: actions/setup-python at v6
         with:
-          python-version: 3.12
+          python-version: 3.14
 
       - name: Install requirements
         run: |


=====================================
.python-version
=====================================
@@ -1 +1 @@
-3.12
+3.14


=====================================
CHANGES.txt
=====================================
@@ -1,3 +1,21 @@
+7.0.0 2026-07-17
+~~~~~~~~~~~~~~~~
+
+Breaking:
+
+  - Security Fix: Avoiding path traversals in dimensions parameter.
+    In rare cases, existing cache directories will not be reused and created newly with safe directory names
+
+Maintenance:
+
+  - Raising python version in workflows and docker images to 3.14
+  - Update dependencies
+
+Fixes:
+
+  - Error with transparent PNGs in mixed format
+
+
 6.1.1 2026-06-17
 ~~~~~~~~~~~~~~~~
 


=====================================
Dockerfile
=====================================
@@ -1,4 +1,4 @@
-FROM python:3.12-slim-bookworm AS base-libs
+FROM python:3.14-slim-bookworm AS base-libs
 
 LABEL maintainer="mapproxy.org"
 


=====================================
Dockerfile-alpine
=====================================
@@ -1,4 +1,4 @@
-FROM python:3.12-alpine AS base-libs
+FROM python:3.14-alpine AS base-libs
 
 LABEL maintainer="mapproxy.org"
 


=====================================
debian/changelog
=====================================
@@ -1,3 +1,11 @@
+mapproxy (7.0.0+dfsg-1) unstable; urgency=medium
+
+  * New upstream release.
+  * Add python3-multiprocess to build dependencies.
+  * Refresh patches.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Fri, 17 Jul 2026 15:17:57 +0200
+
 mapproxy (6.1.1+dfsg-1) unstable; urgency=medium
 
   * New upstream release.


=====================================
debian/control
=====================================
@@ -13,6 +13,7 @@ Build-Depends: debhelper-compat (= 13),
                python3-jinja2,
                python3-jsonschema,
                python3-lxml,
+               python3-multiprocess,
                python3-pil,
                python3-pyproj,
                python3-pytest <!nocheck>,


=====================================
debian/patches/xfail.patch
=====================================
@@ -56,7 +56,7 @@ Forwarded: not-needed
          with tmp_image((256, 256), format="jpeg") as img:
 --- a/mapproxy/test/unit/test_cache.py
 +++ b/mapproxy/test/unit/test_cache.py
-@@ -881,6 +881,7 @@ class TestWMSSourceTransform(object):
+@@ -882,6 +882,7 @@ class TestWMSSourceTransform(object):
                              "&format=image%2Fpng&styles=&srs=EPSG%3A4326&request=GetMap&height=450")
  
  
@@ -136,7 +136,7 @@ Forwarded: not-needed
      date = parsedate(date)
 --- a/mapproxy/test/unit/test_image.py
 +++ b/mapproxy/test/unit/test_image.py
-@@ -355,6 +355,7 @@ class TestMergeAll(object):
+@@ -387,6 +387,7 @@ class TestMergeAll(object):
          assert img.size == (300, 300)
          assert img.getcolors() == [(80000, (255, 255, 255)), (10000, (0, 0, 0))]
  
@@ -144,7 +144,7 @@ Forwarded: not-needed
      def test_invalid_tile(self):
          self.cleanup_tiles = [create_tmp_image_file((100, 100)) for _ in range(9)]
          self.tiles = [ImageResult(tile) for tile in self.cleanup_tiles]
-@@ -789,6 +790,7 @@ class TestMakeTransparent(object):
+@@ -821,6 +822,7 @@ class TestMakeTransparent(object):
          colors = img.getcolors()
          assert colors == [(1600, (130, 140, 120, 255)), (900, (130, 150, 120, 0))]
  


=====================================
doc/install_docker.rst
=====================================
@@ -88,6 +88,8 @@ Environment Variables
   mode and will run all configurations in the ``/mapproxy/config/apps`` directory as different apps. Default is ``false``.
 - ``MULTIAPP_ALLOW_LISTINGS``: In multi app mode if set to ``true``, MapProxy lists all available apps on the root page.
   Default is ``false``.
+- ``UWSGI_PROCESSES``: **nginx images only.** Number of uWSGI worker processes. Default is ``2``.
+- ``UWSGI_THREADS``: **nginx images only.** Number of threads per uWSGI worker process. Default is ``10``.
 
 
 Build your own image


=====================================
docker/run-nginx.sh
=====================================
@@ -6,6 +6,10 @@
 done=0
 trap 'done=1' TERM INT
 
+# uwsgi.conf reads these via $(VAR) expansion, so they must be exported
+export UWSGI_PROCESSES="${UWSGI_PROCESSES:-2}"
+export UWSGI_THREADS="${UWSGI_THREADS:-10}"
+
 UWSGI_ADD_OPTIONS=""
 if [ -n "$MAPPROXY_ALPINE" ]; then
   UWSGI_ADD_OPTIONS="--plugin python3"


=====================================
docker/uwsgi.conf
=====================================
@@ -5,8 +5,8 @@ pyargv = /mapproxy/config/mapproxy.yaml
 wsgi-file = /mapproxy/app.py
 pidfile = /tmp/mapproxy.pid
 socket = 0.0.0.0:8080
-processes = 2
-threads = 10
+processes = $(UWSGI_PROCESSES)
+threads = $(UWSGI_THREADS)
 chmod-socket = 777
 uid = mapproxy
 gid = mapproxy


=====================================
mapproxy/cache/path.py
=====================================
@@ -61,6 +61,14 @@ def dimensions_part(dimensions):
 
     """
     if dimensions:
+        def checkTraversal(v):
+            normalized = os.path.normpath(v)
+            parts = normalized.split('/') + normalized.split('\\')
+            isNormalized = v != normalized or any(part == ".." for part in parts)
+            if isNormalized:
+                raise ValueError('Dimension parameter value contains illegal characters')
+        for k, v in dimensions.items():
+            checkTraversal(v)
         dims = NoCaseMultiDict(dimensions)
         predefined_dims, custom_dims = [], []
         for dim in dims.keys():


=====================================
mapproxy/image/__init__.py
=====================================
@@ -349,12 +349,12 @@ class ReadBufWrapper(object):
 
 def img_has_transparency(img: Image.Image) -> bool:
     if img.mode == 'P':
-        if img.info.get('transparency', False):
-            return True
-        # convert to RGBA and check alpha channel
+        # Convert to RGBA and check the actual alpha channel instead of
+        # relying on img.info['transparency'], which may reference a color
+        # that does not actually appear in the image.
         img = img.convert('RGBA')
     if img.mode == 'RGBA':
-        # any alpha except fully opaque
+        # any alpha except fully opaque (alpha < 255)
         return any(img.histogram()[-256:-1])
     return False
 
@@ -423,6 +423,10 @@ def img_to_buf(img: Image.Image, image_opts, georef=None) -> BytesIO:
     if image_opts.mode is not None and img.mode != image_opts.mode:
         img = img.convert(image_opts.mode)
 
+    # JPEG must always be RGB
+    if format == 'jpeg' and img.mode != 'RGB':
+        img = img.convert('RGB')
+
     img.save(buf, format, **defaults)
     buf.seek(0)
     return buf


=====================================
mapproxy/seed/seeder.py
=====================================
@@ -52,9 +52,10 @@ if sys.platform == 'win32' or sys.platform == 'darwin':
     proc_class = threading.Thread
     queue_class = queue.Queue
 else:
-    import multiprocessing
-    proc_class = multiprocessing.Process
-    queue_class = multiprocessing.Queue
+    import multiprocess
+    from multiprocess import Process
+    proc_class: type[Process] = multiprocess.Process
+    queue_class = multiprocess.Queue
 
 
 class TileWorkerPool(object):


=====================================
mapproxy/source/mapnik.py
=====================================
@@ -19,7 +19,7 @@ import logging
 import sys
 import time
 import threading
-import multiprocessing
+import multiprocess
 from io import BytesIO
 from typing import Optional
 
@@ -149,7 +149,7 @@ class MapnikSource(MapLayer):
         if not self.multithreaded:
             return self._create_map_obj(mapfile, None)
 
-        process_id = multiprocessing.current_process()._identity
+        process_id = multiprocess.current_process()._identity
         queue_cachekey = (process_id, mapfile)
         if queue_cachekey in _map_objs_queues:
             try:
@@ -163,7 +163,7 @@ class MapnikSource(MapLayer):
         return self._create_map_obj(mapfile, process_id)
 
     def _put_unused_map_obj(self, mapfile, m):
-        process_id = multiprocessing.current_process()._identity
+        process_id = multiprocess.current_process()._identity
         queue_cachekey = (process_id, mapfile)
         if queue_cachekey not in _map_objs_queues:
             _map_objs_queues[queue_cachekey] = Queue(MAX_UNUSED_MAPS)
@@ -179,14 +179,14 @@ class MapnikSource(MapLayer):
             # all MapnikSources with the same mapfile share the same Mapnik Map.
             return (None, None, mapfile)
         thread_id = threading.current_thread().ident
-        process_id = multiprocessing.current_process()._identity
+        process_id = multiprocess.current_process()._identity
         return (process_id, thread_id, mapfile)
 
     def _cleanup_unused_cached_maps(self, mapfile):
         if not self.multithreaded:
             return
         # clean up no longer used cached maps
-        process_id = multiprocessing.current_process()._identity
+        process_id = multiprocess.current_process()._identity
         process_cache_keys = [k for k in self._map_cache().keys()
                               if k[0] == process_id]
         # To avoid time-consuming cleanup whenever one thread in the


=====================================
mapproxy/test/unit/test_cache.py
=====================================
@@ -30,6 +30,7 @@ import pytest
 
 from mapproxy.cache.base import TileLocker
 from mapproxy.cache.file import FileCache
+from mapproxy.cache.path import dimensions_part
 from mapproxy.cache.tile import Tile
 from mapproxy.cache.tile_manager import TileManager
 from mapproxy.client.http import HTTPClient
@@ -1404,3 +1405,32 @@ class TestTileManagerCacheGeojsonCoverage(TileCacheTestBase):
 
         assert self.cache.stored_tiles == set([])
         assert self.cache.loaded_tiles == counting_set([None for _ in coords])
+
+
+class TestDimensionsPart(TileCacheTestBase):
+
+    def test_dimensions_part_sanitized(self):
+
+        with pytest.raises(ValueError):
+            dimensions_part({"forwardparam": "../"})
+
+        with pytest.raises(ValueError):
+            dimensions_part({"forwardparam": "time/../.."})
+
+        with pytest.raises(ValueError):
+            dimensions_part({"forwardparam": "check/../test"})
+
+        with pytest.raises(ValueError):
+            dimensions_part({"forwardparam": "check\\..\\windoze"})
+
+        retVal = dimensions_part({"forwardparam": "1234-5678"})
+        assert retVal == "forwardparam-1234-5678"
+
+        retVal = dimensions_part({"forwardparam": "2004-10-12T13:55:20Z"})
+        assert retVal == "forwardparam-2004-10-12T13:55:20Z"
+
+        retVal = dimensions_part({"forwardparam": "2020-09-22T11:20:00Z/2020-09-22T14:20:00Z/PT2H"})
+        assert retVal == "forwardparam-2020-09-22T11:20:00Z/2020-09-22T14:20:00Z/PT2H"
+
+        retVal = dimensions_part({"forwardparam": r",;.:-_#'+*~´`?ß=})]([/{}])&%$§!^"})
+        assert retVal == "forwardparam-,;.:-_#'+*~´`?ß=})]([/{}])&%$§!^"


=====================================
mapproxy/test/unit/test_file_lock_load.py
=====================================
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import multiprocessing
+import multiprocess
 import threading
 import time
 
@@ -40,7 +40,7 @@ def test_file_lock_load(tmpdir):
             time.sleep(0.01)
             lock((lock_file, count_file))
     threads = [threading.Thread(target=lock_x) for _ in range(20)]
-    p = multiprocessing.Pool(5)
+    p = multiprocess.Pool(5)
     [t.start() for t in threads]
     p.map(lock, [(lock_file, count_file) for _ in range(50)])
     [t.join() for t in threads]


=====================================
mapproxy/test/unit/test_image.py
=====================================
@@ -219,6 +219,38 @@ class TestImageResult(object):
             "Expected RGBA PNG when mode=RGBA requested, got %s" % result.mode
         )
 
+    def test_rgba_source_image_stored_as_jpeg(self):
+        """
+        Regression test: RGBA PNG from transparent WMS source (e.g. basemapde)
+        must not raise OSError when stored to a JPEG cache.
+        The mode=RGBA from image_opts must not override the JPEG-required RGB conversion.
+        """
+        # Simulate what a WMS with transparent=True & format=image/png returns
+        rgba_img = Image.new("RGBA", (256, 256), (100, 150, 200, 255))
+        source_opts = ImageOptions(format="image/png", transparent=True, mode="RGBA")
+        ir = ImageResult(rgba_img, image_opts=source_opts)
+
+        # Cache is configured as JPEG – mode=RGBA must not override the JPEG conversion
+        jpeg_opts = ImageOptions(format="image/jpeg", mode="RGBA")
+        buf = ir.as_buffer(jpeg_opts)
+        assert is_jpeg(buf), "Expected JPEG output when saving RGBA image with JPEG cache opts"
+
+    def test_rgba_image_to_jpeg_via_img_to_buf(self):
+        """
+        img_to_buf must not raise 'cannot write mode RGBA as JPEG'
+        when image_opts.mode='RGBA' and format='jpeg'.
+        """
+        from mapproxy.image import img_to_buf
+
+        rgba_img = Image.new("RGBA", (256, 256), (100, 150, 200, 128))
+        # The critical case: mode=RGBA but format=jpeg
+        opts = ImageOptions(format="image/jpeg", mode="RGBA", transparent=True)
+
+        # Must not raise OSError
+        buf = img_to_buf(rgba_img, image_opts=opts)
+        result = Image.open(buf)
+        assert result.mode == "RGB", "JPEG output must be RGB, not RGBA"
+
 
 class TestSubImageResult(object):
 
@@ -1095,3 +1127,43 @@ class TestBandMerge(object):
         img = result.as_image()
         assert img.mode == "RGBA"
         assert img.getpixel((0, 0)) == (200, 100, 0, 255)
+
+
+class TestImgHasTransparency(object):
+    """Tests for img_has_transparency"""
+
+    def test_rgb_opaque(self):
+        img = Image.new("RGB", (10, 10), (255, 0, 0))
+        assert not img_has_transparency(img)
+
+    def test_rgba_fully_opaque(self):
+        img = Image.new("RGBA", (10, 10), (255, 0, 0, 255))
+        assert not img_has_transparency(img)
+
+    def test_rgba_with_transparency(self):
+        img = Image.new("RGBA", (10, 10), (255, 0, 0, 255))
+        img.paste((255, 0, 0, 0), (3, 3, 7, 7))
+        assert img_has_transparency(img)
+
+    def test_p_with_transparency_info_but_color_not_used(self):
+        """
+        Regression: P-mode image with transparency info entry, but the
+        transparent color does not appear in the image at all.
+        img_has_transparency should return False, not True.
+        """
+        img = Image.new("RGB", (10, 10), (255, 0, 0)).quantize(256)
+        assert img.mode == "P"
+        pixels = list(img.getdata())
+        assert 1 not in pixels, "palette index 1 must not appear in image for this test to be valid"
+        img.info["transparency"] = 1
+        assert not img_has_transparency(img)
+
+    def test_p_with_actual_transparency(self):
+        """
+        P-mode image where the transparent color actually appears in the image.
+        """
+        img = Image.new("RGBA", (10, 10), (255, 0, 0, 255))
+        img.paste((255, 0, 0, 0), (3, 3, 7, 7))
+        img_p = img.quantize(256)
+        assert img.mode != "P" or img_has_transparency(img_p)
+        assert img_has_transparency(img_p)


=====================================
mapproxy/test/unit/test_seed_cachelock.py
=====================================
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import multiprocessing
+import multiprocess
 import time
 import sys
 
@@ -36,7 +36,7 @@ class TestCacheLock(object):
             assert True
 
     def test_locked_by_process_no_block(self, lock_file):
-        ctx = multiprocessing.get_context('fork')
+        ctx = multiprocess.get_context('fork')
 
         proc_is_locked = ctx.Event()
 
@@ -68,7 +68,7 @@ class TestCacheLock(object):
             p.join()
 
     def test_locked_by_process_waiting(self, lock_file):
-        ctx = multiprocessing.get_context('fork')
+        ctx = multiprocess.get_context('fork')
 
         proc_is_locked = ctx.Event()
 


=====================================
mapproxy/test/unit/test_utils.py
=====================================
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 import glob
-import multiprocessing
+import multiprocess
 import os
 import random
 import shutil
@@ -497,7 +497,7 @@ class TestWriteAtomic(object):
         num_writes = 800
         concurrent_writes = 8
 
-        p = multiprocessing.Pool(concurrent_writes)
+        p = multiprocess.Pool(concurrent_writes)
         p.map(_write_atomic_data, ((i, filename) for i in range(num_writes)))
         p.close()
         p.join()


=====================================
requirements-tests.txt
=====================================
@@ -3,14 +3,14 @@ aws-sam-translator==1.91.0
 aws-xray-sdk==2.12.1
 azure-storage-blob==12.27.1
 beautifulsoup4==4.14.3
-boto3==1.40.55
-botocore==1.40.55
-certifi==2025.4.26
+boto3==1.43.50
+botocore==1.43.50
+certifi==2026.6.17
 cffi==2.0.0
 cfn-lint==0.80.3
 chardet==5.2.0
 coverage==7.11.3
-cryptography==46.0.7
+cryptography==49.0.0
 decorator==5.2.1
 docker==7.1.0
 docutils==0.22.4
@@ -18,7 +18,7 @@ ecdsa==0.18.0
 flake8==7.0.0
 flake8-toml-config==1.0.0
 idna==2.9
-iniconfig==2.0.0
+iniconfig==2.3.0
 Jinja2==2.11.3
 jmespath==1.0.1
 jsondiff==1.3.1
@@ -33,6 +33,7 @@ MarkupSafe==1.1.1
 mock==5.1.0
 more-itertools==10.1.0
 moto==5.0.13
+multiprocess==0.70.19
 mypy==1.18.2
 networkx==3.4.2
 numpy==1.26.4
@@ -43,30 +44,31 @@ py==1.11.0
 pyasn1==0.6.3
 pycparser==2.22
 pyparsing==3.3.2
-pyproj==3.7.1
+pyproj==3.7.1;python_version<"3.14"
+pyproj==3.7.2;python_version>"3.13"
 pyrsistent==0.20.0
 pytest-rerunfailures==16.0.1
 pytest==9.0.3
 python-dateutil==2.9.0.post0
 python-jose==3.5.0
 pytz==2024.2
-redis==5.0.1
+redis==8.0.0
 requests==2.33.0
 responses==0.25.8
 rsa==4.9.1
-Shapely==2.1.0
-soupsieve==2.8
+Shapely==2.1.2
+soupsieve==2.8.4
 sshpubkeys==3.3.1
 toml==0.10.2
 types-PyYAML==6.0.12
 types-requests==2.32.4.20250913
-types-shapely==2.1.0.20250917
+types-shapely==2.1.0.20260630
 types-jsonschema==4.25.1.20251009
 types-python-dateutil==2.9.0.20251008
 types-pytz==2025.2.0.20250809
 urllib3==2.5.0
 waitress==3.0.2
-WebOb==1.8.9
+WebOb==1.8.10
 websocket-client==1.8.0
 WebTest==3.0.0
 wrapt==1.17.2


=====================================
setup.py
=====================================
@@ -16,7 +16,8 @@ install_requires = [
     'jinja2',
     'Babel',  # For jinja2
     'python-dateutil',  # For jinja2
-    'requests'
+    'requests',
+    'multiprocess'
 ]
 
 
@@ -44,7 +45,7 @@ def long_description(changelog_releases=10):
 
 setup(
     name='MapProxy',
-    version="6.1.1",
+    version="7.0.0",
     description='An accelerating proxy for tile and web map services',
     long_description=long_description(7),
     long_description_content_type='text/x-rst',
@@ -73,6 +74,7 @@ setup(
         "Programming Language :: Python :: 3.11",
         "Programming Language :: Python :: 3.12",
         "Programming Language :: Python :: 3.13",
+        "Programming Language :: Python :: 3.14",
         "Topic :: Internet :: Proxy Servers",
         "Topic :: Internet :: WWW/HTTP :: WSGI",
         "Topic :: Scientific/Engineering :: GIS",



View it on GitLab: https://salsa.debian.org/debian-gis-team/mapproxy/-/compare/da49ea1a8c289b8d58eca953737135942edc62fe...a3c6623d6bdd077a3f35014413de91f10aeab4ef

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapproxy/-/compare/da49ea1a8c289b8d58eca953737135942edc62fe...a3c6623d6bdd077a3f35014413de91f10aeab4ef
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260717/d6d8804b/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list