Skip to content

Commit 6381d62

Browse files
committedJun 11, 2013
Use python None object for NULL attributes
1 parent 25244e0 commit 6381d62

File tree

2 files changed

+301
-29
lines changed

2 files changed

+301
-29
lines changed
 

‎python/core/qgsfeature.sip

Lines changed: 250 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,89 @@ typedef qint64 QgsFeatureId;
55
typedef QMap<int, QVariant> QgsAttributeMap;
66

77
typedef QVector<QVariant> QgsAttributes;
8+
// QgsAttributes is implemented as a Python list of Python objects.
9+
%MappedType QgsAttributes /DocType="list-of-attributes"/
10+
{
11+
%TypeHeaderCode
12+
#include <qvector.h>
13+
%End
14+
15+
%ConvertFromTypeCode
16+
// Create the list.
17+
PyObject *l;
18+
19+
if ((l = PyList_New(sipCpp->size())) == NULL)
20+
return NULL;
21+
22+
// Set the list elements.
23+
for (int i = 0; i < sipCpp->size(); ++i)
24+
{
25+
const QVariant& v = sipCpp->at(i);
26+
PyObject *tobj;
27+
28+
if ( v.isNull() )
29+
{
30+
tobj = Py_None;
31+
}
32+
else if ((tobj = sipConvertFromType(&v, sipType_QVariant,Py_None)) == NULL)
33+
{
34+
return NULL;
35+
}
36+
37+
PyList_SET_ITEM(l, i, tobj);
38+
}
39+
40+
return l;
41+
%End
42+
43+
%ConvertToTypeCode
44+
// Check the type if that is all that is required.
45+
if (sipIsErr == NULL)
46+
{
47+
if (!PyList_Check(sipPy))
48+
return 0;
49+
50+
for (SIP_SSIZE_T i = 0; i < PyList_GET_SIZE(sipPy); ++i)
51+
if (!sipCanConvertToType(PyList_GET_ITEM(sipPy, i), sipType_QVariant, SIP_NOT_NONE))
52+
return 0;
53+
54+
return 1;
55+
}
56+
57+
QVector<QVariant> *qv = new QVector<QVariant>;
58+
59+
for (SIP_SSIZE_T i = 0; i < PyList_GET_SIZE(sipPy); ++i)
60+
{
61+
int state;
62+
PyObject* obj = PyList_GET_ITEM(sipPy, i);
63+
QVariant *t;
64+
if ( obj == Py_None )
65+
{
66+
t = new QVariant( QVariant::Int );
67+
}
68+
else
69+
{
70+
t = reinterpret_cast<QVariant *>(sipConvertToType(obj, sipType_QVariant, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr));
71+
72+
if (*sipIsErr)
73+
{
74+
sipReleaseType(t, sipType_QVariant, state);
75+
76+
delete qv;
77+
return 0;
78+
}
79+
}
80+
81+
qv->append(*t);
82+
83+
sipReleaseType(t, sipType_QVariant, state);
84+
}
85+
86+
*sipCppPtr = qv;
87+
88+
return sipGetState(sipTransferObj);
89+
%End
90+
};
891

992
// key = feature id, value = changed attributes
1093
typedef QMap<qint64, QMap<int, QVariant> > QgsChangedAttributesMap;
@@ -38,13 +121,19 @@ class QgsFeature
38121

39122
if (fieldIdx >= 0)
40123
{
41-
QVariant* v = new QVariant( sipCpp->attribute(fieldIdx) );
42-
sipRes = sipConvertFromInstance(v, sipClass_QVariant, Py_None);
124+
const QVariant& v = sipCpp->attribute(fieldIdx);
125+
if ( v.isNull() )
126+
sipRes = Py_None;
127+
else
128+
sipRes = sipConvertFromInstance( &v, sipClass_QVariant, Py_None );
43129
}
44130
else if( altfieldIdx >= 0 )
45131
{
46-
QVariant* v = new QVariant( sipCpp->attribute(altfieldIdx) );
47-
sipRes = sipConvertFromInstance(v, sipClass_QVariant, Py_None);
132+
const QVariant& v = sipCpp->attribute(altfieldIdx);
133+
if ( v.isNull() )
134+
sipRes = Py_None;
135+
else
136+
sipRes = sipConvertFromInstance( &v, sipClass_QVariant, Py_None );
48137
}
49138
else
50139
{
@@ -53,33 +142,50 @@ class QgsFeature
53142
}
54143
%End
55144

