1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
32 _logger = logging.getLogger("pytilities.delegation")
33
34
35
36
37
38
39
40
41
42
43
44
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
70
71 profiles = {"default": Profile()}
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
96 attr_name = mangle(cls.__name__, "__init_delegation_profile")
97 if hasattr(cls, attr_name):
98 getattr(cls, attr_name)(profiles)
99
100
101 factories = tuple(
102 getattr(base, '_delegator_factory')
103 for base in bases)
104
105
106 factory = DelegatorFactory(factories)
107
108 for name, profile in profiles.iteritems():
109 factory.add_delegator_profile(name, profile)
110
111
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
143
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
157
158
159
160
161
162
163
164