Commits

Anonymous committed aa71b47

1.1.2dev: Merged [12066:12068] from 1.0-stable (fix for #10285).

Comments (0)

Files changed (4)

             return value
 
     def __set__(self, instance, value):
-        raise AttributeError, 'can\'t set attribute'
+        raise AttributeError(_("Setting attribute is not allowed."))
 
     def __repr__(self):
         return '<%s [%s] "%s">' % (self.__class__.__name__, self.section,
 
 
 class ExtensionOption(Option):
+    """Name of a component implementing `interface`. Raises a
+    `ConfigurationError` if the component cannot be found in the list of
+    active components implementing the interface."""
 
     def __init__(self, section, name, interface, default=None, doc='',
                  doc_domain='tracini'):
         for impl in self.xtnpt.extensions(instance):
             if impl.__class__.__name__ == value:
                 return impl
-        raise AttributeError('Cannot find an implementation of the "%s" '
-                             'interface named "%s".  Please update the option '
-                             '%s.%s in trac.ini.'
-                             % (self.xtnpt.interface.__name__, value,
-                                self.section, self.name))
+        raise ConfigurationError(
+            _('Cannot find an implementation of the "%(interface)s" '
+              'interface named "%(implementation)s".  Please update '
+              'the option %(section)s.%(name)s in trac.ini.',
+              interface=self.xtnpt.interface.__name__, implementation=value,
+              section=self.section, name=self.name))
 
 
 class OrderedExtensionsOption(ListOption):
             return self
         order = ListOption.__get__(self, instance, owner)
         components = []
+        implementing_classes = []
         for impl in self.xtnpt.extensions(instance):
+            implementing_classes.append(impl.__class__.__name__)
             if self.include_missing or impl.__class__.__name__ in order:
                 components.append(impl)
+        not_found = set(order) - set(implementing_classes)
+        if not_found:
+            raise ConfigurationError(
+                _('Cannot find implementation(s) of the "%(interface)s" '
+                  'interface named "%(implementation)s".  Please update '
+                  'the option %(section)s.%(name)s in trac.ini.',
+                  interface=self.xtnpt.interface.__name__,
+                  implementation=', '.join(not_found),
+                  section=self.section, name=self.name))
 
         def compare(x, y):
             x, y = x.__class__.__name__, y.__class__.__name__
 import unittest
 
 from trac.config import *
-from trac.test import Configuration
+from trac.core import Component, Interface, implements
+from trac.test import Configuration, EnvironmentStub
 from trac.util import create_file
 
 
     def setUp(self):
         tmpdir = os.path.realpath(tempfile.gettempdir())
         self.filename = os.path.join(tmpdir, 'trac-test.ini')
+        self.env = EnvironmentStub()
         self._write([])
         self._orig_registry = Option.registry
         Option.registry = {}
         self.assertEquals('1', foo.other)
         self.assertRaises(ConfigurationError, getattr, foo, 'invalid')
 
+    def test_read_and_getextensionoption(self):
+        self._write(['[a]', 'option = ImplA', 'invalid = ImplB'])
+        config = self._read()
+
+        class IDummy(Interface):
+            pass
+
+        class ImplA(Component):
+            implements(IDummy)
+
+        class Foo(Component):
+            default1 = (ExtensionOption)('a', 'default1', IDummy)
+            default2 = (ExtensionOption)('a', 'default2', IDummy, 'ImplA')
+            default3 = (ExtensionOption)('a', 'default3', IDummy, 'ImplB')
+            option = (ExtensionOption)('a', 'option', IDummy)
+            option2 = (ExtensionOption)('a', 'option', IDummy, 'ImplB')
+            invalid = (ExtensionOption)('a', 'invalid', IDummy)
+
+            def __init__(self):
+                self.config = config
+
+        foo = Foo(self.env)
+        self.assertRaises(ConfigurationError, getattr, foo, 'default1')
+        self.assertTrue(isinstance(foo.default2, ImplA))
+        self.assertRaises(ConfigurationError, getattr, foo, 'default3')
+        self.assertTrue(isinstance(foo.option, ImplA))
+        self.assertTrue(isinstance(foo.option2, ImplA))
+        self.assertRaises(ConfigurationError, getattr, foo, 'invalid')
+
+    def test_read_and_getorderedextensionsoption(self):
+        self._write(['[a]', 'option = ImplA, ImplB',
+                     'invalid = ImplB, ImplD'])
+        config = self._read()
+
+        class IDummy(Interface):
+            pass
+
+        class ImplA(Component):
+            implements(IDummy)
+
+        class ImplB(Component):
+            implements(IDummy)
+
+        class ImplC(Component):
+            implements(IDummy)
+
+        class Foo(Component):
+            # enclose in parentheses to avoid messages extraction
+            default1 = (OrderedExtensionsOption)('a', 'default1', IDummy,
+                                                 include_missing=False)
+            default2 = (OrderedExtensionsOption)('a', 'default2', IDummy)
+            default3 = (OrderedExtensionsOption)('a', 'default3', IDummy,
+                                                 'ImplB, ImplC',
+                                                 include_missing=False)
+            option = (OrderedExtensionsOption)('a', 'option', IDummy,
+                                               include_missing=False)
+            invalid = (OrderedExtensionsOption)('a', 'invalid', IDummy)
+
+            def __init__(self):
+                self.config = config
+
+        foo = Foo(self.env)
+        self.assertEqual([], foo.default1)
+        self.assertEqual(3, len(foo.default2))
+        self.assertTrue(isinstance(foo.default2[0], ImplA))
+        self.assertTrue(isinstance(foo.default2[1], ImplB))
+        self.assertTrue(isinstance(foo.default2[2], ImplC))
+        self.assertEqual(2, len(foo.default3))
+        self.assertTrue(isinstance(foo.default3[0], ImplB))
+        self.assertTrue(isinstance(foo.default3[1], ImplC))
+        self.assertEqual(2, len(foo.option))
+        self.assertTrue(isinstance(foo.option[0], ImplA))
+        self.assertTrue(isinstance(foo.option[1], ImplB))
+        self.assertRaises(ConfigurationError, getattr, foo, 'invalid')
+
     def test_getpath(self):
         base = os.path.dirname(self.filename)
         config = self._read()
         self.assertEquals(os.path.join(os.path.dirname(base), 'parentdir.txt'),
                           config.getpath('a', 'path_c'))
 
+    def test_set_raises(self):
+        class Foo(object):
+            option = Option('a', 'option', 'value')
+
+        f = Foo()
+        self.assertRaises(AttributeError, setattr, f, 'option',
+                          Option('a', 'option2', 'value2'))
+
     def test_set_and_save(self):
         config = self._read()
         config.set('b', u'öption0', 'y')
         self.env = EnvironmentStub(enable=[perm.DefaultPermissionStore,
                                            perm.DefaultPermissionPolicy,
                                            TestPermissionRequestor])
+        self.env.config.set('trac', 'permission_policies',
+                            'DefaultPermissionPolicy')
         self.perm_system = perm.PermissionSystem(self.env)
         # by-pass DefaultPermissionPolicy cache:
         perm.DefaultPermissionPolicy.CACHE_EXPIRY = -1

trac/ticket/tests/batch.py

 # individuals. For the exact contribution history, see the revision
 # history and logs, available at http://trac.edgewall.org/log/.
 
-from trac.perm import PermissionCache
+from trac.perm import DefaultPermissionPolicy, DefaultPermissionStore,\
+                      PermissionCache
 from trac.test import Mock, EnvironmentStub
 from trac.ticket import default_workflow, web_ui
 from trac.ticket.batch import BatchModifyModule
     def setUp(self):
         self.env = EnvironmentStub(default_data=True,
             enable=[default_workflow.ConfigurableTicketWorkflow,
+                    DefaultPermissionPolicy, DefaultPermissionStore,
                     web_ui.TicketModule])
+        self.env.config.set('trac', 'permission_policies',
+                            'DefaultPermissionPolicy')
         self.req = Mock(href=self.env.href, authname='anonymous', tz=utc)
         self.req.session = {}
         self.req.perm = PermissionCache(self.env)