diff --git a/src/bonsai/bonsai/core/ifcgit.py b/src/bonsai/bonsai/core/ifcgit.py index 9ca1469c79..aa5bc78b5e 100644 --- a/src/bonsai/bonsai/core/ifcgit.py +++ b/src/bonsai/bonsai/core/ifcgit.py @@ -1,16 +1,44 @@ -def create_repo(ifcgit, ifc): +# Bonsai - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of Bonsai. +# +# Bonsai is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Bonsai is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Bonsai. If not, see . + +from __future__ import annotations +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + import bpy + import ifcopenshell + import bonsai.tool as tool + import git + + +def create_repo(ifcgit: tool.IfcGit, ifc: tool.Ifc) -> None: path_ifc = ifc.get_path() path_dir = ifcgit.get_path_dir(path_ifc) ifcgit.init_repo(path_dir) -def add_file(ifcgit, ifc): +def add_file(ifcgit: tool.IfcGit, ifc: tool.Ifc) -> None: path_ifc = ifc.get_path() repo = ifcgit.repo_from_path(path_ifc) ifcgit.add_file_to_repo(repo, path_ifc) -def clone_repo(ifcgit, remote_url, local_folder, operator): +def clone_repo(ifcgit: tool.IfcGit, remote_url: str, local_folder: str, operator: bpy.types.Operator) -> None: repo = ifcgit.clone_repo(remote_url, local_folder) if not repo: operator.report({"ERROR"}, "Clone failed") @@ -19,14 +47,14 @@ def clone_repo(ifcgit, remote_url, local_folder, operator): ifcgit.load_anyifc(repo) -def discard_uncommitted(ifcgit, ifc): +def discard_uncommitted(ifcgit: tool.IfcGit, ifc: tool.Ifc) -> None: path_ifc = ifc.get_path() # NOTE this is calling the git binary in a subprocess ifcgit.git_checkout(path_ifc) ifcgit.load_project(path_ifc) -def commit_changes(ifcgit, ifc, repo): +def commit_changes(ifcgit: tool.IfcGit, ifc: tool.Ifc, repo: git.Repo) -> None: """Commit and create new branches as required""" path_ifc = ifc.get_path() @@ -38,34 +66,34 @@ def commit_changes(ifcgit, ifc, repo): ifcgit.git_commit(path_ifc) -def add_tag(ifcgit, repo): +def add_tag(ifcgit: tool.IfcGit, repo: git.Repo) -> None: ifcgit.add_tag(repo) -def delete_tag(ifcgit, repo, tag_name): +def delete_tag(ifcgit: tool.IfcGit, repo: git.Repo, tag_name: git.TagReference) -> None: ifcgit.delete_tag(repo, tag_name) -def add_remote(ifcgit, repo): +def add_remote(ifcgit: tool.IfcGit, repo: git.Repo) -> None: ifcgit.add_remote(repo) -def delete_remote(ifcgit, repo): +def delete_remote(ifcgit: tool.IfcGit, repo: git.Repo) -> None: ifcgit.delete_remote(repo) -def push(ifcgit, repo, remote_name, operator): +def push(ifcgit: tool.IfcGit, repo: git.Repo, remote_name: str, operator: bpy.types.Operator) -> None: error_message = ifcgit.push(repo, remote_name, repo.active_branch.name) if error_message: operator.report({"ERROR"}, error_message) -def refresh_revision_list(ifcgit, repo, ifc): +def refresh_revision_list(ifcgit: tool.IfcGit, repo: git.Repo, ifc: tool.Ifc) -> None: if repo.heads: ifcgit.refresh_revision_list(ifc.get_path()) -def colourise_revision(ifcgit): +def colourise_revision(ifcgit: tool.IfcGit) -> None: step_ids = ifcgit.get_revisions_step_ids() if not step_ids: @@ -75,13 +103,13 @@ def colourise_revision(ifcgit): ifcgit.colourise(final_step_ids) -def colourise_uncommitted(ifcgit, ifc, repo): +def colourise_uncommitted(ifcgit: tool.IfcGit, ifc: tool.Ifc, repo: git.Repo) -> None: path_ifc = ifc.get_path() step_ids = ifcgit.ifc_diff_ids(repo, None, "HEAD", path_ifc) ifcgit.colourise(step_ids) -def switch_revision(ifcgit, ifc): +def switch_revision(ifcgit: tool.IfcGit, ifc: tool.Ifc) -> None: # FIXME bad things happen when switching to a revision that predates current project path_ifc = ifc.get_path() @@ -90,13 +118,13 @@ def switch_revision(ifcgit, ifc): ifcgit.refresh_revision_list(path_ifc) -def merge_branch(ifcgit, ifc, operator): +def merge_branch(ifcgit: tool.IfcGit, ifc: tool.Ifc, operator: bpy.types.Operator) -> None: path_ifc = ifc.get_path() ifcgit.config_ifcmerge() ifcgit.execute_merge(path_ifc, operator) -def entity_log(ifcgit, ifc, step_id, operator): +def entity_log(ifcgit: tool.IfcGit, ifc: tool.Ifc, step_id: int, operator: bpy.types.Operator) -> None: path_ifc = ifc.get_path() log_text = ifcgit.entity_log(path_ifc, step_id) # ERROR is only way to display a multi-line message diff --git a/src/bonsai/bonsai/tool/debug.py b/src/bonsai/bonsai/tool/debug.py index 5451cae5b6..42380e2ae3 100644 --- a/src/bonsai/bonsai/tool/debug.py +++ b/src/bonsai/bonsai/tool/debug.py @@ -26,6 +26,7 @@ import bonsai.core.tool import bonsai.tool as tool from bonsai.bim.ifc import IfcStore from mathutils import Vector +from typing import Iterable class Debug(bonsai.core.tool.Debug): @@ -66,7 +67,7 @@ class Debug(bonsai.core.tool.Debug): ifcopenshell.util.element.remove_deep2(ifc_file, element) @classmethod - def print_unused_elements_stats(cls, requested_ifc_class: str = "", ignore_classes: tuple[str] = tuple()) -> int: + def print_unused_elements_stats(cls, requested_ifc_class: str = "", ignore_classes: Iterable[str] = tuple()) -> int: ifc_file = tool.Ifc.get() # get list of ifc classes used in model diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 1b4698f2eb..d158e7c94d 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -53,13 +53,16 @@ Example: for wall in walls: print(wall.Name) """ - +from __future__ import annotations import os import sys import zipfile import tempfile from pathlib import Path -from typing import Optional, Union +from typing import Optional, Union, TYPE_CHECKING, Any + +if TYPE_CHECKING: + import ifcopenshell.express.schema_class if hasattr(os, "uname"): @@ -161,20 +164,17 @@ def open(path: Union[os.PathLike, str], format: Optional[str] = None, should_str return file(f) -def create_entity(type, schema="IFC4", *args, **kwargs): +def create_entity(type: str, schema: str = "IFC4", *args: Any, **kwargs: Any) -> entity_instance: """Creates a new IFC entity that does not belong to an IFC file object Note that it is more common to create entities within a existing file object. See :meth:`ifcopenshell.file.create_entity`. :param type: Case insensitive name of the IFC class - :type type: string :param schema: The IFC schema identifier - :type schema: string :param args: The positional arguments of the IFC class :param kwargs: The keyword arguments of the IFC class :returns: An entity instance - :rtype: ifcopenshell.entity_instance Example: @@ -191,11 +191,10 @@ def create_entity(type, schema="IFC4", *args, **kwargs): return e -def register_schema(schema): +def register_schema(schema: ifcopenshell.express.schema_class.SchemaClass) -> None: """Registers a custom IFC schema :param schema: A schema object - :type schema: ifcopenshell.express.schema_class.SchemaClass Example: @@ -212,13 +211,13 @@ def register_schema(schema): def schema_by_name( - schema: Optional[str] = None, schema_version: Optional[tuple[int, ...]] = None + schema: Optional[str] = None, + schema_version: Optional[tuple[int, ...]] = None, ) -> ifcopenshell_wrapper.schema_definition: """Returns an object allowing you to query the IFC schema itself :param schema: Which IFC schema to use, chosen from "IFC2X3", "IFC4", or "IFC4X3". These refer to the ISO approved versions of IFC. - :type schema: string, optional :param schema_version: If you want to specify an exact version of IFC that may not be an ISO approved version, use this argument instead of ``schema``. IFC versions on technical.buildingsmart.org are @@ -227,10 +226,9 @@ def schema_by_name( ADD2 TC1, which is the official version approved by ISO when people refer to "IFC4". Generally you should not use this argument unless you are testing non-ISO IFC releases. - :type schema_version: tuple[int, ...], optional :return: Schema definition object. - :rtype: ifocpenshell_wrapper.schema_definition """ + assert schema_version or schema, "Either schema or schema_version must be specified." if schema_version: prefixes = ("IFC", "X", "_ADD", "_TC") schema = "".join("".join(map(str, t)) if t[1] else "" for t in zip(prefixes, schema_version))