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