Esempio n. 1
0
class Datablock(DifferentialApply):
    def test_builtin(self):
        # a python builtin in a dataclock
        # Scene.audio_volume

        # test_diff_apply.Datablock.test_builtin

        self.scene.audio_volume = 0.5
        delta = self.scene_proxy.diff(self.scene,
                                      self.scene.name, self.scenes_property,
                                      self.proxy.context())
        # the diff has audio_volume, updated to 0.5

        # rollback to anything else
        self.scene.audio_volume = 0.0

        # apply the diff
        scene = bpy.data.scenes[self.scene.name]
        self.scene_proxy.apply(scene, bpy.data.scenes, self.scene.name, delta,
                               self.proxy.context())
        self.assertEqual(self.scene.audio_volume, 0.5)

    def test_struct_builtin(self):
        # a python builtin a a struct inside a datablock
        # Scene.eevee.use_bloom

        # test_diff_apply.Datablock.test_struct_builtin

        self.scene.eevee.use_bloom = False
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy: DatablockProxy = self.proxy.data(
            "scenes").search_one("Scene")
        self.scene.eevee.use_bloom = True

        delta = self.scene_proxy.diff(self.scene,
                                      self.scene.name, self.scenes_property,
                                      self.proxy.context())
        # diff is -> True

        # reset
        self.scene.eevee.use_bloom = False

        # apply the diff
        scene = bpy.data.scenes[self.scene.name]
        self.scene_proxy.apply(scene, bpy.data.scenes, self.scene.name, delta,
                               self.proxy.context())
        self.assertEqual(self.scene.eevee.use_bloom, True)
Esempio n. 2
0
class Aos(DifferentialCompute):
    # test_diff_compute.Aos

    # @unittest.skip("AttributeError: 'CollectionObjects' object has no attribute 'fixed_type'")
    def test_modify_value(self):
        # modify a vertex coordinate in a mesh

        # test_diff_compute.Aos.test_modify_value

        mesh = bpy.data.meshes.new("Mesh")
        mesh.vertices.add(4)
        for i in [0, 1, 2, 3]:
            v = 10 * i
            mesh.vertices[i].co = [v, v + 1, v + 2]

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        mesh_proxy = self.proxy.data("meshes").search_one("Mesh")
        plane_mesh = bpy.data.meshes["Mesh"]

        expected_vertex = (-1.0, -2.0, -3.0)
        plane_mesh.vertices[0].co = expected_vertex
        expected_vertices = [list(vertex.co) for vertex in mesh.vertices]

        self.generate_all_uuids()

        mesh_delta = mesh_proxy.diff(plane_mesh, plane_mesh.name, None,
                                     self.proxy.context())

        self.assertIsInstance(mesh_delta, DeltaUpdate)
        mesh_update = mesh_delta.value
        self.assertIsInstance(mesh_update, DatablockProxy)
        self.assertTrue(mesh_update.is_standalone_datablock)

        vertices_delta = mesh_update.data("vertices", resolve_delta=False)
        self.assertIsInstance(vertices_delta, DeltaUpdate)
        vertices_update = vertices_delta.value
        self.assertIsInstance(vertices_update, AosProxy)
        self.assertTrue(vertices_update)

        co_delta = vertices_update.data("co", resolve_delta=False)
        self.assertIsInstance(co_delta, DeltaUpdate)
        co_update = co_delta.value
        self.assertIsInstance(co_update, SoaElement)

        array_ = co_update._array
        self.assertEqual(len(array_), 4 * 3)
        vertices = [[
            x, y, z
        ] for x, y, z in zip(array_[0::3], array_[1::3], array_[2::3])]

        self.assertEqual(vertices, expected_vertices)
Esempio n. 3
0
class Aos(DifferentialApply):
    # test_diff_compute.Aos

    # @unittest.skip("AttributeError: 'CollectionObjects' object has no attribute 'fixed_type'")
    def test_modify_value(self):
        # modify a vertex coordinate in a mesh

        # test_diff_apply.Aos.test_modify_value

        mesh = bpy.data.meshes.new("Mesh")
        mesh.vertices.add(4)
        for i in [0, 1, 2, 3]:
            v = 10 * i
            mesh.vertices[i].co = [v, v + 1, v + 2]

        expected_vertices = [list(vertex.co) for vertex in mesh.vertices]

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        mesh_proxy = self.proxy.data("meshes").search_one("Mesh")
        mesh = bpy.data.meshes["Mesh"]

        modified_vertex = (-1.0, -2.0, -3.0)
        mesh.vertices[0].co = modified_vertex

        self.generate_all_uuids()

        mesh_delta = mesh_proxy.diff(mesh, mesh.name, None,
                                     self.proxy.context())

        # reset mesh state
        mesh.vertices[0].co = (0.0, 1.0, 2.0)

        mesh_proxy.apply(bpy.data.meshes, mesh.name, mesh_delta,
                         self.proxy.context())

        vertices = [list(vertex.co) for vertex in mesh.vertices]
        self.assertEqual(vertices, expected_vertices)
Esempio n. 4
0
class TestCodec(unittest.TestCase):
    def setUp(self):
        bpy.ops.wm.open_mainfile(filepath=test_blend_file)
        self.proxy = BpyDataProxy()
        register_bl_equals(self, test_properties)

    def test_camera(self):
        # test_codec.TestCodec.test_camera

        # prepare camera
        transmit_name = "transmit_camera"
        cam_sent = D.cameras["Camera_0"]

        cam_sent.dof.focus_object = D.objects["Cube"]

        # load into proxy
        self.proxy.load(test_properties)

        # patch the name so that it does not get mixed up as we restore later in the same scene
        cam_proxy_sent = self.proxy.data("cameras").search_one("Camera_0")
        cam_proxy_sent._data["name"] = transmit_name
        self.assertIsInstance(cam_proxy_sent, DatablockProxy)

        # encode
        codec = Codec()
        message = codec.encode(cam_proxy_sent)

        #
        # transmit
        #

        # decode into proxy
        cam_proxy_received = codec.decode(message)

        focus_object_proxy = cam_proxy_received.data("dof").data(
            "focus_object")
        self.assertIsInstance(focus_object_proxy, DatablockRefProxy)
        self.assertEqual(focus_object_proxy._datablock_uuid,
                         cam_sent.dof.focus_object.mixer_uuid)

        # save into blender
        cam_proxy_received._datablock_uuid = "__" + cam_proxy_received._datablock_uuid
        cam_received, _ = cam_proxy_received.create_standalone_datablock(
            self.proxy.context())

        self.assertEqual(cam_sent, cam_received)
        pass
