File: generate_docstring_hpp.py

package info (click to toggle)
opm-common 2025.10%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 96,952 kB
  • sloc: cpp: 291,772; python: 3,609; sh: 198; xml: 174; pascal: 136; makefile: 12
file content (137 lines) | stat: -rwxr-xr-x 5,091 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"""
OPM Docstring Header Generator

This script generates C++ header files with docstrings from JSON configuration files.
It supports two JSON formats with automatic detection and backward compatibility:

1. TEMPLATE FORMAT (New):
   - Uses "simulators", "constructors", "common_methods" sections
   - Supports {{name}} and {{class}} placeholder expansion
   - Requires simulator_type parameter for expansion
   - Example: docstrings_simulators.json

   Template "doc" field usage:
   - Simulator-level "doc": Main class documentation (→ PyClassName_docstring)
   - Constructor-level "doc": Constructor method documentation (→ PyClassName_constructor_docstring)
   - Method-level "doc": Individual method documentation (→ method_name_docstring)

2. FLAT FORMAT (Legacy):
   - Direct key-value pairs with "signature", "doc", "type" fields
   - No template expansion
   - Works with existing files unchanged
   - Example: docstrings_common.json

Format Detection:
- Template format: Detected by presence of both "simulators" AND "common_methods" keys
- Flat format: Used for all other JSON structures (maintains backward compatibility)

Usage:
  python generate_docstring_hpp.py <json_path> <output_hpp_path> <macro_name> <namespace> [simulator_type]

  - simulator_type parameter is required only for template format files
  - simulator_type parameter is ignored for flat format files
"""

import json
import sys

def expand_template(template_dict, simulator_config):
    """Recursively replace {{name}} and {{class}} placeholders"""
    if isinstance(template_dict, dict):
        result = {}
        for key, value in template_dict.items():
            result[key] = expand_template(value, simulator_config)
        return result
    elif isinstance(template_dict, str):
        return (template_dict
                .replace("{{name}}", simulator_config["name"])
                .replace("{{class}}", simulator_config["class"]))
    else:
        return template_dict

def expand_for_simulator(config, simulator_type):
    """Convert template config to flat docstring structure for specific simulator"""
    if simulator_type not in config["simulators"]:
        raise ValueError(f"Unknown simulator type: {simulator_type}")

    sim_config = config["simulators"][simulator_type]
    result = {}

    # Add class docstring
    class_name = sim_config["class"]
    result[class_name] = {
        "doc": sim_config.get("doc", ""),
        "signature": f"opm.simulators.{sim_config['name']}",
        "type": "class"
    }

    # Add constructor docstrings
    for constructor_key, constructor_template in config.get("constructors", {}).items():
        expanded = expand_template(constructor_template, sim_config)
        full_key = f"{class_name}_{constructor_key}"
        result[full_key] = {
            "signature": expanded.get("signature_template", ""),
            "doc": expanded.get("doc", "")
        }

    # Add method docstrings
    for method_name, method_template in config.get("common_methods", {}).items():
        expanded = expand_template(method_template, sim_config)
        result[method_name] = {
            "signature": expanded.get("signature_template", ""),
            "doc": expanded.get("doc", "")
        }

    return result

def generate_hpp_from_json(json_path: str, output_hpp_path: str, macro: str, namespace: str, simulator_type: str = None):
    with open(json_path, 'r', encoding='utf-8') as file:
        docstrings = json.load(file)

    # Check if this is the new template format
    if "simulators" in docstrings and "common_methods" in docstrings:
        if not simulator_type:
            raise ValueError("Simulator type required for template format JSON")
        docstrings = expand_for_simulator(docstrings, simulator_type)
    # else: use docstrings as-is (backward compatibility for flat format)

    # Generate header file (existing code)
    hpp_content = f"""\
#ifndef {macro}
#define {macro}

// Generated docstrings
namespace {namespace} """
    hpp_content += "{"

    for func_name, info in docstrings.items():
        doc = info.get('doc', '').replace('\n', '\n    ')
        hpp_content += f"""
static constexpr char {func_name}_docstring[] = R\"doc(
{doc}
)doc\";\n"""
    hpp_content += "}"
    hpp_content += f"""\
 // namespace {namespace}

#endif // {macro}
"""

    with open(output_hpp_path, 'w', encoding='utf-8') as file:
        file.write(hpp_content)

    print(f"Generated {output_hpp_path} from {json_path}" + (f" for simulator type {simulator_type}" if simulator_type else ""))

if __name__ == "__main__":
    # Updated to accept optional 5th parameter
    if len(sys.argv) not in [5, 6]:
        print("Usage: python generate_docstring_hpp.py <json_path> <output_hpp_path> <macro_name> <namespace> [simulator_type]")
        sys.exit(1)

    json_path = sys.argv[1]
    output_hpp_path = sys.argv[2]
    macro = sys.argv[3]
    namespace = sys.argv[4]
    simulator_type = sys.argv[5] if len(sys.argv) == 6 else None

    generate_hpp_from_json(json_path, output_hpp_path, macro, namespace, simulator_type)