diff options
author | Jisi Liu <jisi.liu@gmail.com> | 2015-10-05 11:59:43 -0700 |
---|---|---|
committer | Jisi Liu <jisi.liu@gmail.com> | 2015-10-05 11:59:43 -0700 |
commit | 46e8ff63cb67a6520711da5317aaaef04d0414d0 (patch) | |
tree | 64370726fe469f8dfca7b14f8b8cb80b6cc856f6 /python/google/protobuf/pyext | |
parent | 0087da9d4775f79c67362cc89c653f3a33a9bae2 (diff) | |
download | protobuf-46e8ff63cb67a6520711da5317aaaef04d0414d0.tar.gz protobuf-46e8ff63cb67a6520711da5317aaaef04d0414d0.tar.bz2 protobuf-46e8ff63cb67a6520711da5317aaaef04d0414d0.zip |
Down-integrate from google internal.
Diffstat (limited to 'python/google/protobuf/pyext')
-rw-r--r-- | python/google/protobuf/pyext/descriptor.cc | 41 | ||||
-rw-r--r-- | python/google/protobuf/pyext/descriptor.h | 2 | ||||
-rw-r--r-- | python/google/protobuf/pyext/descriptor_containers.cc | 88 | ||||
-rw-r--r-- | python/google/protobuf/pyext/descriptor_containers.h | 1 | ||||
-rw-r--r-- | python/google/protobuf/pyext/descriptor_pool.cc | 112 | ||||
-rw-r--r-- | python/google/protobuf/pyext/descriptor_pool.h | 15 | ||||
-rw-r--r-- | python/google/protobuf/pyext/extension_dict.cc | 3 | ||||
-rw-r--r-- | python/google/protobuf/pyext/message.cc | 153 | ||||
-rw-r--r-- | python/google/protobuf/pyext/message.h | 13 |
9 files changed, 337 insertions, 91 deletions
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc index 3806643f..b238fd02 100644 --- a/python/google/protobuf/pyext/descriptor.cc +++ b/python/google/protobuf/pyext/descriptor.cc @@ -223,8 +223,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) { options.SerializeToString(&serialized); io::CodedInputStream input( reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size()); - input.SetExtensionRegistry(pool->pool, - GetDescriptorPool()->message_factory); + input.SetExtensionRegistry(pool->pool, pool->message_factory); bool success = cmsg->message->MergePartialFromCodedStream(&input); if (!success) { PyErr_Format(PyExc_ValueError, "Error parsing Options message"); @@ -414,8 +413,14 @@ static PyObject* GetFile(PyBaseDescriptor *self, void *closure) { } static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) { + // Retuns the canonical class for the given descriptor. + // This is the class that was registered with the primary descriptor pool + // which contains this descriptor. + // This might not be the one you expect! For example the returned object does + // not know about extensions defined in a custom pool. PyObject* concrete_class(cdescriptor_pool::GetMessageClass( - GetDescriptorPool(), _GetDescriptor(self))); + GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()), + _GetDescriptor(self))); Py_XINCREF(concrete_class); return concrete_class; } @@ -424,6 +429,11 @@ static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) { return NewMessageFieldsByName(_GetDescriptor(self)); } +static PyObject* GetFieldsByCamelcaseName(PyBaseDescriptor* self, + void *closure) { + return NewMessageFieldsByCamelcaseName(_GetDescriptor(self)); +} + static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) { return NewMessageFieldsByNumber(_GetDescriptor(self)); } @@ -564,6 +574,8 @@ static PyGetSetDef Getters[] = { { "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"}, { "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"}, + { "fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, NULL, + "Fields by camelCase name"}, { "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"}, { "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"}, { "nested_types_by_name", (getter)GetNestedTypesByName, NULL, @@ -662,6 +674,10 @@ static PyObject* GetName(PyBaseDescriptor *self, void *closure) { return PyString_FromCppString(_GetDescriptor(self)->name()); } +static PyObject* GetCamelcaseName(PyBaseDescriptor* self, void *closure) { + return PyString_FromCppString(_GetDescriptor(self)->camelcase_name()); +} + static PyObject* GetType(PyBaseDescriptor *self, void *closure) { return PyInt_FromLong(_GetDescriptor(self)->type()); } @@ -850,6 +866,7 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value, static PyGetSetDef Getters[] = { { "full_name", (getter)GetFullName, NULL, "Full name"}, { "name", (getter)GetName, NULL, "Unqualified name"}, + { "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"}, { "type", (getter)GetType, NULL, "C++ Type"}, { "cpp_type", (getter)GetCppType, NULL, "C++ Type"}, { "label", (getter)GetLabel, NULL, "Label"}, @@ -1070,6 +1087,15 @@ PyObject* PyEnumDescriptor_FromDescriptor( &PyEnumDescriptor_Type, enum_descriptor, NULL); } +const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) { + if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) { + PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor"); + return NULL; + } + return reinterpret_cast<const EnumDescriptor*>( + reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor); +} + namespace enumvalue_descriptor { // Unchecked accessor to the C++ pointer. @@ -1359,6 +1385,15 @@ PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb( return py_descriptor; } +const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) { + if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) { + PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor"); + return NULL; + } + return reinterpret_cast<const FileDescriptor*>( + reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor); +} + namespace oneof_descriptor { // Unchecked accessor to the C++ pointer. diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h index b2550406..eb99df18 100644 --- a/python/google/protobuf/pyext/descriptor.h +++ b/python/google/protobuf/pyext/descriptor.h @@ -72,6 +72,8 @@ PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb( // exception set. const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj); const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj); +const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj); +const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj); // Returns the raw C++ pointer. const void* PyDescriptor_AsVoidPtr(PyObject* obj); diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc index 92e11e31..b20f5e4f 100644 --- a/python/google/protobuf/pyext/descriptor_containers.cc +++ b/python/google/protobuf/pyext/descriptor_containers.cc @@ -79,9 +79,12 @@ struct PyContainer; typedef int (*CountMethod)(PyContainer* self); typedef const void* (*GetByIndexMethod)(PyContainer* self, int index); typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name); +typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self, + const string& name); typedef const void* (*GetByNumberMethod)(PyContainer* self, int index); typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor); typedef const string& (*GetItemNameMethod)(const void* descriptor); +typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor); typedef int (*GetItemNumberMethod)(const void* descriptor); typedef int (*GetItemIndexMethod)(const void* descriptor); @@ -95,6 +98,9 @@ struct DescriptorContainerDef { // Retrieve item by name (usually a call to some 'FindByName' method). // Used by "by_name" mappings. GetByNameMethod get_by_name_fn; + // Retrieve item by camelcase name (usually a call to some + // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings. + GetByCamelcaseNameMethod get_by_camelcase_name_fn; // Retrieve item by declared number (field tag, or enum value). // Used by "by_number" mappings. GetByNumberMethod get_by_number_fn; @@ -102,6 +108,9 @@ struct DescriptorContainerDef { NewObjectFromItemMethod new_object_from_item_fn; // Retrieve the name of an item. Used by iterators on "by_name" mappings. GetItemNameMethod get_item_name_fn; + // Retrieve the camelcase name of an item. Used by iterators on + // "by_camelcase_name" mappings. + GetItemCamelcaseNameMethod get_item_camelcase_name_fn; // Retrieve the number of an item. Used by iterators on "by_number" mappings. GetItemNumberMethod get_item_number_fn; // Retrieve the index of an item for the container type. @@ -125,6 +134,7 @@ struct PyContainer { enum ContainerKind { KIND_SEQUENCE, KIND_BYNAME, + KIND_BYCAMELCASENAME, KIND_BYNUMBER, } kind; }; @@ -172,6 +182,23 @@ static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) { self, string(name, name_size)); return true; } + case PyContainer::KIND_BYCAMELCASENAME: + { + char* camelcase_name; + Py_ssize_t name_size; + if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + // Not a string, cannot be in the container. + PyErr_Clear(); + *item = NULL; + return true; + } + return false; + } + *item = self->container_def->get_by_camelcase_name_fn( + self, string(camelcase_name, name_size)); + return true; + } case PyContainer::KIND_BYNUMBER: { Py_ssize_t number = PyNumber_AsSsize_t(key, NULL); @@ -203,6 +230,12 @@ static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) { const string& name(self->container_def->get_item_name_fn(item)); return PyString_FromStringAndSize(name.c_str(), name.size()); } + case PyContainer::KIND_BYCAMELCASENAME: + { + const string& name( + self->container_def->get_item_camelcase_name_fn(item)); + return PyString_FromStringAndSize(name.c_str(), name.size()); + } case PyContainer::KIND_BYNUMBER: { int value = self->container_def->get_item_number_fn(item); @@ -276,6 +309,9 @@ static PyObject* ContainerRepr(PyContainer* self) { case PyContainer::KIND_BYNAME: kind = "mapping by name"; break; + case PyContainer::KIND_BYCAMELCASENAME: + kind = "mapping by camelCase name"; + break; case PyContainer::KIND_BYNUMBER: kind = "mapping by number"; break; @@ -731,6 +767,18 @@ static PyObject* NewMappingByName( return reinterpret_cast<PyObject*>(self); } +static PyObject* NewMappingByCamelcaseName( + DescriptorContainerDef* container_def, const void* descriptor) { + PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); + if (self == NULL) { + return NULL; + } + self->descriptor = descriptor; + self->container_def = container_def; + self->kind = PyContainer::KIND_BYCAMELCASENAME; + return reinterpret_cast<PyObject*>(self); +} + static PyObject* NewMappingByNumber( DescriptorContainerDef* container_def, const void* descriptor) { if (container_def->get_by_number_fn == NULL || @@ -889,6 +937,11 @@ static ItemDescriptor GetByName(PyContainer* self, const string& name) { return GetDescriptor(self)->FindFieldByName(name); } +static ItemDescriptor GetByCamelcaseName(PyContainer* self, + const string& name) { + return GetDescriptor(self)->FindFieldByCamelcaseName(name); +} + static ItemDescriptor GetByNumber(PyContainer* self, int number) { return GetDescriptor(self)->FindFieldByNumber(number); } @@ -905,6 +958,10 @@ static const string& GetItemName(ItemDescriptor item) { return item->name(); } +static const string& GetItemCamelcaseName(ItemDescriptor item) { + return item->camelcase_name(); +} + static int GetItemNumber(ItemDescriptor item) { return item->number(); } @@ -918,9 +975,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)GetByCamelcaseName, (GetByNumberMethod)GetByNumber, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)GetItemCamelcaseName, (GetItemNumberMethod)GetItemNumber, (GetItemIndexMethod)GetItemIndex, }; @@ -931,6 +990,11 @@ PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) { return descriptor::NewMappingByName(&fields::ContainerDef, descriptor); } +PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) { + return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef, + descriptor); +} + PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) { return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor); } @@ -972,9 +1036,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1022,9 +1088,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1094,9 +1162,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)NULL, }; @@ -1140,9 +1210,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1190,9 +1262,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1258,9 +1332,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)GetByNumber, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)GetItemNumber, (GetItemIndexMethod)GetItemIndex, }; @@ -1314,9 +1390,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)NULL, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)NULL, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1370,9 +1448,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1416,9 +1496,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1462,9 +1544,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)GetByName, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)GetItemName, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)GetItemIndex, }; @@ -1496,9 +1580,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)NULL, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)NULL, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)NULL, }; @@ -1530,9 +1616,11 @@ static DescriptorContainerDef ContainerDef = { (CountMethod)Count, (GetByIndexMethod)GetByIndex, (GetByNameMethod)NULL, + (GetByCamelcaseNameMethod)NULL, (GetByNumberMethod)NULL, (NewObjectFromItemMethod)NewObjectFromItem, (GetItemNameMethod)NULL, + (GetItemCamelcaseNameMethod)NULL, (GetItemNumberMethod)NULL, (GetItemIndexMethod)NULL, }; diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h index 8fbdaff9..ce40747d 100644 --- a/python/google/protobuf/pyext/descriptor_containers.h +++ b/python/google/protobuf/pyext/descriptor_containers.h @@ -54,6 +54,7 @@ bool InitDescriptorMappingTypes(); namespace message_descriptor { PyObject* NewMessageFieldsByName(const Descriptor* descriptor); +PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor); PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor); PyObject* NewMessageFieldsSeq(const Descriptor* descriptor); diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc index 7aed651d..6443a7d5 100644 --- a/python/google/protobuf/pyext/descriptor_pool.cc +++ b/python/google/protobuf/pyext/descriptor_pool.cc @@ -108,6 +108,7 @@ static void Dealloc(PyDescriptorPool* self) { Py_DECREF(it->second); } delete self->descriptor_options; + delete self->pool; delete self->message_factory; Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); } @@ -131,22 +132,9 @@ PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) { } // Add a message class to our database. -const Descriptor* RegisterMessageClass( - PyDescriptorPool* self, PyObject *message_class, PyObject* descriptor) { - ScopedPyObjectPtr full_message_name( - PyObject_GetAttrString(descriptor, "full_name")); - Py_ssize_t name_size; - char* name; - if (PyString_AsStringAndSize(full_message_name, &name, &name_size) < 0) { - return NULL; - } - const Descriptor *message_descriptor = - self->pool->FindMessageTypeByName(string(name, name_size)); - if (!message_descriptor) { - PyErr_Format(PyExc_TypeError, "Could not find C++ descriptor for '%s'", - name); - return NULL; - } +int RegisterMessageClass(PyDescriptorPool* self, + const Descriptor *message_descriptor, + PyObject *message_class) { Py_INCREF(message_class); typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator; std::pair<iterator, bool> ret = self->classes_by_descriptor->insert( @@ -156,7 +144,7 @@ const Descriptor* RegisterMessageClass( Py_DECREF(ret.first->second); ret.first->second = message_class; } - return message_descriptor; + return 0; } // Retrieve the message class added to our database. @@ -260,6 +248,80 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) { return PyOneofDescriptor_FromDescriptor(oneof_descriptor); } +PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) { + Py_ssize_t name_size; + char* name; + if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { + return NULL; + } + + const FileDescriptor* file_descriptor = + self->pool->FindFileContainingSymbol(string(name, name_size)); + if (file_descriptor == NULL) { + PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name); + return NULL; + } + + return PyFileDescriptor_FromDescriptor(file_descriptor); +} + +// These functions should not exist -- the only valid way to create +// descriptors is to call Add() or AddSerializedFile(). +// But these AddDescriptor() functions were created in Python and some people +// call them, so we support them for now for compatibility. +// However we do check that the existing descriptor already exists in the pool, +// which appears to always be true for existing calls -- but then why do people +// call a function that will just be a no-op? +// TODO(amauryfa): Need to investigate further. + +PyObject* AddFileDescriptor(PyDescriptorPool* self, PyObject* descriptor) { + const FileDescriptor* file_descriptor = + PyFileDescriptor_AsDescriptor(descriptor); + if (!file_descriptor) { + return NULL; + } + if (file_descriptor != + self->pool->FindFileByName(file_descriptor->name())) { + PyErr_Format(PyExc_ValueError, + "The file descriptor %s does not belong to this pool", + file_descriptor->name().c_str()); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject* AddDescriptor(PyDescriptorPool* self, PyObject* descriptor) { + const Descriptor* message_descriptor = + PyMessageDescriptor_AsDescriptor(descriptor); + if (!message_descriptor) { + return NULL; + } + if (message_descriptor != + self->pool->FindMessageTypeByName(message_descriptor->full_name())) { + PyErr_Format(PyExc_ValueError, + "The message descriptor %s does not belong to this pool", + message_descriptor->full_name().c_str()); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject* AddEnumDescriptor(PyDescriptorPool* self, PyObject* descriptor) { + const EnumDescriptor* enum_descriptor = + PyEnumDescriptor_AsDescriptor(descriptor); + if (!enum_descriptor) { + return NULL; + } + if (enum_descriptor != + self->pool->FindEnumTypeByName(enum_descriptor->full_name())) { + PyErr_Format(PyExc_ValueError, + "The enum descriptor %s does not belong to this pool", + enum_descriptor->full_name().c_str()); + return NULL; + } + Py_RETURN_NONE; +} + // The code below loads new Descriptors from a serialized FileDescriptorProto. @@ -341,6 +403,15 @@ static PyMethodDef Methods[] = { { "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O, "Adds a serialized FileDescriptorProto to this pool." }, + // TODO(amauryfa): Understand why the Python implementation differs from + // this one, ask users to use another API and deprecate these functions. + { "AddFileDescriptor", (PyCFunction)AddFileDescriptor, METH_O, + "No-op. Add() must have been called before." }, + { "AddDescriptor", (PyCFunction)AddDescriptor, METH_O, + "No-op. Add() must have been called before." }, + { "AddEnumDescriptor", (PyCFunction)AddEnumDescriptor, METH_O, + "No-op. Add() must have been called before." }, + { "FindFileByName", (PyCFunction)FindFileByName, METH_O, "Searches for a file descriptor by its .proto name." }, { "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O, @@ -353,6 +424,9 @@ static PyMethodDef Methods[] = { "Searches for enum type descriptor by full name." }, { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O, "Searches for oneof descriptor by full name." }, + + { "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O, + "Gets the FileDescriptor containing the specified symbol." }, {NULL} }; @@ -420,7 +494,7 @@ bool InitDescriptorPool() { return true; } -PyDescriptorPool* GetDescriptorPool() { +PyDescriptorPool* GetDefaultDescriptorPool() { return python_generated_pool; } @@ -432,7 +506,7 @@ PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) { } hash_map<const DescriptorPool*, PyDescriptorPool*>::iterator it = descriptor_pool_map.find(pool); - if (it != descriptor_pool_map.end()) { + if (it == descriptor_pool_map.end()) { PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool"); return NULL; } diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h index 541d920b..eda73d38 100644 --- a/python/google/protobuf/pyext/descriptor_pool.h +++ b/python/google/protobuf/pyext/descriptor_pool.h @@ -89,12 +89,10 @@ const Descriptor* FindMessageTypeByName(PyDescriptorPool* self, const string& name); // Registers a new Python class for the given message descriptor. -// Returns the message Descriptor. -// On error, returns NULL with a Python exception set. -const Descriptor* RegisterMessageClass( - PyDescriptorPool* self, PyObject* message_class, PyObject* descriptor); - -// The function below are also exposed as methods of the DescriptorPool type. +// On error, returns -1 with a Python exception set. +int RegisterMessageClass(PyDescriptorPool* self, + const Descriptor* message_descriptor, + PyObject* message_class); // Retrieves the Python class registered with the given message descriptor. // @@ -103,6 +101,8 @@ const Descriptor* RegisterMessageClass( PyObject* GetMessageClass(PyDescriptorPool* self, const Descriptor* message_descriptor); +// The functions below are also exposed as methods of the DescriptorPool type. + // Looks up a message by name. Returns a PyMessageDescriptor corresponding to // the field on success, or NULL on failure. // @@ -136,8 +136,9 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg); } // namespace cdescriptor_pool // Retrieve the global descriptor pool owned by the _message module. +// This is the one used by pb2.py generated modules. // Returns a *borrowed* reference. -PyDescriptorPool* GetDescriptorPool(); +PyDescriptorPool* GetDefaultDescriptorPool(); // Retrieve the python descriptor pool owning a C++ descriptor pool. // Returns a *borrowed* reference. diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc index 8ebbb27c..9c9b4178 100644 --- a/python/google/protobuf/pyext/extension_dict.cc +++ b/python/google/protobuf/pyext/extension_dict.cc @@ -123,7 +123,8 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) { if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { PyObject *message_class = cdescriptor_pool::GetMessageClass( - GetDescriptorPool(), descriptor->message_type()); + cmessage::GetDescriptorPoolForMessage(self->parent), + descriptor->message_type()); if (message_class == NULL) { return NULL; } diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 62c7c478..63d53136 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -55,6 +55,7 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/message.h> #include <google/protobuf/text_format.h> +#include <google/protobuf/unknown_field_set.h> #include <google/protobuf/pyext/descriptor.h> #include <google/protobuf/pyext/descriptor_pool.h> #include <google/protobuf/pyext/extension_dict.h> @@ -107,8 +108,18 @@ struct PyMessageMeta { // C++ descriptor of this message. const Descriptor* message_descriptor; + // Owned reference, used to keep the pointer above alive. PyObject* py_message_descriptor; + + // The Python DescriptorPool used to create the class. It is needed to resolve + // fields descriptors, including extensions fields; its C++ MessageFactory is + // used to instantiate submessages. + // This can be different from DESCRIPTOR.file.pool, in the case of a custom + // DescriptorPool which defines new extensions. + // We own the reference, because it's important to keep the descriptors and + // factory alive. + PyDescriptorPool* py_descriptor_pool; }; namespace message_meta { @@ -139,18 +150,10 @@ static bool AddFieldNumberToClass( // Finalize the creation of the Message class. -// Called from its metaclass: GeneratedProtocolMessageType.__init__(). -static int AddDescriptors(PyObject* cls, PyObject* descriptor) { - const Descriptor* message_descriptor = - cdescriptor_pool::RegisterMessageClass( - GetDescriptorPool(), cls, descriptor); - if (message_descriptor == NULL) { - return -1; - } - +static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) { // If there are extension_ranges, the message is "extendable", and extension // classes will register themselves in this class. - if (message_descriptor->extension_range_count() > 0) { + if (descriptor->extension_range_count() > 0) { ScopedPyObjectPtr by_name(PyDict_New()); if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) { return -1; @@ -162,8 +165,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) { } // For each field set: cls.<field>_FIELD_NUMBER = <number> - for (int i = 0; i < message_descriptor->field_count(); ++i) { - if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (!AddFieldNumberToClass(cls, descriptor->field(i))) { return -1; } } @@ -173,8 +176,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) { // The enum descriptor we get from // <messagedescriptor>.enum_types_by_name[name] // which was built previously. - for (int i = 0; i < message_descriptor->enum_type_count(); ++i) { - const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i); + for (int i = 0; i < descriptor->enum_type_count(); ++i) { + const EnumDescriptor* enum_descriptor = descriptor->enum_type(i); ScopedPyObjectPtr enum_type( PyEnumDescriptor_FromDescriptor(enum_descriptor)); if (enum_type == NULL) { @@ -212,8 +215,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) { // Extension descriptors come from // <message descriptor>.extensions_by_name[name] // which was defined previously. - for (int i = 0; i < message_descriptor->extension_count(); ++i) { - const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i); + for (int i = 0; i < descriptor->extension_count(); ++i) { + const google::protobuf::FieldDescriptor* field = descriptor->extension(i); ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field)); if (extension_field == NULL) { return -1; @@ -258,14 +261,14 @@ static PyObject* New(PyTypeObject* type, } // Check dict['DESCRIPTOR'] - PyObject* descriptor = PyDict_GetItem(dict, kDESCRIPTOR); - if (descriptor == NULL) { + PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR); + if (py_descriptor == NULL) { PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); return NULL; } - if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) { + if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) { PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s", - descriptor->ob_type->tp_name); + py_descriptor->ob_type->tp_name); return NULL; } @@ -291,14 +294,28 @@ static PyObject* New(PyTypeObject* type, } // Cache the descriptor, both as Python object and as C++ pointer. - const Descriptor* message_descriptor = - PyMessageDescriptor_AsDescriptor(descriptor); - if (message_descriptor == NULL) { + const Descriptor* descriptor = + PyMessageDescriptor_AsDescriptor(py_descriptor); + if (descriptor == NULL) { + return NULL; + } + Py_INCREF(py_descriptor); + newtype->py_message_descriptor = py_descriptor; + newtype->message_descriptor = descriptor; + // TODO(amauryfa): Don't always use the canonical pool of the descriptor, + // use the MessageFactory optionally passed in the class dict. + newtype->py_descriptor_pool = GetDescriptorPool_FromPool( + descriptor->file()->pool()); + if (newtype->py_descriptor_pool == NULL) { + return NULL; + } + Py_INCREF(newtype->py_descriptor_pool); + + // Add the message to the DescriptorPool. + if (cdescriptor_pool::RegisterMessageClass(newtype->py_descriptor_pool, + descriptor, result) < 0) { return NULL; } - Py_INCREF(descriptor); - newtype->py_message_descriptor = descriptor; - newtype->message_descriptor = message_descriptor; // Continue with type initialization: add other descriptors, enum values... if (AddDescriptors(result, descriptor) < 0) { @@ -309,6 +326,7 @@ static PyObject* New(PyTypeObject* type, static void Dealloc(PyMessageMeta *self) { Py_DECREF(self->py_message_descriptor); + Py_DECREF(self->py_descriptor_pool); Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); } @@ -381,12 +399,20 @@ PyTypeObject PyMessageMeta_Type = { message_meta::New, // tp_new }; -static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) { +static PyMessageMeta* CheckMessageClass(PyTypeObject* cls) { if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) { PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name); return NULL; } - return reinterpret_cast<PyMessageMeta*>(cls)->message_descriptor; + return reinterpret_cast<PyMessageMeta*>(cls); +} + +static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) { + PyMessageMeta* type = CheckMessageClass(cls); + if (type == NULL) { + return NULL; + } + return type->message_descriptor; } // Forward declarations @@ -723,6 +749,17 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor, namespace cmessage { +PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) { + // No need to check the type: the type of instances of CMessage is always + // an instance of PyMessageMeta. Let's prove it with a debug-only check. + GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type)); + return reinterpret_cast<PyMessageMeta*>(Py_TYPE(message))->py_descriptor_pool; +} + +MessageFactory* GetFactoryForMessage(CMessage* message) { + return GetDescriptorPoolForMessage(message)->message_factory; +} + static int MaybeReleaseOverlappingOneofField( CMessage* cmessage, const FieldDescriptor* field) { @@ -773,7 +810,7 @@ static Message* GetMutableMessage( return NULL; } return reflection->MutableMessage( - parent_message, parent_field, GetDescriptorPool()->message_factory); + parent_message, parent_field, GetFactoryForMessage(parent)); } struct FixupMessageReference : public ChildVisitor { @@ -814,10 +851,7 @@ int AssureWritable(CMessage* self) { // If parent is NULL but we are trying to modify a read-only message, this // is a reference to a constant default instance that needs to be replaced // with a mutable top-level message. - const Message* prototype = - GetDescriptorPool()->message_factory->GetPrototype( - self->message->GetDescriptor()); - self->message = prototype->New(); + self->message = self->message->New(); self->owner.reset(self->message); // Cascade the new owner to eventual children: even if this message is // empty, some submessages or repeated containers might exist already. @@ -1190,15 +1224,19 @@ CMessage* NewEmptyMessage(PyObject* type, const Descriptor *descriptor) { // The __new__ method of Message classes. // Creates a new C++ message and takes ownership. -static PyObject* New(PyTypeObject* type, +static PyObject* New(PyTypeObject* cls, PyObject* unused_args, PyObject* unused_kwargs) { + PyMessageMeta* type = CheckMessageClass(cls); + if (type == NULL) { + return NULL; + } // Retrieve the message descriptor and the default instance (=prototype). - const Descriptor* message_descriptor = GetMessageDescriptor(type); + const Descriptor* message_descriptor = type->message_descriptor; if (message_descriptor == NULL) { return NULL; } - const Message* default_message = - GetDescriptorPool()->message_factory->GetPrototype(message_descriptor); + const Message* default_message = type->py_descriptor_pool->message_factory + ->GetPrototype(message_descriptor); if (default_message == NULL) { PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str()); return NULL; @@ -1528,7 +1566,7 @@ int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner) { Message* ReleaseMessage(CMessage* self, const Descriptor* descriptor, const FieldDescriptor* field_descriptor) { - MessageFactory* message_factory = GetDescriptorPool()->message_factory; + MessageFactory* message_factory = GetFactoryForMessage(self); Message* released_message = self->message->GetReflection()->ReleaseMessage( self->message, field_descriptor, message_factory); // ReleaseMessage will return NULL which differs from @@ -1883,8 +1921,8 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) { AssureWritable(self); io::CodedInputStream input( reinterpret_cast<const uint8*>(data), data_length); - input.SetExtensionRegistry(GetDescriptorPool()->pool, - GetDescriptorPool()->message_factory); + PyDescriptorPool* pool = GetDescriptorPoolForMessage(self); + input.SetExtensionRegistry(pool->pool, pool->message_factory); bool success = self->message->MergePartialFromCodedStream(&input); if (success) { return PyInt_FromLong(input.CurrentPosition()); @@ -1907,11 +1945,6 @@ static PyObject* ByteSize(CMessage* self, PyObject* args) { static PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle) { - ScopedPyObjectPtr message_descriptor(PyObject_GetAttr(cls, kDESCRIPTOR)); - if (message_descriptor == NULL) { - return NULL; - } - const FieldDescriptor* descriptor = GetExtensionDescriptor(extension_handle); if (descriptor == NULL) { @@ -1920,13 +1953,6 @@ static PyObject* RegisterExtension(PyObject* cls, const Descriptor* cmessage_descriptor = GetMessageDescriptor( reinterpret_cast<PyTypeObject*>(cls)); - if (cmessage_descriptor != descriptor->containing_type()) { - if (PyObject_SetAttrString(extension_handle, "containing_type", - message_descriptor) < 0) { - return NULL; - } - } - ScopedPyObjectPtr extensions_by_name( PyObject_GetAttr(cls, k_extensions_by_name)); if (extensions_by_name == NULL) { @@ -2050,7 +2076,8 @@ static PyObject* ListFields(CMessage* self) { // TODO(amauryfa): consider building the class on the fly! if (fields[i]->message_type() != NULL && cdescriptor_pool::GetMessageClass( - GetDescriptorPool(), fields[i]->message_type()) == NULL) { + GetDescriptorPoolForMessage(self), + fields[i]->message_type()) == NULL) { PyErr_Clear(); continue; } @@ -2207,7 +2234,9 @@ PyObject* InternalGetScalar(const Message* message, message->GetReflection()->GetUnknownFields(*message); for (int i = 0; i < unknown_field_set.field_count(); ++i) { if (unknown_field_set.field(i).number() == - field_descriptor->number()) { + field_descriptor->number() && + unknown_field_set.field(i).type() == + google::protobuf::UnknownField::TYPE_VARINT) { result = PyInt_FromLong(unknown_field_set.field(i).varint()); break; } @@ -2233,11 +2262,12 @@ PyObject* InternalGetScalar(const Message* message, PyObject* InternalGetSubMessage( CMessage* self, const FieldDescriptor* field_descriptor) { const Reflection* reflection = self->message->GetReflection(); + PyDescriptorPool* pool = GetDescriptorPoolForMessage(self); const Message& sub_message = reflection->GetMessage( - *self->message, field_descriptor, GetDescriptorPool()->message_factory); + *self->message, field_descriptor, pool->message_factory); PyObject *message_class = cdescriptor_pool::GetMessageClass( - GetDescriptorPool(), field_descriptor->message_type()); + pool, field_descriptor->message_type()); if (message_class == NULL) { return NULL; } @@ -2560,7 +2590,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { const FieldDescriptor* value_type = entry_type->FindFieldByName("value"); if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { PyObject* value_class = cdescriptor_pool::GetMessageClass( - GetDescriptorPool(), value_type->message_type()); + GetDescriptorPoolForMessage(self), value_type->message_type()); if (value_class == NULL) { return NULL; } @@ -2583,7 +2613,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { PyObject* py_container = NULL; if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { PyObject *message_class = cdescriptor_pool::GetMessageClass( - GetDescriptorPool(), field_descriptor->message_type()); + GetDescriptorPoolForMessage(self), field_descriptor->message_type()); if (message_class == NULL) { return NULL; } @@ -2908,9 +2938,10 @@ bool InitProto2MessageModule(PyObject *m) { // Expose the DescriptorPool used to hold all descriptors added from generated // pb2.py files. - Py_INCREF(GetDescriptorPool()); // PyModule_AddObject steals a reference. - PyModule_AddObject( - m, "default_pool", reinterpret_cast<PyObject*>(GetDescriptorPool())); + // PyModule_AddObject steals a reference. + Py_INCREF(GetDefaultDescriptorPool()); + PyModule_AddObject(m, "default_pool", + reinterpret_cast<PyObject*>(GetDefaultDescriptorPool())); // This implementation provides full Descriptor types, we advertise it so that // descriptor.py can use them in replacement of the Python classes. diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index f147d433..1ff82e2f 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -49,12 +49,15 @@ class Message; class Reflection; class FieldDescriptor; class Descriptor; +class DescriptorPool; +class MessageFactory; using internal::shared_ptr; namespace python { struct ExtensionDict; +struct PyDescriptorPool; typedef struct CMessage { PyObject_HEAD; @@ -220,6 +223,16 @@ PyObject* FindInitializationErrors(CMessage* self); int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner); int AssureWritable(CMessage* self); + +// Returns the "best" DescriptorPool for the given message. +// This is often equivalent to message.DESCRIPTOR.pool, but not always, when +// the message class was created from a MessageFactory using a custom pool which +// uses the generated pool as an underlay. +// +// The returned pool is suitable for finding fields and building submessages, +// even in the case of extensions. +PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message); + } // namespace cmessage |