Esempio n. 5
0
class TestWriteAttribute(unittest.TestCase):
    def setUp(self):
        bpy.ops.wm.open_mainfile(filepath=test_blend_file)

        # otherwise the loaded scene  way have curves despite use_curve_mapping==False and
        # the new one will not have curves and will not receive them as they are not send
        # use_curve_mapping == False
        D.scenes["Scene_0"].view_settings.use_curve_mapping = True

        self.proxy = BpyDataProxy()
        self.proxy.load(synchronized_properties)
        register_bl_equals(self, synchronized_properties)

    def test_write_simple_types(self):
        scene = D.scenes[0]
        object_ = D.objects[0]
        # matrix = [10.0, 20.0, 30.0, 40.0, 11.0, 21.0, 31.0, 41.0, 12.0, 22.0, 32.0, 42.0, 14.0, 24.0, 34.0, 44]
        matrix2 = [[10.0, 20.0, 30.0, 40], [11.0, 21.0, 31.0, 41],
                   [12.0, 22.0, 32.0, 42], [14.0, 24.0, 34.0, 44]]
        values = [
            # (scene, "name", "Plop"),
            (scene, "frame_current", 99),
            (scene, "use_gravity", False),
            (scene, "gravity", [-1, -2, -3]),
            (scene, "gravity", Vector([-10, -20, -30])),
            (scene, "sync_mode", "FRAME_DROP"),
            # (object_, "matrix_world", matrix),
            (object_, "matrix_world", Matrix(matrix2)),
        ]
        for bl_instance, name, value in values:
            write_attribute(bl_instance, name, value, self.proxy.context())
            stored_value = getattr(bl_instance, name)
            stored_type = type(stored_value)
            self.assertEqual(stored_type(value), stored_value)

    def test_write_bpy_struct_scene_eevee(self):
        scene = D.scenes[0]
        eevee_proxy = self.proxy._data["scenes"].search_one(
            "Scene_0")._data["eevee"]
        eevee_proxy._data["gi_cubemap_resolution"] = "64"
        eevee_proxy.save(scene, "eevee", self.proxy.context())
        self.assertEqual("64", scene.eevee.gi_cubemap_resolution)

    def test_write_bpy_property_group_scene_cycles(self):
        # Not very useful it derives from struct
        scene = D.scenes[0]
        cycles_proxy = self.proxy._data["scenes"].search_one(
            "Scene_0")._data["cycles"]
        cycles_proxy._data["shading_system"] = True
        cycles_proxy.save(scene, "cycles", self.proxy.context())
        self.assertEqual(True, scene.cycles.shading_system)

    @unittest.skip("Mesh currently restricted to Mesh.name")
    def test_write_array_of_struct_with_vec(self):
        # self.addTypeEqualityFunc(D.bpy_struct, bl_equalityfunc)
        cube = D.meshes["Cube"]
        vertices_proxy = self.proxy._data["meshes"].search_one(
            "Cube")._data["vertices"]

        # loaded as SOA into array.array
        co_proxy = vertices_proxy._data["co"]._data

        # first vertex
        co_proxy[0] *= 2
        co_proxy[1] *= 2
        co_proxy[2] *= 2

        vertices_proxy.save(cube, "vertices", self.proxy.context())
        self.assertListEqual(list(cube.vertices[0].co[0:3]),
                             co_proxy[0:3].tolist())

    # explicit test per data type , including addition in collections

    def test_write_datablock_light(self):
        # Write a whole scene datablock
        light_name = "Light"
        light = D.lights[light_name]
        light_type = light.type
        light_proxy = self.proxy.data("lights").search_one(light_name)

        light.name = "light_bak"
        light_bak = D.lights["light_bak"]

        light = D.lights.new(light_name, light_type)
        light_proxy.save(D.lights, light_name, self.proxy.context())
        self.assertEqual(D.lights[light_name], light_bak)

    def test_write_datablock_world(self):
        # Write a whole scene datablock
        world_name = "World"
        world = D.worlds[world_name]
        world_proxy = self.proxy.data("worlds").search_one(world_name)

        world.name = "world_bak"
        world_bak = D.worlds["world_bak"]

        world = D.worlds.new(world_name)
        world_proxy.save(D.worlds, world_name, self.proxy.context())
        self.assertEqual(D.worlds[world_name], world_bak)

    def test_write_array_curvemap(self):
        bpy.ops.wm.open_mainfile(filepath=test_blend_file)

        light_name = "Light"
        light = D.lights["Light"]
        points = [(0.111, 0.222), (0.333, 0.444)]
        curve0 = light.falloff_curve.curves[0]
        for i, point in enumerate(points):
            curve0.points[i].location = point

        self.proxy = BpyDataProxy()
        self.proxy.load(synchronized_properties)

        light.name = "light_bak"
        light_bak = D.lights["light_bak"]
        light = None

        light_proxy = self.proxy.data("lights").search_one(light_name)
        light_proxy.save(D.lights, light_name, self.proxy.context())
        light = D.lights[light_name]
        curve = light.falloff_curve.curves[0]
        for i, point in enumerate(points):
            for clone, expected in zip(curve.points[i].location, point):
                self.assertAlmostEqual(clone, expected)

        self.assertEqual(D.lights[light_name], light_bak)

    def test_array_curvemap_shrink(self):
        bpy.ops.wm.open_mainfile(filepath=test_blend_file)

        light_name = "Light"
        light = D.lights["Light"]
        src_points = [(0.666, 0.777), (0.888, 0.999)]
        curve0 = light.falloff_curve.curves[0]
        for i, point in enumerate(src_points):
            curve0.points[i].location = point

        self.proxy = BpyDataProxy()
        self.proxy.load(synchronized_properties)

        light.name = "light_bak"
        light = None

        light_proxy = self.proxy.data("lights").search_one(light_name)

        light_proxy.save(D.lights, light_name, self.proxy.context())
        light = D.lights[light_name]

        dst_curve = light.falloff_curve.curves[0]
        self.assertEqual(len(src_points), len(dst_curve.points))

        # extend the dst curvemap to 3 points
        dst_points = [(0.111, 0.222), (0.333, 0.444), (0.555, 0.666)]
        curve0 = light.falloff_curve.curves[0]
        curve0.points.new(*dst_points[2])
        for i, point in enumerate(dst_points):
            curve0.points[i].location = point
        self.assertEqual(len(dst_points), len(dst_curve.points))

        # restore again, save needs to shrink
        light_proxy.save(D.lights, light_name, self.proxy.context())
        light = D.lights[light_name]

        dst_curve = light.falloff_curve.curves[0]
        self.assertEqual(len(src_points), len(dst_curve.points))
        for i, point in enumerate(src_points):
            for dst, expected in zip(dst_curve.points[i].location, point):
                self.assertAlmostEqual(dst, expected)

    def test_array_curvemap_extend(self):
        bpy.ops.wm.open_mainfile(filepath=test_blend_file)

        light_name = "Light"
        light = D.lights["Light"]
        light_type = light.type
        # extend the source curvemap to 3 points
        src_points = [(0.111, 0.222), (0.333, 0.444), (0.555, 0.666)]
        curve0 = light.falloff_curve.curves[0]
        curve0.points.new(*src_points[2])
        for i, point in enumerate(src_points):
            curve0.points[i].location = point

        self.proxy = BpyDataProxy()
        self.proxy.load(synchronized_properties)

        light.name = "light_bak"

        light = D.lights.new(light_name, light_type)

        # the dst curvemap has 2 points by default
        # save() needs to extend
        light_proxy = self.proxy.data("lights").search_one(light_name)
        light_proxy.save(D.lights, light_name, self.proxy.context())
        dst_curve = light.falloff_curve.curves[0]
        self.assertEqual(len(src_points), len(dst_curve.points))
        for i, point in enumerate(src_points):
            for dst, expected in zip(dst_curve.points[i].location, point):
                self.assertAlmostEqual(dst, expected)

    def test_write_datablock_scene(self):
        # Write a whole scene datablock
        scene_name = "Scene_0"
        scene = D.scenes[scene_name]
        scene_proxy = self.proxy.data("scenes").search_one(scene_name)
        self.assertIsInstance(scene_proxy, DatablockProxy)

        scene.name = "scene_bak"
        scene_bak = D.scenes["scene_bak"]

        scene_proxy.save(D.scenes, scene_name, self.proxy.context())
        self.assertEqual(D.scenes[scene_name], scene_bak)

    def test_write_datablock_reference_scene_world(self):
        # just write the Scene.world attribute
        scene_name = "Scene_0"
        scene = D.scenes[scene_name]
        expected_world = scene.world
        assert expected_world is not None

        world_ref_proxy = self.proxy.data("scenes").search_one(
            scene_name).data("world")
        self.assertIsInstance(world_ref_proxy, DatablockRefProxy)

        scene.world = None
        assert scene.world != expected_world

        world_ref_proxy.save(scene, "world", self.proxy.context())
        self.assertEqual(scene.world, expected_world)

    def test_write_datablock_with_reference_camera_dof_target(self):
        # Write the whole camera datablock, including its reference to dof target

        camera_name = "Camera_0"
        camera = D.cameras[camera_name]

        # setup the scene and reload
        focus_object = D.objects["Cube"]
        camera.dof.focus_object = focus_object
        self.proxy = BpyDataProxy()
        self.proxy.load(synchronized_properties)

        camera.name = "camera_bak"

        camera_proxy = self.proxy.data("cameras").search_one(camera_name)
        camera_proxy.save(D.cameras, camera_name, self.proxy.context())
        self.assertEqual(D.cameras[camera_name].dof.focus_object, focus_object)
