diff --git a/src/ifcopenshell-python/ifcopenshell/entity_instance.py b/src/ifcopenshell-python/ifcopenshell/entity_instance.py index 02a5b748b7..7d364df900 100644 --- a/src/ifcopenshell-python/ifcopenshell/entity_instance.py +++ b/src/ifcopenshell-python/ifcopenshell/entity_instance.py @@ -30,6 +30,7 @@ import functools import subprocess import sys import time +from typing import Union from . import ifcopenshell_wrapper from . import settings @@ -117,6 +118,8 @@ class entity_instance(object): >>> #423=IfcProductDefinitionShape($,$,(#409,#421)) """ + wrapped_data: ifcopenshell_wrapper.entity_instance + def __init__(self, e, file=None): if isinstance(e, tuple): e = ifcopenshell_wrapper.new_IfcBaseClass(*e) @@ -221,7 +224,7 @@ class entity_instance(object): return entity_instance.walk(is_instance, unwrap, v) - def attribute_type(self, attr): + def attribute_type(self, attr: int) -> str: """Return the data type of a positional attribute of the element :param attr: The index of the attribute @@ -231,7 +234,7 @@ class entity_instance(object): attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr) return self.wrapped_data.get_argument_type(attr_idx) - def attribute_name(self, attr_idx): + def attribute_name(self, attr_idx: int) -> str: """Return the name of a positional attribute of the element :param attr_idx: The index of the attribute @@ -272,7 +275,7 @@ class entity_instance(object): def __repr__(self): return repr(self.wrapped_data) - def to_string(self, valid_spf=True): + def to_string(self, valid_spf=True) -> str: """Returns a string representation of the current entity instance. Equal to str(self) when valid_spf=False. When valid_spf is True returns a representation of the string that conforms to valid Step @@ -283,7 +286,7 @@ class entity_instance(object): return self.wrapped_data.to_string(valid_spf) - def is_a(self, *args): + def is_a(self, *args) -> Union[str, bool]: """Return the IFC class name of an instance, or checks if an instance belongs to a class. The check will also return true if a parent class name is provided. @@ -306,7 +309,7 @@ class entity_instance(object): """ return self.wrapped_data.is_a(*args) - def id(self): + def id(self) -> int: """Return the STEP numerical identifier :rtype: int @@ -335,7 +338,7 @@ class entity_instance(object): other.wrapped_data.file_pointer(), ) - def is_entity(self): + def is_entity(self) -> bool: """Tests whether the instance is an entity type as opposed to a simple data type. Returns: @@ -430,7 +433,9 @@ class entity_instance(object): ) ) - def get_info(self, include_identifier=True, recursive=False, return_type=dict, ignore=(), scalar_only=False): + def get_info( + self, include_identifier=True, recursive=False, return_type=dict, ignore=(), scalar_only=False + ) -> dict: """Return a dictionary of the entity_instance's properties (Python and IFC) and their values. :param include_identifier: Whether or not to include the STEP numerical identifier diff --git a/src/ifcopenshell-python/ifcopenshell/file.py b/src/ifcopenshell-python/ifcopenshell/file.py index e654d1cd8c..692386f779 100644 --- a/src/ifcopenshell-python/ifcopenshell/file.py +++ b/src/ifcopenshell-python/ifcopenshell/file.py @@ -27,6 +27,7 @@ import numbers import zipfile import functools from pathlib import Path +from typing import Tuple, List import ifcopenshell.util.element import ifcopenshell.util.file @@ -195,7 +196,9 @@ class file(object): print(products[0] == ifc_file[122] == ifc_file["2XQ$n5SLP5MBLyL442paFx"]) # True """ - def __init__(self, f=None, schema=None, schema_version=None): + wrapped_data: ifcopenshell_wrapper.file + + def __init__(self, f: ifcopenshell_wrapper.file = None, schema: str = None, schema_version: Tuple[int] = None): """Create a new blank IFC model This IFC model does not have any entities in it yet. See the @@ -253,8 +256,9 @@ class file(object): self.transaction = None import weakref + file_dict[self.file_pointer()] = weakref.ref(self) - + def __del__(self): del file_dict[self.file_pointer()] @@ -294,7 +298,7 @@ class file(object): transaction.commit() self.history.append(transaction) - def create_entity(self, type, *args, **kwargs): + def create_entity(self, type: str, *args, **kwargs) -> ifcopenshell.entity_instance: """Create a new IFC entity in the file. :param type: Case insensitive name of the IFC class @@ -392,30 +396,43 @@ class file(object): elif isinstance(key, basestring): return entity_instance(self.wrapped_data.by_guid(str(key)), self) - def by_id(self, id): + def by_id(self, id: int) -> ifcopenshell.entity_instance: """Return an IFC entity instance filtered by IFC ID. :param id: STEP numerical identifier :type id: int + + :raises RuntimeError: If `id` is not found. + :returns: An ifcopenshell.entity_instance.entity_instance :rtype: ifcopenshell.entity_instance.entity_instance """ return self[id] - def by_guid(self, guid): + def by_guid(self, guid: str) -> ifcopenshell.entity_instance: """Return an IFC entity instance filtered by IFC GUID. :param guid: GlobalId value in 22-character encoded form :type guid: string + + :raises RuntimeError: If `guid` is not found. + :returns: An ifcopenshell.entity_instance.entity_instance :rtype: ifcopenshell.entity_instance.entity_instance + """ return self[guid] - def add(self, inst, _id=None): + def add(self, inst: ifcopenshell.entity_instance, _id: int = None) -> ifcopenshell.entity_instance: """Adds an entity including any dependent entities to an IFC file. + If the entity already exists, it is not re-added. Existence of entity is checked by it's `.identity()`. + + :param inst: The entity instance to add + :type inst: ifcopenshell.entity_instance.entity_instance + :returns: An ifcopenshell.entity_instance.entity_instance + :rtype: ifcopenshell.entity_instance.entity_instance + """ - If the entity already exists, it is not re-added.""" if self.transaction: max_id = self.wrapped_data.getMaxId() inst.wrapped_data.this.disown() @@ -425,7 +442,7 @@ class file(object): [self.transaction.store_create(e) for e in reversed(added_elements)] return result - def by_type(self, type, include_subtypes=True): + def by_type(self, type: str, include_subtypes=True) -> List[ifcopenshell.entity_instance]: """Return IFC objects filtered by IFC Type and wrapped with the entity_instance class. If an IFC type class has subclasses, all entities of those subclasses are also returned. @@ -441,7 +458,9 @@ class file(object): return [entity_instance(e, self) for e in self.wrapped_data.by_type(type)] return [entity_instance(e, self) for e in self.wrapped_data.by_type_excl_subtypes(type)] - def traverse(self, inst, max_levels=None, breadth_first=False): + def traverse( + self, inst: ifcopenshell.entity_instance, max_levels=None, breadth_first=False + ) -> List[ifcopenshell.entity_instance]: """Get a list of all referenced instances for a particular instance including itself :param inst: The entity instance to get all sub instances @@ -463,7 +482,9 @@ class file(object): return [entity_instance(e, self) for e in fn(inst.wrapped_data, max_levels)] - def get_inverse(self, inst, allow_duplicate=False, with_attribute_indices=False): + def get_inverse( + self, inst: ifcopenshell.entity_instance, allow_duplicate=False, with_attribute_indices=False + ) -> List[ifcopenshell.entity_instance]: """Return a list of entities that reference this entity :param inst: The entity instance to get inverse relationships @@ -488,7 +509,7 @@ class file(object): return set(inverses) - def get_total_inverses(self, inst): + def get_total_inverses(self, inst: ifcopenshell.entity_instance) -> int: """Returns the number of entities that reference this entity :param inst: The entity instance to get inverse relationships @@ -498,7 +519,7 @@ class file(object): """ return self.wrapped_data.get_total_inverses(inst.wrapped_data) - def remove(self, inst): + def remove(self, inst: ifcopenshell.entity_instance) -> None: """Deletes an IFC object in the file. Attribute values in other entity instances that reference the deleted @@ -573,7 +594,7 @@ class file(object): return @staticmethod - def from_string(s): + def from_string(s: str) -> ifcopenshell.entity_instance: return file(ifcopenshell_wrapper.read(s)) @staticmethod diff --git a/src/ifcpatch/ifcpatch/__init__.py b/src/ifcpatch/ifcpatch/__init__.py index c40f316563..acb17fb92e 100644 --- a/src/ifcpatch/ifcpatch/__init__.py +++ b/src/ifcpatch/ifcpatch/__init__.py @@ -25,9 +25,10 @@ import typing import inspect import collections import importlib +from typing import Union -def execute(args): +def execute(args: dict) -> Union[ifcopenshell.file, str]: """Execute a patch recipe The details of how the patch recipe is executed depends on the definition of @@ -80,7 +81,7 @@ def execute(args): return output -def write(output, filepath): +def write(output: Union[ifcopenshell.file, str], filepath: 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