Coverage for gws-app/gws/plugin/model_value/expression/__init__.py: 77%
31 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-23 20:06 +0200
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-23 20:06 +0200
1"""Expression value.
3Computes the value by evaluating a Python expression. The expression is
4compiled at configuration time; a syntax error is a configuration error.
6The following variables are available in the expression:
8- ``app``: the Application object,
9- ``user``: the current user,
10- ``project``: the current project,
11- ``feature``: the feature the value is computed for,
12- ``mc``: the ``gws.ModelContext`` object,
13- ``date``: the ``gws.lib.datetimex`` module.
15Additional modules can be made available with the ``imports`` option, a list
16of module names, e.g. ``["math", "os.path"]``. Each module is available under
17its top-level package name, so ``os.path`` is used as ``os.path.join(...)``.
18If a module cannot be imported or the evaluation fails, the error is logged
19and the value is None.
21Example::
23 fields+ {
24 name "area_ha"
25 type "float"
26 values+ {
27 type "expression"
28 expression "round(feature.get('area_m2', 0) / 10000, 2)"
29 }
30 }
31"""
33from typing import Optional
34import gws
35import gws.base.model.value
36import gws.lib.datetimex
39@gws.ext.config.modelValue('expression')
40class Config(gws.base.model.value.Config):
41 """Value computed by a Python expression."""
43 expression: str
44 """Python expression to evaluate."""
46 imports: Optional[list[str]]
47 """Additional Python modules available to the expression."""
50@gws.ext.object.modelValue('expression')
51class Object(gws.base.model.value.Object):
52 """Expression value object."""
54 expression: str
55 """Python expression to evaluate."""
56 imports: list[str]
57 """Names of modules imported for the expression."""
59 def configure(self):
60 self.expression = (self.cfg('expression') or '').strip()
61 self.imports = self.cfg('imports') or []
62 try:
63 compile(self.expression, 'expression', 'eval')
64 except Exception as exc:
65 raise gws.ConfigurationError(f'invalid expression: {exc!r}') from exc
67 def compute(self, field, feature, mc):
68 context = {
69 'app': self.root.app,
70 'user': mc.user,
71 'project': mc.project,
72 'feature': feature,
73 'mc': mc,
74 'date': gws.lib.datetimex,
75 }
76 for mod in self.imports:
77 try:
78 context[mod.split('.')[0]] = __import__(mod)
79 except ImportError as exc:
80 gws.log.error(f'failed to import module {mod!r}: {exc!r}')
81 return
83 try:
84 return eval(self.expression, context)
85 except Exception as exc:
86 gws.log.error(f'failed to compute expression: {exc!r}')