Esempio n. 6
0
class StructDatablockRef(DifferentialCompute):
    # datablock reference in a struct
    # Scene.world
    def test_add(self):
        # set reference from NOne to a valid datablock
        # test_diff_compute.StructDatablockRef.test_add
        self.scene.world = None
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        world = bpy.data.worlds.new("W")
        self.scene.world = world
        self.generate_all_uuids()
        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        self.assertIsInstance(scene_delta, DeltaUpdate)
        world_delta = scene_delta.value.data("world", resolve_delta=False)
        self.assertIsInstance(world_delta, DeltaUpdate)
        world_update = world_delta.value
        self.assertIsInstance(world_update, DatablockRefProxy)
        self.assertEqual(world_update._datablock_uuid, world.mixer_uuid)

    def test_update(self):
        # set reference from None to a valid datablock
        # test_diff_compute.StructDatablockRef.test_update
        world1 = bpy.data.worlds.new("W1")
        world2 = bpy.data.worlds.new("W2")
        self.scene.world = world1
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene.world = world2
        self.generate_all_uuids()
        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        self.assertIsInstance(scene_delta, DeltaUpdate)
        world_delta = scene_delta.value.data("world", resolve_delta=False)
        self.assertIsInstance(world_delta, DeltaUpdate)
        world_update = world_delta.value
        self.assertIsInstance(world_update, DatablockRefProxy)
        self.assertEqual(world_update._datablock_uuid, world2.mixer_uuid)

    @unittest.skip("Need BpyIDRefNoneProxy")
    def test_remove(self):
        # set reference from a valid datablock to None
        # test_diff_compute.StructDatablockRef.test_remove
        world1 = bpy.data.worlds.new("W1")
        self.scene.world = world1
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene.world = None
        self.generate_all_uuids()
        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        # TODO fails. should a null ref be implemented as a DatablockRefProxy
        # with a null ref (uuid is None)
        # or what else
        self.assertIsInstance(scene_delta, DeltaUpdate)
        world_delta = scene_delta.value.data("world")
        self.assertIsInstance(world_delta, DeltaDeletion)