56-
void __setattr__(const QString& key, QVariant value);
145+
void __setattr__(const QString& key, QVariant value /GetWrapper/);
57146
%MethodCode
58147
int fieldIdx = sipCpp->fieldNameIndex(*a0);
59148
QString altname = QString(*a0).replace("_"," ");
60149
int altfieldIdx = sipCpp->fieldNameIndex(altname);
61150

62151
if (fieldIdx >= 0)
63152
{
153+
if ( a1Wrapper == Py_None )
154+
{
155+
sipCpp->setAttribute(fieldIdx, QVariant( QVariant::Int ) );
156+
}
157+
else
158+
{
64159
sipCpp->setAttribute(fieldIdx, *a1);
160+
}
65161
}
66162
else if( altfieldIdx >= 0 )
67163
{
164+
if ( a1Wrapper == Py_None )
165+
{
166+
sipCpp->setAttribute(altfieldIdx, QVariant( QVariant::Int ) );
167+
}
168+
else
169+
{
68170
sipCpp->setAttribute(altfieldIdx, *a1);
171+
}
69172
}
70173
else
71174
{
72-
PyObject* key = PyString_FromString(a0->toStdString().c_str());
73-
PyObject* value = sipConvertFromType( a1, sipType_QVariant, sipSelf);
74-
PyObject_GenericSetAttr(sipSelf, key, value);
175+
PyObject* key = PyString_FromString(a0->toStdString().c_str());
176+
PyObject* value = sipConvertFromType( a1, sipType_QVariant, sipSelf);
177+
PyObject_GenericSetAttr(sipSelf, key, value);
75178
}
76179
%End
77180

78181
void __delattr__(const QString& key);
79182
%MethodCode
80183
int fieldIdx = sipCpp->fieldNameIndex(*a0);
81184
if (fieldIdx == -1)
185+
{
82186
PyErr_SetString(PyExc_KeyError, a0->toAscii());
187+
sipIsErr = 1;
188+
}
83189
else
84190
sipCpp->deleteAttribute(fieldIdx);
85191
%End
@@ -88,39 +194,76 @@ class QgsFeature
88194
%MethodCode
89195
const QgsAttributes& attrs = sipCpp->attributes();
90196
if (a0 < 0 || a0 >= attrs.count())
197+
{
91198
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
199+
sipIsErr = 1;
200+
}
92201
else
93202
{
94-
QVariant* v = new QVariant(attrs[a0]);
95-
sipRes = sipConvertFromInstance(v, sipClass_QVariant, Py_None);
203+
const QVariant& v = attrs[a0];
204+
if ( v.isNull() )
205+
sipRes = Py_None;
206+
else
207+
sipRes = sipConvertFromInstance( &v, sipClass_QVariant, Py_None );
96208
}
97209
%End
98210

99211
SIP_PYOBJECT __getitem__(const QString& name);
100212
%MethodCode
101213
int fieldIdx = sipCpp->fieldNameIndex(*a0);
102214
if (fieldIdx == -1)
215+
{
103216
PyErr_SetString(PyExc_KeyError, a0->toAscii());
217+
sipIsErr = 1;
218+
}
104219
else
105220
{
106-
QVariant* v = new QVariant( sipCpp->attribute(fieldIdx) );
107-
sipRes = sipConvertFromInstance(v, sipClass_QVariant, Py_None);
221+
const QVariant& v = sipCpp->attribute(fieldIdx);
222+
if ( v.isNull() )
223+
sipRes = Py_None;
224+
else
225+
sipRes = sipConvertFromInstance( &v, sipClass_QVariant, Py_None );
108226
}
109227
%End
110228

111-
void __setitem__(int key, QVariant value);
229+
void __setitem__(int key, QVariant value /GetWrapper/);
112230
%MethodCode
113-
sipCpp->setAttribute(a0, *a1);
231+
bool rv;
232+
233+
if ( a1Wrapper == Py_None )
234+
{
235+
rv = sipCpp->setAttribute(a0, QVariant( QVariant::Int ) );
236+
}
237+
else
238+
{
239+
rv = sipCpp->setAttribute(a0, *a1);
240+
}
241+
242+
if ( !rv )
243+
{
244+
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
245+
sipIsErr = 1;
246+
}
114247
%End
115248

