3
$\begingroup$

I've created a custom class which creates a new object, loads a mesh from an .OBJ file, then modifies the mesh based on the scene's current frame number. When I create an instance of the class (via the Python console), everything works fine. I'm able to successfully import the .OBJ file and changing the current frame produces the desired effect on the mesh. However, when I save the .blend file and restart Blender, the mesh is still in the scene, but the instance of the class is gone. I have to delete the object and re-create it with the Python console.

Is there a way to save the instance of this class as part of the .blend file?

$\endgroup$
2
  • 1
    $\begingroup$ Can you show some code? I'd imagine you could save the class creation props as custom properties of the mesh and then modify your class to rewire with it, without having to re-import the OBJ. Could do this with an addon or with a registered text block. $\endgroup$
    – batFINGER
    Jun 8 '16 at 20:53
  • $\begingroup$ @batFINGER Thanks for the tip. I had to re-work the code a bit, but your suggestion worked out for me. So is the lesson that it's not possible to save an instance of a class into a .blend file? $\endgroup$
    – Justin
    Jun 15 '16 at 21:11
2
$\begingroup$

I've been dealing with a similar problem; I have a number of instances of custom Python classes defined during the execution of a custom Python script, and I'd like to be able to maintain (or restore) references to these custom class instances even after the script has finished running, or after Blender has been closed and then later re-opened.

The simplest solution I've found so far is to use the standard Python pickling module, extending the base pickler and unpickler classes to build picklers that know how to recover 'persistent external references' to Blender objects. This isn't as nice as saving the custom class instances as part of the .blend file itself, but does allow me to save the custom class instances whenever my script is run, and to later unpickle them with correct Blender object references. With a few minor changes to the script, this lets me optionally run the script multiple times while actively modifying the same class instances, without losing them in between script invocations.

To illustrate what I mean, here's a simple example of a custom class instance with active Blender object references I'd like to be able to pickle to a file and re-load later:

>>> class example():
...     def __init__(self, obj, ex_dict):
...         self.obj = obj
...         self.ex_dict = ex_dict
>>> ex = example(bpy.context.object, {1:2, "dog":"cat"}

By default, I can't pickle this:

>>> with open("example.pickle", 'wb') as f:
...     pickle.dump(ex, f, pickle.HIGHEST_PROTOCOL)
...     
Traceback (most recent call last):
  File "<blender_console>", line 2, in <module>
TypeError: can't pickle Object objects

But I can write a custom pickler, unpickler that know how to store and revive references to 'persistent external (Blender) objects', like so:

>>> class BpyPickler(pickle.Pickler):
...     def persistent_id(self, obj):
...         if isinstance(obj, bpy.types.Object):
...             return ("BpyObj", obj.name)
...         else:
...             return None
...             
>>> class BpyUnpickler(pickle.Unpickler):
...     def __init__(self, f):
...         super().__init__(f)
...     def persistent_load(self, pid):
...         type_tag, type_id = pid
...         if type_tag == "BpyObj":
...             return bpy.data.objects[type_id]
...         else:
...             raise pickle.UnpicklingError(f"unsupported obj with persistent id {pid}")

And with these changes, I can now successfully pickle and unpickle-with-restored-bpy-obj-references my class:

>>> with open("example3.pickle", 'wb') as f:
...     BpyPickler(f).dump(ex)
...     
>>> with open("example3.pickle", 'rb') as f:
...     ex3 = BpyUnpickler(f).load()
...     
>>> ex3
<__main__.example object at 0x000001BD0C4013C8>

>>> ex3.obj
bpy.data.objects['floorPanelSharpCorner.007']

>>> ex3.ex_dict
{1: 2, 'dog': 'cat'}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.