Esempio n. 7
0
class Collection(DifferentialCompute):
    # test_diff_compute.Collection

    # @unittest.skip("AttributeError: 'CollectionObjects' object has no attribute 'fixed_type'")
    def test_datablock_collection(self):
        # Scene.collection.objects
        # A collection of references to standalone datablocks

        # test_diff_compute.Collection.test_datablock_collection
        for i in range(2):
            name = f"Unchanged{i}"
            empty = bpy.data.objects.new(name, None)
            self.scene.collection.objects.link(empty)
        for i in range(2):
            name = f"Deleted{i}"
            empty = bpy.data.objects.new(name, None)
            self.scene.collection.objects.link(empty)

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy = self.proxy.data("scenes").search_one("Scene")
        self.scene = bpy.data.scenes["Scene"]
        for i in range(2):
            name = f"Added{i}"
            empty = bpy.data.objects.new(name, None)
            self.scene.collection.objects.link(empty)
        for i in range(2):
            bpy.data.objects.remove(bpy.data.objects[f"Deleted{i}"])

        self.generate_all_uuids()

        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())

        self.assertIsInstance(scene_delta, DeltaUpdate)
        scene_update = scene_delta.value
        self.assertIsInstance(scene_update, DatablockProxy)
        self.assertTrue(scene_update.is_standalone_datablock)

        collection_delta = scene_update.data("collection", resolve_delta=False)
        self.assertIsInstance(scene_delta, DeltaUpdate)
        collection_update = collection_delta.value
        self.assertIsInstance(collection_update, DatablockProxy)
        self.assertTrue(collection_update.is_embedded_data)

        objects_delta = collection_update.data("objects", resolve_delta=False)
        self.assertIsInstance(objects_delta, DeltaUpdate)
        objects_update = objects_delta.value
        self.assertIsInstance(objects_update, DatablockRefCollectionProxy)

        deltas = {
            delta.value._initial_name: delta
            for delta in objects_update._data.values()
        }
        proxies = {name: delta.value for name, delta in deltas.items()}
        for name in ("Added0", "Added1"):
            self.assertIsInstance(deltas[name], DeltaAddition)
            self.assertIsInstance(proxies[name], DatablockRefProxy)

        for name in ("Deleted0", "Deleted1"):
            self.assertIsInstance(deltas[name], DeltaDeletion)
            self.assertIsInstance(proxies[name], DatablockRefProxy)

    def test_bpy_collection(self):
        # bpy.data.collections[x].objects
        # A collection of references to standalone datablocks

        # test_diff_compute.Collection.test_bpy_collection
        collection = bpy.data.collections.new("Collection")
        for i in range(2):
            empty = bpy.data.objects.new(f"Unchanged{i}", None)
            collection.objects.link(empty)
        for i in range(2):
            empty = bpy.data.objects.new(f"Unlinked{i}", None)
            collection.objects.link(empty)
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.collection_proxy = self.proxy.data("collections").search_one(
            "Collection")
        self.collection = bpy.data.collections["Collection"]
        for i in range(2):
            empty = bpy.data.objects.new(f"Added{i}", None)
            collection.objects.link(empty)
        for i in range(2):
            collection.objects.unlink(bpy.data.objects[f"Unlinked{i}"])

        self.generate_all_uuids()
        collections_property = bpy.data.bl_rna.properties["scenes"]

        collection_delta = self.collection_proxy.diff(self.collection,
                                                      self.collection.name,
                                                      collections_property,
                                                      self.proxy.context())

        self.assertIsInstance(collection_delta, DeltaUpdate)
        collection_update = collection_delta.value
        self.assertIsInstance(collection_update, DatablockProxy)
        self.assertTrue(collection_update.is_standalone_datablock)

        objects_delta = collection_update.data("objects", resolve_delta=False)
        self.assertIsInstance(objects_delta, DeltaUpdate)
        objects_update = objects_delta.value
        self.assertIsInstance(objects_update, DatablockRefCollectionProxy)

        #  test_diff_compute.Collection.test_bpy_collection
        deltas = {
            delta.value._initial_name: delta
            for delta in objects_update._data.values()
        }
        proxies = {name: delta.value for name, delta in deltas.items()}
        for name in ("Added0", "Added1"):
            self.assertIsInstance(deltas[name], DeltaAddition)
            self.assertIsInstance(proxies[name], DatablockRefProxy)

        for name in ("Unlinked0", "Unlinked1"):
            self.assertIsInstance(deltas[name], DeltaDeletion)
            self.assertIsInstance(proxies[name], DatablockRefProxy)

    def test_key_str(self):
        # Scene.render.views
        # A bpy_prop_collection with string keys

        # test_diff_compute.Collection.test_key_str

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy = self.proxy.data("scenes").search_one("Scene")
        self.scene = bpy.data.scenes["Scene"]

        view = self.scene.render.views["right"]
        self.scene.render.views.remove(view)

        view = self.scene.render.views.new("New")

        view = self.scene.render.views["left"]
        view.file_suffix = "new_suffix"

        self.generate_all_uuids()

        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())

        self.assertIsInstance(scene_delta, DeltaUpdate)
        scene_update = scene_delta.value
        self.assertIsInstance(scene_update, DatablockProxy)
        self.assertTrue(scene_update.is_standalone_datablock)

        render_delta = scene_update.data("render", resolve_delta=False)
        self.assertIsInstance(render_delta, DeltaUpdate)
        render_update = render_delta.value
        self.assertIsInstance(render_update, StructProxy)

        views_delta = render_update.data("views", resolve_delta=False)
        self.assertIsInstance(views_delta, DeltaUpdate)
        views_update = views_delta.value
        self.assertIsInstance(views_update, StructCollectionProxy)

        # for why "A" and "D" see BpyProStructCollectionProxy.diff()
        self.assertIn("ANew", views_update)
        view_delta = views_update.data("ANew", resolve_delta=False)
        self.assertIsInstance(view_delta, DeltaAddition)
        view_update = view_delta.value
        self.assertIsInstance(view_update, StructProxy)

        self.assertIn("Dright", views_update)
        view_delta = views_update.data("Dright", resolve_delta=False)
        self.assertIsInstance(view_delta, DeltaDeletion)

        self.assertIn("left", views_update)
        view_delta = views_update.data("left", resolve_delta=False)
        self.assertIsInstance(view_delta, DeltaUpdate)
        view_update = view_delta.value
        self.assertIsInstance(view_update, StructProxy)
        property_delta = view_update.data("file_suffix", resolve_delta=False)
        self.assertIsInstance(view_delta, DeltaUpdate)
        self.assertEqual(property_delta.value, "new_suffix")

    def test_key_int(self):
        # Scene.view_settings.curve_mapping.curves
        # A bpy_prop_collection with string keys

        # test_diff_compute.Collection.test_key_int
        self.scene.view_settings.use_curve_mapping = True
        points_remove = self.scene.view_settings.curve_mapping.curves[0].points
        points_remove.new(0.5, 0.5)
        points_add = self.scene.view_settings.curve_mapping.curves[1].points

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy = self.proxy.data("scenes").search_one("Scene")
        self.scene = bpy.data.scenes["Scene"]

        points_remove.remove(points_remove[1])
        points_add.new(2.0, 2.0)

        self.generate_all_uuids()

        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())

        points_remove_proxy = (scene_delta.value.data("view_settings").data(
            "curve_mapping").data("curves").data(0).data("points"))
        self.assertIsInstance(points_remove_proxy, StructCollectionProxy)

        # points are ordered by location. removing the second one produces an update
        # at index 1 and a delete at index 2
        point1 = points_remove_proxy.data(1)
        point1_update = point1.data("location", resolve_delta=False)
        self.assertIsInstance(point1_update, DeltaUpdate)
        location1 = point1_update.value
        self.assertAlmostEqual(location1[0], 1.0)
        self.assertAlmostEqual(location1[1], 1.0)

        point2 = points_remove_proxy.data(2, resolve_delta=False)
        self.assertIsInstance(point2, DeltaDeletion)

        points_add_proxy = (scene_delta.value.data("view_settings").data(
            "curve_mapping").data("curves").data(1).data("points"))
        self.assertIsInstance(points_add_proxy, StructCollectionProxy)

        self.assertIsInstance(points_add_proxy.data(2, resolve_delta=False),
                              DeltaAddition)

        # points are ordered by location. removing the second one produces an update
        # at index 1 and a delete at index 2
        point = points_add_proxy.data(2)
        location = point.data("location")
        self.assertAlmostEqual(location[0], 2.0)
        self.assertAlmostEqual(location[1], 2.0)
