util.doc - statically type json structures

This commit is contained in:
Andrej730
2025-05-14 16:16:08 +05:00
parent 3a52a848ae
commit 16f9f91561
@@ -23,7 +23,7 @@ import ifcopenshell
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
import ifcopenshell.util.attribute
import ifcopenshell.util.schema
from typing import Optional, Literal
from typing import Optional, Literal, Any, Union, TypedDict, NotRequired
try:
import glob
@@ -48,20 +48,44 @@ IFC4x3_HTML_LOCATION = BASE_MODULE_PATH / "IFC4.3-html"
IFC4x3_DEV_LOCATION = BASE_MODULE_PATH / "IFC4.3.x-development"
IFC4x3_SPEC_URL_TEMPLATE = "https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/%s.htm"
# entities schema
# entity -> description, spec_url, attributes[], predefined_types[]
# types schema
# type -> description, spec_url
class BaseData(TypedDict):
description: str
spec_url: str
class EntityData(BaseData):
attributes: NotRequired[dict[str, str]]
predefined_types: NotRequired[dict[str, str]]
class PsetData(TypedDict):
# Apparently some psets in ifc4 are missing spec url / description.
description: NotRequired[str]
spec_url: NotRequired[str]
properties: dict[str, str]
class PropertyData(TypedDict):
description: str
# in IFC4x3 there is no children[] for properties
children: NotRequired[dict[str, "PropertyData"]]
class ClassesSuggestions(TypedDict):
name: str
predefined_type: NotRequired[str]
class SchemaData(TypedDict):
entities: dict[str, EntityData]
types: dict[str, BaseData]
properties: dict[str, PsetData]
classes_suggestions: dict[str, ClassesSuggestions]
# properties schema
# pset/qset -> description, spec_url, properties[]
# property -> description, children[]
# child -> description
# note: in IFC4x3 there is no children[] for properties
SUPPORTED_SCHEMA = ifcopenshell.util.schema.IFC_SCHEMA
SCHEMA_FILES: dict[SUPPORTED_SCHEMA, dict] = {
SCHEMA_FILES: dict[SUPPORTED_SCHEMA, dict[str, Path]] = {
"IFC2X3": {
"entities": BASE_MODULE_PATH / "schema/ifc2x3_entities.json",
"properties": BASE_MODULE_PATH / "schema/ifc2x3_properties.json",
@@ -82,7 +106,7 @@ SCHEMA_FILES: dict[SUPPORTED_SCHEMA, dict] = {
},
}
db = None
db: dict[SUPPORTED_SCHEMA, SchemaData] = None
schema_by_name: dict[SUPPORTED_SCHEMA, Optional[ifcopenshell_wrapper.schema_definition]] = {
"IFC2X3": None,
"IFC4": None,
@@ -90,7 +114,7 @@ schema_by_name: dict[SUPPORTED_SCHEMA, Optional[ifcopenshell_wrapper.schema_defi
}
def get_db(version):
def get_db(version: ifcopenshell.util.schema.IFC_SCHEMA) -> Union[SchemaData, None]:
global db
if not db:
db = {ifc_version: dict() for ifc_version in SCHEMA_FILES}
@@ -117,7 +141,10 @@ def get_schema_by_name(version: str) -> ifcopenshell_wrapper.schema_definition:
return schema_by_name[version]
def get_class_suggestions(version, class_name):
def get_class_suggestions(
version: ifcopenshell.util.schema.IFC_SCHEMA,
class_name: str,
) -> Union[ClassesSuggestions, None]:
db = get_db(version)
if not db:
return
@@ -125,7 +152,11 @@ def get_class_suggestions(version, class_name):
return class_suggestions
def get_entity_doc(version, entity_name, recursive=True):
def get_entity_doc(
version: ifcopenshell.util.schema.IFC_SCHEMA,
entity_name: str,
recursive: bool = True,
) -> Union[EntityData, None]:
db = get_db(version)
if db:
entity = copy.deepcopy(db["entities"].get(entity_name))
@@ -144,37 +175,46 @@ def get_entity_doc(version, entity_name, recursive=True):
return entity
def get_attribute_doc(version, entity, attribute, recursive=True):
def get_attribute_doc(
version: ifcopenshell.util.schema.IFC_SCHEMA,
entity: str,
attribute: str,
recursive=True,
) -> Union[str, None]:
db = get_db(version)
if db:
entity = get_entity_doc(version, entity, recursive)
if entity:
return entity["attributes"].get(attribute)
entity_ = get_entity_doc(version, entity, recursive)
if entity_ and "attributes" in entity_:
return entity_["attributes"].get(attribute)
def get_predefined_type_doc(version, entity, predefined_type):
def get_predefined_type_doc(
version: ifcopenshell.util.schema.IFC_SCHEMA,
entity: str,
predefined_type: str,
) -> Union[str, None]:
db = get_db(version)
if db:
entity = db["entities"].get(entity)
if entity:
return entity.get("predefined_types", {}).get(predefined_type)
entity_ = db["entities"].get(entity)
if entity_:
return entity_.get("predefined_types", {}).get(predefined_type)
def get_property_set_doc(version, pset):
def get_property_set_doc(version: ifcopenshell.util.schema.IFC_SCHEMA, pset: str) -> Union[PsetData, None]:
db = get_db(version)
if db:
return db["properties"].get(pset)
def get_property_doc(version, pset, prop):
def get_property_doc(version: ifcopenshell.util.schema.IFC_SCHEMA, pset: str, prop: str) -> Union[str, None]:
db = get_db(version)
if db:
pset = db["properties"].get(pset)
if pset:
return pset["properties"].get(prop)
pset_ = db["properties"].get(pset)
if pset_:
return pset_["properties"].get(prop)
def get_type_doc(version, ifc_type):
def get_type_doc(version: ifcopenshell.util.schema.IFC_SCHEMA, ifc_type: str) -> Union[BaseData, None]:
db = get_db(version)
if db:
return db["types"].get(ifc_type)
@@ -209,7 +249,7 @@ def get_inverse_attributes(el):
class DocExtractor:
def clean_highlighted_words(self, text):
def clean_highlighted_words(self, text: str) -> str:
text = re.sub(r"\b_([a-zA-Z0-9]+)_\b", r"\1", text)
text = re.sub(r"\*\*([a-zA-Z0-9]+)\*\*", r"\1", text)
return text