Skip to content

Commit b67b5e8

Browse files
committed
typing
1 parent e2a06e1 commit b67b5e8

5 files changed

Lines changed: 63 additions & 33 deletions

File tree

src/ifccsv/ifccsv.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import ifcopenshell.util.element
3030
import ifcopenshell.util.schema
3131
from statistics import mean
32+
from typing import Optional, Union
3233

3334
try:
3435
from odf.namespaces import OFFICENS
@@ -269,7 +270,7 @@ def natural_sort(value):
269270
elif not include_global_id:
270271
self.results = sorted(self.results, key=lambda x: x[0])
271272

272-
def export_csv(self, output, delimiter=None):
273+
def export_csv(self, output: str, delimiter: Optional[str] = None) -> None:
273274
with open(output, "w", newline="", encoding="utf-8") as f:
274275
writer = csv.writer(f, delimiter=delimiter)
275276
writer.writerow(self.headers)
@@ -387,8 +388,16 @@ def Import(
387388
self.import_xlsx(ifc_file, table, attributes, null, empty, bool_true, bool_false)
388389

389390
def import_csv(
390-
self, ifc_file, table, attributes=None, delimiter=",", null="-", empty="", bool_true="YES", bool_false="NO"
391-
):
391+
self,
392+
ifc_file: ifcopenshell.file,
393+
table: str,
394+
attributes: Optional[list[Union[str, None]]] = None,
395+
delimiter: str = ",",
396+
null: str = "-",
397+
empty: str = "",
398+
bool_true: str = "YES",
399+
bool_false: str = "NO",
400+
) -> None:
392401
with open(table, newline="", encoding="utf-8") as f:
393402
reader = csv.reader(f, delimiter=delimiter)
394403
headers = []
@@ -421,7 +430,17 @@ def import_pd(self, ifc_file, df, attributes=None, null="-", empty="", bool_true
421430
for _, row in df.iterrows():
422431
self.process_row(ifc_file, row.tolist(), headers, attributes, null, empty, bool_true, bool_false)
423432

424-
def process_row(self, ifc_file, row, headers, attributes, null, empty, bool_true, bool_false):
433+
def process_row(
434+
self,
435+
ifc_file: ifcopenshell.file,
436+
row: list[str],
437+
headers: list[str],
438+
attributes: list[Union[str, None]],
439+
null: str,
440+
empty: str,
441+
bool_true: str,
442+
bool_false: str,
443+
) -> None:
425444
try:
426445
element = ifc_file.by_guid(row[0])
427446
except:
@@ -448,9 +467,7 @@ def process_row(self, ifc_file, row, headers, attributes, null, empty, bool_true
448467
parser.add_argument("-s", "--spreadsheet", type=str, default="data.csv", help="The spreadsheet file")
449468
parser.add_argument("-f", "--format", type=str, default="csv", help="The format, chosen from csv, ods, or xlsx")
450469
parser.add_argument("-d", "--delimiter", type=str, default=",", help="The delimiter in CSV. Defaults to a comma.")
451-
parser.add_argument(
452-
"-n", "--null", type=str, default="N/A", help="How to represent null values. Defaults to N/A."
453-
)
470+
parser.add_argument("-n", "--null", type=str, default="N/A", help="How to represent null values. Defaults to N/A.")
454471
parser.add_argument(
455472
"-e", "--empty", type=str, default="-", help="How to represent empty strings. Defaults to a hyphen."
456473
)

src/ifcopenshell-python/ifcopenshell/util/classification.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
1717
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
1818

1919
import ifcopenshell.util.element
20+
from typing import Optional
2021

2122

22-
def get_references(element, should_inherit=True):
23+
def get_references(element: ifcopenshell.entity_instance, should_inherit=True) -> set[ifcopenshell.entity_instance]:
2324
results = set()
2425
if not element.is_a("IfcRoot"):
2526
if hasattr(element, "HasExternalReferences"):
2627
return {r.RelatingReference for r in element.HasExternalReferences or []}
27-
elif hasattr(element, "HasExternalReference"): # Seriously, IFC?
28+
elif hasattr(element, "HasExternalReference"): # Seriously, IFC?
2829
return {r.RelatingReference for r in element.HasExternalReference or []}
2930
if should_inherit:
3031
element_type = ifcopenshell.util.element.get_type(element)
@@ -50,18 +51,17 @@ def get_references(element, should_inherit=True):
5051
return occurrence_results
5152

5253

53-
def get_classification(reference):
54+
def get_classification(reference: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
5455
if reference.is_a("IfcClassification"):
5556
return reference
5657
return get_classification(reference.ReferencedSource)
5758

5859

59-
def get_inherited_references(reference):
60+
def get_inherited_references(reference: Optional[ifcopenshell.entity_instance]) -> list[ifcopenshell.entity_instance]:
6061
results = []
6162
while True:
6263
if not reference or reference.is_a("IfcClassification"):
6364
break
6465
results.append(reference)
6566
reference = reference.ReferencedSource
6667
return results
67-

src/ifcopenshell-python/ifcopenshell/util/placement.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818

1919
import numpy as np
2020
import ifcopenshell
21+
from typing import Literal, Iterable
2122

2223

23-
def a2p(o, z, x):
24+
def a2p(o: Iterable[float], z: Iterable[float], x: Iterable[float]) -> np.array:
2425
"""Converts a location, X, and Z axis vector to a 4x4 transformation matrix
2526
2627
IFC uses a right-handed coordinate system, so it is not necessary to
@@ -73,7 +74,7 @@ def get_axis2placement(placement: ifcopenshell.entity_instance) -> np.array:
7374
return a2p(o, z, x)
7475

7576

76-
def get_local_placement(placement):
77+
def get_local_placement(placement: ifcopenshell.entity_instance) -> np.array:
7778
"""Parse a local placement into a 4x4 transformation matrix
7879
7980
This is typically used to find the location and rotation of an element. The
@@ -107,7 +108,7 @@ def get_local_placement(placement):
107108
return np.dot(parent, get_axis2placement(placement.RelativePlacement))
108109

109110

110-
def get_cartesiantransformationoperator3d(inst):
111+
def get_cartesiantransformationoperator3d(inst: ifcopenshell.entity_instance) -> np.array:
111112
"""Parses an IfcCartesianTransformationOperator into a 4x4 transformation matrix
112113
113114
Note that in general you will not need to call this directly. See
@@ -152,7 +153,7 @@ def get_cartesiantransformationoperator3d(inst):
152153
return m4
153154

154155

155-
def get_mappeditem_transformation(item):
156+
def get_mappeditem_transformation(item: ifcopenshell.entity_instance) -> np.array:
156157
"""Parse an IfcMappedItem into a 4x4 transformation matrix
157158
158159
Mapped items take a representation with an origin and transform them with a
@@ -170,7 +171,7 @@ def get_mappeditem_transformation(item):
170171
return get_cartesiantransformationoperator3d(item.MappingTarget) @ m4
171172

172173

173-
def get_storey_elevation(storey):
174+
def get_storey_elevation(storey: ifcopenshell.entity_instance) -> float:
174175
"""Get the Z elevation in project units of a buildling storey
175176
176177
Building storeys store elevation in two possible locations: the Z value of
@@ -187,7 +188,7 @@ def get_storey_elevation(storey):
187188
return getattr(storey, "Elevation", 0.0) or 0.0
188189

189190

190-
def rotation(angle, axis, is_degrees=True):
191+
def rotation(angle: float, axis: Literal["X", "Y", "Z"], is_degrees=True) -> np.array:
191192
"""Create a 4x4 numpy matrix representing an euler rotation
192193
193194
:param angle: The angle of rotation

src/ifcopenshell-python/ifcopenshell/util/schema.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
import time
2222
import ifcopenshell
2323
import ifcopenshell.util.attribute
24+
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
2425

2526
# This is highly experimental and incomplete, however, it may work for simple datasets.
2627
# In this simple implementation, we only support 2X3<->4 right now
2728

2829
cwd = os.path.dirname(os.path.realpath(__file__))
2930

3031

31-
def get_fallback_schema(version):
32+
def get_fallback_schema(version: str) -> str:
3233
"""fallback to the schema version we do have docs and mapping for,
3334
needed to support IFC versions like 4X3_RC1, 4X1 etc"""
3435
if version.startswith("IFC4X3"):
@@ -38,7 +39,7 @@ def get_fallback_schema(version):
3839
return version
3940

4041

41-
def is_a(entity, ifc_class):
42+
def is_a(entity: ifcopenshell.entity_instance, ifc_class: str) -> bool:
4243
ifc_class = ifc_class.upper()
4344
if entity.name_uc() == ifc_class:
4445
return True
@@ -59,7 +60,9 @@ def get_classes(declaration):
5960
return get_classes(entity)
6061

6162

62-
def reassign_class(ifc_file, element, new_class):
63+
def reassign_class(
64+
ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance, new_class: str
65+
) -> ifcopenshell.entity_instance:
6366
"""
6467
Attempts to change the class (entity name) of `element` to `new_class` by
6568
removing element and recreating a similar instance of type `new_class`
@@ -74,7 +77,7 @@ def reassign_class(ifc_file, element, new_class):
7477
It's unlikely that this affects real-world usage of this function.
7578
"""
7679

77-
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
80+
schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
7881
try:
7982
declaration = schema.declaration_by_name(new_class)
8083
except:
@@ -116,11 +119,11 @@ def reassign_class(ifc_file, element, new_class):
116119

117120

118121
class BatchReassignClass:
119-
def __init__(self, file):
122+
def __init__(self, file: ifcopenshell.file):
120123
self.file = file
121124
self.purge()
122125

123-
def reassign(self, element, new_class):
126+
def reassign(self, element: ifcopenshell.entity_instance, new_class: str) -> ifcopenshell.entity_instance:
124127
try:
125128
new_element = self.file.create_entity(new_class)
126129
except:
@@ -150,9 +153,12 @@ def unbatch(self):
150153
self.file.remove(element)
151154
self.purge()
152155

153-
def purge(self):
154-
self.replacements = {}
155-
self.to_delete = set()
156+
def purge(self) -> None:
157+
# mapping {inverse: {attribute_index: {old_element: new_element} } }
158+
self.replacements: dict[
159+
ifcopenshell.entity_instance, dict[int, dict[ifcopenshell.entity_instance, ifcopenshell.entity_instance]]
160+
] = {}
161+
self.to_delete: set[ifcopenshell.entity_instance] = set()
156162

157163

158164
class Migrator:
@@ -217,7 +223,7 @@ def __init__(self):
217223
"User": None,
218224
}
219225

220-
def migrate(self, element, new_file):
226+
def migrate(self, element: ifcopenshell.entity_instance, new_file: ifcopenshell.file) -> ifcopenshell.entity_instance:
221227
if element.id() == 0:
222228
return new_file.create_entity(element.is_a(), element.wrappedValue)
223229
try:

src/ifcopenshell-python/ifcopenshell/util/selector.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@
2525
import ifcopenshell.util.placement
2626
import ifcopenshell.util.geolocation
2727
import ifcopenshell.util.classification
28+
import ifcopenshell.util.schema
2829
from decimal import Decimal
29-
from typing import Optional
30+
from typing import Optional, Any, Union
3031

3132

3233
filter_elements_grammar = lark.Lark(
@@ -258,8 +259,8 @@ def format(query):
258259
return FormatTransformer().transform(format_grammar.parse(query))
259260

260261

261-
def get_element_value(element, query):
262-
keys = GetElementTransformer().transform(get_element_grammar.parse(query))
262+
def get_element_value(element: ifcopenshell.entity_instance, query: str) -> Any:
263+
keys: list[str] = GetElementTransformer().transform(get_element_grammar.parse(query))
263264
return Selector.get_element_value(element, keys)
264265

265266

@@ -309,7 +310,12 @@ def filter_elements(
309310
return transformer.elements
310311

311312

312-
def set_element_value(ifc_file, element, query, value):
313+
def set_element_value(
314+
ifc_file: ifcopenshell.file,
315+
element: ifcopenshell.entity_instance,
316+
query: Union[str, list[str]],
317+
value: Optional[str],
318+
) -> Union[ifcopenshell.entity_instance, None]:
313319
if isinstance(query, (list, tuple)):
314320
keys = query
315321
else:
@@ -885,7 +891,7 @@ def parse_filter_query(cls, filter_query):
885891
return {"keys": keys, "is_regex": is_regex}
886892

887893
@classmethod
888-
def get_element_value(cls, element, keys):
894+
def get_element_value(cls, element: ifcopenshell.entity_instance, keys: list[str]) -> Any:
889895
value = element
890896
for key in keys:
891897
if value is None:

0 commit comments

Comments
 (0)