From a614fac71a7b2a1b548f767eca35b033ac322fab Mon Sep 17 00:00:00 2001 From: Andrej Date: Mon, 2 Jun 2025 10:58:39 +0500 Subject: [PATCH] typing --- src/bonsai/bonsai/tool/loader.py | 3 - .../ifcopenshell/api/owner/add_application.py | 5 -- .../ifcopenshell/ifcopenshell_wrapper.pyi | 60 ++++++++++++------- .../ifcopenshell/util/shape.py | 12 +--- src/ifcpatch/ifcpatch/__init__.py | 6 +- .../ifcpatch/recipes/ConvertLengthUnit.py | 1 - src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py | 26 +++++--- src/ifcpatch/ifcpatch/recipes/Migrate.py | 1 - 8 files changed, 59 insertions(+), 55 deletions(-) diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 0f3b97c5ea..6f58bbc665 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -74,9 +74,6 @@ class Loader(bonsai.core.tool.Loader): def get_representation_id_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> int: representation_id: str = geometry.id if "-" in representation_id: - # Example: 2432-openings-2468, where - # 2432 is mapped representation id - # and 2468 is IFCRELVOIDSELEMENT representation_id = re.sub(r"\D", "", representation_id.split("-")[0]) else: representation_id = re.sub(r"\D", "", representation_id) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py index 3f18754287..3fc9234c85 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py @@ -38,17 +38,12 @@ def add_application( :param application_developer: The IfcOrganization responsible for creating the application. Defaults to generating an IfcOpenShell organisation if none is provided. - :type application_developer: ifcopenshell.entity_instance, optional :param version: The version of the application. Defaults to the ifcopenshell.version data if not specified. - :type version: str, optional :param application_full_name: The name of the application - :type application_full_name: str, optional :param application_identifier: An identification string for the application intended for computers to read. - :type application_identifier: str, optional :return: The newly created IfcApplication - :rtype: ifcopenshell.entity_instance Example: diff --git a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi index 068b17d3e7..9f8db92bc6 100644 --- a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi +++ b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi @@ -218,7 +218,7 @@ class Element: @property def guid(self): ... @property - def id(self): ... + def id(self) -> int: ... @property def name(self): ... @property @@ -227,9 +227,9 @@ class Element: @property def product(self): ... @property - def transformation(self): ... + def transformation(self) -> Transformation: ... @property - def transformation_buffer(self): ... + def transformation_buffer(self) -> bytes: ... @property def type(self): ... @property @@ -342,7 +342,13 @@ class OpaqueNumber: class Representation: def entity(self): ... @property - def id(self): ... + def id(self) -> str: + """ + Example: `2432-openings-2468`, where + - 2432 - mapped representation id + - 2468 - IfcRelVoidsElement + """ + def settings(self): ... class Serialization(Representation): @@ -458,34 +464,34 @@ class Triangulation(Representation): @property def colors_buffer(self): ... @property - def edges(self): ... + def edges(self) -> tuple[int, ...]: ... @property - def edges_buffer(self): ... - def edges_item_ids(self): ... + def edges_buffer(self) -> bytes: ... + def edges_item_ids(self) -> tuple[int, ...]: ... @property - def edges_item_ids_buffer(self): ... + def edges_item_ids_buffer(self) -> bytes: ... @staticmethod def empty(settings): ... @property - def faces(self): ... + def faces(self) -> tuple[int, ...]: ... @property - def faces_buffer(self): ... + def faces_buffer(self) -> bytes: ... @property - def faces_tri(self): ... + def faces_tri(self) -> tuple[int, ...]: ... @property - def item_ids(self): ... + def item_ids(self) -> tuple[int, ...]: ... @property - def item_ids_buffer(self): ... + def item_ids_buffer(self) -> bytes: ... @property - def material_ids(self): ... + def material_ids(self) -> tuple[int, ...]: ... @property - def material_ids_buffer(self): ... + def material_ids_buffer(self) -> bytes: ... @property - def materials(self): ... + def materials(self) -> tuple[style, ...]: ... @property def normals(self): ... @property - def normals_buffer(self): ... + def normals_buffer(self) -> bytes: ... @property def polyhedral_faces_with_holes(self): ... @property @@ -497,13 +503,13 @@ class Triangulation(Representation): def uvs(self): ... def uvs_ref(self): ... @property - def verts(self): ... + def verts(self) -> tuple[float, ...]: ... @property - def verts_buffer(self): ... + def verts_buffer(self) -> bytes: ... class TriangulationElement(Element): @property - def geometry(self): ... + def geometry(self) -> Triangulation: ... def geometry_pointer(self): ... class TriangulationType: @@ -1183,7 +1189,19 @@ class style(item): def get_color(self): ... def has_specularity(self): ... def has_transparency(self): ... - def instance_id(self): ... + def instance_id(self) -> int: + """ + Possible values for `instance_id`: + - IFC style id if style assigned to the representation items directly + or through material with a style; + - IFC material id if both true: + - element has a material without a style; + - there are parts of the geometry that has no other style assigned to them; + - -1 in case if there is no material; + - 0 in case if there are default materials used. + """ + ... + def kind(self): ... class surface(geom_item): ... diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape.py b/src/ifcopenshell-python/ifcopenshell/util/shape.py index 08ce7bf25b..2047de1834 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape.py @@ -277,17 +277,7 @@ def get_normals(geometry: ShapeType) -> npt.NDArray[np.float64]: def get_shape_material_styles(geometry: ShapeType) -> tuple[W.style, ...]: - """Get list of material styles. - - Possible values for `style.instance_id()`: - - IFC style id if style assigned to the representation items directly - or through material with a style; - - IFC material id if both true: - - element has a material without a style; - - there are parts of the geometry that has no other style assigned to them; - - -1 in case if there is no material; - - 0 in case if there are default materials used. - """ + """Get list of material styles.""" return geometry.materials diff --git a/src/ifcpatch/ifcpatch/__init__.py b/src/ifcpatch/ifcpatch/__init__.py index c2c46b47c3..3b102af0b2 100644 --- a/src/ifcpatch/ifcpatch/__init__.py +++ b/src/ifcpatch/ifcpatch/__init__.py @@ -29,6 +29,7 @@ import collections import importlib import importlib.util import re +from pathlib import Path from typing import Union, Iterable, Optional, Any, TypedDict, Literal, Sequence from typing_extensions import NotRequired @@ -106,19 +107,16 @@ def execute(args: ArgumentsDict) -> Union[ifcopenshell.file, str]: return output -def write(output: Union[ifcopenshell.file, str], filepath: str) -> None: +def write(output: Union[ifcopenshell.file, str], filepath: Union[Path, str]) -> None: """Write the output of an IFC patch to a file Typically a patch output would be a patched IFC model file object, or as a string. This function lets you agnostically write that output to a filepath. :param output: The results from ifcpatch.execute() - :type output: ifcopenshell.file.file,str :param filepath: A filepath to where the results of the patched model should be written to. - :type filepath: str :return: None - :rtype: None """ if output is None: return diff --git a/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py b/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py index 297cdfbda6..7560d7abe5 100644 --- a/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py +++ b/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py @@ -63,7 +63,6 @@ class Patcher: Allowed imperial units include INCH, FOOT, MILE. :param unit: The name of the desired unit, defaults to "METER" - :type unit: LengthUnit Example: diff --git a/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py b/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py index b8e9215796..966986841e 100644 --- a/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py +++ b/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py @@ -29,6 +29,7 @@ import numpy as np import multiprocessing import ifcopenshell import ifcopenshell.geom +import ifcopenshell.ifcopenshell_wrapper as W import ifcopenshell.util.attribute import ifcopenshell.util.element import ifcopenshell.util.placement @@ -36,8 +37,8 @@ import ifcopenshell.util.schema import ifcopenshell.util.shape import ifcopenshell.util.unit from pathlib import Path -from ifcopenshell.geom import ShapeType -from typing import Any, TYPE_CHECKING, Literal +from typing import Any, TYPE_CHECKING, Literal, Union +from typing_extensions import assert_never SQLTypes = typing.Literal["SQLite", "MySQL"] @@ -132,6 +133,9 @@ class Patcher: self.should_get_geometry = should_get_geometry self.should_skip_geometry_data = should_skip_geometry_data + geometry_rows: dict[str, tuple[str, bytes, bytes, bytes, bytes, str]] + shape_rows: dict[int, tuple[int, list[float], list[float], list[float], bytes, str]] + def patch(self) -> None: suffix = ".db" if self.sql_type == "SQLite" else ".sqlite" database = Path(self.database) @@ -153,6 +157,8 @@ class Patcher: host=self.host, user=self.username, password=self.password, database=str(database) ) self.c = self.db.cursor() + else: + assert False self.create_id_map() self.create_metadata() @@ -165,7 +171,9 @@ class Patcher: self.create_geometry() if self.full_schema: - ifc_classes = [d.name() for d in self.schema.declarations() if str(d).startswith("