Skip to content

Commit a4276fe

Browse files
committed
feat: microgen - adds code generation logic
1 parent 485b9d4 commit a4276fe

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

scripts/microgenerator/generate.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)