Esempio n. 8
0
class StructDatablockRef(DifferentialApply):
    # datablock reference in a struct
    # Scene.world

    @unittest.skip("Need BpyIDRefNoneProxy")
    def test_add(self):
        # set reference from None to a valid datablock
        # test_diff_apply.StructDatablockRef.test_add

        # TODO needs a BpyIDNoneRefProxy
        self.scene.world = None
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy: DatablockProxy = self.proxy.data(
            "scenes").search_one("Scene")

        world = bpy.data.worlds.new("W")
        self.scene.world = world
        self.generate_all_uuids()
        delta = self.scene_proxy.diff(self.scene,
                                      self.scene.name, self.scenes_property,
                                      self.proxy.context())
        # diff -> set world

        # reset
        self.scene.world = None

        # apply the diff
        self.scene_proxy.apply(bpy.data.scenes, self.scene.name, delta,
                               self.proxy.context())
        self.assertEqual(self.scene.eevee.use_bloom, True)

    def test_update(self):
        # set reference from None to a valid datablock
        # test_diff_apply.StructDatablockRef.test_update
        world1 = bpy.data.worlds.new("W1")
        world2 = bpy.data.worlds.new("W2")
        self.scene.world = world1
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy: DatablockProxy = self.proxy.data(
            "scenes").search_one("Scene")

        self.scene.world = world2
        self.generate_all_uuids()
        delta = self.scene_proxy.diff(self.scene,
                                      self.scene.name, self.scenes_property,
                                      self.proxy.context())
        # diff -> world2

        # reset
        self.scene.world = world1

        # apply the diff
        self.scene_proxy.apply(bpy.data.scenes, self.scene.name, delta,
                               self.proxy.context())
        self.assertEqual(self.scene.world, world2)

    @unittest.skip("Need BpyIDRefNoneProxy")
    def test_remove(self):
        # set reference from a valid datablock to None
        # test_diff_apply.StructDatablockRef.test_remove
        world1 = bpy.data.worlds.new("W1")
        self.scene.world = world1
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene.world = None
        self.generate_all_uuids()
        _ = self.scene_proxy.diff(self.scene, self.scene.name,
                                  self.scenes_property, self.proxy.context())
