Throw an exception with detailed information if generated code is out of date.

PiperOrigin-RevId: 449249979
diff --git a/python/message.c b/python/message.c
index 5b6bddd..c8430e1 100644
--- a/python/message.c
+++ b/python/message.c
@@ -1075,6 +1075,25 @@
   return PyLong_FromLong(upb_FieldDef_Number(f));
 }
 
+static PyObject* PyUpb_CMessage_CheckCalledFromGeneratedFile(
+    PyObject* unused, PyObject* unused_arg) {
+  PyErr_SetString(
+      PyExc_TypeError,
+      "Descriptors cannot not be created directly.\n"
+      "If this call came from a _pb2.py file, your generated code is out of "
+      "date and must be regenerated with protoc >= 3.19.0.\n"
+      "If you cannot immediately regenerate your protos, some other possible "
+      "workarounds are:\n"
+      " 1. Downgrade the protobuf package to 3.20.x or lower.\n"
+      " 2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will "
+      "use pure-Python parsing and will be much slower).\n"
+      "\n"
+      "More information: "
+      "https://developers.google.com/protocol-buffers/docs/news/"
+      "2022-05-06#python-updates");
+  return NULL;
+}
+
 static bool PyUpb_CMessage_SortFieldList(PyObject* list) {
   PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
   bool ok = false;
@@ -1607,6 +1626,9 @@
     {"_ListFieldsItemKey", PyUpb_CMessage_ListFieldsItemKey,
      METH_O | METH_STATIC,
      "Compares ListFields() list entries by field number"},
+    {"_CheckCalledFromGeneratedFile",
+     PyUpb_CMessage_CheckCalledFromGeneratedFile, METH_NOARGS | METH_STATIC,
+     "Raises TypeError if the caller is not in a _pb2.py file."},
     {NULL, NULL}};
 
 static PyType_Slot PyUpb_CMessage_Slots[] = {