##// END OF EJS Templates
Added SingletonConfigurable with instance method....
Brian Granger -
Show More
@@ -37,6 +37,9 b' class ConfigurableError(Exception):'
37 pass
37 pass
38
38
39
39
40 class MultipleInstanceError(ConfigurableError):
41 pass
42
40 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
41 # Configurable implementation
44 # Configurable implementation
42 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
@@ -170,4 +173,62 b' class Configurable(HasTraits):'
170 def class_print_help(cls):
173 def class_print_help(cls):
171 print cls.class_get_help()
174 print cls.class_get_help()
172
175
173 No newline at end of file
176
177 class SingletonConfigurable(Configurable):
178 """A configurable that only allows one instance.
179
180 This class is for classes that should only have one instance of itself
181 or *any* subclass. To create and retrieve such a class use the
182 :meth:`SingletonConfigurable.instance` method.
183 """
184
185 _instance = None
186
187 @classmethod
188 def instance(cls, *args, **kwargs):
189 """Returns a global instance of this class.
190
191 This method create a new instance if none have previously been created
192 and returns a previously created instance is one already exists.
193
194 The arguments and keyword arguments passed to this method are passed
195 on to the :meth:`__init__` method of the class upon instantiation.
196
197 Examples
198 --------
199
200 Create a singleton class using instance, and retrieve it::
201
202 >>> from IPython.config.configurable import SingletonConfigurable
203 >>> class Foo(SingletonConfigurable): pass
204 >>> foo = Foo.instance()
205 >>> foo == Foo.instance()
206 True
207
208 Create a subclass that is retrived using the base class instance::
209
210 >>> class Bar(SingletonConfigurable): pass
211 >>> class Bam(Bar): pass
212 >>> bam = Bam.instance()
213 >>> bam == Bar.instance()
214 True
215 """
216 # Create and save the instance
217 if cls._instance is None:
218 inst = cls(*args, **kwargs)
219 # Now make sure that the instance will also be returned by
220 # the subclasses instance attribute.
221 for subclass in cls.mro():
222 if issubclass(cls, subclass) and \
223 issubclass(subclass, SingletonConfigurable) and \
224 subclass != SingletonConfigurable:
225 subclass._instance = inst
226 else:
227 break
228 if isinstance(cls._instance, cls):
229 return cls._instance
230 else:
231 raise MultipleInstanceError(
232 'Multiple incompatible subclass instances of '
233 '%s are being created.' % cls.__name__
234 )
@@ -22,10 +22,15 b' Authors:'
22
22
23 from unittest import TestCase
23 from unittest import TestCase
24
24
25 from IPython.config.configurable import Configurable, ConfigurableError
25 from IPython.config.configurable import (
26 Configurable,
27 SingletonConfigurable
28 )
29
26 from IPython.utils.traitlets import (
30 from IPython.utils.traitlets import (
27 TraitError, Int, Float, Str
31 Int, Float, Str
28 )
32 )
33
29 from IPython.config.loader import Config
34 from IPython.config.loader import Config
30
35
31
36
@@ -57,7 +62,7 b' class Bar(Foo):'
57 c = Float(config=True, shortname="c", help="The string c.")
62 c = Float(config=True, shortname="c", help="The string c.")
58
63
59
64
60 class TestConfigurableConfig(TestCase):
65 class TestConfigurable(TestCase):
61
66
62 def test_default(self):
67 def test_default(self):
63 c1 = Configurable()
68 c1 = Configurable()
@@ -141,3 +146,23 b' class TestConfigurableConfig(TestCase):'
141 def test_help(self):
146 def test_help(self):
142 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
147 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
143
148
149
150 class TestSingletonConfigurable(TestCase):
151
152 def test_instance(self):
153 from IPython.config.configurable import SingletonConfigurable
154 class Foo(SingletonConfigurable): pass
155 foo = Foo.instance()
156 self.assertEquals(foo, Foo.instance())
157 self.assertEquals(SingletonConfigurable._instance, None)
158
159 def test_inheritance(self):
160
161 class Bar(SingletonConfigurable): pass
162 class Bam(Bar): pass
163 bam = Bam.instance()
164 bam == Bar.instance()
165 self.assertEquals(bam, Bam._instance)
166 self.assertEquals(bam, Bar._instance)
167 self.assertEquals(SingletonConfigurable._instance, None)
168 No newline at end of file
@@ -117,7 +117,6 b' class TestKeyValueCL(TestCase):'
117 def test_basic(self):
117 def test_basic(self):
118 cl = KeyValueConfigLoader()
118 cl = KeyValueConfigLoader()
119 argv = [s.strip('c.') for s in pyfile.split('\n')[2:-1]]
119 argv = [s.strip('c.') for s in pyfile.split('\n')[2:-1]]
120 print argv
121 config = cl.load_config(argv)
120 config = cl.load_config(argv)
122 self.assertEquals(config.a, 10)
121 self.assertEquals(config.a, 10)
123 self.assertEquals(config.b, 20)
122 self.assertEquals(config.b, 20)
General Comments 0
You need to be logged in to leave comments. Login now