Source code for apptools.persistence.project_loader
# (C) Copyright 2005-2024 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
# Standard library imports
import sys
import pickle
import logging
# Enthought library imports
from apptools.persistence.versioned_unpickler import VersionedUnpickler
logger = logging.getLogger(__name__)
[docs]def load_project(
pickle_filename, updater_path, application_version, protocol, max_pass=-1
):
"""Reads a project from a pickle file and if necessary will update it to
the latest version of the application.
"""
latest_file = pickle_filename
# Read the pickled project's metadata.
f = open(latest_file, "rb")
metadata = VersionedUnpickler(f).load(max_pass)
f.close()
project_version = metadata.get("version", False)
if not project_version:
raise ValueError("Could not read version number from the project file")
logger.debug(
"Project version: %d, Application version: %d"
% (project_version, application_version)
)
# here you can temporarily force an upgrade each time for testing ....
# project_version = 0
latest_file = upgrade_project(
pickle_filename,
updater_path,
project_version,
application_version,
protocol,
max_pass,
)
# Finally we can import the project ...
logger.info("loading %s" % latest_file)
i_f = open(latest_file, "rb")
project = VersionedUnpickler(i_f).load(max_pass)
i_f.close()
return project
[docs]def upgrade_project(
pickle_filename,
updater_path,
project_version,
application_version,
protocol,
max_pass=-1,
):
"""Repeatedly read and write the project to disk updating it one version
at a time.
Example the p5.project is at version 0
The application is at version 3
p5.project --- Update1 ---> p5.project.v1
p5.project.v1 --- Update2 ---> p5.project.v2
p5.project.v2 --- Update3 ---> p5.project.v3
p5.project.v3 ---> loaded into app
The user then has the option to save the updated project as p5.project
"""
first_time = True
latest_file = pickle_filename
# update the project until it's version matches the application's
while project_version < application_version:
next_version = project_version + 1
if first_time:
i_f = open(pickle_filename, "rb")
data = i_f.read()
open("%s.bak" % pickle_filename, "wb").write(data)
i_f.seek(0) # rewind the file to the start
else:
name = "%s.v%d" % (pickle_filename, project_version)
i_f = open(name, "rb")
latest_file = name
logger.info("converting %s" % latest_file)
# find this version's updater ...
updater_name = "%s.update%d" % (updater_path, next_version)
__import__(updater_name)
mod = sys.modules[updater_name]
klass = getattr(mod, "Update%d" % next_version)
updater = klass()
# load and update this version of the project
project = VersionedUnpickler(i_f, updater).load(max_pass)
i_f.close()
# set the project version to be the same as the updater we just
# ran on the unpickled files ...
project.metadata["version"] = next_version
# Persist the updated project ...
name = "%s.v%d" % (pickle_filename, next_version)
latest_file = name
o_f = open(name, "wb")
pickle.dump(project.metadata, o_f, protocol=protocol)
pickle.dump(project, o_f, protocol=protocol)
o_f.close()
# Bump up the version number of the pickled project...
project_version += 1
first_time = False
return latest_file