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