more typing

This commit is contained in:
Andrej730
2024-03-11 12:06:56 +05:00
parent 15dd93b9fb
commit a4a965e7ab
3 changed files with 148 additions and 62 deletions
+31 -25
View File
@@ -23,33 +23,39 @@ import hashlib
import zipfile import zipfile
import tempfile import tempfile
import ifcopenshell import ifcopenshell
import ifcopenshell.geom
import ifcopenshell.ifcopenshell_wrapper
import blenderbim.bim.handler import blenderbim.bim.handler
import blenderbim.tool as tool import blenderbim.tool as tool
from pathlib import Path from pathlib import Path
from blenderbim.tool.brick import BrickStore from blenderbim.tool.brick import BrickStore
from typing import Set, Union
IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object]
class IfcStore: class IfcStore:
path = "" path = ""
file = None file: ifcopenshell.file = None
schema = None schema: ifcopenshell.ifcopenshell_wrapper.schema_definition = None
cache = None cache: ifcopenshell.ifcopenshell_wrapper.HdfSerializer = None
cache_path = None cache_path: str = None
id_map = {} id_map: dict[int, IFC_CONNECTED_TYPE] = {}
guid_map = {} guid_map: dict[str, IFC_CONNECTED_TYPE] = {}
edited_objs = set() edited_objs: Set[bpy.types.Object] = set()
pset_template_path = "" pset_template_path = ""
pset_template_file = None pset_template_file: ifcopenshell.file = None
classification_path = "" classification_path = ""
classification_file = None classification_file: ifcopenshell.file = None
library_path = "" library_path = ""
library_file = None library_file: ifcopenshell.file = None
current_transaction = "" current_transaction = ""
last_transaction = "" last_transaction = ""
history = [] history = []
future = [] future = []
schema_identifiers = ["IFC4", "IFC2X3", "IFC4X3"] schema_identifiers = ["IFC4", "IFC2X3", "IFC4X3"]
session_files = {} session_files: dict[str, ifcopenshell.file] = {}
@staticmethod @staticmethod
def purge(): def purge():
@@ -117,7 +123,7 @@ class IfcStore:
IfcStore.get_cache() IfcStore.get_cache()
@staticmethod @staticmethod
def load_file(path): def load_file(path) -> None:
if not os.path.isfile(path): if not os.path.isfile(path):
return return
extension = path.split(".")[-1] extension = path.split(".")[-1]
@@ -146,7 +152,7 @@ class IfcStore:
return IfcStore.schema return IfcStore.schema
@staticmethod @staticmethod
def get_element(id_or_guid): def get_element(id_or_guid: Union[int, str]) -> IFC_CONNECTED_TYPE:
if isinstance(id_or_guid, int): if isinstance(id_or_guid, int):
map_object = IfcStore.id_map map_object = IfcStore.id_map
else: else:
@@ -159,7 +165,7 @@ class IfcStore:
return obj return obj
@staticmethod @staticmethod
def relink_all_objects(): def relink_all_objects() -> None:
if not IfcStore.get_file(): if not IfcStore.get_file():
return return
for obj in bpy.data.objects: for obj in bpy.data.objects:
@@ -172,7 +178,7 @@ class IfcStore:
IfcStore.relink_object(obj) IfcStore.relink_object(obj)
@staticmethod @staticmethod
def relink_object(obj): def relink_object(obj: IFC_CONNECTED_TYPE) -> None:
if not obj: if not obj:
return return
if obj.BIMObjectProperties.ifc_definition_id: if obj.BIMObjectProperties.ifc_definition_id:
@@ -193,7 +199,7 @@ class IfcStore:
IfcStore.commit_link_element(data) IfcStore.commit_link_element(data)
@staticmethod @staticmethod
def link_element(element, obj): def link_element(element: ifcopenshell.entity_instance, obj: IFC_CONNECTED_TYPE) -> None:
# Please use tool.Ifc.link() instead of this method. We want to # Please use tool.Ifc.link() instead of this method. We want to
# refactor this class and deprecate usage of IfcStore in favour of # refactor this class and deprecate usage of IfcStore in favour of
# tools. # tools.
@@ -259,7 +265,7 @@ class IfcStore:
# TODO We're handling id_map and guid_map, but what about edited_objs? This might cause big problems. # TODO We're handling id_map and guid_map, but what about edited_objs? This might cause big problems.
@staticmethod @staticmethod
def rollback_unlink_element(data): def rollback_unlink_element(data) -> None:
if "id" not in data or "obj" not in data: if "id" not in data or "obj" not in data:
return return
obj = bpy.data.objects.get(data["obj"]) obj = bpy.data.objects.get(data["obj"])
@@ -268,13 +274,13 @@ class IfcStore:
IfcStore.guid_map[data["guid"]] = obj IfcStore.guid_map[data["guid"]] = obj
@staticmethod @staticmethod
def commit_unlink_element(data): def commit_unlink_element(data) -> None:
del IfcStore.id_map[data["id"]] del IfcStore.id_map[data["id"]]
if data["guid"]: if data["guid"]:
del IfcStore.guid_map[data["guid"]] del IfcStore.guid_map[data["guid"]]
@staticmethod @staticmethod
def unlink_element(element=None, obj=None): def unlink_element(element: ifcopenshell.entity_instance = None, obj: IFC_CONNECTED_TYPE = None) -> None:
if element is None: if element is None:
try: try:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
@@ -320,7 +326,7 @@ class IfcStore:
) )
@staticmethod @staticmethod
def execute_ifc_operator(operator, context, is_invoke=False): def execute_ifc_operator(operator: bpy.types.Operator, context: bpy.types.Context, is_invoke=False):
bpy.context.scene.BIMProperties.is_dirty = True bpy.context.scene.BIMProperties.is_dirty = True
is_top_level_operator = not bool(IfcStore.current_transaction) is_top_level_operator = not bool(IfcStore.current_transaction)
@@ -354,17 +360,17 @@ class IfcStore:
return result return result
@staticmethod @staticmethod
def begin_transaction(operator): def begin_transaction(operator: bpy.types.Operator) -> None:
IfcStore.current_transaction = str(uuid.uuid4()) IfcStore.current_transaction = str(uuid.uuid4())
operator.transaction_key = IfcStore.current_transaction operator.transaction_key = IfcStore.current_transaction
@staticmethod @staticmethod
def end_transaction(operator): def end_transaction(operator: bpy.types.Operator) -> None:
IfcStore.current_transaction = "" IfcStore.current_transaction = ""
operator.transaction_key = "" operator.transaction_key = ""
@staticmethod @staticmethod
def add_transaction_operation(operator, rollback=None, commit=None): def add_transaction_operation(operator: bpy.types.Operator, rollback=None, commit=None) -> None:
key = getattr(operator, "transaction_key", None) key = getattr(operator, "transaction_key", None)
data = getattr(operator, "transaction_data", None) data = getattr(operator, "transaction_data", None)
bpy.context.scene.BIMProperties.last_transaction = key bpy.context.scene.BIMProperties.last_transaction = key
@@ -380,7 +386,7 @@ class IfcStore:
IfcStore.future = [] IfcStore.future = []
@staticmethod @staticmethod
def undo(until_key=None): def undo(until_key=None) -> None:
BrickStore.undo() BrickStore.undo()
if not IfcStore.history: if not IfcStore.history:
return return
@@ -395,7 +401,7 @@ class IfcStore:
IfcStore.future.append(event) IfcStore.future.append(event)
@staticmethod @staticmethod
def redo(until_key=None): def redo(until_key=None) -> None:
BrickStore.redo() BrickStore.redo()
if not IfcStore.future: if not IfcStore.future:
@@ -30,7 +30,7 @@ import functools
import subprocess import subprocess
import sys import sys
import time import time
from typing import Union from typing import Union, Any, Callable
from . import ifcopenshell_wrapper from . import ifcopenshell_wrapper
from . import settings from . import settings
@@ -196,7 +196,36 @@ class entity_instance(object):
) )
@staticmethod @staticmethod
def walk(f, g, value): def walk(f: Callable[[Any], bool], g: Callable[[Any], Any], value: Any) -> Any:
"""
Applies transformation to `value` based on a given condition.
If value is a nested structure (e.g., a list or a tuple) will apply transformation to it's elements.
.
:param f: A callable that takes a single argument and returns a boolean value. It represents the condition
:type f: Callable
:param g: A callable that takes a single argument and returns a transformed value. It represents the transformation
:type g: Callable
:param value: Any object, the input value to be processed
:type value: Any
:return: Transformed value
:rtype: Any
Example:
.. code:: python
# Define condition and transformation functions
condition = lambda v: v == old
transform = lambda v: new
# Usage example
attribute_value = element.RelatedElements
print(old in attribute_value, new in attribute_value) # True, False
result = element.walk(condition, transform, element.RelatedElements)
print(old in attribute_value, new in attribute_value) # False, True
"""
if isinstance(value, (tuple, list)): if isinstance(value, (tuple, list)):
return tuple(map(functools.partial(entity_instance.walk, f, g), value)) return tuple(map(functools.partial(entity_instance.walk, f, g), value))
elif f(value): elif f(value):
@@ -18,10 +18,18 @@
from __future__ import annotations from __future__ import annotations
import ifcopenshell import ifcopenshell
from typing import List from typing import List, Any, Callable
def get_pset(element, name, prop=None, psets_only=False, qtos_only=False, should_inherit=True, verbose=False): def get_pset(
element: ifcopenshell.entity_instance,
name: str,
prop: str = None,
psets_only=False,
qtos_only=False,
should_inherit=True,
verbose=False,
) -> dict:
"""Retrieve a single property set or single property """Retrieve a single property set or single property
This is more efficient than ifcopenshell.util.element.get_psets if you know This is more efficient than ifcopenshell.util.element.get_psets if you know
@@ -107,7 +115,9 @@ def get_pset(element, name, prop=None, psets_only=False, qtos_only=False, should
return value return value
def get_psets(element, psets_only=False, qtos_only=False, should_inherit=True, verbose=False): def get_psets(
element: ifcopenshell.entity_instance, psets_only=False, qtos_only=False, should_inherit=True, verbose=False
) -> dict:
"""Retrieve property sets, their related properties' names & values and ids. """Retrieve property sets, their related properties' names & values and ids.
If should_inherit is true, the pset "id" only refers to the ID of the If should_inherit is true, the pset "id" only refers to the ID of the
@@ -301,7 +311,7 @@ def get_properties(properties, verbose=False):
return results return results
def get_predefined_type(element): def get_predefined_type(element: ifcopenshell.entity_instance) -> str:
"""Retrieves the PrefefinedType attribute of an element. """Retrieves the PrefefinedType attribute of an element.
If the predefined type is user defined, the custom type (such as object If the predefined type is user defined, the custom type (such as object
@@ -334,7 +344,7 @@ def get_predefined_type(element):
return predefined_type return predefined_type
def get_type(element): def get_type(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
"""Retrieves the construction type element of an element occurrence """Retrieves the construction type element of an element occurrence
:param element: The element occurrence :param element: The element occurrence
@@ -359,7 +369,7 @@ def get_type(element):
return relationship.RelatingType return relationship.RelatingType
def get_types(type): def get_types(type: ifcopenshell.entity_instance) -> List[ifcopenshell.entity_instance]:
"""Get all the occurrences of a type element """Get all the occurrences of a type element
:param type: The type element :param type: The type element
@@ -408,7 +418,9 @@ def get_shape_aspects(element: ifcopenshell.entity_instance) -> List[ifcopenshel
return shape_aspects return shape_aspects
def get_material(element, should_skip_usage=False, should_inherit=True): def get_material(
element: ifcopenshell.entity_instance, should_skip_usage=False, should_inherit=True
) -> ifcopenshell.entity_instance:
"""Gets the material of the element """Gets the material of the element
The material may be a single material, material set (layered, profiled, or The material may be a single material, material set (layered, profiled, or
@@ -449,7 +461,7 @@ def get_material(element, should_skip_usage=False, should_inherit=True):
return get_material(relating_type, should_skip_usage) return get_material(relating_type, should_skip_usage)
def get_materials(element, should_inherit=True): def get_materials(element: ifcopenshell.entity_instance, should_inherit=True) -> List[ifcopenshell.entity_instance]:
"""Gets individual materials of an element """Gets individual materials of an element
If the element has a material set, the individual materials of that set are If the element has a material set, the individual materials of that set are
@@ -484,7 +496,7 @@ def get_materials(element, should_inherit=True):
return list(material.Materials) return list(material.Materials)
def get_styles(element): def get_styles(element: ifcopenshell.entity_instance) -> List[ifcopenshell.entity_instance]:
"""Retrieves the styles used in an element's representation. """Retrieves the styles used in an element's representation.
Styles may be retreived from the material or the body representation. Styles may be retreived from the material or the body representation.
@@ -528,7 +540,9 @@ def get_styles(element):
return styles return styles
def get_elements_by_material(ifc_file, material): def get_elements_by_material(
ifc_file: ifcopenshell.file, material: ifcopenshell.entity_instance
) -> List[ifcopenshell.entity_instance]:
"""Retrieves the elements related to a material. """Retrieves the elements related to a material.
This includes elements using the material as part of a material set or set This includes elements using the material as part of a material set or set
@@ -570,7 +584,9 @@ def get_elements_by_material(ifc_file, material):
return results return results
def get_elements_by_style(ifc_file, style): def get_elements_by_style(
ifc_file: ifcopenshell.file, style: ifcopenshell.entity_instance
) -> List[ifcopenshell.entity_instance]:
"""Retrieves the elements whose geometric representation uses a style """Retrieves the elements whose geometric representation uses a style
:param ifc_file: The IFC file :param ifc_file: The IFC file
@@ -610,7 +626,9 @@ def get_elements_by_style(ifc_file, style):
return results return results
def get_elements_by_representation(ifc_file, representation): def get_elements_by_representation(
ifc_file: ifcopenshell.file, representation: ifcopenshell.entity_instance
) -> List[ifcopenshell.entity_instance]:
"""Gets all elements using a geometric representation """Gets all elements using a geometric representation
:param ifc_file: The IFC file :param ifc_file: The IFC file
@@ -642,7 +660,9 @@ def get_elements_by_representation(ifc_file, representation):
return results return results
def get_elements_by_layer(ifc_file, layer): def get_elements_by_layer(
ifc_file: ifcopenshell.file, layer: ifcopenshell.entity_instance
) -> List[ifcopenshell.entity_instance]:
"""Get all the elements that are used by a presentation layer """Get all the elements that are used by a presentation layer
:param ifc_file: The IFC file :param ifc_file: The IFC file
@@ -663,7 +683,9 @@ def get_elements_by_layer(ifc_file, layer):
return results return results
def get_layers(ifc_file, element): def get_layers(
ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance
) -> List[ifcopenshell.entity_instance]:
"""Get the CAD layers that an element is part of """Get the CAD layers that an element is part of
An element may have portions or all of its geometry assigned to a An element may have portions or all of its geometry assigned to a
@@ -701,7 +723,9 @@ def get_layers(ifc_file, element):
return layers return layers
def get_container(element, should_get_direct=False, ifc_class=None): def get_container(
element: ifcopenshell.entity_instance, should_get_direct=False, ifc_class: str = None
) -> ifcopenshell.entity_instance:
""" """
Retrieves the spatial structure container of an element. Retrieves the spatial structure container of an element.
@@ -717,6 +741,7 @@ def get_container(element, should_get_direct=False, ifc_class=None):
example, you may be after the storey, not a space. example, you may be after the storey, not a space.
:type ifc_class: str :type ifc_class: str
:return: The direct or indirect container of the element or None. :return: The direct or indirect container of the element or None.
:rtype: ifcopenshell.entity_instance.entity_instance
Example: Example:
@@ -749,7 +774,7 @@ def get_container(element, should_get_direct=False, ifc_class=None):
container = get_aggregate(container) container = get_aggregate(container)
def get_referenced_structures(element): def get_referenced_structures(element: ifcopenshell.entity_instance) -> List[ifcopenshell.entity_instance]:
"""Retreives a list of referenced spatial elements """Retreives a list of referenced spatial elements
Typically useful for multistorey elements, such as columns or facade Typically useful for multistorey elements, such as columns or facade
@@ -758,6 +783,8 @@ def get_referenced_structures(element):
:param element: The IFC element :param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance :type element: ifcopenshell.entity_instance.entity_instance
:return: A list of IfcSpatialElement
:rtype: list[ifcopenshell.entity_instance.entity_instance]
Example: Example:
@@ -771,7 +798,7 @@ def get_referenced_structures(element):
return [] return []
def get_decomposition(element, is_recursive=True): def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True) -> List[ifcopenshell.entity_instance]:
""" """
Retrieves all subelements of an element based on the spatial decomposition Retrieves all subelements of an element based on the spatial decomposition
hierarchy. This includes all subspaces and elements contained in subspaces, hierarchy. This includes all subspaces and elements contained in subspaces,
@@ -813,11 +840,13 @@ def get_decomposition(element, is_recursive=True):
return results return results
def get_grouped_by(element): def get_grouped_by(element: ifcopenshell.entity_instance) -> List[ifcopenshell.entity_instance]:
"""Retrieves all subelements of an element based on the group. """Retrieves all subelements of an element based on the group.
:param element: The IFC element :param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:return: All subelements of the group :return: All subelements of the group
:rtype: list[ifcopenshell.entity_instance.entity_instance]
Example: Example:
@@ -836,12 +865,14 @@ def get_grouped_by(element):
return results return results
def get_aggregate(element): def get_aggregate(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
""" """
Retrieves the aggregate parent of an element. Retrieves the aggregate parent of an element.
:param element: The IFC element :param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:return: The aggregate of the element :return: The aggregate of the element
:rtype: ifcopenshell.entity_instance.entity_instance
Example: Example:
@@ -855,12 +886,14 @@ def get_aggregate(element):
return element.Decomposes[0].RelatingObject return element.Decomposes[0].RelatingObject
def get_nest(element): def get_nest(element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
""" """
Retrieves the nest parent of an element. Retrieves the nest parent of an element.
:param element: The IFC element :param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:return: The nested whole of the element :return: The nested whole of the element
:rtype: ifcopenshell.entity_instance.entity_instance
Example: Example:
@@ -877,12 +910,14 @@ def get_nest(element):
return element.Decomposes[0].RelatingObject return element.Decomposes[0].RelatingObject
def get_parts(element): def get_parts(element: ifcopenshell.entity_instance) -> List[ifcopenshell.entity_instance]:
""" """
Retrieves the parts of an element that have an aggregation relationship. Retrieves the parts of an element that have an aggregation relationship.
:param element: The IFC element :param element: The IFC element
:type element: ifcopenshell.entity_instance.entity_instance
:return: The parts of the element :return: The parts of the element
:rtype: list[ifcopenshell.entity_instance.entity_instance]
Example: Example:
@@ -896,16 +931,17 @@ def get_parts(element):
return element.IsDecomposedBy[0].RelatedObjects return element.IsDecomposedBy[0].RelatedObjects
def get_components(element, include_ports=False): def get_components(element: ifcopenshell.entity_instance, include_ports=False) -> List[ifcopenshell.entity_instance]:
""" """
Retrieves the components of an element that have an nest relationship. Retrieves the components of an element that have an nest relationship.
For nested ports, see ifcopenshell.util.system. For nested ports, see ifcopenshell.util.system.
:param element: The IFC element :param element: The IFC element
:return: The components of the element
:param include_ports: Default as False. Set to true if you also want to get ports. :param include_ports: Default as False. Set to true if you also want to get ports.
:type include_ports: bool,optional :type include_ports: bool,optional
:return: The components of the element
:rtype: list[ifcopenshell.entity_instance.entity_instance]
Example: Example:
@@ -924,13 +960,13 @@ def get_components(element, include_ports=False):
return element.IsDecomposedBy[0].RelatedObjects return element.IsDecomposedBy[0].RelatedObjects
def replace_attribute(element, old, new): def replace_attribute(element: ifcopenshell.entity_instance, old: Any, new: Any) -> None:
for i, attribute in enumerate(element): for i, attribute_value in enumerate(element):
if has_element_reference(attribute, old): if has_element_reference(attribute_value, old):
element[i] = element.walk(lambda v: v == old, lambda v: new, attribute) element[i] = element.walk(lambda v: v == old, lambda v: new, attribute_value)
def has_element_reference(value, element): def has_element_reference(value: Any, element: ifcopenshell.entity_instance) -> bool:
if isinstance(value, (tuple, list)): if isinstance(value, (tuple, list)):
for v in value: for v in value:
if has_element_reference(v, element): if has_element_reference(v, element):
@@ -939,7 +975,7 @@ def has_element_reference(value, element):
return value == element return value == element
def remove_deep(ifc_file, element): def remove_deep(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> None:
"""Recursively purges a subgraph safely. """Recursively purges a subgraph safely.
Do not use, use remove_deep2() instead. Do not use, use remove_deep2() instead.
@@ -954,7 +990,7 @@ def remove_deep(ifc_file, element):
ifc_file.unbatch() ifc_file.unbatch()
def batch_remove_deep2(ifc_file): def batch_remove_deep2(ifc_file: ifcopenshell.file) -> None:
"""Enable batch removal after running remove_deep2 using serialisation """Enable batch removal after running remove_deep2 using serialisation
See #944 and #3226. Removing elements in an IFC graph is slow as a lot of See #944 and #3226. Removing elements in an IFC graph is slow as a lot of
@@ -990,7 +1026,7 @@ def batch_remove_deep2(ifc_file):
ifc_file.to_delete = set() ifc_file.to_delete = set()
def unbatch_remove_deep2(ifc_file): def unbatch_remove_deep2(ifc_file: ifcopenshell.file) -> ifcopenshell.file:
"""Finish removing elements batched from remove_deep2 using string replacement """Finish removing elements batched from remove_deep2 using string replacement
See documentation for batch_remove_deep2. See documentation for batch_remove_deep2.
@@ -1020,7 +1056,12 @@ def unbatch_remove_deep2(ifc_file):
return ifcopenshell.file.from_string("\n".join(result)) return ifcopenshell.file.from_string("\n".join(result))
def remove_deep2(ifc_file, element, also_consider=[], do_not_delete=[]): def remove_deep2(
ifc_file: ifcopenshell.file,
element: ifcopenshell.entity_instance,
also_consider: List[ifcopenshell.entity_instance] = [],
do_not_delete: List[ifcopenshell.entity_instance] = [],
) -> None:
"""Recursively purges a subgraph safely, starting at an element """Recursively purges a subgraph safely, starting at an element
This should always be used instead of remove_deep. See #1812. The start This should always be used instead of remove_deep. See #1812. The start
@@ -1047,6 +1088,10 @@ def remove_deep2(ifc_file, element, also_consider=[], do_not_delete=[]):
:param ifc_file: The IFC file object :param ifc_file: The IFC file object
:type ifc_file: ifcopenshell.file.file :type ifc_file: ifcopenshell.file.file
:param also_consider: elements to also consider as a part of a subgraph
:type also_consider: list[ifcopenshell.entity_instance.entity_instance], optional
:param do_not_delete: elements to protect from deletion
:type do_not_delete: list[ifcopenshell.entity_instance.entity_instance], optional
:param element: The starting element that defines the subgraph :param element: The starting element that defines the subgraph
:type element: ifcopenshell.entity_instance.entity_instance :type element: ifcopenshell.entity_instance.entity_instance
""" """
@@ -1088,7 +1133,7 @@ def remove_deep2(ifc_file, element, also_consider=[], do_not_delete=[]):
# ifc_file.unbatch() # ifc_file.unbatch()
def copy(ifc_file, element): def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
""" """
Copy a single element. Any referenced elements are not copied. Copy a single element. Any referenced elements are not copied.
@@ -1112,7 +1157,13 @@ def copy(ifc_file, element):
return new return new
def copy_deep(ifc_file, element, exclude=None, exclude_callback=None, copied_entities=None): def copy_deep(
ifc_file: ifcopenshell.file,
element: ifcopenshell.entity_instance,
exclude: List[str] = None,
exclude_callback: Callable[[ifcopenshell.entity_instance], bool] = None,
copied_entities: dict[int, ifcopenshell.entity_instance] = None,
) -> ifcopenshell.entity_instance:
""" """
Recursively copy an element and all of its directly related subelements. Recursively copy an element and all of its directly related subelements.
@@ -1132,7 +1183,7 @@ def copy_deep(ifc_file, element, exclude=None, exclude_callback=None, copied_ent
:param copied_entities: A dictionary of IDs as keys and entities as values :param copied_entities: A dictionary of IDs as keys and entities as values
to reuse when coming across the same entity twice. This can typically to reuse when coming across the same entity twice. This can typically
be left as None. be left as None.
:type copied_entities: dict[int:ifcopenshell.entity_instance.entity_instance] :type copied_entities: dict[int:ifcopenshell.entity_instance.entity_instance], optional
:return: The newly copied element :return: The newly copied element
:rtype: ifcopenshell.entity_instance.entity_instance :rtype: ifcopenshell.entity_instance.entity_instance
""" """