Show More
@@ -0,0 +1,160 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """Displayhook formatters. | |||
|
3 | ||||
|
4 | The DefaultFormatter is always present and may be configured from the | |||
|
5 | ipython_config.py file. For example, to add a pretty-printer for a numpy.dtype | |||
|
6 | object:: | |||
|
7 | ||||
|
8 | def dtype_pprinter(obj, p, cycle): | |||
|
9 | if cycle: | |||
|
10 | return p.text('dtype(...)') | |||
|
11 | if hasattr(obj, 'fields'): | |||
|
12 | if obj.fields is None: | |||
|
13 | p.text(repr(obj)) | |||
|
14 | else: | |||
|
15 | p.begin_group(7, 'dtype([') | |||
|
16 | for i, field in enumerate(obj.descr): | |||
|
17 | if i > 0: | |||
|
18 | p.text(',') | |||
|
19 | p.breakable() | |||
|
20 | p.pretty(field) | |||
|
21 | p.end_group(7, '])') | |||
|
22 | ||||
|
23 | c.DefaultFormatter.deferred_pprinters = { | |||
|
24 | ('numpy', 'dtype'): dtype_pprinter, | |||
|
25 | } | |||
|
26 | ||||
|
27 | The deferred_pprinters dictionary is the preferred way to configure these | |||
|
28 | pretty-printers. This allows you to define the pretty-printer without needing to | |||
|
29 | import the type itself. The dictionary maps (modulename, typename) pairs to | |||
|
30 | a function. | |||
|
31 | ||||
|
32 | See the `IPython.external.pretty` documentation for how to write | |||
|
33 | pretty-printer functions. | |||
|
34 | ||||
|
35 | Authors: | |||
|
36 | ||||
|
37 | * Robert Kern | |||
|
38 | """ | |||
|
39 | ||||
|
40 | import abc | |||
|
41 | from cStringIO import StringIO | |||
|
42 | ||||
|
43 | from IPython.config.configurable import Configurable | |||
|
44 | from IPython.external import pretty | |||
|
45 | from IPython.utils.traitlets import Bool, Dict, Int, Str | |||
|
46 | ||||
|
47 | ||||
|
48 | class DefaultFormatter(Configurable): | |||
|
49 | """ The default pretty-printer. | |||
|
50 | """ | |||
|
51 | ||||
|
52 | # The ID of the formatter. | |||
|
53 | id = Str('default') | |||
|
54 | ||||
|
55 | # The kind of data returned. | |||
|
56 | # This is often, but not always a MIME type. | |||
|
57 | format = Str('text/plain') | |||
|
58 | ||||
|
59 | # Whether to pretty-print or not. | |||
|
60 | pprint = Bool(True, config=True) | |||
|
61 | ||||
|
62 | # Whether to be verbose or not. | |||
|
63 | verbose = Bool(False, config=True) | |||
|
64 | ||||
|
65 | # The maximum width. | |||
|
66 | max_width = Int(79, config=True) | |||
|
67 | ||||
|
68 | # The newline character. | |||
|
69 | newline = Str('\n', config=True) | |||
|
70 | ||||
|
71 | # The singleton prettyprinters. | |||
|
72 | # Maps the IDs of the builtin singleton objects to the format functions. | |||
|
73 | singleton_pprinters = Dict(config=True) | |||
|
74 | def _singleton_pprinters_default(self): | |||
|
75 | return pretty._singleton_pprinters.copy() | |||
|
76 | ||||
|
77 | # The type-specific prettyprinters. | |||
|
78 | # Map type objects to the format functions. | |||
|
79 | type_pprinters = Dict(config=True) | |||
|
80 | def _type_pprinters_default(self): | |||
|
81 | return pretty._type_pprinters.copy() | |||
|
82 | ||||
|
83 | # The deferred-import type-specific prettyprinters. | |||
|
84 | # Map (modulename, classname) pairs to the format functions. | |||
|
85 | deferred_pprinters = Dict(config=True) | |||
|
86 | def _deferred_pprinters_default(self): | |||
|
87 | return pretty._deferred_type_pprinters.copy() | |||
|
88 | ||||
|
89 | #### FormatterABC interface #### | |||
|
90 | ||||
|
91 | def __call__(self, obj): | |||
|
92 | """ Format the object. | |||
|
93 | """ | |||
|
94 | if not self.pprint: | |||
|
95 | try: | |||
|
96 | return repr(obj) | |||
|
97 | except TypeError: | |||
|
98 | return '' | |||
|
99 | else: | |||
|
100 | stream = StringIO() | |||
|
101 | printer = pretty.RepresentationPrinter(stream, self.verbose, | |||
|
102 | self.max_width, self.newline, | |||
|
103 | singleton_pprinters=self.singleton_pprinters, | |||
|
104 | type_pprinters=self.type_pprinters, | |||
|
105 | deferred_pprinters=self.deferred_pprinters) | |||
|
106 | printer.pretty(obj) | |||
|
107 | printer.flush() | |||
|
108 | return stream.getvalue() | |||
|
109 | ||||
|
110 | ||||
|
111 | #### DefaultFormatter interface #### | |||
|
112 | ||||
|
113 | def for_type(self, typ, func): | |||
|
114 | """ | |||
|
115 | Add a pretty printer for a given type. | |||
|
116 | """ | |||
|
117 | oldfunc = self.type_pprinters.get(typ, None) | |||
|
118 | if func is not None: | |||
|
119 | # To support easy restoration of old pprinters, we need to ignore | |||
|
120 | # Nones. | |||
|
121 | self.type_pprinters[typ] = func | |||
|
122 | return oldfunc | |||
|
123 | ||||
|
124 | def for_type_by_name(self, type_module, type_name, func): | |||
|
125 | """ | |||
|
126 | Add a pretty printer for a type specified by the module and name of | |||
|
127 | a type rather than the type object itself. | |||
|
128 | """ | |||
|
129 | key = (type_module, type_name) | |||
|
130 | oldfunc = self.deferred_pprinters.get(key, None) | |||
|
131 | if func is not None: | |||
|
132 | # To support easy restoration of old pprinters, we need to ignore | |||
|
133 | # Nones. | |||
|
134 | self.deferred_pprinters[key] = func | |||
|
135 | return oldfunc | |||
|
136 | ||||
|
137 | ||||
|
138 | class FormatterABC(object): | |||
|
139 | """ Abstract base class for Formatters. | |||
|
140 | """ | |||
|
141 | __metaclass__ = abc.ABCMeta | |||
|
142 | ||||
|
143 | # The ID of the formatter. | |||
|
144 | id = 'abstract' | |||
|
145 | ||||
|
146 | # The kind of data returned. | |||
|
147 | format = 'text/plain' | |||
|
148 | ||||
|
149 | @abc.abstractmethod | |||
|
150 | def __call__(self, obj): | |||
|
151 | """ Return a JSONable representation of the object. | |||
|
152 | ||||
|
153 | If the object cannot be formatted by this formatter, then return None | |||
|
154 | """ | |||
|
155 | try: | |||
|
156 | return repr(obj) | |||
|
157 | except TypeError: | |||
|
158 | return None | |||
|
159 | ||||
|
160 | FormatterABC.register(DefaultFormatter) |
@@ -0,0 +1,30 b'' | |||||
|
1 | """Tests for the Formatters. | |||
|
2 | """ | |||
|
3 | ||||
|
4 | import nose.tools as nt | |||
|
5 | ||||
|
6 | from IPython.core.formatters import FormatterABC, DefaultFormatter | |||
|
7 | ||||
|
8 | class A(object): | |||
|
9 | def __repr__(self): | |||
|
10 | return 'A()' | |||
|
11 | ||||
|
12 | class B(A): | |||
|
13 | def __repr__(self): | |||
|
14 | return 'B()' | |||
|
15 | ||||
|
16 | def foo_printer(obj, pp, cycle): | |||
|
17 | pp.text('foo') | |||
|
18 | ||||
|
19 | def test_pretty(): | |||
|
20 | f = DefaultFormatter() | |||
|
21 | f.for_type(A, foo_printer) | |||
|
22 | nt.assert_equals(f(A()), 'foo') | |||
|
23 | nt.assert_equals(f(B()), 'foo') | |||
|
24 | f.pprint = False | |||
|
25 | nt.assert_equals(f(A()), 'A()') | |||
|
26 | nt.assert_equals(f(B()), 'B()') | |||
|
27 | ||||
|
28 | def test_deferred(): | |||
|
29 | f = DefaultFormatter() | |||
|
30 |
@@ -20,15 +20,14 b' Authors:' | |||||
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 |
|
21 | |||
22 | import __builtin__ |
|
22 | import __builtin__ | |
23 | from pprint import PrettyPrinter |
|
|||
24 | pformat = PrettyPrinter().pformat |
|
|||
25 |
|
23 | |||
26 | from IPython.config.configurable import Configurable |
|
24 | from IPython.config.configurable import Configurable | |
27 | from IPython.core import prompts |
|
25 | from IPython.core import prompts | |
28 | import IPython.utils.generics |
|
26 | import IPython.utils.generics | |
29 | import IPython.utils.io |
|
27 | import IPython.utils.io | |
30 |
from IPython.utils.traitlets import Instance, |
|
28 | from IPython.utils.traitlets import Instance, List | |
31 | from IPython.utils.warn import warn |
|
29 | from IPython.utils.warn import warn | |
|
30 | from IPython.core.formatters import DefaultFormatter | |||
32 |
|
31 | |||
33 | #----------------------------------------------------------------------------- |
|
32 | #----------------------------------------------------------------------------- | |
34 | # Main displayhook class |
|
33 | # Main displayhook class | |
@@ -55,6 +54,16 b' class DisplayHook(Configurable):' | |||||
55 |
|
54 | |||
56 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
55 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
57 |
|
56 | |||
|
57 | # The default formatter. | |||
|
58 | default_formatter = Instance('IPython.core.formatters.FormatterABC') | |||
|
59 | def _default_formatter_default(self): | |||
|
60 | # FIXME: backwards compatibility for the InteractiveShell.pprint option? | |||
|
61 | return DefaultFormatter(config=self.config) | |||
|
62 | ||||
|
63 | # Any additional FormatterABC instances we use. | |||
|
64 | # FIXME: currently unused. | |||
|
65 | extra_formatters = List(config=True) | |||
|
66 | ||||
58 | # Each call to the In[] prompt raises it by 1, even the first. |
|
67 | # Each call to the In[] prompt raises it by 1, even the first. | |
59 | #prompt_count = Int(0) |
|
68 | #prompt_count = Int(0) | |
60 |
|
69 | |||
@@ -109,7 +118,6 b' class DisplayHook(Configurable):' | |||||
109 | self.output_sep = output_sep |
|
118 | self.output_sep = output_sep | |
110 | self.output_sep2 = output_sep2 |
|
119 | self.output_sep2 = output_sep2 | |
111 | self._,self.__,self.___ = '','','' |
|
120 | self._,self.__,self.___ = '','','' | |
112 | self.pprint_types = map(type,[(),[],{}]) |
|
|||
113 |
|
121 | |||
114 | # these are deliberately global: |
|
122 | # these are deliberately global: | |
115 | to_user_ns = {'_':self._,'__':self.__,'___':self.___} |
|
123 | to_user_ns = {'_':self._,'__':self.__,'___':self.___} | |
@@ -184,39 +192,35 b' class DisplayHook(Configurable):' | |||||
184 | if self.do_full_cache: |
|
192 | if self.do_full_cache: | |
185 | IPython.utils.io.Term.cout.write(outprompt) |
|
193 | IPython.utils.io.Term.cout.write(outprompt) | |
186 |
|
194 | |||
187 | # TODO: Make this method an extension point. The previous implementation |
|
|||
188 | # has both a result_display hook as well as a result_display generic |
|
|||
189 | # function to customize the repr on a per class basis. We need to rethink |
|
|||
190 | # the hooks mechanism before doing this though. |
|
|||
191 | def compute_result_repr(self, result): |
|
195 | def compute_result_repr(self, result): | |
192 | """Compute and return the repr of the object to be displayed. |
|
196 | """Compute and return the repr of the object to be displayed. | |
193 |
|
197 | |||
194 | This method only compute the string form of the repr and should NOT |
|
198 | This method only compute the string form of the repr and should NOT | |
195 |
actual print or write that to a stream. |
|
199 | actual print or write that to a stream. | |
196 | the result itself, but the default implementation passes the original |
|
|||
197 | through. |
|
|||
198 | """ |
|
200 | """ | |
199 | try: |
|
201 | result_repr = self.default_formatter(result) | |
200 | if self.shell.pprint: |
|
202 | if '\n' in result_repr: | |
201 | try: |
|
203 | # So that multi-line strings line up with the left column of | |
202 | result_repr = pformat(result) |
|
204 | # the screen, instead of having the output prompt mess up | |
203 | except: |
|
205 | # their first line. | |
204 | # Work around possible bugs in pformat |
|
206 | outprompt = str(self.prompt_out) | |
205 | result_repr = repr(result) |
|
207 | if outprompt and not outprompt.endswith('\n'): | |
206 | if '\n' in result_repr: |
|
208 | # But avoid extraneous empty lines. | |
207 | # So that multi-line strings line up with the left column of |
|
209 | result_repr = '\n' + result_repr | |
208 | # the screen, instead of having the output prompt mess up |
|
210 | ||
209 | # their first line. |
|
211 | extra_formats = [] | |
210 | result_repr = '\n' + result_repr |
|
212 | for f in self.extra_formatters: | |
211 |
|
|
213 | try: | |
212 |
|
|
214 | data = f(result) | |
213 |
except |
|
215 | except Exception: | |
214 | # This happens when result.__repr__ doesn't return a string, |
|
216 | # FIXME: log the exception. | |
215 | # such as when it returns None. |
|
217 | continue | |
216 | result_repr = '\n' |
|
218 | if data is not None: | |
217 | return result, result_repr |
|
219 | extra_formats.append((f.id, f.format, data)) | |
218 |
|
220 | |||
219 | def write_result_repr(self, result_repr): |
|
221 | return result_repr, extra_formats | |
|
222 | ||||
|
223 | def write_result_repr(self, result_repr, extra_formats): | |||
220 | # We want to print because we want to always make sure we have a |
|
224 | # We want to print because we want to always make sure we have a | |
221 | # newline, even if all the prompt separators are ''. This is the |
|
225 | # newline, even if all the prompt separators are ''. This is the | |
222 | # standard IPython behavior. |
|
226 | # standard IPython behavior. | |
@@ -271,8 +275,8 b' class DisplayHook(Configurable):' | |||||
271 | if result is not None and not self.quiet(): |
|
275 | if result is not None and not self.quiet(): | |
272 | self.start_displayhook() |
|
276 | self.start_displayhook() | |
273 | self.write_output_prompt() |
|
277 | self.write_output_prompt() | |
274 |
result, |
|
278 | result_repr, extra_formats = self.compute_result_repr(result) | |
275 | self.write_result_repr(result_repr) |
|
279 | self.write_result_repr(result_repr, extra_formats) | |
276 | self.update_user_ns(result) |
|
280 | self.update_user_ns(result) | |
277 | self.log_output(result) |
|
281 | self.log_output(result) | |
278 | self.finish_displayhook() |
|
282 | self.finish_displayhook() |
@@ -475,6 +475,7 b' class InteractiveShell(Configurable, Magic):' | |||||
475 | def init_displayhook(self): |
|
475 | def init_displayhook(self): | |
476 | # Initialize displayhook, set in/out prompts and printing system |
|
476 | # Initialize displayhook, set in/out prompts and printing system | |
477 | self.displayhook = self.displayhook_class( |
|
477 | self.displayhook = self.displayhook_class( | |
|
478 | config=self.config, | |||
478 | shell=self, |
|
479 | shell=self, | |
479 | cache_size=self.cache_size, |
|
480 | cache_size=self.cache_size, | |
480 | input_sep = self.separate_in, |
|
481 | input_sep = self.separate_in, |
@@ -306,10 +306,21 b' class RepresentationPrinter(PrettyPrinter):' | |||||
306 | verbose mode. |
|
306 | verbose mode. | |
307 | """ |
|
307 | """ | |
308 |
|
308 | |||
309 |
def __init__(self, output, verbose=False, max_width=79, newline='\n' |
|
309 | def __init__(self, output, verbose=False, max_width=79, newline='\n', | |
|
310 | singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None): | |||
|
311 | ||||
310 | PrettyPrinter.__init__(self, output, max_width, newline) |
|
312 | PrettyPrinter.__init__(self, output, max_width, newline) | |
311 | self.verbose = verbose |
|
313 | self.verbose = verbose | |
312 | self.stack = [] |
|
314 | self.stack = [] | |
|
315 | if singleton_pprinters is None: | |||
|
316 | singleton_pprinters = _singleton_pprinters.copy() | |||
|
317 | self.singleton_pprinters = singleton_pprinters | |||
|
318 | if type_pprinters is None: | |||
|
319 | type_pprinters = _type_pprinters.copy() | |||
|
320 | self.type_pprinters = type_pprinters | |||
|
321 | if deferred_pprinters is None: | |||
|
322 | deferred_pprinters = _deferred_type_pprinters.copy() | |||
|
323 | self.deferred_pprinters = deferred_pprinters | |||
313 |
|
324 | |||
314 | def pretty(self, obj): |
|
325 | def pretty(self, obj): | |
315 | """Pretty print the given object.""" |
|
326 | """Pretty print the given object.""" | |
@@ -322,14 +333,14 b' class RepresentationPrinter(PrettyPrinter):' | |||||
322 | if hasattr(obj_class, '__pretty__'): |
|
333 | if hasattr(obj_class, '__pretty__'): | |
323 | return obj_class.__pretty__(obj, self, cycle) |
|
334 | return obj_class.__pretty__(obj, self, cycle) | |
324 | try: |
|
335 | try: | |
325 |
printer = |
|
336 | printer = self.singleton_pprinters[obj_id] | |
326 | except (TypeError, KeyError): |
|
337 | except (TypeError, KeyError): | |
327 | pass |
|
338 | pass | |
328 | else: |
|
339 | else: | |
329 | return printer(obj, self, cycle) |
|
340 | return printer(obj, self, cycle) | |
330 | for cls in _get_mro(obj_class): |
|
341 | for cls in _get_mro(obj_class): | |
331 |
if cls in |
|
342 | if cls in self.type_pprinters: | |
332 |
return |
|
343 | return self.type_pprinters[cls](obj, self, cycle) | |
333 | else: |
|
344 | else: | |
334 | printer = self._in_deferred_types(cls) |
|
345 | printer = self._in_deferred_types(cls) | |
335 | if printer is not None: |
|
346 | if printer is not None: | |
@@ -351,14 +362,13 b' class RepresentationPrinter(PrettyPrinter):' | |||||
351 | name = getattr(cls, '__name__', None) |
|
362 | name = getattr(cls, '__name__', None) | |
352 | key = (mod, name) |
|
363 | key = (mod, name) | |
353 | printer = None |
|
364 | printer = None | |
354 |
if key in |
|
365 | if key in self.deferred_pprinters: | |
355 | # Move the printer over to the regular registry. |
|
366 | # Move the printer over to the regular registry. | |
356 |
printer = |
|
367 | printer = self.deferred_pprinters.pop(key) | |
357 |
|
|
368 | self.type_pprinters[cls] = printer | |
358 | return printer |
|
369 | return printer | |
359 |
|
370 | |||
360 |
|
371 | |||
361 |
|
||||
362 | class Printable(object): |
|
372 | class Printable(object): | |
363 |
|
373 | |||
364 | def output(self, stream, output_width): |
|
374 | def output(self, stream, output_width): |
@@ -1,11 +1,14 b'' | |||||
1 | """ Defines miscellaneous Qt-related helper classes and functions. |
|
1 | """ Defines miscellaneous Qt-related helper classes and functions. | |
2 | """ |
|
2 | """ | |
3 |
|
3 | |||
|
4 | # Standard library imports. | |||
|
5 | import inspect | |||
|
6 | ||||
4 | # System library imports. |
|
7 | # System library imports. | |
5 | from PyQt4 import QtCore, QtGui |
|
8 | from PyQt4 import QtCore, QtGui | |
6 |
|
9 | |||
7 | # IPython imports. |
|
10 | # IPython imports. | |
8 | from IPython.utils.traitlets import HasTraits |
|
11 | from IPython.utils.traitlets import HasTraits, TraitType | |
9 |
|
12 | |||
10 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
11 | # Metaclasses |
|
14 | # Metaclasses | |
@@ -14,7 +17,6 b' from IPython.utils.traitlets import HasTraits' | |||||
14 | MetaHasTraits = type(HasTraits) |
|
17 | MetaHasTraits = type(HasTraits) | |
15 | MetaQObject = type(QtCore.QObject) |
|
18 | MetaQObject = type(QtCore.QObject) | |
16 |
|
19 | |||
17 | # You can switch the order of the parents here and it doesn't seem to matter. |
|
|||
18 | class MetaQObjectHasTraits(MetaQObject, MetaHasTraits): |
|
20 | class MetaQObjectHasTraits(MetaQObject, MetaHasTraits): | |
19 | """ A metaclass that inherits from the metaclasses of HasTraits and QObject. |
|
21 | """ A metaclass that inherits from the metaclasses of HasTraits and QObject. | |
20 |
|
22 | |||
@@ -22,7 +24,24 b' class MetaQObjectHasTraits(MetaQObject, MetaHasTraits):' | |||||
22 | QObject. Using SuperQObject instead of QObject is highly recommended. See |
|
24 | QObject. Using SuperQObject instead of QObject is highly recommended. See | |
23 | QtKernelManager for an example. |
|
25 | QtKernelManager for an example. | |
24 | """ |
|
26 | """ | |
25 | pass |
|
27 | def __new__(mcls, name, bases, classdict): | |
|
28 | # FIXME: this duplicates the code from MetaHasTraits. | |||
|
29 | # I don't think a super() call will help me here. | |||
|
30 | for k,v in classdict.iteritems(): | |||
|
31 | if isinstance(v, TraitType): | |||
|
32 | v.name = k | |||
|
33 | elif inspect.isclass(v): | |||
|
34 | if issubclass(v, TraitType): | |||
|
35 | vinst = v() | |||
|
36 | vinst.name = k | |||
|
37 | classdict[k] = vinst | |||
|
38 | cls = MetaQObject.__new__(mcls, name, bases, classdict) | |||
|
39 | return cls | |||
|
40 | ||||
|
41 | def __init__(mcls, name, bases, classdict): | |||
|
42 | # Note: super() did not work, so we explicitly call these. | |||
|
43 | MetaQObject.__init__(mcls, name, bases, classdict) | |||
|
44 | MetaHasTraits.__init__(mcls, name, bases, classdict) | |||
26 |
|
45 | |||
27 | #----------------------------------------------------------------------------- |
|
46 | #----------------------------------------------------------------------------- | |
28 | # Classes |
|
47 | # Classes |
@@ -129,6 +129,29 b' class TestTraitType(TestCase):' | |||||
129 | a = A() |
|
129 | a = A() | |
130 | self.assertRaises(TraitError, A.tt.error, a, 10) |
|
130 | self.assertRaises(TraitError, A.tt.error, a, 10) | |
131 |
|
131 | |||
|
132 | def test_dynamic_initializer(self): | |||
|
133 | class A(HasTraits): | |||
|
134 | x = Int(10) | |||
|
135 | def _x_default(self): | |||
|
136 | return 11 | |||
|
137 | class B(A): | |||
|
138 | x = Int(20) | |||
|
139 | class C(A): | |||
|
140 | def _x_default(self): | |||
|
141 | return 21 | |||
|
142 | ||||
|
143 | a = A() | |||
|
144 | self.assertEquals(a._trait_values, {}) | |||
|
145 | self.assertEquals(a.x, 11) | |||
|
146 | self.assertEquals(a._trait_values, {'x': 11}) | |||
|
147 | b = B() | |||
|
148 | self.assertEquals(b._trait_values, {'x': 20}) | |||
|
149 | self.assertEquals(b.x, 20) | |||
|
150 | c = C() | |||
|
151 | self.assertEquals(c._trait_values, {}) | |||
|
152 | self.assertEquals(c.x, 21) | |||
|
153 | self.assertEquals(c._trait_values, {'x': 21}) | |||
|
154 | ||||
132 |
|
155 | |||
133 | class TestHasTraitsMeta(TestCase): |
|
156 | class TestHasTraitsMeta(TestCase): | |
134 |
|
157 |
@@ -248,9 +248,21 b' class TraitType(object):' | |||||
248 | default values must be delayed until the parent :class:`HasTraits` |
|
248 | default values must be delayed until the parent :class:`HasTraits` | |
249 | class has been instantiated. |
|
249 | class has been instantiated. | |
250 | """ |
|
250 | """ | |
251 | dv = self.get_default_value() |
|
251 | # Check for a deferred initializer defined in the same class as the | |
252 | newdv = self._validate(obj, dv) |
|
252 | # trait declaration or above. | |
253 | obj._trait_values[self.name] = newdv |
|
253 | mro = type(obj).mro() | |
|
254 | meth_name = '_%s_default' % self.name | |||
|
255 | for cls in mro[:mro.index(self.this_class)+1]: | |||
|
256 | if meth_name in cls.__dict__: | |||
|
257 | break | |||
|
258 | else: | |||
|
259 | # We didn't find one. Do static initialization. | |||
|
260 | dv = self.get_default_value() | |||
|
261 | newdv = self._validate(obj, dv) | |||
|
262 | obj._trait_values[self.name] = newdv | |||
|
263 | return | |||
|
264 | # Complete the dynamic initialization. | |||
|
265 | self.dynamic_initializer = cls.__dict__[meth_name] | |||
254 |
|
266 | |||
255 | def __get__(self, obj, cls=None): |
|
267 | def __get__(self, obj, cls=None): | |
256 | """Get the value of the trait by self.name for the instance. |
|
268 | """Get the value of the trait by self.name for the instance. | |
@@ -265,7 +277,19 b' class TraitType(object):' | |||||
265 | else: |
|
277 | else: | |
266 | try: |
|
278 | try: | |
267 | value = obj._trait_values[self.name] |
|
279 | value = obj._trait_values[self.name] | |
268 | except: |
|
280 | except KeyError: | |
|
281 | # Check for a dynamic initializer. | |||
|
282 | if hasattr(self, 'dynamic_initializer'): | |||
|
283 | value = self.dynamic_initializer(obj) | |||
|
284 | # FIXME: Do we really validate here? | |||
|
285 | value = self._validate(obj, value) | |||
|
286 | obj._trait_values[self.name] = value | |||
|
287 | return value | |||
|
288 | else: | |||
|
289 | raise TraitError('Unexpected error in TraitType: ' | |||
|
290 | 'both default value and dynamic initializer are ' | |||
|
291 | 'absent.') | |||
|
292 | except Exception: | |||
269 | # HasTraits should call set_default_value to populate |
|
293 | # HasTraits should call set_default_value to populate | |
270 | # this. So this should never be reached. |
|
294 | # this. So this should never be reached. | |
271 | raise TraitError('Unexpected error in TraitType: ' |
|
295 | raise TraitError('Unexpected error in TraitType: ' | |
@@ -294,6 +318,11 b' class TraitType(object):' | |||||
294 | else: |
|
318 | else: | |
295 | return value |
|
319 | return value | |
296 |
|
320 | |||
|
321 | def set_dynamic_initializer(self, method): | |||
|
322 | """ Set the dynamic initializer method, if any. | |||
|
323 | """ | |||
|
324 | self.dynamic_initializer = method | |||
|
325 | ||||
297 | def info(self): |
|
326 | def info(self): | |
298 | return self.info_text |
|
327 | return self.info_text | |
299 |
|
328 |
@@ -65,8 +65,9 b' class ZMQDisplayHook(DisplayHook):' | |||||
65 | if self.do_full_cache: |
|
65 | if self.do_full_cache: | |
66 | self.msg['content']['execution_count'] = self.prompt_count |
|
66 | self.msg['content']['execution_count'] = self.prompt_count | |
67 |
|
67 | |||
68 | def write_result_repr(self, result_repr): |
|
68 | def write_result_repr(self, result_repr, extra_formats): | |
69 | self.msg['content']['data'] = result_repr |
|
69 | self.msg['content']['data'] = result_repr | |
|
70 | self.msg['content']['extra_formats'] = extra_formats | |||
70 |
|
71 | |||
71 | def finish_displayhook(self): |
|
72 | def finish_displayhook(self): | |
72 | """Finish up all displayhook activities.""" |
|
73 | """Finish up all displayhook activities.""" |
@@ -725,16 +725,35 b' case, the kernel instantiates as ``sys.displayhook`` an object which has' | |||||
725 | similar behavior, but which instead of printing to stdout, broadcasts these |
|
725 | similar behavior, but which instead of printing to stdout, broadcasts these | |
726 | values as ``pyout`` messages for clients to display appropriately. |
|
726 | values as ``pyout`` messages for clients to display appropriately. | |
727 |
|
727 | |||
|
728 | IPython's displayhook can handle multiple simultaneous formats depending on its | |||
|
729 | configuration. The default pretty-printed repr text is always given with the | |||
|
730 | ``data`` entry in this message. Any other formats are provided in the | |||
|
731 | ``extra_formats`` list. Frontends are free to display any or all of these | |||
|
732 | according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID | |||
|
733 | string, a type string, and the data. The ID is unique to the formatter | |||
|
734 | implementation that created the data. Frontends will typically ignore the ID | |||
|
735 | unless if it has requested a particular formatter. The type string tells the | |||
|
736 | frontend how to interpret the data. It is often, but not always a MIME type. | |||
|
737 | Frontends should ignore types that it does not understand. The data itself is | |||
|
738 | any JSON object and depends on the format. It is often, but not always a string. | |||
|
739 | ||||
728 | Message type: ``pyout``:: |
|
740 | Message type: ``pyout``:: | |
729 |
|
741 | |||
730 | content = { |
|
742 | content = { | |
731 | # The data is typically the repr() of the object. |
|
743 | # The data is typically the repr() of the object. It should be displayed | |
732 | 'data' : str, |
|
744 | # as monospaced text. | |
|
745 | 'data' : str, | |||
733 |
|
746 | |||
734 | # The counter for this execution is also provided so that clients can |
|
747 | # The counter for this execution is also provided so that clients can | |
735 |
# display it, since IPython automatically creates variables called _N |
|
748 | # display it, since IPython automatically creates variables called _N | |
736 | # prompt N). |
|
749 | # (for prompt N). | |
737 | 'execution_count' : int, |
|
750 | 'execution_count' : int, | |
|
751 | ||||
|
752 | # Any extra formats. | |||
|
753 | # The tuples are of the form (ID, type, data). | |||
|
754 | 'extra_formats' : [ | |||
|
755 | [str, str, object] | |||
|
756 | ] | |||
738 | } |
|
757 | } | |
739 |
|
758 | |||
740 | Python errors |
|
759 | Python errors |
General Comments 0
You need to be logged in to leave comments.
Login now