mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
mvd info to module, add testing, setattr & getattr
This commit is contained in:
committed by
Thomas Krijnen
parent
9f11568aff
commit
cbe8fc1ebd
@@ -37,9 +37,7 @@ from typing import Any
|
||||
from . import ifcopenshell_wrapper
|
||||
from .entity_instance import entity_instance
|
||||
|
||||
from lark import Lark, Transformer
|
||||
from lark.exceptions import UnexpectedCharacters, UnexpectedEOF, UnexpectedToken
|
||||
|
||||
from ifcopenshell.util.mvd_info import MvdInfo, LARK_AVAILABLE
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import ifcopenshell.util.schema
|
||||
@@ -211,106 +209,6 @@ NO_HEADER = ifcopenshell_wrapper.file_open_status.NO_HEADER
|
||||
UNSUPPORTED_SCHEMA = ifcopenshell_wrapper.file_open_status.UNSUPPORTED_SCHEMA
|
||||
INVALID_SYNTAX = ifcopenshell_wrapper.file_open_status.INVALID_SYNTAX
|
||||
|
||||
mvd_grammar = r'''
|
||||
start: entry+
|
||||
|
||||
entry: "ViewDefinition" "[" simple_value_list "]" -> view_definition
|
||||
| "Comment" "[" comment_text "]" -> comment
|
||||
| GENERIC_KEYWORD "[" value_list_set "]" -> dynamic_option
|
||||
|
||||
%declare COMMENT_TEXT // Ensure Lark treats it with higher priority
|
||||
|
||||
GENERIC_KEYWORD: /[A-Za-z0-9_]+/
|
||||
|
||||
simple_value_list: value ("," value)*
|
||||
|
||||
value_list_set: value_set (";" value_set)*
|
||||
|
||||
value_set: set_name ":" simple_value_list
|
||||
|
||||
set_name: /[A-Za-z0-9_]+/
|
||||
|
||||
value: /[A-Za-z0-9 _\.-]+/
|
||||
|
||||
comment_text: /[^\[\]]+/ // Free text inside COMMENT brackets
|
||||
|
||||
%import common.WS
|
||||
%ignore WS
|
||||
'''
|
||||
|
||||
parser = Lark(mvd_grammar, parser='lalr')
|
||||
class DescriptionTransform(Transformer):
|
||||
def __init__(self):
|
||||
self.mvd = []
|
||||
self.keywords = set()
|
||||
self.comments = ""
|
||||
self.exchangerequirement = ""
|
||||
self.option = ''
|
||||
|
||||
|
||||
def view_definition(self, args):
|
||||
self.keywords.add('mvd')
|
||||
self.mvd.extend(args[0])
|
||||
|
||||
|
||||
def dynamic_option(self, args):
|
||||
"""
|
||||
e.g. in case of 'Remark' as optional keyword in the description
|
||||
The value can be retrieved through DescriptionTransform.remark
|
||||
"""
|
||||
key = str(args[0]).lower()
|
||||
attr_name = f"{key}"
|
||||
if attr_name not in self.keywords:
|
||||
setattr(self, attr_name, {})
|
||||
self.keywords.add(attr_name)
|
||||
dynamic_dict = getattr(self, attr_name)
|
||||
for value_set in args[1]:
|
||||
set_name, *values = value_set
|
||||
dynamic_dict[set_name] = values if len(values) > 1 else values[0]
|
||||
|
||||
|
||||
def comment(self, args):
|
||||
self.keywords.add('comment')
|
||||
self.comments = " ".join(str(child) for child in args[0].children).strip()
|
||||
|
||||
def simple_value_list(self, args):
|
||||
return [str(arg) for arg in args]
|
||||
|
||||
def value_list_set(self, args):
|
||||
return args
|
||||
|
||||
def value_set(self, args):
|
||||
return [str(args[0])] + args[1]
|
||||
|
||||
def value(self, args):
|
||||
return str(args[0])
|
||||
|
||||
def set_name(self, args):
|
||||
return str(args[0])
|
||||
|
||||
@property
|
||||
def other_keywords(self):
|
||||
""""
|
||||
The predefined keywords are 'ViewDefinition', 'Option', 'Comment', 'ExchangeRequirement' and 'Option'
|
||||
Keywords in the description not from this lists are returned
|
||||
"""
|
||||
return {k for k in self.keywords if k not in {'mvd', 'comment', 'exchangerequirement', 'option'}}
|
||||
|
||||
|
||||
def parse_mvd(description):
|
||||
text = ' '.join(description)
|
||||
parser = Lark(mvd_grammar, parser='lalr')
|
||||
parsed_description = DescriptionTransform()
|
||||
try:
|
||||
if not text:
|
||||
parsed_description.mvd = None
|
||||
return parsed_description
|
||||
parse_tree = parser.parse(text)
|
||||
parsed_description.transform(parse_tree)
|
||||
except (UnexpectedCharacters, UnexpectedEOF, UnexpectedToken) as e:
|
||||
parsed_description.mvd = None
|
||||
return parsed_description
|
||||
|
||||
class file:
|
||||
"""Base class for containing IFC files.
|
||||
|
||||
@@ -409,7 +307,6 @@ class file:
|
||||
import weakref
|
||||
|
||||
file_dict[self.file_pointer()] = weakref.ref(self)
|
||||
self.parsed_description = parse_mvd(self.wrapped_data.header.file_description.description)
|
||||
|
||||
def __del__(self) -> None:
|
||||
# Avoid infinite recursion if file is failed to initialize
|
||||
@@ -569,68 +466,16 @@ class file:
|
||||
number = re.search(prefix + r"(\d)", schema)
|
||||
version.append(int(number.group(1)) if number else 0)
|
||||
return tuple(version)
|
||||
|
||||
@property
|
||||
def mvd(self) -> str:
|
||||
"""
|
||||
View Definition supported by the exporting application that is reflected in the IFC file
|
||||
For example:
|
||||
“CoordinationView”
|
||||
| “PresentationView”
|
||||
| “StructuralAnalysisView”
|
||||
| “FMHandOverView”
|
||||
| “QuantityTakeOffAddOnView”
|
||||
| “SpaceBoundary1stLevelAddOnView”
|
||||
| “SpaceBoundary2ndLevelAddOnView”
|
||||
"""
|
||||
return ','.join(self.parsed_description.mvd)
|
||||
|
||||
@property
|
||||
def mvd_comments(self) -> str:
|
||||
"""
|
||||
For example; 'Comment [This
|
||||
export contains Boolean Operation geometry that may not be fully
|
||||
supported by other application]'
|
||||
|
||||
f.mvd_comments
|
||||
'This export contains Boolean Operation geometry that may not be fully supported by other application'
|
||||
"""
|
||||
return str(self.parsed_description.comments)
|
||||
|
||||
@property
|
||||
def mvd_exchange_requirements(self) -> str:
|
||||
return str(self.parsed_description.exchangerequirement)
|
||||
|
||||
@property
|
||||
def mvd_options(self) -> str:
|
||||
"""
|
||||
Option being used by the exporting application for e.g. quality control and debugging
|
||||
a. this is an optional field providing informal information, the values for the Option keyword
|
||||
reflect the export settings of the exporting software application, those settings may be
|
||||
specific to the exporting software
|
||||
For example:
|
||||
> "{'ExcludedObjects': [' Stair', ' Ramp', ' Space'], 'SplitLevel': ' On'}"
|
||||
"""
|
||||
return str(self.parsed_description.option)
|
||||
|
||||
@property
|
||||
def mvd_keywords(self) -> str:
|
||||
"""
|
||||
Returns all keywords from description, e.g.
|
||||
f.mvd_keywords
|
||||
"{'exchangerequirement', 'mvd', 'option', 'comment', 'remark'}"_
|
||||
"""
|
||||
return str(self.parsed_description.keywords)
|
||||
|
||||
@property
|
||||
def mvd_optional_keyword_fields(self) -> str:
|
||||
""""
|
||||
Returns fields from keywords other than 'ViewDefinition', 'Option', 'Comment' and 'ExchangeRequirement'.
|
||||
For example, in case of
|
||||
'REMARK [SomeKey: SomeValue; AnotherKey: AnotherValue]'
|
||||
file.mvd_optional_keywords_fields == "{'remark': {'SomeKey': ' SomeValue', 'AnotherKey': ' AnotherValue'}}"
|
||||
"""
|
||||
return str({kw: getattr(self.parsed_description, kw) for kw in self.parsed_description.other_keywords})
|
||||
def mvd(self):
|
||||
if not LARK_AVAILABLE:
|
||||
return None
|
||||
file_description = self.wrapped_data.header.file_description
|
||||
return MvdInfo(
|
||||
get_description=lambda: file_description.description,
|
||||
set_description=lambda d: setattr(file_description, "description", tuple(d))
|
||||
)
|
||||
|
||||
def __getattr__(self, attr) -> Union[Any, Callable[..., ifcopenshell.entity_instance]]:
|
||||
if attr[0:6] == "create":
|
||||
|
||||
Reference in New Issue
Block a user