Breaking Change: Python setdefault behavior change for map field.
  -setdefault will be similar with dict for ScalarMap. But both key and value must be set.
  -setdefault will be rejected for MessageMap.

PiperOrigin-RevId: 695768629
diff --git a/python/map.c b/python/map.c
index 1e2b380..4fe7c19 100644
--- a/python/map.c
+++ b/python/map.c
@@ -217,6 +217,48 @@
   Py_RETURN_NONE;
 }
 
+static PyObject* PyUpb_ScalarMapContainer_Setdefault(PyObject* _self,
+                                                     PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = Py_None;
+
+  if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &default_value)) {
+    return NULL;
+  }
+
+  if (default_value == Py_None) {
+    PyErr_Format(PyExc_ValueError,
+                 "The value for scalar map setdefault must be set.");
+    return NULL;
+  }
+
+  PyUpb_MapContainer* self = (PyUpb_MapContainer*)_self;
+  upb_Map* map = PyUpb_MapContainer_EnsureReified(_self);
+  const upb_FieldDef* f = PyUpb_MapContainer_GetField(self);
+  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f);
+  const upb_FieldDef* key_f = upb_MessageDef_Field(entry_m, 0);
+  const upb_FieldDef* val_f = upb_MessageDef_Field(entry_m, 1);
+  upb_MessageValue u_key, u_val;
+  if (!PyUpb_PyToUpb(key, key_f, &u_key, NULL)) return NULL;
+  if (upb_Map_Get(map, u_key, &u_val)) {
+    return PyUpb_UpbToPy(u_val, val_f, self->arena);
+  }
+
+  upb_Arena* arena = PyUpb_Arena_Get(self->arena);
+  if (!PyUpb_PyToUpb(default_value, val_f, &u_val, arena)) return NULL;
+  if (!PyUpb_MapContainer_Set(self, map, u_key, u_val, arena)) return NULL;
+
+  Py_INCREF(default_value);
+  return default_value;
+}
+
+static PyObject* PyUpb_MessageMapContainer_Setdefault(PyObject* self,
+                                                      PyObject* args) {
+  PyErr_Format(PyExc_NotImplementedError,
+               "Set message map value directly is not supported.");
+  return NULL;
+}
+
 static PyObject* PyUpb_MapContainer_Get(PyObject* _self, PyObject* args,
                                         PyObject* kwargs) {
   PyUpb_MapContainer* self = (PyUpb_MapContainer*)_self;
@@ -331,6 +373,9 @@
 static PyMethodDef PyUpb_ScalarMapContainer_Methods[] = {
     {"clear", PyUpb_MapContainer_Clear, METH_NOARGS,
      "Removes all elements from the map."},
+    {"setdefault", (PyCFunction)PyUpb_ScalarMapContainer_Setdefault,
+     METH_VARARGS,
+     "If the key does not exist, insert the key, with the specified value"},
     {"get", (PyCFunction)PyUpb_MapContainer_Get, METH_VARARGS | METH_KEYWORDS,
      "Gets the value for the given key if present, or otherwise a default"},
     {"GetEntryClass", PyUpb_MapContainer_GetEntryClass, METH_NOARGS,
@@ -373,6 +418,8 @@
 static PyMethodDef PyUpb_MessageMapContainer_Methods[] = {
     {"clear", PyUpb_MapContainer_Clear, METH_NOARGS,
      "Removes all elements from the map."},
+    {"setdefault", (PyCFunction)PyUpb_MessageMapContainer_Setdefault,
+     METH_VARARGS, "setdefault is disallowed in MessageMap."},
     {"get", (PyCFunction)PyUpb_MapContainer_Get, METH_VARARGS | METH_KEYWORDS,
      "Gets the value for the given key if present, or otherwise a default"},
     {"get_or_create", PyUpb_MapContainer_Subscript, METH_O,
@@ -480,8 +527,8 @@
   PyObject* base = GetMutableMappingBase();
   if (!base) return false;
 
-  const char* methods[] = {"keys", "items",   "values", "__eq__",     "__ne__",
-                           "pop",  "popitem", "update", "setdefault", NULL};
+  const char* methods[] = {"keys", "items",   "values", "__eq__", "__ne__",
+                           "pop",  "popitem", "update", NULL};
 
   state->message_map_container_type = PyUpb_AddClassWithRegister(
       m, &PyUpb_MessageMapContainer_Spec, base, methods);