File indexing completed on 2024-12-01 04:22:15
0001 #!/usr/bin/python2.5 0002 # -*- coding: utf-8 -*- 0003 ############################################################################ 0004 # sealed.py # 0005 # # 0006 # Copyright (C) 2007 by Simon Edwards <simon@simonzone.com> # 0007 # # 0008 # This program is free software; you can redistribute it and/or modify # 0009 # it under the terms of the GNU General Public License as published by # 0010 # the Free Software Foundation; either version 2 of the License, or # 0011 # (at your option) any later version. # 0012 ############################################################################ 0013 import sys 0014 0015 def sealed(func): 0016 """Decorator to seal an object after initialisation 0017 0018 This decorator can be used to enforce the initialisation pattern where 0019 any attributes are initialised in __init__() and no other attributes 0020 can be added once initialisation has been done. 0021 0022 This decorator should be applied to __init__ methods. 0023 0024 >>> x = MyNormalClass() 0025 >>> x.new_attribute_y = True # <- Succeeds as normal 0026 0027 >>> x = MySealedClass() 0028 >>> x.new_attribute_y = True # <- Raises an AttributeError 0029 """ 0030 def sealing_init(self, *args, **kw): 0031 func(self, *args, **kw) 0032 0033 # Do not do anything if we are called from the __init__ method of a subclass. 0034 caller = sys._getframe(1) 0035 if caller.f_code.co_name=='__init__': 0036 if 'self' in caller.f_locals: 0037 if caller.f_locals['self'] is self: 0038 return 0039 0040 # Only create the wedge class once. 0041 if sealing_init.wedge_class is None: 0042 class wedge_class(self.__class__): 0043 def __setattr__(self,name,value): 0044 getattr(self,name) 0045 #if name not in self.__dict__: 0046 # raise AttributeError("No new attributes may be added to this object.") 0047 super(wedge_class,self).__setattr__(name,value) 0048 sealing_init.wedge_class = wedge_class 0049 sealing_init.wedge_class.__name__ = self.__class__.__name__+" @sealed" 0050 # Replace the class of self with a new one that has a modified __setattr__. 0051 self.__class__ = sealing_init.wedge_class 0052 0053 sealing_init.wedge_class = None 0054 return sealing_init