116-
void __setitem__(const QString& key, QVariant value);
249+
void __setitem__(const QString& key, QVariant value /GetWrapper/);
117250
%MethodCode
118251
int fieldIdx = sipCpp->fieldNameIndex(*a0);
119252
if (fieldIdx == -1)
253+
{
120254
PyErr_SetString(PyExc_KeyError, a0->toAscii());
255+
sipIsErr = 1;
256+
}
121257
else
122258
{
123-
sipCpp->setAttribute(fieldIdx, *a1);
259+
if ( a1Wrapper == Py_None )
260+
{
261+
sipCpp->setAttribute(a0, QVariant( QVariant::Int ) );
262+
}
263+
else
264+
{
265+
sipCpp->setAttribute(fieldIdx, *a1);
266+
}
124267
}
125268
%End
126269

@@ -129,14 +272,20 @@ class QgsFeature
129272
if (a0 >= 0 && a0 < sipCpp->attributes().count())
130273
sipCpp->deleteAttribute(a0);
131274
else
275+
{
132276
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
277+
sipIsErr = 1;
278+
}
133279
%End
134280

135281
void __delitem__(const QString& name);
136282
%MethodCode
137283
int fieldIdx = sipCpp->fieldNameIndex(*a0);
138284
if (fieldIdx == -1)
285+
{
139286
PyErr_SetString(PyExc_KeyError, a0->toAscii());
287+
sipIsErr = 1;
288+
}
140289
else
141290
sipCpp->deleteAttribute(fieldIdx);
142291
%End
@@ -167,12 +316,39 @@ class QgsFeature
167316
const QgsAttributes& attributes() const;
168317
//QgsAttributes& attributes();
169318
void setAttributes(const QgsAttributes& attrs);
170-
bool setAttribute( int field, const QVariant& attr );
319+
bool setAttribute( int field, const QVariant& attr /GetWrapper/);
320+
%MethodCode
321+
bool rv;
322+
323+
if ( a1Wrapper == Py_None )
324+
{
325+
rv = sipCpp->setAttribute(a0, QVariant( QVariant::Int ) );
326+
}
327+
else
328+
{
329+
rv = sipCpp->setAttribute(a0, *a1);
330+
}
331+
332+
if ( !rv )
333+
{
334+
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
335+
sipIsErr = 1;
336+
}
337+
%End
338+
171339
void initAttributes( int fieldCount );
172340

173341
/**Deletes an attribute and its value*/
174342
void deleteAttribute( int field );
175-
343+
%MethodCode
344+
if ( a0 >= 0 && a0 < sipCpp->attributes().count() )
345+
sipCpp->deleteAttribute(a0);
346+
else
347+
{
348+
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
349+
sipIsErr = 1;
350+
}
351+
%End
176352
/**
177353
* Return the validity of this feature. This is normally set by
178354
* the provider to indicate some problem that makes the feature
@@ -229,24 +405,71 @@ class QgsFeature
229405
*/
230406
const QgsFields* fields() const;
231407

232-
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
408+
/** Insert a value into attribute.
409+
* Raises a KeyError exception if the attribute name is not found
233410
* Field map must be associated to make this work.
234411
* @note added in 2.0
235412
*/
236-
bool setAttribute( const QString& name, QVariant value );
237-
238-
/** Remove an attribute value. Returns false if attribute name could not be converted to index.
413+
void setAttribute( const QString& name, QVariant value /GetWrapper/ );
414+
%MethodCode
415+
int fieldIdx = sipCpp->fieldNameIndex(*a0);
416+
if (fieldIdx == -1)
417+
{
418+
PyErr_SetString(PyExc_KeyError, a0->toAscii());
419+
sipIsErr = 1;
420+
}
421+
else
422+
{
423+
if ( a1Wrapper == Py_None )
424+
{
425+
sipCpp->setAttribute(a0, QVariant( QVariant::Int ) );
426+
}
427+
else
428+
{
429+
sipCpp->setAttribute(fieldIdx, *a1);
430+
}
431+
}
432+
%End
433+
/** Remove an attribute value.
434+
* Raises a KeyError exception if the attribute name is not found
239435
* Field map must be associated to make this work.
240436
* @note added in 2.0
241437
*/
242-
bool deleteAttribute( const QString& name );
243-
244-
/** Lookup attribute value from attribute name. Returns invalid variant if attribute name could not be converted to index.
438+
void deleteAttribute( const QString& name );
439+
%MethodCode
440+
int fieldIdx = sipCpp->fieldNameIndex(*a0);
441+
if (fieldIdx == -1)
442+
{
443+
PyErr_SetString(PyExc_KeyError, a0->toAscii());
444+
sipIsErr = 1;
445+
}
446+
else
447+
{
448+
sipCpp->deleteAttribute( fieldIdx );
449+
}
450+
%End
451+
/** Lookup attribute value from attribute name.
452+
* Raises a KeyError exception if the attribute is not found
245453
* Field map must be associated to make this work.
246454
* @note added in 2.0
247455
*/
248-
QVariant attribute( const QString& name ) const;
249-
456+
SIP_PYOBJECT attribute( const QString& name ) const;
457+
%MethodCode
458+
int fieldIdx = sipCpp->fieldNameIndex(*a0);
459+
if (fieldIdx == -1)
460+
{
461+
PyErr_SetString(PyExc_KeyError, a0->toAscii());
462+
sipIsErr = 1;
463+
}
464+
else
465+
{
466+
const QVariant& v = sipCpp->attribute(fieldIdx);
467+
if ( v.isNull() )
468+
sipRes = Py_None;
469+
else
470+
sipRes = sipConvertFromInstance( &v, sipClass_QVariant, Py_None );
471+
}
472+
%End
250473
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
251474
* Field map must be associated to make this work.
252475
* @note added in 2.0

