Skip to content

Commit

Permalink
[FEATURE] Add ability to create user defined Python (and C++) express…
Browse files Browse the repository at this point in the history
…ion functions
  • Loading branch information
NathanW2 committed Nov 10, 2012
1 parent d5dc331 commit a7699e2
Show file tree
Hide file tree
Showing 8 changed files with 368 additions and 134 deletions.
38 changes: 21 additions & 17 deletions python/core/qgsexpression.sip
Expand Up @@ -117,29 +117,33 @@ class QgsExpression
// static const char* BinaryOgcOperatorText[];
// static const char* UnaryOgcOperatorText[];

struct FunctionDef /NoDefaultCtors/
class Function
{
//FunctionDef( QString fnname, int params, FcnEval fcn, QString group, QString helpText = QString(), bool usesGeometry = false );
/** The name of the function. */
QString mName;
/** The number of parameters this function takes. */
int mParams;
/** Pointer to function. */
//FcnEval mFcn;
/** Does this function use a geometry object. */
bool mUsesGeometry;
/** The group the function belongs to. */
QString mGroup;
/** The help text for the function. */
QString mHelpText;
public:
Function( QString fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false );
/** The name of the function. */
QString name();
/** The number of parameters this function takes. */
int params();
/** Does this function use a geometry object. */
bool usesgeometry();
/** The group the function belongs to. */
QString group();
/** The help text for the function. */
QString helptext();

virtual QVariant func(const QVariantList& values, QgsFeature* f, QgsExpression* parent) = 0;
};

static const QList<QgsExpression::FunctionDef> &BuiltinFunctions();
static const QList<QgsExpression::Function *> &Functions();

static bool registerFunction(Function* function);
static bool unregisterFunction(QString name);

// tells whether the identifier is a name of existing function
static bool isFunctionName( QString name );

// return index of the function in BuiltinFunctions array
// return index of the function in Functions array
static int functionIndex( QString name );

/** Returns the number of functions defined in the parser
Expand All @@ -150,7 +154,7 @@ class QgsExpression
/**
* Returns a list of special Column definitions
*/
static QList<QgsExpression::FunctionDef> specialColumns();
static QList<QgsExpression::Function *> specialColumns();

//! return quoted column reference (in double quotes)
static QString quotedColumnRef( QString name );
Expand Down
58 changes: 56 additions & 2 deletions python/utils.py
Expand Up @@ -28,8 +28,9 @@
"""

from PyQt4.QtCore import QCoreApplication,QLocale
from qgis.core import QGis
from PyQt4.QtCore import QCoreApplication,QLocale, QString
from qgis.core import QGis, QgsExpression
from string import Template
import sys
import traceback
import glob
Expand Down Expand Up @@ -371,6 +372,59 @@ def closeProjectMacro():
mod.closeProject()


def qgsfunction(args, group, **kwargs):
"""
Decorator function used to define a user expression function.
Custom functions should take (values, feature, parent) as args,
they can also shortcut naming feature and parent args by using *args
if they are not needed in the function.
Functions should return a value compatible with QVariant
Eval errors can be raised using parent.setEvalErrorString()
Functions must be unregistered when no longer needed using
QgsExpression.unregisterFunction
Example:
@qgsfunction(2, 'test'):
def add(values, feature, parent):
pass
Will create and register a function in QgsExpression called 'add' in the
'test' group that takes two arguments.
or not using feature and parent:
@qgsfunction(2, 'test'):
def add(values, *args):
pass
"""
helptemplate = Template("""<h3>$name function</h3><br>$doc""")
class QgsExpressionFunction(QgsExpression.Function):
def __init__(self, name, args, group, helptext=''):
QgsExpression.Function.__init__(self, name, args, group, QString(helptext))

def func(self, values, feature, parent):
pass

def wrapper(func):
name = kwargs.get('name', func.__name__)
help = func.__doc__ or ''
help = help.strip()
if args == 0 and not name[0] == '$':
name = '${0}'.format(name)
func.__name__ = name
help = helptemplate.safe_substitute(name=name, doc=help)
f = QgsExpressionFunction(name, args, group, help)
f.func = func
register = kwargs.get('register', True)
if register:
QgsExpression.registerFunction(f)
return f
return wrapper

#######################
# IMPORT wrapper

Expand Down

0 comments on commit a7699e2

Please sign in to comment.