summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorPaul Sokolovsky <pfalcon@users.sourceforge.net>2014-05-11 03:12:36 +0300
committerPaul Sokolovsky <pfalcon@users.sourceforge.net>2014-05-11 03:33:19 +0300
commit9511f60f016547ab00f634d451c230351bd8b225 (patch)
treec4bb8fcc41a0d63f1434943b8b9134c292666b43
parent69f3eb2c9688752d674254c3f4158cae688053be (diff)
downloadmicropython-9511f60f016547ab00f634d451c230351bd8b225.tar.gz
micropython-9511f60f016547ab00f634d451c230351bd8b225.zip
py: Don't try to "bind" types store as attributes of objects.
This was hit when trying to make urlparse.py from stdlib run. Took quite some time to debug. TODO: Reconsile bound method creation process better, maybe callable is to generic type to bind at all?
-rw-r--r--py/objtype.c3
-rw-r--r--py/runtime.c3
-rw-r--r--tests/basics/class_store_class.py44
3 files changed, 50 insertions, 0 deletions
diff --git a/py/objtype.c b/py/objtype.c
index 345eee7140..ef5f6b9d9c 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -333,6 +333,9 @@ STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_
// return a bound method, with self being the type of this object
dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
dest[1] = mp_obj_get_type(self);
+ } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) {
+ // Don't try to bind types
+ dest[0] = member;
} else if (mp_obj_is_callable(member)) {
// return a bound method, with self being this object
dest[0] = member;
diff --git a/py/runtime.c b/py/runtime.c
index 1479d8cba3..a2de2d75b1 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -840,6 +840,9 @@ void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
// return a bound method, with self being the type of this object
dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
dest[1] = mp_obj_get_type(base);
+ } else if (MP_OBJ_IS_TYPE(elem->value, &mp_type_type)) {
+ // Don't try to bind types
+ dest[0] = elem->value;
} else if (mp_obj_is_callable(elem->value)) {
// return a bound method, with self being this object
dest[0] = elem->value;
diff --git a/tests/basics/class_store_class.py b/tests/basics/class_store_class.py
new file mode 100644
index 0000000000..c765fceaa8
--- /dev/null
+++ b/tests/basics/class_store_class.py
@@ -0,0 +1,44 @@
+# Inspired by urlparse.py from CPython 3.3 stdlib
+# There was a bug in MicroPython that under some conditions class stored
+# in instance attribute later was returned "bound" as if it was a method,
+# which caused class constructor to receive extra argument.
+from collections import namedtuple
+
+_DefragResultBase = namedtuple('DefragResult', 'foo bar')
+
+class _ResultMixinStr(object):
+ def encode(self):
+ return self._encoded_counterpart(*(x.encode() for x in self))
+
+class _ResultMixinBytes(object):
+ def decode(self):
+ return self._decoded_counterpart(*(x.decode() for x in self))
+
+class DefragResult(_DefragResultBase, _ResultMixinStr):
+ pass
+
+class DefragResultBytes(_DefragResultBase, _ResultMixinBytes):
+ pass
+
+
+DefragResult._encoded_counterpart = DefragResultBytes
+DefragResultBytes._decoded_counterpart = DefragResult
+
+# Due to differences in type and native subclass printing,
+# the best thing we can do here is to just test that no exceptions
+# happen
+
+#print(DefragResult, DefragResult._encoded_counterpart)
+#print(DefragResultBytes, DefragResultBytes._decoded_counterpart)
+
+o1 = DefragResult("a", "b")
+#print(o1, type(o1))
+o2 = DefragResultBytes("a", "b")
+#print(o2, type(o2))
+
+#print(o1._encoded_counterpart)
+_o1 = o1.encode()
+print(_o1[0], _o1[1])
+#print(_o1, type(_o1))
+
+print("All's ok")