Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions django/contrib/gis/gdal/raster/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def __init__(self, ds_input, write=False):
)

def __del__(self):
if self.is_vsi_based:
if self._is_vsimem_based:
# Remove the temporary file from the VSI in-memory filesystem.
capi.unlink_vsi_file(force_bytes(self.name))
super().__del__()
Expand Down Expand Up @@ -276,9 +276,7 @@ def _flush(self):

@property
def vsi_buffer(self):
if not (
self.is_vsi_based and self.name.startswith(VSI_MEM_FILESYSTEM_BASE_PATH)
):
if not self._is_vsimem_based:
return None
# Prepare an integer that will contain the buffer length.
out_length = c_int()
Expand All @@ -295,6 +293,10 @@ def vsi_buffer(self):
def is_vsi_based(self):
return self._ptr and self.name.startswith(VSI_FILESYSTEM_PREFIX)

@cached_property
def _is_vsimem_based(self):
return self._ptr and self.name.startswith(VSI_MEM_FILESYSTEM_BASE_PATH)

@property
def name(self):
"""
Expand Down
4 changes: 3 additions & 1 deletion docs/ref/contrib/gis/gdal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1688,7 +1688,7 @@ bands: one for red, one for green, and one for blue.
.. attribute:: vsi_buffer

A ``bytes`` representation of this raster. Returns ``None`` for rasters
that are not stored in GDAL's virtual filesystem.
that are not stored in GDAL's in-memory virtual filesystem.

.. attribute:: is_vsi_based

Expand Down Expand Up @@ -2116,6 +2116,8 @@ can directly access compressed files using the ``/vsizip/``, ``/vsigzip/``, or
>>> rst = GDALRaster("/vsigzip/path/to/your/file.gz")
>>> rst = GDALRaster("/vsitar/path/to/your/file.tar/path/to/raster.tif")

.. _gdal-raster-network:

Network rasters
^^^^^^^^^^^^^^^

Expand Down
3 changes: 1 addition & 2 deletions docs/ref/contrib/gis/install/geolibs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ geospatial libraries:
============================== ==================================== ================================ =========================================================
Program Description Required Supported Versions
============================== ==================================== ================================ =========================================================
:ref:`GEOS <geos-overview>` Geometry Engine Open Source Yes 3.15, 3.14, 3.13, 3.12, 3.11, 3.10
:ref:`GEOS <geos-overview>` Geometry Engine Open Source Yes 3.15, 3.14, 3.13, 3.12, 3.11
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 9.x, 8.x, 7.x, 6.x
:ref:`GDAL <gdal-overview>` Geospatial Data Abstraction Library Yes 3.13, 3.12, 3.11, 3.10, 3.9, 3.8, 3.7, 3.6, 3.5, 3.4, 3.3
:ref:`GeoIP <geoip2-overview>` IP-based geolocation library No 2
Expand All @@ -26,7 +26,6 @@ totally fine with GeoDjango. Your mileage may vary.

..
Libs release dates:
GEOS 3.10.0 2021-10-20
GEOS 3.11.0 2022-07-01
GEOS 3.12.0 2023-06-27
GEOS 3.13.0 2024-09-06
Expand Down
13 changes: 13 additions & 0 deletions docs/releases/5.2.18.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
===========================
Django 5.2.18 release notes
===========================

*Expected October 6, 2026*

Django 5.2.18 fixes one data loss issue in 4.0.

Bugfixes
========

* Fixed a data loss issue in Django 4.0 where :ref:`network rasters
<gdal-raster-network>` were deleted by GeoDjango when closed.
13 changes: 13 additions & 0 deletions docs/releases/6.0.9.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
==========================
Django 6.0.9 release notes
==========================

*Expected October 6, 2026*

Django 6.0.9 fixes one data loss issue in 4.0.

Bugfixes
========

* Fixed a data loss issue in Django 4.0 where :ref:`network rasters
<gdal-raster-network>` were deleted by GeoDjango when closed.
5 changes: 3 additions & 2 deletions docs/releases/6.1.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ Django 6.1.2 release notes

*Expected October 6, 2026*

Django 6.1.2 fixes several bugs in 6.1.1.
Django 6.1.2 fixes one data loss issue in 4.0 and several bugs in 6.1.1.

Bugfixes
========

* ...
* Fixed a data loss issue in Django 4.0 where :ref:`network rasters
<gdal-raster-network>` were deleted by GeoDjango when closed.
2 changes: 2 additions & 0 deletions docs/releases/6.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ backends.
:mod:`django.contrib.gis`
-------------------------

* Support for GEOS 3.10 is removed.

* The seconds value returned by
:meth:`~django.contrib.gis.gdal.Field.as_datetime` is now a ``c_float``
rather than a ``c_int``.
Expand Down
2 changes: 2 additions & 0 deletions docs/releases/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree::
:maxdepth: 1

6.0.9
6.0.8
6.0.7
6.0.6
Expand All @@ -56,6 +57,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree::
:maxdepth: 1

5.2.18
5.2.17
5.2.16
5.2.15
Expand Down
19 changes: 18 additions & 1 deletion tests/gis_tests/gdal_tests/test_raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from django.contrib.gis.gdal import GDAL_VERSION, GDALRaster, SpatialReference
from django.contrib.gis.gdal.error import GDALException
from django.contrib.gis.gdal.prototypes import raster as capi
from django.contrib.gis.gdal.raster.band import GDALBand
from django.contrib.gis.shortcuts import numpy
from django.core.files.temp import NamedTemporaryFile
Expand Down Expand Up @@ -192,7 +193,10 @@ def test_file_based_raster_creation(self):

def test_nonexistent_file(self):
msg = 'Unable to read raster source input "nonexistent.tif".'
with self.assertRaisesMessage(GDALException, msg):
with (
self.assertNoLogs("django.contrib.gis", "ERROR"),
self.assertRaisesMessage(GDALException, msg),
):
GDALRaster("nonexistent.tif")

def test_vsi_raster_creation(self):
Expand Down Expand Up @@ -284,6 +288,19 @@ def test_vsi_vsizip_filesystem(self):
self.assertIs(rst.is_vsi_based, True)
self.assertIsNone(rst.vsi_buffer)

def test_non_vsimem_raster_not_unlinked(self):
"""Closing a non-/vsimem/ raster doesn't unlink its source."""
rst_zipfile = NamedTemporaryFile(suffix=".zip")
self.addCleanup(rst_zipfile.close)
with zipfile.ZipFile(rst_zipfile, mode="w") as zf:
zf.write(self.rs_path, "raster.tif")
rst_path = "/vsizip/" + os.path.join(rst_zipfile.name, "raster.tif")
rst = GDALRaster(rst_path)
self.assertIs(rst._is_vsimem_based, False)
with mock.patch.object(capi, "unlink_vsi_file") as unlink_vsi_file:
del rst
unlink_vsi_file.assert_not_called()

def test_offset_size_and_shape_on_raster_creation(self):
rast = GDALRaster(
{
Expand Down
Loading