LCOV - code coverage report
Current view: top level - gcore - gdalpythondriverloader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 628 924 68.0 %
Date: 2025-10-21 22:35:35 Functions: 39 47 83.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Python plugin loader
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2017-2019, Even Rouault, <even dot rouault at spatialys dot
       9             :  *com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : #include "cpl_minixml.h"
      16             : #include "cpl_multiproc.h"
      17             : #include "cpl_string.h"
      18             : #include "gdal_priv.h"
      19             : #include "ogrsf_frmts.h"
      20             : #include "gdalpython.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <memory>
      24             : #include <mutex>
      25             : 
      26             : using namespace GDALPy;
      27             : 
      28             : #ifdef GDAL_NO_AUTOLOAD
      29             : void GDALDriverManager::AutoLoadPythonDrivers()
      30             : {
      31             : }
      32             : 
      33             : void GDALDriverManager::CleanupPythonDrivers()
      34             : {
      35             : }
      36             : 
      37             : #else
      38             : 
      39             : static PyObject *layer_featureCount(PyObject *m, PyObject *args,
      40             :                                     PyObject *kwargs);
      41             : 
      42             : static const PyMethodDef gdal_python_driver_methods[] = {
      43             :     {"layer_featureCount", layer_featureCount, METH_VARARGS | METH_KEYWORDS,
      44             :      nullptr},
      45             :     {nullptr, nullptr, 0, nullptr}};
      46             : 
      47             : static PyObject *Py_None = nullptr;
      48             : 
      49             : static PyObject *gpoGDALPythonDriverModule = nullptr;
      50             : 
      51             : /************************************************************************/
      52             : /*                         IncRefAndReturn()                            */
      53             : /************************************************************************/
      54             : 
      55           9 : static PyObject *IncRefAndReturn(PyObject *obj)
      56             : {
      57           9 :     Py_IncRef(obj);
      58           9 :     return obj;
      59             : }
      60             : 
      61             : /************************************************************************/
      62             : /*                            CallPython()                              */
      63             : /************************************************************************/
      64             : 
      65           1 : static PyObject *CallPython(PyObject *function)
      66             : {
      67           1 :     PyObject *pyArgs = PyTuple_New(0);
      68           1 :     PyObject *pRet = PyObject_Call(function, pyArgs, nullptr);
      69           1 :     Py_DecRef(pyArgs);
      70           1 :     return pRet;
      71             : }
      72             : 
      73             : /************************************************************************/
      74             : /*                            CallPython()                              */
      75             : /************************************************************************/
      76             : 
      77           3 : static PyObject *CallPython(PyObject *function, int nVal)
      78             : {
      79           3 :     PyObject *pyArgs = PyTuple_New(1);
      80           3 :     PyTuple_SetItem(pyArgs, 0, PyLong_FromLong(nVal));
      81           3 :     PyObject *pRet = PyObject_Call(function, pyArgs, nullptr);
      82           3 :     Py_DecRef(pyArgs);
      83           3 :     return pRet;
      84             : }
      85             : 
      86             : /************************************************************************/
      87             : /*                InitializePythonAndLoadGDALPythonDriverModule() */
      88             : /************************************************************************/
      89             : 
      90           3 : static bool InitializePythonAndLoadGDALPythonDriverModule()
      91             : {
      92           3 :     if (!GDALPythonInitialize())
      93           0 :         return false;
      94             : 
      95             :     static std::mutex gMutex;
      96             :     static bool gbAlreadyInitialized = false;
      97           6 :     std::lock_guard<std::mutex> guard(gMutex);
      98             : 
      99           3 :     if (gbAlreadyInitialized)
     100           2 :         return true;
     101           1 :     gbAlreadyInitialized = true;
     102             : 
     103           1 :     GIL_Holder oHolder(false);
     104             : 
     105             :     static PyModuleDef gdal_python_driver_moduledef = {
     106             :         PyModuleDef_HEAD_INIT,
     107             :         "_gdal_python_driver",
     108             :         nullptr,
     109             :         static_cast<Py_ssize_t>(-1),  // sizeof(struct module_state),
     110             :         gdal_python_driver_methods,
     111             :         nullptr,
     112             :         nullptr,
     113             :         nullptr,
     114             :         nullptr};
     115             : 
     116             :     PyObject *module =
     117           1 :         PyModule_Create2(&gdal_python_driver_moduledef, PYTHON_API_VERSION);
     118             :     // Add module to importable modules
     119           1 :     PyObject *sys = PyImport_ImportModule("sys");
     120           1 :     PyObject *sys_modules = PyObject_GetAttrString(sys, "modules");
     121           1 :     PyDict_SetItemString(sys_modules, "_gdal_python_driver", module);
     122           1 :     Py_DecRef(sys_modules);
     123           1 :     Py_DecRef(sys);
     124           1 :     Py_DecRef(module);
     125             : 
     126           1 :     PyObject *poCompiledString = Py_CompileString(
     127             :         "import _gdal_python_driver\n"
     128             :         "import json\n"
     129             :         "import inspect\n"
     130             :         "import sys\n"
     131             :         "class BaseLayer:\n"
     132             :         "   RandomRead='RandomRead'\n"
     133             :         "   FastSpatialFilter='FastSpatialFilter'\n"
     134             :         "   FastFeatureCount='FastFeatureCount'\n"
     135             :         "   FastGetExtent='FastGetExtent'\n"
     136             :         "   StringsAsUTF8='StringsAsUTF8'\n"
     137             :         "\n"
     138             :         "   def __init__(self):\n"
     139             :         "       pass\n"
     140             :         "\n"
     141             :         "   def feature_count(self, force):\n"
     142             :         "       assert isinstance(self, BaseLayer), 'self not instance of "
     143             :         "BaseLayer'\n"
     144             :         "       return _gdal_python_driver.layer_featureCount(self, force)\n"
     145             :         "\n"
     146             :         "class BaseDataset:\n"
     147             :         "   def __init__(self):\n"
     148             :         "       pass\n"
     149             :         "\n"
     150             :         "class BaseDriver:\n"
     151             :         "   def __init__(self):\n"
     152             :         "       pass\n"
     153             :         "\n"
     154             :         "def _gdal_returnNone():\n"
     155             :         "  return None"
     156             :         "\n"
     157             :         "def _gdal_json_serialize(d):\n"
     158             :         "  return json.dumps(d)\n"
     159             :         "\n"
     160             :         "def _instantiate_plugin(plugin_module):\n"
     161             :         "   candidate = None\n"
     162             :         "   for key in dir(plugin_module):\n"
     163             :         "       elt = getattr(plugin_module, key)\n"
     164             :         "       if inspect.isclass(elt) and sys.modules[elt.__module__] == "
     165             :         "plugin_module and issubclass(elt, BaseDriver):\n"
     166             :         "           if candidate:\n"
     167             :         "               raise Exception(\"several classes in \" + "
     168             :         "plugin_module.__name__ + \" deriving from "
     169             :         "gdal_python_driver.BaseDriver\")\n"
     170             :         "           candidate = elt\n"
     171             :         "   if candidate:\n"
     172             :         "       return candidate()\n"
     173             :         "   raise Exception(\"cannot find class in \" + plugin_module.__name__ "
     174             :         "+ \" deriving from gdal_python_driver.BaseDriver\")\n",
     175             :         "gdal_python_driver", Py_file_input);
     176           1 :     gpoGDALPythonDriverModule =
     177           1 :         PyImport_ExecCodeModule("gdal_python_driver", poCompiledString);
     178           1 :     Py_DecRef(poCompiledString);
     179             : 
     180             :     // Initialize Py_None
     181             :     PyObject *returnNone =
     182           1 :         PyObject_GetAttrString(gpoGDALPythonDriverModule, "_gdal_returnNone");
     183           1 :     Py_None = CallPython(returnNone);
     184           1 :     Py_DecRef(returnNone);
     185             : 
     186           1 :     return true;
     187             : }
     188             : 
     189             : /************************************************************************/
     190             : /*                           GetIntRes()                                */
     191             : /************************************************************************/
     192             : 
     193           0 : static int GetIntRes(PyObject *poObj, const char *pszFunctionName)
     194             : {
     195           0 :     PyObject *poMethod = PyObject_GetAttrString(poObj, pszFunctionName);
     196           0 :     if (poMethod == nullptr || PyErr_Occurred())
     197             :     {
     198           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
     199           0 :                  GetPyExceptionString().c_str());
     200           0 :         return 0;
     201             :     }
     202             : 
     203           0 :     PyObject *poMethodRes = CallPython(poMethod);
     204           0 :     if (ErrOccurredEmitCPLError())
     205             :     {
     206           0 :         Py_DecRef(poMethod);
     207           0 :         return 0;
     208             :     }
     209           0 :     Py_DecRef(poMethod);
     210             : 
     211           0 :     int nRes = static_cast<int>(PyLong_AsLong(poMethodRes));
     212           0 :     if (ErrOccurredEmitCPLError())
     213             :     {
     214           0 :         Py_DecRef(poMethodRes);
     215           0 :         return 0;
     216             :     }
     217             : 
     218           0 :     Py_DecRef(poMethodRes);
     219           0 :     return nRes;
     220             : }
     221             : 
     222             : /************************************************************************/
     223             : /*                           GetDict()                                  */
     224             : /************************************************************************/
     225             : 
     226           0 : static char **GetDict(PyObject *poDict)
     227             : {
     228             :     PyObject *key, *value;
     229           0 :     size_t pos = 0;
     230             : 
     231           0 :     char **papszRes = nullptr;
     232           0 :     while (PyDict_Next(poDict, &pos, &key, &value))
     233             :     {
     234           0 :         if (ErrOccurredEmitCPLError())
     235             :         {
     236           0 :             break;
     237             :         }
     238           0 :         CPLString osKey = GetString(key);
     239           0 :         if (ErrOccurredEmitCPLError())
     240             :         {
     241           0 :             break;
     242             :         }
     243           0 :         CPLString osValue = GetString(value);
     244           0 :         if (ErrOccurredEmitCPLError())
     245             :         {
     246           0 :             break;
     247             :         }
     248           0 :         papszRes = CSLSetNameValue(papszRes, osKey, osValue);
     249             :     }
     250           0 :     return papszRes;
     251             : }
     252             : 
     253             : /************************************************************************/
     254             : /*                          GetStringRes()                              */
     255             : /************************************************************************/
     256             : 
     257           0 : static CPLString GetStringRes(PyObject *poObj, const char *pszFunctionName,
     258             :                               bool bOptionalMethod = false)
     259             : {
     260           0 :     PyObject *poMethod = PyObject_GetAttrString(poObj, pszFunctionName);
     261           0 :     if (poMethod == nullptr || PyErr_Occurred())
     262             :     {
     263           0 :         if (bOptionalMethod)
     264             :         {
     265           0 :             PyErr_Clear();
     266             :         }
     267             :         else
     268             :         {
     269           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s",
     270           0 :                      GetPyExceptionString().c_str());
     271             :         }
     272           0 :         return CPLString();
     273             :     }
     274             : 
     275           0 :     PyObject *poMethodRes = CallPython(poMethod);
     276             : 
     277           0 :     if (ErrOccurredEmitCPLError())
     278             :     {
     279           0 :         Py_DecRef(poMethod);
     280           0 :         return CPLString();
     281             :     }
     282           0 :     Py_DecRef(poMethod);
     283             : 
     284           0 :     CPLString osRes = GetString(poMethodRes);
     285           0 :     if (ErrOccurredEmitCPLError())
     286             :     {
     287           0 :         Py_DecRef(poMethodRes);
     288           0 :         return CPLString();
     289             :     }
     290             : 
     291           0 :     Py_DecRef(poMethodRes);
     292           0 :     return osRes;
     293             : }
     294             : 
     295             : /************************************************************************/
     296             : /*                          PythonPluginLayer                           */
     297             : /************************************************************************/
     298             : 
     299             : class PythonPluginLayer final : public OGRLayer
     300             : {
     301             :     mutable PyObject *m_poLayer = nullptr;
     302             :     mutable OGRFeatureDefn *m_poFeatureDefn = nullptr;
     303             :     mutable CPLString m_osName{};
     304             :     mutable CPLString m_osFIDColumn{};
     305             :     mutable bool m_bHasFIDColumn = false;
     306             :     std::map<CPLString, CPLStringList> m_oMapMD{};
     307             :     PyObject *m_pyFeatureByIdMethod = nullptr;
     308             :     bool m_bIteratorHonourSpatialFilter = false;
     309             :     bool m_bIteratorHonourAttributeFilter = false;
     310             :     bool m_bFeatureCountHonourSpatialFilter = false;
     311             :     bool m_bFeatureCountHonourAttributeFilter = false;
     312             :     PyObject *m_pyIterator = nullptr;
     313             :     bool m_bStopIteration = false;
     314             : 
     315             :     void RefreshHonourFlags();
     316             :     void StoreSpatialFilter();
     317             : 
     318             :     void GetFields() const;
     319             :     void GetGeomFields() const;
     320             :     OGRFeature *TranslateToOGRFeature(PyObject *poObj);
     321             : 
     322             :     PythonPluginLayer(const PythonPluginLayer &) = delete;
     323             :     PythonPluginLayer &operator=(const PythonPluginLayer &) = delete;
     324             : 
     325             :   public:
     326             :     explicit PythonPluginLayer(PyObject *poLayer);
     327             :     ~PythonPluginLayer() override;
     328             : 
     329             :     const char *GetName() const override;
     330             :     void ResetReading() override;
     331             :     OGRFeature *GetNextFeature() override;
     332             :     OGRFeature *GetFeature(GIntBig nFID) override;
     333             :     int TestCapability(const char *) const override;
     334             :     const OGRFeatureDefn *GetLayerDefn() const override;
     335             : 
     336             :     GIntBig GetFeatureCount(int bForce) override;
     337             :     const char *GetFIDColumn() const override;
     338             :     OGRErr SetAttributeFilter(const char *) override;
     339             : 
     340             :     OGRErr ISetSpatialFilter(int iGeomField, const OGRGeometry *) override;
     341             : 
     342             :     OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
     343             :                       bool bForce) override;
     344             : 
     345             :     char **GetMetadata(const char *pszDomain = "") override;
     346             : };
     347             : 
     348             : /************************************************************************/
     349             : /*                          PythonPluginLayer()                         */
     350             : /************************************************************************/
     351             : 
     352           3 : PythonPluginLayer::PythonPluginLayer(PyObject *poLayer)
     353           3 :     : m_poLayer(poLayer), m_poFeatureDefn(nullptr)
     354             : {
     355           3 :     SetDescription(PythonPluginLayer::GetName());
     356           3 :     const char *pszPtr = CPLSPrintf("%p", this);
     357           3 :     PyObject *ptr = PyUnicode_FromString(pszPtr);
     358           3 :     PyObject_SetAttrString(m_poLayer, "_gdal_pointer", ptr);
     359           3 :     Py_DecRef(ptr);
     360           3 :     PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", Py_None);
     361           3 :     PyObject_SetAttrString(m_poLayer, "spatial_filter", Py_None);
     362           3 :     PyObject_SetAttrString(m_poLayer, "attribute_filter", Py_None);
     363           3 :     auto poFalse = PyBool_FromLong(false);
     364           3 :     if (!PyObject_HasAttrString(m_poLayer, "iterator_honour_attribute_filter"))
     365             :     {
     366           3 :         PyObject_SetAttrString(m_poLayer, "iterator_honour_attribute_filter",
     367             :                                poFalse);
     368             :     }
     369           3 :     if (!PyObject_HasAttrString(m_poLayer, "iterator_honour_spatial_filter"))
     370             :     {
     371           3 :         PyObject_SetAttrString(m_poLayer, "iterator_honour_spatial_filter",
     372             :                                poFalse);
     373             :     }
     374           3 :     if (!PyObject_HasAttrString(m_poLayer,
     375             :                                 "feature_count_honour_attribute_filter"))
     376             :     {
     377           3 :         PyObject_SetAttrString(
     378             :             m_poLayer, "feature_count_honour_attribute_filter", poFalse);
     379             :     }
     380           3 :     if (!PyObject_HasAttrString(m_poLayer,
     381             :                                 "feature_count_honour_spatial_filter"))
     382             :     {
     383           3 :         PyObject_SetAttrString(m_poLayer, "feature_count_honour_spatial_filter",
     384             :                                poFalse);
     385             :     }
     386           3 :     Py_DecRef(poFalse);
     387           3 :     RefreshHonourFlags();
     388             : 
     389           3 :     if (PyObject_HasAttrString(m_poLayer, "feature_by_id"))
     390             :     {
     391           0 :         m_pyFeatureByIdMethod =
     392           0 :             PyObject_GetAttrString(m_poLayer, "feature_by_id");
     393             :     }
     394           3 : }
     395             : 
     396             : /************************************************************************/
     397             : /*                          ~PythonPluginLayer()                        */
     398             : /************************************************************************/
     399             : 
     400           6 : PythonPluginLayer::~PythonPluginLayer()
     401             : {
     402           6 :     GIL_Holder oHolder(false);
     403           3 :     if (m_poFeatureDefn)
     404           3 :         m_poFeatureDefn->Release();
     405           3 :     Py_DecRef(m_pyFeatureByIdMethod);
     406           3 :     Py_DecRef(m_poLayer);
     407           3 :     Py_DecRef(m_pyIterator);
     408           6 : }
     409             : 
     410             : /************************************************************************/
     411             : /*                        RefreshHonourFlags()               */
     412             : /************************************************************************/
     413             : 
     414           3 : void PythonPluginLayer::RefreshHonourFlags()
     415             : {
     416           3 :     if (PyObject_HasAttrString(m_poLayer, "iterator_honour_attribute_filter"))
     417             :     {
     418           3 :         auto poObj = PyObject_GetAttrString(m_poLayer,
     419             :                                             "iterator_honour_attribute_filter");
     420           3 :         m_bIteratorHonourAttributeFilter = PyLong_AsLong(poObj) != 0;
     421           3 :         Py_DecRef(poObj);
     422             :     }
     423           3 :     if (PyObject_HasAttrString(m_poLayer, "iterator_honour_spatial_filter"))
     424             :     {
     425             :         auto poObj =
     426           3 :             PyObject_GetAttrString(m_poLayer, "iterator_honour_spatial_filter");
     427           3 :         m_bIteratorHonourSpatialFilter = PyLong_AsLong(poObj) != 0;
     428           3 :         Py_DecRef(poObj);
     429             :     }
     430           3 :     if (PyObject_HasAttrString(m_poLayer,
     431           3 :                                "feature_count_honour_attribute_filter"))
     432             :     {
     433           3 :         auto poObj = PyObject_GetAttrString(
     434             :             m_poLayer, "feature_count_honour_attribute_filter");
     435           3 :         m_bFeatureCountHonourAttributeFilter = PyLong_AsLong(poObj) != 0;
     436           3 :         Py_DecRef(poObj);
     437             :     }
     438           3 :     if (PyObject_HasAttrString(m_poLayer,
     439           3 :                                "feature_count_honour_spatial_filter"))
     440             :     {
     441           3 :         auto poObj = PyObject_GetAttrString(
     442             :             m_poLayer, "feature_count_honour_spatial_filter");
     443           3 :         m_bFeatureCountHonourSpatialFilter = PyLong_AsLong(poObj) != 0;
     444           3 :         Py_DecRef(poObj);
     445             :     }
     446           3 : }
     447             : 
     448             : /************************************************************************/
     449             : /*                          SetAttributeFilter()                        */
     450             : /************************************************************************/
     451             : 
     452          12 : OGRErr PythonPluginLayer::SetAttributeFilter(const char *pszFilter)
     453             : {
     454          24 :     GIL_Holder oHolder(false);
     455             :     PyObject *str =
     456          12 :         pszFilter ? PyUnicode_FromString(pszFilter) : IncRefAndReturn(Py_None);
     457          12 :     PyObject_SetAttrString(m_poLayer, "attribute_filter", str);
     458          12 :     Py_DecRef(str);
     459             : 
     460          12 :     if (PyObject_HasAttrString(m_poLayer, "attribute_filter_changed"))
     461             :     {
     462             :         auto poObj =
     463           0 :             PyObject_GetAttrString(m_poLayer, "attribute_filter_changed");
     464           0 :         Py_DecRef(CallPython(poObj));
     465           0 :         Py_DecRef(poObj);
     466             :     }
     467             : 
     468          24 :     return OGRLayer::SetAttributeFilter(pszFilter);
     469             : }
     470             : 
     471             : /************************************************************************/
     472             : /*                          StoreSpatialFilter()                        */
     473             : /************************************************************************/
     474             : 
     475          12 : void PythonPluginLayer::StoreSpatialFilter()
     476             : {
     477          24 :     GIL_Holder oHolder(false);
     478          12 :     if (m_poFilterGeom && !m_poFilterGeom->IsEmpty())
     479             :     {
     480           3 :         PyObject *list = PyList_New(4);
     481           3 :         PyList_SetItem(list, 0, PyFloat_FromDouble(m_sFilterEnvelope.MinX));
     482           3 :         PyList_SetItem(list, 1, PyFloat_FromDouble(m_sFilterEnvelope.MinY));
     483           3 :         PyList_SetItem(list, 2, PyFloat_FromDouble(m_sFilterEnvelope.MaxX));
     484           3 :         PyList_SetItem(list, 3, PyFloat_FromDouble(m_sFilterEnvelope.MaxY));
     485           3 :         PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", list);
     486           3 :         Py_DecRef(list);
     487             : 
     488           3 :         char *pszWKT = nullptr;
     489           3 :         m_poFilterGeom->exportToWkt(&pszWKT);
     490           3 :         PyObject *str = PyUnicode_FromString(pszWKT);
     491           3 :         PyObject_SetAttrString(m_poLayer, "spatial_filter", str);
     492           3 :         Py_DecRef(str);
     493           3 :         CPLFree(pszWKT);
     494             :     }
     495             :     else
     496             :     {
     497           9 :         PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", Py_None);
     498           9 :         PyObject_SetAttrString(m_poLayer, "spatial_filter", Py_None);
     499             :     }
     500             : 
     501          12 :     if (PyObject_HasAttrString(m_poLayer, "spatial_filter_changed"))
     502             :     {
     503             :         auto poObj =
     504           0 :             PyObject_GetAttrString(m_poLayer, "spatial_filter_changed");
     505           0 :         Py_DecRef(CallPython(poObj));
     506           0 :         Py_DecRef(poObj);
     507             :     }
     508          12 : }
     509             : 
     510             : /************************************************************************/
     511             : /*                         ISetSpatialFilter()                          */
     512             : /************************************************************************/
     513             : 
     514          12 : OGRErr PythonPluginLayer::ISetSpatialFilter(int iGeomField,
     515             :                                             const OGRGeometry *poGeom)
     516             : {
     517          12 :     const OGRErr eErr = OGRLayer::ISetSpatialFilter(iGeomField, poGeom);
     518          12 :     if (eErr == OGRERR_NONE)
     519          12 :         StoreSpatialFilter();
     520          12 :     return eErr;
     521             : }
     522             : 
     523             : /************************************************************************/
     524             : /*                           GetName()                                  */
     525             : /************************************************************************/
     526             : 
     527           9 : const char *PythonPluginLayer::GetName() const
     528             : {
     529           9 :     if (m_osName.empty())
     530             :     {
     531           3 :         GIL_Holder oHolder(false);
     532             : 
     533           3 :         PyObject *poObj = PyObject_GetAttrString(m_poLayer, "name");
     534           3 :         if (ErrOccurredEmitCPLError())
     535           0 :             return m_osName;
     536           3 :         if (PyCallable_Check(poObj))
     537             :         {
     538           0 :             m_osName = GetStringRes(m_poLayer, "name");
     539             :         }
     540             :         else
     541             :         {
     542           3 :             m_osName = GetString(poObj);
     543           3 :             CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
     544             :         }
     545           3 :         Py_DecRef(poObj);
     546             :     }
     547           9 :     return m_osName;
     548             : }
     549             : 
     550             : /************************************************************************/
     551             : /*                       TestCapability()                               */
     552             : /************************************************************************/
     553             : 
     554          12 : int PythonPluginLayer::TestCapability(const char *pszCap) const
     555             : {
     556          24 :     GIL_Holder oHolder(false);
     557          12 :     if (PyObject_HasAttrString(m_poLayer, "test_capability"))
     558             :     {
     559          12 :         PyObject *poObj = PyObject_GetAttrString(m_poLayer, "test_capability");
     560          12 :         if (ErrOccurredEmitCPLError())
     561           0 :             return 0;
     562          12 :         PyObject *pyArgs = PyTuple_New(1);
     563          12 :         PyTuple_SetItem(pyArgs, 0, PyUnicode_FromString(pszCap));
     564          12 :         PyObject *pRet = PyObject_Call(poObj, pyArgs, nullptr);
     565          12 :         Py_DecRef(pyArgs);
     566          12 :         Py_DecRef(poObj);
     567          12 :         if (ErrOccurredEmitCPLError())
     568             :         {
     569           0 :             Py_DecRef(pRet);
     570           0 :             return 0;
     571             :         }
     572          12 :         int nRes = static_cast<int>(PyLong_AsLong(pRet));
     573          12 :         Py_DecRef(pRet);
     574          12 :         if (ErrOccurredEmitCPLError())
     575             :         {
     576           0 :             return 0;
     577             :         }
     578          12 :         return nRes;
     579             :     }
     580           0 :     return 0;
     581             : }
     582             : 
     583             : /************************************************************************/
     584             : /*                         GetFIDColumn()                               */
     585             : /************************************************************************/
     586             : 
     587           6 : const char *PythonPluginLayer::GetFIDColumn() const
     588             : {
     589           6 :     if (!m_bHasFIDColumn)
     590             :     {
     591           3 :         m_bHasFIDColumn = true;
     592           6 :         GIL_Holder oHolder(false);
     593           3 :         PyObject *poObj = PyObject_GetAttrString(m_poLayer, "fid_name");
     594           3 :         if (PyErr_Occurred())
     595             :         {
     596           0 :             PyErr_Clear();
     597             :         }
     598             :         else
     599             :         {
     600           3 :             if (PyCallable_Check(poObj))
     601             :             {
     602           0 :                 m_osFIDColumn = GetStringRes(m_poLayer, "fid_name", true);
     603             :             }
     604             :             else
     605             :             {
     606           3 :                 m_osFIDColumn = GetString(poObj);
     607           3 :                 CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
     608             :             }
     609           3 :             Py_DecRef(poObj);
     610             :         }
     611             :     }
     612           6 :     return m_osFIDColumn;
     613             : }
     614             : 
     615             : /************************************************************************/
     616             : /*                        layer_featureCount()                           */
     617             : /************************************************************************/
     618             : 
     619           0 : static PyObject *layer_featureCount(PyObject * /*m*/, PyObject *args,
     620             :                                     PyObject * /*kwargs*/)
     621             : {
     622           0 :     PyObject *poPyLayer = nullptr;
     623           0 :     int bForce = 0;
     624           0 :     if (PyArg_ParseTuple(args, "O|i", &poPyLayer, &bForce))
     625             :     {
     626             :         PyObject *poPointer =
     627           0 :             PyObject_GetAttrString(poPyLayer, "_gdal_pointer");
     628           0 :         if (poPointer)
     629             :         {
     630           0 :             CPLString osPtr = GetString(poPointer);
     631           0 :             Py_DecRef(poPointer);
     632           0 :             void *pPtr = nullptr;
     633           0 :             sscanf(osPtr, "%p", &pPtr);
     634           0 :             PythonPluginLayer *poLayer = static_cast<PythonPluginLayer *>(pPtr);
     635           0 :             return PyLong_FromLongLong(
     636           0 :                 poLayer->OGRLayer::GetFeatureCount(bForce));
     637             :         }
     638             :     }
     639           0 :     Py_IncRef(Py_None);
     640           0 :     return Py_None;
     641             : }
     642             : 
     643             : /************************************************************************/
     644             : /*                         GetFeatureCount()                            */
     645             : /************************************************************************/
     646             : 
     647           9 : GIntBig PythonPluginLayer::GetFeatureCount(int bForce)
     648             : {
     649          18 :     GIL_Holder oHolder(false);
     650             : 
     651           9 :     if (PyObject_HasAttrString(m_poLayer, "feature_count") &&
     652          15 :         (m_bFeatureCountHonourAttributeFilter || m_poAttrQuery == nullptr) &&
     653           6 :         (m_bFeatureCountHonourSpatialFilter || m_poFilterGeom == nullptr))
     654             :     {
     655           3 :         auto poMethod = PyObject_GetAttrString(m_poLayer, "feature_count");
     656           3 :         PyObject *poRet = CallPython(poMethod, bForce);
     657           3 :         if (ErrOccurredEmitCPLError())
     658             :         {
     659           0 :             Py_DecRef(poRet);
     660           0 :             return OGRLayer::GetFeatureCount(bForce);
     661             :         }
     662             : 
     663           3 :         GIntBig nRet = PyLong_AsLongLong(poRet);
     664           3 :         if (ErrOccurredEmitCPLError())
     665             :         {
     666           0 :             Py_DecRef(poRet);
     667           0 :             return OGRLayer::GetFeatureCount(bForce);
     668             :         }
     669             : 
     670           3 :         Py_DecRef(poRet);
     671           3 :         return nRet;
     672             :     }
     673           6 :     return OGRLayer::GetFeatureCount(bForce);
     674             : }
     675             : 
     676             : /************************************************************************/
     677             : /*                          IGetExtent()                                */
     678             : /************************************************************************/
     679             : 
     680           0 : OGRErr PythonPluginLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     681             :                                      bool bForce)
     682             : {
     683           0 :     GIL_Holder oHolder(false);
     684           0 :     if (PyObject_HasAttrString(m_poLayer, "extent"))
     685             :     {
     686           0 :         PyObject *poMethod = PyObject_GetAttrString(m_poLayer, "extent");
     687           0 :         if (poMethod != nullptr)
     688             :         {
     689           0 :             PyObject *poRet = CallPython(poMethod, bForce);
     690             : 
     691           0 :             if (ErrOccurredEmitCPLError())
     692             :             {
     693           0 :                 Py_DecRef(poRet);
     694           0 :                 return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     695             :             }
     696             : 
     697           0 :             if (poRet == Py_None)
     698             :             {
     699           0 :                 Py_DecRef(poRet);
     700           0 :                 return OGRERR_FAILURE;
     701             :             }
     702             : 
     703           0 :             if (PySequence_Size(poRet) == 4)
     704             :             {
     705           0 :                 PyObject *poMinX = PySequence_GetItem(poRet, 0);
     706           0 :                 PyObject *poMinY = PySequence_GetItem(poRet, 1);
     707           0 :                 PyObject *poMaxX = PySequence_GetItem(poRet, 2);
     708           0 :                 PyObject *poMaxY = PySequence_GetItem(poRet, 3);
     709           0 :                 double dfMinX = PyFloat_AsDouble(poMinX);
     710           0 :                 double dfMinY = PyFloat_AsDouble(poMinY);
     711           0 :                 double dfMaxX = PyFloat_AsDouble(poMaxX);
     712           0 :                 double dfMaxY = PyFloat_AsDouble(poMaxY);
     713           0 :                 if (ErrOccurredEmitCPLError())
     714             :                 {
     715           0 :                     Py_DecRef(poRet);
     716           0 :                     return OGRLayer::GetExtent(psExtent, bForce);
     717             :                 }
     718           0 :                 Py_DecRef(poRet);
     719           0 :                 psExtent->MinX = dfMinX;
     720           0 :                 psExtent->MinY = dfMinY;
     721           0 :                 psExtent->MaxX = dfMaxX;
     722           0 :                 psExtent->MaxY = dfMaxY;
     723           0 :                 return OGRERR_NONE;
     724             :             }
     725             :             else
     726             :             {
     727           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     728             :                          "List should have 4 values");
     729             :             }
     730             : 
     731           0 :             Py_DecRef(poRet);
     732             :         }
     733             :     }
     734           0 :     return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     735             : }
     736             : 
     737             : /************************************************************************/
     738             : /*                      TranslateToOGRFeature()                         */
     739             : /************************************************************************/
     740             : 
     741          78 : OGRFeature *PythonPluginLayer::TranslateToOGRFeature(PyObject *poObj)
     742             : {
     743          78 :     if (poObj == Py_None)
     744           0 :         return nullptr;
     745             : 
     746          78 :     OGRFeature *poFeature = new OGRFeature(GetLayerDefn());
     747             : 
     748          78 :     PyObject *myBool = PyBool_FromLong(1);
     749          78 :     PyObject *myBoolType = PyObject_Type(myBool);
     750          78 :     PyObject *myInt = PyLong_FromLong(1);
     751          78 :     PyObject *myIntType = PyObject_Type(myInt);
     752          78 :     PyObject *myLong = PyLong_FromLongLong(1);
     753          78 :     PyObject *myLongType = PyObject_Type(myLong);
     754          78 :     PyObject *myFloat = PyFloat_FromDouble(1.0);
     755          78 :     PyObject *myFloatType = PyObject_Type(myFloat);
     756          78 :     PyObject *myStr = PyUnicode_FromString("");
     757          78 :     PyObject *myStrType = PyObject_Type(myStr);
     758             : 
     759          78 :     auto poFields = PyDict_GetItemString(poObj, "fields");
     760          78 :     auto poGeometryFields = PyDict_GetItemString(poObj, "geometry_fields");
     761          78 :     auto poId = PyDict_GetItemString(poObj, "id");
     762          78 :     auto poStyleString = PyDict_GetItemString(poObj, "style");
     763          78 :     PyErr_Clear();
     764             : 
     765          78 :     if (poId && PyObject_IsInstance(poId, myLongType))
     766             :     {
     767          78 :         poFeature->SetFID(static_cast<GIntBig>(PyLong_AsLongLong(poId)));
     768             :     }
     769           0 :     else if (poId && PyObject_IsInstance(poId, myIntType))
     770             :     {
     771           0 :         poFeature->SetFID(static_cast<GIntBig>(PyLong_AsLong(poId)));
     772             :     }
     773             : 
     774          78 :     if (poStyleString && poStyleString != Py_None)
     775             :     {
     776          96 :         CPLString osValue = GetString(poStyleString);
     777          48 :         if (!ErrOccurredEmitCPLError())
     778             :         {
     779          48 :             poFeature->SetStyleString(osValue);
     780             :         }
     781             :     }
     782             : 
     783          78 :     if (poGeometryFields && poGeometryFields != Py_None)
     784             :     {
     785          78 :         PyObject *key = nullptr;
     786          78 :         PyObject *value = nullptr;
     787          78 :         size_t pos = 0;
     788         156 :         while (PyDict_Next(poGeometryFields, &pos, &key, &value))
     789             :         {
     790          78 :             CPLString osKey = GetString(key);
     791          78 :             if (ErrOccurredEmitCPLError())
     792             :             {
     793           0 :                 break;
     794             :             }
     795          78 :             if (value != Py_None)
     796             :             {
     797          78 :                 const int idx = m_poFeatureDefn->GetGeomFieldIndex(osKey);
     798          78 :                 if (idx >= 0)
     799             :                 {
     800          78 :                     OGRGeometry *poGeom = nullptr;
     801          78 :                     if (PyObject_IsInstance(value, myStrType))
     802             :                     {
     803             :                         // WKT
     804          26 :                         CPLString osValue = GetString(value);
     805          26 :                         if (ErrOccurredEmitCPLError())
     806             :                         {
     807           0 :                             break;
     808             :                         }
     809          26 :                         OGRGeometryFactory::createFromWkt(osValue.c_str(),
     810             :                                                           nullptr, &poGeom);
     811             :                     }
     812             :                     else
     813             :                     {
     814             :                         // WKB (from bytes, bytearray, memoryview)
     815          52 :                         PyObject *poBytes = PyBytes_FromObject(value);
     816          52 :                         if (ErrOccurredEmitCPLError())
     817             :                         {
     818           0 :                             break;
     819             :                         }
     820          52 :                         char *buffer = nullptr;
     821          52 :                         size_t length = 0;
     822          52 :                         PyBytes_AsStringAndSize(poBytes, &buffer, &length);
     823          52 :                         if (ErrOccurredEmitCPLError())
     824             :                         {
     825           0 :                             break;
     826             :                         }
     827             : 
     828          52 :                         OGRGeometryFactory::createFromWkb(
     829             :                             buffer, nullptr, &poGeom, length, wkbVariantIso);
     830             :                     }
     831             : 
     832          78 :                     if (poGeom)
     833             :                     {
     834             :                         const auto poGeomFieldDefn =
     835          78 :                             m_poFeatureDefn->GetGeomFieldDefn(idx);
     836          78 :                         if (poGeomFieldDefn)
     837          78 :                             poGeom->assignSpatialReference(
     838          78 :                                 poGeomFieldDefn->GetSpatialRef());
     839             :                     }
     840          78 :                     poFeature->SetGeomFieldDirectly(idx, poGeom);
     841             :                 }
     842             :             }
     843             :         }
     844             :     }
     845             : 
     846          78 :     PyObject *key = nullptr;
     847          78 :     PyObject *value = nullptr;
     848          78 :     size_t pos = 0;
     849        2028 :     while (poFields && poFields != Py_None &&
     850        1014 :            PyDict_Next(poFields, &pos, &key, &value))
     851             :     {
     852         936 :         CPLString osKey = GetString(key);
     853         936 :         if (ErrOccurredEmitCPLError())
     854             :         {
     855           0 :             break;
     856             :         }
     857             : 
     858         936 :         if (value == Py_None)
     859             :         {
     860          78 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     861          78 :             if (idx >= 0)
     862             :             {
     863          78 :                 poFeature->SetFieldNull(idx);
     864             :             }
     865             :         }
     866         858 :         else if (PyObject_IsInstance(value, myLongType))
     867             :         {
     868         312 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     869         312 :             if (idx >= 0)
     870             :             {
     871         312 :                 poFeature->SetField(
     872             :                     idx, static_cast<GIntBig>(PyLong_AsLongLong(value)));
     873             :             }
     874             :         }
     875        1092 :         else if (PyObject_IsInstance(value, myBoolType) ||
     876         546 :                  PyObject_IsInstance(value, myIntType))
     877             :         {
     878           0 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     879           0 :             if (idx >= 0)
     880             :             {
     881           0 :                 poFeature->SetField(idx,
     882           0 :                                     static_cast<GIntBig>(PyLong_AsLong(value)));
     883             :             }
     884             :         }
     885         546 :         else if (PyObject_IsInstance(value, myFloatType))
     886             :         {
     887         156 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     888         156 :             if (idx >= 0)
     889             :             {
     890         156 :                 poFeature->SetField(idx, PyFloat_AsDouble(value));
     891             :             }
     892             :         }
     893             :         else
     894             :         {
     895         390 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     896         780 :             if (idx >= 0 &&
     897         390 :                 m_poFeatureDefn->GetFieldDefn(idx)->GetType() == OFTBinary)
     898             :             {
     899          78 :                 Py_ssize_t nSize = PyBytes_Size(value);
     900          78 :                 const char *pszBytes = PyBytes_AsString(value);
     901          78 :                 poFeature->SetField(
     902             :                     idx, static_cast<int>(nSize),
     903             :                     const_cast<GByte *>(
     904             :                         reinterpret_cast<const GByte *>(pszBytes)));
     905          78 :                 continue;
     906             :             }
     907             : 
     908         312 :             CPLString osValue = GetString(value);
     909         312 :             if (ErrOccurredEmitCPLError())
     910             :             {
     911           0 :                 break;
     912             :             }
     913         312 :             if (idx >= 0)
     914             :             {
     915         312 :                 poFeature->SetField(idx, osValue);
     916             :             }
     917             :         }
     918             :     }
     919             : 
     920          78 :     Py_DecRef(myBoolType);
     921          78 :     Py_DecRef(myBool);
     922          78 :     Py_DecRef(myIntType);
     923          78 :     Py_DecRef(myInt);
     924          78 :     Py_DecRef(myLongType);
     925          78 :     Py_DecRef(myLong);
     926          78 :     Py_DecRef(myFloatType);
     927          78 :     Py_DecRef(myFloat);
     928          78 :     Py_DecRef(myStr);
     929          78 :     Py_DecRef(myStrType);
     930             : 
     931          78 :     return poFeature;
     932             : }
     933             : 
     934             : /************************************************************************/
     935             : /*                            GetFeature()                              */
     936             : /************************************************************************/
     937             : 
     938           3 : OGRFeature *PythonPluginLayer::GetFeature(GIntBig nFID)
     939             : {
     940           6 :     GIL_Holder oHolder(false);
     941             : 
     942           3 :     if (m_pyFeatureByIdMethod)
     943             :     {
     944           0 :         PyObject *pyArgs = PyTuple_New(1);
     945           0 :         PyTuple_SetItem(pyArgs, 0, PyLong_FromLongLong(nFID));
     946           0 :         PyObject *pRet = PyObject_Call(m_pyFeatureByIdMethod, pyArgs, nullptr);
     947           0 :         Py_DecRef(pyArgs);
     948           0 :         if (ErrOccurredEmitCPLError())
     949             :         {
     950           0 :             Py_DecRef(pRet);
     951           0 :             return nullptr;
     952             :         }
     953           0 :         auto poFeature = TranslateToOGRFeature(pRet);
     954           0 :         Py_DecRef(pRet);
     955           0 :         if (ErrOccurredEmitCPLError())
     956             :         {
     957           0 :             return nullptr;
     958             :         }
     959           0 :         return poFeature;
     960             :     }
     961           3 :     return OGRLayer::GetFeature(nFID);
     962             : }
     963             : 
     964             : /************************************************************************/
     965             : /*                           ResetReading()                             */
     966             : /************************************************************************/
     967             : 
     968          36 : void PythonPluginLayer::ResetReading()
     969             : {
     970          36 :     m_bStopIteration = false;
     971             : 
     972          36 :     GIL_Holder oHolder(false);
     973             : 
     974          36 :     Py_DecRef(m_pyIterator);
     975          36 :     m_pyIterator = PyObject_GetIter(m_poLayer);
     976          36 :     CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
     977          36 : }
     978             : 
     979             : /************************************************************************/
     980             : /*                          GetNextFeature()                            */
     981             : /************************************************************************/
     982             : 
     983          33 : OGRFeature *PythonPluginLayer::GetNextFeature()
     984             : {
     985          66 :     GIL_Holder oHolder(false);
     986             : 
     987          33 :     if (m_bStopIteration)
     988           0 :         return nullptr;
     989             : 
     990          33 :     if (m_pyIterator == nullptr)
     991             :     {
     992           0 :         ResetReading();
     993           0 :         if (m_pyIterator == nullptr)
     994             :         {
     995           0 :             return nullptr;
     996             :         }
     997             :     }
     998             : 
     999             :     while (true)
    1000             :     {
    1001          93 :         PyObject *poRet = PyIter_Next(m_pyIterator);
    1002          93 :         if (poRet == nullptr)
    1003             :         {
    1004          15 :             m_bStopIteration = true;
    1005          15 :             CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
    1006          15 :             return nullptr;
    1007             :         }
    1008             : 
    1009          78 :         auto poFeature = TranslateToOGRFeature(poRet);
    1010          78 :         Py_DecRef(poRet);
    1011          78 :         if (poFeature == nullptr)
    1012             :         {
    1013           0 :             return nullptr;
    1014             :         }
    1015             : 
    1016          78 :         if ((m_bIteratorHonourSpatialFilter || m_poFilterGeom == nullptr ||
    1017         156 :              FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
    1018          48 :             (m_bIteratorHonourAttributeFilter || m_poAttrQuery == nullptr ||
    1019          30 :              m_poAttrQuery->Evaluate(poFeature)))
    1020             :         {
    1021          18 :             return poFeature;
    1022             :         }
    1023             : 
    1024          60 :         delete poFeature;
    1025          60 :     }
    1026             : }
    1027             : 
    1028             : /************************************************************************/
    1029             : /*                         GetLayerDefn()                               */
    1030             : /************************************************************************/
    1031             : 
    1032          93 : const OGRFeatureDefn *PythonPluginLayer::GetLayerDefn() const
    1033             : {
    1034          93 :     if (m_poFeatureDefn)
    1035          90 :         return m_poFeatureDefn;
    1036             : 
    1037           3 :     GIL_Holder oHolder(false);
    1038           3 :     m_poFeatureDefn = new OGRFeatureDefn(GetName());
    1039           3 :     m_poFeatureDefn->Reference();
    1040           3 :     m_poFeatureDefn->SetGeomType(wkbNone);
    1041             : 
    1042           3 :     GetFields();
    1043           3 :     GetGeomFields();
    1044           3 :     return m_poFeatureDefn;
    1045             : }
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                           GetFields()                                */
    1049             : /************************************************************************/
    1050             : 
    1051           3 : void PythonPluginLayer::GetFields() const
    1052             : {
    1053           3 :     PyObject *poFields = PyObject_GetAttrString(m_poLayer, "fields");
    1054           3 :     if (ErrOccurredEmitCPLError())
    1055           0 :         return;
    1056           3 :     if (PyCallable_Check(poFields))
    1057             :     {
    1058           0 :         PyObject *poFieldsRes = CallPython(poFields);
    1059           0 :         if (ErrOccurredEmitCPLError())
    1060             :         {
    1061           0 :             Py_DecRef(poFields);
    1062             : 
    1063           0 :             return;
    1064             :         }
    1065           0 :         Py_DecRef(poFields);
    1066           0 :         poFields = poFieldsRes;
    1067             :     }
    1068             : 
    1069           3 :     size_t nSize = PySequence_Size(poFields);
    1070           3 :     if (ErrOccurredEmitCPLError())
    1071             :     {
    1072           0 :         Py_DecRef(poFields);
    1073             : 
    1074           0 :         return;
    1075             :     }
    1076          42 :     for (size_t i = 0; i < nSize; i++)
    1077             :     {
    1078          39 :         PyObject *poItem = PySequence_GetItem(poFields, i);
    1079          39 :         if (poItem == nullptr || PyErr_Occurred())
    1080             :         {
    1081           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1082           0 :                      GetPyExceptionString().c_str());
    1083           0 :             Py_DecRef(poFields);
    1084             : 
    1085           0 :             return;
    1086             :         }
    1087             : 
    1088             :         PyObject *key, *value;
    1089          39 :         size_t pos = 0;
    1090          39 :         CPLString osFieldName;
    1091          39 :         OGRFieldType eType = OFTString;
    1092          39 :         OGRFieldSubType eSubType = OFSTNone;
    1093         117 :         while (PyDict_Next(poItem, &pos, &key, &value))
    1094             :         {
    1095          78 :             if (ErrOccurredEmitCPLError())
    1096             :             {
    1097           0 :                 Py_DecRef(poFields);
    1098             : 
    1099           0 :                 return;
    1100             :             }
    1101          78 :             CPLString osKey = GetString(key);
    1102          78 :             if (ErrOccurredEmitCPLError())
    1103             :             {
    1104           0 :                 Py_DecRef(poFields);
    1105             : 
    1106           0 :                 return;
    1107             :             }
    1108          78 :             if (strcmp(osKey, "name") == 0)
    1109             :             {
    1110          39 :                 osFieldName = GetString(value);
    1111          39 :                 if (ErrOccurredEmitCPLError())
    1112             :                 {
    1113           0 :                     Py_DecRef(poFields);
    1114             : 
    1115           0 :                     return;
    1116             :                 }
    1117             :             }
    1118          39 :             else if (strcmp(osKey, "type") == 0)
    1119             :             {
    1120          39 :                 PyObject *myInt = PyLong_FromLong(1);
    1121          39 :                 PyObject *myIntType = PyObject_Type(myInt);
    1122          39 :                 if (PyObject_IsInstance(value, myIntType))
    1123             :                 {
    1124           0 :                     int nType = static_cast<int>(PyLong_AsLong(value));
    1125           0 :                     if (nType < 0 || nType > OFTMaxType)
    1126             :                     {
    1127           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %d",
    1128             :                                  nType);
    1129             :                     }
    1130             :                     else
    1131             :                     {
    1132           0 :                         eType = static_cast<OGRFieldType>(nType);
    1133           0 :                         if (ErrOccurredEmitCPLError())
    1134             :                         {
    1135           0 :                             Py_DecRef(poFields);
    1136             : 
    1137           0 :                             return;
    1138             :                         }
    1139             :                     }
    1140             :                 }
    1141             :                 else
    1142             :                 {
    1143          39 :                     CPLString osValue = GetString(value);
    1144          39 :                     if (ErrOccurredEmitCPLError())
    1145             :                     {
    1146           0 :                         Py_DecRef(poFields);
    1147             : 
    1148           0 :                         return;
    1149             :                     }
    1150          39 :                     if (EQUAL(osValue, "String"))
    1151           9 :                         eType = OFTString;
    1152          30 :                     else if (EQUAL(osValue, "Integer") ||
    1153          57 :                              EQUAL(osValue, "Integer32") ||
    1154          27 :                              EQUAL(osValue, "Int32"))
    1155           3 :                         eType = OFTInteger;
    1156          27 :                     else if (EQUAL(osValue, "Boolean"))
    1157             :                     {
    1158           3 :                         eType = OFTInteger;
    1159           3 :                         eSubType = OFSTBoolean;
    1160             :                     }
    1161          45 :                     else if (EQUAL(osValue, "Integer16") ||
    1162          21 :                              EQUAL(osValue, "Int16"))
    1163             :                     {
    1164           3 :                         eType = OFTInteger;
    1165           3 :                         eSubType = OFSTInt16;
    1166             :                     }
    1167          39 :                     else if (EQUAL(osValue, "Integer64") ||
    1168          18 :                              EQUAL(osValue, "Int64"))
    1169           3 :                         eType = OFTInteger64;
    1170          18 :                     else if (EQUAL(osValue, "Real"))
    1171           3 :                         eType = OFTReal;
    1172          27 :                     else if (EQUAL(osValue, "Float") ||
    1173          12 :                              EQUAL(osValue, "Float32"))
    1174             :                     {
    1175           3 :                         eType = OFTReal;
    1176           3 :                         eSubType = OFSTFloat32;
    1177             :                     }
    1178          12 :                     else if (EQUAL(osValue, "Binary"))
    1179           3 :                         eType = OFTBinary;
    1180           9 :                     else if (EQUAL(osValue, "DateTime"))
    1181           3 :                         eType = OFTDateTime;
    1182           6 :                     else if (EQUAL(osValue, "Date"))
    1183           3 :                         eType = OFTDate;
    1184           3 :                     else if (EQUAL(osValue, "Time"))
    1185           3 :                         eType = OFTTime;
    1186             :                     else
    1187             :                     {
    1188           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %s",
    1189             :                                  osValue.c_str());
    1190             :                     }
    1191             :                 }
    1192          39 :                 Py_DecRef(myInt);
    1193          39 :                 Py_DecRef(myIntType);
    1194             :             }
    1195             :             else
    1196             :             {
    1197           0 :                 CPLDebug("GDAL", "Unknown field property: %s", osKey.c_str());
    1198             :             }
    1199             :         }
    1200             : 
    1201          39 :         if (!osFieldName.empty())
    1202             :         {
    1203          78 :             OGRFieldDefn oFieldDefn(osFieldName, eType);
    1204          39 :             oFieldDefn.SetSubType(eSubType);
    1205          39 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
    1206             :         }
    1207             :     }
    1208             : 
    1209           3 :     Py_DecRef(poFields);
    1210             : }
    1211             : 
    1212             : /************************************************************************/
    1213             : /*                         GetGeomFields()                              */
    1214             : /************************************************************************/
    1215             : 
    1216           3 : void PythonPluginLayer::GetGeomFields() const
    1217             : {
    1218           3 :     PyObject *poFields = PyObject_GetAttrString(m_poLayer, "geometry_fields");
    1219           3 :     if (ErrOccurredEmitCPLError())
    1220           0 :         return;
    1221           3 :     if (PyCallable_Check(poFields))
    1222             :     {
    1223           0 :         PyObject *poFieldsRes = CallPython(poFields);
    1224           0 :         if (ErrOccurredEmitCPLError())
    1225             :         {
    1226           0 :             Py_DecRef(poFields);
    1227             : 
    1228           0 :             return;
    1229             :         }
    1230           0 :         Py_DecRef(poFields);
    1231           0 :         poFields = poFieldsRes;
    1232             :     }
    1233             : 
    1234           3 :     size_t nSize = PySequence_Size(poFields);
    1235           3 :     if (ErrOccurredEmitCPLError())
    1236             :     {
    1237           0 :         Py_DecRef(poFields);
    1238             : 
    1239           0 :         return;
    1240             :     }
    1241           6 :     for (size_t i = 0; i < nSize; i++)
    1242             :     {
    1243           3 :         PyObject *poItem = PySequence_GetItem(poFields, i);
    1244           3 :         if (poItem == nullptr || PyErr_Occurred())
    1245             :         {
    1246           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1247           0 :                      GetPyExceptionString().c_str());
    1248           0 :             Py_DecRef(poFields);
    1249             : 
    1250           0 :             return;
    1251             :         }
    1252             : 
    1253             :         PyObject *key, *value;
    1254           3 :         size_t pos = 0;
    1255           3 :         CPLString osFieldName, osSRS;
    1256           3 :         OGRwkbGeometryType eType = wkbUnknown;
    1257          12 :         while (PyDict_Next(poItem, &pos, &key, &value))
    1258             :         {
    1259           9 :             if (ErrOccurredEmitCPLError())
    1260             :             {
    1261           0 :                 Py_DecRef(poFields);
    1262             : 
    1263           0 :                 return;
    1264             :             }
    1265           9 :             CPLString osKey = GetString(key);
    1266           9 :             if (ErrOccurredEmitCPLError())
    1267             :             {
    1268           0 :                 Py_DecRef(poFields);
    1269             : 
    1270           0 :                 return;
    1271             :             }
    1272           9 :             if (strcmp(osKey, "name") == 0)
    1273             :             {
    1274           3 :                 osFieldName = GetString(value);
    1275           3 :                 if (ErrOccurredEmitCPLError())
    1276             :                 {
    1277           0 :                     Py_DecRef(poFields);
    1278             : 
    1279           0 :                     return;
    1280             :                 }
    1281             :             }
    1282           6 :             else if (strcmp(osKey, "type") == 0)
    1283             :             {
    1284           3 :                 PyObject *myInt = PyLong_FromLong(1);
    1285           3 :                 PyObject *myIntType = PyObject_Type(myInt);
    1286           3 :                 if (PyObject_IsInstance(value, myIntType))
    1287             :                 {
    1288           0 :                     eType =
    1289           0 :                         static_cast<OGRwkbGeometryType>(PyLong_AsLong(value));
    1290           0 :                     if (ErrOccurredEmitCPLError())
    1291             :                     {
    1292           0 :                         Py_DecRef(poFields);
    1293             : 
    1294           0 :                         return;
    1295             :                     }
    1296             :                 }
    1297             :                 else
    1298             :                 {
    1299           3 :                     CPLString osValue = GetString(value);
    1300           3 :                     if (ErrOccurredEmitCPLError())
    1301             :                     {
    1302           0 :                         Py_DecRef(poFields);
    1303             : 
    1304           0 :                         return;
    1305             :                     }
    1306           3 :                     eType = OGRFromOGCGeomType(osValue);
    1307           3 :                     if (eType == wkbUnknown && !EQUAL(osValue, "Geometry"))
    1308             :                     {
    1309           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %s",
    1310             :                                  osValue.c_str());
    1311             :                     }
    1312             :                 }
    1313           3 :                 Py_DecRef(myInt);
    1314           3 :                 Py_DecRef(myIntType);
    1315             :             }
    1316           3 :             else if (strcmp(osKey, "srs") == 0)
    1317             :             {
    1318           3 :                 if (value != Py_None)
    1319             :                 {
    1320           3 :                     osSRS = GetString(value);
    1321           3 :                     if (ErrOccurredEmitCPLError())
    1322             :                     {
    1323           0 :                         Py_DecRef(poFields);
    1324             : 
    1325           0 :                         return;
    1326             :                     }
    1327             :                 }
    1328             :             }
    1329             :             else
    1330             :             {
    1331           0 :                 CPLDebug("GDAL", "Unknown geometry field property: %s",
    1332             :                          osKey.c_str());
    1333             :             }
    1334             :         }
    1335             : 
    1336           6 :         OGRGeomFieldDefn oFieldDefn(osFieldName, eType);
    1337           3 :         if (!osSRS.empty())
    1338             :         {
    1339           3 :             OGRSpatialReference *poSRS = new OGRSpatialReference();
    1340           3 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1341           3 :             poSRS->SetFromUserInput(
    1342             :                 osSRS, OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS);
    1343           3 :             oFieldDefn.SetSpatialRef(poSRS);
    1344           3 :             poSRS->Release();
    1345             :         }
    1346           3 :         m_poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
    1347             :     }
    1348             : 
    1349           3 :     Py_DecRef(poFields);
    1350             : }
    1351             : 
    1352             : /************************************************************************/
    1353             : /*                          GetMetadata()                               */
    1354             : /************************************************************************/
    1355             : 
    1356           0 : static char **GetMetadata(PyObject *obj, const char *pszDomain)
    1357             : {
    1358           0 :     if (!PyObject_HasAttrString(obj, "metadata"))
    1359           0 :         return nullptr;
    1360           0 :     PyObject *poMetadata = PyObject_GetAttrString(obj, "metadata");
    1361           0 :     CPLAssert(poMetadata);
    1362             :     PyObject *poMethodRes;
    1363           0 :     if (PyCallable_Check(poMetadata))
    1364             :     {
    1365           0 :         PyObject *pyArgs = PyTuple_New(1);
    1366           0 :         PyTuple_SetItem(pyArgs, 0,
    1367           0 :                         pszDomain && pszDomain[0]
    1368           0 :                             ? PyUnicode_FromString(pszDomain)
    1369           0 :                             : IncRefAndReturn(Py_None));
    1370           0 :         poMethodRes = PyObject_Call(poMetadata, pyArgs, nullptr);
    1371           0 :         Py_DecRef(pyArgs);
    1372           0 :         Py_DecRef(poMetadata);
    1373             : 
    1374           0 :         if (ErrOccurredEmitCPLError())
    1375             :         {
    1376           0 :             return nullptr;
    1377             :         }
    1378             :     }
    1379             :     else
    1380             :     {
    1381           0 :         poMethodRes = poMetadata;
    1382             :     }
    1383             : 
    1384           0 :     if (poMethodRes == Py_None)
    1385             :     {
    1386           0 :         Py_DecRef(poMethodRes);
    1387           0 :         return nullptr;
    1388             :     }
    1389           0 :     char **papszMD = GetDict(poMethodRes);
    1390           0 :     Py_DecRef(poMethodRes);
    1391           0 :     return papszMD;
    1392             : }
    1393             : 
    1394             : /************************************************************************/
    1395             : /*                          GetMetadata()                               */
    1396             : /************************************************************************/
    1397             : 
    1398           0 : char **PythonPluginLayer::GetMetadata(const char *pszDomain)
    1399             : {
    1400           0 :     GIL_Holder oHolder(false);
    1401           0 :     if (pszDomain == nullptr)
    1402           0 :         pszDomain = "";
    1403           0 :     m_oMapMD[pszDomain] = CPLStringList(::GetMetadata(m_poLayer, pszDomain));
    1404           0 :     return m_oMapMD[pszDomain].List();
    1405             : }
    1406             : 
    1407             : /************************************************************************/
    1408             : /*                         PythonPluginDataset                          */
    1409             : /************************************************************************/
    1410             : 
    1411             : class PythonPluginDataset final : public GDALDataset
    1412             : {
    1413             :     PyObject *m_poDataset = nullptr;
    1414             :     mutable std::map<int, std::unique_ptr<OGRLayer>> m_oMapLayer{};
    1415             :     std::map<CPLString, CPLStringList> m_oMapMD{};
    1416             :     bool m_bHasLayersMember = false;
    1417             : 
    1418             :     PythonPluginDataset(const PythonPluginDataset &) = delete;
    1419             :     PythonPluginDataset &operator=(const PythonPluginDataset &) = delete;
    1420             : 
    1421             :   public:
    1422             :     PythonPluginDataset(GDALOpenInfo *poOpenInfo, PyObject *poDataset);
    1423             :     ~PythonPluginDataset() override;
    1424             : 
    1425             :     int GetLayerCount() const override;
    1426             :     OGRLayer *GetLayer(int) const override;
    1427             :     char **GetMetadata(const char *pszDomain = "") override;
    1428             : };
    1429             : 
    1430             : /************************************************************************/
    1431             : /*                         PythonPluginDataset()                        */
    1432             : /************************************************************************/
    1433             : 
    1434           3 : PythonPluginDataset::PythonPluginDataset(GDALOpenInfo *poOpenInfo,
    1435           3 :                                          PyObject *poDataset)
    1436           3 :     : m_poDataset(poDataset)
    1437             : {
    1438           3 :     SetDescription(poOpenInfo->pszFilename);
    1439             : 
    1440           6 :     GIL_Holder oHolder(false);
    1441             : 
    1442           3 :     const auto poLayers = PyObject_GetAttrString(m_poDataset, "layers");
    1443           3 :     PyErr_Clear();
    1444           3 :     if (poLayers)
    1445             :     {
    1446           3 :         if (PySequence_Check(poLayers))
    1447             :         {
    1448           3 :             m_bHasLayersMember = true;
    1449           3 :             const int nSize = static_cast<int>(PySequence_Size(poLayers));
    1450           6 :             for (int i = 0; i < nSize; i++)
    1451             :             {
    1452           3 :                 const auto poLayer = PySequence_GetItem(poLayers, i);
    1453           3 :                 Py_IncRef(poLayer);
    1454           6 :                 m_oMapLayer[i] = std::unique_ptr<PythonPluginLayer>(
    1455           6 :                     new PythonPluginLayer(poLayer));
    1456             :             }
    1457             :         }
    1458           3 :         Py_DecRef(poLayers);
    1459             :     }
    1460           3 : }
    1461             : 
    1462             : /************************************************************************/
    1463             : /*                        ~PythonPluginDataset()                        */
    1464             : /************************************************************************/
    1465             : 
    1466           6 : PythonPluginDataset::~PythonPluginDataset()
    1467             : {
    1468           6 :     GIL_Holder oHolder(false);
    1469             : 
    1470           3 :     if (m_poDataset && PyObject_HasAttrString(m_poDataset, "close"))
    1471             :     {
    1472           3 :         PyObject *poClose = PyObject_GetAttrString(m_poDataset, "close");
    1473           3 :         PyObject *pyArgs = PyTuple_New(0);
    1474           3 :         Py_DecRef(PyObject_Call(poClose, pyArgs, nullptr));
    1475           3 :         Py_DecRef(pyArgs);
    1476           3 :         Py_DecRef(poClose);
    1477             : 
    1478           3 :         CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
    1479             :     }
    1480           3 :     Py_DecRef(m_poDataset);
    1481           6 : }
    1482             : 
    1483             : /************************************************************************/
    1484             : /*                          GetLayerCount()                             */
    1485             : /************************************************************************/
    1486             : 
    1487           3 : int PythonPluginDataset::GetLayerCount() const
    1488             : {
    1489           3 :     if (m_bHasLayersMember)
    1490           3 :         return static_cast<int>(m_oMapLayer.size());
    1491             : 
    1492           0 :     GIL_Holder oHolder(false);
    1493           0 :     return GetIntRes(m_poDataset, "layer_count");
    1494             : }
    1495             : 
    1496             : /************************************************************************/
    1497             : /*                            GetLayer()                                */
    1498             : /************************************************************************/
    1499             : 
    1500           9 : OGRLayer *PythonPluginDataset::GetLayer(int idx) const
    1501             : {
    1502           9 :     if (idx < 0)
    1503           3 :         return nullptr;
    1504             : 
    1505           6 :     auto oIter = m_oMapLayer.find(idx);
    1506           6 :     if (oIter != m_oMapLayer.end())
    1507           3 :         return m_oMapLayer[idx].get();
    1508             : 
    1509           3 :     if (m_bHasLayersMember)
    1510           3 :         return nullptr;
    1511             : 
    1512           0 :     GIL_Holder oHolder(false);
    1513             : 
    1514           0 :     PyObject *poMethod = PyObject_GetAttrString(m_poDataset, "layer");
    1515           0 :     if (poMethod == nullptr || PyErr_Occurred())
    1516             :     {
    1517           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1518           0 :                  GetPyExceptionString().c_str());
    1519           0 :         return nullptr;
    1520             :     }
    1521             : 
    1522           0 :     PyObject *poMethodRes = CallPython(poMethod, idx);
    1523           0 :     if (ErrOccurredEmitCPLError())
    1524             :     {
    1525           0 :         Py_DecRef(poMethod);
    1526           0 :         return nullptr;
    1527             :     }
    1528           0 :     Py_DecRef(poMethod);
    1529             : 
    1530           0 :     if (poMethodRes == Py_None)
    1531             :     {
    1532           0 :         m_oMapLayer[idx] = nullptr;
    1533           0 :         Py_DecRef(poMethodRes);
    1534           0 :         return nullptr;
    1535             :     }
    1536             :     return m_oMapLayer
    1537           0 :         .insert(std::make_pair(idx, std::unique_ptr<PythonPluginLayer>(
    1538           0 :                                         new PythonPluginLayer(poMethodRes))))
    1539           0 :         .first->second.get();
    1540             : }
    1541             : 
    1542             : /************************************************************************/
    1543             : /*                          GetMetadata()                               */
    1544             : /************************************************************************/
    1545             : 
    1546           0 : char **PythonPluginDataset::GetMetadata(const char *pszDomain)
    1547             : {
    1548           0 :     GIL_Holder oHolder(false);
    1549           0 :     if (pszDomain == nullptr)
    1550           0 :         pszDomain = "";
    1551           0 :     m_oMapMD[pszDomain] = CPLStringList(::GetMetadata(m_poDataset, pszDomain));
    1552           0 :     return m_oMapMD[pszDomain].List();
    1553             : }
    1554             : 
    1555             : /************************************************************************/
    1556             : /*                          PythonPluginDriver                          */
    1557             : /************************************************************************/
    1558             : 
    1559             : class PythonPluginDriver final : public GDALDriver
    1560             : {
    1561             :     CPLMutex *m_hMutex = nullptr;
    1562             :     CPLString m_osFilename;
    1563             :     PyObject *m_poPlugin = nullptr;
    1564             : 
    1565             :     PythonPluginDriver(const PythonPluginDriver &) = delete;
    1566             :     PythonPluginDriver &operator=(const PythonPluginDriver &) = delete;
    1567             : 
    1568             :     bool LoadPlugin();
    1569             : 
    1570             :     int Identify(GDALOpenInfo *);
    1571             :     static int IdentifyEx(GDALDriver *, GDALOpenInfo *);
    1572             : 
    1573             :     GDALDataset *Open(GDALOpenInfo *);
    1574             :     static GDALDataset *OpenEx(GDALDriver *, GDALOpenInfo *);
    1575             : 
    1576             :   public:
    1577             :     PythonPluginDriver(const char *pszFilename, const char *pszPluginName,
    1578             :                        char **papszMD);
    1579             :     ~PythonPluginDriver() override;
    1580             : };
    1581             : 
    1582             : /************************************************************************/
    1583             : /*                            LoadPlugin()                              */
    1584             : /************************************************************************/
    1585             : 
    1586           3 : bool PythonPluginDriver::LoadPlugin()
    1587             : {
    1588           6 :     CPLMutexHolder oMutexHolder(&m_hMutex);
    1589           3 :     if (m_poPlugin)
    1590           0 :         return true;
    1591           3 :     if (!InitializePythonAndLoadGDALPythonDriverModule())
    1592           0 :         return false;
    1593           6 :     GIL_Holder oHolder(false);
    1594             : 
    1595           6 :     CPLString osStr;
    1596           3 :     VSILFILE *fp = VSIFOpenL(m_osFilename, "rb");
    1597           3 :     VSIFSeekL(fp, 0, SEEK_END);
    1598           3 :     auto nSize = VSIFTellL(fp);
    1599           3 :     if (nSize > 10 * 1024 * 1024)
    1600             :     {
    1601           0 :         VSIFCloseL(fp);
    1602           0 :         return false;
    1603             :     }
    1604           3 :     VSIFSeekL(fp, 0, SEEK_SET);
    1605           3 :     osStr.resize(static_cast<size_t>(nSize));
    1606           3 :     VSIFReadL(&osStr[0], 1, static_cast<size_t>(nSize), fp);
    1607           3 :     VSIFCloseL(fp);
    1608             :     PyObject *poCompiledString =
    1609           3 :         Py_CompileString(osStr, m_osFilename, Py_file_input);
    1610           3 :     if (poCompiledString == nullptr || PyErr_Occurred())
    1611             :     {
    1612           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Couldn't compile code:\n%s",
    1613           0 :                  GetPyExceptionString().c_str());
    1614           0 :         return false;
    1615             :     }
    1616           6 :     const CPLString osPluginModuleName(CPLGetBasenameSafe(m_osFilename));
    1617             :     PyObject *poModule =
    1618           3 :         PyImport_ExecCodeModule(osPluginModuleName, poCompiledString);
    1619           3 :     Py_DecRef(poCompiledString);
    1620             : 
    1621           3 :     if (poModule == nullptr || PyErr_Occurred())
    1622             :     {
    1623           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1624           0 :                  GetPyExceptionString().c_str());
    1625           0 :         return false;
    1626             :     }
    1627             : 
    1628           3 :     PyObject *poInstantiate = PyObject_GetAttrString(gpoGDALPythonDriverModule,
    1629             :                                                      "_instantiate_plugin");
    1630           3 :     CPLAssert(poInstantiate);
    1631             : 
    1632           3 :     PyObject *pyArgs = PyTuple_New(1);
    1633           3 :     PyTuple_SetItem(pyArgs, 0, poModule);
    1634           3 :     PyObject *poPlugin = PyObject_Call(poInstantiate, pyArgs, nullptr);
    1635           3 :     Py_DecRef(pyArgs);
    1636           3 :     Py_DecRef(poInstantiate);
    1637             : 
    1638           3 :     if (ErrOccurredEmitCPLError())
    1639             :     {
    1640           1 :         return false;
    1641             :     }
    1642             :     else
    1643             :     {
    1644           2 :         m_poPlugin = poPlugin;
    1645           2 :         return true;
    1646             :     }
    1647             : }
    1648             : 
    1649             : /************************************************************************/
    1650             : /*                       BuildIdentifyOpenArgs()                        */
    1651             : /************************************************************************/
    1652             : 
    1653          11 : static void BuildIdentifyOpenArgs(GDALOpenInfo *poOpenInfo, PyObject *&pyArgs,
    1654             :                                   PyObject *&pyKwargs)
    1655             : {
    1656          11 :     pyArgs = PyTuple_New(3);
    1657          11 :     PyTuple_SetItem(pyArgs, 0, PyUnicode_FromString(poOpenInfo->pszFilename));
    1658          11 :     PyTuple_SetItem(pyArgs, 1,
    1659          11 :                     PyBytes_FromStringAndSize(poOpenInfo->pabyHeader,
    1660          11 :                                               poOpenInfo->nHeaderBytes));
    1661          11 :     PyTuple_SetItem(pyArgs, 2, PyLong_FromLong(poOpenInfo->nOpenFlags));
    1662          11 :     pyKwargs = PyDict_New();
    1663          11 :     PyObject *pyOpenOptions = PyDict_New();
    1664          11 :     PyDict_SetItemString(pyKwargs, "open_options", pyOpenOptions);
    1665          11 :     if (poOpenInfo->papszOpenOptions)
    1666             :     {
    1667          12 :         for (char **papszIter = poOpenInfo->papszOpenOptions; *papszIter;
    1668             :              ++papszIter)
    1669             :         {
    1670           6 :             char *pszKey = nullptr;
    1671           6 :             const char *pszValue = CPLParseNameValue(*papszIter, &pszKey);
    1672           6 :             if (pszKey && pszValue)
    1673             :             {
    1674           6 :                 auto pyValue = PyUnicode_FromString(pszValue);
    1675           6 :                 PyDict_SetItemString(pyOpenOptions, pszKey, pyValue);
    1676           6 :                 Py_DecRef(pyValue);
    1677             :             }
    1678           6 :             CPLFree(pszKey);
    1679             :         }
    1680             :     }
    1681          11 :     Py_DecRef(pyOpenOptions);
    1682          11 : }
    1683             : 
    1684             : /************************************************************************/
    1685             : /*                            Identify()                                */
    1686             : /************************************************************************/
    1687             : 
    1688          10 : int PythonPluginDriver::Identify(GDALOpenInfo *poOpenInfo)
    1689             : {
    1690          10 :     if (m_poPlugin == nullptr)
    1691             :     {
    1692           3 :         if (!LoadPlugin())
    1693           1 :             return FALSE;
    1694             :     }
    1695             : 
    1696          18 :     GIL_Holder oHolder(false);
    1697             : 
    1698           9 :     PyObject *poMethod = PyObject_GetAttrString(m_poPlugin, "identify");
    1699           9 :     if (poMethod == nullptr || PyErr_Occurred())
    1700             :     {
    1701           1 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1702           2 :                  GetPyExceptionString().c_str());
    1703           1 :         return 0;
    1704             :     }
    1705             : 
    1706           8 :     PyObject *pyArgs = nullptr;
    1707           8 :     PyObject *pyKwargs = nullptr;
    1708           8 :     BuildIdentifyOpenArgs(poOpenInfo, pyArgs, pyKwargs);
    1709           8 :     PyObject *poMethodRes = PyObject_Call(poMethod, pyArgs, pyKwargs);
    1710           8 :     Py_DecRef(pyArgs);
    1711           8 :     Py_DecRef(pyKwargs);
    1712             : 
    1713           8 :     if (ErrOccurredEmitCPLError())
    1714             :     {
    1715           0 :         Py_DecRef(poMethod);
    1716           0 :         return 0;
    1717             :     }
    1718           8 :     Py_DecRef(poMethod);
    1719             : 
    1720           8 :     int nRes = static_cast<int>(PyLong_AsLong(poMethodRes));
    1721           8 :     if (ErrOccurredEmitCPLError())
    1722             :     {
    1723           0 :         Py_DecRef(poMethodRes);
    1724           0 :         return 0;
    1725             :     }
    1726             : 
    1727           8 :     Py_DecRef(poMethodRes);
    1728           8 :     return nRes;
    1729             : }
    1730             : 
    1731             : /************************************************************************/
    1732             : /*                            IdentifyEx()                              */
    1733             : /************************************************************************/
    1734             : 
    1735          10 : int PythonPluginDriver::IdentifyEx(GDALDriver *poDrv, GDALOpenInfo *poOpenInfo)
    1736             : {
    1737          10 :     return reinterpret_cast<PythonPluginDriver *>(poDrv)->Identify(poOpenInfo);
    1738             : }
    1739             : 
    1740             : /************************************************************************/
    1741             : /*                               Open()                                 */
    1742             : /************************************************************************/
    1743             : 
    1744           3 : GDALDataset *PythonPluginDriver::Open(GDALOpenInfo *poOpenInfo)
    1745             : {
    1746           3 :     if (m_poPlugin == nullptr)
    1747             :     {
    1748           0 :         if (!LoadPlugin())
    1749           0 :             return nullptr;
    1750             :     }
    1751             : 
    1752           6 :     GIL_Holder oHolder(false);
    1753             : 
    1754           3 :     PyObject *poMethod = PyObject_GetAttrString(m_poPlugin, "open");
    1755           3 :     if (poMethod == nullptr || PyErr_Occurred())
    1756             :     {
    1757           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1758           0 :                  GetPyExceptionString().c_str());
    1759           0 :         return nullptr;
    1760             :     }
    1761             : 
    1762           3 :     PyObject *pyArgs = nullptr;
    1763           3 :     PyObject *pyKwargs = nullptr;
    1764           3 :     BuildIdentifyOpenArgs(poOpenInfo, pyArgs, pyKwargs);
    1765           3 :     PyObject *poMethodRes = PyObject_Call(poMethod, pyArgs, pyKwargs);
    1766           3 :     Py_DecRef(pyArgs);
    1767           3 :     Py_DecRef(pyKwargs);
    1768             : 
    1769           3 :     if (ErrOccurredEmitCPLError())
    1770             :     {
    1771           0 :         Py_DecRef(poMethod);
    1772           0 :         return nullptr;
    1773             :     }
    1774           3 :     Py_DecRef(poMethod);
    1775             : 
    1776           3 :     if (poMethodRes == Py_None)
    1777             :     {
    1778           0 :         Py_DecRef(poMethodRes);
    1779           0 :         return nullptr;
    1780             :     }
    1781           3 :     return new PythonPluginDataset(poOpenInfo, poMethodRes);
    1782             : }
    1783             : 
    1784             : /************************************************************************/
    1785             : /*                              OpenEx()                                */
    1786             : /************************************************************************/
    1787             : 
    1788           3 : GDALDataset *PythonPluginDriver::OpenEx(GDALDriver *poDrv,
    1789             :                                         GDALOpenInfo *poOpenInfo)
    1790             : {
    1791           3 :     return reinterpret_cast<PythonPluginDriver *>(poDrv)->Open(poOpenInfo);
    1792             : }
    1793             : 
    1794             : /************************************************************************/
    1795             : /*                        PythonPluginDriver()                          */
    1796             : /************************************************************************/
    1797             : 
    1798           3 : PythonPluginDriver::PythonPluginDriver(const char *pszFilename,
    1799             :                                        const char *pszPluginName,
    1800           3 :                                        char **papszMD)
    1801           3 :     : m_hMutex(nullptr), m_osFilename(pszFilename), m_poPlugin(nullptr)
    1802             : {
    1803           3 :     SetDescription(pszPluginName);
    1804           3 :     SetMetadata(papszMD);
    1805           3 :     pfnIdentifyEx = IdentifyEx;
    1806           3 :     pfnOpenWithDriverArg = OpenEx;
    1807           3 : }
    1808             : 
    1809             : /************************************************************************/
    1810             : /*                       ~PythonPluginDriver()                          */
    1811             : /************************************************************************/
    1812             : 
    1813           6 : PythonPluginDriver::~PythonPluginDriver()
    1814             : {
    1815           3 :     if (m_hMutex)
    1816           3 :         CPLDestroyMutex(m_hMutex);
    1817             : 
    1818           3 :     if (m_poPlugin)
    1819             :     {
    1820           4 :         GIL_Holder oHolder(false);
    1821           2 :         Py_DecRef(m_poPlugin);
    1822             :     }
    1823           6 : }
    1824             : 
    1825             : /************************************************************************/
    1826             : /*                         LoadPythonDriver()                           */
    1827             : /************************************************************************/
    1828             : 
    1829           5 : static void LoadPythonDriver(const char *pszFilename)
    1830             : {
    1831           5 :     char **papszLines = CSLLoad2(pszFilename, 1000, 1000, nullptr);
    1832           5 :     if (papszLines == nullptr)
    1833             :     {
    1834           0 :         return;
    1835             :     }
    1836          10 :     CPLString osPluginName;
    1837           5 :     char **papszMD = nullptr;
    1838           5 :     bool bAPIOK = false;
    1839           5 :     constexpr int CURRENT_API_VERSION = 1;
    1840         306 :     for (int i = 0; papszLines[i] != nullptr; i++)
    1841             :     {
    1842         301 :         const char *pszLine = papszLines[i];
    1843         301 :         if (!STARTS_WITH_CI(pszLine, "# gdal: DRIVER_"))
    1844         284 :             continue;
    1845          17 :         pszLine += strlen("# gdal: DRIVER_");
    1846             : 
    1847          17 :         const char *pszEqual = strchr(pszLine, '=');
    1848          17 :         if (pszEqual == nullptr)
    1849           0 :             continue;
    1850             : 
    1851          34 :         CPLString osKey(pszLine);
    1852          17 :         osKey.resize(pszEqual - pszLine);
    1853          17 :         osKey.Trim();
    1854             : 
    1855          34 :         CPLString osValue(pszEqual + 1);
    1856          17 :         osValue.Trim();
    1857             : 
    1858          17 :         char chQuote = 0;
    1859          17 :         if (!osValue.empty() && (osValue[0] == '"' || osValue[0] == '\''))
    1860             :         {
    1861          13 :             chQuote = osValue[0];
    1862          13 :             osValue = osValue.substr(1);
    1863             :         }
    1864          17 :         if (!osValue.empty() && osValue[osValue.size() - 1] == chQuote)
    1865          13 :             osValue.resize(osValue.size() - 1);
    1866          17 :         if (EQUAL(osKey, "NAME"))
    1867             :         {
    1868           4 :             osPluginName = std::move(osValue);
    1869             :         }
    1870          13 :         else if (EQUAL(osKey, "SUPPORTED_API_VERSION"))
    1871             :         {
    1872             :             const CPLStringList aosTokens(
    1873           8 :                 CSLTokenizeString2(osValue, "[, ]", 0));
    1874           5 :             for (int j = 0; j < aosTokens.size(); ++j)
    1875             :             {
    1876           4 :                 if (atoi(aosTokens[j]) == CURRENT_API_VERSION)
    1877             :                 {
    1878           3 :                     bAPIOK = true;
    1879           3 :                     break;
    1880             :                 }
    1881             :             }
    1882             :         }
    1883             :         else
    1884             :         {
    1885           9 :             papszMD = CSLSetNameValue(papszMD, osKey.c_str(), osValue);
    1886             :         }
    1887             :     }
    1888           5 :     papszMD = CSLSetNameValue(papszMD, "DRIVER_LANGUAGE", "PYTHON");
    1889           5 :     CSLDestroy(papszLines);
    1890             : 
    1891           5 :     if (osPluginName.empty())
    1892             :     {
    1893           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    1894             :                  "Missing global # gdal: DRIVER_NAME declaration in %s",
    1895             :                  pszFilename);
    1896             :     }
    1897           4 :     else if (!bAPIOK)
    1898             :     {
    1899           1 :         CPLDebug(
    1900             :             "GDAL",
    1901             :             "Plugin %s does not declare # gdal: DRIVER_SUPPORTED_API_VERSION "
    1902             :             "or not at version %d",
    1903             :             osPluginName.c_str(), CURRENT_API_VERSION);
    1904             :     }
    1905           3 :     else if (GDALGetDriverByName(osPluginName) == nullptr)
    1906             :     {
    1907             :         GDALDriver *poDriver =
    1908           3 :             new PythonPluginDriver(pszFilename, osPluginName, papszMD);
    1909           3 :         GetGDALDriverManager()->RegisterDriver(poDriver);
    1910             :     }
    1911           5 :     CSLDestroy(papszMD);
    1912             : }
    1913             : 
    1914             : /************************************************************************/
    1915             : /*                        AutoLoadPythonDrivers()                       */
    1916             : /************************************************************************/
    1917             : 
    1918             : /**
    1919             :  * \brief Auto-load GDAL drivers from Python scripts.
    1920             :  *
    1921             :  * This function will automatically load drivers from Python scripts.
    1922             :  * It searches them first from the directory pointed by the
    1923             :  * GDAL_PYTHON_DRIVER_PATH configuration option. If not defined, it will
    1924             :  * use GDAL_DRIVER_PATH. If not defined, it will use the path for
    1925             :  * drivers hardcoded at build time.
    1926             :  * Scripts must begin with gdal_ or ogr_ and end up with .py
    1927             :  *
    1928             :  * @since GDAL 3.1
    1929             :  */
    1930             : 
    1931        2039 : void GDALDriverManager::AutoLoadPythonDrivers()
    1932             : {
    1933             :     const char *pszPythonDriverPath =
    1934        2039 :         CPLGetConfigOption("GDAL_PYTHON_DRIVER_PATH", nullptr);
    1935        2039 :     if (pszPythonDriverPath == nullptr)
    1936             :     {
    1937        2034 :         pszPythonDriverPath = CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr);
    1938             :     }
    1939        2039 :     char **papszSearchPaths = GetSearchPaths(pszPythonDriverPath);
    1940             : 
    1941             :     /* -------------------------------------------------------------------- */
    1942             :     /*      Format the ABI version specific subdirectory to look in.        */
    1943             :     /* -------------------------------------------------------------------- */
    1944        4078 :     CPLString osABIVersion;
    1945             : 
    1946        2039 :     osABIVersion.Printf("%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
    1947             : 
    1948             :     /* -------------------------------------------------------------------- */
    1949             :     /*      Scan each directory                                             */
    1950             :     /* -------------------------------------------------------------------- */
    1951        4078 :     std::vector<CPLString> aosPythonFiles;
    1952        2039 :     const int nSearchPaths = CSLCount(papszSearchPaths);
    1953        4078 :     for (int iDir = 0; iDir < nSearchPaths; ++iDir)
    1954             :     {
    1955             :         std::string osABISpecificDir =
    1956        4078 :             CPLFormFilenameSafe(papszSearchPaths[iDir], osABIVersion, nullptr);
    1957             : 
    1958             :         VSIStatBufL sStatBuf;
    1959        2039 :         if (VSIStatL(osABISpecificDir.c_str(), &sStatBuf) != 0)
    1960        2039 :             osABISpecificDir = papszSearchPaths[iDir];
    1961             : 
    1962        2039 :         char **papszFiles = CPLReadDir(osABISpecificDir.c_str());
    1963       81384 :         for (int i = 0; papszFiles && papszFiles[i]; i++)
    1964             :         {
    1965      197355 :             if ((STARTS_WITH_CI(papszFiles[i], "gdal_") ||
    1966      150540 :                  STARTS_WITH_CI(papszFiles[i], "ogr_")) &&
    1967      150540 :                 EQUAL(CPLGetExtensionSafe(papszFiles[i]).c_str(), "py"))
    1968             :             {
    1969           5 :                 aosPythonFiles.push_back(CPLFormFilenameSafe(
    1970           5 :                     osABISpecificDir.c_str(), papszFiles[i], nullptr));
    1971             :             }
    1972             :         }
    1973        2039 :         CSLDestroy(papszFiles);
    1974             :     }
    1975        2039 :     CSLDestroy(papszSearchPaths);
    1976             : 
    1977        2044 :     for (const auto &osPythonFile : aosPythonFiles)
    1978             :     {
    1979           5 :         LoadPythonDriver(osPythonFile);
    1980             :     }
    1981        2039 : }
    1982             : 
    1983             : /************************************************************************/
    1984             : /*                        CleanupPythonDrivers()                        */
    1985             : /************************************************************************/
    1986             : 
    1987        1123 : void GDALDriverManager::CleanupPythonDrivers()
    1988             : {
    1989        1123 :     if (gpoGDALPythonDriverModule)
    1990             :     {
    1991             :         // On Windows, with pytest, GDALDestroy() can call this after having
    1992             :         // stopped Python, so do not attempt any Python related action.
    1993           0 :         if (Py_IsInitialized())
    1994             :         {
    1995           0 :             GIL_Holder oHolder(false);
    1996           0 :             Py_DecRef(Py_None);
    1997           0 :             Py_DecRef(gpoGDALPythonDriverModule);
    1998             :         }
    1999           0 :         Py_None = nullptr;
    2000           0 :         gpoGDALPythonDriverModule = nullptr;
    2001             :     }
    2002        1123 : }
    2003             : 
    2004             : #endif

Generated by: LCOV version 1.14