‎src/core/qgsfeature.h

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,32 @@ class CORE_EXPORT QgsFeature
143143
const QgsAttributes& attributes() const { return mAttributes; }
144144
QgsAttributes& attributes() { return mAttributes; }
145145
void setAttributes( const QgsAttributes& attrs ) { mAttributes = attrs; }
146+
147+
/**
148+
* Set an attribute by id
149+
*
150+
* @param field The index of the field to set
151+
* @param attr The value of the attribute
152+
*
153+
* @return false, if the field id does not exist
154+
*
155+
* @note For Python: raises a KeyError exception instead of returning false
156+
*/
146157
bool setAttribute( int field, const QVariant& attr );
158+
159+
/**
160+
* Initialize this feature with the given number of fields. Discard any previously set attribute data.
161+
* @param fieldCount Number of fields to initialize
162+
*/
147163
void initAttributes( int fieldCount );
148164

149-
/**Deletes an attribute and its value*/
165+
/**
166+
* Deletes an attribute and its value
167+
*
168+
* @param field The index of the field
169+
*
170+
* @note For Python: raises a KeyError exception if the field is not found
171+
*/
150172
void deleteAttribute( int field );
151173

152174
/**
@@ -209,29 +231,56 @@ class CORE_EXPORT QgsFeature
209231

210232
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
211233
* Field map must be associated to make this work.
234+
*
235+
* @param name The name of the field to set
236+
* @param value The value to set
237+
*
238+
* @return false if attribute name could not be converted to index (C++ only)
239+
*
240+
* @note For Python: raises a KeyError exception instead of returning false
212241
* @note added in 2.0
213242
*/
214243
bool setAttribute( const QString& name, QVariant value );
215244

216245
/** Remove an attribute value. Returns false if attribute name could not be converted to index.
217246
* Field map must be associated to make this work.
247+
*
248+
* @param name The name of the field to delete
249+
*
250+
* @return false if attribute name could not be converted to index (C++ only)
251+
*
252+
* @note For Python: raises a KeyError exception instead of returning false
218253
* @note added in 2.0
219254
*/
220255
bool deleteAttribute( const QString& name );
221256

222-
/** Lookup attribute value from attribute name. Returns invalid variant if attribute name could not be converted to index.
257+
/** Lookup attribute value from attribute name.
258+
* Returns invalid variant if attribute name could not be converted to index (C++ only)
223259
* Field map must be associated to make this work.
260+
*
261+
* @param name The name of the attribute to get
262+
*
263+
* @return The value of the attribute (C++: Invalid variant if no such name exists )
264+
*
265+
* @note For Python: raises a KeyError exception if field is not found
224266
* @note added in 2.0
225267
*/
226268
QVariant attribute( const QString& name ) const;
227269

228270
/** Lookup attribute value from its index. Returns invalid variant if the index does not exist.
271+
*
272+
* @param fieldIdx The index of the attribute to get
273+
*
274+
* @return The value of the attribute (C++: Invalid variant if no such index exists )
275+
*
276+
* @note For Python: raises a KeyError exception if field is not found
229277
* @note added in 2.0
230278
*/
231279
QVariant attribute( int fieldIdx ) const;
232280

233281
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
234282
* Field map must be associated to make this work.
283+
*
235284
* @note added in 2.0
236285
*/
237286
int fieldNameIndex( const QString& fieldName ) const;

0 commit comments

Comments
 (0)
Please sign in to comment.