Source code for apptools.persistence.version_registry

# (C) Copyright 2005-2022 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!
"""A version registry that manages handlers for different state
versions.
"""


# Standard library imports.
import sys
import inspect
import logging


logger = logging.getLogger(__name__)


######################################################################
# Utility functions.
######################################################################
[docs]def get_version(obj): """Walks the class hierarchy and obtains the versions of the various classes and returns a list of tuples of the form ((class_name, module), version) in reverse order of the MRO. """ res = [] for cls in inspect.getmro(obj.__class__): class_name, module = cls.__name__, cls.__module__ if module in ["__builtin__"]: # No point in versioning builtins. continue try: version = cls.__version__ except AttributeError: version = -1 res.append(((class_name, module), version)) res.reverse() return res
###################################################################### # `HandlerRegistry` class. ######################################################################
[docs]class HandlerRegistry: """A simple version conversion handler registry. Classes register handlers in order to convert the state version to the latest version. When an object's state is about to be set, the `update` method of the registy is called. This in turn calls any handlers registered for the class/module and this handler is then called with the state and the version of the state. The state is modified in-place by the handlers. """ def __init__(self): # The version conversion handlers. # Key: (class_name, module), value: handler self.handlers = {}
[docs] def register(self, class_name, module, handler): """Register `handler` that handles versioning for class having class name (`class_name`) and module name (`module`). The handler function will be passed the state and its version to fix. """ key = (class_name, module) if key in self.handlers: msg = "Overwriting version handler for (%s, %s)" % (key[0], key[1]) logger.warn(msg) self.handlers[(class_name, module)] = handler
[docs] def unregister(self, class_name, module): """Unregisters any handlers for a class and module.""" self.handlers.pop((class_name, module))
[docs] def update(self, state): """Updates the given state using the handlers. Note that the state is modified in-place. """ if (not self.handlers) or (not hasattr(state, "__metadata__")): return versions = state.__metadata__["version"] for ver in versions: key = ver[0] try: self.handlers[key](state, ver[1]) except KeyError: pass
def _create_registry(): """Creates a reload safe, singleton registry.""" registry = None for key in sys.modules.keys(): if "version_registry" in key: mod = sys.modules[key] if hasattr(mod, "registry"): registry = mod.registry break if not registry: registry = HandlerRegistry() return registry # The singleton registry. registry = _create_registry()