@@ -492,3 +492,121 @@ def analyze_source_files(
492492
493493 return parsed_data , all_imports , all_types , request_arg_schema
494494
495+
496+ # =============================================================================
497+ # Section 3: Code Generation
498+ # =============================================================================
499+
500+ def _generate_import_statement (
501+ context : List [Dict [str , Any ]], key : str , path : str
502+ ) -> str :
503+ """Generates a formatted import statement from a list of context dictionaries.
504+
505+ Args:
506+ context: A list of dictionaries containing the data.
507+ key: The key to extract from each dictionary in the context.
508+ path: The base import path (e.g., "google.cloud.bigquery_v2.services").
509+
510+ Returns:
511+ A formatted, multi-line import statement string.
512+ """
513+ names = sorted (list (set ([item [key ] for item in context ])))
514+ names_str = ",\n " .join (names )
515+ return f"from { path } import (\n { names_str } \n )"
516+
517+
518+ def generate_code (config : Dict [str , Any ], analysis_results : tuple ) -> None :
519+ """
520+ Generates source code files using Jinja2 templates.
521+ """
522+ data , all_imports , all_types , request_arg_schema = analysis_results
523+ project_root = config ["project_root" ]
524+ config_dir = config ["config_dir" ]
525+
526+ templates_config = config .get ("templates" , [])
527+ for item in templates_config :
528+ template_path = os .path .join (config_dir , item ["template" ])
529+ output_path = os .path .join (project_root , item ["output" ])
530+
531+ template = utils .load_template (template_path )
532+ methods_context = []
533+ for class_name , methods in data .items ():
534+ for method_name , method_info in methods .items ():
535+ context = {
536+ "name" : method_name ,
537+ "class_name" : class_name ,
538+ "return_type" : method_info ["return_type" ],
539+ }
540+
541+ # Infer the request class and find its schema.
542+ inferred_request_name = name_utils .method_to_request_class_name (
543+ method_name
544+ )
545+
546+ # Check for a request class name override in the config.
547+ method_overrides = (
548+ config .get ("filter" , {}).get ("methods" , {}).get ("overrides" , {})
549+ )
550+ if method_name in method_overrides :
551+ inferred_request_name = method_overrides [method_name ].get (
552+ "request_class_name" , inferred_request_name
553+ )
554+
555+ fq_request_name = ""
556+ for key in request_arg_schema .keys ():
557+ if key .endswith (f".{ inferred_request_name } " ):
558+ fq_request_name = key
559+ break
560+
561+ # If found, augment the method context.
562+ if fq_request_name :
563+ context ["request_class_full_name" ] = fq_request_name
564+ context ["request_id_args" ] = request_arg_schema [fq_request_name ]
565+
566+ methods_context .append (context )
567+
568+ # Prepare imports for the template
569+ services_context = []
570+ client_class_names = sorted (
571+ list (set ([m ["class_name" ] for m in methods_context ]))
572+ )
573+
574+ for class_name in client_class_names :
575+ service_name_cluster = name_utils .generate_service_names (class_name )
576+ services_context .append (service_name_cluster )
577+
578+ # Also need to update methods_context to include the service_name and module_name
579+ # so the template knows which client to use for each method.
580+ class_to_service_map = {s ["service_client_class" ]: s for s in services_context }
581+ for method in methods_context :
582+ service_info = class_to_service_map .get (method ["class_name" ])
583+ if service_info :
584+ method ["service_name" ] = service_info ["service_name" ]
585+ method ["service_module_name" ] = service_info ["service_module_name" ]
586+
587+ # Prepare new imports
588+ service_imports = [
589+ _generate_import_statement (
590+ services_context ,
591+ "service_module_name" ,
592+ "google.cloud.bigquery_v2.services" ,
593+ )
594+ ]
595+
596+ # Prepare type imports
597+ type_imports = [
598+ _generate_import_statement (
599+ services_context , "service_name" , "google.cloud.bigquery_v2.types"
600+ )
601+ ]
602+
603+ final_code = template .render (
604+ service_name = config .get ("service_name" ),
605+ methods = methods_context ,
606+ services = services_context ,
607+ service_imports = service_imports ,
608+ type_imports = type_imports ,
609+ request_arg_schema = request_arg_schema ,
610+ )
611+
612+ utils .write_code_to_file (output_path , final_code )
0 commit comments