Nextgen Proto Pythonic API: Struct/ListValue assignment and creation

Python dict is now able to be assigned (by create and copy, not reference) and compared with the Protobuf Struct field.
Python list is now able to be assigned (by create and copy, not reference) and compared with the Protobuf ListValue field.

example usage:
  dictionary = {'key1': 5.0, 'key2': {'subkey': 11.0, 'k': False},}
  list_value = [6, 'seven', True, False, None, dictionary]
  msg = more_messages_pb2.WKTMessage(
      optional_struct=dictionary, optional_list_value=list_value
  )
  self.assertEqual(msg.optional_struct, dictionary)
  self.assertEqual(msg.optional_list_value, list_value)

PiperOrigin-RevId: 646099987
diff --git a/python/message.c b/python/message.c
index 719f858..c81b43b 100644
--- a/python/message.c
+++ b/python/message.c
@@ -432,6 +432,8 @@
   return ok;
 }
 
+static PyObject* PyUpb_Message_Clear(PyUpb_Message* self);
+
 static bool PyUpb_Message_InitMessageAttribute(PyObject* _self, PyObject* name,
                                                const upb_FieldDef* field,
                                                PyObject* value) {
@@ -445,25 +447,31 @@
     Py_XDECREF(tmp);
   } else if (PyDict_Check(value)) {
     assert(!PyErr_Occurred());
-    ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0;
+    const upb_MessageDef* msgdef = upb_FieldDef_MessageSubDef(field);
+    if (upb_MessageDef_WellKnownType(msgdef) == kUpb_WellKnown_Struct) {
+      ok = PyObject_CallMethod(submsg, "_internal_assign", "O", value);
+      if (!ok && PyDict_Size(value) == 1 &&
+          PyDict_Contains(value, PyUnicode_FromString("fields"))) {
+        // Fall back to init as normal message field.
+        PyErr_Clear();
+        PyObject* tmp = PyUpb_Message_Clear((PyUpb_Message*)submsg);
+        Py_DECREF(tmp);
+        ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0;
+      }
+    } else {
+      ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0;
+    }
   } else {
     const upb_MessageDef* msgdef = upb_FieldDef_MessageSubDef(field);
-    switch (upb_MessageDef_WellKnownType(msgdef)) {
-      case kUpb_WellKnown_Timestamp: {
-        ok = PyObject_CallMethod(submsg, "FromDatetime", "O", value);
-        break;
-      }
-      case kUpb_WellKnown_Duration: {
-        ok = PyObject_CallMethod(submsg, "FromTimedelta", "O", value);
-        break;
-      }
-      default: {
-        const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
-        PyErr_Format(PyExc_TypeError,
-                     "Message must be initialized with a dict: %s",
-                     upb_MessageDef_FullName(m));
-        ok = false;
-      }
+    if (upb_MessageDef_WellKnownType(msgdef) != kUpb_WellKnown_Unspecified &&
+        PyObject_HasAttrString(submsg, "_internal_assign")) {
+      ok = PyObject_CallMethod(submsg, "_internal_assign", "O", value);
+    } else {
+      const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
+      PyErr_Format(PyExc_TypeError,
+                   "Message must be initialized with a dict: %s",
+                   upb_MessageDef_FullName(m));
+      ok = false;
     }
   }
   Py_DECREF(submsg);
@@ -772,6 +780,13 @@
     Py_INCREF(Py_NotImplemented);
     return Py_NotImplemented;
   }
+  const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
+  upb_WellKnown wkt = upb_MessageDef_WellKnownType(msgdef);
+  if ((wkt == kUpb_WellKnown_ListValue && PyList_Check(other)) ||
+      (wkt == kUpb_WellKnown_Struct && PyDict_Check(other))) {
+    return PyObject_CallMethod(_self, "_internal_compare", "O", other);
+  }
+
   if (!PyObject_TypeCheck(other, Py_TYPE(self))) {
     Py_INCREF(Py_NotImplemented);
     return Py_NotImplemented;
@@ -962,30 +977,21 @@
 
   if (upb_FieldDef_IsSubMessage(field)) {
     const upb_MessageDef* msgdef = upb_FieldDef_MessageSubDef(field);
-    switch (upb_MessageDef_WellKnownType(msgdef)) {
-      case kUpb_WellKnown_Timestamp: {
-        PyObject* sub_message = PyUpb_Message_GetFieldValue(_self, field);
+    if (upb_MessageDef_WellKnownType(msgdef) != kUpb_WellKnown_Unspecified) {
+      PyObject* sub_message = PyUpb_Message_GetFieldValue(_self, field);
+      if (PyObject_HasAttrString(sub_message, "_internal_assign")) {
         PyObject* ok =
-            PyObject_CallMethod(sub_message, "FromDatetime", "O", value);
+            PyObject_CallMethod(sub_message, "_internal_assign", "O", value);
         if (!ok) return -1;
         Py_DECREF(ok);
         return 0;
       }
-      case kUpb_WellKnown_Duration: {
-        PyObject* sub_message = PyUpb_Message_GetFieldValue(_self, field);
-        PyObject* ok =
-            PyObject_CallMethod(sub_message, "FromTimedelta", "O", value);
-        if (!ok) return -1;
-        Py_DECREF(ok);
-        return 0;
-      }
-      default:
-        PyErr_Format(exc,
-                     "Assignment not allowed to message "
-                     "field \"%s\" in protocol message object.",
-                     upb_FieldDef_Name(field));
-        return -1;
     }
+    PyErr_Format(exc,
+                 "Assignment not allowed to message "
+                 "field \"%s\" in protocol message object.",
+                 upb_FieldDef_Name(field));
+    return -1;
   }
 
   upb_MessageValue val;
@@ -1272,8 +1278,6 @@
   Py_RETURN_NONE;
 }
 
-static PyObject* PyUpb_Message_Clear(PyUpb_Message* self);
-
 static PyObject* PyUpb_Message_CopyFrom(PyObject* _self, PyObject* arg) {
   if (_self->ob_type != arg->ob_type) {
     PyErr_Format(PyExc_TypeError,