1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
# (C) Copyright 2005-2025 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__)
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
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
|