From 26280d24fed721d1c9c3253ba168ee498fe8429a Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 20 Mar 2026 15:35:53 +0500 Subject: [PATCH] Add `ty` to check for missing symbols and other simple errors --- pyproject.toml | 167 +++++++++++++++++- .../bonsai/bim/module/aggregate/decorator.py | 2 +- src/bonsai/bonsai/bim/module/bcf/prop.py | 2 +- src/bonsai/bonsai/bim/module/brick/prop.py | 8 +- .../bonsai/bim/module/drawing/helper.py | 3 +- .../bonsai/bim/module/geometry/operator.py | 2 +- src/bonsai/bonsai/bim/module/gis/prop.py | 2 +- src/bonsai/bonsai/bim/module/light/prop.py | 2 +- src/bonsai/bonsai/bim/module/model/product.py | 8 +- src/bonsai/bonsai/bim/module/model/task.py | 4 +- .../bonsai/bim/module/nest/decorator.py | 2 +- .../bonsai/bim/module/qto/calculator.py | 2 +- .../bonsai/bim/module/structural/shader.py | 6 +- src/bonsai/bonsai/tool/cost.py | 2 +- src/bonsai/bonsai/tool/ifcgit.py | 2 +- src/bonsai/scripts/bonsai_deps.py | 23 +++ src/bonsai/scripts/bonsai_translations.py | 4 +- src/bonsai/scripts/gbxml.py | 4 +- .../generate_steel_profiles_library.py | 2 +- src/bonsai/scripts/obj2ifc-meshlab.py | 2 +- src/bonsai/scripts/obj2ifc.py | 2 +- src/bonsai/test/bim/test_feature.py | 2 +- src/bonsai/type-check-requirements.txt | 41 +++++ src/bsdd/bsdd_json.py | 2 +- .../ifcopenshell/__init__.py | 4 +- .../api/geometry/add_representation.py | 6 +- .../ifcopenshell/api/project/append_asset.py | 2 +- .../api/style/add_surface_textures.py | 2 +- .../ifcopenshell/geom/__init__.py | 4 +- .../ifcopenshell/geom/main.py | 6 +- .../ifcopenshell/geom/occ_utils.py | 24 ++- .../ifcopenshell/util/shape_builder.py | 2 +- .../ifcopenshell/validate.py | 3 +- .../test/util/test_shape_builder.py | 10 +- .../type-check-requirements.txt | 31 ++++ .../recipes/FixArchiCADToRevitSpaces.py | 4 +- .../ifcpatch/recipes/FixRevit2025TINs.py | 16 +- src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py | 4 +- .../ifcpatch/recipes/MergeDuplicateTypes.py | 2 +- src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py | 2 +- src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py | 2 +- 41 files changed, 350 insertions(+), 70 deletions(-) create mode 100644 src/bonsai/scripts/bonsai_deps.py create mode 100644 src/bonsai/type-check-requirements.txt create mode 100644 src/ifcopenshell-python/type-check-requirements.txt diff --git a/pyproject.toml b/pyproject.toml index 895e74679e..a306ffa166 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,14 +79,136 @@ ignore = [ ] [tool.ty.rules] -# We only use `ty` currently to check for deprecated methods. all = "ignore" + +# Structural rules (no deep type inference needed, easier to adapt). +abstract-method-in-final-class = "error" +ambiguous-protocol-member = "error" +byte-string-type-annotation = "error" +conflicting-declarations = "error" +conflicting-metaclass = "error" +cyclic-class-definition = "error" +cyclic-type-alias-definition = "error" +dataclass-field-order = "error" +duplicate-base = "error" +duplicate-kw-only = "error" +empty-body = "error" +escape-character-in-forward-annotation = "error" +final-on-non-method = "error" +final-without-value = "error" +fstring-type-annotation = "error" +ignore-comment-unknown-rule = "error" +implicit-concatenated-string-type-annotation = "error" +inconsistent-mro = "error" +ineffective-final = "error" +instance-layout-conflict = "error" +invalid-dataclass = "error" +invalid-dataclass-override = "error" +invalid-enum-member-annotation = "error" +invalid-explicit-override = "error" +invalid-frozen-dataclass-subclass = "error" +invalid-generic-class = "error" +invalid-generic-enum = "error" +invalid-ignore-comment = "error" +invalid-legacy-positional-parameter = "error" +invalid-legacy-type-variable = "error" +invalid-named-tuple = "error" +invalid-newtype = "error" +invalid-overload = "error" +invalid-paramspec = "error" +invalid-protocol = "error" +invalid-syntax-in-forward-annotation = "error" +invalid-total-ordering = "error" +invalid-type-alias-type = "error" +invalid-type-checking-constant = "error" +invalid-type-guard-definition = "error" +invalid-type-variable-bound = "error" +invalid-type-variable-constraints = "error" +invalid-typed-dict-header = "error" +invalid-typed-dict-statement = "error" +override-of-final-method = "error" +override-of-final-variable = "error" +possibly-missing-import = "error" +possibly-missing-submodule = "error" +# Has false positives due to ty walrus operator bug. +# possibly-unresolved-reference = "error" +raw-string-type-annotation = "error" +redundant-final-classvar = "error" +shadowed-type-variable = "error" +subclass-of-final-class = "error" +super-call-in-named-tuple-method = "error" +unavailable-implicit-super-arguments = "error" +unbound-type-variable = "error" +undefined-reveal = "error" +unresolved-global = "error" +unresolved-import = "error" +unresolved-reference = "error" +unused-ignore-comment = "error" +unused-type-ignore-comment = "error" +useless-overload-body = "error" + +# Non-structural rules: deprecated = "error" +zero-stepsize-in-slice = "error" +possibly-missing-implicit-call = "error" +unused-awaitable = "error" + +# Function argument rules: +# Conflicts with `ifcopenshell.api.geometry.add_representation` type of callables we have, confusing them with a module. +# call-non-callable = "error" +conflicting-argument-forms = "error" +# Too many false positives. +# invalid-argument-type = "error" +missing-argument = "error" +parameter-already-assigned = "error" +positional-only-parameter-as-kwarg = "error" +too-many-positional-arguments = "error" +unknown-argument = "error" +# Has a lot of warnings due to current ty walrus operator issues. +# index-out-of-bounds = "error" +# unresolved-attribute = "error" + +[tool.ty.environment] +extra-paths = [ + "src/bonsai/external_dependencies", + "src/bcf", + "src/bsdd", + "src/bonsai", + "src/ifc4d", + "src/ifc5d", + "src/ifccityjson", + "src/ifcclash", + "src/ifccsv", + "src/ifcdiff", + "src/ifcfm", + "src/ifcopenshell-python", + "src/ifcpatch", + "src/ifctester", +] [tool.ty.src] exclude = [ - "src/ifc2ca/templates", + # External dependencies cloned for type checking only. + "src/bonsai/external_dependencies", + # Submodules. + "src/ifcopenshell-python/ifcopenshell/express", + "src/ifcopenshell-python/ifcopenshell/mvd", + "src/ifcopenshell-python/ifcopenshell/simple_spf", "src/svgfill/3rdparty", + # Has special dependencies. + "src/ifcopenshell-python/ifcopenshell/geom/app.py", + "src/ifcopenshell-python/ifcopenshell/geom/code_editor_pane.py", + "src/ifcopenshell-python/ifcopenshell/util/doc.py", + "src/ifcopenshell-python/ifcopenshell/util/generate_pset_templates.py", + "src/ifcopenshell-python/ifcopenshell/util/ifc4x3dev_scrape_data_for_docs.py", + # Too esoteric. + "src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py", + "src/ifc2ca/templates", + # Too dev. + "src/bcf/setup.py", + "src/bsdd/yml_to_classes.py", + # Deprecated. + "src/ifc2ca/_deprecated", ] [tool.poe.tasks] @@ -98,8 +220,47 @@ ruff.sequence = ["ruff-main", "ruff-old"] black = "black ." -ty = "ty check" +ty.sequence = ["ty-bonsai", "ty-ios"] +ty.help = "Run ty type checker. Requires ty-venv to be set up first." +ty-bonsai = "ty check src/bonsai --python=src/bonsai/.venv" + +ty-venv.sequence = ["ty-venv-bonsai", "ty-venv-ios"] + +ty-venv-bonsai.sequence = [ + {cmd = "uv venv src/bonsai/.venv --python=3.11 --allow-existing"}, + {cmd = "uv pip install -r src/bonsai/type-check-requirements.txt --python=src/bonsai/.venv"}, +] + +ty-venv-ios.sequence = [ + {cmd = "uv venv src/ifcopenshell-python/.venv --python=3.10 --allow-existing"}, + {cmd = "uv pip install -r src/ifcopenshell-python/type-check-requirements.txt --python=src/ifcopenshell-python/.venv"}, +] format.sequence = ["black", "ruff-main", "ruff-old"] cmake-format = "gersemi . --in-place" + +[tool.poe.tasks.ty-ios] +# --ignore unresolved-reference: walrus operator false positives in ty. +cmd = """ + ty check + src/bcf + src/bsdd + src/ifc2ca + src/ifc4d + src/ifc5d + src/ifccityjson + src/ifcclash + src/ifccsv + src/ifcdiff + src/ifcfm + src/ifcopenshell-python + src/ifcpatch + src/ifctester + --python=src/ifcopenshell-python/.venv + --ignore unresolved-reference +""" + +[tool.poe.tasks.bonsai-deps] +help = "Clone or update Bonsai external dependencies." +cmd = "python src/bonsai/scripts/bonsai_deps.py" diff --git a/src/bonsai/bonsai/bim/module/aggregate/decorator.py b/src/bonsai/bonsai/bim/module/aggregate/decorator.py index eb389a58bd..2cd1c1bca0 100644 --- a/src/bonsai/bonsai/bim/module/aggregate/decorator.py +++ b/src/bonsai/bonsai/bim/module/aggregate/decorator.py @@ -101,7 +101,7 @@ class AggregateDecorator: cls.is_installed = False def dotted_line_shader(self): - vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") # ty:ignore[too-many-positional-arguments] vert_out.smooth("FLOAT", "v_ArcLength") shader_info = gpu.types.GPUShaderCreateInfo() diff --git a/src/bonsai/bonsai/bim/module/bcf/prop.py b/src/bonsai/bonsai/bim/module/bcf/prop.py index 3ac751387e..651c0c052f 100644 --- a/src/bonsai/bonsai/bim/module/bcf/prop.py +++ b/src/bonsai/bonsai/bim/module/bcf/prop.py @@ -230,7 +230,7 @@ class BcfTopic(PropertyGroup): def get_related_topics(self: "BCFProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]: - global RELATED_TOPICS_ENUM_ITEMS + global RELATED_TOPICS_ENUM_ITEMS # ty: ignore[unresolved-global] props = self active_topic = props.active_topic active_related_topics = active_topic.related_topics.keys() diff --git a/src/bonsai/bonsai/bim/module/brick/prop.py b/src/bonsai/bonsai/bim/module/brick/prop.py index 6201113a09..2d507411e4 100644 --- a/src/bonsai/bonsai/bim/module/brick/prop.py +++ b/src/bonsai/bonsai/bim/module/brick/prop.py @@ -46,26 +46,26 @@ def get_libraries(self, context): def get_namespaces(self, context): - global NAMESPACES_ENUM_ITEMS + global NAMESPACES_ENUM_ITEMS # ty: ignore[unresolved-global] NAMESPACES_ENUM_ITEMS = [(uri, f"{alias}: {uri}", "") for alias, uri in BrickStore.namespaces] return NAMESPACES_ENUM_ITEMS def get_brick_entity_classes(self, context): - global ENTITY_CLASSES_ENUM_ITEMS + global ENTITY_CLASSES_ENUM_ITEMS # ty: ignore[unresolved-global] entity = self.brick_entity_create_type ENTITY_CLASSES_ENUM_ITEMS = [(uri, uri.split("#")[-1], "") for uri in BrickStore.entity_classes[entity]] return ENTITY_CLASSES_ENUM_ITEMS def get_brick_roots(self, context): - global BRICK_ROOTS_ENUM_ITEMS + global BRICK_ROOTS_ENUM_ITEMS # ty: ignore[unresolved-global] BRICK_ROOTS_ENUM_ITEMS = [(root, root, "") for root in BrickStore.root_classes] return BRICK_ROOTS_ENUM_ITEMS def get_brick_relations(self, context): - global BRICK_RELATIONS_ENUM_ITEMS + global BRICK_RELATIONS_ENUM_ITEMS # ty: ignore[unresolved-global] BRICK_RELATIONS_ENUM_ITEMS = [(uri, uri.split("#")[-1], "") for uri in BrickStore.relationships] for relation in BrickschemaData.data["active_relations"]: if relation["predicate_name"] == "label": diff --git a/src/bonsai/bonsai/bim/module/drawing/helper.py b/src/bonsai/bonsai/bim/module/drawing/helper.py index 7dce81359d..d4895410cb 100644 --- a/src/bonsai/bonsai/bim/module/drawing/helper.py +++ b/src/bonsai/bonsai/bim/module/drawing/helper.py @@ -456,7 +456,8 @@ def format_distance( tx_dist = fmt % d_cm else: - tx_dist = fmt % value + assert f"Unexpected unit_system - '{unit_system}'." + # tx_dist = fmt % value return tx_dist diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index f8389cb3af..d5f159abe3 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -1066,7 +1066,7 @@ class OverrideOutlinerDelete(bpy.types.Operator, tool.Ifc.Operator): cls.poll_message_set("Only available from Outliner.") return False - def execute(self, context): + def execute(self, context): # ty:ignore[override-of-final-method] if len(getattr(context, "selected_ids", [])) == 0: return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/gis/prop.py b/src/bonsai/bonsai/bim/module/gis/prop.py index 9f685517c3..5971fa80a9 100644 --- a/src/bonsai/bonsai/bim/module/gis/prop.py +++ b/src/bonsai/bonsai/bim/module/gis/prop.py @@ -27,7 +27,7 @@ from bonsai.bim.prop import StrProperty class BIMCityJsonProperties(PropertyGroup): def get_lods(self, context): - global LODS_ENUM_ITEMS + global LODS_ENUM_ITEMS # ty: ignore[unresolved-global] LODS_ENUM_ITEMS = [(item.name, "LOD" + item.name, "Level of Detail " + item.name) for item in self.lods] return LODS_ENUM_ITEMS diff --git a/src/bonsai/bonsai/bim/module/light/prop.py b/src/bonsai/bonsai/bim/module/light/prop.py index d3498f18b8..24233b44d8 100644 --- a/src/bonsai/bonsai/bim/module/light/prop.py +++ b/src/bonsai/bonsai/bim/module/light/prop.py @@ -320,7 +320,7 @@ class RadianceExporterProperties(PropertyGroup): ) def get_subcategories(self, context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS: - global SUBCATEGORIES_ENUM_ITEMS + global SUBCATEGORIES_ENUM_ITEMS # ty: ignore[unresolved-global] if self.category in spectraldb: SUBCATEGORIES_ENUM_ITEMS = [(k, k, "") for k in spectraldb[self.category].keys()] else: diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index d7c96bce1d..4cf4e00172 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -694,10 +694,14 @@ def generate_box(usecase_path: str, ifc_file: ifcopenshell.file, settings: dict[ new_settings = settings.copy() new_settings["context"] = box_context - new_box = ifcopenshell.api.geometry.add_representation(ifc_file, should_run_listeners=False, **new_settings) + new_box = ifcopenshell.api.geometry.add_representation( + ifc_file, + should_run_listeners=False, # ty:ignore[unknown-argument] + **new_settings, + ) ifcopenshell.api.geometry.assign_representation( ifc_file, - should_run_listeners=False, + should_run_listeners=False, # ty:ignore[unknown-argument] product=product, representation=new_box, ) diff --git a/src/bonsai/bonsai/bim/module/model/task.py b/src/bonsai/bonsai/bim/module/model/task.py index a6fe2607a2..72d2ee4556 100644 --- a/src/bonsai/bonsai/bim/module/model/task.py +++ b/src/bonsai/bonsai/bim/module/model/task.py @@ -31,11 +31,11 @@ def calculate_quantities(usecase_path, ifc_file: ifcopenshell.file, settings): return task = next(e for e in ifc_file.get_inverse(element) if e.is_a("IfcTask")) qto = ifcopenshell.api.pset.add_qto( - ifc_file, should_run_listeners=False, product=task, name="Qto_TaskBaseQuantities" + ifc_file, should_run_listeners=False, product=task, name="Qto_TaskBaseQuantities" # ty:ignore[unknown-argument] ) ifcopenshell.api.pset.edit_qto( ifc_file, - should_run_listeners=False, + should_run_listeners=False, # ty:ignore[unknown-argument] qto=qto, properties={ "StandardWork": ifcopenshell.util.date.ifc2datetime(element.ScheduleDuration).days, diff --git a/src/bonsai/bonsai/bim/module/nest/decorator.py b/src/bonsai/bonsai/bim/module/nest/decorator.py index 28c3835ba7..4a3637caa6 100644 --- a/src/bonsai/bonsai/bim/module/nest/decorator.py +++ b/src/bonsai/bonsai/bim/module/nest/decorator.py @@ -101,7 +101,7 @@ class NestDecorator: cls.is_installed = False def dotted_line_shader(self): - vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") # ty:ignore[too-many-positional-arguments] vert_out.smooth("FLOAT", "v_ArcLength") shader_info = gpu.types.GPUShaderCreateInfo() diff --git a/src/bonsai/bonsai/bim/module/qto/calculator.py b/src/bonsai/bonsai/bim/module/qto/calculator.py index c0e5aa474f..638d603f89 100644 --- a/src/bonsai/bonsai/bim/module/qto/calculator.py +++ b/src/bonsai/bonsai/bim/module/qto/calculator.py @@ -321,7 +321,7 @@ def get_gross_perimeter(o: bpy.types.Object) -> float: return gross_perimeter -def get_space_net_perimeter(obj: bpy.types.Object) -> float: +def get_space_net_perimeter(obj: bpy.types.Object) -> None: pass diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index b9b5a5c7bc..9688ce9f0e 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -83,7 +83,7 @@ class DecorationShader: PARALLEL DISTRIBUTED FORCE, DISTRIBUTED MOMENT, """ - vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") # ty:ignore[too-many-positional-arguments] vert_out.smooth("VEC3", "forces") vert_out.smooth("VEC3", "co") @@ -203,7 +203,7 @@ class DecorationShader: """param: pattern: type of pattern SINGLE FORCE, SINGLE MOMENT""" - vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") # ty: ignore[too-many-positional-arguments] vert_out.smooth("VEC3", "co") shader_info = gpu.types.GPUShaderCreateInfo() @@ -253,7 +253,7 @@ class DecorationShader: def get_planar_shader(self) -> gpu.types.GPUShader: """shader for planar loads""" - vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") # ty: ignore[too-many-positional-arguments] vert_out.smooth("VEC3", "co") shader_info = gpu.types.GPUShaderCreateInfo() diff --git a/src/bonsai/bonsai/tool/cost.py b/src/bonsai/bonsai/tool/cost.py index 663b16040e..bbec525ee9 100644 --- a/src/bonsai/bonsai/tool/cost.py +++ b/src/bonsai/bonsai/tool/cost.py @@ -154,7 +154,7 @@ class Cost(bonsai.core.tool.Cost): device = aud.Device() # chaching.mp3 is by Lucish_ CC-BY-3.0 https://freesound.org/people/Lucish_/sounds/554841/ filepath = tool.Blender.get_data_dir_path("chaching.mp3").__str__() - sound = aud.Sound(filepath) + sound = aud.Sound(filepath) # ty:ignore[too-many-positional-arguments] device.play(sound) @classmethod diff --git a/src/bonsai/bonsai/tool/ifcgit.py b/src/bonsai/bonsai/tool/ifcgit.py index db557542bc..64b3957169 100644 --- a/src/bonsai/bonsai/tool/ifcgit.py +++ b/src/bonsai/bonsai/tool/ifcgit.py @@ -284,7 +284,7 @@ class IfcGit: if re.match("^Ifc", obj.name): bpy.data.objects.remove(obj, do_unlink=True) - bpy.data.orphans_purge(do_recursive=True) + bpy.data.orphans_purge(do_recursive=True) # ty:ignore[unknown-argument] settings = import_ifc.IfcImportSettings.factory(bpy.context, path_ifc, logging.getLogger("ImportIFC")) settings.should_setup_viewport_camera = False diff --git a/src/bonsai/scripts/bonsai_deps.py b/src/bonsai/scripts/bonsai_deps.py new file mode 100644 index 0000000000..678fa49bb1 --- /dev/null +++ b/src/bonsai/scripts/bonsai_deps.py @@ -0,0 +1,23 @@ +"""Clone or update Bonsai external dependencies. + +Must be run from the repository root. +""" + +import subprocess +from pathlib import Path + +DEPS = [ + ("https://projects.blender.org/pioverfour/sun_position.git", "sun_position"), + ("https://github.com/kevancress/MeasureIt_ARCH", "MeasureIt_ARCH"), + ("https://github.com/nortikin/sverchok.git", "sverchok"), +] + +base = Path("src/bonsai/external_dependencies") +base.mkdir(parents=True, exist_ok=True) + +for url, name in DEPS: + path = base / name + if not path.exists(): + subprocess.check_call(["git", "clone", url, str(path)]) + else: + subprocess.check_call(["git", "-C", str(path), "pull", "--rebase"]) diff --git a/src/bonsai/scripts/bonsai_translations.py b/src/bonsai/scripts/bonsai_translations.py index fbf11df6e8..7b6ae960db 100644 --- a/src/bonsai/scripts/bonsai_translations.py +++ b/src/bonsai/scripts/bonsai_translations.py @@ -273,10 +273,10 @@ if BPY_IS_LOADED: f"Couldn't find locale path in the source directory, creating dummy directory: {source_locale_path}.", ) - from ui_translate.settings import ( # pyright: ignore[reportMissingImports] + from ui_translate.settings import ( # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] settings as ui_translate_settings, ) - from ui_translate.update_ui import ( # pyright: ignore[reportMissingImports] + from ui_translate.update_ui import ( # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] UI_OT_i18n_updatetranslation_init_settings, ) diff --git a/src/bonsai/scripts/gbxml.py b/src/bonsai/scripts/gbxml.py index 7bd8063a15..6cf104f2c1 100644 --- a/src/bonsai/scripts/gbxml.py +++ b/src/bonsai/scripts/gbxml.py @@ -23,7 +23,9 @@ import bpy # sys.path.append('C:\Program Files\Python37\Lib\site-packages') import lxml.etree -from bspy import Gbxml # pyright: ignore[reportMissingImports] +from bspy import ( # ty: ignore[unresolved-import] + Gbxml, # pyright: ignore[reportMissingImports] +) class GbxmlExporter: diff --git a/src/bonsai/scripts/generate_steel_profiles_library.py b/src/bonsai/scripts/generate_steel_profiles_library.py index 255a448127..ca45648122 100644 --- a/src/bonsai/scripts/generate_steel_profiles_library.py +++ b/src/bonsai/scripts/generate_steel_profiles_library.py @@ -22,7 +22,7 @@ from math import pi from pathlib import Path -import boltspy as bolts # pyright: ignore[reportMissingImports] +import boltspy as bolts # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import ifcopenshell.api import ifcopenshell.api.material import ifcopenshell.api.project diff --git a/src/bonsai/scripts/obj2ifc-meshlab.py b/src/bonsai/scripts/obj2ifc-meshlab.py index 70849e11d9..d707c8bda7 100644 --- a/src/bonsai/scripts/obj2ifc-meshlab.py +++ b/src/bonsai/scripts/obj2ifc-meshlab.py @@ -31,7 +31,7 @@ import ifcopenshell.api.spatial import ifcopenshell.api.unit import ifcopenshell.guid import numpy as np -import pymeshlab # pyright: ignore[reportMissingImports] +import pymeshlab # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] class Obj2Ifc: diff --git a/src/bonsai/scripts/obj2ifc.py b/src/bonsai/scripts/obj2ifc.py index ec5459c4a3..0b3252cd1c 100644 --- a/src/bonsai/scripts/obj2ifc.py +++ b/src/bonsai/scripts/obj2ifc.py @@ -31,7 +31,7 @@ import ifcopenshell.api.spatial import ifcopenshell.api.unit import ifcopenshell.guid import numpy as np -import pywavefront # pyright: ignore[reportMissingImports] +import pywavefront # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] class Obj2Ifc: diff --git a/src/bonsai/test/bim/test_feature.py b/src/bonsai/test/bim/test_feature.py index 3a1efa5d5b..b7dc932024 100644 --- a/src/bonsai/test/bim/test_feature.py +++ b/src/bonsai/test/bim/test_feature.py @@ -242,7 +242,7 @@ class TemplateListItemSpy(PanelSpy): self.spied_props: list[dict[str, Any]] = [] self.spied_operators: list[dict[str, Any]] = [] if len(signature(blender_panel.draw_item).parameters) == 8: - blender_panel.draw_item( + blender_panel.draw_item( # ty:ignore[missing-argument] self, bpy.context, self, diff --git a/src/bonsai/type-check-requirements.txt b/src/bonsai/type-check-requirements.txt new file mode 100644 index 0000000000..1a8419c7d3 --- /dev/null +++ b/src/bonsai/type-check-requirements.txt @@ -0,0 +1,41 @@ +aiohttp +beautifulsoup4 +boto3 +botocore +brickschema +cjio >=0.8, <0.10 +debugpy +ezdxf +fake-bpy-module-latest +git+https://github.com/prochitecture/bpypolyskel +git+https://github.com/Andrej730/IFC2JSON_python.git@pyproject_toml +gitpython +isodate +lark +lxml +lxml-stubs +markdown-it-py +natsort +numpy +odfpy +openpyxl +pandas +pillow +platformdirs +pygments +pyradiance +pystache +pytest +pytest_bdd +pytest_blender +python-dateutil +python-socketio +pytz +rdflib +requests +shapely +svgwrite +typing-extensions +typst +tzfpy +xsdata diff --git a/src/bsdd/bsdd_json.py b/src/bsdd/bsdd_json.py index becaac810b..6a89d19753 100644 --- a/src/bsdd/bsdd_json.py +++ b/src/bsdd/bsdd_json.py @@ -7,7 +7,7 @@ from typing import Literal, Optional from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator -from .type_hints import * +from type_hints import * def _lower_first(s: str) -> str: diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 28a3512e2e..51638f6954 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -111,8 +111,8 @@ __all__ = [ ] try: - from .stream import stream, stream_entity - from .stream import stream as _stream + from .stream import stream, stream_entity # ty: ignore[possibly-missing-import] + from .stream import stream as _stream # ty: ignore[possibly-missing-import] except: pass diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py index 7cb9368f68..e756cb07cf 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py @@ -20,11 +20,11 @@ from __future__ import annotations import math from typing import TYPE_CHECKING, Any, Literal, Optional, Union -import bmesh # pyright: ignore[reportMissingImports] -import bpy # pyright: ignore[reportMissingImports] +import bmesh # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] +import bpy # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import numpy as np import numpy.typing as npt -from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports] +from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import ifcopenshell.util.shape_builder import ifcopenshell.util.unit diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py index 0f09bd4991..8a8f2307a4 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py @@ -431,7 +431,7 @@ class Usecase: ) ifcopenshell.api.type.assign_type( self.file, - should_run_listeners=False, + should_run_listeners=False, # ty:ignore[unknown-argument] related_objects=[element], relating_type=new_type, should_map_representations=False, diff --git a/src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py b/src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py index 3db088f83e..7ef4858041 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py +++ b/src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py @@ -22,7 +22,7 @@ from typing import TYPE_CHECKING, Any, Optional import ifcopenshell if TYPE_CHECKING: - import bpy # pyright: ignore[reportMissingImports] + import bpy # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] def add_surface_textures( diff --git a/src/ifcopenshell-python/ifcopenshell/geom/__init__.py b/src/ifcopenshell-python/ifcopenshell/geom/__init__.py index 606004864c..2b01d63925 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/__init__.py @@ -33,14 +33,14 @@ def _has_occ(): # Previous versions (pythonocc<=0.17.3) are using just OCC. try: - import OCC.Core.BRepTools # pyright: ignore[reportMissingImports] + import OCC.Core.BRepTools # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] return True except ImportError: pass try: - import OCC.BRepTools # noqa: F401 # pyright: ignore[reportMissingImports] + import OCC.BRepTools # noqa: F401 # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] return True except ImportError: diff --git a/src/ifcopenshell-python/ifcopenshell/geom/main.py b/src/ifcopenshell-python/ifcopenshell/geom/main.py index 36f9b48070..9c36e4b933 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/main.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/main.py @@ -28,7 +28,7 @@ from ..file import file from . import has_occ if TYPE_CHECKING: - from OCC.Core import TopoDS # pyright: ignore[reportMissingImports] + from OCC.Core import TopoDS # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] IteratorOutput = Union["ShapeElementType", "utils.shape_tuple"] @@ -47,9 +47,9 @@ if has_occ: from . import occ_utils as utils try: - from OCC.Core import TopoDS # pyright: ignore[reportMissingImports] + from OCC.Core import TopoDS # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] except ImportError: - from OCC import TopoDS # pyright: ignore[reportMissingImports] + from OCC import TopoDS # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] def wrap_shape_creation(settings: settings, shape: ifcopenshell_wrapper.Element): if getattr(settings, "use_python_opencascade", False): diff --git a/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py b/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py index 9a4a44c18f..15a4dfc838 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py @@ -26,17 +26,33 @@ import warnings from collections.abc import Iterable from typing import NamedTuple, Union -import OCC # pyright: ignore[reportMissingImports] +import OCC # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] from typing_extensions import assert_never import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper try: - from OCC.Core import AIS, BRepTools, Graphic3d, Quantity, TopoDS, V3d, gp # pyright: ignore[reportMissingImports] + from OCC.Core import ( # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] + AIS, + BRepTools, + Graphic3d, + Quantity, + TopoDS, + V3d, + gp, + ) USE_OCCT_HANDLE = False except ImportError: - from OCC import AIS, BRepTools, Graphic3d, Quantity, TopoDS, V3d, gp # pyright: ignore[reportMissingImports] + from OCC import ( # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] + AIS, + BRepTools, + Graphic3d, + Quantity, + TopoDS, + V3d, + gp, + ) USE_OCCT_HANDLE = True @@ -68,7 +84,7 @@ DEFAULT_STYLES = { def initialize_display(): - import OCC.Display.SimpleGui # pyright: ignore[reportMissingImports] + import OCC.Display.SimpleGui # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] global handle, main_loop, add_menu, add_function_to_menu handle, main_loop, add_menu, add_function_to_menu = OCC.Display.SimpleGui.init_display() diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index 907cb85b5a..774c0c898e 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -40,7 +40,7 @@ if TYPE_CHECKING: # NOTE: mathutils is never used at runtime in ifcopenshell, # only for type checking to ensure methods are compatible with # Blender vectors. - from mathutils import Vector # pyright: ignore[reportMissingImports] + from mathutils import Vector # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # Support both numpy arrays and python sequences as inputs. VectorType = Union[Sequence[float], Vector, np.ndarray] diff --git a/src/ifcopenshell-python/ifcopenshell/validate.py b/src/ifcopenshell-python/ifcopenshell/validate.py index a98282fd1c..524dc78d35 100644 --- a/src/ifcopenshell-python/ifcopenshell/validate.py +++ b/src/ifcopenshell-python/ifcopenshell/validate.py @@ -47,6 +47,7 @@ from __future__ import annotations import argparse import functools +import itertools import json import os import sys @@ -331,7 +332,7 @@ def log_internal_cpp_errors( lines = list(open(filename, "rb")) lengths = list(map(len, lines)) cumsum = 0 - cs = [cumsum := cumsum + x for x in lengths] + cs = list(itertools.accumulate(lengths)) for offsets, msg in zip(chr_offsets, msgs): if offsets: diff --git a/src/ifcopenshell-python/test/util/test_shape_builder.py b/src/ifcopenshell-python/test/util/test_shape_builder.py index 5ff8adc03f..6a01a74201 100644 --- a/src/ifcopenshell-python/test/util/test_shape_builder.py +++ b/src/ifcopenshell-python/test/util/test_shape_builder.py @@ -41,7 +41,7 @@ from ifcopenshell.util.shape_builder import ( class TestMathutilsCompatibleMethods(test.bootstrap.IFC4): def test_np_rotation_matrix(self): - from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports] + from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # 2D. assert np.allclose(Matrix.Rotation(radians(45), 2), np_rotation_matrix(radians(45), 2)) @@ -62,7 +62,7 @@ class TestMathutilsCompatibleMethods(test.bootstrap.IFC4): assert np.allclose(Matrix.Rotation(*rotation_vector_args), np_rotation_matrix(*rotation_vector_args)) def test_np_matrix_to_euler(self): - from mathutils import Euler # pyright: ignore[reportMissingImports] + from mathutils import Euler # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # Test 3x3. rot = Euler((0.5, 0.5, 0.5)).to_matrix() @@ -77,7 +77,7 @@ class TestMathutilsCompatibleMethods(test.bootstrap.IFC4): assert np.allclose(rot.to_euler(), np_matrix_to_euler(V(rot))) def test_np_angle(self): - from mathutils import Vector # pyright: ignore[reportMissingImports] + from mathutils import Vector # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] v1, v2 = (1, 0, 0), (0, 1, 0) angle = np_angle(v1, v2) @@ -100,7 +100,7 @@ class TestMathutilsCompatibleMethods(test.bootstrap.IFC4): assert is_x(angle, radians(90)) def test_np_normal(self): - import mathutils.geometry # pyright: ignore[reportMissingImports] + import mathutils.geometry # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] vectors = (0, 0, 0), (1, 0, 0), (0, 1, 0) n = mathutils.geometry.normal(vectors) @@ -113,7 +113,7 @@ class TestMathutilsCompatibleMethods(test.bootstrap.IFC4): assert np.allclose(n, (0, 0, -1)) def test_np_intersect_line_line(self): - import mathutils.geometry # pyright: ignore[reportMissingImports] + import mathutils.geometry # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] p1, p2 = [0, 0, 0], [1, 1, 1] q1, q2 = [0, 1, 0], [1, 0, 1] diff --git a/src/ifcopenshell-python/type-check-requirements.txt b/src/ifcopenshell-python/type-check-requirements.txt new file mode 100644 index 0000000000..c797c28034 --- /dev/null +++ b/src/ifcopenshell-python/type-check-requirements.txt @@ -0,0 +1,31 @@ +beautifulsoup4 +cjio >=0.8, <0.10 +deepdiff +docutils +flask +isodate +jinja2 +lark +meshio +mysql-connector-python +networkx +numpy +odfpy +openpyxl +pandas +psutil +pydantic +PyP6Xer +pystache +pytest +python-dateutil +requests +scikit-learn +shapely +tabulate +toposort +typing-extensions +typst +xlsxwriter +xmlschema +xsdata diff --git a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py index 8a80b5d264..fac4573a23 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py +++ b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py @@ -67,9 +67,9 @@ class Patcher: def patch(self) -> None: import bonsai.tool as tool - import bpy # pyright: ignore[reportMissingImports] + import bpy # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import ifcopenshell.util.element - from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports] + from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] if len(bpy.data.objects) > 0: bpy.data.batch_remove(bpy.data.objects) diff --git a/src/ifcpatch/ifcpatch/recipes/FixRevit2025TINs.py b/src/ifcpatch/ifcpatch/recipes/FixRevit2025TINs.py index 5d4844e779..8cb68c3dfc 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixRevit2025TINs.py +++ b/src/ifcpatch/ifcpatch/recipes/FixRevit2025TINs.py @@ -26,7 +26,7 @@ import ifcopenshell import ifcopenshell.util.shape_builder if TYPE_CHECKING: - import bpy # pyright: ignore[reportMissingImports] + import bpy # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] class Patcher: @@ -114,9 +114,9 @@ class Patcher: self.should_create_edges = should_create_edges def patch(self) -> None: - import bmesh # pyright: ignore[reportMissingImports] + import bmesh # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import bonsai.tool as tool - import bpy # pyright: ignore[reportMissingImports] + import bpy # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import ifcopenshell.util.schema import ifcopenshell.util.unit @@ -167,9 +167,9 @@ class Patcher: self.file = tool.Ifc.get() def create_edges(self, obj: bpy.types.Object) -> None: - import bmesh # pyright: ignore[reportMissingImports] + import bmesh # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import bonsai.tool as tool - import bpy # pyright: ignore[reportMissingImports] + import bpy # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import ifcopenshell.api.geometry import ifcopenshell.api.root import ifcopenshell.util.representation @@ -235,7 +235,7 @@ class Patcher: # No sharp faces from math import degrees - import bmesh # pyright: ignore[reportMissingImports] + import bmesh # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import bonsai.tool as tool import ifcopenshell.api.geometry import ifcopenshell.api.root @@ -282,13 +282,13 @@ class Patcher: # This is crazy but we need a sharp face per island from math import degrees, radians, sin - import bmesh # pyright: ignore[reportMissingImports] + import bmesh # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import bonsai.tool as tool import ifcopenshell.api.geometry import ifcopenshell.api.root import ifcopenshell.util.representation import ifcopenshell.util.shape_builder - from mathutils import Matrix # pyright: ignore[reportMissingImports] + from mathutils import Matrix # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # Get the active object (assumed to have a mesh) mesh = obj.data diff --git a/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py b/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py index a1912d3b6e..cd801d9fe3 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py +++ b/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py @@ -80,9 +80,9 @@ class Patcher: def patch(self) -> None: from math import degrees - import bmesh # pyright: ignore[reportMissingImports] + import bmesh # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] import bonsai.tool as tool - import bpy # pyright: ignore[reportMissingImports] + import bpy # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] props = tool.Project.get_project_props() props.should_use_native_meshes = True diff --git a/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py b/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py index 38b01135b3..8da51a4ac8 100644 --- a/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py +++ b/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py @@ -97,5 +97,5 @@ class Patcher: relating_type=relating_type, related_objects=related_objects, should_map_representations=False, - should_run_listeners=False, + should_run_listeners=False, # ty:ignore[unknown-argument] ) diff --git a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py index 785d5db718..134ad05d99 100644 --- a/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/bmesh_to_ifc.py @@ -193,7 +193,7 @@ class SvIfcBMeshToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.help blender_object=obj, geometry=obj.data, context=context, - should_run_listeners=False, + should_run_listeners=False, # ty:ignore[unknown-argument] ) if not representation: raise Exception("Couldn't create representation. Possibly wrong context.") diff --git a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py index be06fac1ce..eb0965b8b3 100644 --- a/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py +++ b/src/ifcsverchok/nodes/ifc/sverchok_to_ifc.py @@ -143,7 +143,7 @@ class SvIfcSverchokToIfcRepr(bpy.types.Node, SverchCustomTreeNode, ifcsverchok.h for item in obj: representation = ifcopenshell.api.geometry.add_mesh_representation( self.file, - should_run_listeners=False, + should_run_listeners=False, # ty:ignore[unknown-argument] context=self.context, vertices=[list(map(tuple, item[0]))], edges=[list(map(tuple, item[1]))],