summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorPetr Viktorin <encukou@gmail.com>2020-05-07 13:39:59 (GMT)
committerGitHub <noreply@github.com>2020-05-07 13:39:59 (GMT)
commite1becf46b4e3ba6d7d32ebf4bbd3e0804766a423 (patch)
treebe3fda5019edbdc78e82ee21985ea963686f3eb8 /Lib
parent4638c6429575bd6de26b12b2af5df74d6568b553 (diff)
downloadcpython-e1becf46b4e3ba6d7d32ebf4bbd3e0804766a423.zip
cpython-e1becf46b4e3ba6d7d32ebf4bbd3e0804766a423.tar.gz
cpython-e1becf46b4e3ba6d7d32ebf4bbd3e0804766a423.tar.bz2
bpo-38787: C API for module state access from extension methods (PEP 573) (GH-19936)
Module C state is now accessible from C-defined heap type methods (PEP 573). Patch by Marcel Plch and Petr Viktorin. Co-authored-by: Marcel Plch <mplch@redhat.com> Co-authored-by: Victor Stinner <vstinner@python.org>
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_capi.py73
-rw-r--r--Lib/test/test_sys.py2
2 files changed, 74 insertions, 1 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index f9578d3..5c7526a 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -13,6 +13,8 @@ import threading
import time
import unittest
import weakref
+import importlib.machinery
+import importlib.util
from test import support
from test.support import MISSING_C_DOCSTRINGS
from test.support.script_helper import assert_python_failure, assert_python_ok
@@ -774,5 +776,76 @@ class PyMemDefaultTests(PyMemDebugTests):
PYTHONMALLOC = ''
+class Test_ModuleStateAccess(unittest.TestCase):
+ """Test access to module start (PEP 573)"""
+
+ # The C part of the tests lives in _testmultiphase, in a module called
+ # _testmultiphase_meth_state_access.
+ # This module has multi-phase initialization, unlike _testcapi.
+
+ def setUp(self):
+ fullname = '_testmultiphase_meth_state_access' # XXX
+ origin = importlib.util.find_spec('_testmultiphase').origin
+ loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
+ spec = importlib.util.spec_from_loader(fullname, loader)
+ module = importlib.util.module_from_spec(spec)
+ loader.exec_module(module)
+ self.module = module
+
+ def test_subclass_get_module(self):
+ """PyType_GetModule for defining_class"""
+ class StateAccessType_Subclass(self.module.StateAccessType):
+ pass
+
+ instance = StateAccessType_Subclass()
+ self.assertIs(instance.get_defining_module(), self.module)
+
+ def test_subclass_get_module_with_super(self):
+ class StateAccessType_Subclass(self.module.StateAccessType):
+ def get_defining_module(self):
+ return super().get_defining_module()
+
+ instance = StateAccessType_Subclass()
+ self.assertIs(instance.get_defining_module(), self.module)
+
+ def test_state_access(self):
+ """Checks methods defined with and without argument clinic
+
+ This tests a no-arg method (get_count) and a method with
+ both a positional and keyword argument.
+ """
+
+ a = self.module.StateAccessType()
+ b = self.module.StateAccessType()
+
+ methods = {
+ 'clinic': a.increment_count_clinic,
+ 'noclinic': a.increment_count_noclinic,
+ }
+
+ for name, increment_count in methods.items():
+ with self.subTest(name):
+ self.assertEqual(a.get_count(), b.get_count())
+ self.assertEqual(a.get_count(), 0)
+
+ increment_count()
+ self.assertEqual(a.get_count(), b.get_count())
+ self.assertEqual(a.get_count(), 1)
+
+ increment_count(3)
+ self.assertEqual(a.get_count(), b.get_count())
+ self.assertEqual(a.get_count(), 4)
+
+ increment_count(-2, twice=True)
+ self.assertEqual(a.get_count(), b.get_count())
+ self.assertEqual(a.get_count(), 0)
+
+ with self.assertRaises(TypeError):
+ increment_count(thrice=3)
+
+ with self.assertRaises(TypeError):
+ increment_count(1, 2, 3)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 91a645b..33b3459 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1322,7 +1322,7 @@ class SizeofTest(unittest.TestCase):
'3P' # PyMappingMethods
'10P' # PySequenceMethods
'2P' # PyBufferProcs
- '4P')
+ '5P')
class newstyleclass(object): pass
# Separate block for PyDictKeysObject with 8 keys and 5 entries
check(newstyleclass, s + calcsize("2nP2n0P") + 8 + 5*calcsize("n2P"))