move IfcHeaderExtractor to util.file

edited pyproject.toml as `disableBytesTypePromotions` is disabled by default in non-strict mode and type checker intrerprets `bytes` as `bytes | memoryview | bytearray` which is deprecated in https://peps.python.org/pep-0688/#no-special-meaning-for-bytes
This commit is contained in:
Andrej730
2024-07-01 13:33:47 +05:00
parent 375deaad1e
commit ae2a299616
4 changed files with 115 additions and 49 deletions
+1
View File
@@ -3,3 +3,4 @@ line-length = 120
[tool.pyright] [tool.pyright]
reportInvalidTypeForm = false reportInvalidTypeForm = false
disableBytesTypePromotions = true
-48
View File
@@ -20,7 +20,6 @@
import bpy import bpy
import json import json
import math import math
import zipfile
import ifcopenshell import ifcopenshell
import ifcopenshell.util.attribute import ifcopenshell.util.attribute
import ifcopenshell.util.element import ifcopenshell.util.element
@@ -322,50 +321,3 @@ def draw_filter(layout, filter_groups, data, module):
op.group_index = i op.group_index = i
op.index = j op.index = j
op.module = module op.module = module
# TODO this should move into ifcopenshell.util
class IfcHeaderExtractor:
def __init__(self, filepath: str):
self.filepath = filepath
def extract(self):
extension = self.filepath.split(".")[-1]
if extension.lower() == "ifc":
with open(self.filepath) as ifc_file:
return self.extract_ifc_spf(ifc_file)
elif extension.lower() == "ifczip":
return self.extract_ifc_zip()
elif extension.lower() == "ifcsqlite":
return {} # TODO
def extract_ifc_spf(self, ifc_file):
# https://www.steptools.com/stds/step/IS_final_p21e3.html#clause-8
data = {}
max_lines_to_parse = 50
for _ in range(max_lines_to_parse):
line = next(ifc_file)
if isinstance(line, bytes):
line = line.decode("utf-8")
if line.startswith("FILE_DESCRIPTION"):
for i, part in enumerate(line.split("'")):
if i == 1:
data["description"] = part
elif i == 3:
data["implementation_level"] = part
elif line.startswith("FILE_NAME"):
for i, part in enumerate(line.split("'")):
if i == 1:
data["name"] = part
elif i == 3:
data["time_stamp"] = part
elif line.startswith("FILE_SCHEMA"):
data["schema_name"] = line.split("'")[1]
break
return data
def extract_ifc_zip(self):
archive = zipfile.ZipFile(self.filepath, "r")
return self.extract_ifc_spf(archive.open(archive.filelist[0]))
+1 -1
View File
@@ -33,7 +33,7 @@ from . import ifc
from blenderbim import get_debug_info from blenderbim import get_debug_info
import blenderbim.bim import blenderbim.bim
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.helper import IfcHeaderExtractor from ifcopenshell.util.file import IfcHeaderExtractor
from blenderbim.bim.prop import Attribute from blenderbim.bim.prop import Attribute
from typing import Optional from typing import Optional
@@ -0,0 +1,113 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import zipfile
from typing import IO, Union, TypedDict, NotRequired
class HeaderMetadata(TypedDict):
name: NotRequired[str]
description: NotRequired[str]
implementation_level: NotRequired[str]
time_stamp: NotRequired[str]
schema_name: NotRequired[str]
class IfcHeaderExtractor:
"""An utility class for extracting header information from IFC files.
This class provides functionality to extract key metadata from the header section of
IFC files without recreating the entire file as `ifcopenshell.file`.
For optimization, extractor will search only for the first 50 lines
of the IFC file for metadata.
Supported formats: .ifc, .ifczip.
Metadata available by the extraction is presented in the example below.
Example:
.. code:: python
from ifcopenshell.util.file import IfcHeaderExtractor
extractor = IfcHeaderExtractor("path/to/your/file.ifc")
# Get dictionary of the extracted metadata.
header_info = extractor.extract()
# Print the extracted information
# ViewDefinition[DesignTransferView]
print("File Description:", header_info.get("description"))
# 2;1
print("Implementation Level:", header_info.get("implementation_level"))
# file.ifc
print("File Name:", header_info.get("name"))
# 2024-06-25T15:48:10+05:00
print("Time Stamp:", header_info.get("time_stamp"))
# IFC4X3_ADD2
print("Schema Name:", header_info.get("schema_name"))
"""
def __init__(self, filepath: str):
self.filepath = filepath
def extract(self) -> HeaderMetadata:
extension = self.filepath.split(".")[-1]
if extension.lower() == "ifc":
with open(self.filepath) as ifc_file:
return self.extract_ifc_spf(ifc_file)
elif extension.lower() == "ifczip":
return self.extract_ifc_zip()
elif extension.lower() == "ifcsqlite":
return {} # TODO
raise ValueError(f"Unsupported file extension: '{extension}'.")
def extract_ifc_spf(self, ifc_file: Union[IO[bytes], IO[str]]) -> HeaderMetadata:
# https://www.steptools.com/stds/step/IS_final_p21e3.html#clause-8
data = HeaderMetadata()
max_lines_to_parse = 50
for _ in range(max_lines_to_parse):
line = next(ifc_file)
if isinstance(line, bytes):
line = line.decode("utf-8")
if line.startswith("FILE_DESCRIPTION"):
for i, part in enumerate(line.split("'")):
if i == 1:
data["description"] = part
elif i == 3:
data["implementation_level"] = part
elif line.startswith("FILE_NAME"):
for i, part in enumerate(line.split("'")):
if i == 1:
data["name"] = part
elif i == 3:
data["time_stamp"] = part
elif line.startswith("FILE_SCHEMA"):
data["schema_name"] = line.split("'")[1]
break
return data
def extract_ifc_zip(self) -> HeaderMetadata:
archive = zipfile.ZipFile(self.filepath, "r")
return self.extract_ifc_spf(archive.open(archive.filelist[0]))