mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-131747: ctypes: Deprecate _pack_ implicitly setting _layout_ = 'ms' (GH-133205)
On non-Windows, warn when _pack_ implicitly changes default _layout_ to 'ms'. Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
parent
f554237b8e
commit
59f78d7b06
14 changed files with 115 additions and 16 deletions
|
@ -7,6 +7,8 @@ Deprecations
|
||||||
|
|
||||||
.. include:: pending-removal-in-3.17.rst
|
.. include:: pending-removal-in-3.17.rst
|
||||||
|
|
||||||
|
.. include:: pending-removal-in-3.19.rst
|
||||||
|
|
||||||
.. include:: pending-removal-in-future.rst
|
.. include:: pending-removal-in-future.rst
|
||||||
|
|
||||||
C API deprecations
|
C API deprecations
|
||||||
|
|
8
Doc/deprecations/pending-removal-in-3.19.rst
Normal file
8
Doc/deprecations/pending-removal-in-3.19.rst
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Pending removal in Python 3.19
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
* :mod:`ctypes`:
|
||||||
|
|
||||||
|
* Implicitly switching to the MSVC-compatible struct layout by setting
|
||||||
|
:attr:`~ctypes.Structure._pack_` but not :attr:`~ctypes.Structure._layout_`
|
||||||
|
on non-Windows platforms.
|
|
@ -2754,6 +2754,16 @@ fields, or any other data types containing pointer type fields.
|
||||||
when :attr:`_fields_` is assigned, otherwise it will have no effect.
|
when :attr:`_fields_` is assigned, otherwise it will have no effect.
|
||||||
Setting this attribute to 0 is the same as not setting it at all.
|
Setting this attribute to 0 is the same as not setting it at all.
|
||||||
|
|
||||||
|
This is only implemented for the MSVC-compatible memory layout.
|
||||||
|
|
||||||
|
.. deprecated-removed:: next 3.19
|
||||||
|
|
||||||
|
For historical reasons, if :attr:`!_pack_` is non-zero,
|
||||||
|
the MSVC-compatible layout will be used by default.
|
||||||
|
On non-Windows platforms, this default is deprecated and is slated to
|
||||||
|
become an error in Python 3.19.
|
||||||
|
If it is intended, set :attr:`~Structure._layout_` to ``'ms'``
|
||||||
|
explicitly.
|
||||||
|
|
||||||
.. attribute:: _align_
|
.. attribute:: _align_
|
||||||
|
|
||||||
|
@ -2782,12 +2792,15 @@ fields, or any other data types containing pointer type fields.
|
||||||
Currently the default will be:
|
Currently the default will be:
|
||||||
|
|
||||||
- On Windows: ``"ms"``
|
- On Windows: ``"ms"``
|
||||||
- When :attr:`~Structure._pack_` is specified: ``"ms"``
|
- When :attr:`~Structure._pack_` is specified: ``"ms"``.
|
||||||
|
(This is deprecated; see :attr:`~Structure._pack_` documentation.)
|
||||||
- Otherwise: ``"gcc-sysv"``
|
- Otherwise: ``"gcc-sysv"``
|
||||||
|
|
||||||
:attr:`!_layout_` must already be defined when
|
:attr:`!_layout_` must already be defined when
|
||||||
:attr:`~Structure._fields_` is assigned, otherwise it will have no effect.
|
:attr:`~Structure._fields_` is assigned, otherwise it will have no effect.
|
||||||
|
|
||||||
|
.. versionadded:: next
|
||||||
|
|
||||||
.. attribute:: _anonymous_
|
.. attribute:: _anonymous_
|
||||||
|
|
||||||
An optional sequence that lists the names of unnamed (anonymous) fields.
|
An optional sequence that lists the names of unnamed (anonymous) fields.
|
||||||
|
|
|
@ -1874,6 +1874,12 @@ Deprecated
|
||||||
:func:`codecs.open` is now deprecated. Use :func:`open` instead.
|
:func:`codecs.open` is now deprecated. Use :func:`open` instead.
|
||||||
(Contributed by Inada Naoki in :gh:`133036`.)
|
(Contributed by Inada Naoki in :gh:`133036`.)
|
||||||
|
|
||||||
|
* :mod:`ctypes`:
|
||||||
|
On non-Windows platforms, setting :attr:`.Structure._pack_` to use a
|
||||||
|
MSVC-compatible default memory layout is deprecated in favor of setting
|
||||||
|
:attr:`.Structure._layout_` to ``'ms'``.
|
||||||
|
(Contributed by Petr Viktorin in :gh:`131747`.)
|
||||||
|
|
||||||
* :mod:`ctypes`:
|
* :mod:`ctypes`:
|
||||||
Calling :func:`ctypes.POINTER` on a string is deprecated.
|
Calling :func:`ctypes.POINTER` on a string is deprecated.
|
||||||
Use :ref:`ctypes-incomplete-types` for self-referential structures.
|
Use :ref:`ctypes-incomplete-types` for self-referential structures.
|
||||||
|
@ -1948,6 +1954,8 @@ Deprecated
|
||||||
|
|
||||||
.. include:: ../deprecations/pending-removal-in-3.17.rst
|
.. include:: ../deprecations/pending-removal-in-3.17.rst
|
||||||
|
|
||||||
|
.. include:: ../deprecations/pending-removal-in-3.19.rst
|
||||||
|
|
||||||
.. include:: ../deprecations/pending-removal-in-future.rst
|
.. include:: ../deprecations/pending-removal-in-future.rst
|
||||||
|
|
||||||
Removed
|
Removed
|
||||||
|
|
|
@ -5,6 +5,7 @@ may change at any time.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import warnings
|
||||||
|
|
||||||
from _ctypes import CField, buffer_info
|
from _ctypes import CField, buffer_info
|
||||||
import ctypes
|
import ctypes
|
||||||
|
@ -66,9 +67,26 @@ def get_layout(cls, input_fields, is_struct, base):
|
||||||
|
|
||||||
# For clarity, variables that count bits have `bit` in their names.
|
# For clarity, variables that count bits have `bit` in their names.
|
||||||
|
|
||||||
|
pack = getattr(cls, '_pack_', None)
|
||||||
|
|
||||||
layout = getattr(cls, '_layout_', None)
|
layout = getattr(cls, '_layout_', None)
|
||||||
if layout is None:
|
if layout is None:
|
||||||
if sys.platform == 'win32' or getattr(cls, '_pack_', None):
|
if sys.platform == 'win32':
|
||||||
|
gcc_layout = False
|
||||||
|
elif pack:
|
||||||
|
if is_struct:
|
||||||
|
base_type_name = 'Structure'
|
||||||
|
else:
|
||||||
|
base_type_name = 'Union'
|
||||||
|
warnings._deprecated(
|
||||||
|
'_pack_ without _layout_',
|
||||||
|
f"Due to '_pack_', the '{cls.__name__}' {base_type_name} will "
|
||||||
|
+ "use memory layout compatible with MSVC (Windows). "
|
||||||
|
+ "If this is intended, set _layout_ to 'ms'. "
|
||||||
|
+ "The implicit default is deprecated and slated to become "
|
||||||
|
+ "an error in Python {remove}.",
|
||||||
|
remove=(3, 19),
|
||||||
|
)
|
||||||
gcc_layout = False
|
gcc_layout = False
|
||||||
else:
|
else:
|
||||||
gcc_layout = True
|
gcc_layout = True
|
||||||
|
@ -95,7 +113,6 @@ def get_layout(cls, input_fields, is_struct, base):
|
||||||
else:
|
else:
|
||||||
big_endian = sys.byteorder == 'big'
|
big_endian = sys.byteorder == 'big'
|
||||||
|
|
||||||
pack = getattr(cls, '_pack_', None)
|
|
||||||
if pack is not None:
|
if pack is not None:
|
||||||
try:
|
try:
|
||||||
pack = int(pack)
|
pack = int(pack)
|
||||||
|
|
|
@ -316,6 +316,7 @@ class TestAlignedStructures(unittest.TestCase, StructCheckMixin):
|
||||||
|
|
||||||
class Main(sbase):
|
class Main(sbase):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = "ms"
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("a", c_ubyte),
|
("a", c_ubyte),
|
||||||
("b", Inner),
|
("b", Inner),
|
||||||
|
|
|
@ -430,6 +430,7 @@ class BitFieldTest(unittest.TestCase, StructCheckMixin):
|
||||||
def test_gh_84039(self):
|
def test_gh_84039(self):
|
||||||
class Bad(Structure):
|
class Bad(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = "ms"
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("a0", c_uint8, 1),
|
("a0", c_uint8, 1),
|
||||||
("a1", c_uint8, 1),
|
("a1", c_uint8, 1),
|
||||||
|
@ -443,9 +444,9 @@ class BitFieldTest(unittest.TestCase, StructCheckMixin):
|
||||||
("b1", c_uint16, 12),
|
("b1", c_uint16, 12),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class GoodA(Structure):
|
class GoodA(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = "ms"
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("a0", c_uint8, 1),
|
("a0", c_uint8, 1),
|
||||||
("a1", c_uint8, 1),
|
("a1", c_uint8, 1),
|
||||||
|
@ -460,6 +461,7 @@ class BitFieldTest(unittest.TestCase, StructCheckMixin):
|
||||||
|
|
||||||
class Good(Structure):
|
class Good(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = "ms"
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("a", GoodA),
|
("a", GoodA),
|
||||||
("b0", c_uint16, 4),
|
("b0", c_uint16, 4),
|
||||||
|
@ -475,6 +477,7 @@ class BitFieldTest(unittest.TestCase, StructCheckMixin):
|
||||||
def test_gh_73939(self):
|
def test_gh_73939(self):
|
||||||
class MyStructure(Structure):
|
class MyStructure(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = "ms"
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("P", c_uint16),
|
("P", c_uint16),
|
||||||
("L", c_uint16, 9),
|
("L", c_uint16, 9),
|
||||||
|
|
|
@ -269,6 +269,7 @@ class Test(unittest.TestCase, StructCheckMixin):
|
||||||
|
|
||||||
class S(base):
|
class S(base):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = "ms"
|
||||||
_fields_ = [("b", c_byte),
|
_fields_ = [("b", c_byte),
|
||||||
("h", c_short),
|
("h", c_short),
|
||||||
|
|
||||||
|
@ -296,6 +297,7 @@ class Test(unittest.TestCase, StructCheckMixin):
|
||||||
|
|
||||||
class S(Structure):
|
class S(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = "ms"
|
||||||
_fields_ = [("b", c_byte),
|
_fields_ = [("b", c_byte),
|
||||||
|
|
||||||
("h", c_short),
|
("h", c_short),
|
||||||
|
|
|
@ -125,18 +125,21 @@ class Nested(Structure):
|
||||||
class Packed1(Structure):
|
class Packed1(Structure):
|
||||||
_fields_ = [('a', c_int8), ('b', c_int64)]
|
_fields_ = [('a', c_int8), ('b', c_int64)]
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
class Packed2(Structure):
|
class Packed2(Structure):
|
||||||
_fields_ = [('a', c_int8), ('b', c_int64)]
|
_fields_ = [('a', c_int8), ('b', c_int64)]
|
||||||
_pack_ = 2
|
_pack_ = 2
|
||||||
|
_layout_ = 'ms'
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
class Packed3(Structure):
|
class Packed3(Structure):
|
||||||
_fields_ = [('a', c_int8), ('b', c_int64)]
|
_fields_ = [('a', c_int8), ('b', c_int64)]
|
||||||
_pack_ = 4
|
_pack_ = 4
|
||||||
|
_layout_ = 'ms'
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
|
@ -155,6 +158,7 @@ class Packed4(Structure):
|
||||||
|
|
||||||
_fields_ = [('a', c_int8), ('b', c_int64)]
|
_fields_ = [('a', c_int8), ('b', c_int64)]
|
||||||
_pack_ = 8
|
_pack_ = 8
|
||||||
|
_layout_ = 'ms'
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
class X86_32EdgeCase(Structure):
|
class X86_32EdgeCase(Structure):
|
||||||
|
@ -366,6 +370,7 @@ class Example_gh_95496(Structure):
|
||||||
@register()
|
@register()
|
||||||
class Example_gh_84039_bad(Structure):
|
class Example_gh_84039_bad(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("a0", c_uint8, 1),
|
_fields_ = [("a0", c_uint8, 1),
|
||||||
("a1", c_uint8, 1),
|
("a1", c_uint8, 1),
|
||||||
("a2", c_uint8, 1),
|
("a2", c_uint8, 1),
|
||||||
|
@ -380,6 +385,7 @@ class Example_gh_84039_bad(Structure):
|
||||||
@register()
|
@register()
|
||||||
class Example_gh_84039_good_a(Structure):
|
class Example_gh_84039_good_a(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("a0", c_uint8, 1),
|
_fields_ = [("a0", c_uint8, 1),
|
||||||
("a1", c_uint8, 1),
|
("a1", c_uint8, 1),
|
||||||
("a2", c_uint8, 1),
|
("a2", c_uint8, 1),
|
||||||
|
@ -392,6 +398,7 @@ class Example_gh_84039_good_a(Structure):
|
||||||
@register()
|
@register()
|
||||||
class Example_gh_84039_good(Structure):
|
class Example_gh_84039_good(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("a", Example_gh_84039_good_a),
|
_fields_ = [("a", Example_gh_84039_good_a),
|
||||||
("b0", c_uint16, 4),
|
("b0", c_uint16, 4),
|
||||||
("b1", c_uint16, 12)]
|
("b1", c_uint16, 12)]
|
||||||
|
@ -399,6 +406,7 @@ class Example_gh_84039_good(Structure):
|
||||||
@register()
|
@register()
|
||||||
class Example_gh_73939(Structure):
|
class Example_gh_73939(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("P", c_uint16),
|
_fields_ = [("P", c_uint16),
|
||||||
("L", c_uint16, 9),
|
("L", c_uint16, 9),
|
||||||
("Pro", c_uint16, 1),
|
("Pro", c_uint16, 1),
|
||||||
|
@ -419,6 +427,7 @@ class Example_gh_86098(Structure):
|
||||||
@register()
|
@register()
|
||||||
class Example_gh_86098_pack(Structure):
|
class Example_gh_86098_pack(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("a", c_uint8, 8),
|
_fields_ = [("a", c_uint8, 8),
|
||||||
("b", c_uint8, 8),
|
("b", c_uint8, 8),
|
||||||
("c", c_uint32, 16)]
|
("c", c_uint32, 16)]
|
||||||
|
@ -528,7 +537,7 @@ def dump_ctype(tp, struct_or_union_tag='', variable_name='', semi=''):
|
||||||
pushes.append(f'#pragma pack(push, {pack})')
|
pushes.append(f'#pragma pack(push, {pack})')
|
||||||
pops.append(f'#pragma pack(pop)')
|
pops.append(f'#pragma pack(pop)')
|
||||||
layout = getattr(tp, '_layout_', None)
|
layout = getattr(tp, '_layout_', None)
|
||||||
if layout == 'ms' or pack:
|
if layout == 'ms':
|
||||||
# The 'ms_struct' attribute only works on x86 and PowerPC
|
# The 'ms_struct' attribute only works on x86 and PowerPC
|
||||||
requires.add(
|
requires.add(
|
||||||
'defined(MS_WIN32) || ('
|
'defined(MS_WIN32) || ('
|
||||||
|
|
|
@ -81,6 +81,7 @@ class Point(Structure):
|
||||||
|
|
||||||
class PackedPoint(Structure):
|
class PackedPoint(Structure):
|
||||||
_pack_ = 2
|
_pack_ = 2
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("x", c_long), ("y", c_long)]
|
_fields_ = [("x", c_long), ("y", c_long)]
|
||||||
|
|
||||||
class PointMidPad(Structure):
|
class PointMidPad(Structure):
|
||||||
|
@ -88,6 +89,7 @@ class PointMidPad(Structure):
|
||||||
|
|
||||||
class PackedPointMidPad(Structure):
|
class PackedPointMidPad(Structure):
|
||||||
_pack_ = 2
|
_pack_ = 2
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("x", c_byte), ("y", c_uint64)]
|
_fields_ = [("x", c_byte), ("y", c_uint64)]
|
||||||
|
|
||||||
class PointEndPad(Structure):
|
class PointEndPad(Structure):
|
||||||
|
@ -95,6 +97,7 @@ class PointEndPad(Structure):
|
||||||
|
|
||||||
class PackedPointEndPad(Structure):
|
class PackedPointEndPad(Structure):
|
||||||
_pack_ = 2
|
_pack_ = 2
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("x", c_uint64), ("y", c_byte)]
|
_fields_ = [("x", c_uint64), ("y", c_byte)]
|
||||||
|
|
||||||
class Point2(Structure):
|
class Point2(Structure):
|
||||||
|
|
|
@ -11,6 +11,8 @@ from ._support import (_CData, PyCStructType, UnionType,
|
||||||
Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
||||||
Py_TPFLAGS_IMMUTABLETYPE)
|
Py_TPFLAGS_IMMUTABLETYPE)
|
||||||
from struct import calcsize
|
from struct import calcsize
|
||||||
|
import contextlib
|
||||||
|
from test.support import MS_WINDOWS
|
||||||
|
|
||||||
|
|
||||||
class StructUnionTestBase:
|
class StructUnionTestBase:
|
||||||
|
@ -335,6 +337,22 @@ class StructUnionTestBase:
|
||||||
self.assertIn("from_address", dir(type(self.cls)))
|
self.assertIn("from_address", dir(type(self.cls)))
|
||||||
self.assertIn("in_dll", dir(type(self.cls)))
|
self.assertIn("in_dll", dir(type(self.cls)))
|
||||||
|
|
||||||
|
def test_pack_layout_switch(self):
|
||||||
|
# Setting _pack_ implicitly sets default layout to MSVC;
|
||||||
|
# this is deprecated on non-Windows platforms.
|
||||||
|
if MS_WINDOWS:
|
||||||
|
warn_context = contextlib.nullcontext()
|
||||||
|
else:
|
||||||
|
warn_context = self.assertWarns(DeprecationWarning)
|
||||||
|
with warn_context:
|
||||||
|
class X(self.cls):
|
||||||
|
_pack_ = 1
|
||||||
|
# _layout_ missing
|
||||||
|
_fields_ = [('a', c_int8, 1), ('b', c_int16, 2)]
|
||||||
|
|
||||||
|
# Check MSVC layout (bitfields of different types aren't combined)
|
||||||
|
self.check_sizeof(X, struct_size=3, union_size=2)
|
||||||
|
|
||||||
|
|
||||||
class StructureTestCase(unittest.TestCase, StructUnionTestBase):
|
class StructureTestCase(unittest.TestCase, StructUnionTestBase):
|
||||||
cls = Structure
|
cls = Structure
|
||||||
|
|
|
@ -25,6 +25,7 @@ class StructureTestCase(unittest.TestCase, StructCheckMixin):
|
||||||
_fields_ = [("a", c_byte),
|
_fields_ = [("a", c_byte),
|
||||||
("b", c_longlong)]
|
("b", c_longlong)]
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
self.check_struct(X)
|
self.check_struct(X)
|
||||||
|
|
||||||
self.assertEqual(sizeof(X), 9)
|
self.assertEqual(sizeof(X), 9)
|
||||||
|
@ -34,6 +35,7 @@ class StructureTestCase(unittest.TestCase, StructCheckMixin):
|
||||||
_fields_ = [("a", c_byte),
|
_fields_ = [("a", c_byte),
|
||||||
("b", c_longlong)]
|
("b", c_longlong)]
|
||||||
_pack_ = 2
|
_pack_ = 2
|
||||||
|
_layout_ = 'ms'
|
||||||
self.check_struct(X)
|
self.check_struct(X)
|
||||||
self.assertEqual(sizeof(X), 10)
|
self.assertEqual(sizeof(X), 10)
|
||||||
self.assertEqual(X.b.offset, 2)
|
self.assertEqual(X.b.offset, 2)
|
||||||
|
@ -45,6 +47,7 @@ class StructureTestCase(unittest.TestCase, StructCheckMixin):
|
||||||
_fields_ = [("a", c_byte),
|
_fields_ = [("a", c_byte),
|
||||||
("b", c_longlong)]
|
("b", c_longlong)]
|
||||||
_pack_ = 4
|
_pack_ = 4
|
||||||
|
_layout_ = 'ms'
|
||||||
self.check_struct(X)
|
self.check_struct(X)
|
||||||
self.assertEqual(sizeof(X), min(4, longlong_align) + longlong_size)
|
self.assertEqual(sizeof(X), min(4, longlong_align) + longlong_size)
|
||||||
self.assertEqual(X.b.offset, min(4, longlong_align))
|
self.assertEqual(X.b.offset, min(4, longlong_align))
|
||||||
|
@ -53,27 +56,33 @@ class StructureTestCase(unittest.TestCase, StructCheckMixin):
|
||||||
_fields_ = [("a", c_byte),
|
_fields_ = [("a", c_byte),
|
||||||
("b", c_longlong)]
|
("b", c_longlong)]
|
||||||
_pack_ = 8
|
_pack_ = 8
|
||||||
|
_layout_ = 'ms'
|
||||||
self.check_struct(X)
|
self.check_struct(X)
|
||||||
|
|
||||||
self.assertEqual(sizeof(X), min(8, longlong_align) + longlong_size)
|
self.assertEqual(sizeof(X), min(8, longlong_align) + longlong_size)
|
||||||
self.assertEqual(X.b.offset, min(8, longlong_align))
|
self.assertEqual(X.b.offset, min(8, longlong_align))
|
||||||
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
d = {"_fields_": [("a", "b"),
|
class X(Structure):
|
||||||
("b", "q")],
|
_fields_ = [("a", "b"), ("b", "q")]
|
||||||
"_pack_": -1}
|
_pack_ = -1
|
||||||
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
|
_layout_ = "ms"
|
||||||
|
|
||||||
@support.cpython_only
|
@support.cpython_only
|
||||||
def test_packed_c_limits(self):
|
def test_packed_c_limits(self):
|
||||||
# Issue 15989
|
# Issue 15989
|
||||||
import _testcapi
|
import _testcapi
|
||||||
d = {"_fields_": [("a", c_byte)],
|
with self.assertRaises(ValueError):
|
||||||
"_pack_": _testcapi.INT_MAX + 1}
|
class X(Structure):
|
||||||
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
|
_fields_ = [("a", c_byte)]
|
||||||
d = {"_fields_": [("a", c_byte)],
|
_pack_ = _testcapi.INT_MAX + 1
|
||||||
"_pack_": _testcapi.UINT_MAX + 2}
|
_layout_ = "ms"
|
||||||
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_byte)]
|
||||||
|
_pack_ = _testcapi.UINT_MAX + 2
|
||||||
|
_layout_ = "ms"
|
||||||
|
|
||||||
def test_initializers(self):
|
def test_initializers(self):
|
||||||
class Person(Structure):
|
class Person(Structure):
|
||||||
|
|
|
@ -19,10 +19,12 @@ for typ in [c_short, c_int, c_long, c_longlong,
|
||||||
c_ushort, c_uint, c_ulong, c_ulonglong]:
|
c_ushort, c_uint, c_ulong, c_ulonglong]:
|
||||||
class X(Structure):
|
class X(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("pad", c_byte),
|
_fields_ = [("pad", c_byte),
|
||||||
("value", typ)]
|
("value", typ)]
|
||||||
class Y(SwappedStructure):
|
class Y(SwappedStructure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
|
_layout_ = 'ms'
|
||||||
_fields_ = [("pad", c_byte),
|
_fields_ = [("pad", c_byte),
|
||||||
("value", typ)]
|
("value", typ)]
|
||||||
structures.append(X)
|
structures.append(X)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
On non-Windows platforms, deprecate using :attr:`ctypes.Structure._pack_` to
|
||||||
|
use a Windows-compatible layout on non-Windows platforms. The layout should
|
||||||
|
be specified explicitly by setting :attr:`ctypes.Structure._layout_` to
|
||||||
|
``'ms'``.
|
Loading…
Add table
Add a link
Reference in a new issue