Author: Yannick Jadoul <[email protected]>
Branch: py3.7-pep562
Changeset: r97732:bb000a053f9f
Date: 2019-10-04 01:34 +0200
http://bitbucket.org/pypy/pypy/changeset/bb000a053f9f/

Log:    Implementation of PEP 562, adding __getattr__ and __dir__ for
        modules

diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -134,6 +134,10 @@
         except OperationError as e:
             if not e.match(space, space.w_AttributeError):
                 raise
+            w_dict = self.w_dict
+            w_getattr = space.finditem(w_dict, space.newtext('__getattr__'))
+            if w_getattr is not None:
+                return space.call_function(w_getattr, w_attr)
             w_name = space.finditem(self.w_dict, space.newtext('__name__'))
             if w_name is None:
                 raise oefmt(space.w_AttributeError,
@@ -147,6 +151,9 @@
         if not space.isinstance_w(w_dict, space.w_dict):
             raise oefmt(space.w_TypeError, "%N.__dict__ is not a dictionary",
                         self)
+        w_dir = space.finditem(w_dict, space.newtext('__dir__'))
+        if w_dir is not None:
+            return space.call_function(w_dir)
         return space.call_function(space.w_list, w_dict)
 
     # These three methods are needed to implement '__class__' assignment
diff --git a/pypy/interpreter/test/test_module.py 
b/pypy/interpreter/test/test_module.py
--- a/pypy/interpreter/test/test_module.py
+++ b/pypy/interpreter/test/test_module.py
@@ -262,3 +262,29 @@
         raises(AttributeError, "del x.a")
         raises(TypeError, "x.__class__ = X")
         raises(TypeError, "sys.__class__ = XX")
+
+    def test_getattr_dir(self):
+        def __getattr__(name):
+            if name == 'y':
+                return 42
+            elif name == 'z':
+                return
+            raise AttributeError("No attribute '{}'".format(name))
+
+        def __dir__():
+            return ['x', 'y', 'z', 'w']
+
+        import sys
+        m = type(sys)('foo')
+        m.x = 'x'
+        m.__getattr__ = __getattr__
+        print(m.__dir__)
+        m.__dir__ = __dir__
+
+        assert m.x == 'x'
+        assert m.y == 42
+        assert m.z == None
+        excinfo = raises(AttributeError, 'm.w')
+        assert str(excinfo.value) == "No attribute 'w'"
+        print(dir(m))
+        assert dir(m) == sorted(['x', 'y', 'z', 'w'])
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to