Show More
@@ -37,6 +37,9 b' class ConfigurableError(Exception):' | |||
|
37 | 37 | pass |
|
38 | 38 | |
|
39 | 39 | |
|
40 | class MultipleInstanceError(ConfigurableError): | |
|
41 | pass | |
|
42 | ||
|
40 | 43 | #----------------------------------------------------------------------------- |
|
41 | 44 | # Configurable implementation |
|
42 | 45 | #----------------------------------------------------------------------------- |
@@ -171,3 +174,61 b' class Configurable(HasTraits):' | |||
|
171 | 174 | print cls.class_get_help() |
|
172 | 175 | |
|
173 | 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 | 23 | from unittest import TestCase |
|
24 | 24 | |
|
25 |
from IPython.config.configurable import |
|
|
25 | from IPython.config.configurable import ( | |
|
26 | Configurable, | |
|
27 | SingletonConfigurable | |
|
28 | ) | |
|
29 | ||
|
26 | 30 | from IPython.utils.traitlets import ( |
|
27 |
|
|
|
31 | Int, Float, Str | |
|
28 | 32 | ) |
|
33 | ||
|
29 | 34 | from IPython.config.loader import Config |
|
30 | 35 | |
|
31 | 36 | |
@@ -57,7 +62,7 b' class Bar(Foo):' | |||
|
57 | 62 | c = Float(config=True, shortname="c", help="The string c.") |
|
58 | 63 | |
|
59 | 64 | |
|
60 |
class TestConfigurable |
|
|
65 | class TestConfigurable(TestCase): | |
|
61 | 66 | |
|
62 | 67 | def test_default(self): |
|
63 | 68 | c1 = Configurable() |
@@ -141,3 +146,23 b' class TestConfigurableConfig(TestCase):' | |||
|
141 | 146 | def test_help(self): |
|
142 | 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 | 117 | def test_basic(self): |
|
118 | 118 | cl = KeyValueConfigLoader() |
|
119 | 119 | argv = [s.strip('c.') for s in pyfile.split('\n')[2:-1]] |
|
120 | print argv | |
|
121 | 120 | config = cl.load_config(argv) |
|
122 | 121 | self.assertEquals(config.a, 10) |
|
123 | 122 | self.assertEquals(config.b, 20) |
General Comments 0
You need to be logged in to leave comments.
Login now