From 043b23dcbc07c3a8a6f54e446d02e928fe8639e7 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 11:45:48 +0200 Subject: [PATCH 01/19] fix: import user might not be able to select font --- .../tree_clipper/src/tree_clipper/dynamic_pointer.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py index addba49..a0654ce 100644 --- a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py +++ b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py @@ -1,5 +1,7 @@ import bpy +from pathlib import Path + from typing import Type from .common import no_clobber @@ -106,6 +108,14 @@ def set_active_pointer_type(self, type_name: str): for ty in KNOWN_POINTABLES: setattr(self, get_pointer_property_name(ty), None) + # Otherwise, there might be no font to select + # https://github.com/Algebraic-UG/tree_clipper/issues/219 + if type_name == "VectorFont": + font_path = ( + Path(bpy.utils.system_resource("DATAFILES")) / "fonts" / "Inter.woff2" + ) + bpy.data.fonts.load(str(font_path), check_existing=True) + # this is needed to display the property def get_active_pointer_identifier(self) -> str: return f"{prefix}{self.active_ptr_type_name}" From e3441b5ffe8ff1aad93e645cc491f94a8f113b69 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 11:49:02 +0200 Subject: [PATCH 02/19] fix: switch to PyPI for bpy 5.2 --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e027cc3..4bd0cdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,9 +55,9 @@ norecursedirs = [".git", "build", "__pycache__", "_vendor"] target = "packages/tree_clipper_addon/src/tree_clipper_addon/_vendor" packages = ["packages/tree_clipper"] -[[tool.uv.index]] -name = "bpy" -url = "https://bradyajohnston.github.io/dailybpy/" +#[[tool.uv.index]] +#name = "bpy" +#url = "https://bradyajohnston.github.io/dailybpy/" [[tool.uv.index]] name = "testpypi" From 73cc46887e581bdabf9e0a2e42909758239ae8da Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 11:49:23 +0200 Subject: [PATCH 03/19] fix: only load font if none are present --- packages/tree_clipper/src/tree_clipper/dynamic_pointer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py index a0654ce..97d822f 100644 --- a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py +++ b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py @@ -110,7 +110,7 @@ def set_active_pointer_type(self, type_name: str): # Otherwise, there might be no font to select # https://github.com/Algebraic-UG/tree_clipper/issues/219 - if type_name == "VectorFont": + if type_name == "VectorFont" and not bpy.data.fonts: font_path = ( Path(bpy.utils.system_resource("DATAFILES")) / "fonts" / "Inter.woff2" ) From 90e7a050ffcf3b644928832c275811ddff7e5bdb Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 11:52:49 +0200 Subject: [PATCH 04/19] fix: load in a temporary text curve to trigger loading default font --- packages/tree_clipper/src/tree_clipper/dynamic_pointer.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py index 97d822f..e793af2 100644 --- a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py +++ b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py @@ -111,10 +111,8 @@ def set_active_pointer_type(self, type_name: str): # Otherwise, there might be no font to select # https://github.com/Algebraic-UG/tree_clipper/issues/219 if type_name == "VectorFont" and not bpy.data.fonts: - font_path = ( - Path(bpy.utils.system_resource("DATAFILES")) / "fonts" / "Inter.woff2" - ) - bpy.data.fonts.load(str(font_path), check_existing=True) + text_curve = bpy.data.curves.new("Temp Text", type="FONT") + bpy.data.curves.remove(text_curve) # this is needed to display the property def get_active_pointer_identifier(self) -> str: From 9c80d62fb0dba68793c4bbfcb64931d28e3fb555 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 11:53:12 +0200 Subject: [PATCH 05/19] chore: update uv.lock --- uv.lock | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/uv.lock b/uv.lock index 96b71b4..531ab92 100644 --- a/uv.lock +++ b/uv.lock @@ -2,6 +2,9 @@ version = 1 revision = 3 requires-python = "==3.13.*" +[options] +prerelease-mode = "allow" + [manifest] members = [ "tree-clipper", @@ -21,8 +24,8 @@ wheels = [ [[package]] name = "bpy" -version = "5.2.0b0" -source = { registry = "https://bradyajohnston.github.io/dailybpy/" } +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cattrs" }, { name = "cython" }, @@ -31,9 +34,10 @@ dependencies = [ { name = "zstandard" }, ] wheels = [ - { url = "https://github.com/BradyAJohnston/dailybpy/releases/download/daily-2026-06-05/bpy-5.2.0b0-cp313-cp313-macosx_11_0_arm64.whl" }, - { url = "https://github.com/BradyAJohnston/dailybpy/releases/download/daily-2026-06-05/bpy-5.2.0b0-cp313-cp313-manylinux_2_39_x86_64.whl" }, - { url = "https://github.com/BradyAJohnston/dailybpy/releases/download/daily-2026-06-05/bpy-5.2.0b0-cp313-cp313-win_amd64.whl" }, + { url = "https://files.pythonhosted.org/packages/85/3a/ebdfeedbefe18641ac541c44bbe433fa363d377fedbabf4fbabb571faf5e/bpy-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6b5f9d4e02de90be7100494807a021b60c194c5d5315daef089213b2cdc8cd9d", size = 245126219, upload-time = "2026-07-14T12:14:33.631Z" }, + { url = "https://files.pythonhosted.org/packages/53/74/827c0930eec8d1b74b8c67d4066bf922f1e15a3d80f0f50ed4a48a2692b1/bpy-5.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:daae68954f1ab33996aa582861323eff815210e5c56641ac62f855a8365201c2", size = 401306561, upload-time = "2026-07-14T12:13:25.07Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d5/dd33167ec5540244b170a9f6ee1436e453ee89f0914401831268f69ea0bd/bpy-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:d657ee262bb01217343d19156c869819441b2ec436a24b302de8f1fa3a0ef1eb", size = 338722862, upload-time = "2026-07-14T12:14:14.093Z" }, + { url = "https://files.pythonhosted.org/packages/82/cb/a8d985a59e8e31cf55f6b62144305379a4c3d795633186933059bc91c16a/bpy-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:925ae162a1bcde29a514804a5ef3afc5516fccc5ce568e7c8dee95d66a06215a", size = 210627206, upload-time = "2026-07-14T12:13:44.824Z" }, ] [[package]] @@ -275,7 +279,7 @@ wheels = [ [[package]] name = "tree-clipper" -version = "0.1.6" +version = "0.1.8" source = { editable = "packages/tree_clipper" } [package.optional-dependencies] From 09d7a299936bb9aa523c259bcb2b821c6b4aad05 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 11:58:15 +0200 Subject: [PATCH 06/19] chore: update ruff --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4bd0cdf..c19190f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ dev = [ "fake-bpy-module>=20251003", "pytest>=9.0.1", "deepdiff>=8.6.1", - "ruff>=0.14.10", + "ruff>=0.16.0", "ty>=0.0.3", "vendorize", "pip>=25.3", From c1e17f2ac1d3ed9f7a1bd57f03be6f4847ca95da Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:08:31 +0200 Subject: [PATCH 07/19] fix: ruff --fix --- .../tree_clipper/src/tree_clipper/common.py | 14 ++--- .../src/tree_clipper/dynamic_pointer.py | 8 +-- .../src/tree_clipper/export_nodes.py | 52 ++++++++--------- .../src/tree_clipper/id_data_getter.py | 4 +- .../src/tree_clipper/import_nodes.py | 57 +++++++++---------- .../src/tree_clipper/scene_info.py | 6 +- .../src/tree_clipper/specific_abstract.py | 17 +++--- .../src/tree_clipper/specific_handlers.py | 32 +++++------ packages/tree_clipper/tests/conftest.py | 5 +- .../tree_clipper/tests/test_5_0_to_5_1.py | 2 +- .../tree_clipper/tests/test_5_1_to_5_2.py | 2 +- packages/tree_clipper/tests/test_all_nodes.py | 9 ++- .../tree_clipper/tests/test_bundled_assets.py | 4 +- .../tests/test_erindales_nodevember.py | 4 +- .../tree_clipper/tests/test_external_items.py | 24 ++++---- .../tests/test_known_pointables.py | 5 +- .../tests/test_microscopy_nodes.py | 5 +- .../tests/test_molecular_nodes.py | 3 +- .../tests/test_multi_input_order.py | 2 +- .../tests/test_new_default_input.py | 2 +- .../tests/test_panel_toggle_order.py | 3 +- .../tests/test_render_layers_edgecase.py | 2 +- .../tests/test_squishy_volumes.py | 3 +- .../tests/test_third_party_attributes.py | 5 +- .../tree_clipper/tests/test_typst_importer.py | 3 +- packages/tree_clipper/tests/test_version.py | 2 +- packages/tree_clipper/tests/util.py | 18 +++--- .../src/tree_clipper_addon/__init__.py | 15 ++--- .../tree_clipper_addon/operators_export.py | 10 ++-- .../tree_clipper_addon/operators_import.py | 12 ++-- .../tree_clipper_tools/export_all_trees.py | 6 +- .../tree_clipper_tools/get_json_from_file.py | 5 +- .../tree_clipper_tools/print_trees_in_file.py | 3 +- 33 files changed, 160 insertions(+), 184 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/common.py b/packages/tree_clipper/src/tree_clipper/common.py index fd0ad2f..441d6fb 100644 --- a/packages/tree_clipper/src/tree_clipper/common.py +++ b/packages/tree_clipper/src/tree_clipper/common.py @@ -1,10 +1,10 @@ -import bpy - -from types import NoneType -from typing import Any, Callable, TYPE_CHECKING -from pathlib import Path import tempfile +from collections.abc import Callable +from pathlib import Path +from types import NoneType +from typing import TYPE_CHECKING, Any +import bpy if TYPE_CHECKING: from .export_nodes import Exporter @@ -110,7 +110,7 @@ def most_specific_type_handled( return next( ( ty - for ty in specific_handlers.keys() + for ty in specific_handlers if ty != NoneType and ty.bl_rna.identifier == obj.bl_rna.identifier # type: ignore ), NoneType, @@ -118,7 +118,7 @@ def most_specific_type_handled( ty = type(obj) while True: - if ty in specific_handlers.keys(): + if ty in specific_handlers: return ty if len(ty.__bases__) == 0: return NoneType diff --git a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py index e793af2..8daabf9 100644 --- a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py +++ b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py @@ -1,12 +1,8 @@ -import bpy - -from pathlib import Path -from typing import Type +import bpy from .common import no_clobber - # TODO: we might need to return a list that fits the Blender version KNOWN_POINTABLES = { bpy.types.SunLight, @@ -77,7 +73,7 @@ def add_all_known_pointer_properties( *, - cls: Type[bpy.types.PropertyGroup], + cls: type[bpy.types.PropertyGroup], prefix: str, ): def get_pointer_property_name(ty: type): diff --git a/packages/tree_clipper/src/tree_clipper/export_nodes.py b/packages/tree_clipper/src/tree_clipper/export_nodes.py index e64a95c..87cb2d3 100644 --- a/packages/tree_clipper/src/tree_clipper/export_nodes.py +++ b/packages/tree_clipper/src/tree_clipper/export_nodes.py @@ -1,52 +1,52 @@ -import bpy - import base64 import gzip import json +from collections.abc import Iterator from pathlib import Path from types import NoneType -from typing import Any, cast, Type, Iterator, Tuple +from typing import Any, cast + +import bpy from .common import ( + BL_RNA, BLENDER_VERSION, CURRENT_TREE_CLIPPER_VERSION, DATA, DEFAULT_VALUE, DIMENSIONS, DISPLAY_SHAPE, + EXTERNAL, EXTERNAL_DESCRIPTION, + EXTERNAL_FIXED_TYPE_NAME, + EXTERNAL_SCENE_ID, + EXTERNAL_SERIALIZATION, FORBIDDEN_PROPERTIES, + FROM_ROOT, ID, + ITEMS, MAGIC_STRING, MATERIAL_NAME, - SIMPLE_PROPERTY_TYPES_AS_STRS, + NAME, + NODE_TREE, + PROP_TYPE_BOOLEAN, + PROP_TYPE_COLLECTION, + PROP_TYPE_ENUM, + PROP_TYPE_FLOAT, + PROP_TYPE_INT, + PROP_TYPE_POINTER, + RNA_TYPE, + SCENES, SERIALIZER, SIMPLE_DATA_TYPE, SIMPLE_PROP_TYPE, + SIMPLE_PROPERTY_TYPES_AS_STRS, TREE_CLIPPER_VERSION, TREES, FromRoot, most_specific_type_handled, no_clobber, - EXTERNAL_SERIALIZATION, - PROP_TYPE_BOOLEAN, - PROP_TYPE_INT, - PROP_TYPE_FLOAT, - PROP_TYPE_ENUM, - PROP_TYPE_POINTER, - PROP_TYPE_COLLECTION, - NAME, - ITEMS, - BL_RNA, - FROM_ROOT, - RNA_TYPE, - EXTERNAL, - EXTERNAL_FIXED_TYPE_NAME, - NODE_TREE, - SCENES, - EXTERNAL_SCENE_ID, ) - from .id_data_getter import canonical_reference from .scene_info import export_scene_info @@ -112,7 +112,7 @@ def export_all_simple_writable_properties( self, *, obj: bpy.types.bpy_struct, - assumed_type: Type[bpy.types.bpy_struct], + assumed_type: type[bpy.types.bpy_struct], from_root: FromRoot, ) -> dict[str, SIMPLE_DATA_TYPE]: data = {} @@ -222,7 +222,7 @@ def _export_property_simple( ) # https://github.com/Algebraic-UG/tree_clipper/issues/96 - def clamp_and_report(value: int | float) -> int | float: + def clamp_and_report(value: float) -> int | float: # https://github.com/Algebraic-UG/tree_clipper/issues/162 if isinstance(obj, bpy.types.NodeTreeInterfaceSocket): return value @@ -311,7 +311,7 @@ def _export_property_collection( self._export_obj( obj=element, from_root=from_root.add( - f"[{i}] ({getattr(attribute[i], NAME, 'unnamed')})" + f"[{i}] ({getattr(element, NAME, 'unnamed')})" ), ) for i, element in enumerate(attribute) @@ -712,7 +712,7 @@ def get_external(self) -> dict[int, External]: def set_external( self, - ids_and_descriptions: Iterator[Tuple[int, str]], + ids_and_descriptions: Iterator[tuple[int, str]], ) -> None: assert not self.unexported_trees for external_id, description in ids_and_descriptions: diff --git a/packages/tree_clipper/src/tree_clipper/id_data_getter.py b/packages/tree_clipper/src/tree_clipper/id_data_getter.py index 8c7cf58..083144e 100644 --- a/packages/tree_clipper/src/tree_clipper/id_data_getter.py +++ b/packages/tree_clipper/src/tree_clipper/id_data_getter.py @@ -1,6 +1,6 @@ -import bpy +from collections.abc import Callable -from typing import Callable +import bpy _ID_TYPE_TO_DATA_BLOCK: dict[str, Callable[[], bpy.types.bpy_prop_collection]] = { "ACTION": lambda: bpy.data.actions, diff --git a/packages/tree_clipper/src/tree_clipper/import_nodes.py b/packages/tree_clipper/src/tree_clipper/import_nodes.py index 21a397e..053e1f4 100644 --- a/packages/tree_clipper/src/tree_clipper/import_nodes.py +++ b/packages/tree_clipper/src/tree_clipper/import_nodes.py @@ -1,53 +1,50 @@ -import bpy - -from operator import xor - import base64 import gzip import json +from collections.abc import Iterator +from operator import xor +from pathlib import Path from types import NoneType +from typing import Any -from typing import Any, Type, Tuple, Iterator - -from pathlib import Path +import bpy from .common import ( + BL_IDNAME, + BL_RNA, + BLENDER_VERSION, CURRENT_TREE_CLIPPER_VERSION, DATA, + DEFAULT_VALUE, DESERIALIZER, + EXTERNAL, + EXTERNAL_DESCRIPTION, + EXTERNAL_SCENE_ID, + EXTERNAL_SERIALIZATION, FORBIDDEN_PROPERTIES, GETTER, ID, + ITEMS, + MAGIC_STRING, MATERIAL_NAME, - SIMPLE_PROP_TYPE, - SIMPLE_PROPERTY_TYPES_AS_STRS, - BLENDER_VERSION, + NAME, + PROP_TYPE_COLLECTION, + PROP_TYPE_ENUM, + PROP_TYPE_POINTER, + RNA_TYPE, + SCENES, SIMPLE_DATA_TYPE, + SIMPLE_PROP_TYPE, SIMPLE_PROP_TYPE_TUPLE, + SIMPLE_PROPERTY_TYPES_AS_STRS, TREE_CLIPPER_VERSION, TREES, FromRoot, most_specific_type_handled, - MAGIC_STRING, - EXTERNAL_SERIALIZATION, - PROP_TYPE_ENUM, - DEFAULT_VALUE, - PROP_TYPE_POINTER, - PROP_TYPE_COLLECTION, - ITEMS, - NAME, - BL_RNA, - RNA_TYPE, - BL_IDNAME, - EXTERNAL_DESCRIPTION, - EXTERNAL, - SCENES, no_clobber, - EXTERNAL_SCENE_ID, ) - from .id_data_getter import make_id_data_getter -from .scene_info import verify_scene, SceneValidationError +from .scene_info import SceneValidationError, verify_scene class ImportReport: @@ -113,7 +110,7 @@ def import_all_simple_writable_properties( *, getter: GETTER, serialization: dict[str, Any], - assumed_type: Type[bpy.types.bpy_struct], + assumed_type: type[bpy.types.bpy_struct], forbidden: list[str], from_root: FromRoot, ) -> None: @@ -282,7 +279,7 @@ def make_getter(i: int) -> GETTER: name = item[DATA].get(NAME, "unnamed") self._import_obj( getter=make_getter(i), - serialization=serialized_items[i], + serialization=item, from_root=from_root.add(f"[{i}] ({name})"), ) @@ -619,7 +616,7 @@ def get_external(self) -> dict[str, EXTERNAL_SERIALIZATION]: def set_external( self, - ids_and_references: Iterator[Tuple[int, bpy.types.ID | None]], + ids_and_references: Iterator[tuple[int, bpy.types.ID | None]], ) -> None: for external_id, external_item in ids_and_references: scene_id = self.get_external()[str(external_id)][EXTERNAL_SCENE_ID] diff --git a/packages/tree_clipper/src/tree_clipper/scene_info.py b/packages/tree_clipper/src/tree_clipper/scene_info.py index 3c8e4c2..fc9ca7b 100644 --- a/packages/tree_clipper/src/tree_clipper/scene_info.py +++ b/packages/tree_clipper/src/tree_clipper/scene_info.py @@ -4,11 +4,11 @@ # parameters to reconstruct the tree around the nodes that reference it and it's view layers. # All of this is very ad-hoc and might well break in the future. -import bpy - from typing import Any -from .common import no_clobber, PROP_TYPE_BOOLEAN, NAME +import bpy + +from .common import NAME, PROP_TYPE_BOOLEAN, no_clobber # to help prevent typos VIEW_LAYERS = "view_layers" diff --git a/packages/tree_clipper/src/tree_clipper/specific_abstract.py b/packages/tree_clipper/src/tree_clipper/specific_abstract.py index 7292efd..0a2f5eb 100644 --- a/packages/tree_clipper/src/tree_clipper/specific_abstract.py +++ b/packages/tree_clipper/src/tree_clipper/specific_abstract.py @@ -1,17 +1,16 @@ from __future__ import annotations -import bpy - -from types import NoneType from abc import ABC, abstractmethod -from typing import Any, Callable, Generic, TypeVar, ClassVar, Type +from collections.abc import Callable +from types import NoneType +from typing import Any, ClassVar, Generic, TypeVar +import bpy from .common import FromRoot, no_clobber from .export_nodes import Exporter from .import_nodes import GETTER, Importer - AssumedType = TypeVar("AssumedType", bound=bpy.types.bpy_struct) @@ -67,7 +66,7 @@ def serialize(self): """ # the concrete bpy type for this subclass, e.g. bpy.types.NodeTree - assumed_type: ClassVar[Type[AssumedType]] + assumed_type: ClassVar[type[AssumedType]] # this does three things # 1. fetch the type we want to treat and store it in `assumed_type` @@ -80,7 +79,7 @@ def __init_subclass__(cls, **kwargs): # Infer AssumedType from: class Foo(SpecificExporter[SomeType]): # it's a bit complicated to allow for multiple base classes # (if you wanted that for some reason) - assumed_type: Type[bpy.types.bpy_struct] | None = None + assumed_type: type[bpy.types.bpy_struct] | None = None for base in getattr(cls, "__orig_bases__", ()): origin = getattr(base, "__origin__", None) if origin is SpecificExporter: @@ -192,7 +191,7 @@ def deserialize(self): """ # the concrete bpy type for this subclass, e.g. bpy.types.NodeTree - assumed_type: ClassVar[Type[AssumedType]] + assumed_type: ClassVar[type[AssumedType]] # this does three things # 1. fetch the type we want to treat and store it in `assumed_type` @@ -205,7 +204,7 @@ def __init_subclass__(cls, **kwargs): # Infer AssumedType from: class Foo(SpecificImporter[SomeType]): # it's a bit complicated to allow for multiple base classes # (if you wanted that for some reason) - assumed_type: Type[bpy.types.bpy_struct] | None = None + assumed_type: type[bpy.types.bpy_struct] | None = None for base in getattr(cls, "__orig_bases__", ()): origin = getattr(base, "__origin__", None) if origin is SpecificImporter: diff --git a/packages/tree_clipper/src/tree_clipper/specific_handlers.py b/packages/tree_clipper/src/tree_clipper/specific_handlers.py index ed26d2e..5f09bc1 100644 --- a/packages/tree_clipper/src/tree_clipper/specific_handlers.py +++ b/packages/tree_clipper/src/tree_clipper/specific_handlers.py @@ -1,27 +1,25 @@ -import bpy - -from typing import Type, Any +from typing import Any -from .specific_abstract import ( - _BUILT_IN_EXPORTER, - _BUILT_IN_IMPORTER, - SpecificExporter, - SpecificImporter, -) - -from .import_nodes import Importer +import bpy from .common import ( + BL_IDNAME, DATA, + DEFAULT_VALUE, DIMENSIONS, + GETTER, ID, - no_clobber, ITEMS, - BL_IDNAME, NAME, - DEFAULT_VALUE, - GETTER, NODE_TREE, + no_clobber, +) +from .import_nodes import Importer +from .specific_abstract import ( + _BUILT_IN_EXPORTER, + _BUILT_IN_IMPORTER, + SpecificExporter, + SpecificImporter, ) # to help prevent typos, especially when used multiple times @@ -112,7 +110,7 @@ # this might not be needed anymore in many cases, because # due to https://github.com/Algebraic-UG/tree_clipper/issues/59 # we don't skip defaults anymore -def _or_default(serialization: dict, ty: Type[bpy.types.bpy_struct], identifier: str): +def _or_default(serialization: dict, ty: type[bpy.types.bpy_struct], identifier: str): return serialization.get(identifier, ty.bl_rna.properties[identifier].default) # ty: ignore[unresolved-attribute] @@ -1538,7 +1536,7 @@ def make_getter(i: int) -> GETTER: name = item.get(NAME, "unnamed") self.importer._import_obj( getter=make_getter(i), - serialization=serialized_outputs[i], + serialization=item, from_root=self.from_root.add(f"[{i}] ({name})"), ) diff --git a/packages/tree_clipper/tests/conftest.py b/packages/tree_clipper/tests/conftest.py index 3e4cc6e..c2004dd 100644 --- a/packages/tree_clipper/tests/conftest.py +++ b/packages/tree_clipper/tests/conftest.py @@ -1,11 +1,10 @@ -import bpy import _rna_info as rna_info - +import bpy import pytest -from .util import all_subclasses, BACKWARDS_COMPATIBILITY_FILES_DIR from .test_all_nodes import test_all_nodes from .test_backwards_compatibility import test_backwards_compatibility_to_0_1_1 +from .util import BACKWARDS_COMPATIBILITY_FILES_DIR, all_subclasses @pytest.fixture(autouse=True) diff --git a/packages/tree_clipper/tests/test_5_0_to_5_1.py b/packages/tree_clipper/tests/test_5_0_to_5_1.py index f61aa4e..3f9c4da 100644 --- a/packages/tree_clipper/tests/test_5_0_to_5_1.py +++ b/packages/tree_clipper/tests/test_5_0_to_5_1.py @@ -1,9 +1,9 @@ import bpy from .util import ( - save_failed, BACKWARDS_COMPATIBILITY_FILES_DIR, import_and_check_export, + save_failed, ) _DIR = BACKWARDS_COMPATIBILITY_FILES_DIR / "blender_5_0_to_5_1" diff --git a/packages/tree_clipper/tests/test_5_1_to_5_2.py b/packages/tree_clipper/tests/test_5_1_to_5_2.py index bfe51fc..70b3197 100644 --- a/packages/tree_clipper/tests/test_5_1_to_5_2.py +++ b/packages/tree_clipper/tests/test_5_1_to_5_2.py @@ -1,9 +1,9 @@ import bpy from .util import ( - save_failed, BACKWARDS_COMPATIBILITY_FILES_DIR, import_and_check_export, + save_failed, ) _DIR = BACKWARDS_COMPATIBILITY_FILES_DIR / "blender_5_1_to_5_2" diff --git a/packages/tree_clipper/tests/test_all_nodes.py b/packages/tree_clipper/tests/test_all_nodes.py index d863385..69846e1 100644 --- a/packages/tree_clipper/tests/test_all_nodes.py +++ b/packages/tree_clipper/tests/test_all_nodes.py @@ -1,8 +1,7 @@ -import bpy -from typing import Type +import bpy -from .util import make_test_node_tree, save_failed, round_trip +from .util import make_test_node_tree, round_trip, save_failed _PAIRED_NODE_TYPES = { bpy.types.GeometryNodeForeachGeometryElementInput: bpy.types.GeometryNodeForeachGeometryElementOutput, @@ -12,7 +11,7 @@ } -def test_all_nodes(node_type: Type[bpy.types.Node]): +def test_all_nodes(node_type: type[bpy.types.Node]): try: ignore = [ bpy.types.NodeGroup, @@ -51,7 +50,7 @@ def test_all_nodes(node_type: Type[bpy.types.Node]): tree.nodes.new(type=node_type_str) # these need to be tested in combination with the outputs - if node_type in _PAIRED_NODE_TYPES.keys(): + if node_type in _PAIRED_NODE_TYPES: output_type = _PAIRED_NODE_TYPES[node_type] output_node = tree.nodes.new(type=output_type.bl_rna.identifier) # ty: ignore[unresolved-attribute] tree.nodes[0].pair_with_output(output_node) diff --git a/packages/tree_clipper/tests/test_bundled_assets.py b/packages/tree_clipper/tests/test_bundled_assets.py index a8da15b..024c97d 100644 --- a/packages/tree_clipper/tests/test_bundled_assets.py +++ b/packages/tree_clipper/tests/test_bundled_assets.py @@ -1,9 +1,9 @@ import bpy from .util import ( - save_failed, - round_trip, NODE_ASSETS_DIR, + round_trip, + save_failed, ) if (bpy.app.version[0] == 5 and bpy.app.version[1] >= 2) or bpy.app.version[0] > 5: diff --git a/packages/tree_clipper/tests/test_erindales_nodevember.py b/packages/tree_clipper/tests/test_erindales_nodevember.py index 95ac0f1..62846cf 100644 --- a/packages/tree_clipper/tests/test_erindales_nodevember.py +++ b/packages/tree_clipper/tests/test_erindales_nodevember.py @@ -2,9 +2,9 @@ from .util import ( BINARY_BLEND_FILES_DIR, - save_failed, - round_trip, make_everything_local, + round_trip, + save_failed, ) testdata = [ diff --git a/packages/tree_clipper/tests/test_external_items.py b/packages/tree_clipper/tests/test_external_items.py index 472ad83..32bcdb1 100644 --- a/packages/tree_clipper/tests/test_external_items.py +++ b/packages/tree_clipper/tests/test_external_items.py @@ -1,20 +1,18 @@ +from collections.abc import Callable + +import bpy +from tree_clipper.common import EXTERNAL_SERIALIZATION +from tree_clipper.export_nodes import ExportIntermediate, ExportParameters, External +from tree_clipper.import_nodes import ImportIntermediate, ImportParameters +from tree_clipper.specific_handlers import BUILT_IN_EXPORTER, BUILT_IN_IMPORTER + from tests.util import ( - make_test_object, make_test_collection, make_test_node_tree, + make_test_object, make_test_sound, save_failed, ) -import bpy - -from typing import Callable - -from tree_clipper.common import EXTERNAL_SERIALIZATION -from tree_clipper.import_nodes import ImportIntermediate, ImportParameters - -from tree_clipper.specific_handlers import BUILT_IN_EXPORTER, BUILT_IN_IMPORTER -from tree_clipper.export_nodes import ExportIntermediate, ExportParameters, External - _EXTERNAL_ITEM_MAKER: dict[str, Callable[[], bpy.types.ID]] = { "Image": lambda: bpy.data.images.new(name="test", width=10, height=10), @@ -91,7 +89,7 @@ def _check_before_export(external_items: list[External]): == external_item.pointed_to_by.fixed_type_name ) - for expected_external_type in _EXTERNAL_ITEM_MAKER.keys(): + for expected_external_type in _EXTERNAL_ITEM_MAKER: assert ( len( [ @@ -115,7 +113,7 @@ def _check_before_import(external_items: list[EXTERNAL_SERIALIZATION]): external_item["fixed_type_name"] # ty: ignore[invalid-argument-type] ) - for expected_external_type in _EXTERNAL_ITEM_MAKER.keys(): + for expected_external_type in _EXTERNAL_ITEM_MAKER: assert ( len( [ diff --git a/packages/tree_clipper/tests/test_known_pointables.py b/packages/tree_clipper/tests/test_known_pointables.py index c561ad5..d43c28c 100644 --- a/packages/tree_clipper/tests/test_known_pointables.py +++ b/packages/tree_clipper/tests/test_known_pointables.py @@ -1,7 +1,6 @@ -import deepdiff -import bpy import _rna_info as rna_info - +import bpy +import deepdiff from tree_clipper.dynamic_pointer import KNOWN_POINTABLES from .util import all_subclasses diff --git a/packages/tree_clipper/tests/test_microscopy_nodes.py b/packages/tree_clipper/tests/test_microscopy_nodes.py index f2fec83..f1d3775 100644 --- a/packages/tree_clipper/tests/test_microscopy_nodes.py +++ b/packages/tree_clipper/tests/test_microscopy_nodes.py @@ -2,12 +2,11 @@ from .util import ( BINARY_BLEND_FILES_DIR, - save_failed, - round_trip, make_everything_local, + round_trip, + save_failed, ) - _DIR = BINARY_BLEND_FILES_DIR / "microscopy_nodes" diff --git a/packages/tree_clipper/tests/test_molecular_nodes.py b/packages/tree_clipper/tests/test_molecular_nodes.py index 0239553..14cbd67 100644 --- a/packages/tree_clipper/tests/test_molecular_nodes.py +++ b/packages/tree_clipper/tests/test_molecular_nodes.py @@ -1,7 +1,6 @@ import bpy -from .util import BINARY_BLEND_FILES_DIR, save_failed, round_trip - +from .util import BINARY_BLEND_FILES_DIR, round_trip, save_failed _DIR = BINARY_BLEND_FILES_DIR / "molecular_nodes" diff --git a/packages/tree_clipper/tests/test_multi_input_order.py b/packages/tree_clipper/tests/test_multi_input_order.py index c6348a3..cd4c5d9 100644 --- a/packages/tree_clipper/tests/test_multi_input_order.py +++ b/packages/tree_clipper/tests/test_multi_input_order.py @@ -1,4 +1,4 @@ -from .util import round_trip_without_external, make_test_node_tree, save_failed +from .util import make_test_node_tree, round_trip_without_external, save_failed def test_multi_input_order(): diff --git a/packages/tree_clipper/tests/test_new_default_input.py b/packages/tree_clipper/tests/test_new_default_input.py index 65f7316..e6096ce 100644 --- a/packages/tree_clipper/tests/test_new_default_input.py +++ b/packages/tree_clipper/tests/test_new_default_input.py @@ -1,6 +1,6 @@ import bpy -from .util import round_trip_without_external, make_test_node_tree, save_failed +from .util import make_test_node_tree, round_trip_without_external, save_failed if (bpy.app.version[0] == 5 and bpy.app.version[1] >= 2) or bpy.app.version[0] > 5: diff --git a/packages/tree_clipper/tests/test_panel_toggle_order.py b/packages/tree_clipper/tests/test_panel_toggle_order.py index 9562bef..c007384 100644 --- a/packages/tree_clipper/tests/test_panel_toggle_order.py +++ b/packages/tree_clipper/tests/test_panel_toggle_order.py @@ -1,5 +1,6 @@ import bpy -from .util import round_trip_without_external, make_test_node_tree, save_failed + +from .util import make_test_node_tree, round_trip_without_external, save_failed # https://github.com/Algebraic-UG/tree_clipper/issues/80 diff --git a/packages/tree_clipper/tests/test_render_layers_edgecase.py b/packages/tree_clipper/tests/test_render_layers_edgecase.py index 1002e51..f64ccf4 100644 --- a/packages/tree_clipper/tests/test_render_layers_edgecase.py +++ b/packages/tree_clipper/tests/test_render_layers_edgecase.py @@ -2,8 +2,8 @@ from .util import ( make_test_node_tree, - save_failed, round_trip, + save_failed, ) diff --git a/packages/tree_clipper/tests/test_squishy_volumes.py b/packages/tree_clipper/tests/test_squishy_volumes.py index d246bcb..ce57cdc 100644 --- a/packages/tree_clipper/tests/test_squishy_volumes.py +++ b/packages/tree_clipper/tests/test_squishy_volumes.py @@ -1,7 +1,6 @@ import bpy -from .util import BINARY_BLEND_FILES_DIR, save_failed, round_trip - +from .util import BINARY_BLEND_FILES_DIR, round_trip, save_failed _DIR = BINARY_BLEND_FILES_DIR / "squishy_volumes" diff --git a/packages/tree_clipper/tests/test_third_party_attributes.py b/packages/tree_clipper/tests/test_third_party_attributes.py index ad4c68f..895c952 100644 --- a/packages/tree_clipper/tests/test_third_party_attributes.py +++ b/packages/tree_clipper/tests/test_third_party_attributes.py @@ -1,13 +1,12 @@ import bpy - from tree_clipper.import_nodes import ImportIntermediate, ImportParameters from tree_clipper.specific_handlers import BUILT_IN_EXPORTER, BUILT_IN_IMPORTER from .util import ( + diff_exports, + export_to_string, make_test_node_tree, round_trip_without_external, - export_to_string, - diff_exports, ) diff --git a/packages/tree_clipper/tests/test_typst_importer.py b/packages/tree_clipper/tests/test_typst_importer.py index 630c692..94281f8 100644 --- a/packages/tree_clipper/tests/test_typst_importer.py +++ b/packages/tree_clipper/tests/test_typst_importer.py @@ -1,7 +1,6 @@ import bpy -from .util import BINARY_BLEND_FILES_DIR, save_failed, round_trip - +from .util import BINARY_BLEND_FILES_DIR, round_trip, save_failed _DIR = BINARY_BLEND_FILES_DIR / "typst_importer" diff --git a/packages/tree_clipper/tests/test_version.py b/packages/tree_clipper/tests/test_version.py index b36c8d2..d571495 100644 --- a/packages/tree_clipper/tests/test_version.py +++ b/packages/tree_clipper/tests/test_version.py @@ -1,5 +1,5 @@ -from pathlib import Path import tomllib +from pathlib import Path from tree_clipper.common import CURRENT_TREE_CLIPPER_VERSION diff --git a/packages/tree_clipper/tests/util.py b/packages/tree_clipper/tests/util.py index 7d738b0..8e7a3d9 100644 --- a/packages/tree_clipper/tests/util.py +++ b/packages/tree_clipper/tests/util.py @@ -1,24 +1,24 @@ -import deepdiff import json from pathlib import Path from typing import Literal -import bpy +import bpy +import deepdiff from tree_clipper.common import ( - EXTERNAL_FIXED_TYPE_NAME, + BLENDER_VERSION, + CURRENT_TREE_CLIPPER_VERSION, + DATA, + DEFAULT_HINT, EXTERNAL_DESCRIPTION, + EXTERNAL_FIXED_TYPE_NAME, EXTERNAL_SERIALIZATION, - DATA, MATERIAL_NAME, - TREES, NAME, - DEFAULT_HINT, TREE_CLIPPER_VERSION, - CURRENT_TREE_CLIPPER_VERSION, - BLENDER_VERSION, + TREES, ) -from tree_clipper.id_data_getter import get_data_block_from_id_name from tree_clipper.export_nodes import ExportIntermediate, ExportParameters +from tree_clipper.id_data_getter import get_data_block_from_id_name from tree_clipper.import_nodes import ImportIntermediate, ImportParameters, ImportReport from tree_clipper.specific_handlers import BUILT_IN_EXPORTER, BUILT_IN_IMPORTER diff --git a/packages/tree_clipper_addon/src/tree_clipper_addon/__init__.py b/packages/tree_clipper_addon/src/tree_clipper_addon/__init__.py index bfb20f9..2db9dc7 100644 --- a/packages/tree_clipper_addon/src/tree_clipper_addon/__init__.py +++ b/packages/tree_clipper_addon/src/tree_clipper_addon/__init__.py @@ -14,25 +14,22 @@ import bpy from .operators_export import ( - Tree_Clipper_External_Export_Item, - SCENE_UL_Tree_Clipper_External_Export_List, SCENE_OT_Tree_Clipper_Export_Cache, SCENE_OT_Tree_Clipper_Export_Modal, SCENE_OT_Tree_Clipper_Export_Prepare, + SCENE_UL_Tree_Clipper_External_Export_List, + Tree_Clipper_External_Export_Item, ) - from .operators_import import ( - Tree_Clipper_External_Import_Item, - Tree_Clipper_External_Import_Items, - SCENE_UL_Tree_Clipper_External_Import_List, SCENE_OT_Tree_Clipper_Import_Cache, - SCENE_OT_Tree_Clipper_Import_File_Prepare, SCENE_OT_Tree_Clipper_Import_Clipboard_Prepare, + SCENE_OT_Tree_Clipper_Import_File_Prepare, SCENE_OT_Tree_Clipper_Import_Modal, + SCENE_UL_Tree_Clipper_External_Import_List, + Tree_Clipper_External_Import_Item, + Tree_Clipper_External_Import_Items, ) - from .panel import SCENE_PT_Tree_Clipper_Panel - from .preferences import TreeClipperPreferences classes = [ diff --git a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py index cf97589..47b8caa 100644 --- a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py +++ b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py @@ -1,20 +1,18 @@ -import bpy +from typing import TYPE_CHECKING, Any -from typing import Any, TYPE_CHECKING +import bpy if TYPE_CHECKING: - import bpy._typing.rna_enums as rna_enums # type: ignore + from bpy._typing import rna_enums # type: ignore from pathlib import Path from ._vendor.tree_clipper.common import DEFAULT_FILE, DEFAULT_HINT - +from ._vendor.tree_clipper.export_nodes import ExportIntermediate, ExportParameters from ._vendor.tree_clipper.specific_handlers import ( BUILT_IN_EXPORTER, ) -from ._vendor.tree_clipper.export_nodes import ExportParameters, ExportIntermediate - from .preferences import get_max_clipboard_bytes, get_show_advanced_options _INTERMEDIATE_EXPORT_CACHE = None diff --git a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py index e3a20e6..110c456 100644 --- a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py +++ b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py @@ -1,22 +1,20 @@ -import bpy import time +from typing import TYPE_CHECKING, Any -from typing import Any, TYPE_CHECKING +import bpy if TYPE_CHECKING: - import bpy._typing.rna_enums as rna_enums # type: ignore + from bpy._typing import rna_enums # type: ignore from pathlib import Path -from ._vendor.tree_clipper.dynamic_pointer import add_all_known_pointer_properties from ._vendor.tree_clipper.common import DEFAULT_FILE - +from ._vendor.tree_clipper.dynamic_pointer import add_all_known_pointer_properties +from ._vendor.tree_clipper.import_nodes import ImportIntermediate, ImportParameters from ._vendor.tree_clipper.specific_handlers import ( BUILT_IN_IMPORTER, ) -from ._vendor.tree_clipper.import_nodes import ImportParameters, ImportIntermediate - from .post_import import post_import from .preferences import get_show_advanced_options diff --git a/packages/tree_clipper_tools/src/tree_clipper_tools/export_all_trees.py b/packages/tree_clipper_tools/src/tree_clipper_tools/export_all_trees.py index 19382fa..26e2edd 100644 --- a/packages/tree_clipper_tools/src/tree_clipper_tools/export_all_trees.py +++ b/packages/tree_clipper_tools/src/tree_clipper_tools/export_all_trees.py @@ -1,10 +1,10 @@ -from tree_clipper.specific_handlers import BUILT_IN_EXPORTER -from tree_clipper.export_nodes import ExportIntermediate, ExportParameters import argparse from pathlib import Path -import bpy +import bpy from tree_clipper.common import NODE_TREE +from tree_clipper.export_nodes import ExportIntermediate, ExportParameters +from tree_clipper.specific_handlers import BUILT_IN_EXPORTER def _collect_sub_trees( diff --git a/packages/tree_clipper_tools/src/tree_clipper_tools/get_json_from_file.py b/packages/tree_clipper_tools/src/tree_clipper_tools/get_json_from_file.py index bf1d336..79db96d 100644 --- a/packages/tree_clipper_tools/src/tree_clipper_tools/get_json_from_file.py +++ b/packages/tree_clipper_tools/src/tree_clipper_tools/get_json_from_file.py @@ -1,7 +1,8 @@ -from tree_clipper.specific_handlers import BUILT_IN_EXPORTER -from tree_clipper.export_nodes import ExportIntermediate, ExportParameters import argparse + import bpy +from tree_clipper.export_nodes import ExportIntermediate, ExportParameters +from tree_clipper.specific_handlers import BUILT_IN_EXPORTER parser = argparse.ArgumentParser(prog="Get JSON from tree in file") parser.add_argument("--filename", required=True) diff --git a/packages/tree_clipper_tools/src/tree_clipper_tools/print_trees_in_file.py b/packages/tree_clipper_tools/src/tree_clipper_tools/print_trees_in_file.py index f82daa8..177afc1 100644 --- a/packages/tree_clipper_tools/src/tree_clipper_tools/print_trees_in_file.py +++ b/packages/tree_clipper_tools/src/tree_clipper_tools/print_trees_in_file.py @@ -1,6 +1,7 @@ -import bpy import sys +import bpy + if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: uv run print_tree_in_file.py ") From 8765310a4705626d3c9c47e5372646a60888ba09 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:24:14 +0200 Subject: [PATCH 08/19] fix: explicitly state options as ClassVar --- .../src/tree_clipper_addon/operators_export.py | 8 ++++---- .../src/tree_clipper_addon/operators_import.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py index 47b8caa..99d8aa5 100644 --- a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py +++ b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar import bpy @@ -21,7 +21,7 @@ class SCENE_OT_Tree_Clipper_Export_Prepare(bpy.types.Operator): bl_idname = "scene.tree_clipper_export_prepare" bl_label = "Export" - bl_options = {"REGISTER"} + bl_options: ClassVar[set[str]] = {"REGISTER"} # ty:ignore[invalid-attribute-override] is_material: bpy.props.BoolProperty(name="Top level Material") # type: ignore name: bpy.props.StringProperty(name="Material/NodeTree") # type: ignore @@ -70,7 +70,7 @@ def draw(self, context: bpy.types.Context) -> None: class SCENE_OT_Tree_Clipper_Export_Modal(bpy.types.Operator): bl_idname = "scene.tree_clipper_export_modal" bl_label = "Export Modal" - bl_options = set() + bl_options: ClassVar[set[str]] = set() # ty:ignore[invalid-attribute-override] _timer = None @@ -151,7 +151,7 @@ class Tree_Clipper_External_Export_Item(bpy.types.PropertyGroup): class SCENE_OT_Tree_Clipper_Export_Cache(bpy.types.Operator): bl_idname = "scene.tree_clipper_export_cache" bl_label = "Export Cache" - bl_options = set() + bl_options: ClassVar[set[str]] = set() # ty:ignore[invalid-attribute-override] clipboard_or_file: bpy.props.EnumProperty(items=[(_CLIPBOARD,) * 3, (_FILE,) * 3]) # type: ignore output_file: bpy.props.StringProperty( diff --git a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py index 110c456..8662f8e 100644 --- a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py +++ b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py @@ -1,5 +1,5 @@ import time -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar import bpy @@ -25,7 +25,7 @@ class SCENE_OT_Tree_Clipper_Import_File_Prepare(bpy.types.Operator): bl_idname = "scene.tree_clipper_import_file_prepare" bl_label = "Import File" - bl_options = {"REGISTER"} + bl_options: ClassVar[set[str]] = {"REGISTER"} # ty:ignore[invalid-attribute-override] input_file: bpy.props.StringProperty( name="Input File", @@ -52,7 +52,7 @@ def execute( class SCENE_OT_Tree_Clipper_Import_Clipboard_Prepare(bpy.types.Operator): bl_idname = "scene.tree_clipper_import_clipboard_prepare" bl_label = "Import Clipboard" - bl_options = {"REGISTER"} + bl_options: ClassVar[set[str]] = {"REGISTER"} # ty:ignore[invalid-attribute-override] def execute( self, context: bpy.types.Context @@ -103,7 +103,7 @@ class Tree_Clipper_External_Import_Items(bpy.types.PropertyGroup): class SCENE_OT_Tree_Clipper_Import_Cache(bpy.types.Operator): bl_idname = "scene.tree_clipper_import_cache" bl_label = "Import Cache" - bl_options = set() + bl_options: ClassVar[set[str]] = set() # ty:ignore[invalid-attribute-override] debug_prints: bpy.props.BoolProperty(name="Debug on Console", default=False) # type: ignore @@ -195,7 +195,7 @@ def draw(self, context: bpy.types.Context) -> None: class SCENE_OT_Tree_Clipper_Import_Modal(bpy.types.Operator): bl_idname = "scene.tree_clipper_import_modal" bl_label = "Import Modal" - bl_options = {"UNDO"} + bl_options: ClassVar[set[str]] = {"UNDO"} # ty:ignore[invalid-attribute-override] _timer = None From d95a462b36341fade6424f82c12546d9b21622bf Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:24:38 +0200 Subject: [PATCH 09/19] fix: more ruff fixes --- packages/tree_clipper/src/tree_clipper/export_nodes.py | 4 +--- packages/tree_clipper/tests/conftest.py | 4 ++-- packages/tree_clipper/tests/test_initial.py | 2 +- .../src/tree_clipper_addon/operators_export.py | 2 +- .../src/tree_clipper_addon/operators_import.py | 1 - 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/export_nodes.py b/packages/tree_clipper/src/tree_clipper/export_nodes.py index 87cb2d3..217dbbc 100644 --- a/packages/tree_clipper/src/tree_clipper/export_nodes.py +++ b/packages/tree_clipper/src/tree_clipper/export_nodes.py @@ -310,9 +310,7 @@ def _export_property_collection( items = [ self._export_obj( obj=element, - from_root=from_root.add( - f"[{i}] ({getattr(element, NAME, 'unnamed')})" - ), + from_root=from_root.add(f"[{i}] ({getattr(element, NAME, 'unnamed')})"), ) for i, element in enumerate(attribute) ] diff --git a/packages/tree_clipper/tests/conftest.py b/packages/tree_clipper/tests/conftest.py index c2004dd..5ebda32 100644 --- a/packages/tree_clipper/tests/conftest.py +++ b/packages/tree_clipper/tests/conftest.py @@ -18,9 +18,9 @@ def pytest_generate_tests(metafunc): rna_info.BuildRNAInfo() # we're only interested in the "leaf" types - node_types = set( + node_types = { cls for cls in all_subclasses(bpy.types.Node) if len(all_subclasses(cls)) == 0 - ) + } if metafunc.function == test_all_nodes: metafunc.parametrize("node_type", node_types) diff --git a/packages/tree_clipper/tests/test_initial.py b/packages/tree_clipper/tests/test_initial.py index 9c45143..6ea3bbd 100644 --- a/packages/tree_clipper/tests/test_initial.py +++ b/packages/tree_clipper/tests/test_initial.py @@ -1,2 +1,2 @@ def test_initial(): - assert 1 == 1 + pass diff --git a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py index 99d8aa5..4f62822 100644 --- a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py +++ b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_export.py @@ -171,7 +171,7 @@ def invoke( ) -> set["rna_enums.OperatorReturnItems"]: self.external_items.clear() assert isinstance(_INTERMEDIATE_EXPORT_CACHE, ExportIntermediate) - for external_id in _INTERMEDIATE_EXPORT_CACHE.get_external().keys(): + for external_id in _INTERMEDIATE_EXPORT_CACHE.get_external(): item = self.external_items.add() item.external_id = external_id return context.window_manager.invoke_props_dialog(self, width=300) # ty:ignore[possibly-missing-attribute] diff --git a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py index 8662f8e..feb8f91 100644 --- a/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py +++ b/packages/tree_clipper_addon/src/tree_clipper_addon/operators_import.py @@ -139,7 +139,6 @@ def invoke( def execute( self, context: bpy.types.Context ) -> set["rna_enums.OperatorReturnItems"]: - global _INTERMEDIATE_IMPORT_CACHE assert isinstance(_INTERMEDIATE_IMPORT_CACHE, ImportIntermediate) assert hasattr(context.scene, "tree_clipper_external_import_items") assert isinstance( From f586dbaca378f41989fa17446444d768cb602dde Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:28:34 +0200 Subject: [PATCH 10/19] fix: allow for nested ifs --- pyproject.toml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c19190f..9b929b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,4 +63,9 @@ packages = ["packages/tree_clipper"] name = "testpypi" url = "https://test.pypi.org/simple/" publish-url = "https://test.pypi.org/legacy/" -explicit = true \ No newline at end of file +explicit = true + +[tool.ruff.lint] +ignore = [ + "SIM102" # > Nesting if statements harder to read -- I disagree! +] \ No newline at end of file From c3a4f7891c9ebf238f23096e0d74c56dae631708 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:31:22 +0200 Subject: [PATCH 11/19] fix: f-strings as doc strings --- .../src/tree_clipper/specific_handlers.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/specific_handlers.py b/packages/tree_clipper/src/tree_clipper/specific_handlers.py index 5f09bc1..81e89c0 100644 --- a/packages/tree_clipper/src/tree_clipper/specific_handlers.py +++ b/packages/tree_clipper/src/tree_clipper/specific_handlers.py @@ -1274,14 +1274,14 @@ def deserialize(self): class CurveMapPointExporter(SpecificExporter[bpy.types.CurveMapPoint]): - f"""The container constructs them using the {LOCATION}""" + __doc__ = f"""The container constructs them using the {LOCATION}""" def serialize(self): return self.export_all_simple_writable_properties() class CurveMapPointsImporter(SpecificImporter[bpy.types.CurveMapPoints]): # ty:ignore[invalid-type-arguments] - f"""The {LOCATION} needs to be picked apart into argumets + __doc__ = f"""The {LOCATION} needs to be picked apart into argumets and there are always at least two points. We remove all but two and skip first and last from the serialization.""" @@ -1308,7 +1308,7 @@ def deferred(): class ConvertToDisplayImporter( SpecificImporter[bpy.types.CompositorNodeConvertToDisplay] ): - f"""The properties on this one are special. + __doc__ = f"""The properties on this one are special. The properties of the pointees {DISPLAY_SETTINGS} and {VIEW_SETTINGS} are set implicitly by setting certain enums values. They also have an implicit ordering, first the display needs to be set, then the view.""" @@ -1344,7 +1344,7 @@ def deserialize(self): class EvalClosureInputItemExporter( SpecificExporter[bpy.types.NodeEvaluateClosureInputItem] ): - f"""We need {SOCKET_TYPE} and {NAME}, both are simple & writable""" + __doc__ = f"""We need {SOCKET_TYPE} and {NAME}, both are simple & writable""" def serialize(self): return self.export_all_simple_writable_properties() @@ -1364,7 +1364,7 @@ def deserialize(self): class EvalClosureOutputItemExporter( SpecificExporter[bpy.types.NodeEvaluateClosureOutputItem] ): - f"""We need {SOCKET_TYPE} and {NAME}, both are simple & writable""" + __doc__ = f"""We need {SOCKET_TYPE} and {NAME}, both are simple & writable""" def serialize(self): return self.export_all_simple_writable_properties() @@ -1455,7 +1455,7 @@ def deserialize(self): class RenderLayersExporter(SpecificExporter[bpy.types.CompositorNodeRLayers]): - f"""We skip the {LAYER} if the {SCENE} is not set. + __doc__ = f"""We skip the {LAYER} if the {SCENE} is not set. {LAYER} is an empty string in that case and we can't set that during import.""" def serialize(self): @@ -1654,7 +1654,7 @@ def deserialize(self): class BakeExporter(SpecificExporter[bpy.types.GeometryNodeBake]): - f"""We need to specialize to avoid {ACTIVE_ITEM}, which is broken + __doc__ = f"""We need to specialize to avoid {ACTIVE_ITEM}, which is broken https://projects.blender.org/blender/blender/issues/151276""" def serialize(self): @@ -1688,7 +1688,7 @@ def deserialize(self): class FieldToGridExporter(SpecificExporter[bpy.types.GeometryNodeFieldToGrid]): - f"""We need to specialize to avoid {ACTIVE_ITEM}, which is broken + __doc__ = f"""We need to specialize to avoid {ACTIVE_ITEM}, which is broken https://projects.blender.org/blender/blender/issues/151276""" def serialize(self): From cff715cd9069ae37d2dbc45379748d7173ad0da4 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:45:56 +0200 Subject: [PATCH 12/19] fix: simple ruff fixes --- packages/tree_clipper/src/tree_clipper/common.py | 16 +++++++--------- .../src/tree_clipper/import_nodes.py | 5 ++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/common.py b/packages/tree_clipper/src/tree_clipper/common.py index 441d6fb..a4eef03 100644 --- a/packages/tree_clipper/src/tree_clipper/common.py +++ b/packages/tree_clipper/src/tree_clipper/common.py @@ -47,15 +47,13 @@ PROP_TYPE_ENUM = "ENUM" PROP_TYPE_POINTER = "POINTER" PROP_TYPE_COLLECTION = "COLLECTION" -SIMPLE_PROPERTY_TYPES_AS_STRS = set( - [ - PROP_TYPE_BOOLEAN, - PROP_TYPE_INT, - PROP_TYPE_FLOAT, - PROP_TYPE_STRING, - PROP_TYPE_ENUM, - ] -) +SIMPLE_PROPERTY_TYPES_AS_STRS = { + PROP_TYPE_BOOLEAN, + PROP_TYPE_INT, + PROP_TYPE_FLOAT, + PROP_TYPE_STRING, + PROP_TYPE_ENUM, +} NODE_TREE = "node_tree" DIMENSIONS = "dimensions" diff --git a/packages/tree_clipper/src/tree_clipper/import_nodes.py b/packages/tree_clipper/src/tree_clipper/import_nodes.py index 053e1f4..78b0686 100644 --- a/packages/tree_clipper/src/tree_clipper/import_nodes.py +++ b/packages/tree_clipper/src/tree_clipper/import_nodes.py @@ -183,9 +183,8 @@ def _import_property_simple( return if ( - ( - isinstance(getter(), bpy.types.NodeSocket) - or isinstance(getter(), bpy.types.NodeTreeInterfaceSocket) + isinstance( + getter(), (bpy.types.NodeSocket, bpy.types.NodeTreeInterfaceSocket) ) and prop.type == PROP_TYPE_ENUM and identifier == DEFAULT_VALUE From eb5910b64dc5710e41f86dfb9f8fa820a700d3dc Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:46:32 +0200 Subject: [PATCH 13/19] fix: switch to preferable generics --- .../tree_clipper/src/tree_clipper/specific_abstract.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/specific_abstract.py b/packages/tree_clipper/src/tree_clipper/specific_abstract.py index 0a2f5eb..3dbc731 100644 --- a/packages/tree_clipper/src/tree_clipper/specific_abstract.py +++ b/packages/tree_clipper/src/tree_clipper/specific_abstract.py @@ -3,7 +3,7 @@ from abc import ABC, abstractmethod from collections.abc import Callable from types import NoneType -from typing import Any, ClassVar, Generic, TypeVar +from typing import Any, ClassVar, TypeVar import bpy @@ -14,9 +14,9 @@ AssumedType = TypeVar("AssumedType", bound=bpy.types.bpy_struct) -def default_serializer( +def default_serializer[T]( _exporter: Exporter, - _obj: AssumedType, + _obj: T, _from_root: FromRoot, ) -> dict[str, Any]: return {} @@ -40,7 +40,7 @@ def default_deserializer( } -class SpecificExporter(Generic[AssumedType], ABC): +class SpecificExporter[AssumedType](ABC): """Helper class for specific exporting. One can also just define functions but this is more convenient. @@ -164,7 +164,7 @@ def serialize(self) -> dict[str, Any]: """Do the actual exporting here""" -class SpecificImporter(Generic[AssumedType], ABC): +class SpecificImporter[AssumedType](ABC): """Helper class for specific importing. One can also just define functions but this is more convenient. From 94c2cf9d12f7170298aff0a9671d22efe5001a81 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:47:05 +0200 Subject: [PATCH 14/19] fix: mutable default arg This could be a bad bug! --- packages/tree_clipper/src/tree_clipper/specific_abstract.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/tree_clipper/src/tree_clipper/specific_abstract.py b/packages/tree_clipper/src/tree_clipper/specific_abstract.py index 3dbc731..32e9bb7 100644 --- a/packages/tree_clipper/src/tree_clipper/specific_abstract.py +++ b/packages/tree_clipper/src/tree_clipper/specific_abstract.py @@ -253,7 +253,9 @@ def __init__( self.serialization = serialization self.from_root = from_root - def import_all_simple_writable_properties(self, forbidden: list[str] = []): + def import_all_simple_writable_properties(self, forbidden: list[str] | None = None): + if forbidden is None: + forbidden = [] self.importer.import_all_simple_writable_properties( getter=self.getter, serialization=self.serialization, From 95e42fc967fc8146bab48adc41d51cd1b57477de Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:47:36 +0200 Subject: [PATCH 15/19] fix: loop argument --- packages/tree_clipper/src/tree_clipper/specific_abstract.py | 5 ++++- packages/tree_clipper/src/tree_clipper/specific_handlers.py | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/specific_abstract.py b/packages/tree_clipper/src/tree_clipper/specific_abstract.py index 32e9bb7..b363e4b 100644 --- a/packages/tree_clipper/src/tree_clipper/specific_abstract.py +++ b/packages/tree_clipper/src/tree_clipper/specific_abstract.py @@ -277,9 +277,12 @@ def import_all_simple_writable_properties_and_list(self, id_list: list[str]): self.import_properties_from_id_list(id_list) def only_create_getters(self, id_list: list[str]): + def create_getter(identifier): + return lambda: getattr(self.getter(), identifier) + for identifier in id_list: self.register_getter( - getter=lambda: getattr(self.getter(), identifier), + getter=create_getter(identifier), serialization=self.serialization[identifier], from_root=self.from_root.add_prop( self.getter().bl_rna.properties[identifier] diff --git a/packages/tree_clipper/src/tree_clipper/specific_handlers.py b/packages/tree_clipper/src/tree_clipper/specific_handlers.py index 81e89c0..8281a49 100644 --- a/packages/tree_clipper/src/tree_clipper/specific_handlers.py +++ b/packages/tree_clipper/src/tree_clipper/specific_handlers.py @@ -302,7 +302,7 @@ def get_type(data: dict): name = _or_default(data, ty, NAME) description = _or_default(data, ty, DESCRIPTION) - def get_parent() -> None | bpy.types.NodeTreeInterfacePanel: + def get_parent(data) -> None | bpy.types.NodeTreeInterfacePanel: if PARENT_INDEX in data: parent_index = data[PARENT_INDEX] assert parent_index < len(self.getter().items_tree) @@ -322,7 +322,7 @@ def get_parent() -> None | bpy.types.NodeTreeInterfacePanel: description=description, in_out=_or_default(data, ty, "in_out"), socket_type=data[SOCKET_TYPE], - parent=get_parent(), + parent=get_parent(data), ) if isinstance(new_item, bpy.types.NodeTreeInterfaceSocketBool): new_item.is_panel_toggle = data[IS_PANEL_TOGGLE] @@ -334,7 +334,7 @@ def get_parent() -> None | bpy.types.NodeTreeInterfacePanel: description=description, default_closed=_or_default(data, ty, DEFAULT_CLOSED), ) - parent = get_parent() + parent = get_parent(data) if parent is not None: self.getter().move_to_parent( item=new_item, From da5e3af3877df6be23f42210b5bbd26ead33600b Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:47:49 +0200 Subject: [PATCH 16/19] fix: import bpy before rna info --- packages/tree_clipper/tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tree_clipper/tests/conftest.py b/packages/tree_clipper/tests/conftest.py index 5ebda32..23d0b94 100644 --- a/packages/tree_clipper/tests/conftest.py +++ b/packages/tree_clipper/tests/conftest.py @@ -1,5 +1,5 @@ -import _rna_info as rna_info import bpy +import _rna_info as rna_info import pytest from .test_all_nodes import test_all_nodes From 712f81e8aec66ebdc1e04f4ebd3a4a580a6247de Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 12:48:18 +0200 Subject: [PATCH 17/19] chore: update uv.lock --- uv.lock | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/uv.lock b/uv.lock index 531ab92..93054a0 100644 --- a/uv.lock +++ b/uv.lock @@ -2,9 +2,6 @@ version = 1 revision = 3 requires-python = "==3.13.*" -[options] -prerelease-mode = "allow" - [manifest] members = [ "tree-clipper", @@ -254,27 +251,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.2" +version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/94/1e5e4967626faf12fa56999cd6222dff6992ceb086ad7945756baf70c7a7/ruff-0.16.0.tar.gz", hash = "sha256:e460aafd5495ec89efaa6ced2e4a9a581116451e1c88b9d37ef497e0f8e93982", size = 4790557, upload-time = "2026-07-23T19:11:30.981Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, - { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, - { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, - { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, - { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, - { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, - { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, - { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, - { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, + { url = "https://files.pythonhosted.org/packages/4b/81/1c8818fee7ce1a04cd7d1b3172e0a8f8e4f1dc4feb7fc390e16daa8af323/ruff-0.16.0-py3-none-linux_armv6l.whl", hash = "sha256:e5115729eb08c585e5121978ba5d5b60caeae394ce21b9fb5e6cd33a1c6c9b1e", size = 10754633, upload-time = "2026-07-23T19:10:46.415Z" }, + { url = "https://files.pythonhosted.org/packages/23/df/beaf59c09d68db84304d555f188b276a77132a5d5b0b67a5c762aa143628/ruff-0.16.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3c954b1d580bfa035b41654f7858cc7e71d5fc3ac5b723dd62bd9133830ed522", size = 10969164, upload-time = "2026-07-23T19:10:50.271Z" }, + { url = "https://files.pythonhosted.org/packages/42/ce/741cd197496a1abbf51352710fd15ed995d2a2be87189c1da26a450d6e83/ruff-0.16.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e01c21d10eb1b29f47b7454e1f4056db9a3f0260c646aa88457c610291db9f81", size = 10488846, upload-time = "2026-07-23T19:10:52.639Z" }, + { url = "https://files.pythonhosted.org/packages/52/2a/a2db8e88cade358f5cdcb05674a917751074109315d014eb6352d9a893f7/ruff-0.16.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e364e5ed22ed8dc05082fd78e35308618260907ac2d3c1d637b2e682415b6c9", size = 10889729, upload-time = "2026-07-23T19:10:54.89Z" }, + { url = "https://files.pythonhosted.org/packages/42/65/62a771694ebd63029dc953e27dbad40e1588bd4860ff9fe881018fddaa49/ruff-0.16.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d327b8fc113a1d4421a04f3839d3752057c8dd1ee320223a6f3f52d04ada462a", size = 10568275, upload-time = "2026-07-23T19:10:56.993Z" }, + { url = "https://files.pythonhosted.org/packages/3f/e2/ced249fe8af5f086c5c58cc21cc3356d50f32f7401c5df87050c999620a7/ruff-0.16.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b50c55e263103586b3dcf5f73d479eb8cb5fdb6098fec59a62891dab653717", size = 11385112, upload-time = "2026-07-23T19:10:59.615Z" }, + { url = "https://files.pythonhosted.org/packages/87/0b/05154977a8fd69eeb6c103271f55403bfd8711f5c0f8ed07489d95a504e7/ruff-0.16.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ff4a79ce3ec0172f3241943835de1c4cb4e2dcd07f0f8c2d02603dbbbee4b17", size = 12207008, upload-time = "2026-07-23T19:11:02.154Z" }, + { url = "https://files.pythonhosted.org/packages/fb/29/98225831a3a1eab0e02f4acc6ca6559a98611dcc68b6965ff4b7234627c1/ruff-0.16.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e95c448fca1fb2a18372a9440926c5a6ee789639bb975c72e7ae6d0b04218ab4", size = 11650842, upload-time = "2026-07-23T19:11:04.557Z" }, + { url = "https://files.pythonhosted.org/packages/91/66/6bd3cf90500653d55dc0ffc8507aa8300bd49d0214b2e8cb4d3fef2943ba/ruff-0.16.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f11a8d11010301d0a398a2fdef67691feca7294da6aef55e2150e8fa2cd520b", size = 11400718, upload-time = "2026-07-23T19:11:09.233Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a2/a54eb4eae05d66364050a5d3b8a9c5ef88196531b3cbe7109d873f87f819/ruff-0.16.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:48044c678e9cb8698246c99b14aaccfa6601dea7379eb48a6f8f73f7a6d86cd0", size = 11426177, upload-time = "2026-07-23T19:11:11.994Z" }, + { url = "https://files.pythonhosted.org/packages/1a/be/16e3eea4b2a478a496919f5e36f17c4559e54620bd3bbac5d6affa068006/ruff-0.16.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7aa0959bad8eb8bef50340154fc9b58678dae31fa4293afa38b44b6e552c0213", size = 10856126, upload-time = "2026-07-23T19:11:14.221Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/252eb8b868a16eec7257c14f504f77537e734b2d69c762e639e588e304a3/ruff-0.16.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28ea2b7df8ebf7f9da6b7d47b230ab48f387c0a29be3b474c4d0740e197bb9af", size = 10571208, upload-time = "2026-07-23T19:11:16.378Z" }, + { url = "https://files.pythonhosted.org/packages/21/09/817a482f542f7570cbb4554b26e896610c7114f539b1d9e2d2145bf6bef6/ruff-0.16.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:33a3dfac8c35f81498dea9181bccc2f4c4bc8f1521a1dd9406e77643e0f0fb09", size = 11063329, upload-time = "2026-07-23T19:11:19.173Z" }, + { url = "https://files.pythonhosted.org/packages/2e/23/9403c180ca1cb9b1f7335f5c3e5305c09d49ea5b345196682a36028bde4a/ruff-0.16.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a5237a0bda500d30d81b8e07a6973a5cbc772864cbf746ae2f4e8a2e01c9f4ed", size = 11489751, upload-time = "2026-07-23T19:11:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/b2/1d/1b2ef7bcde851c78d7f17f1cca13fd6dc695fc4b3d6197941e72cae5b132/ruff-0.16.0-py3-none-win32.whl", hash = "sha256:7fab76fa065c873f41ff744347c6e77bcc3dfec4bcc754dc26b63d23c0f7f5fb", size = 10785885, upload-time = "2026-07-23T19:11:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a3/d5e4ef7a56be3f928ffb90b94c25ba7d3cb9c7fe0736aeaaedf361770712/ruff-0.16.0-py3-none-win_amd64.whl", hash = "sha256:429c117f022bf481fabd9d551e7a3952b24c65e6ef44337ea09d90bebef14472", size = 11923141, upload-time = "2026-07-23T19:11:26.409Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9a/8415f2657cbe200f41a4531ccededf135505a92d4a012229121f885b26f9/ruff-0.16.0-py3-none-win_arm64.whl", hash = "sha256:14296fedcd2705c77ab8235439278bbb38f285cf7da5528b00b3e330c3d4872d", size = 11273407, upload-time = "2026-07-23T19:11:28.705Z" }, ] [[package]] @@ -353,7 +350,7 @@ dev = [ { name = "fake-bpy-module", specifier = ">=20251003" }, { name = "pip", specifier = ">=25.3" }, { name = "pytest", specifier = ">=9.0.1" }, - { name = "ruff", specifier = ">=0.14.10" }, + { name = "ruff", specifier = ">=0.16.0" }, { name = "ty", specifier = ">=0.0.3" }, { name = "vendorize", git = "https://github.com/Vollkornaffe/python-vendorize.git?rev=f284834c558483542ba0886f992ae2b918c22ab3" }, ] From 66edf429fc1c5e408a3050cac278b1ab99e8dc07 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 13:09:29 +0200 Subject: [PATCH 18/19] fix: allow 'unordered' imports for conftest --- packages/tree_clipper/tests/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/tree_clipper/tests/conftest.py b/packages/tree_clipper/tests/conftest.py index 23d0b94..d8afdeb 100644 --- a/packages/tree_clipper/tests/conftest.py +++ b/packages/tree_clipper/tests/conftest.py @@ -1,5 +1,6 @@ -import bpy +import bpy # noqa: I001 import _rna_info as rna_info + import pytest from .test_all_nodes import test_all_nodes From ebb60fbb1ac959afef3e4e0164f6829d06d2e3f2 Mon Sep 17 00:00:00 2001 From: Vollkornaffe Date: Tue, 28 Jul 2026 13:10:47 +0200 Subject: [PATCH 19/19] fix: fmt --- packages/tree_clipper/src/tree_clipper/dynamic_pointer.py | 1 - packages/tree_clipper/tests/test_all_nodes.py | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py index 8daabf9..ec828fe 100644 --- a/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py +++ b/packages/tree_clipper/src/tree_clipper/dynamic_pointer.py @@ -1,4 +1,3 @@ - import bpy from .common import no_clobber diff --git a/packages/tree_clipper/tests/test_all_nodes.py b/packages/tree_clipper/tests/test_all_nodes.py index 69846e1..ee897d7 100644 --- a/packages/tree_clipper/tests/test_all_nodes.py +++ b/packages/tree_clipper/tests/test_all_nodes.py @@ -1,4 +1,3 @@ - import bpy from .util import make_test_node_tree, round_trip, save_failed