diff --git a/molecularnodes/blender/__init__.py b/molecularnodes/blender/__init__.py index 94a1d5c5..a9e8ba98 100644 --- a/molecularnodes/blender/__init__.py +++ b/molecularnodes/blender/__init__.py @@ -1,19 +1 @@ -from pathlib import Path -from typing import Union -import bpy - - -def path_resolve(path: Union[str, Path]) -> Path: - if isinstance(path, str): - return Path(bpy.path.abspath(path)) - elif isinstance(path, Path): - return Path(bpy.path.abspath(str(path))) - else: - raise ValueError(f"Unable to resolve path: {path}") - - -def active_object(context: bpy.types.Context = None) -> bpy.types.Object: - if context is None: - return bpy.context.active_object - - return context.active_object +from .utils import path_resolve diff --git a/molecularnodes/blender/databpy/__init__.py b/molecularnodes/blender/bpyd/__init__.py similarity index 100% rename from molecularnodes/blender/databpy/__init__.py rename to molecularnodes/blender/bpyd/__init__.py diff --git a/molecularnodes/blender/databpy/attribute.py b/molecularnodes/blender/bpyd/attribute.py similarity index 91% rename from molecularnodes/blender/databpy/attribute.py rename to molecularnodes/blender/bpyd/attribute.py index c9a93fe1..41de672a 100644 --- a/molecularnodes/blender/databpy/attribute.py +++ b/molecularnodes/blender/bpyd/attribute.py @@ -1,11 +1,26 @@ from dataclasses import dataclass from enum import Enum from typing import Type -from .utils import evaluate_object - import bpy import numpy as np +from pathlib import Path + + +def evaluate_object(obj: bpy.types.Object): + "Return an object which has the modifiers evaluated." + obj.update_tag() + return obj.evaluated_get(bpy.context.evaluated_depsgraph_get()) + + +def path_resolve(path: str | Path) -> Path: + if isinstance(path, str): + return Path(bpy.path.abspath(path)) + elif isinstance(path, Path): + return Path(bpy.path.abspath(str(path))) + else: + raise ValueError(f"Unable to resolve path: {path}") + @dataclass class AttributeTypeInfo: @@ -161,6 +176,21 @@ def dtype(self) -> Type: def n_values(self) -> int: return np.prod(self.shape, dtype=int) + @classmethod + def from_object( + cls, + obj: bpy.types.Object, + name: str, + atype: AttributeType, + domain: DomainType, + ): + att = obj.data.get(name) + if att is None: + att = obj.data.attributes.new( + name=name, type=atype.value.type_name, domain=domain.value.name + ) + return Attribute(att) + def from_array(self, array: np.ndarray) -> None: """ Set the attribute data from a numpy array @@ -250,7 +280,7 @@ def store_named_attribute( ) # the 'foreach_set' requires a 1D array, regardless of the shape of the attribute - # it also requires the order to be 'c' or blender might crash!! + # so we have to flatten it first attribute.data.foreach_set(atype.value.value_name, data.reshape(-1)) # The updating of data doesn't work 100% of the time (see: diff --git a/molecularnodes/blender/databpy/object.py b/molecularnodes/blender/bpyd/object.py similarity index 81% rename from molecularnodes/blender/databpy/object.py rename to molecularnodes/blender/bpyd/object.py index 94e0569d..36e88876 100644 --- a/molecularnodes/blender/databpy/object.py +++ b/molecularnodes/blender/bpyd/object.py @@ -1,7 +1,8 @@ import bpy import numpy as np -from typing import Union, Optional +from typing import Optional from .attribute import ( + evaluate_object, AttributeTypes, AttributeType, Domains, @@ -124,25 +125,22 @@ def create_object( return obj +def active_object(context: bpy.types.Context = None) -> bpy.types.Object: + if context is None: + return bpy.context.active_object + + return context.active_object + + class BlenderObject: """ A convenience class for working with Blender objects """ - def __init__(self, object: bpy.types.Object | None): - self._object = object - - def store_named_attribute( - self, - data: np.ndarray, - name: str, - atype: str | AttributeType | None = None, - domain: str | DomainType = Domains.POINT, - ) -> None: - attribute.store_named_attribute( - self.object, data=data, name=name, atype=atype, domain=domain - ) - return self + def __init__(self, obj: bpy.types.Object | None): + if not isinstance(obj, bpy.types.Object): + raise ValueError(f"{obj} must be a Blender object of type bpy.types.Object") + self._object = obj @property def object(self) -> bpy.types.Object: @@ -157,6 +155,39 @@ def object(self) -> bpy.types.Object: def object(self, value: bpy.types.Object) -> None: self._object = value + def store_named_attribute( + self, + data: np.ndarray, + name: str, + atype: str | AttributeType | None = None, + domain: str | DomainType = Domains.POINT, + ) -> None: + """ + Parameters + ---------- + data : np.ndarray + The data to be stored as an attribute. + name : str + The name for the attribute. Will overwrite an already existing attribute. + atype : str or AttributeType or None, optional + The attribute type to store the data as. Either string or selection from the + AttributeTypes enum. None will attempt to infer the attribute type from the + input array. + domain : str or DomainType, optional + The domain to store the attribute on. Defaults to Domains.POINT. + + Returns + ------- + self + """ + attribute.store_named_attribute( + self.object, data=data, name=name, atype=atype, domain=domain + ) + return self + + def evaluate(self): + return BlenderObject(evaluate_object(self.object)) + def named_attribute(self, name: str, evaluate: bool = False) -> np.ndarray: return attribute.named_attribute(self.object, name=name, evaluate=evaluate) @@ -203,3 +234,6 @@ def selected_positions(self, mask: Optional[np.ndarray] = None) -> np.ndarray: return self.position[np.logical_and(self.selected, mask)] return self.position[self.selected] + + def __len__(self) -> int: + return len(self.object.data.vertices) diff --git a/molecularnodes/blender/databpy/utils.py b/molecularnodes/blender/databpy/utils.py deleted file mode 100644 index 5b969c2d..00000000 --- a/molecularnodes/blender/databpy/utils.py +++ /dev/null @@ -1,7 +0,0 @@ -import bpy - - -def evaluate_object(obj: bpy.types.Object): - "Return an object which has the modifiers evaluated." - obj.update_tag() - return obj.evaluated_get(bpy.context.evaluated_depsgraph_get()) diff --git a/molecularnodes/blender/mesh.py b/molecularnodes/blender/mesh.py index 6059fc7c..d3aa47a1 100644 --- a/molecularnodes/blender/mesh.py +++ b/molecularnodes/blender/mesh.py @@ -1,19 +1,9 @@ -from typing import Optional - import bpy import numpy as np from . import coll, nodes -from .databpy.attribute import ( - Attribute, - AttributeMismatchError, - AttributeTypes, - guess_atype_from_array, - store_named_attribute, - named_attribute, -) -from .databpy.object import ObjectTracker, create_object -from .databpy.utils import evaluate_object +from .bpyd.attribute import AttributeTypes, evaluate_object +from .bpyd.object import ObjectTracker, create_object, BlenderObject def centre(position: np.ndarray): @@ -95,7 +85,7 @@ def create_data_object(array, collection=None, name="DataObject", world_scale=0. if not collection: collection = coll.data() - obj = create_object(locations, collection=collection, name=name) + bob = BlenderObject(create_object(locations, collection=collection, name=name)) attributes = [ ("rotation", AttributeTypes.QUATERNION), @@ -114,6 +104,6 @@ def create_data_object(array, collection=None, name="DataObject", world_scale=0. if np.issubdtype(data.dtype, str): data = np.unique(data, return_inverse=True)[1] - store_named_attribute(obj=obj, data=data, name=column, atype=type) + bob.store_named_attribute(data=data, name=column, atype=type) - return obj + return bob.object diff --git a/molecularnodes/blender/nodes.py b/molecularnodes/blender/nodes.py index 60ad89dd..00dc1148 100644 --- a/molecularnodes/blender/nodes.py +++ b/molecularnodes/blender/nodes.py @@ -13,6 +13,7 @@ from .. import color, utils from . import mesh +from . import bpyd import re NODE_WIDTH = 180 @@ -725,7 +726,7 @@ def create_assembly_node_tree( "name": "assembly_id", "type": "NodeSocketInt", "min": 1, - "max": max(mesh.named_attribute(data_object, "assembly_id")), + "max": max(bpyd.named_attribute(data_object, "assembly_id")), "default": 1, }, ) diff --git a/molecularnodes/blender/utils.py b/molecularnodes/blender/utils.py new file mode 100644 index 00000000..99dd22c4 --- /dev/null +++ b/molecularnodes/blender/utils.py @@ -0,0 +1,11 @@ +import bpy +from pathlib import Path + + +def path_resolve(path: str | Path) -> Path: + if isinstance(path, str): + return Path(bpy.path.abspath(path)) + elif isinstance(path, Path): + return Path(bpy.path.abspath(str(path))) + else: + raise ValueError(f"Unable to resolve path: {path}") diff --git a/molecularnodes/blender_manifest.toml b/molecularnodes/blender_manifest.toml index 61ae37dc..7d6751bf 100644 --- a/molecularnodes/blender_manifest.toml +++ b/molecularnodes/blender_manifest.toml @@ -35,17 +35,16 @@ wheels = [ "./wheels/biotite-0.41.2-cp311-cp311-macosx_11_0_arm64.whl", "./wheels/biotite-0.41.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "./wheels/biotite-0.41.2-cp311-cp311-win_amd64.whl", - "./wheels/colorama-0.4.6-py2.py3-none-any.whl", "./wheels/contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", "./wheels/contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", "./wheels/contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "./wheels/contourpy-1.3.0-cp311-cp311-win_amd64.whl", "./wheels/cycler-0.12.1-py3-none-any.whl", "./wheels/fasteners-0.19-py3-none-any.whl", - "./wheels/fonttools-4.54.0-cp311-cp311-macosx_10_9_universal2.whl", - "./wheels/fonttools-4.54.0-cp311-cp311-macosx_11_0_arm64.whl", - "./wheels/fonttools-4.54.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "./wheels/fonttools-4.54.0-cp311-cp311-win_amd64.whl", + "./wheels/fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl", + "./wheels/fonttools-4.54.1-cp311-cp311-macosx_11_0_arm64.whl", + "./wheels/fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "./wheels/fonttools-4.54.1-cp311-cp311-win_amd64.whl", "./wheels/joblib-1.4.2-py3-none-any.whl", "./wheels/kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", "./wheels/kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", @@ -62,17 +61,17 @@ wheels = [ "./wheels/msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", "./wheels/msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "./wheels/msgpack-1.1.0-cp311-cp311-win_amd64.whl", - "./wheels/networkx-3.3-py3-none-any.whl", + "./wheels/networkx-3.4.2-py3-none-any.whl", "./wheels/packaging-24.1-py3-none-any.whl", "./wheels/pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", "./wheels/pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", "./wheels/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", "./wheels/pandas-2.2.3-cp311-cp311-win_amd64.whl", - "./wheels/pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", - "./wheels/pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", - "./wheels/pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "./wheels/pillow-10.4.0-cp311-cp311-win_amd64.whl", - "./wheels/pyparsing-3.1.4-py3-none-any.whl", + "./wheels/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", + "./wheels/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", + "./wheels/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "./wheels/pillow-11.0.0-cp311-cp311-win_amd64.whl", + "./wheels/pyparsing-3.2.0-py3-none-any.whl", "./wheels/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", "./wheels/pytz-2024.2-py2.py3-none-any.whl", "./wheels/scipy-1.14.1-cp311-cp311-macosx_10_13_x86_64.whl", @@ -82,7 +81,7 @@ wheels = [ "./wheels/six-1.16.0-py2.py3-none-any.whl", "./wheels/starfile-0.5.6-py3-none-any.whl", "./wheels/threadpoolctl-3.5.0-py3-none-any.whl", - "./wheels/tqdm-4.66.5-py3-none-any.whl", + "./wheels/tqdm-4.66.6-py3-none-any.whl", "./wheels/typing_extensions-4.12.2-py3-none-any.whl", "./wheels/tzdata-2024.2-py2.py3-none-any.whl", ] diff --git a/molecularnodes/entities/ensemble/cellpack.py b/molecularnodes/entities/ensemble/cellpack.py index 32bd7a11..dc274099 100644 --- a/molecularnodes/entities/ensemble/cellpack.py +++ b/molecularnodes/entities/ensemble/cellpack.py @@ -8,7 +8,7 @@ from .cif import OldCIF from ..molecule import molecule from ... import blender as bl -from ...blender.databpy import store_named_attribute, AttributeTypes +from ...blender.bpyd import store_named_attribute, AttributeTypes from ... import color diff --git a/molecularnodes/entities/ensemble/star.py b/molecularnodes/entities/ensemble/star.py index f546efc6..75e694ff 100644 --- a/molecularnodes/entities/ensemble/star.py +++ b/molecularnodes/entities/ensemble/star.py @@ -7,7 +7,7 @@ from PIL import Image from ... import blender as bl -from ...blender.databpy import AttributeTypes, store_named_attribute, BlenderObject +from ...blender.bpyd import AttributeTypes, store_named_attribute, BlenderObject from .ensemble import Ensemble diff --git a/molecularnodes/entities/entity.py b/molecularnodes/entities/entity.py index 0464c6e3..bb6ec38e 100644 --- a/molecularnodes/entities/entity.py +++ b/molecularnodes/entities/entity.py @@ -2,7 +2,7 @@ import bpy from uuid import uuid1 from .. import blender as bl -from ..blender.databpy import ( +from ..blender.bpyd import ( AttributeTypes, BlenderObject, ) diff --git a/molecularnodes/entities/molecule/molecule.py b/molecularnodes/entities/molecule/molecule.py index 7b03a7aa..b9229edd 100644 --- a/molecularnodes/entities/molecule/molecule.py +++ b/molecularnodes/entities/molecule/molecule.py @@ -13,7 +13,7 @@ from ... import blender as bl from ... import color, data, utils -from ...blender.databpy import Domains, AttributeTypes, BlenderObject +from ...blender.bpyd import Domains, AttributeTypes, BlenderObject from ..entity import MolecularEntity diff --git a/molecularnodes/entities/trajectory/dna.py b/molecularnodes/entities/trajectory/dna.py index e5873f71..36f5f56b 100644 --- a/molecularnodes/entities/trajectory/dna.py +++ b/molecularnodes/entities/trajectory/dna.py @@ -2,7 +2,7 @@ import bpy from ... import color from ...blender import mesh, coll, nodes -from ...blender.databpy import store_named_attribute, AttributeTypes +from ...blender.bpyd import store_named_attribute, AttributeTypes bpy.types.Scene.MN_import_oxdna_topology = bpy.props.StringProperty( name="Toplogy", diff --git a/molecularnodes/entities/trajectory/trajectory.py b/molecularnodes/entities/trajectory/trajectory.py index 21603326..4169c52b 100644 --- a/molecularnodes/entities/trajectory/trajectory.py +++ b/molecularnodes/entities/trajectory/trajectory.py @@ -8,7 +8,7 @@ from ... import data from ..entity import MolecularEntity from ...blender import coll, mesh, nodes, path_resolve -from ...blender import databpy as db +from ...blender import bpyd as db from ...utils import lerp, correct_periodic_positions from .selections import Selection, TrajectorySelectionItem diff --git a/molecularnodes/load.py b/molecularnodes/load.py deleted file mode 100644 index e69de29b..00000000 diff --git a/molecularnodes/logger.py b/molecularnodes/logger.py deleted file mode 100644 index 06bae942..00000000 --- a/molecularnodes/logger.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -import logging -from .utils import ADDON_DIR - - -def start_logging(logfile_name: str = "side-packages-install") -> logging.Logger: - """ - Configure and start logging to a file. - - Parameters - ---------- - logfile_name : str, optional - The name of the log file. Defaults to 'side-packages-install'. - - Returns - ------- - logging.Logger - A Logger object that can be used to write log messages. - - This function sets up a logging configuration with a specified log file name and logging level. - The log file will be created in the `ADDON_DIR/logs` directory. If the directory - does not exist, it will be created. The function returns a Logger object that can be used to - write log messages. - - """ - # Create the logs directory if it doesn't exist - logs_dir = os.path.join(os.path.abspath(ADDON_DIR), "logs") - os.makedirs(logs_dir, exist_ok=True) - - # Set up logging configuration - logfile_path = os.path.join(logs_dir, f"{logfile_name}.log") - logging.basicConfig(filename=logfile_path, level=logging.INFO) - - # Return logger object - return logging.getLogger() diff --git a/tests/test_density.py b/tests/test_density.py index 6e470dc5..20b4c6dd 100644 --- a/tests/test_density.py +++ b/tests/test_density.py @@ -29,7 +29,7 @@ def density_file(): def test_density_load(density_file): obj = mn.entities.density.load(density_file).object evaluated = mn.blender.mesh.evaluate_using_mesh(obj) - pos = mn.blender.mesh.named_attribute(evaluated, "position") + pos = mn.blender.bpyd.named_attribute(evaluated, "position") assert len(pos) > 1000 @@ -50,7 +50,7 @@ def test_density_centered(density_file): obj = mn.entities.density.load(density_file, center=True, overwrite=True).object evaluated = mn.blender.mesh.evaluate_using_mesh(obj) - pos = mn.blender.mesh.named_attribute(evaluated, "position") + pos = mn.blender.bpyd.named_attribute(evaluated, "position") assert len(pos) > 1000 @@ -69,7 +69,7 @@ def test_density_invert(density_file): style_node.inputs["Threshold"].default_value = 0.01 evaluated = mn.blender.mesh.evaluate_using_mesh(obj) - pos = mn.blender.mesh.named_attribute(evaluated, "position") + pos = mn.blender.bpyd.named_attribute(evaluated, "position") # At this threshold after inverting we should have a cube the size of the volume assert pos[:, 0].max() > 2.0 assert pos[:, 1].max() > 2.0 diff --git a/tests/test_load.py b/tests/test_load.py index 8e17d178..c4afd7fc 100644 --- a/tests/test_load.py +++ b/tests/test_load.py @@ -64,7 +64,7 @@ def test_download_format(code, format): mol2 = o def verts(object): - return mn.blender.mesh.named_attribute(object, "position") + return mn.blender.bpyd.named_attribute(object, "position") assert np.isclose(verts(mol), verts(mol2)).all() diff --git a/tests/test_nodes.py b/tests/test_nodes.py index 6bf0f61b..3b8b559d 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -266,7 +266,7 @@ def test_node_topology(snapshot_custom: NumpySnapshotExtension, code, node_name) group.links.new(output, input) - assert snapshot_custom == mn.blender.mesh.named_attribute( + assert snapshot_custom == mn.blender.bpyd.named_attribute( mol.object, "test_attribute", evaluate=True ) diff --git a/tests/test_obj.py b/tests/test_obj.py index 261b5f3a..d0379a1c 100644 --- a/tests/test_obj.py +++ b/tests/test_obj.py @@ -1,8 +1,7 @@ -import bpy import numpy as np import molecularnodes as mn from molecularnodes.blender import mesh -from molecularnodes.blender import databpy as db +from molecularnodes.blender import bpyd from .constants import data_dir mn.register() @@ -14,7 +13,7 @@ def test_creat_obj(): locations = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0]] bonds = [(0, 1), (1, 2), (2, 0)] name = "MyMesh" - my_object = db.create_object(locations, bonds, name=name) + my_object = bpyd.create_object(locations, bonds, name=name) assert len(my_object.data.vertices) == 3 assert my_object.name == name @@ -37,25 +36,25 @@ def test_set_position(): def test_eval_mesh(): - a = db.create_object(np.zeros((3, 3))) + a = bpyd.create_object(np.zeros((3, 3))) assert len(a.data.vertices) == 3 - b = db.create_object(np.zeros((5, 3))) + b = bpyd.create_object(np.zeros((5, 3))) assert len(b.data.vertices) == 5 assert len(mesh.evaluate_using_mesh(b).data.vertices) == 5 def test_matrix_read_write(): - obj = db.create_object(np.zeros((5, 3))) + obj = bpyd.create_object(np.zeros((5, 3))) arr = np.array((5, 4, 4), float) arr = np.random.rand(5, 4, 4) - db.store_named_attribute( - obj=obj, data=arr, name="test_matrix", atype=db.AttributeTypes.FLOAT4X4 + bpyd.store_named_attribute( + obj=obj, data=arr, name="test_matrix", atype=bpyd.AttributeTypes.FLOAT4X4 ) - assert np.allclose(mesh.named_attribute(obj, "test_matrix"), arr) + assert np.allclose(bpyd.named_attribute(obj, "test_matrix"), arr) arr2 = np.random.rand(5, 4, 4) - db.store_named_attribute(obj=obj, data=arr2, name="test_matrix2") + bpyd.store_named_attribute(obj=obj, data=arr2, name="test_matrix2") - assert not np.allclose(mesh.named_attribute(obj, "test_matrix2"), arr) + assert not np.allclose(bpyd.named_attribute(obj, "test_matrix2"), arr) diff --git a/tests/test_ops.py b/tests/test_ops.py index ed59ab3e..763c4d39 100644 --- a/tests/test_ops.py +++ b/tests/test_ops.py @@ -3,7 +3,7 @@ import numpy as np import molecularnodes as mn -from molecularnodes.blender.databpy import ObjectTracker, named_attribute +from molecularnodes.blender.bpyd import ObjectTracker, named_attribute from .utils import sample_attribute, NumpySnapshotExtension from .constants import data_dir, codes, attributes diff --git a/tests/test_select.py b/tests/test_select.py index 467b6d41..c896d295 100644 --- a/tests/test_select.py +++ b/tests/test_select.py @@ -1,6 +1,6 @@ import molecularnodes as mn +from molecularnodes.blender import bpyd from molecularnodes.blender import nodes -import bpy import numpy as np import pytest @@ -11,8 +11,6 @@ def create_debug_group(name="MolecularNodesDebugGroup"): group.links.new(info.outputs["Geometry"], group.nodes["Group Output"].inputs[0]) return group - return object.evaluated_get(dg) - custom_selections = [ ("1, 3, 5-7", np.array((1, 3, 5, 6, 7))), @@ -24,14 +22,13 @@ def create_debug_group(name="MolecularNodesDebugGroup"): @pytest.mark.parametrize("selection", custom_selections) def test_select_multiple_residues(selection): n_atoms = 100 - object = mn.blender.mesh.create_object(np.zeros((n_atoms, 3))) - mn.blender.mesh.store_named_attribute( - obj=object, + bob = bpyd.BlenderObject(bpyd.create_object(np.zeros((n_atoms, 3)))) + bob.store_named_attribute( data=np.arange(n_atoms) + 1, name="res_id", ) - mod = nodes.get_mod(object) + mod = nodes.get_mod(bob.object) group = nodes.new_group(fallback=False) mod.node_group = group sep = group.nodes.new("GeometryNodeSeparateGeometry") @@ -41,9 +38,6 @@ def test_select_multiple_residues(selection): node_sel = nodes.add_custom(group, node_sel_group.name) group.links.new(node_sel.outputs["Selection"], sep.inputs["Selection"]) - vertices_count = len(mn.blender.mesh.evaluate_object(object).data.vertices) + vertices_count = len(bob.evaluate()) assert vertices_count == len(selection[1]) - assert ( - mn.blender.mesh.named_attribute(mn.blender.mesh.evaluate_object(object), "res_id") - == selection[1] - ).all() + assert (bob.evaluate().named_attribute("res_id") == selection[1]).all() diff --git a/tests/test_trajectory.py b/tests/test_trajectory.py index f76eecad..0a06acf8 100644 --- a/tests/test_trajectory.py +++ b/tests/test_trajectory.py @@ -2,12 +2,11 @@ import os import pytest import molecularnodes as mn -from molecularnodes.blender.mesh import named_attribute import MDAnalysis as mda import numpy as np from .constants import data_dir -from .utils import sample_attribute, NumpySnapshotExtension +from .utils import NumpySnapshotExtension mn._test_register() diff --git a/tests/utils.py b/tests/utils.py index 923b16ab..f8b11e7f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -61,7 +61,7 @@ def sample_attribute( random.seed(seed) if error: - attribute = mn.blender.mesh.named_attribute( + attribute = mn.blender.bpyd.named_attribute( obj=object, name=attribute, evaluate=evaluate ) length = len(attribute) @@ -77,7 +77,7 @@ def sample_attribute( return attribute[idx, :] else: try: - attribute = mn.blender.mesh.named_attribute( + attribute = mn.blender.bpyd.named_attribute( obj=object, name=attribute, evaluate=evaluate ) length = len(attribute)