Esempio n. 9
0
class Collection(DifferentialApply):
    # test_differential.Collection

    def test_datablock_collection(self):
        # Scene.collection.objects
        # A collection of references to standalone datablocks
        # tests DatablockCollectionProxy.apply()

        # test_diff_apply.Collection.test_datablock_collection
        for i in range(2):
            empty = bpy.data.objects.new(f"Unchanged{i}", None)
            self.scene.collection.objects.link(empty)
        for i in range(2):
            empty = bpy.data.objects.new(f"Deleted{i}", None)
            self.scene.collection.objects.link(empty)
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy = self.proxy.data("scenes").search_one("Scene")
        self.scene = bpy.data.scenes["Scene"]
        for i in range(2):
            empty = bpy.data.objects.new(f"Added{i}", None)
            self.scene.collection.objects.link(empty)
        for i in range(2):
            empty = bpy.data.objects[f"Deleted{i}"]
            self.scene.collection.objects.unlink(empty)

        self.generate_all_uuids()

        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        # delta contains(deleted1, deleted 2, added1, added2)

        # reset
        for i in range(2):
            empty = bpy.data.objects[f"Deleted{i}"]
            self.scene.collection.objects.link(empty)
        for i in range(2):
            empty = bpy.data.objects[f"Added{i}"]
            self.scene.collection.objects.unlink(empty)

        # required because the Added{i} were created after proxy load and are not known by the proxy
        # at this time. IRL the depsgraph handler uses BpyBendDiff to find datablock additions,
        # then BpyDataProxy.update()
        self.proxy.load(test_properties)

        self.scene_proxy.apply(bpy.data.scenes, self.scene.name, scene_delta,
                               self.proxy.context())

        self.assertIn("Unchanged0", self.scene.collection.objects)
        self.assertIn("Unchanged1", self.scene.collection.objects)
        self.assertIn("Added0", self.scene.collection.objects)
        self.assertIn("Added1", self.scene.collection.objects)
        self.assertNotIn("Deleted0", self.scene.collection.objects)
        self.assertNotIn("Deleted1", self.scene.collection.objects)

    def test_key_str(self):
        # Scene.render.views
        # A bpy_prop_collection with string keys
        # tests StructCollectionProxy.apply()

        # test_diff_apply.Collection.test_key_str

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy = self.proxy.data("scenes").search_one("Scene")
        self.scene = bpy.data.scenes["Scene"]

        view_right = self.scene.render.views["right"]
        self.scene.render.views.remove(view_right)

        view = self.scene.render.views.new("New")

        view = self.scene.render.views["left"]
        view_left_suffix_bak = view.file_suffix
        view.file_suffix = "new_suffix"

        self.generate_all_uuids()

        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())

        # reset to initial state
        views = bpy.data.scenes["Scene"].render.views
        view_right = views.new("right")

        views["left"].file_suffix = view_left_suffix_bak

        view_new = views["New"]
        views.remove(view_new)

        self.scene_proxy.apply(bpy.data.scenes, self.scene.name, scene_delta,
                               self.proxy.context())
        self.assertIn("New", views)
        self.assertIn("left", views)
        self.assertEqual(views["left"].file_suffix, "new_suffix")
        self.assertNotIn("right", views)

    @unittest.skip("Not implemented: addition in array")
    def test_key_int(self):
        # Scene.view_settings.curve_mapping.curves
        # A bpy_prop_collection with string keys

        # test_diff_apply.Collection.test_key_int
        self.scene.view_settings.use_curve_mapping = True

        points0 = self.scene.view_settings.curve_mapping.curves[0].points
        points0.new(0.5, 0.5)

        points1 = self.scene.view_settings.curve_mapping.curves[1].points

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy = self.proxy.data("scenes").search_one("Scene")
        self.scene = bpy.data.scenes["Scene"]

        points0.remove(points0[1])
        points1.new(2.0, 2.0)

        self.generate_all_uuids()

        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        # the delta contains :
        #   curves[0]: Deletion of element 1
        #   curves[1]: Addition of element 2

        # reset state
        points0.new(0.5, 0.5)
        points1.remove(points1[2])

        self.scene_proxy.apply(bpy.data.scenes, self.scene.name, scene_delta,
                               self.proxy.context())
        self.assertEqual(len(points0), 2)
        self.assertEqual(list(points0[0].location), [0.0, 0.0])
        self.assertEqual(list(points0[1].location), [1.0, 1.0])

        self.assertEqual(len(points1), 3)
        self.assertEqual(list(points1[0].location), [0.0, 0.0])
        self.assertEqual(list(points1[1].location), [1.0, 1.0])
        self.assertEqual(list(points1[2].location), [2.0, 2.0])
Esempio n. 10
0
class StructDatablockRef(DifferentialCompute):
    # datablock reference in a struct
    # Scene.world
    def test_add(self):
        # set reference from NOne to a valid datablock
        # test_diff_compute.StructDatablockRef.test_add
        self.scene.world = None
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        world = bpy.data.worlds.new("W")
        self.scene.world = world
        self.generate_all_uuids()
        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        self.assertIsInstance(scene_delta, DeltaUpdate)
        world_delta = scene_delta.value.data("world", resolve_delta=False)
        self.assertIsInstance(world_delta, DeltaReplace)
        world_update = world_delta.value
        self.assertIsInstance(world_update, DatablockRefProxy)
        self.assertEqual(world_update._datablock_uuid, world.mixer_uuid)

    def test_update(self):
        # set reference from None to a valid datablock
        # test_diff_compute.StructDatablockRef.test_update
        world1 = bpy.data.worlds.new("W1")
        world2 = bpy.data.worlds.new("W2")
        self.scene.world = world1
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene.world = world2
        self.generate_all_uuids()
        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        self.assertIsInstance(scene_delta, DeltaUpdate)
        world_delta = scene_delta.value.data("world", resolve_delta=False)
        self.assertIsInstance(world_delta, DeltaReplace)
        world_update = world_delta.value
        self.assertIsInstance(world_update, DatablockRefProxy)
        self.assertEqual(world_update._datablock_uuid, world2.mixer_uuid)

    def test_remove(self):
        # set reference from a valid datablock to None
        # test_diff_compute.StructDatablockRef.test_remove
        world1 = bpy.data.worlds.new("W1")
        self.scene.world = world1
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene.world = None
        self.generate_all_uuids()
        # delta contains valid ref to None
        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())
        self.assertIsInstance(scene_delta, DeltaUpdate)
        world_delta = scene_delta.value.data("world", resolve_delta=False)
        self.assertIsInstance(world_delta, DeltaReplace)
        world_update = world_delta.value
        self.assertIsInstance(world_update, DatablockRefProxy)
        self.assertFalse(world_update)
