8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
10 # FOR A PARTICULAR PURPOSE. |
10 # FOR A PARTICULAR PURPOSE. |
11 # |
11 # |
12 |
12 |
13 __docformat__ = 'restructuredtext' |
13 """PyAMS_viewlet.viewlet module |
|
14 |
|
15 This module provides base content providers and viewlets classes, as well as a decorators |
|
16 which can be used instead of ZCML declarations to register content providers and viewlets. |
|
17 """ |
14 |
18 |
15 import logging |
19 import logging |
16 |
20 |
17 import venusian |
21 import venusian |
18 from pyramid.exceptions import ConfigurationError |
22 from pyramid.exceptions import ConfigurationError |
21 from zope.interface import Interface, implementer |
25 from zope.interface import Interface, implementer |
22 |
26 |
23 from pyams_template.template import get_view_template |
27 from pyams_template.template import get_view_template |
24 from pyams_viewlet.interfaces import IViewlet, IViewletManager |
28 from pyams_viewlet.interfaces import IViewlet, IViewletManager |
25 |
29 |
26 |
30 __docformat__ = 'restructuredtext' |
27 logger = logging.getLogger('PyAMS (viewlet)') |
31 |
|
32 |
|
33 LOGGER = logging.getLogger('PyAMS (viewlet)') |
28 |
34 |
29 |
35 |
30 @implementer(IContentProvider) |
36 @implementer(IContentProvider) |
31 class EmptyContentProvider(object): |
37 class EmptyContentProvider: |
32 """Empty content provider base class""" |
38 """Empty content provider base class""" |
33 |
39 |
34 permission = None |
40 permission = None |
35 |
41 |
36 def __init__(self, context, request): |
42 def __init__(self, context, request): |
37 self.context = context |
43 self.context = context |
38 self.request = request |
44 self.request = request |
39 |
45 |
40 def __call__(self): |
46 def __call__(self): |
41 if self.permission and not self.request.has_permission(self.permission, context=self.context): |
47 if self.permission and not self.request.has_permission(self.permission, |
|
48 context=self.context): |
42 return '' |
49 return '' |
43 self.update() |
50 self.update() |
44 return self.render() |
51 return self.render() |
45 |
52 |
46 def update(self): |
53 def update(self): |
47 pass |
54 """See `IContentProvider` interface""" |
48 |
55 |
49 def render(self): |
56 def render(self): # pylint: disable=no-self-use |
|
57 """See `IContentProvider` interface""" |
50 return '' |
58 return '' |
51 |
59 |
52 |
60 |
53 class BaseContentProvider(EmptyContentProvider): |
61 class BaseContentProvider(EmptyContentProvider): |
54 """Base template based content provider""" |
62 """Base template based content provider""" |
69 def __init__(self, context, request, view): |
77 def __init__(self, context, request, view): |
70 super(ViewContentProvider, self).__init__(context, request) |
78 super(ViewContentProvider, self).__init__(context, request) |
71 self.view = self.__parent__ = view |
79 self.view = self.__parent__ = view |
72 |
80 |
73 |
81 |
74 class contentprovider_config(object): |
82 class contentprovider_config: # pylint: disable=invalid-name |
75 """Class decorator used to declare a content provider |
83 """Class decorator used to declare a content provider |
76 |
84 |
77 You can provide same arguments as in 'viewlet' ZCML directive: |
85 You can provide same arguments as in 'viewlet' ZCML directive: |
78 @name = name of the viewlet; may be unique for a given viewlet manager |
86 @name = name of the viewlet; may be unique for a given viewlet manager |
79 @view = the view class or interface for which viewlet is displayed |
87 @view = the view class or interface for which viewlet is displayed |
93 self.__dict__.update(settings) |
101 self.__dict__.update(settings) |
94 |
102 |
95 def __call__(self, wrapped): |
103 def __call__(self, wrapped): |
96 settings = self.__dict__.copy() |
104 settings = self.__dict__.copy() |
97 |
105 |
98 def callback(context, name, ob): |
106 def callback(context, name, obj): # pylint: disable=unused-argument |
99 cdict = { |
107 cdict = { |
100 '__name__': settings.get('name'), |
108 '__name__': settings.get('name'), |
101 '__module__': ob.__module__ |
109 '__module__': obj.__module__ |
102 } |
110 } |
103 if 'permission' in settings: |
111 if 'permission' in settings: |
104 settings['permission'] = settings.get('permission') |
112 settings['permission'] = settings.get('permission') |
105 |
113 |
106 bases = (ob,) |
114 bases = (obj,) |
107 if not IContentProvider.implementedBy(ob): |
115 if not IContentProvider.implementedBy(obj): # pylint: disable=no-value-for-parameter |
108 bases = bases + (ViewContentProvider,) |
116 bases = bases + (ViewContentProvider,) |
109 new_class = type('<ViewContentProvider %s>' % settings.get('name'), bases, cdict) |
117 new_class = type('<ViewContentProvider %s>' % settings.get('name'), bases, cdict) |
110 |
118 |
111 logger.debug("Registering content provider {0} ({1})".format(settings.get('name'), |
119 LOGGER.debug("Registering content provider {0} ({1})".format(settings.get('name'), |
112 str(new_class))) |
120 str(new_class))) |
113 config = context.config.with_package(info.module) |
121 config = context.config.with_package(info.module) # pylint: disable=no-member |
114 config.registry.registerAdapter(new_class, |
122 config.registry.registerAdapter(new_class, |
115 (settings.get('context', Interface), |
123 (settings.get('context', Interface), |
116 settings.get('layer', IRequest), |
124 settings.get('layer', IRequest), |
117 settings.get('view', IView)), |
125 settings.get('view', IView)), |
118 IContentProvider, settings.get('name')) |
126 IContentProvider, settings.get('name')) |
119 |
127 |
120 info = self.venusian.attach(wrapped, callback, category='pyams_viewlet') |
128 info = self.venusian.attach(wrapped, callback, category='pyams_viewlet') |
121 |
129 |
122 if info.scope == 'class': |
130 if info.scope == 'class': # pylint: disable=no-member |
123 # if the decorator was attached to a method in a class, or |
131 # if the decorator was attached to a method in a class, or |
124 # otherwise executed at class scope, we need to set an |
132 # otherwise executed at class scope, we need to set an |
125 # 'attr' into the settings if one isn't already in there |
133 # 'attr' into the settings if one isn't already in there |
126 if settings.get('attr') is None: |
134 if settings.get('attr') is None: |
127 settings['attr'] = wrapped.__name__ |
135 settings['attr'] = wrapped.__name__ |
128 |
136 |
129 settings['_info'] = info.codeinfo # fbo "action_method" |
137 settings['_info'] = info.codeinfo # pylint: disable=no-member |
130 return wrapped |
138 return wrapped |
131 |
139 |
132 |
140 |
133 @implementer(IViewlet) |
141 @implementer(IViewlet) |
134 class EmptyViewlet(object): |
142 class EmptyViewlet: |
135 """Empty viewlet base class""" |
143 """Empty viewlet base class""" |
136 |
144 |
137 permission = None |
145 permission = None |
138 |
146 |
139 def __init__(self, context, request, view, manager): |
147 def __init__(self, context, request, view, manager): |
141 self.request = request |
149 self.request = request |
142 self.__parent__ = view |
150 self.__parent__ = view |
143 self.manager = manager |
151 self.manager = manager |
144 |
152 |
145 def update(self): |
153 def update(self): |
146 pass |
154 """See `IContentProvider` interface""" |
147 |
155 |
148 def render(self): |
156 def render(self): # pylint: disable=no-self-use |
|
157 """See `IContentProvider` interface""" |
149 return '' |
158 return '' |
150 |
159 |
151 |
160 |
152 class Viewlet(EmptyViewlet): |
161 class Viewlet(EmptyViewlet): |
153 """Viewlet adapter class used in meta directive as a mixin class.""" |
162 """Viewlet adapter class used in meta directive as a mixin class.""" |
154 |
163 |
155 render = get_view_template() |
164 render = get_view_template() |
156 |
165 |
157 |
166 |
158 class viewlet_config(object): |
167 class viewlet_config: # pylint: disable=invalid-name |
159 """Class decorator used to declare a viewlet |
168 """Class decorator used to declare a viewlet |
160 |
169 |
161 You can provide same arguments as in 'viewlet' ZCML directive: |
170 You can provide same arguments as in 'viewlet' ZCML directive: |
162 @name = name of the viewlet; may be unique for a given viewlet manager |
171 @name = name of the viewlet; may be unique for a given viewlet manager |
163 @manager = manager class or interface holding the viewlet |
172 @manager = manager class or interface holding the viewlet |
179 self.__dict__.update(settings) |
188 self.__dict__.update(settings) |
180 |
189 |
181 def __call__(self, wrapped): |
190 def __call__(self, wrapped): |
182 settings = self.__dict__.copy() |
191 settings = self.__dict__.copy() |
183 |
192 |
184 def callback(context, name, ob): |
193 def callback(context, name, obj): # pylint: disable=unused-argument |
185 cdict = { |
194 cdict = { |
186 '__name__': settings.get('name'), |
195 '__name__': settings.get('name'), |
187 '__module__': ob.__module__ |
196 '__module__': obj.__module__ |
188 } |
197 } |
189 if 'permission' in settings: |
198 if 'permission' in settings: |
190 cdict['permission'] = settings.get('permission') |
199 cdict['permission'] = settings.get('permission') |
191 if 'weight' in settings: |
200 if 'weight' in settings: |
192 cdict['weight'] = settings.get('weight') |
201 cdict['weight'] = settings.get('weight') |
193 |
202 |
194 bases = (ob,) |
203 bases = (obj,) |
195 if not IViewlet.implementedBy(ob): |
204 if not IViewlet.implementedBy(obj): # pylint: disable=no-value-for-parameter |
196 bases = bases + (Viewlet,) |
205 bases = bases + (Viewlet,) |
197 new_class = type('<Viewlet %s>' % settings.get('name'), bases, cdict) |
206 new_class = type('<Viewlet %s>' % settings.get('name'), bases, cdict) |
198 |
207 |
199 logger.debug("Registering viewlet {0} ({1})".format(settings.get('name'), |
208 LOGGER.debug("Registering viewlet {0} ({1})".format(settings.get('name'), |
200 str(new_class))) |
209 str(new_class))) |
201 config = context.config.with_package(info.module) |
210 config = context.config.with_package(info.module) # pylint: disable=no-member |
202 config.registry.registerAdapter(new_class, |
211 config.registry.registerAdapter(new_class, |
203 (settings.get('context', Interface), |
212 (settings.get('context', Interface), |
204 settings.get('layer', IRequest), |
213 settings.get('layer', IRequest), |
205 settings.get('view', IView), |
214 settings.get('view', IView), |
206 settings.get('manager', IViewletManager)), |
215 settings.get('manager', IViewletManager)), |
207 IViewlet, settings.get('name')) |
216 IViewlet, settings.get('name')) |
208 |
217 |
209 info = self.venusian.attach(wrapped, callback, category='pyams_viewlet') |
218 info = self.venusian.attach(wrapped, callback, category='pyams_viewlet') |
210 |
219 |
211 if info.scope == 'class': |
220 if info.scope == 'class': # pylint: disable=no-member |
212 # if the decorator was attached to a method in a class, or |
221 # if the decorator was attached to a method in a class, or |
213 # otherwise executed at class scope, we need to set an |
222 # otherwise executed at class scope, we need to set an |
214 # 'attr' into the settings if one isn't already in there |
223 # 'attr' into the settings if one isn't already in there |
215 if settings.get('attr') is None: |
224 if settings.get('attr') is None: |
216 settings['attr'] = wrapped.__name__ |
225 settings['attr'] = wrapped.__name__ |
217 |
226 |
218 settings['_info'] = info.codeinfo # fbo "action_method" |
227 settings['_info'] = info.codeinfo # pylint: disable=no-member |
219 return wrapped |
228 return wrapped |