Skip to content

Commit c4ac54f

Browse files
committed
tool: func to generate whole info model for given app type
1 parent 4c735bb commit c4ac54f

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

bin/fields.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def get_applicable_app_types(field_entry):
1313
"""
1414
Get the applicable application types for a field entry.
1515
"""
16+
app_types = None
1617
applies_if = field_entry.get("applies-if")
1718
if applies_if:
1819
# Try to extract application-type(s)
@@ -64,3 +65,7 @@ def is_field_applicable_to_app_type(field_entry, app_type):
6465
if applicable_app_types:
6566
return app_type in applicable_app_types
6667
return True # If no applies-if, assume applicable to all types
68+
69+
70+
def get_codelist(field_def):
71+
return field_def.get("codelist", None)

bin/generate_info_model.py

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
get_requirement_str,
66
is_field_applicable_to_app_type,
77
)
8-
from modules import get_module_parts
8+
from modules import get_codelists_for_module, get_module_parts
9+
from utils import save_string_to_file
910

1011

1112
def format_main_module_table(module, fields_spec, app_type=None):
@@ -108,6 +109,101 @@ def generate_module(module_ref, specification, app_type=None):
108109
return "\n".join(out)
109110

110111

112+
def get_codelists_for_app(module_refs, fields, specification):
113+
codelists = set()
114+
for module_ref in module_refs:
115+
module_parts = get_module_parts(specification, module_ref)
116+
if not module_parts:
117+
print(f"Module '{module_ref}' not found in specification.")
118+
continue
119+
related_components = module_parts.get("related-components", {})
120+
for component in related_components.values():
121+
codelists.update(get_codelists_for_module(component, fields))
122+
return codelists
123+
124+
125+
def generate_codelist_md_str(codelists):
126+
# list out the codelist names
127+
if not codelists:
128+
return ""
129+
lines = ["This are the codelist required to support this specification:\n"]
130+
for codelist in codelists:
131+
lines.append(f"- {codelist}")
132+
return "\n".join(lines)
133+
134+
135+
def generate_application(app_ref, specification):
136+
"""
137+
Generate the information model for a specific application type.
138+
"""
139+
applications = specification.get("application", {})
140+
fields = specification.get("field", {})
141+
app = applications.get(app_ref)
142+
if not app:
143+
print(f"Application '{app_ref}' not found in specification.")
144+
return None
145+
146+
# get the modules that are part of the application
147+
modules = app.get("modules", [])
148+
module_refs = [m["module"] if isinstance(m, dict) else m for m in modules]
149+
inc_codelists = get_codelists_for_app(module_refs, fields, specification)
150+
151+
# generate output
152+
# 1. Heading and Description
153+
out = [f"# {app.get('name', app_ref)}\n"]
154+
if app.get("description"):
155+
out.append(app["description"] + "\n")
156+
157+
# 2. Contents
158+
out.append("## Contents\n")
159+
out.append("* [Application data specification](#application-data-specification)")
160+
module_refs = [
161+
m["module"] if isinstance(m, dict) else m for m in app.get("modules", [])
162+
]
163+
out.append("")
164+
165+
# 3. Modules List (contents)
166+
out.append("### Modules\n")
167+
for mod in module_refs:
168+
mod_schema = specification.get("module", {}).get(mod, {})
169+
mod_name = mod_schema.get("name", mod.replace("-", " ").capitalize())
170+
anchor = mod_name.lower().replace(" ", "-")
171+
out.append(f"* [{mod_name}](#{anchor})")
172+
out.append("")
173+
174+
# 4. Application Data Specification
175+
out.append("## Application data specification\n")
176+
out.append("| field | description | data-type | required | notes |")
177+
out.append("| --- | --- | --- | --- | --- |")
178+
for field_entry in app.get("fields", []):
179+
ref = field_entry["field"]
180+
field_def = specification.get("field", {}).get(ref, {})
181+
description = field_def.get("description", "")
182+
datatype = field_def.get("datatype", "")
183+
required = "MUST" if field_entry.get("required") else "MAY"
184+
notes = field_def.get("notes", "")
185+
out.append(f"| {ref} | {description} | {datatype} | {required} | {notes} |")
186+
out.append("")
187+
188+
# 5. Module Sections
189+
for mod in module_refs:
190+
module_md = generate_module(mod, specification, app_type=app_ref)
191+
if module_md:
192+
# update first header of md file to be ## instead of #
193+
module_md = module_md.replace("# ", "## ", 1)
194+
out.append(module_md)
195+
out.append("")
196+
else:
197+
print(f"Module '{mod}' could not be generated.")
198+
199+
# 6. Required Codelists
200+
if inc_codelists:
201+
out.append("## Required codelists\n")
202+
out.append(generate_codelist_md_str(inc_codelists))
203+
204+
return "\n".join(out)
205+
206+
111207
if __name__ == "__main__":
112208
print("Testing information model generation script.")
113209

@@ -118,12 +214,18 @@ def generate_module(module_ref, specification, app_type=None):
118214
print("Specification loaded successfully")
119215

120216
# Test the function
121-
result = generate_module("interest-details", specification)
217+
# result = save_string_to_file(
218+
# "\n".join(generate_module("interest-details", specification)), "tmp/test-gen.md"
219+
# )
122220
# result = generate_module("res-units", specification, app_type="full")
123221
# result = generate_module("demolition-reason", specification)
124222
# result = generate_module(
125223
# "tree-work-details", specification, app_type="notice-trees-in-con-area"
126224
# )
225+
226+
result = save_string_to_file(
227+
generate_application("full", specification), "tmp/test-gen-app.md"
228+
)
127229
print("Function called successfully")
128230
print(result)
129231

bin/modules.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,25 @@ def get_field_metadata(field_def):
4141
return {}
4242

4343

44+
def get_codelists_for_module(module, fields):
45+
"""
46+
Get a list of codelists used in the module's fields.
47+
Returns a set of unique codelist names.
48+
"""
49+
codelists = set()
50+
for field_entry in module.get("fields", []):
51+
field_ref = field_entry.get("field")
52+
if not field_ref:
53+
continue
54+
field_def = get_field(fields, field_ref)
55+
if not field_def:
56+
continue
57+
codelist = field_def.get("codelist")
58+
if codelist:
59+
codelists.add(codelist)
60+
return codelists
61+
62+
4463
def enqueue_object_type_fields(
4564
field_entries, components, fields, already_enqueued, app_type=None
4665
):

0 commit comments

Comments
 (0)