Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refs #23804 -- RasterField initialization only if HAS_GDAL #4905

Closed
wants to merge 1 commit into from

Conversation

yellowcap
Copy link
Contributor

The automatic instantiation of GDALRaster instances on field values fails if gdal is not installed.

@claudep
Copy link
Member

claudep commented Jun 22, 2015

I don't mind the definition split. But I'm not so enthusiast about conditionally importing some Field. Past personal experiences have shown that this can lead to surprising or hard-to-debug failures.
What about something like this:

diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py
index 5cdb81e..2affd7f 100644
--- a/django/contrib/gis/db/models/fields.py
+++ b/django/contrib/gis/db/models/fields.py
@@ -1,7 +1,7 @@
 from django.contrib.gis import forms
 from django.contrib.gis.db.models.lookups import gis_lookups
 from django.contrib.gis.db.models.proxy import SpatialProxy
-from django.contrib.gis.gdal.raster.source import GDALRaster
+from django.contrib.gis.gdal import HAS_GDAL
 from django.contrib.gis.geometry.backend import Geometry, GeometryException
 from django.core.exceptions import ImproperlyConfigured
 from django.db.models.expressions import Expression
@@ -426,8 +426,12 @@ class RasterField(BaseSpatialField):

     def contribute_to_class(self, cls, name, **kwargs):
         super(RasterField, self).contribute_to_class(cls, name, **kwargs)
-        # Setup for lazy-instantiated Raster object. For large querysets, the
-        # instantiation of all GDALRasters can potentially be expensive. This
-        # delays the instantiation of the objects to the moment of evaluation
-        # of the raster attribute.
-        setattr(cls, self.attname, SpatialProxy(GDALRaster, self))
+        if HAS_GDAL:
+            from django.contrib.gis.gdal.raster.source import GDALRaster
+            # Setup for lazy-instantiated Raster object. For large querysets, the
+            # instantiation of all GDALRasters can potentially be expensive. This
+            # delays the instantiation of the objects to the moment of evaluation
+            # of the raster attribute.
+            setattr(cls, self.attname, SpatialProxy(GDALRaster, self))
+        else:
+            raise ImproperlyConfigured("RasterField requires GDAL.")

@yellowcap
Copy link
Contributor Author

If conditional imports of fields are a bad idea, then splitting the fields module is not necessary.

So I just updated the pull request with a similar idea based on @claudep 's patch. For the field, GDAL is only required for instantiating the spatial proxy (GDALRaster object). So why not just allow returning the raw data and bypass the lazy instantiation?

@yellowcap yellowcap force-pushed the 25011 branch 3 times, most recently from 661d9e2 to a1cc9e2 Compare June 22, 2015 13:25
@timgraham
Copy link
Member

Maybe it would be worth adding a test for the error that runs on systems without GDAL? Also, let's reference the original ticket (#23804) rather than the new one. "Ref -> Refs" in message.

@yellowcap yellowcap changed the title Ref #25011 -- RasterField import only if HAS_GDAL Refs #23804 -- RasterField import only if HAS_GDAL Jun 23, 2015
@yellowcap
Copy link
Contributor Author

I simplified the patch a bit more and tried to add a test for this, but I did not find a way to make HAS_GDAL to be false. I tried overriding the GDAL_LIBRARY_PATH setting, which is used in django.contrib.gis.gdal.libgdal, but that module is loaded before the settings override has an effect. Any ideas on how to run a test where HAS_GDAL is set to be false?

@timgraham
Copy link
Member

I was thinking that the test would only run on systems without GDAL installed so there wouldn't be a need to mock HAS_GDAL.

@yellowcap yellowcap force-pushed the 25011 branch 4 times, most recently from c0a8e30 to a2ef30b Compare June 23, 2015 13:55
@yellowcap
Copy link
Contributor Author

Ok, here is a more viable solution. The HAS_GDAL check is in the __init__ function of the RasterField. I added a test for systems without gdal and ran the test on a fresh ubuntu install without geo libraries, which worked fine.

@@ -405,6 +405,11 @@ class RasterField(BaseSpatialField):
description = _("Raster Field")
geom_type = 'RASTER'

def __init__(self, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to accept *args here too (or at least at verbose_name=None. There's a convention to pass verbose_name as a positional arg: https://docs.djangoproject.com/en/1.8/topics/db/models/#verbose-field-names
Add a test for that too?

Claude, is this approach fine with you?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sounds good. And +1 for the positional argument. (_args, *_kwargs) doesn't cost much.

@yellowcap yellowcap force-pushed the 25011 branch 3 times, most recently from 71c3143 to 6be5bdd Compare June 23, 2015 19:35
@yellowcap
Copy link
Contributor Author

Added *args to RasterField __init__ and a test for the positional verbose name argument.

@yellowcap yellowcap changed the title Refs #23804 -- RasterField import only if HAS_GDAL Refs #23804 -- RasterField initialization only if HAS_GDAL Jun 23, 2015
@timgraham
Copy link
Member

merged in c0fff64, thanks!

@timgraham timgraham closed this Jun 23, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants