##// END OF EJS Templates
make sentinel class for some kwargs....
Matthias Bussonnier -
Show More
@@ -1,965 +1,972 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Display formatters.
2 """Display formatters.
3
3
4 Inheritance diagram:
4 Inheritance diagram:
5
5
6 .. inheritance-diagram:: IPython.core.formatters
6 .. inheritance-diagram:: IPython.core.formatters
7 :parts: 3
7 :parts: 3
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 import abc
13 import abc
14 import inspect
14 import inspect
15 import json
15 import json
16 import sys
16 import sys
17 import traceback
17 import traceback
18 import warnings
18 import warnings
19
19
20 from decorator import decorator
20 from decorator import decorator
21
21
22 from IPython.config.configurable import Configurable
22 from IPython.config.configurable import Configurable
23 from IPython.core.getipython import get_ipython
23 from IPython.core.getipython import get_ipython
24 from IPython.utils.signatures import Sentinel
24 from IPython.lib import pretty
25 from IPython.lib import pretty
25 from IPython.utils.traitlets import (
26 from IPython.utils.traitlets import (
26 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
27 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
27 ForwardDeclaredInstance,
28 ForwardDeclaredInstance,
28 )
29 )
29 from IPython.utils.py3compat import (
30 from IPython.utils.py3compat import (
30 with_metaclass, string_types, unicode_type,
31 with_metaclass, string_types, unicode_type,
31 )
32 )
32
33
33
34
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35 # The main DisplayFormatter class
36 # The main DisplayFormatter class
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37
38
38
39
39 def _safe_get_formatter_method(obj, name):
40 def _safe_get_formatter_method(obj, name):
40 """Safely get a formatter method
41 """Safely get a formatter method
41
42
42 - Classes cannot have formatter methods, only instance
43 - Classes cannot have formatter methods, only instance
43 - protect against proxy objects that claim to have everything
44 - protect against proxy objects that claim to have everything
44 """
45 """
45 if inspect.isclass(obj):
46 if inspect.isclass(obj):
46 # repr methods only make sense on instances, not classes
47 # repr methods only make sense on instances, not classes
47 return None
48 return None
48 method = pretty._safe_getattr(obj, name, None)
49 method = pretty._safe_getattr(obj, name, None)
49 if callable(method):
50 if callable(method):
50 # obj claims to have repr method...
51 # obj claims to have repr method...
51 if callable(pretty._safe_getattr(obj, '_ipython_canary_method_should_not_exist_', None)):
52 if callable(pretty._safe_getattr(obj, '_ipython_canary_method_should_not_exist_', None)):
52 # ...but don't trust proxy objects that claim to have everything
53 # ...but don't trust proxy objects that claim to have everything
53 return None
54 return None
54 return method
55 return method
55
56
56
57
57 class DisplayFormatter(Configurable):
58 class DisplayFormatter(Configurable):
58
59
59 # When set to true only the default plain text formatter will be used.
60 # When set to true only the default plain text formatter will be used.
60 plain_text_only = Bool(False, config=True)
61 plain_text_only = Bool(False, config=True)
61 def _plain_text_only_changed(self, name, old, new):
62 def _plain_text_only_changed(self, name, old, new):
62 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
63 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
63
64
64 Use DisplayFormatter.active_types = ['text/plain']
65 Use DisplayFormatter.active_types = ['text/plain']
65 for the same effect.
66 for the same effect.
66 """, DeprecationWarning)
67 """, DeprecationWarning)
67 if new:
68 if new:
68 self.active_types = ['text/plain']
69 self.active_types = ['text/plain']
69 else:
70 else:
70 self.active_types = self.format_types
71 self.active_types = self.format_types
71
72
72 active_types = List(Unicode, config=True,
73 active_types = List(Unicode, config=True,
73 help="""List of currently active mime-types to display.
74 help="""List of currently active mime-types to display.
74 You can use this to set a white-list for formats to display.
75 You can use this to set a white-list for formats to display.
75
76
76 Most users will not need to change this value.
77 Most users will not need to change this value.
77 """)
78 """)
78 def _active_types_default(self):
79 def _active_types_default(self):
79 return self.format_types
80 return self.format_types
80
81
81 def _active_types_changed(self, name, old, new):
82 def _active_types_changed(self, name, old, new):
82 for key, formatter in self.formatters.items():
83 for key, formatter in self.formatters.items():
83 if key in new:
84 if key in new:
84 formatter.enabled = True
85 formatter.enabled = True
85 else:
86 else:
86 formatter.enabled = False
87 formatter.enabled = False
87
88
88 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
89 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
89 def _ipython_display_formatter_default(self):
90 def _ipython_display_formatter_default(self):
90 return IPythonDisplayFormatter(parent=self)
91 return IPythonDisplayFormatter(parent=self)
91
92
92 # A dict of formatter whose keys are format types (MIME types) and whose
93 # A dict of formatter whose keys are format types (MIME types) and whose
93 # values are subclasses of BaseFormatter.
94 # values are subclasses of BaseFormatter.
94 formatters = Dict()
95 formatters = Dict()
95 def _formatters_default(self):
96 def _formatters_default(self):
96 """Activate the default formatters."""
97 """Activate the default formatters."""
97 formatter_classes = [
98 formatter_classes = [
98 PlainTextFormatter,
99 PlainTextFormatter,
99 HTMLFormatter,
100 HTMLFormatter,
100 MarkdownFormatter,
101 MarkdownFormatter,
101 SVGFormatter,
102 SVGFormatter,
102 PNGFormatter,
103 PNGFormatter,
103 PDFFormatter,
104 PDFFormatter,
104 JPEGFormatter,
105 JPEGFormatter,
105 LatexFormatter,
106 LatexFormatter,
106 JSONFormatter,
107 JSONFormatter,
107 JavascriptFormatter
108 JavascriptFormatter
108 ]
109 ]
109 d = {}
110 d = {}
110 for cls in formatter_classes:
111 for cls in formatter_classes:
111 f = cls(parent=self)
112 f = cls(parent=self)
112 d[f.format_type] = f
113 d[f.format_type] = f
113 return d
114 return d
114
115
115 def format(self, obj, include=None, exclude=None):
116 def format(self, obj, include=None, exclude=None):
116 """Return a format data dict for an object.
117 """Return a format data dict for an object.
117
118
118 By default all format types will be computed.
119 By default all format types will be computed.
119
120
120 The following MIME types are currently implemented:
121 The following MIME types are currently implemented:
121
122
122 * text/plain
123 * text/plain
123 * text/html
124 * text/html
124 * text/markdown
125 * text/markdown
125 * text/latex
126 * text/latex
126 * application/json
127 * application/json
127 * application/javascript
128 * application/javascript
128 * application/pdf
129 * application/pdf
129 * image/png
130 * image/png
130 * image/jpeg
131 * image/jpeg
131 * image/svg+xml
132 * image/svg+xml
132
133
133 Parameters
134 Parameters
134 ----------
135 ----------
135 obj : object
136 obj : object
136 The Python object whose format data will be computed.
137 The Python object whose format data will be computed.
137 include : list or tuple, optional
138 include : list or tuple, optional
138 A list of format type strings (MIME types) to include in the
139 A list of format type strings (MIME types) to include in the
139 format data dict. If this is set *only* the format types included
140 format data dict. If this is set *only* the format types included
140 in this list will be computed.
141 in this list will be computed.
141 exclude : list or tuple, optional
142 exclude : list or tuple, optional
142 A list of format type string (MIME types) to exclude in the format
143 A list of format type string (MIME types) to exclude in the format
143 data dict. If this is set all format types will be computed,
144 data dict. If this is set all format types will be computed,
144 except for those included in this argument.
145 except for those included in this argument.
145
146
146 Returns
147 Returns
147 -------
148 -------
148 (format_dict, metadata_dict) : tuple of two dicts
149 (format_dict, metadata_dict) : tuple of two dicts
149
150
150 format_dict is a dictionary of key/value pairs, one of each format that was
151 format_dict is a dictionary of key/value pairs, one of each format that was
151 generated for the object. The keys are the format types, which
152 generated for the object. The keys are the format types, which
152 will usually be MIME type strings and the values and JSON'able
153 will usually be MIME type strings and the values and JSON'able
153 data structure containing the raw data for the representation in
154 data structure containing the raw data for the representation in
154 that format.
155 that format.
155
156
156 metadata_dict is a dictionary of metadata about each mime-type output.
157 metadata_dict is a dictionary of metadata about each mime-type output.
157 Its keys will be a strict subset of the keys in format_dict.
158 Its keys will be a strict subset of the keys in format_dict.
158 """
159 """
159 format_dict = {}
160 format_dict = {}
160 md_dict = {}
161 md_dict = {}
161
162
162 if self.ipython_display_formatter(obj):
163 if self.ipython_display_formatter(obj):
163 # object handled itself, don't proceed
164 # object handled itself, don't proceed
164 return {}, {}
165 return {}, {}
165
166
166 for format_type, formatter in self.formatters.items():
167 for format_type, formatter in self.formatters.items():
167 if include and format_type not in include:
168 if include and format_type not in include:
168 continue
169 continue
169 if exclude and format_type in exclude:
170 if exclude and format_type in exclude:
170 continue
171 continue
171
172
172 md = None
173 md = None
173 try:
174 try:
174 data = formatter(obj)
175 data = formatter(obj)
175 except:
176 except:
176 # FIXME: log the exception
177 # FIXME: log the exception
177 raise
178 raise
178
179
179 # formatters can return raw data or (data, metadata)
180 # formatters can return raw data or (data, metadata)
180 if isinstance(data, tuple) and len(data) == 2:
181 if isinstance(data, tuple) and len(data) == 2:
181 data, md = data
182 data, md = data
182
183
183 if data is not None:
184 if data is not None:
184 format_dict[format_type] = data
185 format_dict[format_type] = data
185 if md is not None:
186 if md is not None:
186 md_dict[format_type] = md
187 md_dict[format_type] = md
187
188
188 return format_dict, md_dict
189 return format_dict, md_dict
189
190
190 @property
191 @property
191 def format_types(self):
192 def format_types(self):
192 """Return the format types (MIME types) of the active formatters."""
193 """Return the format types (MIME types) of the active formatters."""
193 return list(self.formatters.keys())
194 return list(self.formatters.keys())
194
195
195
196
196 #-----------------------------------------------------------------------------
197 #-----------------------------------------------------------------------------
197 # Formatters for specific format types (text, html, svg, etc.)
198 # Formatters for specific format types (text, html, svg, etc.)
198 #-----------------------------------------------------------------------------
199 #-----------------------------------------------------------------------------
199
200
200
201
201 def _safe_repr(obj):
202 def _safe_repr(obj):
202 """Try to return a repr of an object
203 """Try to return a repr of an object
203
204
204 always returns a string, at least.
205 always returns a string, at least.
205 """
206 """
206 try:
207 try:
207 return repr(obj)
208 return repr(obj)
208 except Exception as e:
209 except Exception as e:
209 return "un-repr-able object (%r)" % e
210 return "un-repr-able object (%r)" % e
210
211
211
212
212 class FormatterWarning(UserWarning):
213 class FormatterWarning(UserWarning):
213 """Warning class for errors in formatters"""
214 """Warning class for errors in formatters"""
214
215
215 @decorator
216 @decorator
216 def catch_format_error(method, self, *args, **kwargs):
217 def catch_format_error(method, self, *args, **kwargs):
217 """show traceback on failed format call"""
218 """show traceback on failed format call"""
218 try:
219 try:
219 r = method(self, *args, **kwargs)
220 r = method(self, *args, **kwargs)
220 except NotImplementedError:
221 except NotImplementedError:
221 # don't warn on NotImplementedErrors
222 # don't warn on NotImplementedErrors
222 return None
223 return None
223 except Exception:
224 except Exception:
224 exc_info = sys.exc_info()
225 exc_info = sys.exc_info()
225 ip = get_ipython()
226 ip = get_ipython()
226 if ip is not None:
227 if ip is not None:
227 ip.showtraceback(exc_info)
228 ip.showtraceback(exc_info)
228 else:
229 else:
229 traceback.print_exception(*exc_info)
230 traceback.print_exception(*exc_info)
230 return None
231 return None
231 return self._check_return(r, args[0])
232 return self._check_return(r, args[0])
232
233
233
234
234 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
235 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
235 """ Abstract base class for Formatters.
236 """ Abstract base class for Formatters.
236
237
237 A formatter is a callable class that is responsible for computing the
238 A formatter is a callable class that is responsible for computing the
238 raw format data for a particular format type (MIME type). For example,
239 raw format data for a particular format type (MIME type). For example,
239 an HTML formatter would have a format type of `text/html` and would return
240 an HTML formatter would have a format type of `text/html` and would return
240 the HTML representation of the object when called.
241 the HTML representation of the object when called.
241 """
242 """
242
243
243 # The format type of the data returned, usually a MIME type.
244 # The format type of the data returned, usually a MIME type.
244 format_type = 'text/plain'
245 format_type = 'text/plain'
245
246
246 # Is the formatter enabled...
247 # Is the formatter enabled...
247 enabled = True
248 enabled = True
248
249
249 @abc.abstractmethod
250 @abc.abstractmethod
250 def __call__(self, obj):
251 def __call__(self, obj):
251 """Return a JSON'able representation of the object.
252 """Return a JSON'able representation of the object.
252
253
253 If the object cannot be formatted by this formatter,
254 If the object cannot be formatted by this formatter,
254 warn and return None.
255 warn and return None.
255 """
256 """
256 return repr(obj)
257 return repr(obj)
257
258
258
259
259 def _mod_name_key(typ):
260 def _mod_name_key(typ):
260 """Return a (__module__, __name__) tuple for a type.
261 """Return a (__module__, __name__) tuple for a type.
261
262
262 Used as key in Formatter.deferred_printers.
263 Used as key in Formatter.deferred_printers.
263 """
264 """
264 module = getattr(typ, '__module__', None)
265 module = getattr(typ, '__module__', None)
265 name = getattr(typ, '__name__', None)
266 name = getattr(typ, '__name__', None)
266 return (module, name)
267 return (module, name)
267
268
268
269
269 def _get_type(obj):
270 def _get_type(obj):
270 """Return the type of an instance (old and new-style)"""
271 """Return the type of an instance (old and new-style)"""
271 return getattr(obj, '__class__', None) or type(obj)
272 return getattr(obj, '__class__', None) or type(obj)
272
273
273 _raise_key_error = object()
274
275 _raise_key_error = Sentinel('_raise_key_error', __name__,
276 """
277 Special value to raise a KeyError
278
279 Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
280 """)
274
281
275
282
276 class BaseFormatter(Configurable):
283 class BaseFormatter(Configurable):
277 """A base formatter class that is configurable.
284 """A base formatter class that is configurable.
278
285
279 This formatter should usually be used as the base class of all formatters.
286 This formatter should usually be used as the base class of all formatters.
280 It is a traited :class:`Configurable` class and includes an extensible
287 It is a traited :class:`Configurable` class and includes an extensible
281 API for users to determine how their objects are formatted. The following
288 API for users to determine how their objects are formatted. The following
282 logic is used to find a function to format an given object.
289 logic is used to find a function to format an given object.
283
290
284 1. The object is introspected to see if it has a method with the name
291 1. The object is introspected to see if it has a method with the name
285 :attr:`print_method`. If is does, that object is passed to that method
292 :attr:`print_method`. If is does, that object is passed to that method
286 for formatting.
293 for formatting.
287 2. If no print method is found, three internal dictionaries are consulted
294 2. If no print method is found, three internal dictionaries are consulted
288 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
295 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
289 and :attr:`deferred_printers`.
296 and :attr:`deferred_printers`.
290
297
291 Users should use these dictionaries to register functions that will be
298 Users should use these dictionaries to register functions that will be
292 used to compute the format data for their objects (if those objects don't
299 used to compute the format data for their objects (if those objects don't
293 have the special print methods). The easiest way of using these
300 have the special print methods). The easiest way of using these
294 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
301 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
295 methods.
302 methods.
296
303
297 If no function/callable is found to compute the format data, ``None`` is
304 If no function/callable is found to compute the format data, ``None`` is
298 returned and this format type is not used.
305 returned and this format type is not used.
299 """
306 """
300
307
301 format_type = Unicode('text/plain')
308 format_type = Unicode('text/plain')
302 _return_type = string_types
309 _return_type = string_types
303
310
304 enabled = Bool(True, config=True)
311 enabled = Bool(True, config=True)
305
312
306 print_method = ObjectName('__repr__')
313 print_method = ObjectName('__repr__')
307
314
308 # The singleton printers.
315 # The singleton printers.
309 # Maps the IDs of the builtin singleton objects to the format functions.
316 # Maps the IDs of the builtin singleton objects to the format functions.
310 singleton_printers = Dict(config=True)
317 singleton_printers = Dict(config=True)
311
318
312 # The type-specific printers.
319 # The type-specific printers.
313 # Map type objects to the format functions.
320 # Map type objects to the format functions.
314 type_printers = Dict(config=True)
321 type_printers = Dict(config=True)
315
322
316 # The deferred-import type-specific printers.
323 # The deferred-import type-specific printers.
317 # Map (modulename, classname) pairs to the format functions.
324 # Map (modulename, classname) pairs to the format functions.
318 deferred_printers = Dict(config=True)
325 deferred_printers = Dict(config=True)
319
326
320 @catch_format_error
327 @catch_format_error
321 def __call__(self, obj):
328 def __call__(self, obj):
322 """Compute the format for an object."""
329 """Compute the format for an object."""
323 if self.enabled:
330 if self.enabled:
324 # lookup registered printer
331 # lookup registered printer
325 try:
332 try:
326 printer = self.lookup(obj)
333 printer = self.lookup(obj)
327 except KeyError:
334 except KeyError:
328 pass
335 pass
329 else:
336 else:
330 return printer(obj)
337 return printer(obj)
331 # Finally look for special method names
338 # Finally look for special method names
332 method = _safe_get_formatter_method(obj, self.print_method)
339 method = _safe_get_formatter_method(obj, self.print_method)
333 if method is not None:
340 if method is not None:
334 return method()
341 return method()
335 return None
342 return None
336 else:
343 else:
337 return None
344 return None
338
345
339 def __contains__(self, typ):
346 def __contains__(self, typ):
340 """map in to lookup_by_type"""
347 """map in to lookup_by_type"""
341 try:
348 try:
342 self.lookup_by_type(typ)
349 self.lookup_by_type(typ)
343 except KeyError:
350 except KeyError:
344 return False
351 return False
345 else:
352 else:
346 return True
353 return True
347
354
348 def _check_return(self, r, obj):
355 def _check_return(self, r, obj):
349 """Check that a return value is appropriate
356 """Check that a return value is appropriate
350
357
351 Return the value if so, None otherwise, warning if invalid.
358 Return the value if so, None otherwise, warning if invalid.
352 """
359 """
353 if r is None or isinstance(r, self._return_type) or \
360 if r is None or isinstance(r, self._return_type) or \
354 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
361 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
355 return r
362 return r
356 else:
363 else:
357 warnings.warn(
364 warnings.warn(
358 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
365 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
359 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
366 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
360 FormatterWarning
367 FormatterWarning
361 )
368 )
362
369
363 def lookup(self, obj):
370 def lookup(self, obj):
364 """Look up the formatter for a given instance.
371 """Look up the formatter for a given instance.
365
372
366 Parameters
373 Parameters
367 ----------
374 ----------
368 obj : object instance
375 obj : object instance
369
376
370 Returns
377 Returns
371 -------
378 -------
372 f : callable
379 f : callable
373 The registered formatting callable for the type.
380 The registered formatting callable for the type.
374
381
375 Raises
382 Raises
376 ------
383 ------
377 KeyError if the type has not been registered.
384 KeyError if the type has not been registered.
378 """
385 """
379 # look for singleton first
386 # look for singleton first
380 obj_id = id(obj)
387 obj_id = id(obj)
381 if obj_id in self.singleton_printers:
388 if obj_id in self.singleton_printers:
382 return self.singleton_printers[obj_id]
389 return self.singleton_printers[obj_id]
383 # then lookup by type
390 # then lookup by type
384 return self.lookup_by_type(_get_type(obj))
391 return self.lookup_by_type(_get_type(obj))
385
392
386 def lookup_by_type(self, typ):
393 def lookup_by_type(self, typ):
387 """Look up the registered formatter for a type.
394 """Look up the registered formatter for a type.
388
395
389 Parameters
396 Parameters
390 ----------
397 ----------
391 typ : type or '__module__.__name__' string for a type
398 typ : type or '__module__.__name__' string for a type
392
399
393 Returns
400 Returns
394 -------
401 -------
395 f : callable
402 f : callable
396 The registered formatting callable for the type.
403 The registered formatting callable for the type.
397
404
398 Raises
405 Raises
399 ------
406 ------
400 KeyError if the type has not been registered.
407 KeyError if the type has not been registered.
401 """
408 """
402 if isinstance(typ, string_types):
409 if isinstance(typ, string_types):
403 typ_key = tuple(typ.rsplit('.',1))
410 typ_key = tuple(typ.rsplit('.',1))
404 if typ_key not in self.deferred_printers:
411 if typ_key not in self.deferred_printers:
405 # We may have it cached in the type map. We will have to
412 # We may have it cached in the type map. We will have to
406 # iterate over all of the types to check.
413 # iterate over all of the types to check.
407 for cls in self.type_printers:
414 for cls in self.type_printers:
408 if _mod_name_key(cls) == typ_key:
415 if _mod_name_key(cls) == typ_key:
409 return self.type_printers[cls]
416 return self.type_printers[cls]
410 else:
417 else:
411 return self.deferred_printers[typ_key]
418 return self.deferred_printers[typ_key]
412 else:
419 else:
413 for cls in pretty._get_mro(typ):
420 for cls in pretty._get_mro(typ):
414 if cls in self.type_printers or self._in_deferred_types(cls):
421 if cls in self.type_printers or self._in_deferred_types(cls):
415 return self.type_printers[cls]
422 return self.type_printers[cls]
416
423
417 # If we have reached here, the lookup failed.
424 # If we have reached here, the lookup failed.
418 raise KeyError("No registered printer for {0!r}".format(typ))
425 raise KeyError("No registered printer for {0!r}".format(typ))
419
426
420 def for_type(self, typ, func=None):
427 def for_type(self, typ, func=None):
421 """Add a format function for a given type.
428 """Add a format function for a given type.
422
429
423 Parameters
430 Parameters
424 -----------
431 -----------
425 typ : type or '__module__.__name__' string for a type
432 typ : type or '__module__.__name__' string for a type
426 The class of the object that will be formatted using `func`.
433 The class of the object that will be formatted using `func`.
427 func : callable
434 func : callable
428 A callable for computing the format data.
435 A callable for computing the format data.
429 `func` will be called with the object to be formatted,
436 `func` will be called with the object to be formatted,
430 and will return the raw data in this formatter's format.
437 and will return the raw data in this formatter's format.
431 Subclasses may use a different call signature for the
438 Subclasses may use a different call signature for the
432 `func` argument.
439 `func` argument.
433
440
434 If `func` is None or not specified, there will be no change,
441 If `func` is None or not specified, there will be no change,
435 only returning the current value.
442 only returning the current value.
436
443
437 Returns
444 Returns
438 -------
445 -------
439 oldfunc : callable
446 oldfunc : callable
440 The currently registered callable.
447 The currently registered callable.
441 If you are registering a new formatter,
448 If you are registering a new formatter,
442 this will be the previous value (to enable restoring later).
449 this will be the previous value (to enable restoring later).
443 """
450 """
444 # if string given, interpret as 'pkg.module.class_name'
451 # if string given, interpret as 'pkg.module.class_name'
445 if isinstance(typ, string_types):
452 if isinstance(typ, string_types):
446 type_module, type_name = typ.rsplit('.', 1)
453 type_module, type_name = typ.rsplit('.', 1)
447 return self.for_type_by_name(type_module, type_name, func)
454 return self.for_type_by_name(type_module, type_name, func)
448
455
449 try:
456 try:
450 oldfunc = self.lookup_by_type(typ)
457 oldfunc = self.lookup_by_type(typ)
451 except KeyError:
458 except KeyError:
452 oldfunc = None
459 oldfunc = None
453
460
454 if func is not None:
461 if func is not None:
455 self.type_printers[typ] = func
462 self.type_printers[typ] = func
456
463
457 return oldfunc
464 return oldfunc
458
465
459 def for_type_by_name(self, type_module, type_name, func=None):
466 def for_type_by_name(self, type_module, type_name, func=None):
460 """Add a format function for a type specified by the full dotted
467 """Add a format function for a type specified by the full dotted
461 module and name of the type, rather than the type of the object.
468 module and name of the type, rather than the type of the object.
462
469
463 Parameters
470 Parameters
464 ----------
471 ----------
465 type_module : str
472 type_module : str
466 The full dotted name of the module the type is defined in, like
473 The full dotted name of the module the type is defined in, like
467 ``numpy``.
474 ``numpy``.
468 type_name : str
475 type_name : str
469 The name of the type (the class name), like ``dtype``
476 The name of the type (the class name), like ``dtype``
470 func : callable
477 func : callable
471 A callable for computing the format data.
478 A callable for computing the format data.
472 `func` will be called with the object to be formatted,
479 `func` will be called with the object to be formatted,
473 and will return the raw data in this formatter's format.
480 and will return the raw data in this formatter's format.
474 Subclasses may use a different call signature for the
481 Subclasses may use a different call signature for the
475 `func` argument.
482 `func` argument.
476
483
477 If `func` is None or unspecified, there will be no change,
484 If `func` is None or unspecified, there will be no change,
478 only returning the current value.
485 only returning the current value.
479
486
480 Returns
487 Returns
481 -------
488 -------
482 oldfunc : callable
489 oldfunc : callable
483 The currently registered callable.
490 The currently registered callable.
484 If you are registering a new formatter,
491 If you are registering a new formatter,
485 this will be the previous value (to enable restoring later).
492 this will be the previous value (to enable restoring later).
486 """
493 """
487 key = (type_module, type_name)
494 key = (type_module, type_name)
488
495
489 try:
496 try:
490 oldfunc = self.lookup_by_type("%s.%s" % key)
497 oldfunc = self.lookup_by_type("%s.%s" % key)
491 except KeyError:
498 except KeyError:
492 oldfunc = None
499 oldfunc = None
493
500
494 if func is not None:
501 if func is not None:
495 self.deferred_printers[key] = func
502 self.deferred_printers[key] = func
496 return oldfunc
503 return oldfunc
497
504
498 def pop(self, typ, default=_raise_key_error):
505 def pop(self, typ, default=_raise_key_error):
499 """Pop a formatter for the given type.
506 """Pop a formatter for the given type.
500
507
501 Parameters
508 Parameters
502 ----------
509 ----------
503 typ : type or '__module__.__name__' string for a type
510 typ : type or '__module__.__name__' string for a type
504 default : object
511 default : object
505 value to be returned if no formatter is registered for typ.
512 value to be returned if no formatter is registered for typ.
506
513
507 Returns
514 Returns
508 -------
515 -------
509 obj : object
516 obj : object
510 The last registered object for the type.
517 The last registered object for the type.
511
518
512 Raises
519 Raises
513 ------
520 ------
514 KeyError if the type is not registered and default is not specified.
521 KeyError if the type is not registered and default is not specified.
515 """
522 """
516
523
517 if isinstance(typ, string_types):
524 if isinstance(typ, string_types):
518 typ_key = tuple(typ.rsplit('.',1))
525 typ_key = tuple(typ.rsplit('.',1))
519 if typ_key not in self.deferred_printers:
526 if typ_key not in self.deferred_printers:
520 # We may have it cached in the type map. We will have to
527 # We may have it cached in the type map. We will have to
521 # iterate over all of the types to check.
528 # iterate over all of the types to check.
522 for cls in self.type_printers:
529 for cls in self.type_printers:
523 if _mod_name_key(cls) == typ_key:
530 if _mod_name_key(cls) == typ_key:
524 old = self.type_printers.pop(cls)
531 old = self.type_printers.pop(cls)
525 break
532 break
526 else:
533 else:
527 old = default
534 old = default
528 else:
535 else:
529 old = self.deferred_printers.pop(typ_key)
536 old = self.deferred_printers.pop(typ_key)
530 else:
537 else:
531 if typ in self.type_printers:
538 if typ in self.type_printers:
532 old = self.type_printers.pop(typ)
539 old = self.type_printers.pop(typ)
533 else:
540 else:
534 old = self.deferred_printers.pop(_mod_name_key(typ), default)
541 old = self.deferred_printers.pop(_mod_name_key(typ), default)
535 if old is _raise_key_error:
542 if old is _raise_key_error:
536 raise KeyError("No registered value for {0!r}".format(typ))
543 raise KeyError("No registered value for {0!r}".format(typ))
537 return old
544 return old
538
545
539 def _in_deferred_types(self, cls):
546 def _in_deferred_types(self, cls):
540 """
547 """
541 Check if the given class is specified in the deferred type registry.
548 Check if the given class is specified in the deferred type registry.
542
549
543 Successful matches will be moved to the regular type registry for future use.
550 Successful matches will be moved to the regular type registry for future use.
544 """
551 """
545 mod = getattr(cls, '__module__', None)
552 mod = getattr(cls, '__module__', None)
546 name = getattr(cls, '__name__', None)
553 name = getattr(cls, '__name__', None)
547 key = (mod, name)
554 key = (mod, name)
548 if key in self.deferred_printers:
555 if key in self.deferred_printers:
549 # Move the printer over to the regular registry.
556 # Move the printer over to the regular registry.
550 printer = self.deferred_printers.pop(key)
557 printer = self.deferred_printers.pop(key)
551 self.type_printers[cls] = printer
558 self.type_printers[cls] = printer
552 return True
559 return True
553 return False
560 return False
554
561
555
562
556 class PlainTextFormatter(BaseFormatter):
563 class PlainTextFormatter(BaseFormatter):
557 """The default pretty-printer.
564 """The default pretty-printer.
558
565
559 This uses :mod:`IPython.lib.pretty` to compute the format data of
566 This uses :mod:`IPython.lib.pretty` to compute the format data of
560 the object. If the object cannot be pretty printed, :func:`repr` is used.
567 the object. If the object cannot be pretty printed, :func:`repr` is used.
561 See the documentation of :mod:`IPython.lib.pretty` for details on
568 See the documentation of :mod:`IPython.lib.pretty` for details on
562 how to write pretty printers. Here is a simple example::
569 how to write pretty printers. Here is a simple example::
563
570
564 def dtype_pprinter(obj, p, cycle):
571 def dtype_pprinter(obj, p, cycle):
565 if cycle:
572 if cycle:
566 return p.text('dtype(...)')
573 return p.text('dtype(...)')
567 if hasattr(obj, 'fields'):
574 if hasattr(obj, 'fields'):
568 if obj.fields is None:
575 if obj.fields is None:
569 p.text(repr(obj))
576 p.text(repr(obj))
570 else:
577 else:
571 p.begin_group(7, 'dtype([')
578 p.begin_group(7, 'dtype([')
572 for i, field in enumerate(obj.descr):
579 for i, field in enumerate(obj.descr):
573 if i > 0:
580 if i > 0:
574 p.text(',')
581 p.text(',')
575 p.breakable()
582 p.breakable()
576 p.pretty(field)
583 p.pretty(field)
577 p.end_group(7, '])')
584 p.end_group(7, '])')
578 """
585 """
579
586
580 # The format type of data returned.
587 # The format type of data returned.
581 format_type = Unicode('text/plain')
588 format_type = Unicode('text/plain')
582
589
583 # This subclass ignores this attribute as it always need to return
590 # This subclass ignores this attribute as it always need to return
584 # something.
591 # something.
585 enabled = Bool(True, config=False)
592 enabled = Bool(True, config=False)
586
593
587 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH, config=True,
594 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH, config=True,
588 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
595 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
589
596
590 Set to 0 to disable truncation.
597 Set to 0 to disable truncation.
591 """
598 """
592 )
599 )
593
600
594 # Look for a _repr_pretty_ methods to use for pretty printing.
601 # Look for a _repr_pretty_ methods to use for pretty printing.
595 print_method = ObjectName('_repr_pretty_')
602 print_method = ObjectName('_repr_pretty_')
596
603
597 # Whether to pretty-print or not.
604 # Whether to pretty-print or not.
598 pprint = Bool(True, config=True)
605 pprint = Bool(True, config=True)
599
606
600 # Whether to be verbose or not.
607 # Whether to be verbose or not.
601 verbose = Bool(False, config=True)
608 verbose = Bool(False, config=True)
602
609
603 # The maximum width.
610 # The maximum width.
604 max_width = Integer(79, config=True)
611 max_width = Integer(79, config=True)
605
612
606 # The newline character.
613 # The newline character.
607 newline = Unicode('\n', config=True)
614 newline = Unicode('\n', config=True)
608
615
609 # format-string for pprinting floats
616 # format-string for pprinting floats
610 float_format = Unicode('%r')
617 float_format = Unicode('%r')
611 # setter for float precision, either int or direct format-string
618 # setter for float precision, either int or direct format-string
612 float_precision = CUnicode('', config=True)
619 float_precision = CUnicode('', config=True)
613
620
614 def _float_precision_changed(self, name, old, new):
621 def _float_precision_changed(self, name, old, new):
615 """float_precision changed, set float_format accordingly.
622 """float_precision changed, set float_format accordingly.
616
623
617 float_precision can be set by int or str.
624 float_precision can be set by int or str.
618 This will set float_format, after interpreting input.
625 This will set float_format, after interpreting input.
619 If numpy has been imported, numpy print precision will also be set.
626 If numpy has been imported, numpy print precision will also be set.
620
627
621 integer `n` sets format to '%.nf', otherwise, format set directly.
628 integer `n` sets format to '%.nf', otherwise, format set directly.
622
629
623 An empty string returns to defaults (repr for float, 8 for numpy).
630 An empty string returns to defaults (repr for float, 8 for numpy).
624
631
625 This parameter can be set via the '%precision' magic.
632 This parameter can be set via the '%precision' magic.
626 """
633 """
627
634
628 if '%' in new:
635 if '%' in new:
629 # got explicit format string
636 # got explicit format string
630 fmt = new
637 fmt = new
631 try:
638 try:
632 fmt%3.14159
639 fmt%3.14159
633 except Exception:
640 except Exception:
634 raise ValueError("Precision must be int or format string, not %r"%new)
641 raise ValueError("Precision must be int or format string, not %r"%new)
635 elif new:
642 elif new:
636 # otherwise, should be an int
643 # otherwise, should be an int
637 try:
644 try:
638 i = int(new)
645 i = int(new)
639 assert i >= 0
646 assert i >= 0
640 except ValueError:
647 except ValueError:
641 raise ValueError("Precision must be int or format string, not %r"%new)
648 raise ValueError("Precision must be int or format string, not %r"%new)
642 except AssertionError:
649 except AssertionError:
643 raise ValueError("int precision must be non-negative, not %r"%i)
650 raise ValueError("int precision must be non-negative, not %r"%i)
644
651
645 fmt = '%%.%if'%i
652 fmt = '%%.%if'%i
646 if 'numpy' in sys.modules:
653 if 'numpy' in sys.modules:
647 # set numpy precision if it has been imported
654 # set numpy precision if it has been imported
648 import numpy
655 import numpy
649 numpy.set_printoptions(precision=i)
656 numpy.set_printoptions(precision=i)
650 else:
657 else:
651 # default back to repr
658 # default back to repr
652 fmt = '%r'
659 fmt = '%r'
653 if 'numpy' in sys.modules:
660 if 'numpy' in sys.modules:
654 import numpy
661 import numpy
655 # numpy default is 8
662 # numpy default is 8
656 numpy.set_printoptions(precision=8)
663 numpy.set_printoptions(precision=8)
657 self.float_format = fmt
664 self.float_format = fmt
658
665
659 # Use the default pretty printers from IPython.lib.pretty.
666 # Use the default pretty printers from IPython.lib.pretty.
660 def _singleton_printers_default(self):
667 def _singleton_printers_default(self):
661 return pretty._singleton_pprinters.copy()
668 return pretty._singleton_pprinters.copy()
662
669
663 def _type_printers_default(self):
670 def _type_printers_default(self):
664 d = pretty._type_pprinters.copy()
671 d = pretty._type_pprinters.copy()
665 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
672 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
666 return d
673 return d
667
674
668 def _deferred_printers_default(self):
675 def _deferred_printers_default(self):
669 return pretty._deferred_type_pprinters.copy()
676 return pretty._deferred_type_pprinters.copy()
670
677
671 #### FormatterABC interface ####
678 #### FormatterABC interface ####
672
679
673 @catch_format_error
680 @catch_format_error
674 def __call__(self, obj):
681 def __call__(self, obj):
675 """Compute the pretty representation of the object."""
682 """Compute the pretty representation of the object."""
676 if not self.pprint:
683 if not self.pprint:
677 return repr(obj)
684 return repr(obj)
678 else:
685 else:
679 # handle str and unicode on Python 2
686 # handle str and unicode on Python 2
680 # io.StringIO only accepts unicode,
687 # io.StringIO only accepts unicode,
681 # cStringIO doesn't handle unicode on py2,
688 # cStringIO doesn't handle unicode on py2,
682 # StringIO allows str, unicode but only ascii str
689 # StringIO allows str, unicode but only ascii str
683 stream = pretty.CUnicodeIO()
690 stream = pretty.CUnicodeIO()
684 printer = pretty.RepresentationPrinter(stream, self.verbose,
691 printer = pretty.RepresentationPrinter(stream, self.verbose,
685 self.max_width, self.newline,
692 self.max_width, self.newline,
686 max_seq_length=self.max_seq_length,
693 max_seq_length=self.max_seq_length,
687 singleton_pprinters=self.singleton_printers,
694 singleton_pprinters=self.singleton_printers,
688 type_pprinters=self.type_printers,
695 type_pprinters=self.type_printers,
689 deferred_pprinters=self.deferred_printers)
696 deferred_pprinters=self.deferred_printers)
690 printer.pretty(obj)
697 printer.pretty(obj)
691 printer.flush()
698 printer.flush()
692 return stream.getvalue()
699 return stream.getvalue()
693
700
694
701
695 class HTMLFormatter(BaseFormatter):
702 class HTMLFormatter(BaseFormatter):
696 """An HTML formatter.
703 """An HTML formatter.
697
704
698 To define the callables that compute the HTML representation of your
705 To define the callables that compute the HTML representation of your
699 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
706 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
700 or :meth:`for_type_by_name` methods to register functions that handle
707 or :meth:`for_type_by_name` methods to register functions that handle
701 this.
708 this.
702
709
703 The return value of this formatter should be a valid HTML snippet that
710 The return value of this formatter should be a valid HTML snippet that
704 could be injected into an existing DOM. It should *not* include the
711 could be injected into an existing DOM. It should *not* include the
705 ```<html>`` or ```<body>`` tags.
712 ```<html>`` or ```<body>`` tags.
706 """
713 """
707 format_type = Unicode('text/html')
714 format_type = Unicode('text/html')
708
715
709 print_method = ObjectName('_repr_html_')
716 print_method = ObjectName('_repr_html_')
710
717
711
718
712 class MarkdownFormatter(BaseFormatter):
719 class MarkdownFormatter(BaseFormatter):
713 """A Markdown formatter.
720 """A Markdown formatter.
714
721
715 To define the callables that compute the Markdown representation of your
722 To define the callables that compute the Markdown representation of your
716 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
723 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
717 or :meth:`for_type_by_name` methods to register functions that handle
724 or :meth:`for_type_by_name` methods to register functions that handle
718 this.
725 this.
719
726
720 The return value of this formatter should be a valid Markdown.
727 The return value of this formatter should be a valid Markdown.
721 """
728 """
722 format_type = Unicode('text/markdown')
729 format_type = Unicode('text/markdown')
723
730
724 print_method = ObjectName('_repr_markdown_')
731 print_method = ObjectName('_repr_markdown_')
725
732
726 class SVGFormatter(BaseFormatter):
733 class SVGFormatter(BaseFormatter):
727 """An SVG formatter.
734 """An SVG formatter.
728
735
729 To define the callables that compute the SVG representation of your
736 To define the callables that compute the SVG representation of your
730 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
737 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
731 or :meth:`for_type_by_name` methods to register functions that handle
738 or :meth:`for_type_by_name` methods to register functions that handle
732 this.
739 this.
733
740
734 The return value of this formatter should be valid SVG enclosed in
741 The return value of this formatter should be valid SVG enclosed in
735 ```<svg>``` tags, that could be injected into an existing DOM. It should
742 ```<svg>``` tags, that could be injected into an existing DOM. It should
736 *not* include the ```<html>`` or ```<body>`` tags.
743 *not* include the ```<html>`` or ```<body>`` tags.
737 """
744 """
738 format_type = Unicode('image/svg+xml')
745 format_type = Unicode('image/svg+xml')
739
746
740 print_method = ObjectName('_repr_svg_')
747 print_method = ObjectName('_repr_svg_')
741
748
742
749
743 class PNGFormatter(BaseFormatter):
750 class PNGFormatter(BaseFormatter):
744 """A PNG formatter.
751 """A PNG formatter.
745
752
746 To define the callables that compute the PNG representation of your
753 To define the callables that compute the PNG representation of your
747 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
754 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
748 or :meth:`for_type_by_name` methods to register functions that handle
755 or :meth:`for_type_by_name` methods to register functions that handle
749 this.
756 this.
750
757
751 The return value of this formatter should be raw PNG data, *not*
758 The return value of this formatter should be raw PNG data, *not*
752 base64 encoded.
759 base64 encoded.
753 """
760 """
754 format_type = Unicode('image/png')
761 format_type = Unicode('image/png')
755
762
756 print_method = ObjectName('_repr_png_')
763 print_method = ObjectName('_repr_png_')
757
764
758 _return_type = (bytes, unicode_type)
765 _return_type = (bytes, unicode_type)
759
766
760
767
761 class JPEGFormatter(BaseFormatter):
768 class JPEGFormatter(BaseFormatter):
762 """A JPEG formatter.
769 """A JPEG formatter.
763
770
764 To define the callables that compute the JPEG representation of your
771 To define the callables that compute the JPEG representation of your
765 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
772 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
766 or :meth:`for_type_by_name` methods to register functions that handle
773 or :meth:`for_type_by_name` methods to register functions that handle
767 this.
774 this.
768
775
769 The return value of this formatter should be raw JPEG data, *not*
776 The return value of this formatter should be raw JPEG data, *not*
770 base64 encoded.
777 base64 encoded.
771 """
778 """
772 format_type = Unicode('image/jpeg')
779 format_type = Unicode('image/jpeg')
773
780
774 print_method = ObjectName('_repr_jpeg_')
781 print_method = ObjectName('_repr_jpeg_')
775
782
776 _return_type = (bytes, unicode_type)
783 _return_type = (bytes, unicode_type)
777
784
778
785
779 class LatexFormatter(BaseFormatter):
786 class LatexFormatter(BaseFormatter):
780 """A LaTeX formatter.
787 """A LaTeX formatter.
781
788
782 To define the callables that compute the LaTeX representation of your
789 To define the callables that compute the LaTeX representation of your
783 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
790 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
784 or :meth:`for_type_by_name` methods to register functions that handle
791 or :meth:`for_type_by_name` methods to register functions that handle
785 this.
792 this.
786
793
787 The return value of this formatter should be a valid LaTeX equation,
794 The return value of this formatter should be a valid LaTeX equation,
788 enclosed in either ```$```, ```$$``` or another LaTeX equation
795 enclosed in either ```$```, ```$$``` or another LaTeX equation
789 environment.
796 environment.
790 """
797 """
791 format_type = Unicode('text/latex')
798 format_type = Unicode('text/latex')
792
799
793 print_method = ObjectName('_repr_latex_')
800 print_method = ObjectName('_repr_latex_')
794
801
795
802
796 class JSONFormatter(BaseFormatter):
803 class JSONFormatter(BaseFormatter):
797 """A JSON string formatter.
804 """A JSON string formatter.
798
805
799 To define the callables that compute the JSONable representation of
806 To define the callables that compute the JSONable representation of
800 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
807 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
801 or :meth:`for_type_by_name` methods to register functions that handle
808 or :meth:`for_type_by_name` methods to register functions that handle
802 this.
809 this.
803
810
804 The return value of this formatter should be a JSONable list or dict.
811 The return value of this formatter should be a JSONable list or dict.
805 JSON scalars (None, number, string) are not allowed, only dict or list containers.
812 JSON scalars (None, number, string) are not allowed, only dict or list containers.
806 """
813 """
807 format_type = Unicode('application/json')
814 format_type = Unicode('application/json')
808 _return_type = (list, dict)
815 _return_type = (list, dict)
809
816
810 print_method = ObjectName('_repr_json_')
817 print_method = ObjectName('_repr_json_')
811
818
812 def _check_return(self, r, obj):
819 def _check_return(self, r, obj):
813 """Check that a return value is appropriate
820 """Check that a return value is appropriate
814
821
815 Return the value if so, None otherwise, warning if invalid.
822 Return the value if so, None otherwise, warning if invalid.
816 """
823 """
817 if r is None:
824 if r is None:
818 return
825 return
819 md = None
826 md = None
820 if isinstance(r, tuple):
827 if isinstance(r, tuple):
821 # unpack data, metadata tuple for type checking on first element
828 # unpack data, metadata tuple for type checking on first element
822 r, md = r
829 r, md = r
823
830
824 # handle deprecated JSON-as-string form from IPython < 3
831 # handle deprecated JSON-as-string form from IPython < 3
825 if isinstance(r, string_types):
832 if isinstance(r, string_types):
826 warnings.warn("JSON expects JSONable list/dict containers, not JSON strings",
833 warnings.warn("JSON expects JSONable list/dict containers, not JSON strings",
827 FormatterWarning)
834 FormatterWarning)
828 r = json.loads(r)
835 r = json.loads(r)
829
836
830 if md is not None:
837 if md is not None:
831 # put the tuple back together
838 # put the tuple back together
832 r = (r, md)
839 r = (r, md)
833 return super(JSONFormatter, self)._check_return(r, obj)
840 return super(JSONFormatter, self)._check_return(r, obj)
834
841
835
842
836 class JavascriptFormatter(BaseFormatter):
843 class JavascriptFormatter(BaseFormatter):
837 """A Javascript formatter.
844 """A Javascript formatter.
838
845
839 To define the callables that compute the Javascript representation of
846 To define the callables that compute the Javascript representation of
840 your objects, define a :meth:`_repr_javascript_` method or use the
847 your objects, define a :meth:`_repr_javascript_` method or use the
841 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
848 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
842 that handle this.
849 that handle this.
843
850
844 The return value of this formatter should be valid Javascript code and
851 The return value of this formatter should be valid Javascript code and
845 should *not* be enclosed in ```<script>``` tags.
852 should *not* be enclosed in ```<script>``` tags.
846 """
853 """
847 format_type = Unicode('application/javascript')
854 format_type = Unicode('application/javascript')
848
855
849 print_method = ObjectName('_repr_javascript_')
856 print_method = ObjectName('_repr_javascript_')
850
857
851
858
852 class PDFFormatter(BaseFormatter):
859 class PDFFormatter(BaseFormatter):
853 """A PDF formatter.
860 """A PDF formatter.
854
861
855 To define the callables that compute the PDF representation of your
862 To define the callables that compute the PDF representation of your
856 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
863 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
857 or :meth:`for_type_by_name` methods to register functions that handle
864 or :meth:`for_type_by_name` methods to register functions that handle
858 this.
865 this.
859
866
860 The return value of this formatter should be raw PDF data, *not*
867 The return value of this formatter should be raw PDF data, *not*
861 base64 encoded.
868 base64 encoded.
862 """
869 """
863 format_type = Unicode('application/pdf')
870 format_type = Unicode('application/pdf')
864
871
865 print_method = ObjectName('_repr_pdf_')
872 print_method = ObjectName('_repr_pdf_')
866
873
867 _return_type = (bytes, unicode_type)
874 _return_type = (bytes, unicode_type)
868
875
869 class IPythonDisplayFormatter(BaseFormatter):
876 class IPythonDisplayFormatter(BaseFormatter):
870 """A Formatter for objects that know how to display themselves.
877 """A Formatter for objects that know how to display themselves.
871
878
872 To define the callables that compute the representation of your
879 To define the callables that compute the representation of your
873 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
880 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
874 or :meth:`for_type_by_name` methods to register functions that handle
881 or :meth:`for_type_by_name` methods to register functions that handle
875 this. Unlike mime-type displays, this method should not return anything,
882 this. Unlike mime-type displays, this method should not return anything,
876 instead calling any appropriate display methods itself.
883 instead calling any appropriate display methods itself.
877
884
878 This display formatter has highest priority.
885 This display formatter has highest priority.
879 If it fires, no other display formatter will be called.
886 If it fires, no other display formatter will be called.
880 """
887 """
881 print_method = ObjectName('_ipython_display_')
888 print_method = ObjectName('_ipython_display_')
882 _return_type = (type(None), bool)
889 _return_type = (type(None), bool)
883
890
884
891
885 @catch_format_error
892 @catch_format_error
886 def __call__(self, obj):
893 def __call__(self, obj):
887 """Compute the format for an object."""
894 """Compute the format for an object."""
888 if self.enabled:
895 if self.enabled:
889 # lookup registered printer
896 # lookup registered printer
890 try:
897 try:
891 printer = self.lookup(obj)
898 printer = self.lookup(obj)
892 except KeyError:
899 except KeyError:
893 pass
900 pass
894 else:
901 else:
895 printer(obj)
902 printer(obj)
896 return True
903 return True
897 # Finally look for special method names
904 # Finally look for special method names
898 method = _safe_get_formatter_method(obj, self.print_method)
905 method = _safe_get_formatter_method(obj, self.print_method)
899 if method is not None:
906 if method is not None:
900 method()
907 method()
901 return True
908 return True
902
909
903
910
904 FormatterABC.register(BaseFormatter)
911 FormatterABC.register(BaseFormatter)
905 FormatterABC.register(PlainTextFormatter)
912 FormatterABC.register(PlainTextFormatter)
906 FormatterABC.register(HTMLFormatter)
913 FormatterABC.register(HTMLFormatter)
907 FormatterABC.register(MarkdownFormatter)
914 FormatterABC.register(MarkdownFormatter)
908 FormatterABC.register(SVGFormatter)
915 FormatterABC.register(SVGFormatter)
909 FormatterABC.register(PNGFormatter)
916 FormatterABC.register(PNGFormatter)
910 FormatterABC.register(PDFFormatter)
917 FormatterABC.register(PDFFormatter)
911 FormatterABC.register(JPEGFormatter)
918 FormatterABC.register(JPEGFormatter)
912 FormatterABC.register(LatexFormatter)
919 FormatterABC.register(LatexFormatter)
913 FormatterABC.register(JSONFormatter)
920 FormatterABC.register(JSONFormatter)
914 FormatterABC.register(JavascriptFormatter)
921 FormatterABC.register(JavascriptFormatter)
915 FormatterABC.register(IPythonDisplayFormatter)
922 FormatterABC.register(IPythonDisplayFormatter)
916
923
917
924
918 def format_display_data(obj, include=None, exclude=None):
925 def format_display_data(obj, include=None, exclude=None):
919 """Return a format data dict for an object.
926 """Return a format data dict for an object.
920
927
921 By default all format types will be computed.
928 By default all format types will be computed.
922
929
923 The following MIME types are currently implemented:
930 The following MIME types are currently implemented:
924
931
925 * text/plain
932 * text/plain
926 * text/html
933 * text/html
927 * text/markdown
934 * text/markdown
928 * text/latex
935 * text/latex
929 * application/json
936 * application/json
930 * application/javascript
937 * application/javascript
931 * application/pdf
938 * application/pdf
932 * image/png
939 * image/png
933 * image/jpeg
940 * image/jpeg
934 * image/svg+xml
941 * image/svg+xml
935
942
936 Parameters
943 Parameters
937 ----------
944 ----------
938 obj : object
945 obj : object
939 The Python object whose format data will be computed.
946 The Python object whose format data will be computed.
940
947
941 Returns
948 Returns
942 -------
949 -------
943 format_dict : dict
950 format_dict : dict
944 A dictionary of key/value pairs, one or each format that was
951 A dictionary of key/value pairs, one or each format that was
945 generated for the object. The keys are the format types, which
952 generated for the object. The keys are the format types, which
946 will usually be MIME type strings and the values and JSON'able
953 will usually be MIME type strings and the values and JSON'able
947 data structure containing the raw data for the representation in
954 data structure containing the raw data for the representation in
948 that format.
955 that format.
949 include : list or tuple, optional
956 include : list or tuple, optional
950 A list of format type strings (MIME types) to include in the
957 A list of format type strings (MIME types) to include in the
951 format data dict. If this is set *only* the format types included
958 format data dict. If this is set *only* the format types included
952 in this list will be computed.
959 in this list will be computed.
953 exclude : list or tuple, optional
960 exclude : list or tuple, optional
954 A list of format type string (MIME types) to exclue in the format
961 A list of format type string (MIME types) to exclue in the format
955 data dict. If this is set all format types will be computed,
962 data dict. If this is set all format types will be computed,
956 except for those included in this argument.
963 except for those included in this argument.
957 """
964 """
958 from IPython.core.interactiveshell import InteractiveShell
965 from IPython.core.interactiveshell import InteractiveShell
959
966
960 InteractiveShell.instance().display_formatter.format(
967 InteractiveShell.instance().display_formatter.format(
961 obj,
968 obj,
962 include,
969 include,
963 exclude
970 exclude
964 )
971 )
965
972
@@ -1,816 +1,832 b''
1 """Function signature objects for callables.
1 """Function signature objects for callables.
2
2
3 Back port of Python 3.3's function signature tools from the inspect module,
3 Back port of Python 3.3's function signature tools from the inspect module,
4 modified to be compatible with Python 2.7 and 3.2+.
4 modified to be compatible with Python 2.7 and 3.2+.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Python 3.3 stdlib inspect.py is public domain
8 # Python 3.3 stdlib inspect.py is public domain
9 #
9 #
10 # Backports Copyright (C) 2013 Aaron Iles
10 # Backports Copyright (C) 2013 Aaron Iles
11 # Used under Apache License Version 2.0
11 # Used under Apache License Version 2.0
12 #
12 #
13 # Further Changes are Copyright (C) 2013 The IPython Development Team
13 # Further Changes are Copyright (C) 2013 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from __future__ import absolute_import, division, print_function
19 from __future__ import absolute_import, division, print_function
20 import itertools
20 import itertools
21 import functools
21 import functools
22 import re
22 import re
23 import types
23 import types
24
24
25
25
26 # patch for single-file
26 # patch for single-file
27 # we don't support 2.6, so we can just import OrderedDict
27 # we don't support 2.6, so we can just import OrderedDict
28 from collections import OrderedDict
28 from collections import OrderedDict
29
29
30 __version__ = '0.3'
30 __version__ = '0.3'
31 # end patch
31 # end patch
32
32
33 __all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature']
33 __all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature']
34
34
35
35
36 _WrapperDescriptor = type(type.__call__)
36 _WrapperDescriptor = type(type.__call__)
37 _MethodWrapper = type(all.__call__)
37 _MethodWrapper = type(all.__call__)
38
38
39 _NonUserDefinedCallables = (_WrapperDescriptor,
39 _NonUserDefinedCallables = (_WrapperDescriptor,
40 _MethodWrapper,
40 _MethodWrapper,
41 types.BuiltinFunctionType)
41 types.BuiltinFunctionType)
42
42
43
43
44 def formatannotation(annotation, base_module=None):
44 def formatannotation(annotation, base_module=None):
45 if isinstance(annotation, type):
45 if isinstance(annotation, type):
46 if annotation.__module__ in ('builtins', '__builtin__', base_module):
46 if annotation.__module__ in ('builtins', '__builtin__', base_module):
47 return annotation.__name__
47 return annotation.__name__
48 return annotation.__module__+'.'+annotation.__name__
48 return annotation.__module__+'.'+annotation.__name__
49 return repr(annotation)
49 return repr(annotation)
50
50
51
51
52 def _get_user_defined_method(cls, method_name, *nested):
52 def _get_user_defined_method(cls, method_name, *nested):
53 try:
53 try:
54 if cls is type:
54 if cls is type:
55 return
55 return
56 meth = getattr(cls, method_name)
56 meth = getattr(cls, method_name)
57 for name in nested:
57 for name in nested:
58 meth = getattr(meth, name, meth)
58 meth = getattr(meth, name, meth)
59 except AttributeError:
59 except AttributeError:
60 return
60 return
61 else:
61 else:
62 if not isinstance(meth, _NonUserDefinedCallables):
62 if not isinstance(meth, _NonUserDefinedCallables):
63 # Once '__signature__' will be added to 'C'-level
63 # Once '__signature__' will be added to 'C'-level
64 # callables, this check won't be necessary
64 # callables, this check won't be necessary
65 return meth
65 return meth
66
66
67
67
68 def signature(obj):
68 def signature(obj):
69 '''Get a signature object for the passed callable.'''
69 '''Get a signature object for the passed callable.'''
70
70
71 if not callable(obj):
71 if not callable(obj):
72 raise TypeError('{0!r} is not a callable object'.format(obj))
72 raise TypeError('{0!r} is not a callable object'.format(obj))
73
73
74 if isinstance(obj, types.MethodType):
74 if isinstance(obj, types.MethodType):
75 if obj.__self__ is None:
75 if obj.__self__ is None:
76 # Unbound method - treat it as a function (no distinction in Py 3)
76 # Unbound method - treat it as a function (no distinction in Py 3)
77 obj = obj.__func__
77 obj = obj.__func__
78 else:
78 else:
79 # Bound method: trim off the first parameter (typically self or cls)
79 # Bound method: trim off the first parameter (typically self or cls)
80 sig = signature(obj.__func__)
80 sig = signature(obj.__func__)
81 return sig.replace(parameters=tuple(sig.parameters.values())[1:])
81 return sig.replace(parameters=tuple(sig.parameters.values())[1:])
82
82
83 try:
83 try:
84 sig = obj.__signature__
84 sig = obj.__signature__
85 except AttributeError:
85 except AttributeError:
86 pass
86 pass
87 else:
87 else:
88 if sig is not None:
88 if sig is not None:
89 return sig
89 return sig
90
90
91 try:
91 try:
92 # Was this function wrapped by a decorator?
92 # Was this function wrapped by a decorator?
93 wrapped = obj.__wrapped__
93 wrapped = obj.__wrapped__
94 except AttributeError:
94 except AttributeError:
95 pass
95 pass
96 else:
96 else:
97 return signature(wrapped)
97 return signature(wrapped)
98
98
99 if isinstance(obj, types.FunctionType):
99 if isinstance(obj, types.FunctionType):
100 return Signature.from_function(obj)
100 return Signature.from_function(obj)
101
101
102 if isinstance(obj, functools.partial):
102 if isinstance(obj, functools.partial):
103 sig = signature(obj.func)
103 sig = signature(obj.func)
104
104
105 new_params = OrderedDict(sig.parameters.items())
105 new_params = OrderedDict(sig.parameters.items())
106
106
107 partial_args = obj.args or ()
107 partial_args = obj.args or ()
108 partial_keywords = obj.keywords or {}
108 partial_keywords = obj.keywords or {}
109 try:
109 try:
110 ba = sig.bind_partial(*partial_args, **partial_keywords)
110 ba = sig.bind_partial(*partial_args, **partial_keywords)
111 except TypeError as ex:
111 except TypeError as ex:
112 msg = 'partial object {0!r} has incorrect arguments'.format(obj)
112 msg = 'partial object {0!r} has incorrect arguments'.format(obj)
113 raise ValueError(msg)
113 raise ValueError(msg)
114
114
115 for arg_name, arg_value in ba.arguments.items():
115 for arg_name, arg_value in ba.arguments.items():
116 param = new_params[arg_name]
116 param = new_params[arg_name]
117 if arg_name in partial_keywords:
117 if arg_name in partial_keywords:
118 # We set a new default value, because the following code
118 # We set a new default value, because the following code
119 # is correct:
119 # is correct:
120 #
120 #
121 # >>> def foo(a): print(a)
121 # >>> def foo(a): print(a)
122 # >>> print(partial(partial(foo, a=10), a=20)())
122 # >>> print(partial(partial(foo, a=10), a=20)())
123 # 20
123 # 20
124 # >>> print(partial(partial(foo, a=10), a=20)(a=30))
124 # >>> print(partial(partial(foo, a=10), a=20)(a=30))
125 # 30
125 # 30
126 #
126 #
127 # So, with 'partial' objects, passing a keyword argument is
127 # So, with 'partial' objects, passing a keyword argument is
128 # like setting a new default value for the corresponding
128 # like setting a new default value for the corresponding
129 # parameter
129 # parameter
130 #
130 #
131 # We also mark this parameter with '_partial_kwarg'
131 # We also mark this parameter with '_partial_kwarg'
132 # flag. Later, in '_bind', the 'default' value of this
132 # flag. Later, in '_bind', the 'default' value of this
133 # parameter will be added to 'kwargs', to simulate
133 # parameter will be added to 'kwargs', to simulate
134 # the 'functools.partial' real call.
134 # the 'functools.partial' real call.
135 new_params[arg_name] = param.replace(default=arg_value,
135 new_params[arg_name] = param.replace(default=arg_value,
136 _partial_kwarg=True)
136 _partial_kwarg=True)
137
137
138 elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and
138 elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and
139 not param._partial_kwarg):
139 not param._partial_kwarg):
140 new_params.pop(arg_name)
140 new_params.pop(arg_name)
141
141
142 return sig.replace(parameters=new_params.values())
142 return sig.replace(parameters=new_params.values())
143
143
144 sig = None
144 sig = None
145 if isinstance(obj, type):
145 if isinstance(obj, type):
146 # obj is a class or a metaclass
146 # obj is a class or a metaclass
147
147
148 # First, let's see if it has an overloaded __call__ defined
148 # First, let's see if it has an overloaded __call__ defined
149 # in its metaclass
149 # in its metaclass
150 call = _get_user_defined_method(type(obj), '__call__')
150 call = _get_user_defined_method(type(obj), '__call__')
151 if call is not None:
151 if call is not None:
152 sig = signature(call)
152 sig = signature(call)
153 else:
153 else:
154 # Now we check if the 'obj' class has a '__new__' method
154 # Now we check if the 'obj' class has a '__new__' method
155 new = _get_user_defined_method(obj, '__new__')
155 new = _get_user_defined_method(obj, '__new__')
156 if new is not None:
156 if new is not None:
157 sig = signature(new)
157 sig = signature(new)
158 else:
158 else:
159 # Finally, we should have at least __init__ implemented
159 # Finally, we should have at least __init__ implemented
160 init = _get_user_defined_method(obj, '__init__')
160 init = _get_user_defined_method(obj, '__init__')
161 if init is not None:
161 if init is not None:
162 sig = signature(init)
162 sig = signature(init)
163 elif not isinstance(obj, _NonUserDefinedCallables):
163 elif not isinstance(obj, _NonUserDefinedCallables):
164 # An object with __call__
164 # An object with __call__
165 # We also check that the 'obj' is not an instance of
165 # We also check that the 'obj' is not an instance of
166 # _WrapperDescriptor or _MethodWrapper to avoid
166 # _WrapperDescriptor or _MethodWrapper to avoid
167 # infinite recursion (and even potential segfault)
167 # infinite recursion (and even potential segfault)
168 call = _get_user_defined_method(type(obj), '__call__', 'im_func')
168 call = _get_user_defined_method(type(obj), '__call__', 'im_func')
169 if call is not None:
169 if call is not None:
170 sig = signature(call)
170 sig = signature(call)
171
171
172 if sig is not None:
172 if sig is not None:
173 return sig
173 return sig
174
174
175 if isinstance(obj, types.BuiltinFunctionType):
175 if isinstance(obj, types.BuiltinFunctionType):
176 # Raise a nicer error message for builtins
176 # Raise a nicer error message for builtins
177 msg = 'no signature found for builtin function {0!r}'.format(obj)
177 msg = 'no signature found for builtin function {0!r}'.format(obj)
178 raise ValueError(msg)
178 raise ValueError(msg)
179
179
180 raise ValueError('callable {0!r} is not supported by signature'.format(obj))
180 raise ValueError('callable {0!r} is not supported by signature'.format(obj))
181
181
182
182
183 class _void(object):
183 class _void(object):
184 '''A private marker - used in Parameter & Signature'''
184 '''A private marker - used in Parameter & Signature'''
185
185
186
186
187 class _empty(object):
187 class _empty(object):
188 pass
188 pass
189
189
190
190
191 class _ParameterKind(int):
191 class _ParameterKind(int):
192 def __new__(self, *args, **kwargs):
192 def __new__(self, *args, **kwargs):
193 obj = int.__new__(self, *args)
193 obj = int.__new__(self, *args)
194 obj._name = kwargs['name']
194 obj._name = kwargs['name']
195 return obj
195 return obj
196
196
197 def __str__(self):
197 def __str__(self):
198 return self._name
198 return self._name
199
199
200 def __repr__(self):
200 def __repr__(self):
201 return '<_ParameterKind: {0!r}>'.format(self._name)
201 return '<_ParameterKind: {0!r}>'.format(self._name)
202
202
203
203
204 _POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY')
204 _POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY')
205 _POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD')
205 _POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD')
206 _VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL')
206 _VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL')
207 _KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY')
207 _KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY')
208 _VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD')
208 _VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD')
209
209
210
210
211 class Parameter(object):
211 class Parameter(object):
212 '''Represents a parameter in a function signature.
212 '''Represents a parameter in a function signature.
213
213
214 Has the following public attributes:
214 Has the following public attributes:
215
215
216 * name : str
216 * name : str
217 The name of the parameter as a string.
217 The name of the parameter as a string.
218 * default : object
218 * default : object
219 The default value for the parameter if specified. If the
219 The default value for the parameter if specified. If the
220 parameter has no default value, this attribute is not set.
220 parameter has no default value, this attribute is not set.
221 * annotation
221 * annotation
222 The annotation for the parameter if specified. If the
222 The annotation for the parameter if specified. If the
223 parameter has no annotation, this attribute is not set.
223 parameter has no annotation, this attribute is not set.
224 * kind : str
224 * kind : str
225 Describes how argument values are bound to the parameter.
225 Describes how argument values are bound to the parameter.
226 Possible values: `Parameter.POSITIONAL_ONLY`,
226 Possible values: `Parameter.POSITIONAL_ONLY`,
227 `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
227 `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
228 `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
228 `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
229 '''
229 '''
230
230
231 __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg')
231 __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg')
232
232
233 POSITIONAL_ONLY = _POSITIONAL_ONLY
233 POSITIONAL_ONLY = _POSITIONAL_ONLY
234 POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD
234 POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD
235 VAR_POSITIONAL = _VAR_POSITIONAL
235 VAR_POSITIONAL = _VAR_POSITIONAL
236 KEYWORD_ONLY = _KEYWORD_ONLY
236 KEYWORD_ONLY = _KEYWORD_ONLY
237 VAR_KEYWORD = _VAR_KEYWORD
237 VAR_KEYWORD = _VAR_KEYWORD
238
238
239 empty = _empty
239 empty = _empty
240
240
241 def __init__(self, name, kind, default=_empty, annotation=_empty,
241 def __init__(self, name, kind, default=_empty, annotation=_empty,
242 _partial_kwarg=False):
242 _partial_kwarg=False):
243
243
244 if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD,
244 if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD,
245 _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD):
245 _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD):
246 raise ValueError("invalid value for 'Parameter.kind' attribute")
246 raise ValueError("invalid value for 'Parameter.kind' attribute")
247 self._kind = kind
247 self._kind = kind
248
248
249 if default is not _empty:
249 if default is not _empty:
250 if kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
250 if kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
251 msg = '{0} parameters cannot have default values'.format(kind)
251 msg = '{0} parameters cannot have default values'.format(kind)
252 raise ValueError(msg)
252 raise ValueError(msg)
253 self._default = default
253 self._default = default
254 self._annotation = annotation
254 self._annotation = annotation
255
255
256 if name is None:
256 if name is None:
257 if kind != _POSITIONAL_ONLY:
257 if kind != _POSITIONAL_ONLY:
258 raise ValueError("None is not a valid name for a "
258 raise ValueError("None is not a valid name for a "
259 "non-positional-only parameter")
259 "non-positional-only parameter")
260 self._name = name
260 self._name = name
261 else:
261 else:
262 name = str(name)
262 name = str(name)
263 if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I):
263 if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I):
264 msg = '{0!r} is not a valid parameter name'.format(name)
264 msg = '{0!r} is not a valid parameter name'.format(name)
265 raise ValueError(msg)
265 raise ValueError(msg)
266 self._name = name
266 self._name = name
267
267
268 self._partial_kwarg = _partial_kwarg
268 self._partial_kwarg = _partial_kwarg
269
269
270 @property
270 @property
271 def name(self):
271 def name(self):
272 return self._name
272 return self._name
273
273
274 @property
274 @property
275 def default(self):
275 def default(self):
276 return self._default
276 return self._default
277
277
278 @property
278 @property
279 def annotation(self):
279 def annotation(self):
280 return self._annotation
280 return self._annotation
281
281
282 @property
282 @property
283 def kind(self):
283 def kind(self):
284 return self._kind
284 return self._kind
285
285
286 def replace(self, name=_void, kind=_void, annotation=_void,
286 def replace(self, name=_void, kind=_void, annotation=_void,
287 default=_void, _partial_kwarg=_void):
287 default=_void, _partial_kwarg=_void):
288 '''Creates a customized copy of the Parameter.'''
288 '''Creates a customized copy of the Parameter.'''
289
289
290 if name is _void:
290 if name is _void:
291 name = self._name
291 name = self._name
292
292
293 if kind is _void:
293 if kind is _void:
294 kind = self._kind
294 kind = self._kind
295
295
296 if annotation is _void:
296 if annotation is _void:
297 annotation = self._annotation
297 annotation = self._annotation
298
298
299 if default is _void:
299 if default is _void:
300 default = self._default
300 default = self._default
301
301
302 if _partial_kwarg is _void:
302 if _partial_kwarg is _void:
303 _partial_kwarg = self._partial_kwarg
303 _partial_kwarg = self._partial_kwarg
304
304
305 return type(self)(name, kind, default=default, annotation=annotation,
305 return type(self)(name, kind, default=default, annotation=annotation,
306 _partial_kwarg=_partial_kwarg)
306 _partial_kwarg=_partial_kwarg)
307
307
308 def __str__(self):
308 def __str__(self):
309 kind = self.kind
309 kind = self.kind
310
310
311 formatted = self._name
311 formatted = self._name
312 if kind == _POSITIONAL_ONLY:
312 if kind == _POSITIONAL_ONLY:
313 if formatted is None:
313 if formatted is None:
314 formatted = ''
314 formatted = ''
315 formatted = '<{0}>'.format(formatted)
315 formatted = '<{0}>'.format(formatted)
316
316
317 # Add annotation and default value
317 # Add annotation and default value
318 if self._annotation is not _empty:
318 if self._annotation is not _empty:
319 formatted = '{0}:{1}'.format(formatted,
319 formatted = '{0}:{1}'.format(formatted,
320 formatannotation(self._annotation))
320 formatannotation(self._annotation))
321
321
322 if self._default is not _empty:
322 if self._default is not _empty:
323 formatted = '{0}={1}'.format(formatted, repr(self._default))
323 formatted = '{0}={1}'.format(formatted, repr(self._default))
324
324
325 if kind == _VAR_POSITIONAL:
325 if kind == _VAR_POSITIONAL:
326 formatted = '*' + formatted
326 formatted = '*' + formatted
327 elif kind == _VAR_KEYWORD:
327 elif kind == _VAR_KEYWORD:
328 formatted = '**' + formatted
328 formatted = '**' + formatted
329
329
330 return formatted
330 return formatted
331
331
332 def __repr__(self):
332 def __repr__(self):
333 return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__,
333 return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__,
334 id(self), self.name)
334 id(self), self.name)
335
335
336 def __hash__(self):
336 def __hash__(self):
337 msg = "unhashable type: '{0}'".format(self.__class__.__name__)
337 msg = "unhashable type: '{0}'".format(self.__class__.__name__)
338 raise TypeError(msg)
338 raise TypeError(msg)
339
339
340 def __eq__(self, other):
340 def __eq__(self, other):
341 return (issubclass(other.__class__, Parameter) and
341 return (issubclass(other.__class__, Parameter) and
342 self._name == other._name and
342 self._name == other._name and
343 self._kind == other._kind and
343 self._kind == other._kind and
344 self._default == other._default and
344 self._default == other._default and
345 self._annotation == other._annotation)
345 self._annotation == other._annotation)
346
346
347 def __ne__(self, other):
347 def __ne__(self, other):
348 return not self.__eq__(other)
348 return not self.__eq__(other)
349
349
350
350
351 class BoundArguments(object):
351 class BoundArguments(object):
352 '''Result of :meth:`Signature.bind` call. Holds the mapping of arguments
352 '''Result of :meth:`Signature.bind` call. Holds the mapping of arguments
353 to the function's parameters.
353 to the function's parameters.
354
354
355 Has the following public attributes:
355 Has the following public attributes:
356
356
357 arguments : :class:`collections.OrderedDict`
357 arguments : :class:`collections.OrderedDict`
358 An ordered mutable mapping of parameters' names to arguments' values.
358 An ordered mutable mapping of parameters' names to arguments' values.
359 Does not contain arguments' default values.
359 Does not contain arguments' default values.
360 signature : :class:`Signature`
360 signature : :class:`Signature`
361 The Signature object that created this instance.
361 The Signature object that created this instance.
362 args : tuple
362 args : tuple
363 Tuple of positional arguments values.
363 Tuple of positional arguments values.
364 kwargs : dict
364 kwargs : dict
365 Dict of keyword arguments values.
365 Dict of keyword arguments values.
366 '''
366 '''
367
367
368 def __init__(self, signature, arguments):
368 def __init__(self, signature, arguments):
369 self.arguments = arguments
369 self.arguments = arguments
370 self._signature = signature
370 self._signature = signature
371
371
372 @property
372 @property
373 def signature(self):
373 def signature(self):
374 return self._signature
374 return self._signature
375
375
376 @property
376 @property
377 def args(self):
377 def args(self):
378 args = []
378 args = []
379 for param_name, param in self._signature.parameters.items():
379 for param_name, param in self._signature.parameters.items():
380 if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or
380 if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or
381 param._partial_kwarg):
381 param._partial_kwarg):
382 # Keyword arguments mapped by 'functools.partial'
382 # Keyword arguments mapped by 'functools.partial'
383 # (Parameter._partial_kwarg is True) are mapped
383 # (Parameter._partial_kwarg is True) are mapped
384 # in 'BoundArguments.kwargs', along with VAR_KEYWORD &
384 # in 'BoundArguments.kwargs', along with VAR_KEYWORD &
385 # KEYWORD_ONLY
385 # KEYWORD_ONLY
386 break
386 break
387
387
388 try:
388 try:
389 arg = self.arguments[param_name]
389 arg = self.arguments[param_name]
390 except KeyError:
390 except KeyError:
391 # We're done here. Other arguments
391 # We're done here. Other arguments
392 # will be mapped in 'BoundArguments.kwargs'
392 # will be mapped in 'BoundArguments.kwargs'
393 break
393 break
394 else:
394 else:
395 if param.kind == _VAR_POSITIONAL:
395 if param.kind == _VAR_POSITIONAL:
396 # *args
396 # *args
397 args.extend(arg)
397 args.extend(arg)
398 else:
398 else:
399 # plain argument
399 # plain argument
400 args.append(arg)
400 args.append(arg)
401
401
402 return tuple(args)
402 return tuple(args)
403
403
404 @property
404 @property
405 def kwargs(self):
405 def kwargs(self):
406 kwargs = {}
406 kwargs = {}
407 kwargs_started = False
407 kwargs_started = False
408 for param_name, param in self._signature.parameters.items():
408 for param_name, param in self._signature.parameters.items():
409 if not kwargs_started:
409 if not kwargs_started:
410 if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or
410 if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or
411 param._partial_kwarg):
411 param._partial_kwarg):
412 kwargs_started = True
412 kwargs_started = True
413 else:
413 else:
414 if param_name not in self.arguments:
414 if param_name not in self.arguments:
415 kwargs_started = True
415 kwargs_started = True
416 continue
416 continue
417
417
418 if not kwargs_started:
418 if not kwargs_started:
419 continue
419 continue
420
420
421 try:
421 try:
422 arg = self.arguments[param_name]
422 arg = self.arguments[param_name]
423 except KeyError:
423 except KeyError:
424 pass
424 pass
425 else:
425 else:
426 if param.kind == _VAR_KEYWORD:
426 if param.kind == _VAR_KEYWORD:
427 # **kwargs
427 # **kwargs
428 kwargs.update(arg)
428 kwargs.update(arg)
429 else:
429 else:
430 # plain keyword argument
430 # plain keyword argument
431 kwargs[param_name] = arg
431 kwargs[param_name] = arg
432
432
433 return kwargs
433 return kwargs
434
434
435 def __hash__(self):
435 def __hash__(self):
436 msg = "unhashable type: '{0}'".format(self.__class__.__name__)
436 msg = "unhashable type: '{0}'".format(self.__class__.__name__)
437 raise TypeError(msg)
437 raise TypeError(msg)
438
438
439 def __eq__(self, other):
439 def __eq__(self, other):
440 return (issubclass(other.__class__, BoundArguments) and
440 return (issubclass(other.__class__, BoundArguments) and
441 self.signature == other.signature and
441 self.signature == other.signature and
442 self.arguments == other.arguments)
442 self.arguments == other.arguments)
443
443
444 def __ne__(self, other):
444 def __ne__(self, other):
445 return not self.__eq__(other)
445 return not self.__eq__(other)
446
446
447
447
448 class Signature(object):
448 class Signature(object):
449 '''A Signature object represents the overall signature of a function.
449 '''A Signature object represents the overall signature of a function.
450 It stores a Parameter object for each parameter accepted by the
450 It stores a Parameter object for each parameter accepted by the
451 function, as well as information specific to the function itself.
451 function, as well as information specific to the function itself.
452
452
453 A Signature object has the following public attributes:
453 A Signature object has the following public attributes:
454
454
455 parameters : :class:`collections.OrderedDict`
455 parameters : :class:`collections.OrderedDict`
456 An ordered mapping of parameters' names to the corresponding
456 An ordered mapping of parameters' names to the corresponding
457 Parameter objects (keyword-only arguments are in the same order
457 Parameter objects (keyword-only arguments are in the same order
458 as listed in `code.co_varnames`).
458 as listed in `code.co_varnames`).
459 return_annotation
459 return_annotation
460 The annotation for the return type of the function if specified.
460 The annotation for the return type of the function if specified.
461 If the function has no annotation for its return type, this
461 If the function has no annotation for its return type, this
462 attribute is not set.
462 attribute is not set.
463 '''
463 '''
464
464
465 __slots__ = ('_return_annotation', '_parameters')
465 __slots__ = ('_return_annotation', '_parameters')
466
466
467 _parameter_cls = Parameter
467 _parameter_cls = Parameter
468 _bound_arguments_cls = BoundArguments
468 _bound_arguments_cls = BoundArguments
469
469
470 empty = _empty
470 empty = _empty
471
471
472 def __init__(self, parameters=None, return_annotation=_empty,
472 def __init__(self, parameters=None, return_annotation=_empty,
473 __validate_parameters__=True):
473 __validate_parameters__=True):
474 '''Constructs Signature from the given list of Parameter
474 '''Constructs Signature from the given list of Parameter
475 objects and 'return_annotation'. All arguments are optional.
475 objects and 'return_annotation'. All arguments are optional.
476 '''
476 '''
477
477
478 if parameters is None:
478 if parameters is None:
479 params = OrderedDict()
479 params = OrderedDict()
480 else:
480 else:
481 if __validate_parameters__:
481 if __validate_parameters__:
482 params = OrderedDict()
482 params = OrderedDict()
483 top_kind = _POSITIONAL_ONLY
483 top_kind = _POSITIONAL_ONLY
484
484
485 for idx, param in enumerate(parameters):
485 for idx, param in enumerate(parameters):
486 kind = param.kind
486 kind = param.kind
487 if kind < top_kind:
487 if kind < top_kind:
488 msg = 'wrong parameter order: {0} before {1}'
488 msg = 'wrong parameter order: {0} before {1}'
489 msg = msg.format(top_kind, param.kind)
489 msg = msg.format(top_kind, param.kind)
490 raise ValueError(msg)
490 raise ValueError(msg)
491 else:
491 else:
492 top_kind = kind
492 top_kind = kind
493
493
494 name = param.name
494 name = param.name
495 if name is None:
495 if name is None:
496 name = str(idx)
496 name = str(idx)
497 param = param.replace(name=name)
497 param = param.replace(name=name)
498
498
499 if name in params:
499 if name in params:
500 msg = 'duplicate parameter name: {0!r}'.format(name)
500 msg = 'duplicate parameter name: {0!r}'.format(name)
501 raise ValueError(msg)
501 raise ValueError(msg)
502 params[name] = param
502 params[name] = param
503 else:
503 else:
504 params = OrderedDict(((param.name, param)
504 params = OrderedDict(((param.name, param)
505 for param in parameters))
505 for param in parameters))
506
506
507 self._parameters = params
507 self._parameters = params
508 self._return_annotation = return_annotation
508 self._return_annotation = return_annotation
509
509
510 @classmethod
510 @classmethod
511 def from_function(cls, func):
511 def from_function(cls, func):
512 '''Constructs Signature for the given python function'''
512 '''Constructs Signature for the given python function'''
513
513
514 if not isinstance(func, types.FunctionType):
514 if not isinstance(func, types.FunctionType):
515 raise TypeError('{0!r} is not a Python function'.format(func))
515 raise TypeError('{0!r} is not a Python function'.format(func))
516
516
517 Parameter = cls._parameter_cls
517 Parameter = cls._parameter_cls
518
518
519 # Parameter information.
519 # Parameter information.
520 func_code = func.__code__
520 func_code = func.__code__
521 pos_count = func_code.co_argcount
521 pos_count = func_code.co_argcount
522 arg_names = func_code.co_varnames
522 arg_names = func_code.co_varnames
523 positional = tuple(arg_names[:pos_count])
523 positional = tuple(arg_names[:pos_count])
524 keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0)
524 keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0)
525 keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)]
525 keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)]
526 annotations = getattr(func, '__annotations__', {})
526 annotations = getattr(func, '__annotations__', {})
527 defaults = func.__defaults__
527 defaults = func.__defaults__
528 kwdefaults = getattr(func, '__kwdefaults__', None)
528 kwdefaults = getattr(func, '__kwdefaults__', None)
529
529
530 if defaults:
530 if defaults:
531 pos_default_count = len(defaults)
531 pos_default_count = len(defaults)
532 else:
532 else:
533 pos_default_count = 0
533 pos_default_count = 0
534
534
535 parameters = []
535 parameters = []
536
536
537 # Non-keyword-only parameters w/o defaults.
537 # Non-keyword-only parameters w/o defaults.
538 non_default_count = pos_count - pos_default_count
538 non_default_count = pos_count - pos_default_count
539 for name in positional[:non_default_count]:
539 for name in positional[:non_default_count]:
540 annotation = annotations.get(name, _empty)
540 annotation = annotations.get(name, _empty)
541 parameters.append(Parameter(name, annotation=annotation,
541 parameters.append(Parameter(name, annotation=annotation,
542 kind=_POSITIONAL_OR_KEYWORD))
542 kind=_POSITIONAL_OR_KEYWORD))
543
543
544 # ... w/ defaults.
544 # ... w/ defaults.
545 for offset, name in enumerate(positional[non_default_count:]):
545 for offset, name in enumerate(positional[non_default_count:]):
546 annotation = annotations.get(name, _empty)
546 annotation = annotations.get(name, _empty)
547 parameters.append(Parameter(name, annotation=annotation,
547 parameters.append(Parameter(name, annotation=annotation,
548 kind=_POSITIONAL_OR_KEYWORD,
548 kind=_POSITIONAL_OR_KEYWORD,
549 default=defaults[offset]))
549 default=defaults[offset]))
550
550
551 # *args
551 # *args
552 if func_code.co_flags & 0x04:
552 if func_code.co_flags & 0x04:
553 name = arg_names[pos_count + keyword_only_count]
553 name = arg_names[pos_count + keyword_only_count]
554 annotation = annotations.get(name, _empty)
554 annotation = annotations.get(name, _empty)
555 parameters.append(Parameter(name, annotation=annotation,
555 parameters.append(Parameter(name, annotation=annotation,
556 kind=_VAR_POSITIONAL))
556 kind=_VAR_POSITIONAL))
557
557
558 # Keyword-only parameters.
558 # Keyword-only parameters.
559 for name in keyword_only:
559 for name in keyword_only:
560 default = _empty
560 default = _empty
561 if kwdefaults is not None:
561 if kwdefaults is not None:
562 default = kwdefaults.get(name, _empty)
562 default = kwdefaults.get(name, _empty)
563
563
564 annotation = annotations.get(name, _empty)
564 annotation = annotations.get(name, _empty)
565 parameters.append(Parameter(name, annotation=annotation,
565 parameters.append(Parameter(name, annotation=annotation,
566 kind=_KEYWORD_ONLY,
566 kind=_KEYWORD_ONLY,
567 default=default))
567 default=default))
568 # **kwargs
568 # **kwargs
569 if func_code.co_flags & 0x08:
569 if func_code.co_flags & 0x08:
570 index = pos_count + keyword_only_count
570 index = pos_count + keyword_only_count
571 if func_code.co_flags & 0x04:
571 if func_code.co_flags & 0x04:
572 index += 1
572 index += 1
573
573
574 name = arg_names[index]
574 name = arg_names[index]
575 annotation = annotations.get(name, _empty)
575 annotation = annotations.get(name, _empty)
576 parameters.append(Parameter(name, annotation=annotation,
576 parameters.append(Parameter(name, annotation=annotation,
577 kind=_VAR_KEYWORD))
577 kind=_VAR_KEYWORD))
578
578
579 return cls(parameters,
579 return cls(parameters,
580 return_annotation=annotations.get('return', _empty),
580 return_annotation=annotations.get('return', _empty),
581 __validate_parameters__=False)
581 __validate_parameters__=False)
582
582
583 @property
583 @property
584 def parameters(self):
584 def parameters(self):
585 try:
585 try:
586 return types.MappingProxyType(self._parameters)
586 return types.MappingProxyType(self._parameters)
587 except AttributeError:
587 except AttributeError:
588 return OrderedDict(self._parameters.items())
588 return OrderedDict(self._parameters.items())
589
589
590 @property
590 @property
591 def return_annotation(self):
591 def return_annotation(self):
592 return self._return_annotation
592 return self._return_annotation
593
593
594 def replace(self, parameters=_void, return_annotation=_void):
594 def replace(self, parameters=_void, return_annotation=_void):
595 '''Creates a customized copy of the Signature.
595 '''Creates a customized copy of the Signature.
596 Pass 'parameters' and/or 'return_annotation' arguments
596 Pass 'parameters' and/or 'return_annotation' arguments
597 to override them in the new copy.
597 to override them in the new copy.
598 '''
598 '''
599
599
600 if parameters is _void:
600 if parameters is _void:
601 parameters = self.parameters.values()
601 parameters = self.parameters.values()
602
602
603 if return_annotation is _void:
603 if return_annotation is _void:
604 return_annotation = self._return_annotation
604 return_annotation = self._return_annotation
605
605
606 return type(self)(parameters,
606 return type(self)(parameters,
607 return_annotation=return_annotation)
607 return_annotation=return_annotation)
608
608
609 def __hash__(self):
609 def __hash__(self):
610 msg = "unhashable type: '{0}'".format(self.__class__.__name__)
610 msg = "unhashable type: '{0}'".format(self.__class__.__name__)
611 raise TypeError(msg)
611 raise TypeError(msg)
612
612
613 def __eq__(self, other):
613 def __eq__(self, other):
614 if (not issubclass(type(other), Signature) or
614 if (not issubclass(type(other), Signature) or
615 self.return_annotation != other.return_annotation or
615 self.return_annotation != other.return_annotation or
616 len(self.parameters) != len(other.parameters)):
616 len(self.parameters) != len(other.parameters)):
617 return False
617 return False
618
618
619 other_positions = dict((param, idx)
619 other_positions = dict((param, idx)
620 for idx, param in enumerate(other.parameters.keys()))
620 for idx, param in enumerate(other.parameters.keys()))
621
621
622 for idx, (param_name, param) in enumerate(self.parameters.items()):
622 for idx, (param_name, param) in enumerate(self.parameters.items()):
623 if param.kind == _KEYWORD_ONLY:
623 if param.kind == _KEYWORD_ONLY:
624 try:
624 try:
625 other_param = other.parameters[param_name]
625 other_param = other.parameters[param_name]
626 except KeyError:
626 except KeyError:
627 return False
627 return False
628 else:
628 else:
629 if param != other_param:
629 if param != other_param:
630 return False
630 return False
631 else:
631 else:
632 try:
632 try:
633 other_idx = other_positions[param_name]
633 other_idx = other_positions[param_name]
634 except KeyError:
634 except KeyError:
635 return False
635 return False
636 else:
636 else:
637 if (idx != other_idx or
637 if (idx != other_idx or
638 param != other.parameters[param_name]):
638 param != other.parameters[param_name]):
639 return False
639 return False
640
640
641 return True
641 return True
642
642
643 def __ne__(self, other):
643 def __ne__(self, other):
644 return not self.__eq__(other)
644 return not self.__eq__(other)
645
645
646 def _bind(self, args, kwargs, partial=False):
646 def _bind(self, args, kwargs, partial=False):
647 '''Private method. Don't use directly.'''
647 '''Private method. Don't use directly.'''
648
648
649 arguments = OrderedDict()
649 arguments = OrderedDict()
650
650
651 parameters = iter(self.parameters.values())
651 parameters = iter(self.parameters.values())
652 parameters_ex = ()
652 parameters_ex = ()
653 arg_vals = iter(args)
653 arg_vals = iter(args)
654
654
655 if partial:
655 if partial:
656 # Support for binding arguments to 'functools.partial' objects.
656 # Support for binding arguments to 'functools.partial' objects.
657 # See 'functools.partial' case in 'signature()' implementation
657 # See 'functools.partial' case in 'signature()' implementation
658 # for details.
658 # for details.
659 for param_name, param in self.parameters.items():
659 for param_name, param in self.parameters.items():
660 if (param._partial_kwarg and param_name not in kwargs):
660 if (param._partial_kwarg and param_name not in kwargs):
661 # Simulating 'functools.partial' behavior
661 # Simulating 'functools.partial' behavior
662 kwargs[param_name] = param.default
662 kwargs[param_name] = param.default
663
663
664 while True:
664 while True:
665 # Let's iterate through the positional arguments and corresponding
665 # Let's iterate through the positional arguments and corresponding
666 # parameters
666 # parameters
667 try:
667 try:
668 arg_val = next(arg_vals)
668 arg_val = next(arg_vals)
669 except StopIteration:
669 except StopIteration:
670 # No more positional arguments
670 # No more positional arguments
671 try:
671 try:
672 param = next(parameters)
672 param = next(parameters)
673 except StopIteration:
673 except StopIteration:
674 # No more parameters. That's it. Just need to check that
674 # No more parameters. That's it. Just need to check that
675 # we have no `kwargs` after this while loop
675 # we have no `kwargs` after this while loop
676 break
676 break
677 else:
677 else:
678 if param.kind == _VAR_POSITIONAL:
678 if param.kind == _VAR_POSITIONAL:
679 # That's OK, just empty *args. Let's start parsing
679 # That's OK, just empty *args. Let's start parsing
680 # kwargs
680 # kwargs
681 break
681 break
682 elif param.name in kwargs:
682 elif param.name in kwargs:
683 if param.kind == _POSITIONAL_ONLY:
683 if param.kind == _POSITIONAL_ONLY:
684 msg = '{arg!r} parameter is positional only, ' \
684 msg = '{arg!r} parameter is positional only, ' \
685 'but was passed as a keyword'
685 'but was passed as a keyword'
686 msg = msg.format(arg=param.name)
686 msg = msg.format(arg=param.name)
687 raise TypeError(msg)
687 raise TypeError(msg)
688 parameters_ex = (param,)
688 parameters_ex = (param,)
689 break
689 break
690 elif (param.kind == _VAR_KEYWORD or
690 elif (param.kind == _VAR_KEYWORD or
691 param.default is not _empty):
691 param.default is not _empty):
692 # That's fine too - we have a default value for this
692 # That's fine too - we have a default value for this
693 # parameter. So, lets start parsing `kwargs`, starting
693 # parameter. So, lets start parsing `kwargs`, starting
694 # with the current parameter
694 # with the current parameter
695 parameters_ex = (param,)
695 parameters_ex = (param,)
696 break
696 break
697 else:
697 else:
698 if partial:
698 if partial:
699 parameters_ex = (param,)
699 parameters_ex = (param,)
700 break
700 break
701 else:
701 else:
702 msg = '{arg!r} parameter lacking default value'
702 msg = '{arg!r} parameter lacking default value'
703 msg = msg.format(arg=param.name)
703 msg = msg.format(arg=param.name)
704 raise TypeError(msg)
704 raise TypeError(msg)
705 else:
705 else:
706 # We have a positional argument to process
706 # We have a positional argument to process
707 try:
707 try:
708 param = next(parameters)
708 param = next(parameters)
709 except StopIteration:
709 except StopIteration:
710 raise TypeError('too many positional arguments')
710 raise TypeError('too many positional arguments')
711 else:
711 else:
712 if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
712 if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
713 # Looks like we have no parameter for this positional
713 # Looks like we have no parameter for this positional
714 # argument
714 # argument
715 raise TypeError('too many positional arguments')
715 raise TypeError('too many positional arguments')
716
716
717 if param.kind == _VAR_POSITIONAL:
717 if param.kind == _VAR_POSITIONAL:
718 # We have an '*args'-like argument, let's fill it with
718 # We have an '*args'-like argument, let's fill it with
719 # all positional arguments we have left and move on to
719 # all positional arguments we have left and move on to
720 # the next phase
720 # the next phase
721 values = [arg_val]
721 values = [arg_val]
722 values.extend(arg_vals)
722 values.extend(arg_vals)
723 arguments[param.name] = tuple(values)
723 arguments[param.name] = tuple(values)
724 break
724 break
725
725
726 if param.name in kwargs:
726 if param.name in kwargs:
727 raise TypeError('multiple values for argument '
727 raise TypeError('multiple values for argument '
728 '{arg!r}'.format(arg=param.name))
728 '{arg!r}'.format(arg=param.name))
729
729
730 arguments[param.name] = arg_val
730 arguments[param.name] = arg_val
731
731
732 # Now, we iterate through the remaining parameters to process
732 # Now, we iterate through the remaining parameters to process
733 # keyword arguments
733 # keyword arguments
734 kwargs_param = None
734 kwargs_param = None
735 for param in itertools.chain(parameters_ex, parameters):
735 for param in itertools.chain(parameters_ex, parameters):
736 if param.kind == _POSITIONAL_ONLY:
736 if param.kind == _POSITIONAL_ONLY:
737 # This should never happen in case of a properly built
737 # This should never happen in case of a properly built
738 # Signature object (but let's have this check here
738 # Signature object (but let's have this check here
739 # to ensure correct behaviour just in case)
739 # to ensure correct behaviour just in case)
740 raise TypeError('{arg!r} parameter is positional only, '
740 raise TypeError('{arg!r} parameter is positional only, '
741 'but was passed as a keyword'. \
741 'but was passed as a keyword'. \
742 format(arg=param.name))
742 format(arg=param.name))
743
743
744 if param.kind == _VAR_KEYWORD:
744 if param.kind == _VAR_KEYWORD:
745 # Memorize that we have a '**kwargs'-like parameter
745 # Memorize that we have a '**kwargs'-like parameter
746 kwargs_param = param
746 kwargs_param = param
747 continue
747 continue
748
748
749 param_name = param.name
749 param_name = param.name
750 try:
750 try:
751 arg_val = kwargs.pop(param_name)
751 arg_val = kwargs.pop(param_name)
752 except KeyError:
752 except KeyError:
753 # We have no value for this parameter. It's fine though,
753 # We have no value for this parameter. It's fine though,
754 # if it has a default value, or it is an '*args'-like
754 # if it has a default value, or it is an '*args'-like
755 # parameter, left alone by the processing of positional
755 # parameter, left alone by the processing of positional
756 # arguments.
756 # arguments.
757 if (not partial and param.kind != _VAR_POSITIONAL and
757 if (not partial and param.kind != _VAR_POSITIONAL and
758 param.default is _empty):
758 param.default is _empty):
759 raise TypeError('{arg!r} parameter lacking default value'. \
759 raise TypeError('{arg!r} parameter lacking default value'. \
760 format(arg=param_name))
760 format(arg=param_name))
761
761
762 else:
762 else:
763 arguments[param_name] = arg_val
763 arguments[param_name] = arg_val
764
764
765 if kwargs:
765 if kwargs:
766 if kwargs_param is not None:
766 if kwargs_param is not None:
767 # Process our '**kwargs'-like parameter
767 # Process our '**kwargs'-like parameter
768 arguments[kwargs_param.name] = kwargs
768 arguments[kwargs_param.name] = kwargs
769 else:
769 else:
770 raise TypeError('too many keyword arguments')
770 raise TypeError('too many keyword arguments')
771
771
772 return self._bound_arguments_cls(self, arguments)
772 return self._bound_arguments_cls(self, arguments)
773
773
774 def bind(self, *args, **kwargs):
774 def bind(self, *args, **kwargs):
775 '''Get a :class:`BoundArguments` object, that maps the passed `args`
775 '''Get a :class:`BoundArguments` object, that maps the passed `args`
776 and `kwargs` to the function's signature. Raises :exc:`TypeError`
776 and `kwargs` to the function's signature. Raises :exc:`TypeError`
777 if the passed arguments can not be bound.
777 if the passed arguments can not be bound.
778 '''
778 '''
779 return self._bind(args, kwargs)
779 return self._bind(args, kwargs)
780
780
781 def bind_partial(self, *args, **kwargs):
781 def bind_partial(self, *args, **kwargs):
782 '''Get a :class:`BoundArguments` object, that partially maps the
782 '''Get a :class:`BoundArguments` object, that partially maps the
783 passed `args` and `kwargs` to the function's signature.
783 passed `args` and `kwargs` to the function's signature.
784 Raises :exc:`TypeError` if the passed arguments can not be bound.
784 Raises :exc:`TypeError` if the passed arguments can not be bound.
785 '''
785 '''
786 return self._bind(args, kwargs, partial=True)
786 return self._bind(args, kwargs, partial=True)
787
787
788 def __str__(self):
788 def __str__(self):
789 result = []
789 result = []
790 render_kw_only_separator = True
790 render_kw_only_separator = True
791 for idx, param in enumerate(self.parameters.values()):
791 for idx, param in enumerate(self.parameters.values()):
792 formatted = str(param)
792 formatted = str(param)
793
793
794 kind = param.kind
794 kind = param.kind
795 if kind == _VAR_POSITIONAL:
795 if kind == _VAR_POSITIONAL:
796 # OK, we have an '*args'-like parameter, so we won't need
796 # OK, we have an '*args'-like parameter, so we won't need
797 # a '*' to separate keyword-only arguments
797 # a '*' to separate keyword-only arguments
798 render_kw_only_separator = False
798 render_kw_only_separator = False
799 elif kind == _KEYWORD_ONLY and render_kw_only_separator:
799 elif kind == _KEYWORD_ONLY and render_kw_only_separator:
800 # We have a keyword-only parameter to render and we haven't
800 # We have a keyword-only parameter to render and we haven't
801 # rendered an '*args'-like parameter before, so add a '*'
801 # rendered an '*args'-like parameter before, so add a '*'
802 # separator to the parameters list ("foo(arg1, *, arg2)" case)
802 # separator to the parameters list ("foo(arg1, *, arg2)" case)
803 result.append('*')
803 result.append('*')
804 # This condition should be only triggered once, so
804 # This condition should be only triggered once, so
805 # reset the flag
805 # reset the flag
806 render_kw_only_separator = False
806 render_kw_only_separator = False
807
807
808 result.append(formatted)
808 result.append(formatted)
809
809
810 rendered = '({0})'.format(', '.join(result))
810 rendered = '({0})'.format(', '.join(result))
811
811
812 if self.return_annotation is not _empty:
812 if self.return_annotation is not _empty:
813 anno = formatannotation(self.return_annotation)
813 anno = formatannotation(self.return_annotation)
814 rendered += ' -> {0}'.format(anno)
814 rendered += ' -> {0}'.format(anno)
815
815
816 return rendered
816 return rendered
817
818 ## Fake unique value as KWargs, in some places.
819 # do not put docstrings here or they will appear
820 # on created fake values.
821 class Sentinel(object):
822
823 def __init__(self, name, module, docstring=None):
824 self.name = name
825 self.module = module
826 if docstring:
827 self.__doc__ = docstring
828
829
830 def __repr__(self):
831 return str(self.module)+'.'+self.name
832
@@ -1,178 +1,167 b''
1 """The IPython notebook format
1 """The IPython notebook format
2
2
3 Use this module to read or write notebook files as particular nbformat versions.
3 Use this module to read or write notebook files as particular nbformat versions.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 import io
8 import io
9 from IPython.utils import py3compat
9 from IPython.utils import py3compat
10
10
11 from IPython.utils.log import get_logger
11 from IPython.utils.log import get_logger
12
12
13 from . import v1
13 from . import v1
14 from . import v2
14 from . import v2
15 from . import v3
15 from . import v3
16 from . import v4
16 from . import v4
17 from IPython.utils.signatures import Sentinel
17
18
18 __all__ = ['versions', 'validate', 'ValidationError', 'convert', 'from_dict',
19 __all__ = ['versions', 'validate', 'ValidationError', 'convert', 'from_dict',
19 'NotebookNode', 'current_nbformat', 'current_nbformat_minor',
20 'NotebookNode', 'current_nbformat', 'current_nbformat_minor',
20 'NBFormatError', 'NO_CONVERT', 'reads', 'read', 'writes', 'write']
21 'NBFormatError', 'NO_CONVERT', 'reads', 'read', 'writes', 'write']
21
22
22 versions = {
23 versions = {
23 1: v1,
24 1: v1,
24 2: v2,
25 2: v2,
25 3: v3,
26 3: v3,
26 4: v4,
27 4: v4,
27 }
28 }
28
29
29 from .validator import validate, ValidationError
30 from .validator import validate, ValidationError
30 from .converter import convert
31 from .converter import convert
31 from . import reader
32 from . import reader
32 from .notebooknode import from_dict, NotebookNode
33 from .notebooknode import from_dict, NotebookNode
33
34
34 from .v4 import (
35 from .v4 import (
35 nbformat as current_nbformat,
36 nbformat as current_nbformat,
36 nbformat_minor as current_nbformat_minor,
37 nbformat_minor as current_nbformat_minor,
37 )
38 )
38
39
39 class NBFormatError(ValueError):
40 class NBFormatError(ValueError):
40 pass
41 pass
41
42
42 # no-conversion singleton
43 # no-conversion singleton
43 class Sentinel(object):
44
45 def __init__(self, name, module, docstring=None):
46 self.name = name
47 self.module = module
48 if docstring:
49 self.__doc__ = docstring
50
51
52 def __repr__(self):
53 return str(self.module)+'.'+self.name
54
55 NO_CONVERT = Sentinel('NO_CONVERT', __name__,
44 NO_CONVERT = Sentinel('NO_CONVERT', __name__,
56 """Value to prevent nbformat to convert notebooks to most recent version.
45 """Value to prevent nbformat to convert notebooks to most recent version.
57 """)
46 """)
58
47
59
48
60 def reads(s, as_version, **kwargs):
49 def reads(s, as_version, **kwargs):
61 """Read a notebook from a string and return the NotebookNode object as the given version.
50 """Read a notebook from a string and return the NotebookNode object as the given version.
62
51
63 The string can contain a notebook of any version.
52 The string can contain a notebook of any version.
64 The notebook will be returned `as_version`, converting, if necessary.
53 The notebook will be returned `as_version`, converting, if necessary.
65
54
66 Notebook format errors will be logged.
55 Notebook format errors will be logged.
67
56
68 Parameters
57 Parameters
69 ----------
58 ----------
70 s : unicode
59 s : unicode
71 The raw unicode string to read the notebook from.
60 The raw unicode string to read the notebook from.
72 as_version : int
61 as_version : int
73 The version of the notebook format to return.
62 The version of the notebook format to return.
74 The notebook will be converted, if necessary.
63 The notebook will be converted, if necessary.
75 Pass nbformat.NO_CONVERT to prevent conversion.
64 Pass nbformat.NO_CONVERT to prevent conversion.
76
65
77 Returns
66 Returns
78 -------
67 -------
79 nb : NotebookNode
68 nb : NotebookNode
80 The notebook that was read.
69 The notebook that was read.
81 """
70 """
82 nb = reader.reads(s, **kwargs)
71 nb = reader.reads(s, **kwargs)
83 if as_version is not NO_CONVERT:
72 if as_version is not NO_CONVERT:
84 nb = convert(nb, as_version)
73 nb = convert(nb, as_version)
85 try:
74 try:
86 validate(nb)
75 validate(nb)
87 except ValidationError as e:
76 except ValidationError as e:
88 get_logger().error("Notebook JSON is invalid: %s", e)
77 get_logger().error("Notebook JSON is invalid: %s", e)
89 return nb
78 return nb
90
79
91
80
92 def writes(nb, version=NO_CONVERT, **kwargs):
81 def writes(nb, version=NO_CONVERT, **kwargs):
93 """Write a notebook to a string in a given format in the given nbformat version.
82 """Write a notebook to a string in a given format in the given nbformat version.
94
83
95 Any notebook format errors will be logged.
84 Any notebook format errors will be logged.
96
85
97 Parameters
86 Parameters
98 ----------
87 ----------
99 nb : NotebookNode
88 nb : NotebookNode
100 The notebook to write.
89 The notebook to write.
101 version : int, optional
90 version : int, optional
102 The nbformat version to write.
91 The nbformat version to write.
103 If unspecified, or specified as nbformat.NO_CONVERT,
92 If unspecified, or specified as nbformat.NO_CONVERT,
104 the notebook's own version will be used and no conversion performed.
93 the notebook's own version will be used and no conversion performed.
105
94
106 Returns
95 Returns
107 -------
96 -------
108 s : unicode
97 s : unicode
109 The notebook as a JSON string.
98 The notebook as a JSON string.
110 """
99 """
111 if version is not NO_CONVERT:
100 if version is not NO_CONVERT:
112 nb = convert(nb, version)
101 nb = convert(nb, version)
113 else:
102 else:
114 version, _ = reader.get_version(nb)
103 version, _ = reader.get_version(nb)
115 try:
104 try:
116 validate(nb)
105 validate(nb)
117 except ValidationError as e:
106 except ValidationError as e:
118 get_logger().error("Notebook JSON is invalid: %s", e)
107 get_logger().error("Notebook JSON is invalid: %s", e)
119 return versions[version].writes_json(nb, **kwargs)
108 return versions[version].writes_json(nb, **kwargs)
120
109
121
110
122 def read(fp, as_version, **kwargs):
111 def read(fp, as_version, **kwargs):
123 """Read a notebook from a file as a NotebookNode of the given version.
112 """Read a notebook from a file as a NotebookNode of the given version.
124
113
125 The string can contain a notebook of any version.
114 The string can contain a notebook of any version.
126 The notebook will be returned `as_version`, converting, if necessary.
115 The notebook will be returned `as_version`, converting, if necessary.
127
116
128 Notebook format errors will be logged.
117 Notebook format errors will be logged.
129
118
130 Parameters
119 Parameters
131 ----------
120 ----------
132 fp : file or str
121 fp : file or str
133 Any file-like object with a read method, or a path to a file.
122 Any file-like object with a read method, or a path to a file.
134 as_version: int
123 as_version: int
135 The version of the notebook format to return.
124 The version of the notebook format to return.
136 The notebook will be converted, if necessary.
125 The notebook will be converted, if necessary.
137 Pass nbformat.NO_CONVERT to prevent conversion.
126 Pass nbformat.NO_CONVERT to prevent conversion.
138
127
139 Returns
128 Returns
140 -------
129 -------
141 nb : NotebookNode
130 nb : NotebookNode
142 The notebook that was read.
131 The notebook that was read.
143 """
132 """
144 if isinstance(fp, py3compat.string_types):
133 if isinstance(fp, py3compat.string_types):
145 with io.open(fp, encoding='utf-8') as f:
134 with io.open(fp, encoding='utf-8') as f:
146 return read(f, as_version, **kwargs)
135 return read(f, as_version, **kwargs)
147
136
148 return reads(fp.read(), as_version, **kwargs)
137 return reads(fp.read(), as_version, **kwargs)
149
138
150
139
151 def write(nb, fp, version=NO_CONVERT, **kwargs):
140 def write(nb, fp, version=NO_CONVERT, **kwargs):
152 """Write a notebook to a file in a given nbformat version.
141 """Write a notebook to a file in a given nbformat version.
153
142
154 The file-like object must accept unicode input.
143 The file-like object must accept unicode input.
155
144
156 Parameters
145 Parameters
157 ----------
146 ----------
158 nb : NotebookNode
147 nb : NotebookNode
159 The notebook to write.
148 The notebook to write.
160 fp : file or str
149 fp : file or str
161 Any file-like object with a write method that accepts unicode, or
150 Any file-like object with a write method that accepts unicode, or
162 a path to write a file.
151 a path to write a file.
163 version : int, optional
152 version : int, optional
164 The nbformat version to write.
153 The nbformat version to write.
165 If nb is not this version, it will be converted.
154 If nb is not this version, it will be converted.
166 If unspecified, or specified as nbformat.NO_CONVERT,
155 If unspecified, or specified as nbformat.NO_CONVERT,
167 the notebook's own version will be used and no conversion performed.
156 the notebook's own version will be used and no conversion performed.
168 """
157 """
169 if isinstance(fp, py3compat.string_types):
158 if isinstance(fp, py3compat.string_types):
170 with io.open(fp, 'w', encoding='utf-8') as f:
159 with io.open(fp, 'w', encoding='utf-8') as f:
171 return write(nb, f, version=version, **kwargs)
160 return write(nb, f, version=version, **kwargs)
172
161
173 s = writes(nb, version, **kwargs)
162 s = writes(nb, version, **kwargs)
174 if isinstance(s, bytes):
163 if isinstance(s, bytes):
175 s = s.decode('utf8')
164 s = s.decode('utf8')
176 fp.write(s)
165 fp.write(s)
177 if not s.endswith(u'\n'):
166 if not s.endswith(u'\n'):
178 fp.write(u'\n')
167 fp.write(u'\n')
@@ -1,1874 +1,1878 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A lightweight Traits like module.
3 A lightweight Traits like module.
4
4
5 This is designed to provide a lightweight, simple, pure Python version of
5 This is designed to provide a lightweight, simple, pure Python version of
6 many of the capabilities of enthought.traits. This includes:
6 many of the capabilities of enthought.traits. This includes:
7
7
8 * Validation
8 * Validation
9 * Type specification with defaults
9 * Type specification with defaults
10 * Static and dynamic notification
10 * Static and dynamic notification
11 * Basic predefined types
11 * Basic predefined types
12 * An API that is similar to enthought.traits
12 * An API that is similar to enthought.traits
13
13
14 We don't support:
14 We don't support:
15
15
16 * Delegation
16 * Delegation
17 * Automatic GUI generation
17 * Automatic GUI generation
18 * A full set of trait types. Most importantly, we don't provide container
18 * A full set of trait types. Most importantly, we don't provide container
19 traits (list, dict, tuple) that can trigger notifications if their
19 traits (list, dict, tuple) that can trigger notifications if their
20 contents change.
20 contents change.
21 * API compatibility with enthought.traits
21 * API compatibility with enthought.traits
22
22
23 There are also some important difference in our design:
23 There are also some important difference in our design:
24
24
25 * enthought.traits does not validate default values. We do.
25 * enthought.traits does not validate default values. We do.
26
26
27 We choose to create this module because we need these capabilities, but
27 We choose to create this module because we need these capabilities, but
28 we need them to be pure Python so they work in all Python implementations,
28 we need them to be pure Python so they work in all Python implementations,
29 including Jython and IronPython.
29 including Jython and IronPython.
30
30
31 Inheritance diagram:
31 Inheritance diagram:
32
32
33 .. inheritance-diagram:: IPython.utils.traitlets
33 .. inheritance-diagram:: IPython.utils.traitlets
34 :parts: 3
34 :parts: 3
35 """
35 """
36
36
37 # Copyright (c) IPython Development Team.
37 # Copyright (c) IPython Development Team.
38 # Distributed under the terms of the Modified BSD License.
38 # Distributed under the terms of the Modified BSD License.
39 #
39 #
40 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
40 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
41 # also under the terms of the Modified BSD License.
41 # also under the terms of the Modified BSD License.
42
42
43 import contextlib
43 import contextlib
44 import inspect
44 import inspect
45 import re
45 import re
46 import sys
46 import sys
47 import types
47 import types
48 from types import FunctionType
48 from types import FunctionType
49 try:
49 try:
50 from types import ClassType, InstanceType
50 from types import ClassType, InstanceType
51 ClassTypes = (ClassType, type)
51 ClassTypes = (ClassType, type)
52 except:
52 except:
53 ClassTypes = (type,)
53 ClassTypes = (type,)
54 from warnings import warn
54 from warnings import warn
55
55
56 from IPython.utils import py3compat
56 from IPython.utils import py3compat
57 from IPython.utils import eventful
57 from IPython.utils import eventful
58 from IPython.utils.getargspec import getargspec
58 from IPython.utils.getargspec import getargspec
59 from IPython.utils.signatures import Sentinel
59 from IPython.utils.importstring import import_item
60 from IPython.utils.importstring import import_item
60 from IPython.utils.py3compat import iteritems, string_types
61 from IPython.utils.py3compat import iteritems, string_types
61 from IPython.testing.skipdoctest import skip_doctest
62 from IPython.testing.skipdoctest import skip_doctest
62
63
63 SequenceTypes = (list, tuple, set, frozenset)
64 SequenceTypes = (list, tuple, set, frozenset)
64
65
65 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
66 # Basic classes
67 # Basic classes
67 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
68
69
69
70
70 class NoDefaultSpecified ( object ): pass
71 NoDefaultSpecified = Sentinel('NoDefaultSpecified', __name__,
71 NoDefaultSpecified = NoDefaultSpecified()
72 '''
73 Used in Traitlets to specify that no defaults are set in kwargs
74 '''
75 )
72
76
73
77
74 class Undefined ( object ): pass
78 class Undefined ( object ): pass
75 Undefined = Undefined()
79 Undefined = Undefined()
76
80
77 class TraitError(Exception):
81 class TraitError(Exception):
78 pass
82 pass
79
83
80 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
81 # Utilities
85 # Utilities
82 #-----------------------------------------------------------------------------
86 #-----------------------------------------------------------------------------
83
87
84
88
85 def class_of ( object ):
89 def class_of ( object ):
86 """ Returns a string containing the class name of an object with the
90 """ Returns a string containing the class name of an object with the
87 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
91 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
88 'a PlotValue').
92 'a PlotValue').
89 """
93 """
90 if isinstance( object, py3compat.string_types ):
94 if isinstance( object, py3compat.string_types ):
91 return add_article( object )
95 return add_article( object )
92
96
93 return add_article( object.__class__.__name__ )
97 return add_article( object.__class__.__name__ )
94
98
95
99
96 def add_article ( name ):
100 def add_article ( name ):
97 """ Returns a string containing the correct indefinite article ('a' or 'an')
101 """ Returns a string containing the correct indefinite article ('a' or 'an')
98 prefixed to the specified string.
102 prefixed to the specified string.
99 """
103 """
100 if name[:1].lower() in 'aeiou':
104 if name[:1].lower() in 'aeiou':
101 return 'an ' + name
105 return 'an ' + name
102
106
103 return 'a ' + name
107 return 'a ' + name
104
108
105
109
106 def repr_type(obj):
110 def repr_type(obj):
107 """ Return a string representation of a value and its type for readable
111 """ Return a string representation of a value and its type for readable
108 error messages.
112 error messages.
109 """
113 """
110 the_type = type(obj)
114 the_type = type(obj)
111 if (not py3compat.PY3) and the_type is InstanceType:
115 if (not py3compat.PY3) and the_type is InstanceType:
112 # Old-style class.
116 # Old-style class.
113 the_type = obj.__class__
117 the_type = obj.__class__
114 msg = '%r %r' % (obj, the_type)
118 msg = '%r %r' % (obj, the_type)
115 return msg
119 return msg
116
120
117
121
118 def is_trait(t):
122 def is_trait(t):
119 """ Returns whether the given value is an instance or subclass of TraitType.
123 """ Returns whether the given value is an instance or subclass of TraitType.
120 """
124 """
121 return (isinstance(t, TraitType) or
125 return (isinstance(t, TraitType) or
122 (isinstance(t, type) and issubclass(t, TraitType)))
126 (isinstance(t, type) and issubclass(t, TraitType)))
123
127
124
128
125 def parse_notifier_name(name):
129 def parse_notifier_name(name):
126 """Convert the name argument to a list of names.
130 """Convert the name argument to a list of names.
127
131
128 Examples
132 Examples
129 --------
133 --------
130
134
131 >>> parse_notifier_name('a')
135 >>> parse_notifier_name('a')
132 ['a']
136 ['a']
133 >>> parse_notifier_name(['a','b'])
137 >>> parse_notifier_name(['a','b'])
134 ['a', 'b']
138 ['a', 'b']
135 >>> parse_notifier_name(None)
139 >>> parse_notifier_name(None)
136 ['anytrait']
140 ['anytrait']
137 """
141 """
138 if isinstance(name, string_types):
142 if isinstance(name, string_types):
139 return [name]
143 return [name]
140 elif name is None:
144 elif name is None:
141 return ['anytrait']
145 return ['anytrait']
142 elif isinstance(name, (list, tuple)):
146 elif isinstance(name, (list, tuple)):
143 for n in name:
147 for n in name:
144 assert isinstance(n, string_types), "names must be strings"
148 assert isinstance(n, string_types), "names must be strings"
145 return name
149 return name
146
150
147
151
148 class _SimpleTest:
152 class _SimpleTest:
149 def __init__ ( self, value ): self.value = value
153 def __init__ ( self, value ): self.value = value
150 def __call__ ( self, test ):
154 def __call__ ( self, test ):
151 return test == self.value
155 return test == self.value
152 def __repr__(self):
156 def __repr__(self):
153 return "<SimpleTest(%r)" % self.value
157 return "<SimpleTest(%r)" % self.value
154 def __str__(self):
158 def __str__(self):
155 return self.__repr__()
159 return self.__repr__()
156
160
157
161
158 def getmembers(object, predicate=None):
162 def getmembers(object, predicate=None):
159 """A safe version of inspect.getmembers that handles missing attributes.
163 """A safe version of inspect.getmembers that handles missing attributes.
160
164
161 This is useful when there are descriptor based attributes that for
165 This is useful when there are descriptor based attributes that for
162 some reason raise AttributeError even though they exist. This happens
166 some reason raise AttributeError even though they exist. This happens
163 in zope.inteface with the __provides__ attribute.
167 in zope.inteface with the __provides__ attribute.
164 """
168 """
165 results = []
169 results = []
166 for key in dir(object):
170 for key in dir(object):
167 try:
171 try:
168 value = getattr(object, key)
172 value = getattr(object, key)
169 except AttributeError:
173 except AttributeError:
170 pass
174 pass
171 else:
175 else:
172 if not predicate or predicate(value):
176 if not predicate or predicate(value):
173 results.append((key, value))
177 results.append((key, value))
174 results.sort()
178 results.sort()
175 return results
179 return results
176
180
177 def _validate_link(*tuples):
181 def _validate_link(*tuples):
178 """Validate arguments for traitlet link functions"""
182 """Validate arguments for traitlet link functions"""
179 for t in tuples:
183 for t in tuples:
180 if not len(t) == 2:
184 if not len(t) == 2:
181 raise TypeError("Each linked traitlet must be specified as (HasTraits, 'trait_name'), not %r" % t)
185 raise TypeError("Each linked traitlet must be specified as (HasTraits, 'trait_name'), not %r" % t)
182 obj, trait_name = t
186 obj, trait_name = t
183 if not isinstance(obj, HasTraits):
187 if not isinstance(obj, HasTraits):
184 raise TypeError("Each object must be HasTraits, not %r" % type(obj))
188 raise TypeError("Each object must be HasTraits, not %r" % type(obj))
185 if not trait_name in obj.traits():
189 if not trait_name in obj.traits():
186 raise TypeError("%r has no trait %r" % (obj, trait_name))
190 raise TypeError("%r has no trait %r" % (obj, trait_name))
187
191
188 @skip_doctest
192 @skip_doctest
189 class link(object):
193 class link(object):
190 """Link traits from different objects together so they remain in sync.
194 """Link traits from different objects together so they remain in sync.
191
195
192 Parameters
196 Parameters
193 ----------
197 ----------
194 *args : pairs of objects/attributes
198 *args : pairs of objects/attributes
195
199
196 Examples
200 Examples
197 --------
201 --------
198
202
199 >>> c = link((obj1, 'value'), (obj2, 'value'), (obj3, 'value'))
203 >>> c = link((obj1, 'value'), (obj2, 'value'), (obj3, 'value'))
200 >>> obj1.value = 5 # updates other objects as well
204 >>> obj1.value = 5 # updates other objects as well
201 """
205 """
202 updating = False
206 updating = False
203 def __init__(self, *args):
207 def __init__(self, *args):
204 if len(args) < 2:
208 if len(args) < 2:
205 raise TypeError('At least two traitlets must be provided.')
209 raise TypeError('At least two traitlets must be provided.')
206 _validate_link(*args)
210 _validate_link(*args)
207
211
208 self.objects = {}
212 self.objects = {}
209
213
210 initial = getattr(args[0][0], args[0][1])
214 initial = getattr(args[0][0], args[0][1])
211 for obj, attr in args:
215 for obj, attr in args:
212 setattr(obj, attr, initial)
216 setattr(obj, attr, initial)
213
217
214 callback = self._make_closure(obj, attr)
218 callback = self._make_closure(obj, attr)
215 obj.on_trait_change(callback, attr)
219 obj.on_trait_change(callback, attr)
216 self.objects[(obj, attr)] = callback
220 self.objects[(obj, attr)] = callback
217
221
218 @contextlib.contextmanager
222 @contextlib.contextmanager
219 def _busy_updating(self):
223 def _busy_updating(self):
220 self.updating = True
224 self.updating = True
221 try:
225 try:
222 yield
226 yield
223 finally:
227 finally:
224 self.updating = False
228 self.updating = False
225
229
226 def _make_closure(self, sending_obj, sending_attr):
230 def _make_closure(self, sending_obj, sending_attr):
227 def update(name, old, new):
231 def update(name, old, new):
228 self._update(sending_obj, sending_attr, new)
232 self._update(sending_obj, sending_attr, new)
229 return update
233 return update
230
234
231 def _update(self, sending_obj, sending_attr, new):
235 def _update(self, sending_obj, sending_attr, new):
232 if self.updating:
236 if self.updating:
233 return
237 return
234 with self._busy_updating():
238 with self._busy_updating():
235 for obj, attr in self.objects.keys():
239 for obj, attr in self.objects.keys():
236 setattr(obj, attr, new)
240 setattr(obj, attr, new)
237
241
238 def unlink(self):
242 def unlink(self):
239 for key, callback in self.objects.items():
243 for key, callback in self.objects.items():
240 (obj, attr) = key
244 (obj, attr) = key
241 obj.on_trait_change(callback, attr, remove=True)
245 obj.on_trait_change(callback, attr, remove=True)
242
246
243 @skip_doctest
247 @skip_doctest
244 class directional_link(object):
248 class directional_link(object):
245 """Link the trait of a source object with traits of target objects.
249 """Link the trait of a source object with traits of target objects.
246
250
247 Parameters
251 Parameters
248 ----------
252 ----------
249 source : pair of object, name
253 source : pair of object, name
250 targets : pairs of objects/attributes
254 targets : pairs of objects/attributes
251
255
252 Examples
256 Examples
253 --------
257 --------
254
258
255 >>> c = directional_link((src, 'value'), (tgt1, 'value'), (tgt2, 'value'))
259 >>> c = directional_link((src, 'value'), (tgt1, 'value'), (tgt2, 'value'))
256 >>> src.value = 5 # updates target objects
260 >>> src.value = 5 # updates target objects
257 >>> tgt1.value = 6 # does not update other objects
261 >>> tgt1.value = 6 # does not update other objects
258 """
262 """
259 updating = False
263 updating = False
260
264
261 def __init__(self, source, *targets):
265 def __init__(self, source, *targets):
262 if len(targets) < 1:
266 if len(targets) < 1:
263 raise TypeError('At least two traitlets must be provided.')
267 raise TypeError('At least two traitlets must be provided.')
264 _validate_link(source, *targets)
268 _validate_link(source, *targets)
265 self.source = source
269 self.source = source
266 self.targets = targets
270 self.targets = targets
267
271
268 # Update current value
272 # Update current value
269 src_attr_value = getattr(source[0], source[1])
273 src_attr_value = getattr(source[0], source[1])
270 for obj, attr in targets:
274 for obj, attr in targets:
271 setattr(obj, attr, src_attr_value)
275 setattr(obj, attr, src_attr_value)
272
276
273 # Wire
277 # Wire
274 self.source[0].on_trait_change(self._update, self.source[1])
278 self.source[0].on_trait_change(self._update, self.source[1])
275
279
276 @contextlib.contextmanager
280 @contextlib.contextmanager
277 def _busy_updating(self):
281 def _busy_updating(self):
278 self.updating = True
282 self.updating = True
279 try:
283 try:
280 yield
284 yield
281 finally:
285 finally:
282 self.updating = False
286 self.updating = False
283
287
284 def _update(self, name, old, new):
288 def _update(self, name, old, new):
285 if self.updating:
289 if self.updating:
286 return
290 return
287 with self._busy_updating():
291 with self._busy_updating():
288 for obj, attr in self.targets:
292 for obj, attr in self.targets:
289 setattr(obj, attr, new)
293 setattr(obj, attr, new)
290
294
291 def unlink(self):
295 def unlink(self):
292 self.source[0].on_trait_change(self._update, self.source[1], remove=True)
296 self.source[0].on_trait_change(self._update, self.source[1], remove=True)
293 self.source = None
297 self.source = None
294 self.targets = []
298 self.targets = []
295
299
296 dlink = directional_link
300 dlink = directional_link
297
301
298
302
299 #-----------------------------------------------------------------------------
303 #-----------------------------------------------------------------------------
300 # Base TraitType for all traits
304 # Base TraitType for all traits
301 #-----------------------------------------------------------------------------
305 #-----------------------------------------------------------------------------
302
306
303
307
304 class TraitType(object):
308 class TraitType(object):
305 """A base class for all trait descriptors.
309 """A base class for all trait descriptors.
306
310
307 Notes
311 Notes
308 -----
312 -----
309 Our implementation of traits is based on Python's descriptor
313 Our implementation of traits is based on Python's descriptor
310 prototol. This class is the base class for all such descriptors. The
314 prototol. This class is the base class for all such descriptors. The
311 only magic we use is a custom metaclass for the main :class:`HasTraits`
315 only magic we use is a custom metaclass for the main :class:`HasTraits`
312 class that does the following:
316 class that does the following:
313
317
314 1. Sets the :attr:`name` attribute of every :class:`TraitType`
318 1. Sets the :attr:`name` attribute of every :class:`TraitType`
315 instance in the class dict to the name of the attribute.
319 instance in the class dict to the name of the attribute.
316 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
320 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
317 instance in the class dict to the *class* that declared the trait.
321 instance in the class dict to the *class* that declared the trait.
318 This is used by the :class:`This` trait to allow subclasses to
322 This is used by the :class:`This` trait to allow subclasses to
319 accept superclasses for :class:`This` values.
323 accept superclasses for :class:`This` values.
320 """
324 """
321
325
322 metadata = {}
326 metadata = {}
323 default_value = Undefined
327 default_value = Undefined
324 allow_none = False
328 allow_none = False
325 info_text = 'any value'
329 info_text = 'any value'
326
330
327 def __init__(self, default_value=NoDefaultSpecified, allow_none=None, **metadata):
331 def __init__(self, default_value=NoDefaultSpecified, allow_none=None, **metadata):
328 """Create a TraitType.
332 """Create a TraitType.
329 """
333 """
330 if default_value is not NoDefaultSpecified:
334 if default_value is not NoDefaultSpecified:
331 self.default_value = default_value
335 self.default_value = default_value
332 if allow_none is not None:
336 if allow_none is not None:
333 self.allow_none = allow_none
337 self.allow_none = allow_none
334
338
335 if 'default' in metadata:
339 if 'default' in metadata:
336 # Warn the user that they probably meant default_value.
340 # Warn the user that they probably meant default_value.
337 warn(
341 warn(
338 "Parameter 'default' passed to TraitType. "
342 "Parameter 'default' passed to TraitType. "
339 "Did you mean 'default_value'?"
343 "Did you mean 'default_value'?"
340 )
344 )
341
345
342 if len(metadata) > 0:
346 if len(metadata) > 0:
343 if len(self.metadata) > 0:
347 if len(self.metadata) > 0:
344 self._metadata = self.metadata.copy()
348 self._metadata = self.metadata.copy()
345 self._metadata.update(metadata)
349 self._metadata.update(metadata)
346 else:
350 else:
347 self._metadata = metadata
351 self._metadata = metadata
348 else:
352 else:
349 self._metadata = self.metadata
353 self._metadata = self.metadata
350
354
351 self.init()
355 self.init()
352
356
353 def init(self):
357 def init(self):
354 pass
358 pass
355
359
356 def get_default_value(self):
360 def get_default_value(self):
357 """Create a new instance of the default value."""
361 """Create a new instance of the default value."""
358 return self.default_value
362 return self.default_value
359
363
360 def instance_init(self):
364 def instance_init(self):
361 """Part of the initialization which may depends on the underlying
365 """Part of the initialization which may depends on the underlying
362 HasTraits instance.
366 HasTraits instance.
363
367
364 It is typically overloaded for specific trait types.
368 It is typically overloaded for specific trait types.
365
369
366 This method is called by :meth:`HasTraits.__new__` and in the
370 This method is called by :meth:`HasTraits.__new__` and in the
367 :meth:`TraitType.instance_init` method of trait types holding
371 :meth:`TraitType.instance_init` method of trait types holding
368 other trait types.
372 other trait types.
369 """
373 """
370 pass
374 pass
371
375
372 def init_default_value(self, obj):
376 def init_default_value(self, obj):
373 """Instantiate the default value for the trait type.
377 """Instantiate the default value for the trait type.
374
378
375 This method is called by :meth:`TraitType.set_default_value` in the
379 This method is called by :meth:`TraitType.set_default_value` in the
376 case a default value is provided at construction time or later when
380 case a default value is provided at construction time or later when
377 accessing the trait value for the first time in
381 accessing the trait value for the first time in
378 :meth:`HasTraits.__get__`.
382 :meth:`HasTraits.__get__`.
379 """
383 """
380 value = self.get_default_value()
384 value = self.get_default_value()
381 value = self._validate(obj, value)
385 value = self._validate(obj, value)
382 obj._trait_values[self.name] = value
386 obj._trait_values[self.name] = value
383 return value
387 return value
384
388
385 def set_default_value(self, obj):
389 def set_default_value(self, obj):
386 """Set the default value on a per instance basis.
390 """Set the default value on a per instance basis.
387
391
388 This method is called by :meth:`HasTraits.__new__` to instantiate and
392 This method is called by :meth:`HasTraits.__new__` to instantiate and
389 validate the default value. The creation and validation of
393 validate the default value. The creation and validation of
390 default values must be delayed until the parent :class:`HasTraits`
394 default values must be delayed until the parent :class:`HasTraits`
391 class has been instantiated.
395 class has been instantiated.
392 Parameters
396 Parameters
393 ----------
397 ----------
394 obj : :class:`HasTraits` instance
398 obj : :class:`HasTraits` instance
395 The parent :class:`HasTraits` instance that has just been
399 The parent :class:`HasTraits` instance that has just been
396 created.
400 created.
397 """
401 """
398 # Check for a deferred initializer defined in the same class as the
402 # Check for a deferred initializer defined in the same class as the
399 # trait declaration or above.
403 # trait declaration or above.
400 mro = type(obj).mro()
404 mro = type(obj).mro()
401 meth_name = '_%s_default' % self.name
405 meth_name = '_%s_default' % self.name
402 for cls in mro[:mro.index(self.this_class)+1]:
406 for cls in mro[:mro.index(self.this_class)+1]:
403 if meth_name in cls.__dict__:
407 if meth_name in cls.__dict__:
404 break
408 break
405 else:
409 else:
406 # We didn't find one. Do static initialization.
410 # We didn't find one. Do static initialization.
407 self.init_default_value(obj)
411 self.init_default_value(obj)
408 return
412 return
409 # Complete the dynamic initialization.
413 # Complete the dynamic initialization.
410 obj._trait_dyn_inits[self.name] = meth_name
414 obj._trait_dyn_inits[self.name] = meth_name
411
415
412 def __get__(self, obj, cls=None):
416 def __get__(self, obj, cls=None):
413 """Get the value of the trait by self.name for the instance.
417 """Get the value of the trait by self.name for the instance.
414
418
415 Default values are instantiated when :meth:`HasTraits.__new__`
419 Default values are instantiated when :meth:`HasTraits.__new__`
416 is called. Thus by the time this method gets called either the
420 is called. Thus by the time this method gets called either the
417 default value or a user defined value (they called :meth:`__set__`)
421 default value or a user defined value (they called :meth:`__set__`)
418 is in the :class:`HasTraits` instance.
422 is in the :class:`HasTraits` instance.
419 """
423 """
420 if obj is None:
424 if obj is None:
421 return self
425 return self
422 else:
426 else:
423 try:
427 try:
424 value = obj._trait_values[self.name]
428 value = obj._trait_values[self.name]
425 except KeyError:
429 except KeyError:
426 # Check for a dynamic initializer.
430 # Check for a dynamic initializer.
427 if self.name in obj._trait_dyn_inits:
431 if self.name in obj._trait_dyn_inits:
428 method = getattr(obj, obj._trait_dyn_inits[self.name])
432 method = getattr(obj, obj._trait_dyn_inits[self.name])
429 value = method()
433 value = method()
430 # FIXME: Do we really validate here?
434 # FIXME: Do we really validate here?
431 value = self._validate(obj, value)
435 value = self._validate(obj, value)
432 obj._trait_values[self.name] = value
436 obj._trait_values[self.name] = value
433 return value
437 return value
434 else:
438 else:
435 return self.init_default_value(obj)
439 return self.init_default_value(obj)
436 except Exception:
440 except Exception:
437 # HasTraits should call set_default_value to populate
441 # HasTraits should call set_default_value to populate
438 # this. So this should never be reached.
442 # this. So this should never be reached.
439 raise TraitError('Unexpected error in TraitType: '
443 raise TraitError('Unexpected error in TraitType: '
440 'default value not set properly')
444 'default value not set properly')
441 else:
445 else:
442 return value
446 return value
443
447
444 def __set__(self, obj, value):
448 def __set__(self, obj, value):
445 new_value = self._validate(obj, value)
449 new_value = self._validate(obj, value)
446 try:
450 try:
447 old_value = obj._trait_values[self.name]
451 old_value = obj._trait_values[self.name]
448 except KeyError:
452 except KeyError:
449 old_value = Undefined
453 old_value = Undefined
450
454
451 obj._trait_values[self.name] = new_value
455 obj._trait_values[self.name] = new_value
452 try:
456 try:
453 silent = bool(old_value == new_value)
457 silent = bool(old_value == new_value)
454 except:
458 except:
455 # if there is an error in comparing, default to notify
459 # if there is an error in comparing, default to notify
456 silent = False
460 silent = False
457 if silent is not True:
461 if silent is not True:
458 # we explicitly compare silent to True just in case the equality
462 # we explicitly compare silent to True just in case the equality
459 # comparison above returns something other than True/False
463 # comparison above returns something other than True/False
460 obj._notify_trait(self.name, old_value, new_value)
464 obj._notify_trait(self.name, old_value, new_value)
461
465
462 def _validate(self, obj, value):
466 def _validate(self, obj, value):
463 if value is None and self.allow_none:
467 if value is None and self.allow_none:
464 return value
468 return value
465 if hasattr(self, 'validate'):
469 if hasattr(self, 'validate'):
466 value = self.validate(obj, value)
470 value = self.validate(obj, value)
467 if obj._cross_validation_lock is False:
471 if obj._cross_validation_lock is False:
468 value = self._cross_validate(obj, value)
472 value = self._cross_validate(obj, value)
469 return value
473 return value
470
474
471 def _cross_validate(self, obj, value):
475 def _cross_validate(self, obj, value):
472 if hasattr(obj, '_%s_validate' % self.name):
476 if hasattr(obj, '_%s_validate' % self.name):
473 cross_validate = getattr(obj, '_%s_validate' % self.name)
477 cross_validate = getattr(obj, '_%s_validate' % self.name)
474 value = cross_validate(value, self)
478 value = cross_validate(value, self)
475 return value
479 return value
476
480
477 def __or__(self, other):
481 def __or__(self, other):
478 if isinstance(other, Union):
482 if isinstance(other, Union):
479 return Union([self] + other.trait_types)
483 return Union([self] + other.trait_types)
480 else:
484 else:
481 return Union([self, other])
485 return Union([self, other])
482
486
483 def info(self):
487 def info(self):
484 return self.info_text
488 return self.info_text
485
489
486 def error(self, obj, value):
490 def error(self, obj, value):
487 if obj is not None:
491 if obj is not None:
488 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
492 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
489 % (self.name, class_of(obj),
493 % (self.name, class_of(obj),
490 self.info(), repr_type(value))
494 self.info(), repr_type(value))
491 else:
495 else:
492 e = "The '%s' trait must be %s, but a value of %r was specified." \
496 e = "The '%s' trait must be %s, but a value of %r was specified." \
493 % (self.name, self.info(), repr_type(value))
497 % (self.name, self.info(), repr_type(value))
494 raise TraitError(e)
498 raise TraitError(e)
495
499
496 def get_metadata(self, key, default=None):
500 def get_metadata(self, key, default=None):
497 return getattr(self, '_metadata', {}).get(key, default)
501 return getattr(self, '_metadata', {}).get(key, default)
498
502
499 def set_metadata(self, key, value):
503 def set_metadata(self, key, value):
500 getattr(self, '_metadata', {})[key] = value
504 getattr(self, '_metadata', {})[key] = value
501
505
502
506
503 #-----------------------------------------------------------------------------
507 #-----------------------------------------------------------------------------
504 # The HasTraits implementation
508 # The HasTraits implementation
505 #-----------------------------------------------------------------------------
509 #-----------------------------------------------------------------------------
506
510
507
511
508 class MetaHasTraits(type):
512 class MetaHasTraits(type):
509 """A metaclass for HasTraits.
513 """A metaclass for HasTraits.
510
514
511 This metaclass makes sure that any TraitType class attributes are
515 This metaclass makes sure that any TraitType class attributes are
512 instantiated and sets their name attribute.
516 instantiated and sets their name attribute.
513 """
517 """
514
518
515 def __new__(mcls, name, bases, classdict):
519 def __new__(mcls, name, bases, classdict):
516 """Create the HasTraits class.
520 """Create the HasTraits class.
517
521
518 This instantiates all TraitTypes in the class dict and sets their
522 This instantiates all TraitTypes in the class dict and sets their
519 :attr:`name` attribute.
523 :attr:`name` attribute.
520 """
524 """
521 # print "MetaHasTraitlets (mcls, name): ", mcls, name
525 # print "MetaHasTraitlets (mcls, name): ", mcls, name
522 # print "MetaHasTraitlets (bases): ", bases
526 # print "MetaHasTraitlets (bases): ", bases
523 # print "MetaHasTraitlets (classdict): ", classdict
527 # print "MetaHasTraitlets (classdict): ", classdict
524 for k,v in iteritems(classdict):
528 for k,v in iteritems(classdict):
525 if isinstance(v, TraitType):
529 if isinstance(v, TraitType):
526 v.name = k
530 v.name = k
527 elif inspect.isclass(v):
531 elif inspect.isclass(v):
528 if issubclass(v, TraitType):
532 if issubclass(v, TraitType):
529 vinst = v()
533 vinst = v()
530 vinst.name = k
534 vinst.name = k
531 classdict[k] = vinst
535 classdict[k] = vinst
532 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
536 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
533
537
534 def __init__(cls, name, bases, classdict):
538 def __init__(cls, name, bases, classdict):
535 """Finish initializing the HasTraits class.
539 """Finish initializing the HasTraits class.
536
540
537 This sets the :attr:`this_class` attribute of each TraitType in the
541 This sets the :attr:`this_class` attribute of each TraitType in the
538 class dict to the newly created class ``cls``.
542 class dict to the newly created class ``cls``.
539 """
543 """
540 for k, v in iteritems(classdict):
544 for k, v in iteritems(classdict):
541 if isinstance(v, TraitType):
545 if isinstance(v, TraitType):
542 v.this_class = cls
546 v.this_class = cls
543 super(MetaHasTraits, cls).__init__(name, bases, classdict)
547 super(MetaHasTraits, cls).__init__(name, bases, classdict)
544
548
545
549
546 class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
550 class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
547
551
548 def __new__(cls, *args, **kw):
552 def __new__(cls, *args, **kw):
549 # This is needed because object.__new__ only accepts
553 # This is needed because object.__new__ only accepts
550 # the cls argument.
554 # the cls argument.
551 new_meth = super(HasTraits, cls).__new__
555 new_meth = super(HasTraits, cls).__new__
552 if new_meth is object.__new__:
556 if new_meth is object.__new__:
553 inst = new_meth(cls)
557 inst = new_meth(cls)
554 else:
558 else:
555 inst = new_meth(cls, **kw)
559 inst = new_meth(cls, **kw)
556 inst._trait_values = {}
560 inst._trait_values = {}
557 inst._trait_notifiers = {}
561 inst._trait_notifiers = {}
558 inst._trait_dyn_inits = {}
562 inst._trait_dyn_inits = {}
559 inst._cross_validation_lock = True
563 inst._cross_validation_lock = True
560 # Here we tell all the TraitType instances to set their default
564 # Here we tell all the TraitType instances to set their default
561 # values on the instance.
565 # values on the instance.
562 for key in dir(cls):
566 for key in dir(cls):
563 # Some descriptors raise AttributeError like zope.interface's
567 # Some descriptors raise AttributeError like zope.interface's
564 # __provides__ attributes even though they exist. This causes
568 # __provides__ attributes even though they exist. This causes
565 # AttributeErrors even though they are listed in dir(cls).
569 # AttributeErrors even though they are listed in dir(cls).
566 try:
570 try:
567 value = getattr(cls, key)
571 value = getattr(cls, key)
568 except AttributeError:
572 except AttributeError:
569 pass
573 pass
570 else:
574 else:
571 if isinstance(value, TraitType):
575 if isinstance(value, TraitType):
572 value.instance_init()
576 value.instance_init()
573 if key not in kw:
577 if key not in kw:
574 value.set_default_value(inst)
578 value.set_default_value(inst)
575 inst._cross_validation_lock = False
579 inst._cross_validation_lock = False
576 return inst
580 return inst
577
581
578 def __init__(self, *args, **kw):
582 def __init__(self, *args, **kw):
579 # Allow trait values to be set using keyword arguments.
583 # Allow trait values to be set using keyword arguments.
580 # We need to use setattr for this to trigger validation and
584 # We need to use setattr for this to trigger validation and
581 # notifications.
585 # notifications.
582 with self.hold_trait_notifications():
586 with self.hold_trait_notifications():
583 for key, value in iteritems(kw):
587 for key, value in iteritems(kw):
584 setattr(self, key, value)
588 setattr(self, key, value)
585
589
586 @contextlib.contextmanager
590 @contextlib.contextmanager
587 def hold_trait_notifications(self):
591 def hold_trait_notifications(self):
588 """Context manager for bundling trait change notifications and cross
592 """Context manager for bundling trait change notifications and cross
589 validation.
593 validation.
590
594
591 Use this when doing multiple trait assignments (init, config), to avoid
595 Use this when doing multiple trait assignments (init, config), to avoid
592 race conditions in trait notifiers requesting other trait values.
596 race conditions in trait notifiers requesting other trait values.
593 All trait notifications will fire after all values have been assigned.
597 All trait notifications will fire after all values have been assigned.
594 """
598 """
595 if self._cross_validation_lock is True:
599 if self._cross_validation_lock is True:
596 yield
600 yield
597 return
601 return
598 else:
602 else:
599 self._cross_validation_lock = True
603 self._cross_validation_lock = True
600 cache = {}
604 cache = {}
601 notifications = {}
605 notifications = {}
602 _notify_trait = self._notify_trait
606 _notify_trait = self._notify_trait
603
607
604 def cache_values(*a):
608 def cache_values(*a):
605 cache[a[0]] = a
609 cache[a[0]] = a
606
610
607 def hold_notifications(*a):
611 def hold_notifications(*a):
608 notifications[a[0]] = a
612 notifications[a[0]] = a
609
613
610 self._notify_trait = cache_values
614 self._notify_trait = cache_values
611
615
612 try:
616 try:
613 yield
617 yield
614 finally:
618 finally:
615 try:
619 try:
616 self._notify_trait = hold_notifications
620 self._notify_trait = hold_notifications
617 for name in cache:
621 for name in cache:
618 if hasattr(self, '_%s_validate' % name):
622 if hasattr(self, '_%s_validate' % name):
619 cross_validate = getattr(self, '_%s_validate' % name)
623 cross_validate = getattr(self, '_%s_validate' % name)
620 setattr(self, name, cross_validate(getattr(self, name), self))
624 setattr(self, name, cross_validate(getattr(self, name), self))
621 except TraitError as e:
625 except TraitError as e:
622 self._notify_trait = lambda *x: None
626 self._notify_trait = lambda *x: None
623 for name in cache:
627 for name in cache:
624 if cache[name][1] is not Undefined:
628 if cache[name][1] is not Undefined:
625 setattr(self, name, cache[name][1])
629 setattr(self, name, cache[name][1])
626 else:
630 else:
627 delattr(self, name)
631 delattr(self, name)
628 cache = {}
632 cache = {}
629 notifications = {}
633 notifications = {}
630 raise e
634 raise e
631 finally:
635 finally:
632 self._notify_trait = _notify_trait
636 self._notify_trait = _notify_trait
633 self._cross_validation_lock = False
637 self._cross_validation_lock = False
634 if isinstance(_notify_trait, types.MethodType):
638 if isinstance(_notify_trait, types.MethodType):
635 # FIXME: remove when support is bumped to 3.4.
639 # FIXME: remove when support is bumped to 3.4.
636 # when original method is restored,
640 # when original method is restored,
637 # remove the redundant value from __dict__
641 # remove the redundant value from __dict__
638 # (only used to preserve pickleability on Python < 3.4)
642 # (only used to preserve pickleability on Python < 3.4)
639 self.__dict__.pop('_notify_trait', None)
643 self.__dict__.pop('_notify_trait', None)
640 # trigger delayed notifications
644 # trigger delayed notifications
641 for v in dict(cache, **notifications).values():
645 for v in dict(cache, **notifications).values():
642 self._notify_trait(*v)
646 self._notify_trait(*v)
643
647
644 def _notify_trait(self, name, old_value, new_value):
648 def _notify_trait(self, name, old_value, new_value):
645
649
646 # First dynamic ones
650 # First dynamic ones
647 callables = []
651 callables = []
648 callables.extend(self._trait_notifiers.get(name,[]))
652 callables.extend(self._trait_notifiers.get(name,[]))
649 callables.extend(self._trait_notifiers.get('anytrait',[]))
653 callables.extend(self._trait_notifiers.get('anytrait',[]))
650
654
651 # Now static ones
655 # Now static ones
652 try:
656 try:
653 cb = getattr(self, '_%s_changed' % name)
657 cb = getattr(self, '_%s_changed' % name)
654 except:
658 except:
655 pass
659 pass
656 else:
660 else:
657 callables.append(cb)
661 callables.append(cb)
658
662
659 # Call them all now
663 # Call them all now
660 for c in callables:
664 for c in callables:
661 # Traits catches and logs errors here. I allow them to raise
665 # Traits catches and logs errors here. I allow them to raise
662 if callable(c):
666 if callable(c):
663 argspec = getargspec(c)
667 argspec = getargspec(c)
664
668
665 nargs = len(argspec[0])
669 nargs = len(argspec[0])
666 # Bound methods have an additional 'self' argument
670 # Bound methods have an additional 'self' argument
667 # I don't know how to treat unbound methods, but they
671 # I don't know how to treat unbound methods, but they
668 # can't really be used for callbacks.
672 # can't really be used for callbacks.
669 if isinstance(c, types.MethodType):
673 if isinstance(c, types.MethodType):
670 offset = -1
674 offset = -1
671 else:
675 else:
672 offset = 0
676 offset = 0
673 if nargs + offset == 0:
677 if nargs + offset == 0:
674 c()
678 c()
675 elif nargs + offset == 1:
679 elif nargs + offset == 1:
676 c(name)
680 c(name)
677 elif nargs + offset == 2:
681 elif nargs + offset == 2:
678 c(name, new_value)
682 c(name, new_value)
679 elif nargs + offset == 3:
683 elif nargs + offset == 3:
680 c(name, old_value, new_value)
684 c(name, old_value, new_value)
681 else:
685 else:
682 raise TraitError('a trait changed callback '
686 raise TraitError('a trait changed callback '
683 'must have 0-3 arguments.')
687 'must have 0-3 arguments.')
684 else:
688 else:
685 raise TraitError('a trait changed callback '
689 raise TraitError('a trait changed callback '
686 'must be callable.')
690 'must be callable.')
687
691
688
692
689 def _add_notifiers(self, handler, name):
693 def _add_notifiers(self, handler, name):
690 if name not in self._trait_notifiers:
694 if name not in self._trait_notifiers:
691 nlist = []
695 nlist = []
692 self._trait_notifiers[name] = nlist
696 self._trait_notifiers[name] = nlist
693 else:
697 else:
694 nlist = self._trait_notifiers[name]
698 nlist = self._trait_notifiers[name]
695 if handler not in nlist:
699 if handler not in nlist:
696 nlist.append(handler)
700 nlist.append(handler)
697
701
698 def _remove_notifiers(self, handler, name):
702 def _remove_notifiers(self, handler, name):
699 if name in self._trait_notifiers:
703 if name in self._trait_notifiers:
700 nlist = self._trait_notifiers[name]
704 nlist = self._trait_notifiers[name]
701 try:
705 try:
702 index = nlist.index(handler)
706 index = nlist.index(handler)
703 except ValueError:
707 except ValueError:
704 pass
708 pass
705 else:
709 else:
706 del nlist[index]
710 del nlist[index]
707
711
708 def on_trait_change(self, handler, name=None, remove=False):
712 def on_trait_change(self, handler, name=None, remove=False):
709 """Setup a handler to be called when a trait changes.
713 """Setup a handler to be called when a trait changes.
710
714
711 This is used to setup dynamic notifications of trait changes.
715 This is used to setup dynamic notifications of trait changes.
712
716
713 Static handlers can be created by creating methods on a HasTraits
717 Static handlers can be created by creating methods on a HasTraits
714 subclass with the naming convention '_[traitname]_changed'. Thus,
718 subclass with the naming convention '_[traitname]_changed'. Thus,
715 to create static handler for the trait 'a', create the method
719 to create static handler for the trait 'a', create the method
716 _a_changed(self, name, old, new) (fewer arguments can be used, see
720 _a_changed(self, name, old, new) (fewer arguments can be used, see
717 below).
721 below).
718
722
719 Parameters
723 Parameters
720 ----------
724 ----------
721 handler : callable
725 handler : callable
722 A callable that is called when a trait changes. Its
726 A callable that is called when a trait changes. Its
723 signature can be handler(), handler(name), handler(name, new)
727 signature can be handler(), handler(name), handler(name, new)
724 or handler(name, old, new).
728 or handler(name, old, new).
725 name : list, str, None
729 name : list, str, None
726 If None, the handler will apply to all traits. If a list
730 If None, the handler will apply to all traits. If a list
727 of str, handler will apply to all names in the list. If a
731 of str, handler will apply to all names in the list. If a
728 str, the handler will apply just to that name.
732 str, the handler will apply just to that name.
729 remove : bool
733 remove : bool
730 If False (the default), then install the handler. If True
734 If False (the default), then install the handler. If True
731 then unintall it.
735 then unintall it.
732 """
736 """
733 if remove:
737 if remove:
734 names = parse_notifier_name(name)
738 names = parse_notifier_name(name)
735 for n in names:
739 for n in names:
736 self._remove_notifiers(handler, n)
740 self._remove_notifiers(handler, n)
737 else:
741 else:
738 names = parse_notifier_name(name)
742 names = parse_notifier_name(name)
739 for n in names:
743 for n in names:
740 self._add_notifiers(handler, n)
744 self._add_notifiers(handler, n)
741
745
742 @classmethod
746 @classmethod
743 def class_trait_names(cls, **metadata):
747 def class_trait_names(cls, **metadata):
744 """Get a list of all the names of this class' traits.
748 """Get a list of all the names of this class' traits.
745
749
746 This method is just like the :meth:`trait_names` method,
750 This method is just like the :meth:`trait_names` method,
747 but is unbound.
751 but is unbound.
748 """
752 """
749 return cls.class_traits(**metadata).keys()
753 return cls.class_traits(**metadata).keys()
750
754
751 @classmethod
755 @classmethod
752 def class_traits(cls, **metadata):
756 def class_traits(cls, **metadata):
753 """Get a `dict` of all the traits of this class. The dictionary
757 """Get a `dict` of all the traits of this class. The dictionary
754 is keyed on the name and the values are the TraitType objects.
758 is keyed on the name and the values are the TraitType objects.
755
759
756 This method is just like the :meth:`traits` method, but is unbound.
760 This method is just like the :meth:`traits` method, but is unbound.
757
761
758 The TraitTypes returned don't know anything about the values
762 The TraitTypes returned don't know anything about the values
759 that the various HasTrait's instances are holding.
763 that the various HasTrait's instances are holding.
760
764
761 The metadata kwargs allow functions to be passed in which
765 The metadata kwargs allow functions to be passed in which
762 filter traits based on metadata values. The functions should
766 filter traits based on metadata values. The functions should
763 take a single value as an argument and return a boolean. If
767 take a single value as an argument and return a boolean. If
764 any function returns False, then the trait is not included in
768 any function returns False, then the trait is not included in
765 the output. This does not allow for any simple way of
769 the output. This does not allow for any simple way of
766 testing that a metadata name exists and has any
770 testing that a metadata name exists and has any
767 value because get_metadata returns None if a metadata key
771 value because get_metadata returns None if a metadata key
768 doesn't exist.
772 doesn't exist.
769 """
773 """
770 traits = dict([memb for memb in getmembers(cls) if
774 traits = dict([memb for memb in getmembers(cls) if
771 isinstance(memb[1], TraitType)])
775 isinstance(memb[1], TraitType)])
772
776
773 if len(metadata) == 0:
777 if len(metadata) == 0:
774 return traits
778 return traits
775
779
776 for meta_name, meta_eval in metadata.items():
780 for meta_name, meta_eval in metadata.items():
777 if type(meta_eval) is not FunctionType:
781 if type(meta_eval) is not FunctionType:
778 metadata[meta_name] = _SimpleTest(meta_eval)
782 metadata[meta_name] = _SimpleTest(meta_eval)
779
783
780 result = {}
784 result = {}
781 for name, trait in traits.items():
785 for name, trait in traits.items():
782 for meta_name, meta_eval in metadata.items():
786 for meta_name, meta_eval in metadata.items():
783 if not meta_eval(trait.get_metadata(meta_name)):
787 if not meta_eval(trait.get_metadata(meta_name)):
784 break
788 break
785 else:
789 else:
786 result[name] = trait
790 result[name] = trait
787
791
788 return result
792 return result
789
793
790 def trait_names(self, **metadata):
794 def trait_names(self, **metadata):
791 """Get a list of all the names of this class' traits."""
795 """Get a list of all the names of this class' traits."""
792 return self.traits(**metadata).keys()
796 return self.traits(**metadata).keys()
793
797
794 def traits(self, **metadata):
798 def traits(self, **metadata):
795 """Get a `dict` of all the traits of this class. The dictionary
799 """Get a `dict` of all the traits of this class. The dictionary
796 is keyed on the name and the values are the TraitType objects.
800 is keyed on the name and the values are the TraitType objects.
797
801
798 The TraitTypes returned don't know anything about the values
802 The TraitTypes returned don't know anything about the values
799 that the various HasTrait's instances are holding.
803 that the various HasTrait's instances are holding.
800
804
801 The metadata kwargs allow functions to be passed in which
805 The metadata kwargs allow functions to be passed in which
802 filter traits based on metadata values. The functions should
806 filter traits based on metadata values. The functions should
803 take a single value as an argument and return a boolean. If
807 take a single value as an argument and return a boolean. If
804 any function returns False, then the trait is not included in
808 any function returns False, then the trait is not included in
805 the output. This does not allow for any simple way of
809 the output. This does not allow for any simple way of
806 testing that a metadata name exists and has any
810 testing that a metadata name exists and has any
807 value because get_metadata returns None if a metadata key
811 value because get_metadata returns None if a metadata key
808 doesn't exist.
812 doesn't exist.
809 """
813 """
810 traits = dict([memb for memb in getmembers(self.__class__) if
814 traits = dict([memb for memb in getmembers(self.__class__) if
811 isinstance(memb[1], TraitType)])
815 isinstance(memb[1], TraitType)])
812
816
813 if len(metadata) == 0:
817 if len(metadata) == 0:
814 return traits
818 return traits
815
819
816 for meta_name, meta_eval in metadata.items():
820 for meta_name, meta_eval in metadata.items():
817 if type(meta_eval) is not FunctionType:
821 if type(meta_eval) is not FunctionType:
818 metadata[meta_name] = _SimpleTest(meta_eval)
822 metadata[meta_name] = _SimpleTest(meta_eval)
819
823
820 result = {}
824 result = {}
821 for name, trait in traits.items():
825 for name, trait in traits.items():
822 for meta_name, meta_eval in metadata.items():
826 for meta_name, meta_eval in metadata.items():
823 if not meta_eval(trait.get_metadata(meta_name)):
827 if not meta_eval(trait.get_metadata(meta_name)):
824 break
828 break
825 else:
829 else:
826 result[name] = trait
830 result[name] = trait
827
831
828 return result
832 return result
829
833
830 def trait_metadata(self, traitname, key, default=None):
834 def trait_metadata(self, traitname, key, default=None):
831 """Get metadata values for trait by key."""
835 """Get metadata values for trait by key."""
832 try:
836 try:
833 trait = getattr(self.__class__, traitname)
837 trait = getattr(self.__class__, traitname)
834 except AttributeError:
838 except AttributeError:
835 raise TraitError("Class %s does not have a trait named %s" %
839 raise TraitError("Class %s does not have a trait named %s" %
836 (self.__class__.__name__, traitname))
840 (self.__class__.__name__, traitname))
837 else:
841 else:
838 return trait.get_metadata(key, default)
842 return trait.get_metadata(key, default)
839
843
840 def add_trait(self, traitname, trait):
844 def add_trait(self, traitname, trait):
841 """Dynamically add a trait attribute to the HasTraits instance."""
845 """Dynamically add a trait attribute to the HasTraits instance."""
842 self.__class__ = type(self.__class__.__name__, (self.__class__,),
846 self.__class__ = type(self.__class__.__name__, (self.__class__,),
843 {traitname: trait})
847 {traitname: trait})
844 trait.set_default_value(self)
848 trait.set_default_value(self)
845
849
846 #-----------------------------------------------------------------------------
850 #-----------------------------------------------------------------------------
847 # Actual TraitTypes implementations/subclasses
851 # Actual TraitTypes implementations/subclasses
848 #-----------------------------------------------------------------------------
852 #-----------------------------------------------------------------------------
849
853
850 #-----------------------------------------------------------------------------
854 #-----------------------------------------------------------------------------
851 # TraitTypes subclasses for handling classes and instances of classes
855 # TraitTypes subclasses for handling classes and instances of classes
852 #-----------------------------------------------------------------------------
856 #-----------------------------------------------------------------------------
853
857
854
858
855 class ClassBasedTraitType(TraitType):
859 class ClassBasedTraitType(TraitType):
856 """
860 """
857 A trait with error reporting and string -> type resolution for Type,
861 A trait with error reporting and string -> type resolution for Type,
858 Instance and This.
862 Instance and This.
859 """
863 """
860
864
861 def _resolve_string(self, string):
865 def _resolve_string(self, string):
862 """
866 """
863 Resolve a string supplied for a type into an actual object.
867 Resolve a string supplied for a type into an actual object.
864 """
868 """
865 return import_item(string)
869 return import_item(string)
866
870
867 def error(self, obj, value):
871 def error(self, obj, value):
868 kind = type(value)
872 kind = type(value)
869 if (not py3compat.PY3) and kind is InstanceType:
873 if (not py3compat.PY3) and kind is InstanceType:
870 msg = 'class %s' % value.__class__.__name__
874 msg = 'class %s' % value.__class__.__name__
871 else:
875 else:
872 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
876 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
873
877
874 if obj is not None:
878 if obj is not None:
875 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
879 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
876 % (self.name, class_of(obj),
880 % (self.name, class_of(obj),
877 self.info(), msg)
881 self.info(), msg)
878 else:
882 else:
879 e = "The '%s' trait must be %s, but a value of %r was specified." \
883 e = "The '%s' trait must be %s, but a value of %r was specified." \
880 % (self.name, self.info(), msg)
884 % (self.name, self.info(), msg)
881
885
882 raise TraitError(e)
886 raise TraitError(e)
883
887
884
888
885 class Type(ClassBasedTraitType):
889 class Type(ClassBasedTraitType):
886 """A trait whose value must be a subclass of a specified class."""
890 """A trait whose value must be a subclass of a specified class."""
887
891
888 def __init__ (self, default_value=None, klass=None, allow_none=False,
892 def __init__ (self, default_value=None, klass=None, allow_none=False,
889 **metadata):
893 **metadata):
890 """Construct a Type trait
894 """Construct a Type trait
891
895
892 A Type trait specifies that its values must be subclasses of
896 A Type trait specifies that its values must be subclasses of
893 a particular class.
897 a particular class.
894
898
895 If only ``default_value`` is given, it is used for the ``klass`` as
899 If only ``default_value`` is given, it is used for the ``klass`` as
896 well.
900 well.
897
901
898 Parameters
902 Parameters
899 ----------
903 ----------
900 default_value : class, str or None
904 default_value : class, str or None
901 The default value must be a subclass of klass. If an str,
905 The default value must be a subclass of klass. If an str,
902 the str must be a fully specified class name, like 'foo.bar.Bah'.
906 the str must be a fully specified class name, like 'foo.bar.Bah'.
903 The string is resolved into real class, when the parent
907 The string is resolved into real class, when the parent
904 :class:`HasTraits` class is instantiated.
908 :class:`HasTraits` class is instantiated.
905 klass : class, str, None
909 klass : class, str, None
906 Values of this trait must be a subclass of klass. The klass
910 Values of this trait must be a subclass of klass. The klass
907 may be specified in a string like: 'foo.bar.MyClass'.
911 may be specified in a string like: 'foo.bar.MyClass'.
908 The string is resolved into real class, when the parent
912 The string is resolved into real class, when the parent
909 :class:`HasTraits` class is instantiated.
913 :class:`HasTraits` class is instantiated.
910 allow_none : bool [ default True ]
914 allow_none : bool [ default True ]
911 Indicates whether None is allowed as an assignable value. Even if
915 Indicates whether None is allowed as an assignable value. Even if
912 ``False``, the default value may be ``None``.
916 ``False``, the default value may be ``None``.
913 """
917 """
914 if default_value is None:
918 if default_value is None:
915 if klass is None:
919 if klass is None:
916 klass = object
920 klass = object
917 elif klass is None:
921 elif klass is None:
918 klass = default_value
922 klass = default_value
919
923
920 if not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
924 if not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
921 raise TraitError("A Type trait must specify a class.")
925 raise TraitError("A Type trait must specify a class.")
922
926
923 self.klass = klass
927 self.klass = klass
924
928
925 super(Type, self).__init__(default_value, allow_none=allow_none, **metadata)
929 super(Type, self).__init__(default_value, allow_none=allow_none, **metadata)
926
930
927 def validate(self, obj, value):
931 def validate(self, obj, value):
928 """Validates that the value is a valid object instance."""
932 """Validates that the value is a valid object instance."""
929 if isinstance(value, py3compat.string_types):
933 if isinstance(value, py3compat.string_types):
930 try:
934 try:
931 value = self._resolve_string(value)
935 value = self._resolve_string(value)
932 except ImportError:
936 except ImportError:
933 raise TraitError("The '%s' trait of %s instance must be a type, but "
937 raise TraitError("The '%s' trait of %s instance must be a type, but "
934 "%r could not be imported" % (self.name, obj, value))
938 "%r could not be imported" % (self.name, obj, value))
935 try:
939 try:
936 if issubclass(value, self.klass):
940 if issubclass(value, self.klass):
937 return value
941 return value
938 except:
942 except:
939 pass
943 pass
940
944
941 self.error(obj, value)
945 self.error(obj, value)
942
946
943 def info(self):
947 def info(self):
944 """ Returns a description of the trait."""
948 """ Returns a description of the trait."""
945 if isinstance(self.klass, py3compat.string_types):
949 if isinstance(self.klass, py3compat.string_types):
946 klass = self.klass
950 klass = self.klass
947 else:
951 else:
948 klass = self.klass.__name__
952 klass = self.klass.__name__
949 result = 'a subclass of ' + klass
953 result = 'a subclass of ' + klass
950 if self.allow_none:
954 if self.allow_none:
951 return result + ' or None'
955 return result + ' or None'
952 return result
956 return result
953
957
954 def instance_init(self):
958 def instance_init(self):
955 self._resolve_classes()
959 self._resolve_classes()
956 super(Type, self).instance_init()
960 super(Type, self).instance_init()
957
961
958 def _resolve_classes(self):
962 def _resolve_classes(self):
959 if isinstance(self.klass, py3compat.string_types):
963 if isinstance(self.klass, py3compat.string_types):
960 self.klass = self._resolve_string(self.klass)
964 self.klass = self._resolve_string(self.klass)
961 if isinstance(self.default_value, py3compat.string_types):
965 if isinstance(self.default_value, py3compat.string_types):
962 self.default_value = self._resolve_string(self.default_value)
966 self.default_value = self._resolve_string(self.default_value)
963
967
964 def get_default_value(self):
968 def get_default_value(self):
965 return self.default_value
969 return self.default_value
966
970
967
971
968 class DefaultValueGenerator(object):
972 class DefaultValueGenerator(object):
969 """A class for generating new default value instances."""
973 """A class for generating new default value instances."""
970
974
971 def __init__(self, *args, **kw):
975 def __init__(self, *args, **kw):
972 self.args = args
976 self.args = args
973 self.kw = kw
977 self.kw = kw
974
978
975 def generate(self, klass):
979 def generate(self, klass):
976 return klass(*self.args, **self.kw)
980 return klass(*self.args, **self.kw)
977
981
978
982
979 class Instance(ClassBasedTraitType):
983 class Instance(ClassBasedTraitType):
980 """A trait whose value must be an instance of a specified class.
984 """A trait whose value must be an instance of a specified class.
981
985
982 The value can also be an instance of a subclass of the specified class.
986 The value can also be an instance of a subclass of the specified class.
983
987
984 Subclasses can declare default classes by overriding the klass attribute
988 Subclasses can declare default classes by overriding the klass attribute
985 """
989 """
986
990
987 klass = None
991 klass = None
988
992
989 def __init__(self, klass=None, args=None, kw=None, allow_none=False,
993 def __init__(self, klass=None, args=None, kw=None, allow_none=False,
990 **metadata ):
994 **metadata ):
991 """Construct an Instance trait.
995 """Construct an Instance trait.
992
996
993 This trait allows values that are instances of a particular
997 This trait allows values that are instances of a particular
994 class or its subclasses. Our implementation is quite different
998 class or its subclasses. Our implementation is quite different
995 from that of enthough.traits as we don't allow instances to be used
999 from that of enthough.traits as we don't allow instances to be used
996 for klass and we handle the ``args`` and ``kw`` arguments differently.
1000 for klass and we handle the ``args`` and ``kw`` arguments differently.
997
1001
998 Parameters
1002 Parameters
999 ----------
1003 ----------
1000 klass : class, str
1004 klass : class, str
1001 The class that forms the basis for the trait. Class names
1005 The class that forms the basis for the trait. Class names
1002 can also be specified as strings, like 'foo.bar.Bar'.
1006 can also be specified as strings, like 'foo.bar.Bar'.
1003 args : tuple
1007 args : tuple
1004 Positional arguments for generating the default value.
1008 Positional arguments for generating the default value.
1005 kw : dict
1009 kw : dict
1006 Keyword arguments for generating the default value.
1010 Keyword arguments for generating the default value.
1007 allow_none : bool [default True]
1011 allow_none : bool [default True]
1008 Indicates whether None is allowed as a value.
1012 Indicates whether None is allowed as a value.
1009
1013
1010 Notes
1014 Notes
1011 -----
1015 -----
1012 If both ``args`` and ``kw`` are None, then the default value is None.
1016 If both ``args`` and ``kw`` are None, then the default value is None.
1013 If ``args`` is a tuple and ``kw`` is a dict, then the default is
1017 If ``args`` is a tuple and ``kw`` is a dict, then the default is
1014 created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is
1018 created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is
1015 None, the None is replaced by ``()`` or ``{}``, respectively.
1019 None, the None is replaced by ``()`` or ``{}``, respectively.
1016 """
1020 """
1017 if klass is None:
1021 if klass is None:
1018 klass = self.klass
1022 klass = self.klass
1019
1023
1020 if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
1024 if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
1021 self.klass = klass
1025 self.klass = klass
1022 else:
1026 else:
1023 raise TraitError('The klass attribute must be a class'
1027 raise TraitError('The klass attribute must be a class'
1024 ' not: %r' % klass)
1028 ' not: %r' % klass)
1025
1029
1026 # self.klass is a class, so handle default_value
1030 # self.klass is a class, so handle default_value
1027 if args is None and kw is None:
1031 if args is None and kw is None:
1028 default_value = None
1032 default_value = None
1029 else:
1033 else:
1030 if args is None:
1034 if args is None:
1031 # kw is not None
1035 # kw is not None
1032 args = ()
1036 args = ()
1033 elif kw is None:
1037 elif kw is None:
1034 # args is not None
1038 # args is not None
1035 kw = {}
1039 kw = {}
1036
1040
1037 if not isinstance(kw, dict):
1041 if not isinstance(kw, dict):
1038 raise TraitError("The 'kw' argument must be a dict or None.")
1042 raise TraitError("The 'kw' argument must be a dict or None.")
1039 if not isinstance(args, tuple):
1043 if not isinstance(args, tuple):
1040 raise TraitError("The 'args' argument must be a tuple or None.")
1044 raise TraitError("The 'args' argument must be a tuple or None.")
1041
1045
1042 default_value = DefaultValueGenerator(*args, **kw)
1046 default_value = DefaultValueGenerator(*args, **kw)
1043
1047
1044 super(Instance, self).__init__(default_value, allow_none=allow_none, **metadata)
1048 super(Instance, self).__init__(default_value, allow_none=allow_none, **metadata)
1045
1049
1046 def validate(self, obj, value):
1050 def validate(self, obj, value):
1047 if isinstance(value, self.klass):
1051 if isinstance(value, self.klass):
1048 return value
1052 return value
1049 else:
1053 else:
1050 self.error(obj, value)
1054 self.error(obj, value)
1051
1055
1052 def info(self):
1056 def info(self):
1053 if isinstance(self.klass, py3compat.string_types):
1057 if isinstance(self.klass, py3compat.string_types):
1054 klass = self.klass
1058 klass = self.klass
1055 else:
1059 else:
1056 klass = self.klass.__name__
1060 klass = self.klass.__name__
1057 result = class_of(klass)
1061 result = class_of(klass)
1058 if self.allow_none:
1062 if self.allow_none:
1059 return result + ' or None'
1063 return result + ' or None'
1060
1064
1061 return result
1065 return result
1062
1066
1063 def instance_init(self):
1067 def instance_init(self):
1064 self._resolve_classes()
1068 self._resolve_classes()
1065 super(Instance, self).instance_init()
1069 super(Instance, self).instance_init()
1066
1070
1067 def _resolve_classes(self):
1071 def _resolve_classes(self):
1068 if isinstance(self.klass, py3compat.string_types):
1072 if isinstance(self.klass, py3compat.string_types):
1069 self.klass = self._resolve_string(self.klass)
1073 self.klass = self._resolve_string(self.klass)
1070
1074
1071 def get_default_value(self):
1075 def get_default_value(self):
1072 """Instantiate a default value instance.
1076 """Instantiate a default value instance.
1073
1077
1074 This is called when the containing HasTraits classes'
1078 This is called when the containing HasTraits classes'
1075 :meth:`__new__` method is called to ensure that a unique instance
1079 :meth:`__new__` method is called to ensure that a unique instance
1076 is created for each HasTraits instance.
1080 is created for each HasTraits instance.
1077 """
1081 """
1078 dv = self.default_value
1082 dv = self.default_value
1079 if isinstance(dv, DefaultValueGenerator):
1083 if isinstance(dv, DefaultValueGenerator):
1080 return dv.generate(self.klass)
1084 return dv.generate(self.klass)
1081 else:
1085 else:
1082 return dv
1086 return dv
1083
1087
1084
1088
1085 class ForwardDeclaredMixin(object):
1089 class ForwardDeclaredMixin(object):
1086 """
1090 """
1087 Mixin for forward-declared versions of Instance and Type.
1091 Mixin for forward-declared versions of Instance and Type.
1088 """
1092 """
1089 def _resolve_string(self, string):
1093 def _resolve_string(self, string):
1090 """
1094 """
1091 Find the specified class name by looking for it in the module in which
1095 Find the specified class name by looking for it in the module in which
1092 our this_class attribute was defined.
1096 our this_class attribute was defined.
1093 """
1097 """
1094 modname = self.this_class.__module__
1098 modname = self.this_class.__module__
1095 return import_item('.'.join([modname, string]))
1099 return import_item('.'.join([modname, string]))
1096
1100
1097
1101
1098 class ForwardDeclaredType(ForwardDeclaredMixin, Type):
1102 class ForwardDeclaredType(ForwardDeclaredMixin, Type):
1099 """
1103 """
1100 Forward-declared version of Type.
1104 Forward-declared version of Type.
1101 """
1105 """
1102 pass
1106 pass
1103
1107
1104
1108
1105 class ForwardDeclaredInstance(ForwardDeclaredMixin, Instance):
1109 class ForwardDeclaredInstance(ForwardDeclaredMixin, Instance):
1106 """
1110 """
1107 Forward-declared version of Instance.
1111 Forward-declared version of Instance.
1108 """
1112 """
1109 pass
1113 pass
1110
1114
1111
1115
1112 class This(ClassBasedTraitType):
1116 class This(ClassBasedTraitType):
1113 """A trait for instances of the class containing this trait.
1117 """A trait for instances of the class containing this trait.
1114
1118
1115 Because how how and when class bodies are executed, the ``This``
1119 Because how how and when class bodies are executed, the ``This``
1116 trait can only have a default value of None. This, and because we
1120 trait can only have a default value of None. This, and because we
1117 always validate default values, ``allow_none`` is *always* true.
1121 always validate default values, ``allow_none`` is *always* true.
1118 """
1122 """
1119
1123
1120 info_text = 'an instance of the same type as the receiver or None'
1124 info_text = 'an instance of the same type as the receiver or None'
1121
1125
1122 def __init__(self, **metadata):
1126 def __init__(self, **metadata):
1123 super(This, self).__init__(None, **metadata)
1127 super(This, self).__init__(None, **metadata)
1124
1128
1125 def validate(self, obj, value):
1129 def validate(self, obj, value):
1126 # What if value is a superclass of obj.__class__? This is
1130 # What if value is a superclass of obj.__class__? This is
1127 # complicated if it was the superclass that defined the This
1131 # complicated if it was the superclass that defined the This
1128 # trait.
1132 # trait.
1129 if isinstance(value, self.this_class) or (value is None):
1133 if isinstance(value, self.this_class) or (value is None):
1130 return value
1134 return value
1131 else:
1135 else:
1132 self.error(obj, value)
1136 self.error(obj, value)
1133
1137
1134
1138
1135 class Union(TraitType):
1139 class Union(TraitType):
1136 """A trait type representing a Union type."""
1140 """A trait type representing a Union type."""
1137
1141
1138 def __init__(self, trait_types, **metadata):
1142 def __init__(self, trait_types, **metadata):
1139 """Construct a Union trait.
1143 """Construct a Union trait.
1140
1144
1141 This trait allows values that are allowed by at least one of the
1145 This trait allows values that are allowed by at least one of the
1142 specified trait types. A Union traitlet cannot have metadata on
1146 specified trait types. A Union traitlet cannot have metadata on
1143 its own, besides the metadata of the listed types.
1147 its own, besides the metadata of the listed types.
1144
1148
1145 Parameters
1149 Parameters
1146 ----------
1150 ----------
1147 trait_types: sequence
1151 trait_types: sequence
1148 The list of trait types of length at least 1.
1152 The list of trait types of length at least 1.
1149
1153
1150 Notes
1154 Notes
1151 -----
1155 -----
1152 Union([Float(), Bool(), Int()]) attempts to validate the provided values
1156 Union([Float(), Bool(), Int()]) attempts to validate the provided values
1153 with the validation function of Float, then Bool, and finally Int.
1157 with the validation function of Float, then Bool, and finally Int.
1154 """
1158 """
1155 self.trait_types = trait_types
1159 self.trait_types = trait_types
1156 self.info_text = " or ".join([tt.info_text for tt in self.trait_types])
1160 self.info_text = " or ".join([tt.info_text for tt in self.trait_types])
1157 self.default_value = self.trait_types[0].get_default_value()
1161 self.default_value = self.trait_types[0].get_default_value()
1158 super(Union, self).__init__(**metadata)
1162 super(Union, self).__init__(**metadata)
1159
1163
1160 def instance_init(self):
1164 def instance_init(self):
1161 for trait_type in self.trait_types:
1165 for trait_type in self.trait_types:
1162 trait_type.name = self.name
1166 trait_type.name = self.name
1163 trait_type.this_class = self.this_class
1167 trait_type.this_class = self.this_class
1164 trait_type.instance_init()
1168 trait_type.instance_init()
1165 super(Union, self).instance_init()
1169 super(Union, self).instance_init()
1166
1170
1167 def validate(self, obj, value):
1171 def validate(self, obj, value):
1168 for trait_type in self.trait_types:
1172 for trait_type in self.trait_types:
1169 try:
1173 try:
1170 v = trait_type._validate(obj, value)
1174 v = trait_type._validate(obj, value)
1171 self._metadata = trait_type._metadata
1175 self._metadata = trait_type._metadata
1172 return v
1176 return v
1173 except TraitError:
1177 except TraitError:
1174 continue
1178 continue
1175 self.error(obj, value)
1179 self.error(obj, value)
1176
1180
1177 def __or__(self, other):
1181 def __or__(self, other):
1178 if isinstance(other, Union):
1182 if isinstance(other, Union):
1179 return Union(self.trait_types + other.trait_types)
1183 return Union(self.trait_types + other.trait_types)
1180 else:
1184 else:
1181 return Union(self.trait_types + [other])
1185 return Union(self.trait_types + [other])
1182
1186
1183 #-----------------------------------------------------------------------------
1187 #-----------------------------------------------------------------------------
1184 # Basic TraitTypes implementations/subclasses
1188 # Basic TraitTypes implementations/subclasses
1185 #-----------------------------------------------------------------------------
1189 #-----------------------------------------------------------------------------
1186
1190
1187
1191
1188 class Any(TraitType):
1192 class Any(TraitType):
1189 default_value = None
1193 default_value = None
1190 info_text = 'any value'
1194 info_text = 'any value'
1191
1195
1192
1196
1193 class Int(TraitType):
1197 class Int(TraitType):
1194 """An int trait."""
1198 """An int trait."""
1195
1199
1196 default_value = 0
1200 default_value = 0
1197 info_text = 'an int'
1201 info_text = 'an int'
1198
1202
1199 def validate(self, obj, value):
1203 def validate(self, obj, value):
1200 if isinstance(value, int):
1204 if isinstance(value, int):
1201 return value
1205 return value
1202 self.error(obj, value)
1206 self.error(obj, value)
1203
1207
1204 class CInt(Int):
1208 class CInt(Int):
1205 """A casting version of the int trait."""
1209 """A casting version of the int trait."""
1206
1210
1207 def validate(self, obj, value):
1211 def validate(self, obj, value):
1208 try:
1212 try:
1209 return int(value)
1213 return int(value)
1210 except:
1214 except:
1211 self.error(obj, value)
1215 self.error(obj, value)
1212
1216
1213 if py3compat.PY3:
1217 if py3compat.PY3:
1214 Long, CLong = Int, CInt
1218 Long, CLong = Int, CInt
1215 Integer = Int
1219 Integer = Int
1216 else:
1220 else:
1217 class Long(TraitType):
1221 class Long(TraitType):
1218 """A long integer trait."""
1222 """A long integer trait."""
1219
1223
1220 default_value = 0
1224 default_value = 0
1221 info_text = 'a long'
1225 info_text = 'a long'
1222
1226
1223 def validate(self, obj, value):
1227 def validate(self, obj, value):
1224 if isinstance(value, long):
1228 if isinstance(value, long):
1225 return value
1229 return value
1226 if isinstance(value, int):
1230 if isinstance(value, int):
1227 return long(value)
1231 return long(value)
1228 self.error(obj, value)
1232 self.error(obj, value)
1229
1233
1230
1234
1231 class CLong(Long):
1235 class CLong(Long):
1232 """A casting version of the long integer trait."""
1236 """A casting version of the long integer trait."""
1233
1237
1234 def validate(self, obj, value):
1238 def validate(self, obj, value):
1235 try:
1239 try:
1236 return long(value)
1240 return long(value)
1237 except:
1241 except:
1238 self.error(obj, value)
1242 self.error(obj, value)
1239
1243
1240 class Integer(TraitType):
1244 class Integer(TraitType):
1241 """An integer trait.
1245 """An integer trait.
1242
1246
1243 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
1247 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
1244
1248
1245 default_value = 0
1249 default_value = 0
1246 info_text = 'an integer'
1250 info_text = 'an integer'
1247
1251
1248 def validate(self, obj, value):
1252 def validate(self, obj, value):
1249 if isinstance(value, int):
1253 if isinstance(value, int):
1250 return value
1254 return value
1251 if isinstance(value, long):
1255 if isinstance(value, long):
1252 # downcast longs that fit in int:
1256 # downcast longs that fit in int:
1253 # note that int(n > sys.maxint) returns a long, so
1257 # note that int(n > sys.maxint) returns a long, so
1254 # we don't need a condition on this cast
1258 # we don't need a condition on this cast
1255 return int(value)
1259 return int(value)
1256 if sys.platform == "cli":
1260 if sys.platform == "cli":
1257 from System import Int64
1261 from System import Int64
1258 if isinstance(value, Int64):
1262 if isinstance(value, Int64):
1259 return int(value)
1263 return int(value)
1260 self.error(obj, value)
1264 self.error(obj, value)
1261
1265
1262
1266
1263 class Float(TraitType):
1267 class Float(TraitType):
1264 """A float trait."""
1268 """A float trait."""
1265
1269
1266 default_value = 0.0
1270 default_value = 0.0
1267 info_text = 'a float'
1271 info_text = 'a float'
1268
1272
1269 def validate(self, obj, value):
1273 def validate(self, obj, value):
1270 if isinstance(value, float):
1274 if isinstance(value, float):
1271 return value
1275 return value
1272 if isinstance(value, int):
1276 if isinstance(value, int):
1273 return float(value)
1277 return float(value)
1274 self.error(obj, value)
1278 self.error(obj, value)
1275
1279
1276
1280
1277 class CFloat(Float):
1281 class CFloat(Float):
1278 """A casting version of the float trait."""
1282 """A casting version of the float trait."""
1279
1283
1280 def validate(self, obj, value):
1284 def validate(self, obj, value):
1281 try:
1285 try:
1282 return float(value)
1286 return float(value)
1283 except:
1287 except:
1284 self.error(obj, value)
1288 self.error(obj, value)
1285
1289
1286 class Complex(TraitType):
1290 class Complex(TraitType):
1287 """A trait for complex numbers."""
1291 """A trait for complex numbers."""
1288
1292
1289 default_value = 0.0 + 0.0j
1293 default_value = 0.0 + 0.0j
1290 info_text = 'a complex number'
1294 info_text = 'a complex number'
1291
1295
1292 def validate(self, obj, value):
1296 def validate(self, obj, value):
1293 if isinstance(value, complex):
1297 if isinstance(value, complex):
1294 return value
1298 return value
1295 if isinstance(value, (float, int)):
1299 if isinstance(value, (float, int)):
1296 return complex(value)
1300 return complex(value)
1297 self.error(obj, value)
1301 self.error(obj, value)
1298
1302
1299
1303
1300 class CComplex(Complex):
1304 class CComplex(Complex):
1301 """A casting version of the complex number trait."""
1305 """A casting version of the complex number trait."""
1302
1306
1303 def validate (self, obj, value):
1307 def validate (self, obj, value):
1304 try:
1308 try:
1305 return complex(value)
1309 return complex(value)
1306 except:
1310 except:
1307 self.error(obj, value)
1311 self.error(obj, value)
1308
1312
1309 # We should always be explicit about whether we're using bytes or unicode, both
1313 # We should always be explicit about whether we're using bytes or unicode, both
1310 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
1314 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
1311 # we don't have a Str type.
1315 # we don't have a Str type.
1312 class Bytes(TraitType):
1316 class Bytes(TraitType):
1313 """A trait for byte strings."""
1317 """A trait for byte strings."""
1314
1318
1315 default_value = b''
1319 default_value = b''
1316 info_text = 'a bytes object'
1320 info_text = 'a bytes object'
1317
1321
1318 def validate(self, obj, value):
1322 def validate(self, obj, value):
1319 if isinstance(value, bytes):
1323 if isinstance(value, bytes):
1320 return value
1324 return value
1321 self.error(obj, value)
1325 self.error(obj, value)
1322
1326
1323
1327
1324 class CBytes(Bytes):
1328 class CBytes(Bytes):
1325 """A casting version of the byte string trait."""
1329 """A casting version of the byte string trait."""
1326
1330
1327 def validate(self, obj, value):
1331 def validate(self, obj, value):
1328 try:
1332 try:
1329 return bytes(value)
1333 return bytes(value)
1330 except:
1334 except:
1331 self.error(obj, value)
1335 self.error(obj, value)
1332
1336
1333
1337
1334 class Unicode(TraitType):
1338 class Unicode(TraitType):
1335 """A trait for unicode strings."""
1339 """A trait for unicode strings."""
1336
1340
1337 default_value = u''
1341 default_value = u''
1338 info_text = 'a unicode string'
1342 info_text = 'a unicode string'
1339
1343
1340 def validate(self, obj, value):
1344 def validate(self, obj, value):
1341 if isinstance(value, py3compat.unicode_type):
1345 if isinstance(value, py3compat.unicode_type):
1342 return value
1346 return value
1343 if isinstance(value, bytes):
1347 if isinstance(value, bytes):
1344 try:
1348 try:
1345 return value.decode('ascii', 'strict')
1349 return value.decode('ascii', 'strict')
1346 except UnicodeDecodeError:
1350 except UnicodeDecodeError:
1347 msg = "Could not decode {!r} for unicode trait '{}' of {} instance."
1351 msg = "Could not decode {!r} for unicode trait '{}' of {} instance."
1348 raise TraitError(msg.format(value, self.name, class_of(obj)))
1352 raise TraitError(msg.format(value, self.name, class_of(obj)))
1349 self.error(obj, value)
1353 self.error(obj, value)
1350
1354
1351
1355
1352 class CUnicode(Unicode):
1356 class CUnicode(Unicode):
1353 """A casting version of the unicode trait."""
1357 """A casting version of the unicode trait."""
1354
1358
1355 def validate(self, obj, value):
1359 def validate(self, obj, value):
1356 try:
1360 try:
1357 return py3compat.unicode_type(value)
1361 return py3compat.unicode_type(value)
1358 except:
1362 except:
1359 self.error(obj, value)
1363 self.error(obj, value)
1360
1364
1361
1365
1362 class ObjectName(TraitType):
1366 class ObjectName(TraitType):
1363 """A string holding a valid object name in this version of Python.
1367 """A string holding a valid object name in this version of Python.
1364
1368
1365 This does not check that the name exists in any scope."""
1369 This does not check that the name exists in any scope."""
1366 info_text = "a valid object identifier in Python"
1370 info_text = "a valid object identifier in Python"
1367
1371
1368 if py3compat.PY3:
1372 if py3compat.PY3:
1369 # Python 3:
1373 # Python 3:
1370 coerce_str = staticmethod(lambda _,s: s)
1374 coerce_str = staticmethod(lambda _,s: s)
1371
1375
1372 else:
1376 else:
1373 # Python 2:
1377 # Python 2:
1374 def coerce_str(self, obj, value):
1378 def coerce_str(self, obj, value):
1375 "In Python 2, coerce ascii-only unicode to str"
1379 "In Python 2, coerce ascii-only unicode to str"
1376 if isinstance(value, unicode):
1380 if isinstance(value, unicode):
1377 try:
1381 try:
1378 return str(value)
1382 return str(value)
1379 except UnicodeEncodeError:
1383 except UnicodeEncodeError:
1380 self.error(obj, value)
1384 self.error(obj, value)
1381 return value
1385 return value
1382
1386
1383 def validate(self, obj, value):
1387 def validate(self, obj, value):
1384 value = self.coerce_str(obj, value)
1388 value = self.coerce_str(obj, value)
1385
1389
1386 if isinstance(value, string_types) and py3compat.isidentifier(value):
1390 if isinstance(value, string_types) and py3compat.isidentifier(value):
1387 return value
1391 return value
1388 self.error(obj, value)
1392 self.error(obj, value)
1389
1393
1390 class DottedObjectName(ObjectName):
1394 class DottedObjectName(ObjectName):
1391 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1395 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1392 def validate(self, obj, value):
1396 def validate(self, obj, value):
1393 value = self.coerce_str(obj, value)
1397 value = self.coerce_str(obj, value)
1394
1398
1395 if isinstance(value, string_types) and py3compat.isidentifier(value, dotted=True):
1399 if isinstance(value, string_types) and py3compat.isidentifier(value, dotted=True):
1396 return value
1400 return value
1397 self.error(obj, value)
1401 self.error(obj, value)
1398
1402
1399
1403
1400 class Bool(TraitType):
1404 class Bool(TraitType):
1401 """A boolean (True, False) trait."""
1405 """A boolean (True, False) trait."""
1402
1406
1403 default_value = False
1407 default_value = False
1404 info_text = 'a boolean'
1408 info_text = 'a boolean'
1405
1409
1406 def validate(self, obj, value):
1410 def validate(self, obj, value):
1407 if isinstance(value, bool):
1411 if isinstance(value, bool):
1408 return value
1412 return value
1409 self.error(obj, value)
1413 self.error(obj, value)
1410
1414
1411
1415
1412 class CBool(Bool):
1416 class CBool(Bool):
1413 """A casting version of the boolean trait."""
1417 """A casting version of the boolean trait."""
1414
1418
1415 def validate(self, obj, value):
1419 def validate(self, obj, value):
1416 try:
1420 try:
1417 return bool(value)
1421 return bool(value)
1418 except:
1422 except:
1419 self.error(obj, value)
1423 self.error(obj, value)
1420
1424
1421
1425
1422 class Enum(TraitType):
1426 class Enum(TraitType):
1423 """An enum that whose value must be in a given sequence."""
1427 """An enum that whose value must be in a given sequence."""
1424
1428
1425 def __init__(self, values, default_value=None, **metadata):
1429 def __init__(self, values, default_value=None, **metadata):
1426 self.values = values
1430 self.values = values
1427 super(Enum, self).__init__(default_value, **metadata)
1431 super(Enum, self).__init__(default_value, **metadata)
1428
1432
1429 def validate(self, obj, value):
1433 def validate(self, obj, value):
1430 if value in self.values:
1434 if value in self.values:
1431 return value
1435 return value
1432 self.error(obj, value)
1436 self.error(obj, value)
1433
1437
1434 def info(self):
1438 def info(self):
1435 """ Returns a description of the trait."""
1439 """ Returns a description of the trait."""
1436 result = 'any of ' + repr(self.values)
1440 result = 'any of ' + repr(self.values)
1437 if self.allow_none:
1441 if self.allow_none:
1438 return result + ' or None'
1442 return result + ' or None'
1439 return result
1443 return result
1440
1444
1441 class CaselessStrEnum(Enum):
1445 class CaselessStrEnum(Enum):
1442 """An enum of strings that are caseless in validate."""
1446 """An enum of strings that are caseless in validate."""
1443
1447
1444 def validate(self, obj, value):
1448 def validate(self, obj, value):
1445 if not isinstance(value, py3compat.string_types):
1449 if not isinstance(value, py3compat.string_types):
1446 self.error(obj, value)
1450 self.error(obj, value)
1447
1451
1448 for v in self.values:
1452 for v in self.values:
1449 if v.lower() == value.lower():
1453 if v.lower() == value.lower():
1450 return v
1454 return v
1451 self.error(obj, value)
1455 self.error(obj, value)
1452
1456
1453 class Container(Instance):
1457 class Container(Instance):
1454 """An instance of a container (list, set, etc.)
1458 """An instance of a container (list, set, etc.)
1455
1459
1456 To be subclassed by overriding klass.
1460 To be subclassed by overriding klass.
1457 """
1461 """
1458 klass = None
1462 klass = None
1459 _cast_types = ()
1463 _cast_types = ()
1460 _valid_defaults = SequenceTypes
1464 _valid_defaults = SequenceTypes
1461 _trait = None
1465 _trait = None
1462
1466
1463 def __init__(self, trait=None, default_value=None, allow_none=False,
1467 def __init__(self, trait=None, default_value=None, allow_none=False,
1464 **metadata):
1468 **metadata):
1465 """Create a container trait type from a list, set, or tuple.
1469 """Create a container trait type from a list, set, or tuple.
1466
1470
1467 The default value is created by doing ``List(default_value)``,
1471 The default value is created by doing ``List(default_value)``,
1468 which creates a copy of the ``default_value``.
1472 which creates a copy of the ``default_value``.
1469
1473
1470 ``trait`` can be specified, which restricts the type of elements
1474 ``trait`` can be specified, which restricts the type of elements
1471 in the container to that TraitType.
1475 in the container to that TraitType.
1472
1476
1473 If only one arg is given and it is not a Trait, it is taken as
1477 If only one arg is given and it is not a Trait, it is taken as
1474 ``default_value``:
1478 ``default_value``:
1475
1479
1476 ``c = List([1,2,3])``
1480 ``c = List([1,2,3])``
1477
1481
1478 Parameters
1482 Parameters
1479 ----------
1483 ----------
1480
1484
1481 trait : TraitType [ optional ]
1485 trait : TraitType [ optional ]
1482 the type for restricting the contents of the Container. If unspecified,
1486 the type for restricting the contents of the Container. If unspecified,
1483 types are not checked.
1487 types are not checked.
1484
1488
1485 default_value : SequenceType [ optional ]
1489 default_value : SequenceType [ optional ]
1486 The default value for the Trait. Must be list/tuple/set, and
1490 The default value for the Trait. Must be list/tuple/set, and
1487 will be cast to the container type.
1491 will be cast to the container type.
1488
1492
1489 allow_none : bool [ default False ]
1493 allow_none : bool [ default False ]
1490 Whether to allow the value to be None
1494 Whether to allow the value to be None
1491
1495
1492 **metadata : any
1496 **metadata : any
1493 further keys for extensions to the Trait (e.g. config)
1497 further keys for extensions to the Trait (e.g. config)
1494
1498
1495 """
1499 """
1496 # allow List([values]):
1500 # allow List([values]):
1497 if default_value is None and not is_trait(trait):
1501 if default_value is None and not is_trait(trait):
1498 default_value = trait
1502 default_value = trait
1499 trait = None
1503 trait = None
1500
1504
1501 if default_value is None:
1505 if default_value is None:
1502 args = ()
1506 args = ()
1503 elif isinstance(default_value, self._valid_defaults):
1507 elif isinstance(default_value, self._valid_defaults):
1504 args = (default_value,)
1508 args = (default_value,)
1505 else:
1509 else:
1506 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1510 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1507
1511
1508 if is_trait(trait):
1512 if is_trait(trait):
1509 self._trait = trait() if isinstance(trait, type) else trait
1513 self._trait = trait() if isinstance(trait, type) else trait
1510 self._trait.name = 'element'
1514 self._trait.name = 'element'
1511 elif trait is not None:
1515 elif trait is not None:
1512 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1516 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1513
1517
1514 super(Container,self).__init__(klass=self.klass, args=args,
1518 super(Container,self).__init__(klass=self.klass, args=args,
1515 allow_none=allow_none, **metadata)
1519 allow_none=allow_none, **metadata)
1516
1520
1517 def element_error(self, obj, element, validator):
1521 def element_error(self, obj, element, validator):
1518 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1522 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1519 % (self.name, class_of(obj), validator.info(), repr_type(element))
1523 % (self.name, class_of(obj), validator.info(), repr_type(element))
1520 raise TraitError(e)
1524 raise TraitError(e)
1521
1525
1522 def validate(self, obj, value):
1526 def validate(self, obj, value):
1523 if isinstance(value, self._cast_types):
1527 if isinstance(value, self._cast_types):
1524 value = self.klass(value)
1528 value = self.klass(value)
1525 value = super(Container, self).validate(obj, value)
1529 value = super(Container, self).validate(obj, value)
1526 if value is None:
1530 if value is None:
1527 return value
1531 return value
1528
1532
1529 value = self.validate_elements(obj, value)
1533 value = self.validate_elements(obj, value)
1530
1534
1531 return value
1535 return value
1532
1536
1533 def validate_elements(self, obj, value):
1537 def validate_elements(self, obj, value):
1534 validated = []
1538 validated = []
1535 if self._trait is None or isinstance(self._trait, Any):
1539 if self._trait is None or isinstance(self._trait, Any):
1536 return value
1540 return value
1537 for v in value:
1541 for v in value:
1538 try:
1542 try:
1539 v = self._trait._validate(obj, v)
1543 v = self._trait._validate(obj, v)
1540 except TraitError:
1544 except TraitError:
1541 self.element_error(obj, v, self._trait)
1545 self.element_error(obj, v, self._trait)
1542 else:
1546 else:
1543 validated.append(v)
1547 validated.append(v)
1544 return self.klass(validated)
1548 return self.klass(validated)
1545
1549
1546 def instance_init(self):
1550 def instance_init(self):
1547 if isinstance(self._trait, TraitType):
1551 if isinstance(self._trait, TraitType):
1548 self._trait.this_class = self.this_class
1552 self._trait.this_class = self.this_class
1549 self._trait.instance_init()
1553 self._trait.instance_init()
1550 super(Container, self).instance_init()
1554 super(Container, self).instance_init()
1551
1555
1552
1556
1553 class List(Container):
1557 class List(Container):
1554 """An instance of a Python list."""
1558 """An instance of a Python list."""
1555 klass = list
1559 klass = list
1556 _cast_types = (tuple,)
1560 _cast_types = (tuple,)
1557
1561
1558 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize, **metadata):
1562 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize, **metadata):
1559 """Create a List trait type from a list, set, or tuple.
1563 """Create a List trait type from a list, set, or tuple.
1560
1564
1561 The default value is created by doing ``List(default_value)``,
1565 The default value is created by doing ``List(default_value)``,
1562 which creates a copy of the ``default_value``.
1566 which creates a copy of the ``default_value``.
1563
1567
1564 ``trait`` can be specified, which restricts the type of elements
1568 ``trait`` can be specified, which restricts the type of elements
1565 in the container to that TraitType.
1569 in the container to that TraitType.
1566
1570
1567 If only one arg is given and it is not a Trait, it is taken as
1571 If only one arg is given and it is not a Trait, it is taken as
1568 ``default_value``:
1572 ``default_value``:
1569
1573
1570 ``c = List([1,2,3])``
1574 ``c = List([1,2,3])``
1571
1575
1572 Parameters
1576 Parameters
1573 ----------
1577 ----------
1574
1578
1575 trait : TraitType [ optional ]
1579 trait : TraitType [ optional ]
1576 the type for restricting the contents of the Container. If unspecified,
1580 the type for restricting the contents of the Container. If unspecified,
1577 types are not checked.
1581 types are not checked.
1578
1582
1579 default_value : SequenceType [ optional ]
1583 default_value : SequenceType [ optional ]
1580 The default value for the Trait. Must be list/tuple/set, and
1584 The default value for the Trait. Must be list/tuple/set, and
1581 will be cast to the container type.
1585 will be cast to the container type.
1582
1586
1583 minlen : Int [ default 0 ]
1587 minlen : Int [ default 0 ]
1584 The minimum length of the input list
1588 The minimum length of the input list
1585
1589
1586 maxlen : Int [ default sys.maxsize ]
1590 maxlen : Int [ default sys.maxsize ]
1587 The maximum length of the input list
1591 The maximum length of the input list
1588
1592
1589 allow_none : bool [ default False ]
1593 allow_none : bool [ default False ]
1590 Whether to allow the value to be None
1594 Whether to allow the value to be None
1591
1595
1592 **metadata : any
1596 **metadata : any
1593 further keys for extensions to the Trait (e.g. config)
1597 further keys for extensions to the Trait (e.g. config)
1594
1598
1595 """
1599 """
1596 self._minlen = minlen
1600 self._minlen = minlen
1597 self._maxlen = maxlen
1601 self._maxlen = maxlen
1598 super(List, self).__init__(trait=trait, default_value=default_value,
1602 super(List, self).__init__(trait=trait, default_value=default_value,
1599 **metadata)
1603 **metadata)
1600
1604
1601 def length_error(self, obj, value):
1605 def length_error(self, obj, value):
1602 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1606 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1603 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1607 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1604 raise TraitError(e)
1608 raise TraitError(e)
1605
1609
1606 def validate_elements(self, obj, value):
1610 def validate_elements(self, obj, value):
1607 length = len(value)
1611 length = len(value)
1608 if length < self._minlen or length > self._maxlen:
1612 if length < self._minlen or length > self._maxlen:
1609 self.length_error(obj, value)
1613 self.length_error(obj, value)
1610
1614
1611 return super(List, self).validate_elements(obj, value)
1615 return super(List, self).validate_elements(obj, value)
1612
1616
1613 def validate(self, obj, value):
1617 def validate(self, obj, value):
1614 value = super(List, self).validate(obj, value)
1618 value = super(List, self).validate(obj, value)
1615 value = self.validate_elements(obj, value)
1619 value = self.validate_elements(obj, value)
1616 return value
1620 return value
1617
1621
1618
1622
1619 class Set(List):
1623 class Set(List):
1620 """An instance of a Python set."""
1624 """An instance of a Python set."""
1621 klass = set
1625 klass = set
1622 _cast_types = (tuple, list)
1626 _cast_types = (tuple, list)
1623
1627
1624
1628
1625 class Tuple(Container):
1629 class Tuple(Container):
1626 """An instance of a Python tuple."""
1630 """An instance of a Python tuple."""
1627 klass = tuple
1631 klass = tuple
1628 _cast_types = (list,)
1632 _cast_types = (list,)
1629
1633
1630 def __init__(self, *traits, **metadata):
1634 def __init__(self, *traits, **metadata):
1631 """Tuple(*traits, default_value=None, **medatata)
1635 """Tuple(*traits, default_value=None, **medatata)
1632
1636
1633 Create a tuple from a list, set, or tuple.
1637 Create a tuple from a list, set, or tuple.
1634
1638
1635 Create a fixed-type tuple with Traits:
1639 Create a fixed-type tuple with Traits:
1636
1640
1637 ``t = Tuple(Int, Str, CStr)``
1641 ``t = Tuple(Int, Str, CStr)``
1638
1642
1639 would be length 3, with Int,Str,CStr for each element.
1643 would be length 3, with Int,Str,CStr for each element.
1640
1644
1641 If only one arg is given and it is not a Trait, it is taken as
1645 If only one arg is given and it is not a Trait, it is taken as
1642 default_value:
1646 default_value:
1643
1647
1644 ``t = Tuple((1,2,3))``
1648 ``t = Tuple((1,2,3))``
1645
1649
1646 Otherwise, ``default_value`` *must* be specified by keyword.
1650 Otherwise, ``default_value`` *must* be specified by keyword.
1647
1651
1648 Parameters
1652 Parameters
1649 ----------
1653 ----------
1650
1654
1651 *traits : TraitTypes [ optional ]
1655 *traits : TraitTypes [ optional ]
1652 the types for restricting the contents of the Tuple. If unspecified,
1656 the types for restricting the contents of the Tuple. If unspecified,
1653 types are not checked. If specified, then each positional argument
1657 types are not checked. If specified, then each positional argument
1654 corresponds to an element of the tuple. Tuples defined with traits
1658 corresponds to an element of the tuple. Tuples defined with traits
1655 are of fixed length.
1659 are of fixed length.
1656
1660
1657 default_value : SequenceType [ optional ]
1661 default_value : SequenceType [ optional ]
1658 The default value for the Tuple. Must be list/tuple/set, and
1662 The default value for the Tuple. Must be list/tuple/set, and
1659 will be cast to a tuple. If `traits` are specified, the
1663 will be cast to a tuple. If `traits` are specified, the
1660 `default_value` must conform to the shape and type they specify.
1664 `default_value` must conform to the shape and type they specify.
1661
1665
1662 allow_none : bool [ default False ]
1666 allow_none : bool [ default False ]
1663 Whether to allow the value to be None
1667 Whether to allow the value to be None
1664
1668
1665 **metadata : any
1669 **metadata : any
1666 further keys for extensions to the Trait (e.g. config)
1670 further keys for extensions to the Trait (e.g. config)
1667
1671
1668 """
1672 """
1669 default_value = metadata.pop('default_value', None)
1673 default_value = metadata.pop('default_value', None)
1670 allow_none = metadata.pop('allow_none', True)
1674 allow_none = metadata.pop('allow_none', True)
1671
1675
1672 # allow Tuple((values,)):
1676 # allow Tuple((values,)):
1673 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1677 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1674 default_value = traits[0]
1678 default_value = traits[0]
1675 traits = ()
1679 traits = ()
1676
1680
1677 if default_value is None:
1681 if default_value is None:
1678 args = ()
1682 args = ()
1679 elif isinstance(default_value, self._valid_defaults):
1683 elif isinstance(default_value, self._valid_defaults):
1680 args = (default_value,)
1684 args = (default_value,)
1681 else:
1685 else:
1682 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1686 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1683
1687
1684 self._traits = []
1688 self._traits = []
1685 for trait in traits:
1689 for trait in traits:
1686 t = trait() if isinstance(trait, type) else trait
1690 t = trait() if isinstance(trait, type) else trait
1687 t.name = 'element'
1691 t.name = 'element'
1688 self._traits.append(t)
1692 self._traits.append(t)
1689
1693
1690 if self._traits and default_value is None:
1694 if self._traits and default_value is None:
1691 # don't allow default to be an empty container if length is specified
1695 # don't allow default to be an empty container if length is specified
1692 args = None
1696 args = None
1693 super(Container,self).__init__(klass=self.klass, args=args, allow_none=allow_none, **metadata)
1697 super(Container,self).__init__(klass=self.klass, args=args, allow_none=allow_none, **metadata)
1694
1698
1695 def validate_elements(self, obj, value):
1699 def validate_elements(self, obj, value):
1696 if not self._traits:
1700 if not self._traits:
1697 # nothing to validate
1701 # nothing to validate
1698 return value
1702 return value
1699 if len(value) != len(self._traits):
1703 if len(value) != len(self._traits):
1700 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1704 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1701 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1705 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1702 raise TraitError(e)
1706 raise TraitError(e)
1703
1707
1704 validated = []
1708 validated = []
1705 for t, v in zip(self._traits, value):
1709 for t, v in zip(self._traits, value):
1706 try:
1710 try:
1707 v = t._validate(obj, v)
1711 v = t._validate(obj, v)
1708 except TraitError:
1712 except TraitError:
1709 self.element_error(obj, v, t)
1713 self.element_error(obj, v, t)
1710 else:
1714 else:
1711 validated.append(v)
1715 validated.append(v)
1712 return tuple(validated)
1716 return tuple(validated)
1713
1717
1714 def instance_init(self):
1718 def instance_init(self):
1715 for trait in self._traits:
1719 for trait in self._traits:
1716 if isinstance(trait, TraitType):
1720 if isinstance(trait, TraitType):
1717 trait.this_class = self.this_class
1721 trait.this_class = self.this_class
1718 trait.instance_init()
1722 trait.instance_init()
1719 super(Container, self).instance_init()
1723 super(Container, self).instance_init()
1720
1724
1721
1725
1722 class Dict(Instance):
1726 class Dict(Instance):
1723 """An instance of a Python dict."""
1727 """An instance of a Python dict."""
1724 _trait = None
1728 _trait = None
1725
1729
1726 def __init__(self, trait=None, default_value=NoDefaultSpecified, allow_none=False, **metadata):
1730 def __init__(self, trait=None, default_value=NoDefaultSpecified, allow_none=False, **metadata):
1727 """Create a dict trait type from a dict.
1731 """Create a dict trait type from a dict.
1728
1732
1729 The default value is created by doing ``dict(default_value)``,
1733 The default value is created by doing ``dict(default_value)``,
1730 which creates a copy of the ``default_value``.
1734 which creates a copy of the ``default_value``.
1731
1735
1732 trait : TraitType [ optional ]
1736 trait : TraitType [ optional ]
1733 the type for restricting the contents of the Container. If unspecified,
1737 the type for restricting the contents of the Container. If unspecified,
1734 types are not checked.
1738 types are not checked.
1735
1739
1736 default_value : SequenceType [ optional ]
1740 default_value : SequenceType [ optional ]
1737 The default value for the Dict. Must be dict, tuple, or None, and
1741 The default value for the Dict. Must be dict, tuple, or None, and
1738 will be cast to a dict if not None. If `trait` is specified, the
1742 will be cast to a dict if not None. If `trait` is specified, the
1739 `default_value` must conform to the constraints it specifies.
1743 `default_value` must conform to the constraints it specifies.
1740
1744
1741 allow_none : bool [ default False ]
1745 allow_none : bool [ default False ]
1742 Whether to allow the value to be None
1746 Whether to allow the value to be None
1743
1747
1744 """
1748 """
1745 if default_value is NoDefaultSpecified and trait is not None:
1749 if default_value is NoDefaultSpecified and trait is not None:
1746 if not is_trait(trait):
1750 if not is_trait(trait):
1747 default_value = trait
1751 default_value = trait
1748 trait = None
1752 trait = None
1749 if default_value is NoDefaultSpecified:
1753 if default_value is NoDefaultSpecified:
1750 default_value = {}
1754 default_value = {}
1751 if default_value is None:
1755 if default_value is None:
1752 args = None
1756 args = None
1753 elif isinstance(default_value, dict):
1757 elif isinstance(default_value, dict):
1754 args = (default_value,)
1758 args = (default_value,)
1755 elif isinstance(default_value, SequenceTypes):
1759 elif isinstance(default_value, SequenceTypes):
1756 args = (default_value,)
1760 args = (default_value,)
1757 else:
1761 else:
1758 raise TypeError('default value of Dict was %s' % default_value)
1762 raise TypeError('default value of Dict was %s' % default_value)
1759
1763
1760 if is_trait(trait):
1764 if is_trait(trait):
1761 self._trait = trait() if isinstance(trait, type) else trait
1765 self._trait = trait() if isinstance(trait, type) else trait
1762 self._trait.name = 'element'
1766 self._trait.name = 'element'
1763 elif trait is not None:
1767 elif trait is not None:
1764 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1768 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1765
1769
1766 super(Dict,self).__init__(klass=dict, args=args,
1770 super(Dict,self).__init__(klass=dict, args=args,
1767 allow_none=allow_none, **metadata)
1771 allow_none=allow_none, **metadata)
1768
1772
1769 def element_error(self, obj, element, validator):
1773 def element_error(self, obj, element, validator):
1770 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1774 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1771 % (self.name, class_of(obj), validator.info(), repr_type(element))
1775 % (self.name, class_of(obj), validator.info(), repr_type(element))
1772 raise TraitError(e)
1776 raise TraitError(e)
1773
1777
1774 def validate(self, obj, value):
1778 def validate(self, obj, value):
1775 value = super(Dict, self).validate(obj, value)
1779 value = super(Dict, self).validate(obj, value)
1776 if value is None:
1780 if value is None:
1777 return value
1781 return value
1778 value = self.validate_elements(obj, value)
1782 value = self.validate_elements(obj, value)
1779 return value
1783 return value
1780
1784
1781 def validate_elements(self, obj, value):
1785 def validate_elements(self, obj, value):
1782 if self._trait is None or isinstance(self._trait, Any):
1786 if self._trait is None or isinstance(self._trait, Any):
1783 return value
1787 return value
1784 validated = {}
1788 validated = {}
1785 for key in value:
1789 for key in value:
1786 v = value[key]
1790 v = value[key]
1787 try:
1791 try:
1788 v = self._trait._validate(obj, v)
1792 v = self._trait._validate(obj, v)
1789 except TraitError:
1793 except TraitError:
1790 self.element_error(obj, v, self._trait)
1794 self.element_error(obj, v, self._trait)
1791 else:
1795 else:
1792 validated[key] = v
1796 validated[key] = v
1793 return self.klass(validated)
1797 return self.klass(validated)
1794
1798
1795 def instance_init(self):
1799 def instance_init(self):
1796 if isinstance(self._trait, TraitType):
1800 if isinstance(self._trait, TraitType):
1797 self._trait.this_class = self.this_class
1801 self._trait.this_class = self.this_class
1798 self._trait.instance_init()
1802 self._trait.instance_init()
1799 super(Dict, self).instance_init()
1803 super(Dict, self).instance_init()
1800
1804
1801
1805
1802 class EventfulDict(Instance):
1806 class EventfulDict(Instance):
1803 """An instance of an EventfulDict."""
1807 """An instance of an EventfulDict."""
1804
1808
1805 def __init__(self, default_value={}, allow_none=False, **metadata):
1809 def __init__(self, default_value={}, allow_none=False, **metadata):
1806 """Create a EventfulDict trait type from a dict.
1810 """Create a EventfulDict trait type from a dict.
1807
1811
1808 The default value is created by doing
1812 The default value is created by doing
1809 ``eventful.EvenfulDict(default_value)``, which creates a copy of the
1813 ``eventful.EvenfulDict(default_value)``, which creates a copy of the
1810 ``default_value``.
1814 ``default_value``.
1811 """
1815 """
1812 if default_value is None:
1816 if default_value is None:
1813 args = None
1817 args = None
1814 elif isinstance(default_value, dict):
1818 elif isinstance(default_value, dict):
1815 args = (default_value,)
1819 args = (default_value,)
1816 elif isinstance(default_value, SequenceTypes):
1820 elif isinstance(default_value, SequenceTypes):
1817 args = (default_value,)
1821 args = (default_value,)
1818 else:
1822 else:
1819 raise TypeError('default value of EventfulDict was %s' % default_value)
1823 raise TypeError('default value of EventfulDict was %s' % default_value)
1820
1824
1821 super(EventfulDict, self).__init__(klass=eventful.EventfulDict, args=args,
1825 super(EventfulDict, self).__init__(klass=eventful.EventfulDict, args=args,
1822 allow_none=allow_none, **metadata)
1826 allow_none=allow_none, **metadata)
1823
1827
1824
1828
1825 class EventfulList(Instance):
1829 class EventfulList(Instance):
1826 """An instance of an EventfulList."""
1830 """An instance of an EventfulList."""
1827
1831
1828 def __init__(self, default_value=None, allow_none=False, **metadata):
1832 def __init__(self, default_value=None, allow_none=False, **metadata):
1829 """Create a EventfulList trait type from a dict.
1833 """Create a EventfulList trait type from a dict.
1830
1834
1831 The default value is created by doing
1835 The default value is created by doing
1832 ``eventful.EvenfulList(default_value)``, which creates a copy of the
1836 ``eventful.EvenfulList(default_value)``, which creates a copy of the
1833 ``default_value``.
1837 ``default_value``.
1834 """
1838 """
1835 if default_value is None:
1839 if default_value is None:
1836 args = ((),)
1840 args = ((),)
1837 else:
1841 else:
1838 args = (default_value,)
1842 args = (default_value,)
1839
1843
1840 super(EventfulList, self).__init__(klass=eventful.EventfulList, args=args,
1844 super(EventfulList, self).__init__(klass=eventful.EventfulList, args=args,
1841 allow_none=allow_none, **metadata)
1845 allow_none=allow_none, **metadata)
1842
1846
1843
1847
1844 class TCPAddress(TraitType):
1848 class TCPAddress(TraitType):
1845 """A trait for an (ip, port) tuple.
1849 """A trait for an (ip, port) tuple.
1846
1850
1847 This allows for both IPv4 IP addresses as well as hostnames.
1851 This allows for both IPv4 IP addresses as well as hostnames.
1848 """
1852 """
1849
1853
1850 default_value = ('127.0.0.1', 0)
1854 default_value = ('127.0.0.1', 0)
1851 info_text = 'an (ip, port) tuple'
1855 info_text = 'an (ip, port) tuple'
1852
1856
1853 def validate(self, obj, value):
1857 def validate(self, obj, value):
1854 if isinstance(value, tuple):
1858 if isinstance(value, tuple):
1855 if len(value) == 2:
1859 if len(value) == 2:
1856 if isinstance(value[0], py3compat.string_types) and isinstance(value[1], int):
1860 if isinstance(value[0], py3compat.string_types) and isinstance(value[1], int):
1857 port = value[1]
1861 port = value[1]
1858 if port >= 0 and port <= 65535:
1862 if port >= 0 and port <= 65535:
1859 return value
1863 return value
1860 self.error(obj, value)
1864 self.error(obj, value)
1861
1865
1862 class CRegExp(TraitType):
1866 class CRegExp(TraitType):
1863 """A casting compiled regular expression trait.
1867 """A casting compiled regular expression trait.
1864
1868
1865 Accepts both strings and compiled regular expressions. The resulting
1869 Accepts both strings and compiled regular expressions. The resulting
1866 attribute will be a compiled regular expression."""
1870 attribute will be a compiled regular expression."""
1867
1871
1868 info_text = 'a regular expression'
1872 info_text = 'a regular expression'
1869
1873
1870 def validate(self, obj, value):
1874 def validate(self, obj, value):
1871 try:
1875 try:
1872 return re.compile(value)
1876 return re.compile(value)
1873 except:
1877 except:
1874 self.error(obj, value)
1878 self.error(obj, value)
General Comments 0
You need to be logged in to leave comments. Login now