Răsfoiți Sursa

support `__getattr__`

blueloveTH 1 an în urmă
părinte
comite
317a37a851
3 a modificat fișierele cu 33 adăugiri și 0 ștergeri
  1. 1 0
      include/pocketpy/xmacros/magics.h
  2. 8 0
      src/public/py_ops.c
  3. 24 0
      tests/50_reflection.py

+ 1 - 0
include/pocketpy/xmacros/magics.h

@@ -59,6 +59,7 @@ MAGIC_METHOD(__package__)
 MAGIC_METHOD(__path__)
 MAGIC_METHOD(__class__)
 MAGIC_METHOD(__abs__)
+MAGIC_METHOD(__getattr__)
 MAGIC_METHOD(__missing__)
 
 #endif

+ 8 - 0
src/public/py_ops.c

@@ -151,6 +151,14 @@ bool py_getattr(py_Ref self, py_Name name) {
         }
     }
 
+    py_Ref fallback = py_tpfindmagic(type, __getattr__);
+    if(fallback){
+        py_push(fallback);
+        py_push(self);
+        py_newstr(py_pushtmp(), py_name2str(name));
+        return py_vectorcall(1, 0);
+    }
+
     if(self->type == tp_module) {
         py_Ref path = py_getdict(self, __path__);
         c11_sbuf buf;

+ 24 - 0
tests/50_reflection.py

@@ -26,3 +26,27 @@ except AttributeError:
     pass
 
 assert getattr(a, 'xxx', 1) == 1
+
+class A:
+    def __init__(self, x):
+        self.x = x
+
+    def __getattr__(self, name):
+        if not name:
+            raise AttributeError
+        return name, None
+    
+a = A(1)
+assert a.x == 1
+assert a.y == ('y', None)
+assert a.zzz == ('zzz', None)
+
+assert getattr(a, 'x') == 1
+assert getattr(a, 'zzz') == ('zzz', None)
+
+assert hasattr(a, 'x')
+assert hasattr(a, 'y')
+assert hasattr(a, 'zzz')
+
+assert not hasattr(a, '')
+