Close #4376: ctypes now supports nested structures in a endian different than
the parent structure. Patch by Vlad Riscutia.
diff --git a/Lib/ctypes/_endian.py b/Lib/ctypes/_endian.py
index 6de0d47..e6b8556 100644
--- a/Lib/ctypes/_endian.py
+++ b/Lib/ctypes/_endian.py
@@ -10,14 +10,18 @@
     """Return the type with the 'other' byte order.  Simple types like
     c_int and so on already have __ctype_be__ and __ctype_le__
     attributes which contain the types, for more complicated types
-    only arrays are supported.
+    arrays and structures are supported.
     """
-    try:
+    # check _OTHER_ENDIAN attribute (present if typ is primitive type)
+    if hasattr(typ, _OTHER_ENDIAN):
         return getattr(typ, _OTHER_ENDIAN)
-    except AttributeError:
-        if type(typ) == _array_type:
-            return _other_endian(typ._type_) * typ._length_
-        raise TypeError("This type does not support other endian: %s" % typ)
+    # if typ is array
+    if isinstance(typ, _array_type):
+        return _other_endian(typ._type_) * typ._length_
+    # if typ is structure
+    if issubclass(typ, Structure):
+        return typ
+    raise TypeError("This type does not support other endian: %s" % typ)
 
 class _swapped_meta(type(Structure)):
     def __setattr__(self, attrname, value):
diff --git a/Lib/ctypes/test/test_byteswap.py b/Lib/ctypes/test/test_byteswap.py
index 3163756..895c660 100644
--- a/Lib/ctypes/test/test_byteswap.py
+++ b/Lib/ctypes/test/test_byteswap.py
@@ -185,18 +185,32 @@
             self.assertRaises(TypeError, setattr, T, "_fields_", [("x", typ)])
 
     def test_struct_struct(self):
-        # Nested structures with different byte order not (yet) supported
-        if sys.byteorder == "little":
-            base = BigEndianStructure
-        else:
-            base = LittleEndianStructure
+        # nested structures with different byteorders
 
-        class T(Structure):
-            _fields_ = [("a", c_int),
-                        ("b", c_int)]
-        class S(base):
-            pass
-        self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)])
+        # create nested structures with given byteorders and set memory to data
+        def set_structures(endianness, nested_endianness, data):
+            class NestedStructure(nested_endianness):
+                _fields_ = [("x", c_uint32),
+                            ("y", c_uint32)]
+
+            class TestStructure(endianness):
+                _fields_ = [("point", NestedStructure)]
+
+            self.assertEqual(len(data), sizeof(TestStructure))
+            return cast(data, POINTER(TestStructure))[0]
+
+        for nested, data in (
+            (BigEndianStructure, b'\0\0\0\1\0\0\0\2'),
+            (LittleEndianStructure, b'\1\0\0\0\2\0\0\0'),
+        ):
+            for parent in (
+                BigEndianStructure,
+                LittleEndianStructure,
+                Structure,
+            ):
+                s = set_structures(parent, nested, data)
+                self.assertEqual(s.point.x, 1)
+                self.assertEqual(s.point.y, 2)
 
     def test_struct_fields_2(self):
         # standard packing in struct uses no alignment.
diff --git a/Misc/ACKS b/Misc/ACKS
index 665f71f..f7f5a34 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -685,6 +685,7 @@
 Armin Rigo
 Nicholas Riley
 Jean-Claude Rimbault
+Vlad Riscutia
 Juan M. Bello Rivas
 Davide Rizzo
 Anthony Roach
diff --git a/Misc/NEWS b/Misc/NEWS
index 4aa48ae..b282c13 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -30,6 +30,9 @@
 Library
 -------
 
+- Issue #4376: ctypes now supports nested structures in a endian different than
+  the parent structure. Patch by Vlad Riscutia.
+
 - Issue #12493: subprocess: Popen.communicate() now also handles EINTR errors
   if the process has only one pipe.