mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-18 03:19:53 +00:00
Fix all ty diagnostics on ifcviewer-wgpu (ci-lint ty-ios + ty-bonsai)
This branch carried v0.8.0's strict `[tool.ty.rules] all = "error"` config but not the source fixes that were made upstream to satisfy it, so both ci-lint ty gates were failing: `poe ty-ios` reported 256 diagnostics and `poe ty-bonsai` 258. Both are now clean. Most fixes are ported from v0.8.0 and follow two idioms: initialise a name before a conditional that may not bind it (plus an `assert` where the invariant is real but not provable), and close an exhaustive `if`/`elif` chain with `else: assert False, <discriminant>`. The branch's own newer accessors are preserved throughout - `.file`, `.declaration`, `file.types()`, `get_max_id()` are kept rather than reverted to `wrapped_data.*`, and non-ty upstream changes (notably the in-progress geometry cache removal) are deliberately not pulled in. Notable fixes that are not straight ports: * ifcopenshell_wrapper.pyi: `entity_instance.file` was declared as `def file(self) -> file`, where the property name shadows the `class file` below it, so the annotation resolved to `Unknown`. Every `element.file` in the codebase was therefore unchecked. Qualifying it to `ifcopenshell.file` restores `.schema` to its Literal union and surfaces no new diagnostics. * model/wall.py: a duplicated merge fragment in the void-straddle path ran an always-true `if void_straddles:` that read `new_opening` from the mutually exclusive branch (stale value, or NameError on the first iteration), followed by an unreachable duplicate `elif`. Removing it makes the file match v0.8.0. * light/operator.py: upstream's own fix unpacks three targets from two values and raises ValueError unconditionally; corrected to `None, None, None`. * assign_system.py, validate.py, geom/main.py: walrus-in-genexp is valid at runtime (PEP 572 binds in the containing scope) but ty does not model it; rewritten as explicit loops, matching upstream. Verified: poe ty-ios, poe ty-bonsai, ruff check src/ nix/, black --check ., and compileall -W error at py3.10 (ifcopenshell-python) and py3.11 (bonsai). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -142,6 +142,8 @@ class Facet:
|
||||
templates = [
|
||||
t.replace("shall", "may").replace("Shall", "May").replace("must", "may") for t in templates
|
||||
]
|
||||
else:
|
||||
assert False, clause_type
|
||||
|
||||
for template in templates:
|
||||
total_variables = len(template) - len(template.replace("{", ""))
|
||||
@@ -242,6 +244,7 @@ class Entity(Facet):
|
||||
elif not is_pass:
|
||||
reason = {"type": "NAME", "actual": inst.is_a().upper()}
|
||||
|
||||
predefined_type = None
|
||||
if is_pass and self.predefinedType:
|
||||
if self.predefinedType == "USERDEFINED":
|
||||
is_pass = ifcopenshell.util.element.is_userdefined_type(inst)
|
||||
@@ -616,6 +619,8 @@ class PartOf(Facet):
|
||||
if predefined_type != self.predefinedType:
|
||||
is_pass = False
|
||||
reason = {"type": "PREDEFINEDTYPE", "actual": predefined_type}
|
||||
else:
|
||||
assert False, self.relation
|
||||
|
||||
if self.cardinality == "prohibited":
|
||||
return PartOfResult(not is_pass, {"type": "PROHIBITED"})
|
||||
@@ -798,11 +803,13 @@ class Property(Facet):
|
||||
]
|
||||
elif prop_entity.is_a("IfcPropertyBoundedValue"):
|
||||
values = []
|
||||
data_type = None
|
||||
for attribute in ["UpperBoundValue", "LowerBoundValue", "SetPointValue"]:
|
||||
value = getattr(prop_entity, attribute)
|
||||
if value is not None:
|
||||
data_type = value.is_a()
|
||||
values.append(value.wrappedValue)
|
||||
assert data_type is not None, prop_entity
|
||||
if self.dataType and data_type.lower() != self.dataType.lower():
|
||||
is_pass = False
|
||||
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||
@@ -823,6 +830,7 @@ class Property(Facet):
|
||||
elif prop_entity.is_a("IfcPropertyTableValue"):
|
||||
values = []
|
||||
units = ifcopenshell.util.unit.get_property_table_unit(prop_entity, inst.file)
|
||||
data_type = None
|
||||
for attribute in ["Defining", "Defined"]:
|
||||
column_values = props[pset_name][prop_entity.Name][f"{attribute}Values"]
|
||||
if not column_values:
|
||||
@@ -845,6 +853,7 @@ class Property(Facet):
|
||||
values.extend(column_values)
|
||||
if not values:
|
||||
is_pass = False
|
||||
assert data_type is not None, prop_entity
|
||||
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||
break
|
||||
props[pset_name][prop_entity.Name] = values
|
||||
@@ -982,6 +991,8 @@ class Material(Facet):
|
||||
values.update(
|
||||
[item.Name, item.Category, item.Material.Name, getattr(item.Material, "Category", None)]
|
||||
)
|
||||
else:
|
||||
assert False, material
|
||||
|
||||
is_pass = False
|
||||
for value in values:
|
||||
|
||||
@@ -24,6 +24,7 @@ import os
|
||||
import re
|
||||
import sys
|
||||
from typing import Literal, Optional, TypedDict, Union
|
||||
from typing_extensions import NotRequired
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
@@ -96,6 +97,12 @@ class ResultsSpecification(TypedDict):
|
||||
applicability: list[str]
|
||||
requirements: list[ResultsRequirement]
|
||||
|
||||
# Filled in by `Html.report()`.
|
||||
is_prohibited: NotRequired[bool]
|
||||
has_requirements: NotRequired[bool]
|
||||
has_omitted_applicable: NotRequired[bool]
|
||||
total_omitted_applicable: NotRequired[int]
|
||||
|
||||
|
||||
class ResultsRequirement(TypedDict):
|
||||
facet_type: str
|
||||
@@ -111,6 +118,15 @@ class ResultsRequirement(TypedDict):
|
||||
total_fail: int
|
||||
percent_pass: ResultsPercent
|
||||
|
||||
# Filled in by `Html.report()`.
|
||||
total_failed_entities: NotRequired[int]
|
||||
total_omitted_failures: NotRequired[int]
|
||||
has_omitted_failures: NotRequired[bool]
|
||||
total_passed_entities: NotRequired[int]
|
||||
total_omitted_passes: NotRequired[int]
|
||||
has_omitted_passes: NotRequired[bool]
|
||||
instructions: NotRequired[str | None]
|
||||
|
||||
|
||||
# use different syntax because of the "class" key
|
||||
ResultsEntity = TypedDict(
|
||||
@@ -244,7 +260,7 @@ class Txt(Console):
|
||||
class Json(Reporter):
|
||||
def __init__(self, ids: Ids, hide_skipped=False):
|
||||
super().__init__(ids)
|
||||
self.results = Results()
|
||||
self.results = Results() # ty:ignore[missing-typed-dict-key]
|
||||
self.results["hide_skipped"] = hide_skipped
|
||||
|
||||
def report(self) -> Results:
|
||||
@@ -327,6 +343,8 @@ class Json(Reporter):
|
||||
elif requirement.value:
|
||||
label = "Reference"
|
||||
value = requirement.value
|
||||
else:
|
||||
assert False, requirement
|
||||
elif facet_type == "PartOf":
|
||||
label = requirement.relation
|
||||
if requirement.predefinedType:
|
||||
@@ -341,6 +359,8 @@ class Json(Reporter):
|
||||
label = "Name / Category"
|
||||
if requirement.value:
|
||||
value = requirement.value
|
||||
else:
|
||||
assert False, facet_type
|
||||
requirements.append(
|
||||
ResultsRequirement(
|
||||
facet_type=facet_type,
|
||||
@@ -410,7 +430,7 @@ class Json(Reporter):
|
||||
"id": e.id(),
|
||||
"global_id": getattr(e, "GlobalId", None),
|
||||
"tag": getattr(e, "Tag", None),
|
||||
}
|
||||
} # ty:ignore[missing-typed-dict-key]
|
||||
)
|
||||
for e in specification.applicable_entities
|
||||
]
|
||||
@@ -428,7 +448,7 @@ class Json(Reporter):
|
||||
"id": e.id(),
|
||||
"global_id": getattr(e, "GlobalId", None),
|
||||
"tag": getattr(e, "Tag", None),
|
||||
}
|
||||
} # ty:ignore[missing-typed-dict-key]
|
||||
)
|
||||
for e in requirement.passed_entities
|
||||
]
|
||||
|
||||
@@ -15,7 +15,17 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
|
||||
]
|
||||
dependencies = ["ifcopenshell", "python-dateutil", "xmlschema", "numpy", "odfpy", "pystache", "bcf-client", "flask"]
|
||||
dependencies = [
|
||||
"ifcopenshell",
|
||||
"python-dateutil",
|
||||
"xmlschema",
|
||||
"numpy",
|
||||
"odfpy",
|
||||
"pystache",
|
||||
"bcf-client",
|
||||
"flask",
|
||||
"typing_extensions",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
advanced = [
|
||||
|
||||
Reference in New Issue
Block a user