File: version_registry.py

package info (click to toggle)
python-apptools 5.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,552 kB
  • sloc: python: 9,868; makefile: 80
file content (110 lines) | stat: -rw-r--r-- 3,763 bytes parent folder | download
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
# (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!
"""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.
######################################################################
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.
######################################################################
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 = {}

    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

    def unregister(self, class_name, module):
        """Unregisters any handlers for a class and module."""
        self.handlers.pop((class_name, module))

    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()