6

I am trying create new columns in an attribute table and fill them with values with expressions using Python Console in QGIS.

I successfully create the new columns but when I try to fill them, I get an assertion error. Here is an example for one column :

layer=QgsVectorLayer(r"C:\Users\ANI\Documents\SIG\fossés\pythontest\mergedlinef1.shp")
features=layer.getFeatures()

layer_provider=layer.dataProvider()
layer_provider.addAttributes([QgsField("long",QVariant.Double)])
layer.updateFields()

layer.startEditing()
exp_long = QgsExpression("$length")
context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

with edit(layer):
    for f in layer.getFeatures():
        context.SetFeature(f)
        f['long'] = exp_long.evaluate(context)
        layer.updateFeature(f)

And the error :

Traceback (most recent call last):
  File "C:\PROGRA~1\QGIS32~1.0\apps\Python39\lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "<string>", line 23, in <module>
  File "C:\PROGRA~1/QGIS32~1.0/apps/qgis/./python\qgis\core\additions\edit.py", line 38, in __enter__
    assert self.layer.startEditing()
AssertionError

Line 23 refers to the line with edit(layer):. What am I doing wrong ?

1 Answer 1

5

Your AssertionError appeared because of the with edit(layer): which was used just after the layer was already brought to the edit mode with layer.startEditing(), so there is no need to double edit it.

A solution is to erase the first statement layer.startEditing(). Another workaround was shown in this thread Setting attribute values using PyQGIS in an edit session.

layer=QgsVectorLayer(r"C:\Users\ANI\Documents\SIG\fossés\pythontest\mergedlinef1.shp")
features=layer.getFeatures()

layer_provider=layer.dataProvider()
layer_provider.addAttributes([QgsField("long",QVariant.Double)])
layer.updateFields()

exp_long = QgsExpression("$length")
context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

with edit(layer):
    for f in layer.getFeatures():
        context.setFeature(f)
        f['long'] = exp_long.evaluate(context)
        layer.updateFeature(f)

Ongoing another error AttributeError: 'QgsExpressionContext' object has no attribute 'SetFeature' will appear because of the SetFeature(f) method which should be setFeature(f).

To simplify your code, you can write it as this

layer = QgsVectorLayer(r"C:\Users\ANI\Documents\SIG\fossés\pythontest\mergedlinef1.shp")
fields = layer.fields()
fields_names = layer.fields().names()

new_field = "long"

if new_field not in fields_names:
    layer_provider = layer.dataProvider()
    layer_provider.addAttributes([QgsField(new_field, QVariant.Double)])
    layer.updateFields()

layer.startEditing()

for feature in layer.getFeatures():
    feature[new_field] = feature.geometry().length()
    layer.updateFeature(feature)

layer.commitChanges()

However, note the differences between $length and length($geometry):

From the QGIS Documentation:

$length:

Returns the length of a linestring. If you need the length of a border of a polygon, use $perimeter instead. The length calculated by this function respects both the current project’s ellipsoid setting and distance unit settings. For example, if an ellipsoid has been set for the project then the calculated length will be ellipsoidal, and if no ellipsoid is set then the calculated length will be planimetric.

length($geometry):

Returns the number of characters in a string or the length of a geometry linestring.


References:

1
  • 1
    Thank you, problem solved!
    – Anthony
    Apr 5, 2022 at 9:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.