Package pytilities :: Package delegation :: Module decorators
[hide private]
[frames] | no frames]

Source Code for Module pytilities.delegation.decorators

  1  # Copyright (C) 2010 Tim Diels <limyreth@users.sourceforge.net> 
  2  #  
  3  # This file is part of pytilities. 
  4  #  
  5  # pytilities is free software: you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation, either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  #  
 10  # pytilities is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  #  
 15  # You should have received a copy of the GNU General Public License 
 16  # along with pytilities.  If not, see <http://www.gnu.org/licenses/>. 
 17  # 
 18   
 19  """ 
 20  Various decorators to ease delegation 
 21  """ 
 22   
 23  __docformat__ = 'reStructuredText' 
 24   
 25  from types import UnboundMethodType 
 26  import logging 
 27   
 28  from pytilities import mangle 
 29  from . import Profile, DelegatorFactory 
 30   
 31  # logging stuff 
 32  _logger = logging.getLogger("pytilities.delegation") 
 33   
 34  # TODO: remember to check for standard exception classes first before making 
 35  # our own. Check our exception classes, see if we can't replace them with 
 36  # standard exceptions 
 37   
 38  # Note: we don't care about mangling here, there's no need to. You won't be 
 39  # delegating any private vars anyway, or at least you shouldn't. 
 40   
 41  # TODO: the entire bases thing is rather complex, perhaps we should remove it 
 42  # all together and have the user simply use __init_delegation_profiles? 
 43  # For now we'll just leave it up to the user to decide whether or not they want 
 44  # to use that feature 
45 -def delegator_factory(bases=()):
46 """ 47 Makes a `DelegatorFactory` on the class and adds profiles to it. 48 49 The factory is stored as a class attribute with name _delegator_factory. 50 51 `Profile`s are created based on the annotations left by `delegated`. 52 53 After the `Profile`s are created, __init_delegation_profiles(profiles) is 54 called, if it exists. It is a static method found on the decorated class. 55 The `profiles` parameter is of type {name::string: ::Profile}. You can 56 modify the profiles as you like, these are the profiles that will be added 57 to the DelegatorFactory after the call. At the time of this call 58 _delegator_factory does not exist yet. 59 60 Parameters: 61 62 `bases` :: iter(cls...) 63 classes that have a _delegator_factory attribute. Classes that 64 contain base factories for this factory, see `DelegatorFactory` for 65 more info on base factories. 66 """ 67 68 def _delegator_factory(cls): 69 # iterate through attributes and generate profiles 70 # {name: Profile} 71 profiles = {"default": Profile()} # there's always a default 72 for name in cls.__dict__: 73 attribute = getattr(cls, name) 74 75 _logger.debug(name) 76 if isinstance(attribute, property): 77 _logger.debug("prop") 78 data_holder = attribute.fget 79 elif isinstance(attribute, UnboundMethodType): 80 _logger.debug("unbound method!") 81 data_holder = attribute.im_func 82 else: 83 _logger.debug("I have no clue what this is") 84 data_holder = attribute 85 86 if hasattr(data_holder, "__pytilities_delegation_profiles"): 87 _logger.debug("is delegated!") 88 profile_data = data_holder.__pytilities_delegation_profiles 89 for profile_name, modifiers in profile_data.iteritems(): 90 profiles.setdefault(profile_name, Profile()) 91 profiles[profile_name].add_mappings(modifiers, name) 92 93 del data_holder.__pytilities_delegation_profiles 94 95 # call __init_delegation_profile, if any 96 attr_name = mangle(cls.__name__, "__init_delegation_profile") 97 if hasattr(cls, attr_name): 98 getattr(cls, attr_name)(profiles) 99 100 # collect bases 101 factories = tuple( 102 getattr(base, '_delegator_factory') 103 for base in bases) 104 105 # make factory with profiles 106 factory = DelegatorFactory(factories) 107 108 for name, profile in profiles.iteritems(): 109 factory.add_delegator_profile(name, profile) 110 111 # install stuff on cls 112 setattr(cls, "_delegator_factory", factory) 113 cls.add_delegator_profile = factory.add_delegator_profile 114 cls.Delegator = factory.Delegator 115 116 return cls
117 118 return _delegator_factory 119
120 -def delegated(profile_name="default", modifiers="rwd"):
121 """ 122 Includes the decorated attribute in the specified delegation profile. 123 124 Parameters: 125 126 `profile_name` :: string 127 name of the `Profile` to add the attribute to 128 129 `modifiers` :: string 130 the types of access to delegate to the target. Possible modifiers 131 are combinations of: 132 133 - `r`: read 134 - `w`: write 135 - `d`: delete 136 """ 137 138 def _delegate(attribute): 139 _logger.debug("%s += %s" % (profile_name, attribute)) 140 if not hasattr(attribute, "__pytilities_delegator_profiles"): 141 if isinstance(attribute, property): 142 # stick data on the getter function, can't set attribs on 143 # properties 144 data_holder = attribute.fget 145 else: 146 data_holder = attribute 147 148 data_holder.__pytilities_delegation_profiles = {} 149 150 data_holder.__pytilities_delegation_profiles[profile_name] = modifiers 151 152 return attribute
153 154 return _delegate 155 156 # TODO: allow delegator profiles to have some mappings removed 157 158 #TODO: test using this as start of test 159 #@delegator_factory 160 #class B: 161 # @delegate("public") 162 # def f(self, a, b, c): 163 # pass 164