Allow to define a custom provider using request annotations
authorThierry Florac <tflorac@ulthar.net>
Wed, 18 Nov 2020 12:59:20 +0100
changeset 59 917951020682
parent 58 aa51effb1d8a
child 60 1d11a4e5ffd8
Allow to define a custom provider using request annotations
src/pyams_viewlet/provider.py
--- a/src/pyams_viewlet/provider.py	Wed Nov 18 12:58:36 2020 +0100
+++ b/src/pyams_viewlet/provider.py	Wed Nov 18 12:59:20 2020 +0100
@@ -16,6 +16,7 @@
 content provider into a Chameleon or ZPT template.
 """
 
+import inspect
 import re
 
 from chameleon.astutil import Symbol
@@ -26,6 +27,7 @@
 from zope.contentprovider.tales import addTALNamespaceData
 from zope.location.interfaces import ILocation
 
+from pyams_utils.factory import is_interface
 from pyams_utils.tales import ContextExprMixin
 
 
@@ -105,7 +107,23 @@
             raise ContentProviderLookupError(name)
 
     registry = request.registry
-    provider = registry.queryMultiAdapter((context, request, view), IContentProvider, name=name)
+
+    # we can look into request annotations to check if a provider implementation has already
+    # been provided during traversal; if not, a simple adapter lookup is done
+    provider = request.annotations.get('provider:{}:factory'.format(name))
+    if isinstance(provider, dict):
+        for intf, factory in provider.items():
+            if (is_interface(intf) and intf.providedBy(context)) or \
+                    (inspect.isclass(intf) and isinstance(context, intf)):
+                provider = factory
+                break
+        else:
+            provider = None
+    if callable(provider):
+        provider = provider(context, request, view)
+    if provider is None:
+        provider = registry.queryMultiAdapter((context, request, view), IContentProvider,
+                                              name=name)
 
     # raise an exception if the provider was not found.
     if provider is None: