1"""A version registry that manages handlers for different state 2versions. 3""" 4# Author: Prabhu Ramachandran <prabhu_r@users.sf.net> 5# Copyright (c) 2005, Enthought, Inc. 6# License: BSD Style. 7 8# Standard library imports. 9import sys 10import inspect 11import logging 12 13 14logger = logging.getLogger(__name__) 15 16 17###################################################################### 18# Utility functions. 19###################################################################### 20def get_version(obj): 21 """Walks the class hierarchy and obtains the versions of the 22 various classes and returns a list of tuples of the form 23 ((class_name, module), version) in reverse order of the MRO. 24 """ 25 res = [] 26 for cls in inspect.getmro(obj.__class__): 27 class_name, module = cls.__name__, cls.__module__ 28 if module in ['__builtin__']: 29 # No point in versioning builtins. 30 continue 31 try: 32 version = cls.__version__ 33 except AttributeError: 34 version = -1 35 res.append( ( (class_name, module), version) ) 36 res.reverse() 37 return res 38 39 40###################################################################### 41# `HandlerRegistry` class. 42###################################################################### 43class HandlerRegistry: 44 """A simple version conversion handler registry. Classes register 45 handlers in order to convert the state version to the latest 46 version. When an object's state is about to be set, the `update` 47 method of the registy is called. This in turn calls any handlers 48 registered for the class/module and this handler is then called 49 with the state and the version of the state. The state is 50 modified in-place by the handlers. 51 """ 52 53 def __init__(self): 54 # The version conversion handlers. 55 # Key: (class_name, module), value: handler 56 self.handlers = {} 57 58 def register(self, class_name, module, handler): 59 """Register `handler` that handles versioning for class having 60 class name (`class_name`) and module name (`module`). The 61 handler function will be passed the state and its version to fix. 62 """ 63 key = (class_name, module) 64 if key in self.handlers: 65 msg = 'Overwriting version handler for (%s, %s)'%(key[0], key[1]) 66 logger.warn(msg) 67 self.handlers[(class_name, module)] = handler 68 69 def unregister(self, class_name, module): 70 """Unregisters any handlers for a class and module. 71 """ 72 self.handlers.pop((class_name, module)) 73 74 def update(self, state): 75 """Updates the given state using the handlers. Note that the 76 state is modified in-place. 77 """ 78 if (not self.handlers) or (not hasattr(state, '__metadata__')): 79 return 80 versions = state.__metadata__['version'] 81 for ver in versions: 82 key = ver[0] 83 try: 84 self.handlers[key](state, ver[1]) 85 except KeyError: 86 pass 87 88 89def _create_registry(): 90 """Creates a reload safe, singleton registry. 91 """ 92 registry = None 93 for key in sys.modules.keys(): 94 if 'version_registry' in key: 95 mod = sys.modules[key] 96 if hasattr(mod, 'registry'): 97 registry = mod.registry 98 break 99 if not registry: 100 registry = HandlerRegistry() 101 return registry 102 103 104# The singleton registry. 105registry = _create_registry() 106 107