File: version_registry.py

package info (click to toggle)
python-apptools 4.4.0-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 2,652 kB
  • sloc: python: 16,657; makefile: 77
file content (106 lines) | stat: -rw-r--r-- 3,486 bytes parent folder | download | duplicates (5)
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
"""A version registry that manages handlers for different state
versions.
"""
# Author: Prabhu Ramachandran <prabhu_r@users.sf.net>
# Copyright (c) 2005, Enthought, Inc.
# License: BSD Style.

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