29
29
import sys
30
30
31
31
from qgis .PyQt .QtCore import QVariant
32
- from qgis .core import (QgsFeature ,
32
+ from qgis .core import (QgsProcessingException ,
33
33
QgsField ,
34
34
QgsFeatureSink ,
35
- QgsApplication ,
36
- QgsProcessingUtils )
35
+ QgsProcessingParameterFeatureSource ,
36
+ QgsProcessingParameterString ,
37
+ QgsProcessingParameterEnum ,
38
+ QgsProcessingParameterNumber ,
39
+ QgsProcessingParameterFeatureSink )
37
40
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
38
- from processing .core .GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
39
- from processing .core .parameters import ParameterVector
40
- from processing .core .parameters import ParameterString
41
- from processing .core .parameters import ParameterNumber
42
- from processing .core .parameters import ParameterSelection
43
- from processing .core .outputs import OutputVector
44
41
45
42
46
43
class FieldsPyculator (QgisAlgorithm ):
47
44
48
- INPUT_LAYER = 'INPUT_LAYER '
45
+ INPUT = 'INPUT '
49
46
FIELD_NAME = 'FIELD_NAME'
50
47
FIELD_TYPE = 'FIELD_TYPE'
51
48
FIELD_LENGTH = 'FIELD_LENGTH'
52
49
FIELD_PRECISION = 'FIELD_PRECISION'
53
50
GLOBAL = 'GLOBAL'
54
51
FORMULA = 'FORMULA'
55
- OUTPUT_LAYER = 'OUTPUT_LAYER '
52
+ OUTPUT = 'OUTPUT '
56
53
RESULT_VAR_NAME = 'value'
57
54
58
55
TYPES = [QVariant .Int , QVariant .Double , QVariant .String ]
@@ -68,21 +65,21 @@ def initAlgorithm(self, config=None):
68
65
self .tr ('Float' ),
69
66
self .tr ('String' )]
70
67
71
- self .addParameter (ParameterVector (self .INPUT_LAYER ,
72
- self .tr ( 'Input layer' )))
73
- self .addParameter ( ParameterString ( self . FIELD_NAME ,
74
- self .tr ( 'Result field name' ), 'NewField' ))
75
- self .addParameter ( ParameterSelection ( self .FIELD_TYPE ,
76
- self .tr ( 'Field type' ), self .type_names ))
77
- self .addParameter ( ParameterNumber ( self . FIELD_LENGTH ,
78
- self .tr ( 'Field length' ), 1 , 255 , 10 ))
79
- self .addParameter ( ParameterNumber ( self . FIELD_PRECISION ,
80
- self .tr ( 'Field precision' ), 0 , 10 , 0 ))
81
- self .addParameter ( ParameterString ( self . GLOBAL ,
82
- self .tr ( 'Global expression' ), multiline = True , optional = True ))
83
- self .addParameter ( ParameterString ( self . FORMULA ,
84
- self .tr ( 'Formula' ), 'value = ' , multiline = True ))
85
- self . addOutput ( OutputVector ( self . OUTPUT_LAYER , self .tr ('Calculated' )))
68
+ self .addParameter (QgsProcessingParameterFeatureSource (self .INPUT , self . tr ( 'Input layer' )))
69
+ self .addParameter ( QgsProcessingParameterString ( self . FIELD_NAME ,
70
+ self .tr ( 'Result field name' ), defaultValue = 'NewField' ))
71
+ self .addParameter ( QgsProcessingParameterEnum ( self . FIELD_TYPE ,
72
+ self .tr ( 'Field type' ), options = self .type_names ))
73
+ self .addParameter ( QgsProcessingParameterNumber ( self .FIELD_LENGTH ,
74
+ self .tr ( 'Field length' ), minValue = 1 , maxValue = 255 , defaultValue = 10 ))
75
+ self .addParameter ( QgsProcessingParameterNumber ( self . FIELD_PRECISION ,
76
+ self .tr ( 'Field precision' ), minValue = 0 , maxValue = 15 , defaultValue = 3 ))
77
+ self .addParameter ( QgsProcessingParameterString ( self . GLOBAL ,
78
+ self .tr ( 'Global expression' ), multiLine = True , optional = True ))
79
+ self .addParameter ( QgsProcessingParameterString ( self . FORMULA ,
80
+ self .tr ( 'Formula' ), defaultValue = 'value = ' , multiLine = True ))
81
+ self .addParameter ( QgsProcessingParameterFeatureSink ( self . OUTPUT ,
82
+ self .tr ('Calculated' )))
86
83
87
84
def name (self ):
88
85
return 'advancedpythonfieldcalculator'
@@ -91,33 +88,33 @@ def displayName(self):
91
88
return self .tr ('Advanced Python field calculator' )
92
89
93
90
def processAlgorithm (self , parameters , context , feedback ):
94
- fieldName = self .getParameterValue (self .FIELD_NAME )
95
- fieldType = self .getParameterValue (self .FIELD_TYPE )
96
- fieldLength = self .getParameterValue (self .FIELD_LENGTH )
97
- fieldPrecision = self .getParameterValue (self .FIELD_PRECISION )
98
- code = self .getParameterValue (self .FORMULA )
99
- globalExpression = self .getParameterValue (self .GLOBAL )
100
- output = self .getOutputFromName (self .OUTPUT_LAYER )
101
-
102
- layer = QgsProcessingUtils .mapLayerFromString (self .getParameterValue (self .INPUT_LAYER ), context )
103
- fields = layer .fields ()
104
- fields .append (QgsField (fieldName , self .TYPES [fieldType ], '' ,
105
- fieldLength , fieldPrecision ))
106
- writer = output .getVectorWriter (fields , layer .wkbType (), layer .crs (), context )
107
- outFeat = QgsFeature ()
91
+ source = self .parameterAsSource (parameters , self .INPUT , context )
92
+ field_name = self .parameterAsString (parameters , self .FIELD_NAME , context )
93
+ field_type = self .TYPES [self .parameterAsEnum (parameters , self .FIELD_TYPE , context )]
94
+ width = self .parameterAsInt (parameters , self .FIELD_LENGTH , context )
95
+ precision = self .parameterAsInt (parameters , self .FIELD_PRECISION , context )
96
+ code = self .parameterAsString (parameters , self .FORMULA , context )
97
+ globalExpression = self .parameterAsString (parameters , self .GLOBAL , context )
98
+
99
+ fields = source .fields ()
100
+ fields .append (QgsField (field_name , self .TYPES [field_type ], '' ,
101
+ width , precision ))
108
102
new_ns = {}
109
103
104
+ (sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
105
+ fields , source .wkbType (), source .sourceCrs ())
106
+
110
107
# Run global code
111
108
if globalExpression .strip () != '' :
112
109
try :
113
110
bytecode = compile (globalExpression , '<string>' , 'exec' )
114
111
exec (bytecode , new_ns )
115
112
except :
116
- raise GeoAlgorithmExecutionException (
113
+ raise QgsProcessingException (
117
114
self .tr ("FieldPyculator code execute error.Global code block can't be executed!\n {0}\n {1}" ).format (str (sys .exc_info ()[0 ].__name__ ), str (sys .exc_info ()[1 ])))
118
115
119
116
# Replace all fields tags
120
- fields = layer .fields ()
117
+ fields = source .fields ()
121
118
num = 0
122
119
for field in fields :
123
120
field_name = str (field .name ())
@@ -136,13 +133,17 @@ def processAlgorithm(self, parameters, context, feedback):
136
133
try :
137
134
bytecode = compile (code , '<string>' , 'exec' )
138
135
except :
139
- raise GeoAlgorithmExecutionException (
136
+ raise QgsProcessingException (
140
137
self .tr ("FieldPyculator code execute error. Field code block can't be executed!\n {0}\n {1}" ).format (str (sys .exc_info ()[0 ].__name__ ), str (sys .exc_info ()[1 ])))
141
138
142
139
# Run
143
- features = QgsProcessingUtils .getFeatures (layer , context )
144
- total = 100.0 / layer .featureCount () if layer .featureCount () else 0
140
+ features = source .getFeatures ()
141
+ total = 100.0 / source .featureCount () if source .featureCount () else 0
142
+
145
143
for current , feat in enumerate (features ):
144
+ if feedback .isCanceled ():
145
+ break
146
+
146
147
feedback .setProgress (int (current * total ))
147
148
attrs = feat .attributes ()
148
149
feat_id = feat .id ()
@@ -168,18 +169,17 @@ def processAlgorithm(self, parameters, context, feedback):
168
169
169
170
# Check result
170
171
if self .RESULT_VAR_NAME not in new_ns :
171
- raise GeoAlgorithmExecutionException (
172
+ raise QgsProcessingException (
172
173
self .tr ("FieldPyculator code execute error\n "
173
174
"Field code block does not return '{0}' variable! "
174
175
"Please declare this variable in your code!" ).format (self .RESULT_VAR_NAME ))
175
176
176
177
# Write feature
177
- outFeat .setGeometry (feat .geometry ())
178
178
attrs .append (new_ns [self .RESULT_VAR_NAME ])
179
- outFeat .setAttributes (attrs )
180
- writer .addFeature (outFeat , QgsFeatureSink .FastInsert )
179
+ feat .setAttributes (attrs )
180
+ sink .addFeature (feat , QgsFeatureSink .FastInsert )
181
181
182
- del writer
182
+ return { self . OUTPUT : dest_id }
183
183
184
184
def checkParameterValues (self , parameters , context ):
185
185
# TODO check that formula is correct and fields exist
0 commit comments