From 8a385920e7218b7a6c7e4d461c02a952b6f5f305 2011-09-07 11:18:47 From: Thomas Kluyver Date: 2011-09-07 11:18:47 Subject: [PATCH] Python 3 compatibility for identifiers. --- diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index a2b31e7..6d4ce71 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1258,13 +1258,9 @@ class InteractiveShell(SingletonConfigurable, Magic): """ oname = oname.strip() #print '1- oname: <%r>' % oname # dbg - if not py3compat.PY3: - try: - oname = oname.encode('ascii') - #print '2- oname: <%r>' % oname # dbg - except UnicodeError: - print 'Python identifiers can only contain ascii characters.' - return dict(found=False) + if not py3compat.isidentifier(oname.lstrip(ESC_MAGIC), dotted=True): + print 'Python identifiers can only contain ascii characters.' + return dict(found=False) alias_ns = None if namespaces is None: diff --git a/IPython/utils/py3compat.py b/IPython/utils/py3compat.py index e491de7..c2dd638 100644 --- a/IPython/utils/py3compat.py +++ b/IPython/utils/py3compat.py @@ -1,3 +1,5 @@ +# coding: utf-8 +"""Compatibility tricks for Python 3. Mainly to do with unicode.""" import sys def no_code(x, encoding=None): @@ -32,6 +34,11 @@ if sys.version_info[0] >= 3: str_to_bytes = encode bytes_to_str = decode + def isidentifier(s, dotted=False): + if dotted: + return all(isidentifier(a) for a in s.split(".")) + return s.isidentifier() + else: PY3 = False @@ -42,6 +49,13 @@ else: unicode_to_str = encode str_to_bytes = no_code bytes_to_str = no_code + + import re + _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$") + def isidentifier(s, dotted=False): + if dotted: + return all(isidentifier(a) for a in s.split(".")) + return bool(_name_re.match(s)) def execfile(fname, glob, loc=None): loc = loc if (loc is not None) else glob diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py index 1bb7479..cb5c34a 100644 --- a/IPython/utils/traitlets.py +++ b/IPython/utils/traitlets.py @@ -1008,12 +1008,12 @@ class ObjectName(TraitType): This does not check that the name exists in any scope.""" info_text = "a valid object identifier in Python" - if sys.version_info[0] < 3: + if py3compat.PY3: + # Python 3: + coerce_str = staticmethod(lambda _,s: s) + + else: # Python 2: - _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$") - def isidentifier(self, s): - return bool(self._name_re.match(s)) - def coerce_str(self, obj, value): "In Python 2, coerce ascii-only unicode to str" if isinstance(value, unicode): @@ -1023,15 +1023,10 @@ class ObjectName(TraitType): self.error(obj, value) return value - else: - # Python 3: - isidentifier = staticmethod(lambda s: s.isidentifier()) - coerce_str = staticmethod(lambda _,s: s) - def validate(self, obj, value): value = self.coerce_str(obj, value) - if isinstance(value, str) and self.isidentifier(value): + if isinstance(value, str) and py3compat.isidentifier(value): return value self.error(obj, value) @@ -1040,8 +1035,7 @@ class DottedObjectName(ObjectName): def validate(self, obj, value): value = self.coerce_str(obj, value) - if isinstance(value, str) and all(self.isidentifier(x) \ - for x in value.split('.')): + if isinstance(value, str) and py3compat.isidentifier(value, dotted=True): return value self.error(obj, value)