Skip to content
Permalink
Browse files

[processing] Port refactor fields to new API

  • Loading branch information
arnaud-morvan authored and m-kuhn committed Jul 21, 2017
1 parent 2364801 commit b3a9e46cfee2bd57428294bb00c655d008d83663
@@ -40,6 +40,8 @@ class QgsProcessingOutputDefinition
sipType = sipType_QgsProcessingOutputString;
else if ( sipCpp->type() == QgsProcessingOutputFolder::typeName() )
sipType = sipType_QgsProcessingOutputFolder;
else
sipType = nullptr;
%End
public:

@@ -191,6 +191,8 @@ class QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterFolderDestination;
else if ( sipCpp->type() == QgsProcessingParameterBand::typeName() )
sipType = sipType_QgsProcessingParameterBand;
else
sipType = nullptr;
%End
public:

@@ -25,159 +25,141 @@

__revision__ = '$Format:%H$'

from qgis.core import (QgsField,
QgsFields,
QgsExpression,
QgsDistanceArea,
QgsFeatureSink,
QgsProject,
QgsFeature,
QgsApplication,
QgsProcessingUtils)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterTable
from processing.core.parameters import Parameter
from processing.core.outputs import OutputVector


class FieldsMapper(QgisAlgorithm):
from qgis.core import (
QgsApplication,
QgsDistanceArea,
QgsExpression,
QgsFeature,
QgsFeatureSink,
QgsField,
QgsFields,
QgsProcessingException,
QgsProcessingParameterDefinition,
QgsProcessingUtils,
QgsProject,
)

from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm


class FieldsMapper(QgisFeatureBasedAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
FIELDS_MAPPING = 'FIELDS_MAPPING'
OUTPUT_LAYER = 'OUTPUT_LAYER'

def __init__(self):
GeoAlgorithm.__init__(self)
self.mapping = None

def group(self):
return self.tr('Vector table tools')

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterTable(self.INPUT_LAYER,
self.tr('Input layer'),
False))
def initParameters(self, config=None):

class ParameterFieldsMapping(Parameter):
class ParameterFieldsMapping(QgsProcessingParameterDefinition):

default_metadata = {
'widget_wrapper': 'processing.algs.qgis.ui.FieldsMappingPanel.FieldsMappingWidgetWrapper'
}
def __init__(self, name, description, parentLayerParameterName='INPUT'):
super().__init__(name, description)
self._parentLayerParameter = parentLayerParameterName

def __init__(self, name='', description='', parent=None):
Parameter.__init__(self, name, description)
self.parent = parent
self.value = []
def type(self):
return 'fields_mapping'

def getValueAsCommandLineParameter(self):
return '"' + str(self.value) + '"'

def setValue(self, value):
if value is None:
def checkValueIsAcceptable(self, value, context):
if not isinstance(value, list):
return False
if isinstance(value, list):
self.value = value
return True
if isinstance(value, str):
try:
self.value = eval(value)
return True
except Exception as e:
# fix_print_with_import
print(str(e)) # display error in console
for field_def in value:
if not isinstance(field_def, dict):
return False
if not field_def.get('name', False):
return False
if not field_def.get('type', False):
return False
if not field_def.get('expression', False):
return False
return False
return True

self.addParameter(ParameterFieldsMapping(self.FIELDS_MAPPING,
self.tr('Fields mapping'),
self.INPUT_LAYER))
self.addOutput(OutputVector(self.OUTPUT_LAYER,
self.tr('Refactored'),
base_input=self.INPUT_LAYER))
def valueAsPythonString(self, value, context):
return str(value)

def asScriptCode(self):
raise NotImplementedError()

@classmethod
def fromScriptCode(cls, name, description, isOptional, definition):
raise NotImplementedError()

def parentLayerParameter(self):
return self._parentLayerParameter

fields_mapping = ParameterFieldsMapping(self.FIELDS_MAPPING,
description=self.tr('Fields mapping'))
fields_mapping.setMetadata({
'widget_wrapper': 'processing.algs.qgis.ui.FieldsMappingPanel.FieldsMappingWidgetWrapper'
})
self.addParameter(fields_mapping)

def name(self):
return 'refactorfields'

def displayName(self):
return self.tr('Refactor fields')

def processAlgorithm(self, parameters, context, feedback):
layer = self.getParameterValue(self.INPUT_LAYER)
mapping = self.getParameterValue(self.FIELDS_MAPPING)
output = self.getOutputFromName(self.OUTPUT_LAYER)
def outputName(self):
return self.tr('Refactored')

