Issue #24254: Preserve class attribute definition order.
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 7741a79..486f445 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -16,8 +16,10 @@
 import types
 import unittest
 import warnings
+from collections import OrderedDict
 from operator import neg
-from test.support import TESTFN, unlink,  run_unittest, check_warnings
+from test.support import (TESTFN, unlink,  run_unittest, check_warnings,
+                          cpython_only)
 from test.support.script_helper import assert_python_ok
 try:
     import pty, signal
@@ -1778,6 +1780,194 @@
             A.__doc__ = doc
             self.assertEqual(A.__doc__, doc)
 
+    def test_type_definition_order_nonempty(self):
+        class Spam:
+            b = 1
+            c = 3
+            a = 2
+            d = 4
+            eggs = 2
+            e = 5
+            b = 42
+
+        self.assertEqual(Spam.__definition_order__,
+                         ('__module__', '__qualname__',
+                          'b', 'c', 'a', 'd', 'eggs', 'e'))
+
+    def test_type_definition_order_empty(self):
+        class Empty:
+            pass
+
+        self.assertEqual(Empty.__definition_order__,
+                         ('__module__', '__qualname__'))
+
+    def test_type_definition_order_on_instance(self):
+        class Spam:
+            a = 2
+            b = 1
+            c = 3
+        with self.assertRaises(AttributeError):
+            Spam().__definition_order__
+
+    def test_type_definition_order_set_to_None(self):
+        class Spam:
+            a = 2
+            b = 1
+            c = 3
+        Spam.__definition_order__ = None
+        self.assertEqual(Spam.__definition_order__, None)
+
+    def test_type_definition_order_set_to_tuple(self):
+        class Spam:
+            a = 2
+            b = 1
+            c = 3
+        Spam.__definition_order__ = ('x', 'y', 'z')
+        self.assertEqual(Spam.__definition_order__, ('x', 'y', 'z'))
+
+    def test_type_definition_order_deleted(self):
+        class Spam:
+            a = 2
+            b = 1
+            c = 3
+        del Spam.__definition_order__
+        self.assertEqual(Spam.__definition_order__, None)
+
+    def test_type_definition_order_set_to_bad_type(self):
+        class Spam:
+            a = 2
+            b = 1
+            c = 3
+        Spam.__definition_order__ = 42
+        self.assertEqual(Spam.__definition_order__, 42)
+
+    def test_type_definition_order_builtins(self):
+        self.assertEqual(object.__definition_order__, None)
+        self.assertEqual(type.__definition_order__, None)
+        self.assertEqual(dict.__definition_order__, None)
+        self.assertEqual(type(None).__definition_order__, None)
+
+    def test_type_definition_order_dunder_names_included(self):
+        class Dunder:
+            VAR = 3
+            def __init__(self):
+                pass
+
+        self.assertEqual(Dunder.__definition_order__,
+                         ('__module__', '__qualname__',
+                          'VAR', '__init__'))
+
+    def test_type_definition_order_only_dunder_names(self):
+        class DunderOnly:
+            __xyz__ = None
+            def __init__(self):
+                pass
+
+        self.assertEqual(DunderOnly.__definition_order__,
+                         ('__module__', '__qualname__',
+                          '__xyz__', '__init__'))
+
+    def test_type_definition_order_underscore_names(self):
+        class HalfDunder:
+            __whether_to_be = True
+            or_not_to_be__ = False
+
+        self.assertEqual(HalfDunder.__definition_order__,
+                         ('__module__', '__qualname__',
+                          '_HalfDunder__whether_to_be', 'or_not_to_be__'))
+
+    def test_type_definition_order_with_slots(self):
+        class Slots:
+            __slots__ = ('x', 'y')
+            a = 1
+            b = 2
+
+        self.assertEqual(Slots.__definition_order__,
+                         ('__module__', '__qualname__',
+                          '__slots__', 'a', 'b'))
+
+    def test_type_definition_order_overwritten_None(self):
+        class OverwrittenNone:
+            __definition_order__ = None
+            a = 1
+            b = 2
+            c = 3
+
+        self.assertEqual(OverwrittenNone.__definition_order__, None)
+
+    def test_type_definition_order_overwritten_tuple(self):
+        class OverwrittenTuple:
+            __definition_order__ = ('x', 'y', 'z')
+            a = 1
+            b = 2
+            c = 3
+
+        self.assertEqual(OverwrittenTuple.__definition_order__,
+                         ('x', 'y', 'z'))
+
+    def test_type_definition_order_overwritten_bad_item(self):
+        with self.assertRaises(TypeError):
+            class PoorlyOverwritten:
+                __definition_order__ = ('a', 2, 'c')
+                a = 1
+                b = 2
+                c = 3
+
+    def test_type_definition_order_overwritten_bad_type(self):
+        with self.assertRaises(TypeError):
+            class PoorlyOverwritten:
+                __definition_order__ = ['a', 2, 'c']
+                a = 1
+                b = 2
+                c = 3
+
+    def test_type_definition_order_metaclass(self):
+        class Meta(type):
+            SPAM = 42
+
+            def __init__(self, *args, **kwargs):
+                super().__init__(*args, **kwargs)
+
+        self.assertEqual(Meta.__definition_order__,
+                         ('__module__', '__qualname__',
+                          'SPAM', '__init__'))
+
+    def test_type_definition_order_OrderedDict(self):
+        class Meta(type):
+            def __prepare__(self, *args, **kwargs):
+                return OrderedDict()
+
+        class WithODict(metaclass=Meta):
+            x='y'
+
+        self.assertEqual(WithODict.__definition_order__,
+                         ('__module__', '__qualname__', 'x'))
+
+        class Meta(type):
+            def __prepare__(self, *args, **kwargs):
+                class ODictSub(OrderedDict):
+                    pass
+                return ODictSub()
+
+        class WithODictSub(metaclass=Meta):
+            x='y'
+
+        self.assertEqual(WithODictSub.__definition_order__,
+                         ('__module__', '__qualname__', 'x'))
+
+    @cpython_only
+    def test_type_definition_order_cpython(self):
+        # some implementations will have an ordered-by-default dict.
+
+        class Meta(type):
+            def __prepare__(self, *args, **kwargs):
+                return {}
+
+        class NotOrdered(metaclass=Meta):
+            x='y'
+
+        self.assertEqual(NotOrdered.__definition_order__, None)
+
     def test_bad_args(self):
         with self.assertRaises(TypeError):
             type()