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

1"""Python templates. 

2 

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. 

8 

9Example:: 

10 

11 templates+ { 

12 subject "feature.description" 

13 type "py" 

14 path "/data/templates/description.py" 

15 } 

16 

17with ``description.py``:: 

18 

19 import gws 

20 

21 def main(args): 

22 return gws.ContentResponse(mimeType='text/plain', content=f'Subject: {args.subject}') 

23""" 

24 

25from typing import Optional 

26 

27import gws 

28import gws.base.template 

29 

30 

31@gws.ext.config.template('py') 

32class Config(gws.base.template.Config): 

33 """Template implemented as a Python module with a main function.""" 

34 

35 path: Optional[gws.FilePath] 

36 """Python module file with the main function.""" 

37 

38 

39@gws.ext.props.template('py') 

40class Props(gws.base.template.Props): 

41 pass 

42 

43 

44_ENTRYPOINT_NAME = 'main' 

45 

46 

47@gws.ext.object.template('py') 

48class Object(gws.base.template.Object): 

49 """Template implemented as a Python module with a ``main`` function.""" 

50 

51 path: str 

52 """Python module file path.""" 

53 

54 def configure(self): 

55 self.path = self.cfg('path') 

56 self.compile() 

57 

58 def render(self, tri): 

59 self.notify(tri, 'begin_print') 

60 

61 args = self.prepare_args(tri) 

62 entrypoint = self.compile() 

63 

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 

69 

70 self.notify(tri, 'end_print') 

71 return res 

72 

73 def compile(self): 

74 """Load the module and return its ``main`` function. 

75 

76 Returns: 

77 The ``main`` function. 

78 

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