Coverage for gws-app/gws/plugin/template/py/__init__.py: 88%
34 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""Python templates.
3A ``py`` template is a Python module. The module must provide a function
4called ``main``, which receives the template arguments object and returns
5a :obj:`gws.Response` object. The module is loaded when the template is
6configured and loaded again on each render, so changes to the file take
7effect immediately.
9Example::
11 templates+ {
12 subject "feature.description"
13 type "py"
14 path "/data/templates/description.py"
15 }
17with ``description.py``::
19 import gws
21 def main(args):
22 return gws.ContentResponse(mimeType='text/plain', content=f'Subject: {args.subject}')
23"""
25from typing import Optional
27import gws
28import gws.base.template
31@gws.ext.config.template('py')
32class Config(gws.base.template.Config):
33 """Template implemented as a Python module with a main function."""
35 path: Optional[gws.FilePath]
36 """Python module file with the main function."""
39@gws.ext.props.template('py')
40class Props(gws.base.template.Props):
41 pass
44_ENTRYPOINT_NAME = 'main'
47@gws.ext.object.template('py')
48class Object(gws.base.template.Object):
49 """Template implemented as a Python module with a ``main`` function."""
51 path: str
52 """Python module file path."""
54 def configure(self):
55 self.path = self.cfg('path')
56 self.compile()
58 def render(self, tri):
59 self.notify(tri, 'begin_print')
61 args = self.prepare_args(tri)
62 entrypoint = self.compile()
64 try:
65 res = entrypoint(args)
66 except Exception as exc:
67 # @TODO stack traces with the filename
68 raise gws.Error(f'py error: {exc!r} path={self.path!r}') from exc
70 self.notify(tri, 'end_print')
71 return res
73 def compile(self):
74 """Load the module and return its ``main`` function.
76 Returns:
77 The ``main`` function.
79 Raises:
80 ``gws.Error``: If the module cannot be executed or has no ``main`` function.
81 """
82 text = gws.u.read_file(self.path)
83 try:
84 g = {}
85 exec(text, g)
86 return g[_ENTRYPOINT_NAME]
87 except Exception as exc:
88 raise gws.Error(f'py load error: {exc!r} in {self.path!r}') from exc