Author: Amaury Forgeot d'Arc <[email protected]>
Branch: py3k
Changeset: r59114:c6fd4a0b49cd
Date: 2012-11-28 23:35 +0100
http://bitbucket.org/pypy/pypy/changeset/c6fd4a0b49cd/

Log:    When attribute string cannot be encoded to utf8, raise
        AttributeError, not UnicodeError.

diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -49,25 +49,35 @@
     return w_iter
 list_iter._annspecialcase_ = 'specialize:memo'
 
-def raiseattrerror(space, w_obj, name, w_descr=None):
+def raiseattrerror(space, w_obj, w_name, w_descr=None):
     w_type = space.type(w_obj)
     typename = w_type.getname(space)
+    # space.repr always returns an encodable string.
+    name = space.str_w(space.repr(w_name))
     if w_descr is None:
         raise operationerrfmt(space.w_AttributeError,
-                              "'%s' object has no attribute '%s'",
+                              "'%s' object has no attribute %s",
                               typename, name)
     else:
         raise operationerrfmt(space.w_AttributeError,
-                              "'%s' object attribute '%s' is read-only",
+                              "'%s' object attribute %s is read-only",
                               typename, name)
 
+def get_attribute_name(space, w_obj, w_name):
+    try:
+        return space.str_w(w_name)
+    except OperationError as e:
+        if e.match(space, space.w_UnicodeEncodeError):
+            raiseattrerror(space, w_obj, w_name)
+        raise
+
 def _same_class_w(space, w_obj1, w_obj2, w_typ1, w_typ2):
     return space.is_w(w_typ1, w_typ2)
 
 
 class Object(object):
     def descr__getattribute__(space, w_obj, w_name):
-        name = space.str_w(w_name)
+        name = get_attribute_name(space, w_obj, w_name)
         w_descr = space.lookup(w_obj, name)
         if w_descr is not None:
             if space.is_data_descr(w_descr):
@@ -83,10 +93,10 @@
             return w_value
         if w_descr is not None:
             return space.get(w_descr, w_obj)
-        raiseattrerror(space, w_obj, name)
+        raiseattrerror(space, w_obj, w_name)
 
     def descr__setattr__(space, w_obj, w_name, w_value):
-        name = space.str_w(w_name)
+        name = get_attribute_name(space, w_obj, w_name)
         w_descr = space.lookup(w_obj, name)
         if w_descr is not None:
             if space.is_data_descr(w_descr):
@@ -94,10 +104,10 @@
                 return
         if w_obj.setdictvalue(space, name, w_value):
             return
-        raiseattrerror(space, w_obj, name, w_descr)
+        raiseattrerror(space, w_obj, w_name, w_descr)
 
     def descr__delattr__(space, w_obj, w_name):
-        name = space.str_w(w_name)
+        name = get_attribute_name(space, w_obj, w_name)
         w_descr = space.lookup(w_obj, name)
         if w_descr is not None:
             if space.is_data_descr(w_descr):
@@ -105,7 +115,7 @@
                 return
         if w_obj.deldictvalue(space, name):
             return
-        raiseattrerror(space, w_obj, name, w_descr)
+        raiseattrerror(space, w_obj, w_name, w_descr)
 
     def descr__init__(space, w_obj, __args__):
         pass
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -6,7 +6,8 @@
 from pypy.interpreter.typedef import get_unique_interplevel_subclass
 from pypy.objspace.std import (builtinshortcut, stdtypedef, frame, model,
                                transparent, callmethod, proxyobject)
-from pypy.objspace.descroperation import DescrOperation, raiseattrerror
+from pypy.objspace.descroperation import (
+    DescrOperation, get_attribute_name, raiseattrerror)
 from pypy.rlib.objectmodel import instantiate, r_dict, specialize, 
is_annotation_constant
 from pypy.rlib.debug import make_sure_not_resized
 from pypy.rlib.rarithmetic import base_int, widen, maxint, is_valid_int
@@ -561,7 +562,7 @@
 
         # fast path: XXX this is duplicating most of the logic
         # from the default __getattribute__ and the getattr() method...
-        name = self.str_w(w_name)
+        name = get_attribute_name(space, w_obj, w_name)
         w_descr = w_type.lookup(name)
         e = None
         if w_descr is not None:
@@ -597,7 +598,7 @@
         elif e is not None:
             raise e
         else:
-            raiseattrerror(self, w_obj, name)
+            raiseattrerror(self, w_obj, w_name)
 
     def finditem_str(self, w_obj, key):
         """ Perform a getitem on w_obj with key (string). Returns found
diff --git a/pypy/objspace/test/test_descriptor.py 
b/pypy/objspace/test/test_descriptor.py
--- a/pypy/objspace/test/test_descriptor.py
+++ b/pypy/objspace/test/test_descriptor.py
@@ -72,6 +72,14 @@
         raises(AttributeError, delattr, x, 'v')
         raises(AttributeError, X.v.__delete__, x)
 
+    def test_invalid_unicode_identifier(self):
+        class X(object):
+            pass
+        x = X()
+        raises(AttributeError, setattr, x, '\ud800', 1)
+        raises(AttributeError, getattr, x, '\ud800')
+        raises(AttributeError, delattr, x, '\ud800')
+
     def test_special_methods_returning_strings(self): 
         class A(object): 
             seen = []
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to