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