# -*- coding: utf-8 -*- """ *************************************************************************** qgsfunction.py --------------------- Date : May 2018 Copyright : (C) 2018 by Denis Rouzaud Email : denis@opengis.ch *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * *************************************************************************** """ import inspect import string import traceback from builtins import str from qgis.PyQt.QtCore import QCoreApplication from qgis._core import QgsExpressionFunction, QgsExpression, QgsMessageLog, QgsFeatureRequest, Qgis def register_function(function, arg_count, group, usesgeometry=False, referenced_columns=[QgsFeatureRequest.ALL_ATTRIBUTES], handlesnull=False, **kwargs): """ Register a Python function to be used as a expression function. Functions should take (values, feature, parent) as args: Example: def myfunc(values, feature, parent): pass They can also shortcut naming feature and parent args by using *args if they are not needed in the function. Example: def myfunc(values, *args): pass Functions should return a value compatible with QVariant Eval errors can be raised using parent.setEvalErrorString("Error message") :param function: :param arg_count: :param group: :param usesgeometry: :param handlesnull: Needs to be set to True if this function does not always return NULL if any parameter is NULL. Default False. :return: """ class QgsPyExpressionFunction(QgsExpressionFunction): def __init__(self, func, name, args, group, helptext='', usesGeometry=True, referencedColumns=QgsFeatureRequest.ALL_ATTRIBUTES, expandargs=False, handlesNull=False): QgsExpressionFunction.__init__(self, name, args, group, helptext) self.function = func self.expandargs = expandargs self.uses_geometry = usesGeometry self.referenced_columns = referencedColumns self.handles_null = handlesNull def func(self, values, context, parent, node): feature = None if context: feature = context.feature() try: if self.expandargs: values.append(feature) values.append(parent) if inspect.getfullargspec(self.function).args[-1] == 'context': values.append(context) return self.function(*values) else: if inspect.getfullargspec(self.function).args[-1] == 'context': self.function(values, feature, parent, context) return self.function(values, feature, parent) except Exception as ex: tb = traceback.format_exception(None, ex, ex.__traceback__) formatted_traceback = ''.join(tb) formatted_exception = f"{ex}:
{formatted_traceback}" parent.setEvalErrorString(formatted_exception) return None def usesGeometry(self, node): return self.uses_geometry def referencedColumns(self, node): return self.referenced_columns def handlesNull(self): return self.handles_null helptemplate = string.Template("""