Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add ObjectName and DottedObjectName trait types for referring to Pyth…

…on identifiers.
  • Loading branch information...
commit 97ea6aa1d9f6c7f8626539b130ebd81d38904452 1 parent 0784a05
Thomas Kluyver authored
18 IPython/core/formatters.py
@@ -28,7 +28,7 @@
28 28 # Our own imports
29 29 from IPython.config.configurable import Configurable
30 30 from IPython.lib import pretty
31   -from IPython.utils.traitlets import Bool, Dict, Int, Unicode, CUnicode
  31 +from IPython.utils.traitlets import Bool, Dict, Int, Unicode, CUnicode, ObjectName
32 32
33 33
34 34 #-----------------------------------------------------------------------------
@@ -195,7 +195,7 @@ class BaseFormatter(Configurable):
195 195
196 196 enabled = Bool(True, config=True)
197 197
198   - print_method = Unicode('__repr__')
  198 + print_method = ObjectName('__repr__')
199 199
200 200 # The singleton printers.
201 201 # Maps the IDs of the builtin singleton objects to the format functions.
@@ -344,7 +344,7 @@ def dtype_pprinter(obj, p, cycle):
344 344 enabled = Bool(True, config=False)
345 345
346 346 # Look for a _repr_pretty_ methods to use for pretty printing.
347   - print_method = Unicode('_repr_pretty_')
  347 + print_method = ObjectName('_repr_pretty_')
348 348
349 349 # Whether to pretty-print or not.
350 350 pprint = Bool(True, config=True)
@@ -456,7 +456,7 @@ class HTMLFormatter(BaseFormatter):
456 456 """
457 457 format_type = Unicode('text/html')
458 458
459   - print_method = Unicode('_repr_html_')
  459 + print_method = ObjectName('_repr_html_')
460 460
461 461
462 462 class SVGFormatter(BaseFormatter):
@@ -473,7 +473,7 @@ class SVGFormatter(BaseFormatter):
473 473 """
474 474 format_type = Unicode('image/svg+xml')
475 475
476   - print_method = Unicode('_repr_svg_')
  476 + print_method = ObjectName('_repr_svg_')
477 477
478 478
479 479 class PNGFormatter(BaseFormatter):
@@ -489,7 +489,7 @@ class PNGFormatter(BaseFormatter):
489 489 """
490 490 format_type = Unicode('image/png')
491 491
492   - print_method = Unicode('_repr_png_')
  492 + print_method = ObjectName('_repr_png_')
493 493
494 494
495 495 class LatexFormatter(BaseFormatter):
@@ -505,7 +505,7 @@ class LatexFormatter(BaseFormatter):
505 505 """
506 506 format_type = Unicode('text/latex')
507 507
508   - print_method = Unicode('_repr_latex_')
  508 + print_method = ObjectName('_repr_latex_')
509 509
510 510
511 511 class JSONFormatter(BaseFormatter):
@@ -520,7 +520,7 @@ class JSONFormatter(BaseFormatter):
520 520 """
521 521 format_type = Unicode('application/json')
522 522
523   - print_method = Unicode('_repr_json_')
  523 + print_method = ObjectName('_repr_json_')
524 524
525 525
526 526 class JavascriptFormatter(BaseFormatter):
@@ -536,7 +536,7 @@ class JavascriptFormatter(BaseFormatter):
536 536 """
537 537 format_type = Unicode('application/javascript')
538 538
539   - print_method = Unicode('_repr_javascript_')
  539 + print_method = ObjectName('_repr_javascript_')
540 540
541 541 FormatterABC.register(BaseFormatter)
542 542 FormatterABC.register(PlainTextFormatter)
37 IPython/utils/tests/test_traitlets.py
@@ -22,12 +22,14 @@
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24 24
  25 +import sys