Esempio n. 11
0
class Collection(DifferentialCompute):
    # test_diff_compute.Collection

    # @unittest.skip("AttributeError: 'CollectionObjects' object has no attribute 'fixed_type'")
    def test_datablock_collection(self):
        # Scene.collection.objects
        # A collection of references to standalone datablocks

        # test_diff_compute.Collection.test_datablock_collection
        for i in range(2):
            name = f"Unchanged{i}"
            empty = bpy.data.objects.new(name, None)
            self.scene.collection.objects.link(empty)
        for i in range(2):
            name = f"Deleted{i}"
            empty = bpy.data.objects.new(name, None)
            self.scene.collection.objects.link(empty)

        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        for i in range(2):
            name = f"Added{i}"
            empty = bpy.data.objects.new(name, None)
            self.scene.collection.objects.link(empty)
        for i in range(2):
            bpy.data.objects.remove(bpy.data.objects[f"Deleted{i}"])

        self.generate_all_uuids()

        scene_delta = self.scene_proxy.diff(self.scene, self.scene.name,
                                            self.scenes_property,
                                            self.proxy.context())

        self.assertIsInstance(scene_delta, DeltaUpdate)
        scene_update = scene_delta.value
        self.assertIsInstance(scene_update, DatablockProxy)

        collection_delta = scene_update.data("collection", resolve_delta=False)
        self.assertIsInstance(scene_delta, DeltaUpdate)
        collection_update = collection_delta.value
        self.assertIsInstance(collection_update, StructProxy)

        objects_delta = collection_update.data("objects", resolve_delta=False)
        self.assertIsInstance(objects_delta, DeltaUpdate)
        objects_update = objects_delta.value
        self.assertIsInstance(objects_update, DatablockRefCollectionProxy)

        deltas = {
            delta.value._initial_name: delta
            for delta in objects_update._data.values()
        }
        proxies = {name: delta.value for name, delta in deltas.items()}
        for name in ("Added0", "Added1"):
            self.assertIsInstance(deltas[name], DeltaAddition)
            self.assertIsInstance(proxies[name], DatablockRefProxy)

        for name in ("Deleted0", "Deleted1"):
            self.assertIsInstance(deltas[name], DeltaDeletion)
            self.assertIsInstance(proxies[name], DatablockRefProxy)

    def test_bpy_collection(self):
        # bpy.data.collections[x].objects
        # A collection of references to standalone datablocks

        # test_diff_compute.Collection.test_bpy_collection
        collection = bpy.data.collections.new("Collection")
        for i in range(2):
            empty = bpy.data.objects.new(f"Unchanged{i}", None)
            collection.objects.link(empty)
        for i in range(2):
            empty = bpy.data.objects.new(f"Unlinked{i}", None)
            collection.objects.link(empty)
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.collection_proxy = self.proxy.data("collections").search_one(
            "Collection")
        self.collection = bpy.data.collections["Collection"]
        for i in range(2):
            empty = bpy.data.objects.new(f"Added{i}", None)
            collection.objects.link(empty)
        for i in range(2):
            collection.objects.unlink(bpy.data.objects[f"Unlinked{i}"])

        self.generate_all_uuids()
        collections_property = bpy.data.bl_rna.properties["scenes"]

        collection_delta = self.collection_proxy.diff(self.collection,
                                                      self.collection.name,
                                                      collections_property,
                                                      self.proxy.context())

        self.assertIsInstance(collection_delta, DeltaUpdate)
        collection_update = collection_delta.value
        self.assertIsInstance(collection_update, DatablockProxy)

        objects_delta = collection_update.data("objects", resolve_delta=False)
        self.assertIsInstance(objects_delta, DeltaUpdate)
        objects_update = objects_delta.value
        self.assertIsInstance(objects_update, DatablockRefCollectionProxy)

        #  test_diff_compute.Collection.test_bpy_collection
        deltas = {
            delta.value._initial_name: delta
            for delta in objects_update._data.values()
        }
        proxies = {name: delta.value for name, delta in deltas.items()}
        for name in ("Added0", "Added1"):
            self.assertIsInstance(deltas[name], DeltaAddition)
            self.assertIsInstance(proxies[name], DatablockRefProxy)

        for name in ("Unlinked0", "Unlinked1"):
            self.assertIsInstance(deltas[name], DeltaDeletion)
            self.assertIsInstance(proxies[name], DatablockRefProxy)
