[Qgis-developer] calling createEmptyDataSource from python
Stefanie Tellex
stefie10 at media.mit.edu
Thu Jun 5 16:46:35 EDT 2008
Hi,
I wrote a patch that makes it possible to call createEmptyDataSource
from python, against revision 8592. It's kind of big. There are three
parts:
1. Changes to qgisapp.cpp, qgsvectordataprovider.cpp,
qgsvectordataprovider.h
* qgisapp.cpp was looking up createEmptyDataSource dynamically in the
ogr library. I refactored this into a function in
qgsvectordataprovider. This function looks up the real
createEmptyDataSource in exactly the same way, but takes an additional
parameter that is the name of the provider. qgisapp.cpp now calls this
function.
2. Changes to the python interface.
* Updated conversions.sip to convert an std::list<std::pair<TYPE1,
TYPE2>> to and from a list of tuples. I didn't test the "to" code.
(This is required to pass the attributes of the new data source.)
* qgsvectordataprovider.sip - declare the new method, and added an
extra include. (The extra include is needed because it's a function,
not a class method.)
3. Error messages in qgsogrprovider.cpp. I added a bunch of warnings
to createEmptyDataSource to help debug the new code I wrote, when
calling it from python.
Stefanie
(PS: Here's my python test case:
def testNewLayer(self):
try:
print createEmptyDataSource
fname = "newlayertest"
self.assertEqual(os.path.exists(fname), False)
out = createEmptyDataSource("ogr", fname, "ESRI Shapefile",
"System", QGis.WKBLineString,
[("id", "Integer")])
print "out", out
self.assertEqual(out, True)
self.assertEqual(os.path.exists(fname), True)
layer = QgsVectorLayer("%s/%s.shp" % (fname, fname), "test
layer", "ogr")
self.assertEqual(layer.featureCount(), 0)
self.assertEqual(layer.getDataProvider().indexFromFieldName("id"), 0)
finally:
os.system("rm -rf %s" % (fname))
pass
)
Stefanie Tellex wrote:
> Hi,
>
> Is there a way to call the ogr provider's createEmptyDataSource function
> from python? I could try using ctypes, but I wasn't sure if it would
> work with the sip interface. Combining two ways of talking to C/C++
> from python seems hairy.
>
> I played around with adding it via SIP, but it also got hairy. SIP seems
> to like separate modules for C and C++ interfaces, and there aren't
> (yet) provider specific python modules.
>
> I can do the work to add it to the python interface, but advice on the
> best way to do it would be great.
>
> Thanks!
>
> Stefanie
> _______________________________________________
> Qgis-developer mailing list
> Qgis-developer at lists.osgeo.org
> http://lists.osgeo.org/mailman/listinfo/qgis-developer
-------------- next part --------------
Index: qgis/qgis_unstable/src/core/qgsvectordataprovider.cpp
===================================================================
--- qgis.orig/qgis_unstable/src/core/qgsvectordataprovider.cpp 2008-06-05 10:16:54.000000000 -0400
+++ qgis/qgis_unstable/src/core/qgsvectordataprovider.cpp 2008-06-05 16:05:00.000000000 -0400
@@ -18,7 +18,8 @@
#include <cfloat> // for DBL_MAX
#include <climits>
-
+#include <QLibrary>
+#include "qgsproviderregistry.h"
#include "qgsvectordataprovider.h"
#include "qgsfeature.h"
#include "qgsfield.h"
@@ -356,3 +357,42 @@
mCacheMinMaxDirty = FALSE;
}
+
+bool createEmptyDataSource(const QString& provider,
+ const QString& filename,
+ const QString& fileformat,
+ const QString& enc,
+ QGis::WKBTYPE geometrytype,
+ const std::list<std::pair<QString, QString> >& attributes) {
+
+ QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
+ QString lib = pReg->library(provider);
+ // load the data provider
+ QLibrary* myLib = new QLibrary(lib);
+ bool loaded = myLib->load();
+ typedef bool (*createEmptyDataSourceProc)(const QString&, const QString&, const QString&, QGis::WKBTYPE, const std::list<std::pair<QString, QString> >&);
+
+ createEmptyDataSourceProc createEmptyDataSource=(createEmptyDataSourceProc)myLib->resolve("createEmptyDataSource");
+
+ if(createEmptyDataSource)
+ {
+ if(geometrytype != QGis::WKBUnknown)
+ {
+ bool retval = createEmptyDataSource(filename,fileformat, enc, geometrytype, attributes);
+ if (! retval) {
+ QgsLogger::warning("Could not greate data source. See previous messages for details.");
+ }
+ return retval;
+ }
+ else
+ {
+ QgsLogger::warning("geometry type not recognised");
+ return FALSE;
+ }
+ }
+ else
+ {
+ QgsLogger::warning("Resolving newEmptyDataSource(...) failed");
+ return FALSE;
+ }
+}
Index: qgis/qgis_unstable/src/core/qgsvectordataprovider.h
===================================================================
--- qgis.orig/qgis_unstable/src/core/qgsvectordataprovider.h 2008-06-05 12:17:20.000000000 -0400
+++ qgis/qgis_unstable/src/core/qgsvectordataprovider.h 2008-06-05 12:37:57.000000000 -0400
@@ -295,4 +295,11 @@
QSet<QString> mSupportedNativeTypes;
};
+bool createEmptyDataSource(const QString& provider,
+ const QString& filename,
+ const QString& fileformat,
+ const QString& enc,
+ QGis::WKBTYPE geometrytype,
+ const std::list<std::pair<QString, QString> >& attributes);
+
#endif
Index: qgis/qgis_unstable/src/app/qgisapp.cpp
===================================================================
--- qgis.orig/qgis_unstable/src/app/qgisapp.cpp 2008-06-05 12:33:57.000000000 -0400
+++ qgis/qgis_unstable/src/app/qgisapp.cpp 2008-06-05 16:12:36.000000000 -0400
@@ -2683,51 +2683,13 @@
settings.writeEntry("/UI/encoding", openFileDialog->encoding());
delete openFileDialog;
-
- //try to create the new layer with OGRProvider instead of QgsVectorFileWriter
- QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
- QString ogrlib = pReg->library("ogr");
- // load the data provider
- QLibrary* myLib = new QLibrary(ogrlib);
- bool loaded = myLib->load();
- if (loaded)
- {
- QgsDebugMsg("ogr provider loaded");
-
- typedef bool (*createEmptyDataSourceProc)(const QString&, const QString&, const QString&, QGis::WKBTYPE, \
- const std::list<std::pair<QString, QString> >&);
- createEmptyDataSourceProc createEmptyDataSource=(createEmptyDataSourceProc)myLib->resolve("createEmptyDataSource");
- if(createEmptyDataSource)
- {
-#if 0
- if(geometrytype == QGis::WKBPoint)
- {
- createEmptyDataSource(filename,fileformat, enc, QGis::WKBPoint, attributes);
- }
- else if (geometrytype == QGis::WKBLineString)
- {
- createEmptyDataSource(filename,fileformat, enc, QGis::WKBLineString, attributes);
- }
- else if(geometrytype == QGis::WKBPolygon)
- {
- createEmptyDataSource(filename,fileformat, enc, QGis::WKBPolygon, attributes);
- }
-#endif
- if(geometrytype != QGis::WKBUnknown)
- {
- createEmptyDataSource(filename,fileformat, enc, geometrytype, attributes);
- }
- else
- {
- QgsDebugMsg("geometry type not recognised");
- return;
- }
- }
- else
- {
- QgsDebugMsg("Resolving newEmptyDataSource(...) failed");
+ QgsLogger::warning("format");
+ QgsLogger::warning(fileformat);
+ if (!createEmptyDataSource("ogr", filename, fileformat, enc,
+ geometrytype, attributes)) {
+ QgsDebugMsg("Data source not created");
+ return;
}
- }
//then add the layer to the view
QStringList filenames;
Index: qgis/qgis_unstable/python/core/qgsvectordataprovider.sip
===================================================================
--- qgis.orig/qgis_unstable/python/core/qgsvectordataprovider.sip 2008-06-05 12:46:07.000000000 -0400
+++ qgis/qgis_unstable/python/core/qgsvectordataprovider.sip 2008-06-05 15:17:36.000000000 -0400
@@ -1,4 +1,9 @@
+%ModuleHeaderCode
+#include <qgsvectordataprovider.h>
+%End
+
+
class QgsVectorDataProvider : QgsDataProvider
{
%TypeHeaderCode
@@ -239,3 +244,9 @@
void setFetchFeaturesWithoutGeom(bool fetch);
};
+bool createEmptyDataSource(const QString& provider,
+ const QString& filename,
+ const QString& fileformat,
+ const QString& enc,
+ QGis::WKBTYPE geometrytype,
+ const std::list<std::pair<QString, QString> >& attributes);
Index: qgis/qgis_unstable/python/core/conversions.sip
===================================================================
--- qgis.orig/qgis_unstable/python/core/conversions.sip 2008-06-05 14:47:51.000000000 -0400
+++ qgis/qgis_unstable/python/core/conversions.sip 2008-06-05 16:32:35.000000000 -0400
@@ -8,6 +8,7 @@
- QMap<int, QMap<int, TYPE> >
- QMap<TYPE1, TYPE2*>
- QMultiMap<double, TYPE2>
+- std::list<std::pair<TYPE1, TYPE2>>
*/
%ModuleHeaderCode
@@ -631,3 +632,115 @@
return sipGetState(sipTransferObj);
%End
};
+
+
+
+
+
+template<TYPE1, TYPE2>
+%MappedType std::list<std::pair<TYPE1, TYPE2>>
+{
+%TypeHeaderCode
+#include <list>
+#include <utility>
+%End
+
+%ConvertFromTypeCode
+ // Create the dictionary.
+ PyObject *list = PyList_New(0);
+
+ if (!list)
+ return NULL;
+
+ // Set the dictionary elements.
+ std::list<std::pair<TYPE1, TYPE2> >::const_iterator i = sipCpp->begin();
+
+ while (i != sipCpp->end())
+ {
+ TYPE1 t1 = i->first;
+ TYPE2 t2 = i->second;
+
+ PyObject *t1obj = sipConvertFromNewInstance(&t1, sipClass_TYPE1, sipTransferObj);
+ PyObject *t2obj = sipConvertFromInstance(&t2, sipClass_TYPE2, sipTransferObj);
+
+ PyObject *tuple = PyTuple_New(2);
+ if (PyTuple_SetItem(tuple, 0, t1obj) ||
+ PyTuple_SetItem(tuple, 1, t2obj) ||
+ PyList_Append(list, tuple)) {
+ Py_DECREF(list);
+ if (t1obj) {
+ Py_DECREF(t1obj);
+ }
+ if (t2obj) {
+ Py_DECREF(t2obj);
+ }
+ if (tuple) {
+ Py_DECREF(tuple);
+ }
+ return NULL;
+ }
+
+ Py_DECREF(t1obj);
+ Py_DECREF(t2obj);
+
+ ++i;
+ }
+
+ return list;
+%End
+
+%ConvertToTypeCode
+ PyObject *t1obj, *t2obj;
+#if PY_VERSION_HEX >= 0x02050000
+ Py_ssize_t i = 0;
+#else
+ int i = 0;
+#endif
+
+ // Check the type if that is all that is required.
+ if (sipIsErr == NULL)
+ {
+ if (!PyList_Check(sipPy))
+ return 0;
+
+ for (i = 0; i < PyList_Size(sipPy); i++) {
+ PyObject * tuple = PyList_GetItem(sipPy, i);
+ t1obj = PyTuple_GetItem(tuple, 0);
+ t2obj = PyTuple_GetItem(tuple, 1);
+ if (!sipCanConvertToInstance(t1obj, sipClass_TYPE1, SIP_NOT_NONE))
+ return 0;
+
+ if (!sipCanConvertToInstance(t2obj, sipClass_TYPE2, SIP_NOT_NONE))
+ return 0;
+ }
+ return 1;
+ }
+
+ std::list<std::pair<TYPE1, TYPE2> > *list = new std::list<std::pair<TYPE1, TYPE2> >;
+ for (i = 0; i < PyList_Size(sipPy); i++) {
+ int state1, state2;
+ PyObject * tuple = PyList_GetItem(sipPy, i);
+ PyObject * sip1 = PyTuple_GetItem(tuple, 0);
+ PyObject * sip2 = PyTuple_GetItem(tuple, 1);
+
+ TYPE1 * t1 = reinterpret_cast<TYPE1 *>(sipConvertToInstance(sip1, sipClass_TYPE1, sipTransferObj, SIP_NOT_NONE, &state1, sipIsErr));
+ TYPE2 * t2 = reinterpret_cast<TYPE2 *>(sipConvertToInstance(sip2, sipClass_TYPE2, sipTransferObj, SIP_NOT_NONE, &state2, sipIsErr));
+ if (*sipIsErr)
+ {
+ sipReleaseInstance(t1, sipClass_TYPE1, state1);
+ sipReleaseInstance(t2, sipClass_TYPE2, state2);
+ delete list;
+ return 0;
+ }
+
+ list->push_back(std::pair<TYPE1, TYPE2>(*t1, *t2));
+ sipReleaseInstance(t1, sipClass_TYPE1, state1);
+ sipReleaseInstance(t2, sipClass_TYPE2, state2);
+ }
+
+ *sipCppPtr = list;
+
+ return sipGetState(sipTransferObj);
+%End
+};
+
Index: qgis/qgis_unstable/src/providers/ogr/qgsogrprovider.cpp
===================================================================
--- qgis.orig/qgis_unstable/src/providers/ogr/qgsogrprovider.cpp 2008-06-05 16:03:12.000000000 -0400
+++ qgis/qgis_unstable/src/providers/ogr/qgsogrprovider.cpp 2008-06-05 16:32:32.000000000 -0400
@@ -1132,6 +1132,10 @@
driver = OGRGetDriverByName(format.toAscii());
if(driver == NULL)
{
+ QString msg = "Failed to get the driver.";
+ msg.append(" Name: ");
+ msg.append(format);
+ QgsLogger::warning(msg);
return false;
}
@@ -1139,6 +1143,7 @@
dataSource = OGR_Dr_CreateDataSource(driver,QFile::encodeName(uri).constData(), NULL);
if(dataSource == NULL)
{
+ QgsLogger::warning("Failed to create the data source.");
return false;
}
@@ -1177,8 +1182,7 @@
break;
default:
{
- QgsLogger::debug("Unknown vector type of: ", (int)(vectortype), 1,
- __FILE__, __FUNCTION__, __LINE__);
+ QgsLogger::warning("Unknown vector type of");
return false;
break;
}
@@ -1188,6 +1192,7 @@
layer = OGR_DS_CreateLayer(dataSource,QFile::encodeName(QFileInfo(uri).baseName()).constData(), reference, OGRvectortype, NULL);
if(layer == NULL)
{
+ QgsLogger::warning("Could not create layer");
return false;
}
@@ -1224,6 +1229,12 @@
QgsLogger::warning("creation of OFTString field failed");
}
}
+ else {
+ QString msg = "Unknown attribute type. Ignoring attribute. ";
+ msg.append(" Type: ");
+ msg.append(it->second);
+ QgsLogger::warning(msg);
+ }
}
OGR_DS_Destroy(dataSource);
More information about the Qgis-developer
mailing list