reapy icon indicating copy to clipboard operation
reapy copied to clipboard

standardize serialization of core objects (tracks, projects, items etc)

Open Levitanus opened this issue 6 years ago • 3 comments

On the start of my project, I've made some tests considering how to keep objects between Reaper sessions. And, occasionally, I found, that id property is good. But the test itself was wrong, and only today I really got that id property is nothing than just a pointer. So, at first, I think, the docs should be updated to clearly make user understand that id persists only during one Reaper session.

At the second, I think we should consider the unified interface to save and restore objects, like it can be done with Track.GUID, for example.

Levitanus avatar Apr 23 '20 18:04 Levitanus

As an option, __getstate__ and __setstate__ can be defined, so, if user wants to serialize the object he can use pickle. For example:

# project.py
@rpr.inside_reaper()
    def __getstate__(self) -> ty.Dict[str, object]:
        state = self.__dict__
        s_id = ty.cast(str, self.get_ext_state(EXT_SECTION, 'guid'))
        if s_id == '':
            s_id = str(uuid4())
            self.set_ext_state(EXT_SECTION, 'guid', s_id)
        state['_guid'] = s_id
        return state

    @rpr.inside_reaper()
    def __setstate__(self, state: ty.Dict[str, object]) -> None:
        guid = state['_guid']
        for pr in rpr.get_projects():
            if pr.get_ext_state(EXT_SECTION, 'guid') == guid:
                state['id'] = pr.id
                for k, v in state.items():
                    self.__dict__[k] = v
                return
        raise KeyError(f"cannot find project with guid {guid}")

take a look at projects pointers (the first is stored before reaper relaunch)

from reasession.session.projects import Project
import pickle
import reapy as rpr

# dump = pickle.dumps(Project('test_master'))
# Project("(ReaProject*)0x00000000070B91F0")
dump = b'\x80\x03creasession.session.projects\nProject\nq\x00)\x81q\x01}q\x02(X\x08\x00\x00\x00_host_ipq\x03X\t\x00\x00\x00localhostq\x04X\x05\x00\x00\x00_hostq\x05NX\x0f\x00\x00\x00_slave_projectsq\x06}q\x07X\x0b\x00\x00\x00_out_tracksq\x08}q\tX\x02\x00\x00\x00idq\nX\x1f\x00\x00\x00(ReaProject*)0x00000000070B91F0q\x0bX\x05\x00\x00\x00_guidq\x0cX$\x00\x00\x005252efb9-26e7-4d94-b557-0318d5155486q\rub.'
print(dump)
loaded = pickle.loads(dump)
print(loaded, loaded.name)
# Project("(ReaProject*)0x000000000738FC50") test_master.RPP
print(rpr.Project("(ReaProject*)0x00000000070B91F0").name)
# test_midi_sends.RPP

Levitanus avatar Apr 24 '20 00:04 Levitanus

BTW, the last example is indirect confirmation that fix of #80 is not breaking things, and call to the ValidatePtr is unnecessary. C-side of API still will fall back to something safe.

Levitanus avatar Apr 24 '20 00:04 Levitanus

I still think it is good idea, as I started to add more fields to my custom project class for keeping it serializable. For example, now it is self._filename.

Levitanus avatar May 12 '20 20:05 Levitanus