diff options
| author | Christian Tismer <tismer@stackless.com> | 2022-06-21 10:22:04 +0200 |
|---|---|---|
| committer | Christian Tismer <tismer@stackless.com> | 2022-07-14 17:21:31 +0200 |
| commit | f92b7dcac9537fb091dc15d3ee218f1984d8abef (patch) | |
| tree | 1bad4ea3cfa9d7c5eeb88450df38a103a7402e99 /sources/pyside6/tests/pysidetest/enum_test.py | |
| parent | da2cf031521815a9559ca784beadb70c7a2852d9 (diff) | |
PyEnum: Increase compatibility by allowing defaults and old flag names
This patch supports to write
Qt.Alignment()
instead of
Qt.AlignmentFlag(0)
Also supported is
Qt.AlignmentFlag()
which is mapped to
Qt.AlignmentFlag(0)
This trickery was quite involved since the Python opcodes
needed to be analyzed if we have a parameterless call.
Only in that case, we insert a partial object which supplies the
missing value=0 default.
Changing the implementation of PyEnum was not desired because this
is highly complicated, not portable and even not possible.
The change has been tested with Python 3.6 to 3.11.0b3 .
[ChangeLog][shiboken6] The new Python enums are made as compatible
to the old ones as possible. It is again allowed to use Qt.Alignment()
instead of Qt.AlignmentFlag(0), and a default of 0 is always allowed.
Change-Id: If6a93f8210ff6cae4e38251420e1ad5fffbe42cb
Pick-to: 6.3
Task-number: PYSIDE-1735
Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/pyside6/tests/pysidetest/enum_test.py')
| -rw-r--r-- | sources/pyside6/tests/pysidetest/enum_test.py | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/sources/pyside6/tests/pysidetest/enum_test.py b/sources/pyside6/tests/pysidetest/enum_test.py index 34f90702a..158faf37c 100644 --- a/sources/pyside6/tests/pysidetest/enum_test.py +++ b/sources/pyside6/tests/pysidetest/enum_test.py @@ -13,6 +13,7 @@ init_test_paths(True) from PySide6.QtCore import Qt from testbinding import Enum1, TestObjectWithoutNamespace +import dis class ListConnectionTest(unittest.TestCase): @@ -44,6 +45,120 @@ class ListConnectionTest(unittest.TestCase): self.assertFalse(Qt.AlignBottom < Qt.AlignHCenter) self.assertTrue(Qt.AlignBottom > Qt.AlignHCenter) +# PYSIDE-1735: We are testing that opcodes do what they are supposed to do. +# This is needed in the PyEnum forgiveness mode where we need +# to introspect the code if an Enum was called with no args. +class InvestigateOpcodesTest(unittest.TestCase): + + def probe_function1(self): + x = Qt.Alignment + + def probe_function2(self): + x = Qt.Alignment() + + @staticmethod + def read_code(func, **kw): + return list(instr[:3] for instr in dis.Bytecode(func, **kw)) + + @staticmethod + def get_sizes(func, **kw): + ops = list((instr.opname, instr.offset) for instr in dis.Bytecode(func, **kw)) + res = [] + for idx in range(1, len(ops)): + res.append((ops[idx - 1][0], ops[idx][1] - ops[idx - 1][1])) + return sorted(res, key=lambda x: (x[1], x[0])) + + def testByteCode(self): + # opname, opcode, arg + result_1 = [('LOAD_GLOBAL', 116, 0), + ('LOAD_ATTR', 106, 1), + ('STORE_FAST', 125, 1), + ('LOAD_CONST', 100, 0), + ('RETURN_VALUE', 83, None)] + + result_2 = [('LOAD_GLOBAL', 116, 0), + ('LOAD_METHOD', 160, 1), + ('CALL_METHOD', 161, 0), + ('STORE_FAST', 125, 1), + ('LOAD_CONST', 100, 0), + ('RETURN_VALUE', 83, None)] + + if sys.version_info[:2] <= (3, 6): + + result_2 = [('LOAD_GLOBAL', 116, 0), + ('LOAD_ATTR', 106, 1), + ('CALL_FUNCTION', 131, 0), + ('STORE_FAST', 125, 1), + ('LOAD_CONST', 100, 0), + ('RETURN_VALUE', 83, None)] + + if sys.version_info[:2] >= (3, 11): + # Note: Python 3.11 is a bit more complex because it can optimize itself. + # Opcodes are a bit different, and a hidden second code object is used. + # We investigate this a bit, because we want to be warned when things change. + QUICKENING_WARMUP_DELAY = 8 + + result_1 = [('RESUME', 151, 0), + ('LOAD_GLOBAL', 116, 0), + ('LOAD_ATTR', 106, 1), + ('STORE_FAST', 125, 1), + ('LOAD_CONST', 100, 0), + ('RETURN_VALUE', 83, None)] + + result_2 = [('RESUME', 151, 0), + ('LOAD_GLOBAL', 116, 1), + ('LOAD_ATTR', 106, 1), + ('PRECALL', 166, 0), + ('CALL', 171, 0), + ('STORE_FAST', 125, 1), + ('LOAD_CONST', 100, 0), + ('RETURN_VALUE', 83, None)] + + sizes_2 = [('LOAD_CONST', 2), + ('RESUME', 2), + ('STORE_FAST', 2), + ('PRECALL', 4), + ('CALL', 10), + ('LOAD_ATTR', 10), + ('LOAD_GLOBAL', 12)] + + self.assertEqual(self.read_code(self.probe_function2, adaptive=True), result_2) + self.assertEqual(self.get_sizes(self.probe_function2, adaptive=True), sizes_2) + + @staticmethod + def code_quicken(f, times): + # running the code triggers acceleration after some runs. + for _ in range(times): + f() + + code_quicken(self.probe_function2, QUICKENING_WARMUP_DELAY-1) + self.assertEqual(self.read_code(self.probe_function2, adaptive=True), result_2) + self.assertEqual(self.get_sizes(self.probe_function2, adaptive=True), sizes_2) + + result_3 = [('RESUME_QUICK', 150, 0), + ('LOAD_GLOBAL_MODULE', 55, 1), + ('LOAD_ATTR_ADAPTIVE', 39, 1), + ('PRECALL_ADAPTIVE', 64, 0), + ('CALL_ADAPTIVE', 22, 0), + ('STORE_FAST', 125, 1), + ('LOAD_CONST', 100, 0), + ('RETURN_VALUE', 83, None)] + + sizes_3 = [('LOAD_CONST', 2), + ('RESUME_QUICK', 2), + ('STORE_FAST', 2), + ('PRECALL_ADAPTIVE', 4), + ('CALL_ADAPTIVE', 10), + ('LOAD_ATTR_ADAPTIVE', 10), + ('LOAD_GLOBAL_MODULE', 12)] + + code_quicken(self.probe_function2, 1) + self.assertEqual(self.read_code(self.probe_function2, adaptive=True), result_3) + self.assertEqual(self.get_sizes(self.probe_function2, adaptive=True), sizes_3) + + self.assertEqual(self.read_code(self.probe_function1), result_1) + self.assertEqual(self.read_code(self.probe_function2), result_2) + if __name__ == '__main__': unittest.main() |
