Commits

Olemis Lang committed 484d0ab

TracBasicMacros: Using info in global `Option`'s cache. Tested for extension options.

  • Participants
  • Parent commits 0f219be

Comments (0)

Files changed (2)

trac-dev/tracbm/tracbm/config.py

 """
 __author__ = 'Olemis Lang'
 
-from trac.core import TracError
-from trac.config import ExtensionOption, OrderedExtensionsOption, _TRUE_VALUES
+from trac.core import TracError, Interface
+from trac.config import *
+from trac.config import _TRUE_VALUES
 from trac.util.text import to_unicode
 from trac.util.translation import _
 from trac.wiki.api import parse_args
                             appropriate format according to the option 
                             type. Supported values are `text`,
                             `bool`, `int`, `list`, `path`, `extension`,
-                            `extension_list`. The `default` is to use 
-                            the information stored in the global 
+                            `extension_list`. Default behavior is `auto` which 
+                            means using the information stored in the global 
                             options cache.
     ''sep'' :               list separator (optional, ignored if 
                             `type`! = `list`).
                             by the option ordered first (optional if type is 
                             `extension_list`).
     """
+    OPTION_MAP = {Option: 'text',
+                    BoolOption: 'bool',
+                    IntOption: 'int',
+                    ListOption: 'list',
+                    PathOption: 'path',
+                    ExtensionOption: 'extension',
+                    OrderedExtensionsOption: 'extension_list',
+                    }
+    
     def expand_macro(self, formatter, name, content):
         # TODO: Implement `type` and `sep` options
         # TODO: Permissions for sections and individual options
             raise TracError(_('Specify both section and option name, and nothing else'))
         else :
             s = s.strip() ; o = o.strip()
-            opt_type = kw.get('type', 'text')
+            opt_type = kw.get('type', 'auto')
             self.log.debug('Rendering config option %s in %s using %s', 
-                            s, o, opt_type)
-            return getattr(self, '_render_' + opt_type, self._do_render_unknown) (s, o, kw)
+                            o, s, opt_type)
+            return getattr(self, '_render_' + opt_type, 
+                                self._do_render_unknown) (s, o, kw)
     
     # Rendering methods
+    def _render_auto(self, s, o, opts):
+        opt = Option.registry.get((s, o))
+        if opt is not None :
+            opt_type = self.OPTION_MAP.get(opt.__class__, 'unknown')
+            if opt_type in ('extension', 'extension_list'):
+                opts.setdefault('interface', opt.xtnpt.interface)
+                cond = getattr(opt, 'include_missing', None) in _TRUE_VALUES
+                opts.setdefault('include_missing', cond and 'true' or '')
+            if opt_type in ('list', 'extension_list'):
+                opts.setdefault('sep', opt.sep)
+                opts.setdefault('keep_empty', opt.keep_empty and 'true' or '')
+            opts['default'] = opt.default
+            return getattr(self, '_render_' + opt_type, 
+                                self._do_render_unknown) (s, o, opts)
+    
     def _render_text(self, s, o, opts):
-        value = self.config.get(s, o, None)
-        if value is not None :
+        value = self.config.get(s, o, opts.get('default'))
+        if value :
             return to_unicode(value)
         else :
             return self._do_render_none(s, o, opts)
     
     def _render_bool(self, s, o, opts):
-        value = self.config.getbool(s, o, None)
-        if value is not None :
-            return tag.input(type="radio", 
-                            checked=value in _TRUE_VALUES and "true" or None, 
-                            disabled="true")
-        else :
-            return self._do_render_none(s, o, opts)
+        value = self.config.getbool(s, o, opts.get('default'))
+        return tag.input(type="radio", 
+                        checked=value in _TRUE_VALUES and "true" or None, 
+                        disabled="true")
     
     def _render_int(self, s, o, opts):
-        value = self.config.getint(s, o, None)
-        if value is not None :
-            return tag.tt(str(value))
-        else :
-            return self._do_render_none(s, o, opts)
+        value = self.config.getint(s, o, opts.get('default'))
+        return tag.tt(str(value))
     
     def _render_list(self, s, o, opts):
         value = self.config.getlist(s, o, None, opts.get('sep', ','), 
                                         opts.get('keep_empty', 'true').lower() in _TRUE_VALUES)
-        if value is not None :
+        if value :
             return tag.o([tag.li(item) for item in value])
         else :
-            return self._do_render_none(s, o, opts)
+            return tag.strike('Empty list')
     
     _render_path = _render_text
     
     def _render_extension(self, s, o, opts):
         try :
-            intf_path = opts['interface']
+            interface = opts.get('interface') or \
+                        Option.registry.get((s, o)).xtnpt.interface
         except :
             raise TracError(_('Keyword argument `interface` is required'))
-        interface = load_interface()
+        if not issubclass(interface, Interface):
+            interface = load_interface(interface)
+        self.log.debug("Rendering extension implementing %s", interface)
         try :
             if s is not None :
                 value = ExtensionOption(s, o, interface, None).__get__(self, self.__class__)
     def _render_extension_list(self, s, o, opts):
         include_missing = opts.get('include_missing', 'true').lower()  in _TRUE_VALUES
         try :
-            intf_path = opts['interface']
+            interface = opts.get('interface') or \
+                        Option.registry.get((s, o)).xtnpt.interface
         except :
             raise TracError(_('Keyword argument `interface` is required'))
-        interface = load_interface()
-        option = OrderedExtensionsOption(s, o, interface, None, include_missing)
+        if not issubclass(interface, Interface):
+            interface = load_interface(interface)
+        opts['interface'] = interface
+        self.log.debug("Listing extensions for %s", interface)
+        option = OrderedExtensionsOption(s, o, interface, include_missing=include_missing)
         components = option.__get__(self, self.__class__)
         if components :
-            return tag.strike(_('Empty list'))
-        else :
             return tag.ol([tag.li(self._render_extension(None, c, opts))] \
                             for c in components)
+        else :
+            return tag.strike(_('Empty list'))
     
     def _do_render_none(self, s, o, opts):
-        return tag.strike(_('Default value'))
+        return tag.strike(_('Missing ?'))
     
     def _do_render_unknown(self, s, o, opts):
         raise TracError(_('Invalid configuration option type'))
+    
+    _render_unknown = _do_render_unknown

trac-dev/tracbm/tracbm/util.py

+
+# Copyright 2009-2011 Olemis Lang <olemis at gmail.com>
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+
+r"""Helper classes and functions
+
+Copyright 2009-2011 Olemis Lang <olemis at gmail.com>
+Licensed under the Apache License
+"""
+__author__ = 'Olemis Lang'
+
+from trac.core import TracError, Interface
+
+from pkg_resources import EntryPoint
+
+def load_object(objpath):
+    r"""Dynamically load an object at a given global object path
+    following `pkg_resources` syntax.
+    """
+    ep = EntryPoint.parse("x=" + objpath)
+    return ep.load(require=False)
+
+def load_interface(objpath):
+    r"""Dynamically load a Trac interface. Raise `TracError` if path 
+    leads to an invalid object.
+    """
+    intf = load_object(objpath)
+    if not isinstance(intf, Interface):
+        raise TracError('Trac interface expected at `%s`' % (objpath,), 
+                        'Invalid object')
+    else :
+        return intf