Skip to content

Commit 80deddb

Browse files
committed
Add a test.
Such an implementation is used in `IUnknown` of `comtypes`.
1 parent b61fece commit 80deddb

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import unittest
2+
import ctypes
3+
from ctypes import POINTER, c_void_p
4+
5+
from ._support import PyCSimpleType
6+
7+
8+
class PyCSimpleTypeAsMetaclassTest(unittest.TestCase):
9+
def tearDown(self):
10+
# to not leak references, we must clean _pointer_type_cache
11+
ctypes._reset_cache()
12+
13+
def test_early_return_in_dunder_new_1(self):
14+
# Such an implementation is used in `IUnknown` of `comtypes`.
15+
16+
class _ct_meta(type):
17+
def __new__(cls, name, bases, namespace):
18+
self = super().__new__(cls, name, bases, namespace)
19+
if bases == (c_void_p,):
20+
return self
21+
if issubclass(self, _PtrBase):
22+
return self
23+
if bases == (object,):
24+
_ptr_bases = (self, _PtrBase)
25+
else:
26+
_ptr_bases = (self, POINTER(bases[0]))
27+
p = _p_meta(f"POINTER({self.__name__})", _ptr_bases, {})
28+
ctypes._pointer_type_cache[self] = p
29+
return self
30+
31+
class _p_meta(PyCSimpleType, _ct_meta):
32+
pass
33+
34+
class _PtrBase(c_void_p, metaclass=_p_meta):
35+
pass
36+
37+
class _CtBase(object, metaclass=_ct_meta):
38+
pass
39+
40+
class _Sub(_CtBase):
41+
pass
42+
43+
class _Sub2(_Sub):
44+
pass
45+
46+
self.assertIsInstance(POINTER(_Sub2), _p_meta)
47+
self.assertTrue(issubclass(POINTER(_Sub2), _Sub2))
48+
self.assertTrue(issubclass(POINTER(_Sub2), POINTER(_Sub)))
49+
self.assertTrue(issubclass(POINTER(_Sub), POINTER(_CtBase)))

0 commit comments

Comments
 (0)