25 from zope.interface import alsoProvides, implementedBy |
25 from zope.interface import alsoProvides, implementedBy |
26 from zope.lifecycleevent import ObjectCreatedEvent |
26 from zope.lifecycleevent import ObjectCreatedEvent |
27 from zope.location import locate as zope_locate |
27 from zope.location import locate as zope_locate |
28 |
28 |
29 from pyams_utils.factory import get_object_factory, is_interface |
29 from pyams_utils.factory import get_object_factory, is_interface |
30 from pyams_utils.registry import get_current_registry |
30 from pyams_utils.registry import get_current_registry, get_global_registry |
31 |
31 |
32 |
32 |
33 __docformat__ = 'restructuredtext' |
33 __docformat__ = 'restructuredtext' |
34 |
34 |
35 logger = logging.getLogger('PyAMS (utils)') |
35 LOGGER = logging.getLogger('PyAMS (utils)') |
36 |
36 |
37 |
37 |
38 class ContextAdapter(object): |
38 class ContextAdapter: |
39 """Context adapter""" |
39 """Context adapter""" |
40 |
40 |
41 def __init__(self, context): |
41 def __init__(self, context): |
42 self.context = context |
42 self.context = context |
43 |
43 |
44 |
44 |
45 class ContextRequestAdapter(object): |
45 class ContextRequestAdapter: |
46 """Context + request multi-adapter""" |
46 """Context + request multi-adapter""" |
47 |
47 |
48 def __init__(self, context, request): |
48 def __init__(self, context, request): |
49 self.context = context |
49 self.context = context |
50 self.request = request |
50 self.request = request |
51 |
51 |
52 |
52 |
53 class ContextRequestViewAdapter(object): |
53 class ContextRequestViewAdapter: |
54 """Context + request + view multi-adapter""" |
54 """Context + request + view multi-adapter""" |
55 |
55 |
56 def __init__(self, context, request, view): |
56 def __init__(self, context, request, view): |
57 self.context = context |
57 self.context = context |
58 self.request = request |
58 self.request = request |
59 self.view = view |
59 self.view = view |
60 |
60 |
61 |
61 |
62 class NullAdapter(object): |
62 class NullAdapter: |
63 """An adapter which always return None! |
63 """An adapter which always return None! |
64 |
64 |
65 Can be useful to override a default adapter... |
65 Can be useful to override a default adapter... |
66 """ |
66 """ |
67 |
67 |
68 def __new__(cls, *arsg, **kwargs): |
68 def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument |
69 return None |
69 return None |
70 |
70 |
71 |
71 |
72 class adapter_config(object): |
72 class adapter_config: # pylint: disable=invalid-name |
73 """Function or class decorator to declare an adapter |
73 """Function or class decorator to declare an adapter |
74 |
74 |
75 Annotation parameters can be: |
75 Annotation parameters can be: |
76 |
76 |
77 :param str='' name: name of the adapter |
77 :param str='' name: name of the adapter |
78 :param [Interface...] context: an interface, or a tuple of interfaces, that the component adapts |
78 :param [Interface...] context: an interface, or a tuple of interfaces, that the component adapts |
79 :param Interface provides: the interface that the adapter provides |
79 :param Interface provides: the interface that the adapter provides |
|
80 :param registry: the registry into which adapter registration should be made |
80 """ |
81 """ |
81 |
82 |
82 venusian = venusian |
83 venusian = venusian |
83 |
84 |
84 def __init__(self, **settings): |
85 def __init__(self, **settings): |
89 |
90 |
90 def __call__(self, wrapped): |
91 def __call__(self, wrapped): |
91 settings = self.__dict__.copy() |
92 settings = self.__dict__.copy() |
92 depth = settings.pop('_depth', 0) |
93 depth = settings.pop('_depth', 0) |
93 |
94 |
94 def callback(context, name, ob): |
95 def callback(context, name, obj): |
95 adapts = settings.get('context') |
96 adapts = settings.get('context') |
96 if adapts is None: |
97 if adapts is None: |
97 adapts = getattr(ob, '__component_adapts__', None) |
98 adapts = getattr(obj, '__component_adapts__', None) |
98 if adapts is None: |
99 if adapts is None: |
99 raise TypeError("No for argument was provided for %r and " |
100 raise TypeError("No for argument was provided for %r and " |
100 "can't determine what the factory adapts." % ob) |
101 "can't determine what the factory adapts." % obj) |
101 if not isinstance(adapts, tuple): |
102 if not isinstance(adapts, tuple): |
102 adapts = (adapts,) |
103 adapts = (adapts,) |
103 |
104 |
104 provides = settings.get('provides') |
105 provides = settings.get('provides') |
105 if provides is None: |
106 if provides is None: |
106 intfs = list(implementedBy(ob)) |
107 intfs = list(implementedBy(obj)) |
107 if len(intfs) == 1: |
108 if len(intfs) == 1: |
108 provides = intfs[0] |
109 provides = intfs[0] |
109 if provides is None: |
110 if provides is None: |
110 raise TypeError("Missing 'provides' argument") |
111 raise TypeError("Missing 'provides' argument") |
111 |
112 |
112 config = context.config.with_package(info.module) |
113 config = context.config.with_package(info.module) # pylint: disable=no-member |
113 logger.debug("Registering adapter {0} for {1} providing {2}".format(str(ob), |
114 LOGGER.debug("Registering adapter %s for %s providing %s", |
114 str(adapts), |
115 str(obj), str(adapts), str(provides)) |
115 str(provides))) |
116 registry = settings.get('registry', config.registry) |
116 config.registry.registerAdapter(ob, adapts, provides, settings.get('name', '')) |
117 registry.registerAdapter(obj, adapts, provides, settings.get('name', '')) |
117 |
118 |
118 info = self.venusian.attach(wrapped, callback, category='pyams_adapter', |
119 info = self.venusian.attach(wrapped, callback, category='pyams_adapter', |
119 depth=depth + 1) |
120 depth=depth + 1) |
120 |
121 |
121 if info.scope == 'class': |
122 if info.scope == 'class': # pylint: disable=no-member |
122 # if the decorator was attached to a method in a class, or |
123 # if the decorator was attached to a method in a class, or |
123 # otherwise executed at class scope, we need to set an |
124 # otherwise executed at class scope, we need to set an |
124 # 'attr' into the settings if one isn't already in there |
125 # 'attr' into the settings if one isn't already in there |
125 if settings.get('attr') is None: |
126 if settings.get('attr') is None: |
126 settings['attr'] = wrapped.__name__ |
127 settings['attr'] = wrapped.__name__ |
127 |
128 |
128 settings['_info'] = info.codeinfo # fbo "action_method" |
129 settings['_info'] = info.codeinfo # pylint: disable=no-member |
129 return wrapped |
130 return wrapped |
130 |
131 |
131 |
132 |
132 def get_annotation_adapter(context, key, factory=None, markers=None, notify=True, |
133 def get_annotation_adapter(context, key, factory=None, markers=None, notify=True, |
133 locate=True, parent=None, name=None, callback=None, **kwargs): |
134 locate=True, parent=None, name=None, callback=None, **kwargs): |
|
135 # pylint: disable=too-many-arguments |
134 """Get an adapter via object's annotations, creating it if not existent |
136 """Get an adapter via object's annotations, creating it if not existent |
135 |
137 |
136 :param object context: context object which should be adapted |
138 :param object context: context object which should be adapted |
137 :param str key: annotations key to look for |
139 :param str key: annotations key to look for |
138 :param factory: if annotations key is not found, this is the factory which will be used to |
140 :param factory: if annotations key is not found, this is the factory which will be used to |
139 create a new object; factory can be a class or callable object, or an interface for which |
141 create a new object; factory can be a class or callable object, or an interface for which |
140 a factory has been registered; if factory is None and is requested object can't be found, |
142 a factory has been registered; if factory is None and is requested object can't be found, |
149 :param callback: if not None, callback function which will be called after object creation |
151 :param callback: if not None, callback function which will be called after object creation |
150 """ |
152 """ |
151 annotations = IAnnotations(context, None) |
153 annotations = IAnnotations(context, None) |
152 if annotations is None: |
154 if annotations is None: |
153 return None |
155 return None |
154 adapter = annotations.get(key) |
156 adapter = annotations.get(key) # pylint: disable=assignment-from-no-return |
155 if adapter is None: |
157 if adapter is None: |
156 if 'default' in kwargs: |
158 if 'default' in kwargs: |
157 return kwargs['default'] |
159 return kwargs['default'] |
158 elif factory is None: |
160 if factory is None: |
159 return None |
161 return None |
160 else: |
162 if is_interface(factory): |
161 if is_interface(factory): |
163 factory = get_object_factory(factory) |
162 factory = get_object_factory(factory) |
164 assert factory is not None, "Missing object factory" |
163 assert factory is not None, "Missing object factory" |
165 adapter = annotations[key] = factory() |
164 adapter = annotations[key] = factory() |
166 if markers: |
165 if markers: |
167 if not isinstance(markers, (list, tuple, set)): |
166 if not isinstance(markers, (list, tuple, set)): |
168 markers = {markers} |
167 markers = {markers} |
169 for marker in markers: |
168 for marker in markers: |
170 alsoProvides(adapter, marker) |
169 alsoProvides(adapter, marker) |
171 if notify: |
170 if notify: |
172 get_current_registry().notify(ObjectCreatedEvent(adapter)) |
171 get_current_registry().notify(ObjectCreatedEvent(adapter)) |
173 if locate: |
172 if locate: |
174 zope_locate(adapter, context if parent is None else parent, name) |
173 zope_locate(adapter, context if parent is None else parent, name) |
175 if callback: |
174 if callback: |
176 callback(adapter) |
175 callback(adapter) |
|
176 return adapter |
177 return adapter |
177 |
178 |
178 |
179 |
179 def get_adapter_weight(item): |
180 def get_adapter_weight(item): |
180 """Get adapters weight sort key""" |
181 """Get adapters weight sort key""" |