25 26 from unittest import TestCase
26 27
27 28 from IPython.utils.traitlets import (
28 29 HasTraits, MetaHasTraits, TraitType, Any, CBytes,
29 30 Int, Long, Float, Complex, Bytes, Unicode, TraitError,
30   - Undefined, Type, This, Instance, TCPAddress, List, Tuple
  31 + Undefined, Type, This, Instance, TCPAddress, List, Tuple,
  32 + ObjectName, DottedObjectName
31 33 )
32 34
33 35
@@ -725,11 +727,42 @@ class TestUnicode(TraitTestBase):
725 727
726 728 _default_value = u'unicode'
727 729 _good_values = ['10', '-10', '10L', '-10L', '10.1',
728   - '-10.1', '', u'', 'string', u'string', ]
  730 + '-10.1', '', u'', 'string', u'string', u"€"]
729 731 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
730 732 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
731 733
732 734
  735 +class ObjectNameTrait(HasTraits):
  736 + value = ObjectName("abc")
  737 +
  738 +class TestObjectName(TraitTestBase):
  739 + obj = ObjectNameTrait()
  740 +
  741 + _default_value = "abc"
  742 + _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"]
  743 + _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]",
  744 + object(), object]
  745 + if sys.version_info[0] < 3:
  746 + _bad_values.append(u"þ")
  747 + else:
  748 + _good_values.append(u"þ") # þ=1 is valid in Python 3 (PEP 3131).
  749 +
  750 +
  751 +class DottedObjectNameTrait(HasTraits):
  752 + value = DottedObjectName("a.b")
  753 +
  754 +class TestDottedObjectName(TraitTestBase):
  755 + obj = DottedObjectNameTrait()
  756 +
  757 + _default_value = "a.b"
  758 + _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"]
  759 + _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc."]
  760 + if sys.version_info[0] < 3:
  761 + _bad_values.append(u"t.þ")
  762 + else:
  763 + _good_values.append(u"t.þ")
  764 +
  765 +
733 766 class TCPAddressTrait(HasTraits):
734 767
735 768 value = TCPAddress()
45 IPython/utils/traitlets.py
@@ -50,6 +50,7 @@
50 50
51 51
52 52 import inspect
  53 +import re
53 54 import sys
54 55 import types
55 56 from types import (
@@ -998,6 +999,50 @@ def validate(self, obj, value):
998 999 return unicode(value)
999 1000 except:
1000 1001 self.error(obj, value)
  1002 +
  1003 +
  1004 +class ObjectName(TraitType):
  1005 + """A string holding a valid object name in this version of Python.
  1006 +
  1007 + This does not check that the name exists in any scope."""
  1008 + info_text = "a valid object identifier in Python"
  1009 +
  1010 + if sys.version_info[0] < 3:
  1011 + # Python 2:
  1012 + _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
  1013 + def isidentifier(self, s):
  1014 + return bool(self._name_re.match(s))
  1015 +
  1016 + def coerce_str(self, obj, value):
  1017 + "In Python 2, coerce ascii-only unicode to str"
  1018 + if isinstance(value, unicode):
  1019 + try:
  1020 + return str(value)
  1021 + except UnicodeEncodeError:
  1022 + self.error(obj, value)
  1023 + return value
  1024 +
  1025 + else:
  1026 + # Python 3:
  1027 + isidentifier = staticmethod(lambda s: s.isidentifier())
  1028 + coerce_str = staticmethod(lambda _,s: s)
  1029 +
  1030 + def validate(self, obj, value):
  1031 + value = self.coerce_str(obj, value)
  1032 +
  1033 + if isinstance(value, str) and self.isidentifier(value):
  1034 + return value
  1035 + self.error(obj, value)
  1036 +
  1037 +class DottedObjectName(ObjectName):
  1038 + """A string holding a valid dotted object name in Python, such as A.b3._c"""
  1039 + def validate(self, obj, value):
  1040 + value = self.coerce_str(obj, value)
  1041 +
  1042 + if isinstance(value, str) and all(self.isidentifier(x) \
  1043 + for x in value.split('.')):
  1044 + return value
  1045 + self.error(obj, value)
1001 1046
1002 1047
1003 1048 class Bool(TraitType):

0 comments on commit 97ea6aa

Please sign in to comment.
Something went wrong with that request. Please try again.