Implemented DescriptorPool methods.
diff --git a/python/descriptor_pool.c b/python/descriptor_pool.c
index 8e95bdf..e48b82c 100644
--- a/python/descriptor_pool.c
+++ b/python/descriptor_pool.c
@@ -28,6 +28,7 @@
 #include "python/descriptor_pool.h"
 
 #include "python/descriptor.h"
+#include "python/message.h"
 #include "python/protobuf.h"
 #include "upb/def.h"
 
@@ -39,6 +40,7 @@
   PyObject_HEAD
   upb_symtab* symtab;
   PyObject* db;
+  PyObject* serialized_pb_dict;
 } PyUpb_DescriptorPool;
 
 PyObject* PyUpb_DescriptorPool_GetDefaultPool() {
@@ -46,12 +48,12 @@
   return s->default_pool;
 }
 
-static PyObject* PyUpb_DescriptorPool_DoCreateWithCache(PyTypeObject* type,
-                                               PyObject* db,
-                                               PyUpb_WeakMap *obj_cache) {
+static PyObject* PyUpb_DescriptorPool_DoCreateWithCache(
+    PyTypeObject* type, PyObject* db, PyUpb_WeakMap* obj_cache) {
   PyUpb_DescriptorPool* pool = (void*)PyType_GenericAlloc(type, 0);
   pool->symtab = upb_symtab_new();
   pool->db = db;
+  pool->serialized_pb_dict = PyDict_New();
   Py_XINCREF(pool->db);
   PyUpb_WeakMap_Add(obj_cache, pool->symtab, &pool->ob_base);
   return &pool->ob_base;
@@ -85,12 +87,19 @@
 }
 
 static void PyUpb_DescriptorPool_Dealloc(PyUpb_DescriptorPool* self) {
-  upb_symtab_free(self->symtab);
   PyUpb_DescriptorPool_Clear(self);
+  Py_DECREF(self->serialized_pb_dict);
+  upb_symtab_free(self->symtab);
   PyUpb_ObjCache_Delete(self->symtab);
   PyUpb_Dealloc(self);
 }
 
+PyObject* PyUpb_DescriptorPool_GetSerializedPb(PyObject* _self,
+                                               const char* filename) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+  return PyDict_GetItemString(self->serialized_pb_dict, filename);
+}
+
 /*
  * DescriptorPool.__new__()
  *
@@ -106,6 +115,7 @@
     return NULL;
   }
 
+  if (db == Py_None) db = NULL;
   return PyUpb_DescriptorPool_DoCreate(type, db);
 }
 
@@ -156,6 +166,9 @@
     goto done;
   }
 
+  PyDict_SetItemString(self->serialized_pb_dict, upb_filedef_name(filedef),
+                       serialized_pb);
+
   result = PyUpb_FileDescriptor_Get(filedef);
 
 done:
@@ -163,6 +176,40 @@
   return result;
 }
 
+static PyObject* PyUpb_DescriptorPool_Add(PyObject* _self,
+                                          PyObject* file_desc) {
+  PyObject* subargs = PyTuple_New(0);
+  // TODO: check file_desc type more.
+  PyObject* serialized =
+      PyUpb_CMessage_SerializeToString(file_desc, subargs, NULL);
+  Py_DECREF(subargs);
+  if (!serialized) return NULL;
+  PyObject* ret = PyUpb_DescriptorPool_AddSerializedFile(_self, serialized);
+  Py_DECREF(serialized);
+  return ret;
+}
+
+/*
+ * PyUpb_DescriptorPool_FindFileByName()
+ *
+ * Implements:
+ *   DescriptorPool.FindFileByName(self, name)
+ */
+static PyObject* PyUpb_DescriptorPool_FindFileByName(PyObject* _self,
+                                                     PyObject* arg) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+  const char* name = PyUpb_GetStrData(arg);
+  if (!name) return NULL;
+
+  const upb_filedef* file = upb_symtab_lookupfile(self->symtab, name);
+  if (file == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s", name);
+  }
+
+  return PyUpb_FileDescriptor_Get(file);
+}
+
 /*
  * PyUpb_DescriptorPool_FindExtensionByName()
  *
@@ -184,40 +231,195 @@
   return PyUpb_FieldDescriptor_Get(field);
 }
 
+/*
+ * PyUpb_DescriptorPool_FindMessageTypeByName()
+ *
+ * Implements:
+ *   DescriptorPool.FindMessageTypeByName(self, name)
+ */
+static PyObject* PyUpb_DescriptorPool_FindMessageTypeByName(PyObject* _self,
+                                                            PyObject* arg) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+  const char* name = PyUpb_GetStrData(arg);
+  if (!name) return NULL;
+
+  const upb_msgdef* m = upb_symtab_lookupmsg(self->symtab, name);
+  if (m == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
+  }
+
+  return PyUpb_Descriptor_Get(m);
+}
+
+/*
+ * PyUpb_DescriptorPool_FindFieldByName()
+ *
+ * Implements:
+ *   DescriptorPool.FindFieldByName(self, name)
+ */
+static PyObject* PyUpb_DescriptorPool_FindFieldByName(PyObject* _self,
+                                                      PyObject* arg) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+  const char* name = PyUpb_GetStrData(arg);
+  if (!name) return NULL;
+
+  const upb_fielddef* f = upb_symtab_lookupext(self->symtab, name);
+  if (!f) {
+    const char* last_dot = strrchr(name, '.');
+    if (last_dot) {
+      const upb_msgdef* parent =
+          upb_symtab_lookupmsg2(self->symtab, name, last_dot - name);
+      if (parent) {
+        f = upb_msgdef_ntofz(parent, last_dot + 1);
+      }
+    }
+  }
+
+  if (!f) {
+    return PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
+  }
+
+  return PyUpb_FieldDescriptor_Get(f);
+}
+
+/*
+ * PyUpb_DescriptorPool_FindEnumTypeByName()
+ *
+ * Implements:
+ *   DescriptorPool.FindEnumTypeByName(self, name)
+ */
+static PyObject* PyUpb_DescriptorPool_FindEnumTypeByName(PyObject* _self,
+                                                         PyObject* arg) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+  const char* name = PyUpb_GetStrData(arg);
+  if (!name) return NULL;
+
+  const upb_enumdef* e = upb_symtab_lookupenum(self->symtab, name);
+  if (e == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
+  }
+
+  return PyUpb_EnumDescriptor_Get(e);
+}
+
+/*
+ * PyUpb_DescriptorPool_FindOneofByName()
+ *
+ * Implements:
+ *   DescriptorPool.FindOneofByName(self, name)
+ */
+static PyObject* PyUpb_DescriptorPool_FindOneofByName(PyObject* _self,
+                                                      PyObject* arg) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+  const char* name = PyUpb_GetStrData(arg);
+  if (!name) return NULL;
+
+  const char* last_dot = strrchr(name, '.');
+  if (last_dot) {
+    const upb_msgdef* parent =
+        upb_symtab_lookupmsg2(self->symtab, name, last_dot - name);
+    if (parent) {
+      const upb_oneofdef* o = upb_msgdef_ntooz(parent, last_dot + 1);
+      return PyUpb_OneofDescriptor_Get(o);
+    }
+  }
+
+  return PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
+}
+
+static PyObject* PyUpb_DescriptorPool_FindServiceByName(PyObject* _self,
+                                                        PyObject* arg) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+  const char* name = PyUpb_GetStrData(arg);
+  if (!name) return NULL;
+
+  const upb_servicedef* s = upb_symtab_lookupservice(self->symtab, name);
+  if (s == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
+  }
+
+  return PyUpb_ServiceDescriptor_Get(s);
+}
+
+static PyObject* PyUpb_DescriptorPool_FindFileContainingSymbol(PyObject* _self,
+                                                               PyObject* arg) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+
+  const char* name = PyUpb_GetStrData(arg);
+  if (!name) return NULL;
+
+  const upb_filedef* f = upb_symtab_lookupfileforsym(self->symtab, name);
+  if (f == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
+  }
+
+  return PyUpb_FileDescriptor_Get(f);
+}
+
+static PyObject* PyUpb_DescriptorPool_FindExtensionByNumber(PyObject* _self,
+                                                            PyObject* args) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+  PyObject* message_descriptor;
+  int number;
+  if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
+    return NULL;
+  }
+
+  const upb_fielddef* f = upb_symtab_lookupextbynum(
+      self->symtab, PyUpb_Descriptor_GetDef(message_descriptor), number);
+  if (f == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
+  }
+
+  return PyUpb_FieldDescriptor_Get(f);
+}
+
+static PyObject* PyUpb_DescriptorPool_FindAllExtensions(PyObject* _self,
+                                                        PyObject* msg_desc) {
+  PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
+  const upb_msgdef* m = PyUpb_Descriptor_GetDef(msg_desc);
+  size_t n;
+  const upb_fielddef** ext = upb_symtab_getallexts(self->symtab, m, &n);
+  PyObject* ret = PyList_New(n);
+  for (size_t i = 0; i < n; i++) {
+    PyObject* field = PyUpb_FieldDescriptor_Get(ext[i]);
+    PyList_SetItem(ret, i, field);
+  }
+  return ret;
+}
+
 static PyMethodDef PyUpb_DescriptorPool_Methods[] = {
-    /*
-      TODO: implement remaining methods.
-    { "Add", Add, METH_O,
-      "Adds the FileDescriptorProto and its types to this pool." },
-      */
+    {"Add", PyUpb_DescriptorPool_Add, METH_O,
+     "Adds the FileDescriptorProto and its types to this pool."},
     {"AddSerializedFile", PyUpb_DescriptorPool_AddSerializedFile, METH_O,
      "Adds a serialized FileDescriptorProto to this pool."},
-    /*
-    { "FindFileByName", FindFileByName, METH_O,
-      "Searches for a file descriptor by its .proto name." },
-    { "FindMessageTypeByName", FindMessageByName, METH_O,
-      "Searches for a message descriptor by full name." },
-    { "FindFieldByName", FindFieldByNameMethod, METH_O,
-      "Searches for a field descriptor by full name." },
-      */
+    {"FindFileByName", PyUpb_DescriptorPool_FindFileByName, METH_O,
+     "Searches for a file descriptor by its .proto name."},
+    {"FindMessageTypeByName", PyUpb_DescriptorPool_FindMessageTypeByName,
+     METH_O, "Searches for a message descriptor by full name."},
+    {"FindFieldByName", PyUpb_DescriptorPool_FindFieldByName, METH_O,
+     "Searches for a field descriptor by full name."},
     {"FindExtensionByName", PyUpb_DescriptorPool_FindExtensionByName, METH_O,
      "Searches for extension descriptor by full name."},
-    /*
-    { "FindEnumTypeByName", FindEnumTypeByNameMethod, METH_O,
-      "Searches for enum type descriptor by full name." },
-    { "FindOneofByName", FindOneofByNameMethod, METH_O,
-      "Searches for oneof descriptor by full name." },
-    { "FindServiceByName", FindServiceByName, METH_O,
-      "Searches for service descriptor by full name." },
-    { "FindMethodByName", FindMethodByName, METH_O,
-      "Searches for method descriptor by full name." },
-    { "FindFileContainingSymbol", FindFileContainingSymbol, METH_O,
-      "Gets the FileDescriptor containing the specified symbol." },
-    { "FindExtensionByNumber", FindExtensionByNumber, METH_VARARGS,
-      "Gets the extension descriptor for the given number." },
-    { "FindAllExtensions", FindAllExtensions, METH_O,
-      "Gets all known extensions of the given message descriptor." },
-    */
+    {"FindEnumTypeByName", PyUpb_DescriptorPool_FindEnumTypeByName, METH_O,
+     "Searches for enum type descriptor by full name."},
+    {"FindOneofByName", PyUpb_DescriptorPool_FindOneofByName, METH_O,
+     "Searches for oneof descriptor by full name."},
+    {"FindServiceByName", PyUpb_DescriptorPool_FindServiceByName, METH_O,
+     "Searches for service descriptor by full name."},
+    //{ "Find, PyUpb_DescriptorPool_Find, METH_O,
+    //  "Searches for method descriptor by full name." },
+    {"FindFileContainingSymbol", PyUpb_DescriptorPool_FindFileContainingSymbol,
+     METH_O, "Gets the FileDescriptor containing the specified symbol."},
+    {"FindExtensionByNumber", PyUpb_DescriptorPool_FindExtensionByNumber,
+     METH_VARARGS, "Gets the extension descriptor for the given number."},
+    {"FindAllExtensions", PyUpb_DescriptorPool_FindAllExtensions, METH_O,
+     "Gets all known extensions of the given message descriptor."},
     {NULL}};
 
 static PyType_Slot PyUpb_DescriptorPool_Slots[] = {
@@ -241,9 +443,9 @@
 // -----------------------------------------------------------------------------
 
 bool PyUpb_InitDescriptorPool(PyObject* m) {
-  PyUpb_ModuleState *state = PyUpb_ModuleState_GetFromModule(m);
+  PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
   PyTypeObject* descriptor_pool_type =
-      AddObject(m, "DescriptorPool", &PyUpb_DescriptorPool_Spec);
+      PyUpb_AddClass(m, &PyUpb_DescriptorPool_Spec);
 
   if (!descriptor_pool_type) return false;