#36441: Add lazy loading support for GDAL library in `django.contrib.gis.gdal`
-------------------------------------+-------------------------------------
     Reporter:  Josh Thomas          |                    Owner:  Josh
         Type:                       |  Thomas
  Cleanup/optimization               |                   Status:  assigned
    Component:  GIS                  |                  Version:  dev
     Severity:  Normal               |               Resolution:
     Keywords:  gdal                 |             Triage Stage:  Accepted
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  1
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Comment (by Jacob Walls):

 > So at what point would an exception be raised? How does it compare to
 GEOS?

 I rechecked this, and GEOS isn't lazy-loaded after all, I don't think.
 This is the traceback I get on startup when setting `GEOS_LIBRARY_PATH =
 "/dev/null"`:

 {{{#!py
   File "/Users/jwalls/django/django/__init__.py", line 24, in setup
     apps.populate(settings.INSTALLED_APPS)
     ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/jwalls/django/django/apps/registry.py", line 116, in
 populate
     app_config.import_models()
     ~~~~~~~~~~~~~~~~~~~~~~~~^^
   File "/Users/jwalls/django/django/apps/config.py", line 269, in
 import_models
     self.models_module = import_module(models_module_name)
                          ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
   File
 
"/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/importlib/__init__.py",
 line 88, in import_module
     return _bootstrap._gcd_import(name[level:], package, level)
            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
   File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
   File "<frozen importlib._bootstrap>", line 1331, in
 _find_and_load_unlocked
   File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
   File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
   File "<frozen importlib._bootstrap>", line 488, in
 _call_with_frames_removed
   File "/Users/jwalls/django/django/contrib/auth/models.py", line 5, in
 <module>
     from django.contrib.auth.base_user import AbstractBaseUser,
 BaseUserManager
   File "/Users/jwalls/django/django/contrib/auth/base_user.py", line 43,
 in <module>
     class AbstractBaseUser(models.Model):
     ...<120 lines>...
             )
   File "/Users/jwalls/django/django/db/models/base.py", line 146, in
 __new__
     new_class.add_to_class("_meta", Options(meta, app_label))
     ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/jwalls/django/django/db/models/base.py", line 394, in
 add_to_class
     value.contribute_to_class(cls, name)
     ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
   File "/Users/jwalls/django/django/db/models/options.py", line 245, in
 contribute_to_class
     self.db_table, connection.ops.max_name_length()
                    ^^^^^^^^^^^^^^
   File "/Users/jwalls/django/django/utils/connection.py", line 15, in
 __getattr__
     return getattr(self._connections[self._alias], item)
                    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
   File "/Users/jwalls/django/django/utils/connection.py", line 62, in
 __getitem__
     conn = self.create_connection(alias)
   File "/Users/jwalls/django/django/db/utils.py", line 196, in
 create_connection
     backend = load_backend(db["ENGINE"])
   File "/Users/jwalls/django/django/db/utils.py", line 116, in
 load_backend
     return import_module("%s.base" % backend_name)
   File
 
"/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/importlib/__init__.py",
 line 88, in import_module
     return _bootstrap._gcd_import(name[level:], package, level)
            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File
 "/Users/jwalls/django/django/contrib/gis/db/backends/postgis/base.py",
 line 16, in <module>
     from .adapter import PostGISAdapter
   File
 "/Users/jwalls/django/django/contrib/gis/db/backends/postgis/adapter.py",
 line 6, in <module>
     from django.contrib.gis.geos import GEOSGeometry
   File "/Users/jwalls/django/django/contrib/gis/geos/__init__.py", line 6,
 in <module>
     from .collections import (  # NOQA
     ...<4 lines>...
     )
   File "/Users/jwalls/django/django/contrib/gis/geos/collections.py", line
 7, in <module>
     from django.contrib.gis.geos.geometry import GEOSGeometry,
 LinearGeometryMixin
   File "/Users/jwalls/django/django/contrib/gis/geos/geometry.py", line
 18, in <module>
     from django.contrib.gis.geos.prototypes.io import ewkb_w, wkb_r,
 wkb_w, wkt_r, wkt_w
   File "/Users/jwalls/django/django/contrib/gis/geos/prototypes/io.py",
 line 249, in <module>
     class WKBWriter(IOBase):
     ...<67 lines>...
             wkb_writer_set_include_srid(self.ptr, bool(include))
   File "/Users/jwalls/django/django/contrib/gis/geos/prototypes/io.py",
 line 253, in WKBWriter
     geos_version = geos_version_tuple()
   File "/Users/jwalls/django/django/contrib/gis/geos/libgeos.py", line
 175, in geos_version_tuple
     return get_version_tuple(geos_version().decode())
                              ~~~~~~~~~~~~^^
   File "/Users/jwalls/django/django/contrib/gis/geos/libgeos.py", line
 170, in geos_version
     return lgeos.GEOSversion()
            ^^^^^^^^^^^^^^^^^
   File "/Users/jwalls/django/django/utils/functional.py", line 251, in
 inner
     self._setup()
     ~~~~~~~~~~~^^
   File "/Users/jwalls/django/django/utils/functional.py", line 404, in
 _setup
     self._wrapped = self._setupfunc()
                     ~~~~~~~~~~~~~~~^^
   File "/Users/jwalls/django/django/contrib/gis/geos/libgeos.py", line 62,
 in load_geos
     _lgeos = CDLL(lib_path)
   File
 
"/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/ctypes/__init__.py",
 line 390, in __init__
     self._handle = _dlopen(self._name, mode)
                    ~~~~~~~^^^^^^^^^^^^^^^^^^
 OSError: dlopen(/dev/null, 0x0006): tried: '/dev/null' (not a file),
 '/System/Volumes/Preboot/Cryptexes/OS/dev/null' (no such file),
 '/dev/null' (not a file)
 }}}

 So the effect of the PR would be to hide failures only for GDAL, rather
 than to bring the behavior to parity with GEOS.

 Josh, do you agree that a simple system check for a working registration
 of GDAL registered by `contrib.gis` would be enough to move this forward?
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36441#comment:23>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019c2ab844b0-d44767dc-8941-4ed6-9faf-30d6938f402e-000000%40eu-central-1.amazonses.com.

Reply via email to