Skip to content

Commit 4f69961

Browse files
committed
gh-104533: Fix @ctypes.util.struct with string annotations
Fix @ctypes.util.struct on structures declared in a module which uses "from __future__ import annotations". The decorator now calls get_annotations() with eval_str=True.
1 parent a1d5804 commit 4f69961

3 files changed

Lines changed: 27 additions & 4 deletions

File tree

Lib/ctypes/util.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,8 @@ def _process_struct(decorated_class, /, *, align, layout, endian, pack):
512512
fields.extend(decorated_class._fields_)
513513
anonymous.extend(decorated_class._anonymous_)
514514

515-
for name, hint in annotationlib.get_annotations(decorated_class).items():
515+
annotations = annotationlib.get_annotations(decorated_class, eval_str=True)
516+
for name, hint in annotations.items():
516517
if get_origin(hint) is ClassVar:
517518
continue
518519

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from __future__ import annotations
2+
from ctypes.util import struct
3+
from ctypes import c_int
4+
5+
class TestAnn:
6+
x: c_int
7+
8+
# Check that "from __future__ import annotations" works as expected
9+
if not isinstance(TestAnn.__annotations__['x'], str):
10+
raise Exception("annotations must be strings")
11+
12+
@struct
13+
class Point:
14+
x: c_int
15+
y: c_int

Lib/test/test_ctypes/test_structures.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ class X(Structure):
8888
self.assertEqual(sizeof(X), min(8, longlong_align) + longlong_size)
8989
self.assertEqual(X.b.offset, min(8, longlong_align))
9090

91-
with self.assertRaises(ValueError):
92-
if use_struct_util:
91+
if use_struct_util:
92+
with self.assertRaises(NameError):
9393
@struct_util(pack=-1, layout='ms')
9494
class X:
9595
a: "b"
9696
b: "q"
97-
else:
97+
else:
98+
with self.assertRaises(ValueError):
9899
class X(Structure):
99100
_fields_ = [("a", "b"), ("b", "q")]
100101
_pack_ = -1
@@ -954,6 +955,12 @@ class Foo:
954955

955956
self.assertEqual(Foo.__name__, "Foo")
956957

958+
def test_string_annotations(self):
959+
from test.test_ctypes import struct_str_ann
960+
Point = struct_str_ann.Point
961+
fields = [['x', c_int], ['y', c_int]]
962+
self.assertEqual(Point._fields_, fields)
963+
957964

958965
if __name__ == '__main__':
959966
unittest.main()

0 commit comments

Comments
 (0)