layer = QgsProcessingUtils.mapLayerFromString(layer, context)
fields = QgsFields()
expressions = []
def parameterAsFieldsMapping(self, parameters, name, context):
return parameters[name]

def prepareAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, 'INPUT', context)
mapping = self.parameterAsFieldsMapping(parameters, self.FIELDS_MAPPING, context)

self.fields = QgsFields()
self.expressions = []

da = QgsDistanceArea()
da.setSourceCrs(layer.crs())
da.setSourceCrs(source.sourceCrs())
da.setEllipsoid(context.project().ellipsoid())

exp_context = layer.createExpressionContext()

for field_def in mapping:
fields.append(QgsField(field_def['name'],
field_def['type'],
field_def['length'],
field_def['precision']))

self.fields.append(QgsField(name=field_def['name'],
type=field_def['type'],
typeName="",
len=field_def.get('length', 0),
prec=field_def.get('precision', 0)))
expression = QgsExpression(field_def['expression'])
expression.setGeomCalculator(da)
expression.setDistanceUnits(context.project().distanceUnits())
expression.setAreaUnits(context.project().areaUnits())
expression.prepare(exp_context)
if expression.hasParserError():
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr(u'Parser error in expression "{}": {}')
.format(str(expression.expression()),
str(expression.parserErrorString())))
expressions.append(expression)

writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(), context)

# Create output vector layer with new attributes
error_exp = None
inFeat = QgsFeature()
outFeat = QgsFeature()
features = QgsProcessingUtils.getFeatures(layer, context)
count = QgsProcessingUtils.featureCount(layer, context)
if count > 0:
total = 100.0 / count
for current, inFeat in enumerate(features):
rownum = current + 1

geometry = inFeat.geometry()
outFeat.setGeometry(geometry)

attrs = []
for i in range(0, len(mapping)):
field_def = mapping[i]
expression = expressions[i]
exp_context.setFeature(inFeat)
exp_context.lastScope().setVariable("row_number", rownum)
value = expression.evaluate(exp_context)
if expression.hasEvalError():
error_exp = expression
break

attrs.append(value)
outFeat.setAttributes(attrs)

writer.addFeature(outFeat, QgsFeatureSink.FastInsert)

feedback.setProgress(int(current * total))
else:
feedback.setProgress(100)

del writer

if error_exp is not None:
raise GeoAlgorithmExecutionException(
self.tr(u'Evaluation error in expression "{}": {}')
.format(str(error_exp.expression()),
str(error_exp.parserErrorString())))
self.expressions.append(expression)
return True

def outputFields(self, inputFields):
return self.fields

def processAlgorithm(self, parameters, context, feeback):
# create an expression context using thead safe processing context
self.expr_context = self.createExpressionContext(parameters, context)
for expression in self.expressions:
expression.prepare(self.expr_context)
self._row_number = 0
return super().processAlgorithm(parameters, context, feeback)

def processFeature(self, feature, feedback):
attributes = []
for expression in self.expressions:
self.expr_context.setFeature(feature)
self.expr_context.lastScope().setVariable("row_number", self._row_number)
value = expression.evaluate(self.expr_context)
if expression.hasEvalError():
raise QgsProcessingException(
self.tr(u'Evaluation error in expression "{}": {}')
.format(str(expression.expression()),
str(expression.parserErrorString())))
attributes.append(value)
feature.setAttributes(attributes)
self._row_number += 1
return feature
@@ -160,7 +160,7 @@
# from .SetRasterStyle import SetRasterStyle
# from .SelectByAttributeSum import SelectByAttributeSum
# from .HypsometricCurves import HypsometricCurves
# from .FieldsMapper import FieldsMapper
from .FieldsMapper import FieldsMapper
# from .Datasources2Vrt import Datasources2Vrt
# from .OrientedMinimumBoundingBox import OrientedMinimumBoundingBox
# from .DefineProjection import DefineProjection
@@ -231,6 +231,7 @@ def getAlgs(self):
ExtentFromLayer(),
ExtractNodes(),
ExtractSpecificNodes(),
FieldsMapper(),
FixedDistanceBuffer(),
FixGeometry(),
GeometryByExpression(),

0 comments on commit b3a9e46

Please sign in to comment.
You can’t perform that action at this time.