Esempio n. 12
0
class TestCore(unittest.TestCase):
    def setUp(self):
        bpy.ops.wm.open_mainfile(filepath=test_blend_file)
        register_bl_equals(self, test_properties)
        self._proxy = BpyDataProxy()
        self._context = self._proxy.context()

    def test_issubclass(self):

        # Warning T.bpy_struct is not T.Struct !!
        self.assertTrue(issubclass(T.ID, T.bpy_struct))
        self.assertFalse(issubclass(T.bpy_struct, T.ID))

        self.assertTrue(issubclass(T.StringProperty, T.StringProperty))
        self.assertTrue(issubclass(T.StringProperty, T.Property))
        self.assertTrue(issubclass(T.StringProperty, T.bpy_struct))
        self.assertFalse(issubclass(T.StringProperty, T.ID))

        self.assertTrue(issubclass(T.ShaderNodeTree, T.NodeTree))
        self.assertTrue(issubclass(T.ShaderNodeTree, T.ID))
        self.assertTrue(issubclass(T.ShaderNodeTree, T.bpy_struct))
        self.assertTrue(isinstance(T.ShaderNodeTree.bl_rna, T.NodeTree))
        self.assertTrue(isinstance(T.ShaderNodeTree.bl_rna, T.ID))
        self.assertTrue(isinstance(T.ShaderNodeTree.bl_rna, T.bpy_struct))

        self.assertTrue(issubclass(T.Camera, T.Camera))
        self.assertTrue(issubclass(T.Camera, T.ID))
        self.assertTrue(isinstance(T.Camera.bl_rna, T.Camera))
        self.assertTrue(isinstance(T.Camera.bl_rna, T.ID))

    def test_invariants(self):
        s = D.scenes[0]

        #
        # same bl_rna in type and property
        self.assertTrue(isinstance(s, T.Scene))
        self.assertIs(T.Scene.bl_rna, s.bl_rna)

        #
        # Pointers
        self.assertTrue(isinstance(s.eevee, T.SceneEEVEE))
        self.assertFalse(isinstance(s.eevee, T.PointerProperty))
        self.assertIsNot(T.Scene.bl_rna.properties["eevee"].bl_rna,
                         s.eevee.bl_rna)
        self.assertIs(T.Scene.bl_rna.properties["eevee"].bl_rna,
                      T.PointerProperty.bl_rna)
        self.assertIs(T.Scene.bl_rna.properties["eevee"].fixed_type.bl_rna,
                      T.SceneEEVEE.bl_rna)
        # readonly pointer with readwrite pointee :
        self.assertTrue(T.Scene.bl_rna.properties["eevee"].is_readonly)
        s.eevee.use_volumetric_shadows = not s.eevee.use_volumetric_shadows
        # readwrite pointer :
        self.assertFalse(T.Scene.bl_rna.properties["camera"].is_readonly)

        #
        # Collection element type
        # The type of a collection element : Scene.objects is a T.Object
        objects_rna_property = T.Scene.bl_rna.properties["objects"]
        self.assertNotEqual(objects_rna_property.fixed_type, T.Object)
        self.assertIs(objects_rna_property.fixed_type.bl_rna, T.Object.bl_rna)
        self.assertIs(T.Mesh.bl_rna.properties["vertices"].srna.bl_rna,
                      T.MeshVertices.bl_rna)

    def test_types_grease_pencil(self):
        # Grease pencil elements
        triangles = T.GPencilStroke.bl_rna.properties["triangles"]
        self.assertIs(triangles.bl_rna, T.CollectionProperty.bl_rna)
        self.assertIs(triangles.fixed_type.bl_rna, T.GPencilTriangle.bl_rna)

    def test_check_types(self):
        # check our own assertions about types
        for name in dir(bpy.types):
            item = getattr(bpy.types, name)
            try:
                rna = item.bl_rna
            except AttributeError:
                continue

            for prop in rna.properties.values():
                # All ID are behind pointers or in collections
                self.assertFalse(isinstance(prop.bl_rna, T.ID))

    def test_pointer_class(self):
        eevee = T.Scene.bl_rna.properties["eevee"]
        self.assertTrue(is_pointer_to(eevee, T.SceneEEVEE))

        collection = T.Scene.bl_rna.properties["collection"]
        self.assertTrue(is_pointer_to(collection, T.Collection))
        node_tree = T.World.bl_rna.properties["node_tree"]
        self.assertTrue(is_pointer_to(node_tree, T.NodeTree))
        self.assertFalse(is_pointer_to(node_tree, T.ShaderNodeTree))

        camera = T.Scene.bl_rna.properties["camera"]
        self.assertTrue(is_pointer_to(camera, T.Object))

        data = T.Object.bl_rna.properties["data"]
        self.assertTrue(is_pointer_to(data, T.ID))

    def test_scene_viewlayer_layercollection_is_master(self):
        s = D.scenes["Scene_0"]
        master_coll = s.collection
        for vl in s.view_layers:
            self.assertIs(vl.layer_collection.collection, master_coll)

    def test_skip_ShaderNodeTree(self):  # noqa N802
        world = D.worlds["World"]
        proxy = StructProxy().load(world, self._context)
        self.assertTrue("color" in proxy._data)
        # self.assertFalse("node_tree" in proxy._data)

    def test_equals(self):
        self.assertTrue(equals(D, D))
        self.assertTrue(equals(D.objects[0], D.objects[0]))
        self.assertFalse(equals(D.objects[0], D.objects[1]))

    def test_equality_func(self):
        self.assertEqual(D.objects[0], D.objects[0])
        self.assertNotEqual(D.objects[0], D.objects[1])
        self.assertEqual(D.objects, D.objects)
        self.assertEqual(D, D)
Esempio n. 13
0
class StructDatablockRef(DifferentialApply):
    # datablock reference in a struct
    # Scene.world

    def test_add(self):
        # set reference from None to a valid datablock
        # test_diff_apply.StructDatablockRef.test_add

        # create first so that is is correctly registered (bpt_data.diff would register it, not scene_proxy.diff)
        world = bpy.data.worlds.new("W")
        self.scene.world = None
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        # Loaded proxy contains scene.world = None
        self.scene_proxy: DatablockProxy = self.proxy.data(
            "scenes").search_one("Scene")

        self.scene.world = world
        self.generate_all_uuids()
        delta = self.scene_proxy.diff(self.scene,
                                      self.scene.name, self.scenes_property,
                                      self.proxy.context())
        # Diff contains set scene.proxy to world

        self.scene.world = None

        # apply the diff
        scene = bpy.data.scenes[self.scene.name]
        self.scene_proxy.apply(scene, bpy.data.scenes, self.scene.name, delta,
                               self.proxy.context())
        self.assertEqual(self.scene.world, world)

    def test_update(self):
        # set reference from None to a valid datablock
        # test_diff_apply.StructDatablockRef.test_update
        world1 = bpy.data.worlds.new("W1")
        world2 = bpy.data.worlds.new("W2")
        self.scene.world = world1
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        self.scene_proxy: DatablockProxy = self.proxy.data(
            "scenes").search_one("Scene")

        self.scene.world = world2
        self.generate_all_uuids()
        delta = self.scene_proxy.diff(self.scene,
                                      self.scene.name, self.scenes_property,
                                      self.proxy.context())
        # diff -> world2

        # reset
        self.scene.world = world1

        # apply the diff
        scene = bpy.data.scenes[self.scene.name]
        self.scene_proxy.apply(scene, bpy.data.scenes, self.scene.name, delta,
                               self.proxy.context())
        self.assertEqual(self.scene.world, world2)

    def test_remove(self):
        # apply sets reference from a valid datablock to None
        # test_diff_apply.StructDatablockRef.test_remove
        world = bpy.data.worlds.new("W")
        self.scene.world = world
        self.proxy = BpyDataProxy()
        self.proxy.load(test_properties)
        # Loaded proxy contains scene.world = world
        self.scene_proxy: DatablockProxy = self.proxy.data(
            "scenes").search_one("Scene")

        self.scene.world = None
        self.generate_all_uuids()
        delta = self.scene_proxy.diff(self.scene,
                                      self.scene.name, self.scenes_property,
                                      self.proxy.context())
        # Delta contains set scene.proxy to none

        self.scene.world = world

        # apply the diff
        scene = bpy.data.scenes[self.scene.name]
        self.scene_proxy.apply(scene, bpy.data.scenes, self.scene.name, delta,
                               self.proxy.context())
        self.assertEqual(self.scene.world, None)