summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorIvan Levkivskyi <levkivskyi@gmail.com>2017-12-14 10:59:44 (GMT)
committerGitHub <noreply@github.com>2017-12-14 10:59:44 (GMT)
commit5364b5cd7571f2dfa75acd37b388c14ac33fef73 (patch)
tree43b89bf162a571e979946d2d9dcfda82b4e0f4c8 /Lib
parent9e7c136ad8bc8e8eec50c2a8ae5ff02752f695a2 (diff)
downloadcpython-5364b5cd7571f2dfa75acd37b388c14ac33fef73.zip
cpython-5364b5cd7571f2dfa75acd37b388c14ac33fef73.tar.gz
cpython-5364b5cd7571f2dfa75acd37b388c14ac33fef73.tar.bz2
bpo-32225: Implementation of PEP 562 (#4731)
Implement PEP 562: module __getattr__ and __dir__. The implementation simply updates module_getattro and module_dir.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/bad_getattr.py4
-rw-r--r--Lib/test/bad_getattr2.py7
-rw-r--r--Lib/test/bad_getattr3.py5
-rw-r--r--Lib/test/good_getattr.py11
-rw-r--r--Lib/test/test_module.py51
5 files changed, 78 insertions, 0 deletions
diff --git a/Lib/test/bad_getattr.py b/Lib/test/bad_getattr.py
new file mode 100644
index 0000000..16f901b
--- /dev/null
+++ b/Lib/test/bad_getattr.py
@@ -0,0 +1,4 @@
+x = 1
+
+__getattr__ = "Surprise!"
+__dir__ = "Surprise again!"
diff --git a/Lib/test/bad_getattr2.py b/Lib/test/bad_getattr2.py
new file mode 100644
index 0000000..0a52a53
--- /dev/null
+++ b/Lib/test/bad_getattr2.py
@@ -0,0 +1,7 @@
+def __getattr__():
+ "Bad one"
+
+x = 1
+
+def __dir__(bad_sig):
+ return []
diff --git a/Lib/test/bad_getattr3.py b/Lib/test/bad_getattr3.py
new file mode 100644
index 0000000..0d5f926
--- /dev/null
+++ b/Lib/test/bad_getattr3.py
@@ -0,0 +1,5 @@
+def __getattr__(name):
+ if name != 'delgetattr':
+ raise AttributeError
+ del globals()['__getattr__']
+ raise AttributeError
diff --git a/Lib/test/good_getattr.py b/Lib/test/good_getattr.py
new file mode 100644
index 0000000..7d27de6
--- /dev/null
+++ b/Lib/test/good_getattr.py
@@ -0,0 +1,11 @@
+x = 1
+
+def __dir__():
+ return ['a', 'b', 'c']
+
+def __getattr__(name):
+ if name == "yolo":
+ raise AttributeError("Deprecated, use whatever instead")
+ return f"There is {name}"
+
+y = 2
diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py
index 6d0d594..efe9a8e 100644
--- a/Lib/test/test_module.py
+++ b/Lib/test/test_module.py
@@ -125,6 +125,57 @@ a = A(destroyed)"""
gc_collect()
self.assertIs(wr(), None)
+ def test_module_getattr(self):
+ import test.good_getattr as gga
+ from test.good_getattr import test
+ self.assertEqual(test, "There is test")
+ self.assertEqual(gga.x, 1)
+ self.assertEqual(gga.y, 2)
+ with self.assertRaisesRegex(AttributeError,
+ "Deprecated, use whatever instead"):
+ gga.yolo
+ self.assertEqual(gga.whatever, "There is whatever")
+ del sys.modules['test.good_getattr']
+
+ def test_module_getattr_errors(self):
+ import test.bad_getattr as bga
+ from test import bad_getattr2
+ self.assertEqual(bga.x, 1)
+ self.assertEqual(bad_getattr2.x, 1)
+ with self.assertRaises(TypeError):
+ bga.nope
+ with self.assertRaises(TypeError):
+ bad_getattr2.nope
+ del sys.modules['test.bad_getattr']
+ if 'test.bad_getattr2' in sys.modules:
+ del sys.modules['test.bad_getattr2']
+
+ def test_module_dir(self):
+ import test.good_getattr as gga
+ self.assertEqual(dir(gga), ['a', 'b', 'c'])
+ del sys.modules['test.good_getattr']
+
+ def test_module_dir_errors(self):
+ import test.bad_getattr as bga
+ from test import bad_getattr2
+ with self.assertRaises(TypeError):
+ dir(bga)
+ with self.assertRaises(TypeError):
+ dir(bad_getattr2)
+ del sys.modules['test.bad_getattr']
+ if 'test.bad_getattr2' in sys.modules:
+ del sys.modules['test.bad_getattr2']
+
+ def test_module_getattr_tricky(self):
+ from test import bad_getattr3
+ # these lookups should not crash
+ with self.assertRaises(AttributeError):
+ bad_getattr3.one
+ with self.assertRaises(AttributeError):
+ bad_getattr3.delgetattr
+ if 'test.bad_getattr3' in sys.modules:
+ del sys.modules['test.bad_getattr3']
+
def test_module_repr_minimal(self):
# reprs when modules have no __file__, __name__, or __loader__
m = ModuleType('foo')