6

I'm new using PyQGIS 3 and I'm wondering how to access the field information from a layer generated by script.

Inside my processAlgorithm function I have the following:

alg_params = {
    'EXPRESSION': parameters[self.IN_EXPRESSION],
    'INPUT': parameters[self.IN_SHP],
    'OUTPUT': parameters[self.OUT_SHP]
}

final_output = processing.run('native:extractbyexpression', alg_params, context=context, feedback=feedback, is_child_algorithm=True)['OUTPUT']

output_lyr = QgsVectorLayer(final_output, "output_testing", "ogr")    

fields = output_lyr.fields()
fieldnames = [field.name() for field in fields]
print(fieldnames)

return {"result": final_output }

The algorithm itself is returning the right output, however I'm not able to access the fields during inside the code, the print is returning me a empty list, however my final_output DO have fields.

Someone, could give me a glimpse of what I've missed?

4
  • Have you tested print(fields.names()) ? – J. Monticolo Aug 12 '20 at 13:55
  • It returns an empy list... – Matt_Geo Aug 12 '20 at 14:36
  • and print(final_output.fields().names()) ? – J. Monticolo Aug 12 '20 at 14:38
  • It raises: File "<string>", line 168, in processAlgorithm AttributeError: 'str' object has no attribute 'fields' when I have ['OUTPUT'] in the end of it. If I remove this part it changes to AttributeError: 'dict' object has no attribute 'fields' – Matt_Geo Aug 12 '20 at 14:42
5

Normally, when using a vector tool, processing.run with TEMPORARY_OUTPUT returns ["OUTPUT": QgsVectorLayer]. If is_child_algorithm=True is added, it returns a temporary layer id.

The reference of a temporary layer can be obtained by means of context.temporaryLayerStore(). You can add the following lines to your processing script to get the temporary layer's reference.

import os 
# ... other imports

class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
    # ... other stuffs

    def processAlgorithm(self, parameters, context, feedback):    
        # ... previous lines

        final_output = processing.run('native:extractbyexpression',
                                      alg_params, context=context, feedback=feedback,
                                      is_child_algorithm=True)['OUTPUT']

        # check output type
        if isinstance(final_output, str):            
            # check if a file path
            if os.path.isfile(final_output):
                output_lyr = QgsVectorLayer(final_output, "output_testing", "ogr")                            
            else: # if not a path, then it is a temporary layer's ID
                output_lyr = context.temporaryLayerStore().mapLayers()[final_output]        
        # possible QgsVectorLayer if "is_child_algorithm=True" is not used
        elif isinstance(final_output, QgsVectorLayer):
            output_lyr = final_output        
        else:
            raise ValueError('A very specific bad thing happened.')
        
        print([f.name() for f in output_lyr.fields()])
    
        return {"OUTPUT": final_output}
1

Use final_output['OUTPUT'] since the output is saved in a dictionary:

output_lyr = QgsVectorLayer(final_output['OUTPUT'], "output_testing", "ogr")
1
  • I think the code editor above is hiding that part, but I'm accessing the ['OUTPUT'] already in my example. See the last characters of the line when I created the final_output variable – Matt_Geo Aug 12 '20 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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