1
+ import sys
2
+ import os
3
+ import yaml
4
+ import argparse
5
+
6
+ from jinja2 import Environment , FileSystemLoader
7
+
8
+ from utils import get_additional_parameters
9
+ from exceptions import MissingKeyError
10
+
11
+ def render_prop_mixin (env : Environment ,
12
+ name : str ,
13
+ properties : list ,
14
+ base_name : str ,
15
+ template_name : str = "mixins.py" ,
16
+ path_prefix : str = "../webexteamssdk/models/mixins/"
17
+ ) -> str :
18
+ """ Renders a simple property mixin for the SDK based on the
19
+ information provided in the descriptor file.
20
+
21
+ Args:
22
+ env(Environment): The jinja environment to render under. Defines
23
+ the templates that will be used.
24
+ name(str): The name of our endpoint. Will be turned into the class
25
+ name as {name}SimplePropertyMixin.
26
+ properties(list): List of property extracted from the list.properties
27
+ key in the descriptor file.
28
+ base_name(str): Base name of the descriptor file. Used to generate
29
+ the filenames.
30
+ template_name(str): Name of the template to use. Default: mixins.py
31
+ path_prefix(str): Path to the mixins folder.
32
+ Default: ../webexteamssdk/models/mixins/
33
+
34
+ Returns:
35
+ str: Path to the generated
36
+ """
37
+
38
+ # Render template based on loaded properties
39
+ tmpl = env .get_template (template_name )
40
+ out = tmpl .render (name = name , properties = properties )
41
+
42
+ target_path = os .path .join (path_prefix , f"{ base_name } .py" )
43
+
44
+ with open (target_path , "w" ) as fh :
45
+ fh .writelines (out )
46
+
47
+ return target_path
48
+
49
+ def render_api_class (env : Environment ,
50
+ descr : dict ,
51
+ base_name : str ,
52
+ template_name : str = "api.py" ,
53
+ path_prefix : str = "../webexteamssdk/api/"
54
+ ) -> str :
55
+ """ Renders an API class based on the properties described in
56
+ the descr file.
57
+
58
+ Args:
59
+ env(Environment): The jinja environment to render under. Defines
60
+ the templates that will be used.
61
+ descr(dict): Descriptor parsed from the yaml file defining the
62
+ properties of the endpoint and target api model.
63
+ base_name(str): Base name of the descriptor file. Used to generate
64
+ the filenames.
65
+ template_name(str): Name of the template to use. Default: api.py
66
+ path_prefix(str): Path to the target api folder that the output will
67
+ we placed in. Default: ../webexteamssdk/api/
68
+
69
+ Returns:
70
+ str: The path to the generated api class
71
+ """
72
+ create_parameters = get_additional_parameters (descr , 'create' )
73
+ update_parameters = get_additional_parameters (descr , 'update' )
74
+
75
+ additional_code = descr .get ("additional_code" , None )
76
+
77
+ # Render template
78
+ tpl = env .get_template (template_name )
79
+ out = tpl .render (name = descr ['name' ],
80
+ endpoint = descr ['endpoint' ],
81
+ object_type = descr ['object_type' ],
82
+ query_parameters = descr ['query_parameters' ],
83
+ create_parameters = create_parameters ,
84
+ update_parameters = update_parameters ,
85
+ methods = descr ['methods' ],
86
+ additional_code = additional_code ),
87
+
88
+ target_path = os .path .join (path_prefix , f"{ base_name } .py" )
89
+
90
+ with open (target_path , "w" ) as fh :
91
+ fh .writelines (out )
92
+
93
+ return target_path
94
+
95
+ def main ():
96
+ # Setup arg parser
97
+ parser = argparse .ArgumentParser (description = 'Generate new endpoints for the SDK' )
98
+ parser .add_argument ('-d' ,
99
+ '--descriptor' ,
100
+ help = "Path to the descriptor .yaml file" ,
101
+ type = str ,
102
+ required = True )
103
+ parser .add_argument ('-t' ,
104
+ '--template_dir' ,
105
+ help = "Path to the templates directory" ,
106
+ type = str ,
107
+ default = "templates" ,
108
+ required = False )
109
+ args = parser .parse_args ()
110
+
111
+ # Setup jinja environment and load information from description file
112
+ env = Environment (loader = FileSystemLoader (args .template_dir ))
113
+
114
+ descr_file = args .descriptor
115
+ base_name = os .path .splitext (os .path .basename (descr_file ))[0 ]
116
+
117
+ descr = yaml .safe_load (open (descr_file ))
118
+
119
+ # Check that all required keys are present
120
+ required_keys = [
121
+ 'name' ,
122
+ 'list.properties' ,
123
+ 'endpoint' ,
124
+ 'object_type' ,
125
+ 'query_parameters' ,
126
+ 'methods'
127
+ ]
128
+
129
+ for key in required_keys :
130
+ # Check all keys - subkeys (i.e. d['list']['properties']
131
+ # can be passed in dot notation, so list.properties)
132
+ keys = key .split ("." )
133
+
134
+ d = descr
135
+ for sub_key in keys :
136
+ if sub_key not in d .keys ():
137
+ raise MissingKeyError (f"Missing required key '{ key } '" )
138
+ else :
139
+ d = d .get (sub_key )
140
+
141
+ mixin_path = render_prop_mixin (env = env ,
142
+ name = descr ['name' ],
143
+ properties = descr ['list' ]['properties' ],
144
+ base_name = base_name
145
+ )
146
+ print (f"Rendered mixin for { descr ['name' ]} to { mixin_path } " )
147
+
148
+ api_path = render_api_class (env = env ,
149
+ descr = descr ,
150
+ base_name = base_name )
151
+ print (f"Rendered api class for { descr ['name' ]} to { api_path } " )
152
+
153
+
154
+ if __name__ == "__main__" :
155
+ main ()
156
+ # print("Manually add: ")
157
+ # print("In webexteamssdk/models/immutable.py")
158
+ # print(f"from .mixins.{ base_name } import { descr['name'] }BasicPropertiesMixin")
159
+
160
+ # cls_model_def = f"""
161
+ # class { descr['name'] }(ImmutableData, { descr['name'] }BasicPropertiesMixin):
162
+ # \"\"\"Webex { descr['name'] } data model\"\"\"
163
+ # """
164
+ # print(cls_model_def)
165
+
166
+ # print(f"{descr['object_type']}={ descr['name'] }")
167
+
168
+ # print()
169
+ # print()
170
+ # print("In webexteamssdk/api/__init__.py")
171
+ # print(f"from {base_name} import {descr['name']}API")
172
+ # print(f"self.{descr['object_type']}s = {descr['name']}(self._session, object_factory)")
0 commit comments