diff options
Diffstat (limited to 'python/google/protobuf/pyext/message.cc')
-rw-r--r-- | python/google/protobuf/pyext/message.cc | 495 |
1 files changed, 243 insertions, 252 deletions
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 9fb7083f..cd956e0e 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -71,7 +71,7 @@ #error "Python 3.0 - 3.2 are not supported." #else #define PyString_AsString(ob) \ - (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob)) + (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob)) #endif #endif @@ -81,7 +81,9 @@ namespace python { // Forward declarations namespace cmessage { -static PyObject* GetDescriptor(CMessage* self, PyObject* name); +static const google::protobuf::FieldDescriptor* GetFieldDescriptor( + CMessage* self, PyObject* name); +static const google::protobuf::Descriptor* GetMessageDescriptor(PyTypeObject* cls); static string GetMessageName(CMessage* self); int InternalReleaseFieldByDescriptor( const google::protobuf::FieldDescriptor* field_descriptor, @@ -147,12 +149,15 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) { PyObject* key; PyObject* field; + // Never use self->message in this function, it may be already freed. + const google::protobuf::Descriptor* message_descriptor = + cmessage::GetMessageDescriptor(Py_TYPE(self)); + // Visit normal fields. while (PyDict_Next(self->composite_fields, &pos, &key, &field)) { - PyObject* cdescriptor = cmessage::GetDescriptor(self, key); - if (cdescriptor != NULL) { - const google::protobuf::FieldDescriptor* descriptor = - reinterpret_cast<CFieldDescriptor*>(cdescriptor)->descriptor; + const google::protobuf::FieldDescriptor* descriptor = + message_descriptor->FindFieldByName(PyString_AsString(key)); + if (descriptor != NULL) { if (VisitCompositeField(descriptor, field, visitor) == -1) return -1; } @@ -161,11 +166,11 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) { // Visit extension fields. if (self->extensions != NULL) { while (PyDict_Next(self->extensions->values, &pos, &key, &field)) { - CFieldDescriptor* cdescriptor = - extension_dict::InternalGetCDescriptorFromExtension(key); - if (cdescriptor == NULL) + const google::protobuf::FieldDescriptor* descriptor = + cmessage::GetExtensionDescriptor(key); + if (descriptor == NULL) return -1; - if (VisitCompositeField(cdescriptor->descriptor, field, visitor) == -1) + if (VisitCompositeField(descriptor, field, visitor) == -1) return -1; } } @@ -191,18 +196,19 @@ PyObject* PickleError_class; // Constant PyString values used for GetAttr/GetItem. static PyObject* kDESCRIPTOR; -static PyObject* k__descriptors; +static PyObject* k_cdescriptor; static PyObject* kfull_name; static PyObject* kname; -static PyObject* kmessage_type; -static PyObject* kis_extendable; static PyObject* kextensions_by_name; static PyObject* k_extensions_by_name; static PyObject* k_extensions_by_number; -static PyObject* k_concrete_class; static PyObject* kfields_by_name; -static CDescriptorPool* descriptor_pool; +static PyDescriptorPool* descriptor_pool; + +PyDescriptorPool* GetDescriptorPool() { + return descriptor_pool; +} /* Is 64bit */ void FormatTypeError(PyObject* arg, char* expected_types) { @@ -313,12 +319,12 @@ bool CheckAndSetString( } if (PyBytes_Check(arg)) { - PyObject* unicode = PyUnicode_FromEncodedObject(arg, "ascii", NULL); + PyObject* unicode = PyUnicode_FromEncodedObject(arg, "utf-8", NULL); if (unicode == NULL) { PyObject* repr = PyObject_Repr(arg); PyErr_Format(PyExc_ValueError, - "%s has type str, but isn't in 7-bit ASCII " - "encoding. Non-ASCII strings must be converted to " + "%s has type str, but isn't valid UTF-8 " + "encoding. Non-UTF-8 strings must be converted to " "unicode objects before being added.", PyString_AsString(repr)); Py_DECREF(repr); @@ -335,12 +341,9 @@ bool CheckAndSetString( PyObject* encoded_string = NULL; if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) { if (PyBytes_Check(arg)) { -#if PY_MAJOR_VERSION < 3 - encoded_string = PyString_AsEncodedObject(arg, "utf-8", NULL); -#else + // The bytes were already validated as correctly encoded UTF-8 above. encoded_string = arg; // Already encoded. Py_INCREF(encoded_string); -#endif } else { encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL); } @@ -391,6 +394,17 @@ PyObject* ToStringObject( return result; } +bool CheckFieldBelongsToMessage(const google::protobuf::FieldDescriptor* field_descriptor, + const google::protobuf::Message* message) { + if (message->GetDescriptor() == field_descriptor->containing_type()) { + return true; + } + PyErr_Format(PyExc_KeyError, "Field '%s' does not belong to message '%s'", + field_descriptor->full_name().c_str(), + message->GetDescriptor()->full_name().c_str()); + return false; +} + google::protobuf::DynamicMessageFactory* global_message_factory; namespace cmessage { @@ -489,7 +503,7 @@ int AssureWritable(CMessage* self) { google::protobuf::Message* parent_message = self->parent->message; google::protobuf::Message* mutable_message = GetMutableMessage( self->parent, - self->parent_field->descriptor); + self->parent_field_descriptor); if (mutable_message == NULL) { return -1; } @@ -512,26 +526,61 @@ int AssureWritable(CMessage* self) { // --- Globals: -static PyObject* GetDescriptor(CMessage* self, PyObject* name) { - PyObject* descriptors = - PyDict_GetItem(Py_TYPE(self)->tp_dict, k__descriptors); - if (descriptors == NULL) { - PyErr_SetString(PyExc_TypeError, "No __descriptors"); +// Retrieve the C++ Descriptor of a message class. +// On error, returns NULL with an exception set. +static const google::protobuf::Descriptor* GetMessageDescriptor(PyTypeObject* cls) { + ScopedPyObjectPtr descriptor(PyObject_GetAttr( + reinterpret_cast<PyObject*>(cls), kDESCRIPTOR)); + if (descriptor == NULL) { + PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); + return NULL; + } + ScopedPyObjectPtr cdescriptor(PyObject_GetAttr(descriptor, k_cdescriptor)); + if (cdescriptor == NULL) { + PyErr_SetString(PyExc_TypeError, "Unregistered message."); + return NULL; + } + if (!PyObject_TypeCheck(cdescriptor, &CMessageDescriptor_Type)) { + PyErr_SetString(PyExc_TypeError, "Not a CMessageDescriptor"); return NULL; } + return reinterpret_cast<CMessageDescriptor*>(cdescriptor.get())->descriptor; +} - return PyDict_GetItem(descriptors, name); +// Retrieve a C++ FieldDescriptor for a message attribute. +// The C++ message must be valid. +// TODO(amauryfa): This function should stay internal, because exception +// handling is not consistent. +static const google::protobuf::FieldDescriptor* GetFieldDescriptor( + CMessage* self, PyObject* name) { + const google::protobuf::Descriptor *message_descriptor = self->message->GetDescriptor(); + const char* field_name = PyString_AsString(name); + if (field_name == NULL) { + return NULL; + } + const google::protobuf::FieldDescriptor *field_descriptor = + message_descriptor->FindFieldByName(field_name); + if (field_descriptor == NULL) { + // Note: No exception is set! + return NULL; + } + return field_descriptor; } -static const google::protobuf::Message* CreateMessage(const char* message_type) { - string message_name(message_type); - const google::protobuf::Descriptor* descriptor = - GetDescriptorPool()->FindMessageTypeByName(message_name); - if (descriptor == NULL) { - PyErr_SetString(PyExc_TypeError, message_type); +// Retrieve a C++ FieldDescriptor for an extension handle. +const google::protobuf::FieldDescriptor* GetExtensionDescriptor(PyObject* extension) { + ScopedPyObjectPtr cdescriptor( + PyObject_GetAttrString(extension, "_cdescriptor")); + if (cdescriptor == NULL) { + PyErr_SetString(PyExc_KeyError, "Unregistered extension."); + return NULL; + } + if (!PyObject_TypeCheck(cdescriptor, &CFieldDescriptor_Type)) { + PyErr_SetString(PyExc_TypeError, "Not a CFieldDescriptor"); + Py_DECREF(cdescriptor); return NULL; } - return global_message_factory->GetPrototype(descriptor); + return reinterpret_cast<CFieldDescriptor*>(cdescriptor.get())->descriptor; } // If cmessage_list is not NULL, this function releases values into the @@ -627,39 +676,8 @@ int InternalDeleteRepeatedField( return 0; } -int InitAttributes(CMessage* self, PyObject* arg, PyObject* kwargs) { - ScopedPyObjectPtr descriptor; - if (arg == NULL) { - descriptor.reset( - PyObject_GetAttr(reinterpret_cast<PyObject*>(self), kDESCRIPTOR)); - if (descriptor == NULL) { - return NULL; - } - } else { - descriptor.reset(arg); - descriptor.inc(); - } - ScopedPyObjectPtr is_extendable(PyObject_GetAttr(descriptor, kis_extendable)); - if (is_extendable == NULL) { - return NULL; - } - int retcode = PyObject_IsTrue(is_extendable); - if (retcode == -1) { - return NULL; - } - if (retcode) { - PyObject* py_extension_dict = PyObject_CallObject( - reinterpret_cast<PyObject*>(&ExtensionDict_Type), NULL); - if (py_extension_dict == NULL) { - return NULL; - } - ExtensionDict* extension_dict = reinterpret_cast<ExtensionDict*>( - py_extension_dict); - extension_dict->parent = self; - extension_dict->message = self->message; - self->extensions = extension_dict; - } - +// Initializes fields of a message. Used in constructors. +int InitAttributes(CMessage* self, PyObject* kwargs) { if (kwargs == NULL) { return 0; } @@ -672,14 +690,12 @@ int InitAttributes(CMessage* self, PyObject* arg, PyObject* kwargs) { PyErr_SetString(PyExc_ValueError, "Field name must be a string"); return -1; } - PyObject* py_cdescriptor = GetDescriptor(self, name); - if (py_cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = GetFieldDescriptor(self, name); + if (descriptor == NULL) { PyErr_Format(PyExc_ValueError, "Protocol message has no \"%s\" field.", PyString_AsString(name)); return -1; } - const google::protobuf::FieldDescriptor* descriptor = - reinterpret_cast<CFieldDescriptor*>(py_cdescriptor)->descriptor; if (descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { ScopedPyObjectPtr container(GetAttr(self, name)); if (container == NULL) { @@ -719,15 +735,19 @@ int InitAttributes(CMessage* self, PyObject* arg, PyObject* kwargs) { return 0; } -static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) { - CMessage* self = reinterpret_cast<CMessage*>(type->tp_alloc(type, 0)); +// Allocates an incomplete Python Message: the caller must fill self->message, +// self->owner and eventually self->parent. +CMessage* NewEmptyMessage(PyObject* type, + const google::protobuf::Descriptor *descriptor) { + CMessage* self = reinterpret_cast<CMessage*>( + PyType_GenericAlloc(reinterpret_cast<PyTypeObject*>(type), 0)); if (self == NULL) { return NULL; } self->message = NULL; self->parent = NULL; - self->parent_field = NULL; + self->parent_field_descriptor = NULL; self->read_only = false; self->extensions = NULL; @@ -735,43 +755,58 @@ static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) { if (self->composite_fields == NULL) { return NULL; } - return reinterpret_cast<PyObject*>(self); -} - -PyObject* NewEmpty(PyObject* type) { - return New(reinterpret_cast<PyTypeObject*>(type), NULL, NULL); -} -static int Init(CMessage* self, PyObject* args, PyObject* kwargs) { - if (kwargs == NULL) { - // TODO(anuraag): Set error - return -1; + // If there are extension_ranges, the message is "extendable". Allocate a + // dictionary to store the extension fields. + if (descriptor->extension_range_count() > 0) { + // TODO(amauryfa): Delay the construction of this dict until extensions are + // really used on the object. + ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self); + if (extension_dict == NULL) { + return NULL; + } + self->extensions = extension_dict; } - PyObject* descriptor = PyTuple_GetItem(args, 0); - if (descriptor == NULL || PyTuple_Size(args) != 1) { - PyErr_SetString(PyExc_ValueError, "args must contain one arg: descriptor"); - return -1; - } + return self; +} - ScopedPyObjectPtr py_message_type(PyObject_GetAttr(descriptor, kfull_name)); - if (py_message_type == NULL) { - return -1; +// The __new__ method of Message classes. +// Creates a new C++ message and takes ownership. +static PyObject* New(PyTypeObject* type, + PyObject* unused_args, PyObject* unused_kwargs) { + // Retrieve the message descriptor and the default instance (=prototype). + const google::protobuf::Descriptor* message_descriptor = GetMessageDescriptor(type); + if (message_descriptor == NULL) { + return NULL; } - - const char* message_type = PyString_AsString(py_message_type.get()); - const google::protobuf::Message* message = CreateMessage(message_type); - if (message == NULL) { - return -1; + const google::protobuf::Message* default_message = + global_message_factory->GetPrototype(message_descriptor); + if (default_message == NULL) { + PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str()); + return NULL; } - self->message = message->New(); + CMessage* self = NewEmptyMessage(reinterpret_cast<PyObject*>(type), + message_descriptor); + if (self == NULL) { + return NULL; + } + self->message = default_message->New(); self->owner.reset(self->message); - if (InitAttributes(self, descriptor, kwargs) < 0) { + return reinterpret_cast<PyObject*>(self); +} + +// The __init__ method of Message classes. +// It initializes fields from keywords passed to the constructor. +static int Init(CMessage* self, PyObject* args, PyObject* kwargs) { + if (PyTuple_Size(args) != 0) { + PyErr_SetString(PyExc_TypeError, "No positional arguments allowed"); return -1; } - return 0; + + return InitAttributes(self, kwargs); } // --------------------------------------------------------------------- @@ -853,9 +888,7 @@ PyObject* IsInitialized(CMessage* self, PyObject* args) { PyObject* HasFieldByDescriptor( CMessage* self, const google::protobuf::FieldDescriptor* field_descriptor) { google::protobuf::Message* message = self->message; - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString(PyExc_KeyError, - "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(field_descriptor, message)) { return NULL; } if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { @@ -1048,7 +1081,7 @@ int ReleaseSubMessage(google::protobuf::Message* message, child_cmessage->message = released_message.get(); child_cmessage->owner.swap(released_message); child_cmessage->parent = NULL; - child_cmessage->parent_field = NULL; + child_cmessage->parent_field_descriptor = NULL; child_cmessage->read_only = false; return ForEachCompositeField(child_cmessage, SetOwnerVisitor(child_cmessage->owner)); @@ -1090,10 +1123,8 @@ int InternalReleaseFieldByDescriptor( int InternalReleaseField(CMessage* self, PyObject* composite_field, PyObject* name) { - PyObject* cdescriptor = GetDescriptor(self, name); - if (cdescriptor != NULL) { - const google::protobuf::FieldDescriptor* descriptor = - reinterpret_cast<CFieldDescriptor*>(cdescriptor)->descriptor; + const google::protobuf::FieldDescriptor* descriptor = GetFieldDescriptor(self, name); + if (descriptor != NULL) { return InternalReleaseFieldByDescriptor( descriptor, composite_field, self->message); } @@ -1104,9 +1135,7 @@ int InternalReleaseField(CMessage* self, PyObject* composite_field, PyObject* ClearFieldByDescriptor( CMessage* self, const google::protobuf::FieldDescriptor* descriptor) { - if (!FIELD_BELONGS_TO_MESSAGE(descriptor, self->message)) { - PyErr_SetString(PyExc_KeyError, - "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(descriptor, self->message)) { return NULL; } AssureWritable(self); @@ -1177,15 +1206,10 @@ PyObject* Clear(CMessage* self) { // fields have been released. if (self->extensions != NULL) { Py_CLEAR(self->extensions); - PyObject* py_extension_dict = PyObject_CallObject( - reinterpret_cast<PyObject*>(&ExtensionDict_Type), NULL); - if (py_extension_dict == NULL) { + ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self); + if (extension_dict == NULL) { return NULL; } - ExtensionDict* extension_dict = reinterpret_cast<ExtensionDict*>( - py_extension_dict); - extension_dict->parent = self; - extension_dict->message = self->message; self->extensions = extension_dict; } PyDict_Clear(self->composite_fields); @@ -1196,8 +1220,8 @@ PyObject* Clear(CMessage* self) { // --------------------------------------------------------------------- static string GetMessageName(CMessage* self) { - if (self->parent_field != NULL) { - return self->parent_field->descriptor->full_name(); + if (self->parent_field_descriptor != NULL) { + return self->parent_field_descriptor->full_name(); } else { return self->message->GetDescriptor()->full_name(); } @@ -1219,7 +1243,7 @@ static PyObject* SerializeToString(CMessage* self, PyObject* args) { return NULL; } PyErr_Format(EncodeError_class, "Message %s is missing required fields: %s", - GetMessageName(self).c_str(), PyString_AsString(joined.get())); + GetMessageName(self).c_str(), PyString_AsString(joined)); return NULL; } int size = self->message->ByteSize(); @@ -1361,7 +1385,7 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) { AssureWritable(self); google::protobuf::io::CodedInputStream input( reinterpret_cast<const uint8*>(data), data_length); - input.SetExtensionRegistry(GetDescriptorPool(), global_message_factory); + input.SetExtensionRegistry(descriptor_pool->pool, global_message_factory); bool success = self->message->MergePartialFromCodedStream(&input); if (success) { return PyInt_FromLong(input.CurrentPosition()); @@ -1421,15 +1445,11 @@ static PyObject* RegisterExtension(PyObject* cls, return NULL; } - CFieldDescriptor* cdescriptor = - extension_dict::InternalGetCDescriptorFromExtension(extension_handle); - ScopedPyObjectPtr py_cdescriptor(reinterpret_cast<PyObject*>(cdescriptor)); - if (cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = + GetExtensionDescriptor(extension_handle); + if (descriptor == NULL) { return NULL; } - Py_INCREF(extension_handle); - cdescriptor->descriptor_field = extension_handle; - const google::protobuf::FieldDescriptor* descriptor = cdescriptor->descriptor; // Check if it's a message set if (descriptor->is_extension() && descriptor->containing_type()->options().message_set_wire_format() && @@ -1608,8 +1628,14 @@ static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) { } if (opid == Py_EQ || opid == Py_NE) { ScopedPyObjectPtr self_fields(ListFields(self)); + if (!self_fields) { + return NULL; + } ScopedPyObjectPtr other_fields(ListFields( reinterpret_cast<CMessage*>(other))); + if (!other_fields) { + return NULL; + } return PyObject_RichCompare(self_fields, other_fields, opid); } else { Py_INCREF(Py_NotImplemented); @@ -1623,9 +1649,7 @@ PyObject* InternalGetScalar( google::protobuf::Message* message = self->message; const google::protobuf::Reflection* reflection = message->GetReflection(); - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString( - PyExc_KeyError, "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(field_descriptor, message)) { return NULL; } @@ -1701,43 +1725,31 @@ PyObject* InternalGetScalar( return result; } -PyObject* InternalGetSubMessage(CMessage* self, - CFieldDescriptor* cfield_descriptor) { - PyObject* field = cfield_descriptor->descriptor_field; - ScopedPyObjectPtr message_type(PyObject_GetAttr(field, kmessage_type)); - if (message_type == NULL) { - return NULL; - } - ScopedPyObjectPtr concrete_class( - PyObject_GetAttr(message_type, k_concrete_class)); - if (concrete_class == NULL) { +PyObject* InternalGetSubMessage( + CMessage* self, const google::protobuf::FieldDescriptor* field_descriptor) { + const google::protobuf::Reflection* reflection = self->message->GetReflection(); + const google::protobuf::Message& sub_message = reflection->GetMessage( + *self->message, field_descriptor, global_message_factory); + + PyObject *message_class = cdescriptor_pool::GetMessageClass( + descriptor_pool, field_descriptor->message_type()); + if (message_class == NULL) { return NULL; } - PyObject* py_cmsg = cmessage::NewEmpty(concrete_class); - if (py_cmsg == NULL) { + + CMessage* cmsg = cmessage::NewEmptyMessage(message_class, + sub_message.GetDescriptor()); + if (cmsg == NULL) { return NULL; } - if (!PyObject_TypeCheck(py_cmsg, &CMessage_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a CMessage!"); - } - CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg); - const google::protobuf::FieldDescriptor* field_descriptor = - cfield_descriptor->descriptor; - const google::protobuf::Reflection* reflection = self->message->GetReflection(); - const google::protobuf::Message& sub_message = reflection->GetMessage( - *self->message, field_descriptor, global_message_factory); cmsg->owner = self->owner; cmsg->parent = self; - cmsg->parent_field = cfield_descriptor; + cmsg->parent_field_descriptor = field_descriptor; cmsg->read_only = !reflection->HasField(*self->message, field_descriptor); cmsg->message = const_cast<google::protobuf::Message*>(&sub_message); - if (InitAttributes(cmsg, NULL, NULL) < 0) { - Py_DECREF(py_cmsg); - return NULL; - } - return py_cmsg; + return reinterpret_cast<PyObject*>(cmsg); } int InternalSetScalar( @@ -1747,9 +1759,7 @@ int InternalSetScalar( google::protobuf::Message* message = self->message; const google::protobuf::Reflection* reflection = message->GetReflection(); - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString( - PyExc_KeyError, "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(field_descriptor, message)) { return -1; } @@ -1838,25 +1848,35 @@ PyObject* FromString(PyTypeObject* cls, PyObject* serialized) { return NULL; } - if (InitAttributes(cmsg, NULL, NULL) < 0) { - Py_DECREF(py_cmsg); - return NULL; - } return py_cmsg; } + +// Finalize the creation of the Message class. +// Called from its metaclass: GeneratedProtocolMessageType.__init__(). static PyObject* AddDescriptors(PyTypeObject* cls, PyObject* descriptor) { - if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls), - k_extensions_by_name, PyDict_New()) < 0) { - return NULL; - } - if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls), - k_extensions_by_number, PyDict_New()) < 0) { + const google::protobuf::Descriptor* message_descriptor = + cdescriptor_pool::RegisterMessageClass( + descriptor_pool, reinterpret_cast<PyObject*>(cls), descriptor); + if (message_descriptor == NULL) { return NULL; } - ScopedPyObjectPtr field_descriptors(PyDict_New()); + // 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) { + ScopedPyObjectPtr by_name(PyDict_New()); + if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls), + k_extensions_by_name, by_name) < 0) { + return NULL; + } + ScopedPyObjectPtr by_number(PyDict_New()); + if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls), + k_extensions_by_number, by_number) < 0) { + return NULL; + } + } ScopedPyObjectPtr fields(PyObject_GetAttrString(descriptor, "fields")); if (fields == NULL) { @@ -1878,19 +1898,14 @@ static PyObject* AddDescriptors(PyTypeObject* cls, return NULL; } - PyObject* field_descriptor = - cdescriptor_pool::FindFieldByName(descriptor_pool, full_field_name); + ScopedPyObjectPtr field_descriptor( + cdescriptor_pool::FindFieldByName(descriptor_pool, full_field_name)); if (field_descriptor == NULL) { PyErr_SetString(PyExc_TypeError, "Couldn't find field"); return NULL; } - Py_INCREF(field); CFieldDescriptor* cfield_descriptor = reinterpret_cast<CFieldDescriptor*>( - field_descriptor); - cfield_descriptor->descriptor_field = field; - if (PyDict_SetItem(field_descriptors, field_name, field_descriptor) < 0) { - return NULL; - } + field_descriptor.get()); // The FieldDescriptor's name field might either be of type bytes or // of type unicode, depending on whether the FieldDescriptor was @@ -1919,8 +1934,6 @@ static PyObject* AddDescriptors(PyTypeObject* cls, } } - PyDict_SetItem(cls->tp_dict, k__descriptors, field_descriptors); - // Enum Values ScopedPyObjectPtr enum_types(PyObject_GetAttrString(descriptor, "enum_types")); @@ -1994,15 +2007,11 @@ static PyObject* AddDescriptors(PyTypeObject* cls, extension_name, extension_field) == -1) { return NULL; } - ScopedPyObjectPtr py_cfield_descriptor( - PyObject_GetAttrString(extension_field, "_cdescriptor")); - if (py_cfield_descriptor == NULL) { + const google::protobuf::FieldDescriptor* field_descriptor = + GetExtensionDescriptor(extension_field); + if (field_descriptor == NULL) { return NULL; } - CFieldDescriptor* cfield_descriptor = - reinterpret_cast<CFieldDescriptor*>(py_cfield_descriptor.get()); - Py_INCREF(extension_field); - cfield_descriptor->descriptor_field = extension_field; ScopedPyObjectPtr field_name_upcased( PyObject_CallMethod(extension_name, "upper", NULL)); @@ -2015,13 +2024,12 @@ static PyObject* AddDescriptors(PyTypeObject* cls, return NULL; } ScopedPyObjectPtr number(PyInt_FromLong( - cfield_descriptor->descriptor->number())); + field_descriptor->number())); if (number == NULL) { return NULL; } if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls), - field_number_name, PyInt_FromLong( - cfield_descriptor->descriptor->number())) == -1) { + field_number_name, number) == -1) { return NULL; } } @@ -2039,10 +2047,6 @@ PyObject* DeepCopy(CMessage* self, PyObject* arg) { Py_DECREF(clone); return NULL; } - if (InitAttributes(reinterpret_cast<CMessage*>(clone), NULL, NULL) < 0) { - Py_DECREF(clone); - return NULL; - } if (MergeFrom(reinterpret_cast<CMessage*>(clone), reinterpret_cast<PyObject*>(self)) == NULL) { Py_DECREF(clone); @@ -2202,48 +2206,30 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { return value; } - PyObject* descriptor = GetDescriptor(self, name); - if (descriptor != NULL) { - CFieldDescriptor* cdescriptor = - reinterpret_cast<CFieldDescriptor*>(descriptor); - const google::protobuf::FieldDescriptor* field_descriptor = cdescriptor->descriptor; + const google::protobuf::FieldDescriptor* field_descriptor = GetFieldDescriptor( + self, name); + if (field_descriptor != NULL) { if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { if (field_descriptor->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject* py_container = PyObject_CallObject( - reinterpret_cast<PyObject*>(&RepeatedCompositeContainer_Type), - NULL); - if (py_container == NULL) { + PyObject *message_class = cdescriptor_pool::GetMessageClass( + descriptor_pool, field_descriptor->message_type()); + if (message_class == NULL) { return NULL; } - RepeatedCompositeContainer* container = - reinterpret_cast<RepeatedCompositeContainer*>(py_container); - PyObject* field = cdescriptor->descriptor_field; - PyObject* message_type = PyObject_GetAttr(field, kmessage_type); - if (message_type == NULL) { - return NULL; - } - PyObject* concrete_class = - PyObject_GetAttr(message_type, k_concrete_class); - if (concrete_class == NULL) { + PyObject* py_container = repeated_composite_container::NewContainer( + self, field_descriptor, message_class); + if (py_container == NULL) { return NULL; } - container->parent = self; - container->parent_field = cdescriptor; - container->message = self->message; - container->owner = self->owner; - container->subclass_init = concrete_class; - Py_DECREF(message_type); if (PyDict_SetItem(self->composite_fields, name, py_container) < 0) { Py_DECREF(py_container); return NULL; } return py_container; } else { - ScopedPyObjectPtr init_args(PyTuple_Pack(2, self, cdescriptor)); - PyObject* py_container = PyObject_CallObject( - reinterpret_cast<PyObject*>(&RepeatedScalarContainer_Type), - init_args); + PyObject* py_container = repeated_scalar_container::NewContainer( + self, field_descriptor); if (py_container == NULL) { return NULL; } @@ -2256,7 +2242,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { } else { if (field_descriptor->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject* sub_message = InternalGetSubMessage(self, cdescriptor); + PyObject* sub_message = InternalGetSubMessage(self, field_descriptor); if (PyDict_SetItem(self->composite_fields, name, sub_message) < 0) { Py_DECREF(sub_message); return NULL; @@ -2278,12 +2264,10 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) { return -1; } - PyObject* descriptor = GetDescriptor(self, name); - if (descriptor != NULL) { + const google::protobuf::FieldDescriptor* field_descriptor = + GetFieldDescriptor(self, name); + if (field_descriptor != NULL) { AssureWritable(self); - CFieldDescriptor* cdescriptor = - reinterpret_cast<CFieldDescriptor*>(descriptor); - const google::protobuf::FieldDescriptor* field_descriptor = cdescriptor->descriptor; if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { PyErr_Format(PyExc_AttributeError, "Assignment not allowed to repeated " "field \"%s\" in protocol message object.", @@ -2401,22 +2385,18 @@ void InitGlobals() { kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max); kDESCRIPTOR = PyString_FromString("DESCRIPTOR"); - k__descriptors = PyString_FromString("__descriptors"); + k_cdescriptor = PyString_FromString("_cdescriptor"); kfull_name = PyString_FromString("full_name"); - kis_extendable = PyString_FromString("is_extendable"); kextensions_by_name = PyString_FromString("extensions_by_name"); k_extensions_by_name = PyString_FromString("_extensions_by_name"); k_extensions_by_number = PyString_FromString("_extensions_by_number"); - k_concrete_class = PyString_FromString("_concrete_class"); - kmessage_type = PyString_FromString("message_type"); kname = PyString_FromString("name"); kfields_by_name = PyString_FromString("fields_by_name"); - global_message_factory = new DynamicMessageFactory(GetDescriptorPool()); - global_message_factory->SetDelegateToGeneratedFactory(true); + descriptor_pool = cdescriptor_pool::NewDescriptorPool(); - descriptor_pool = reinterpret_cast<google::protobuf::python::CDescriptorPool*>( - Python_NewCDescriptorPool(NULL, NULL)); + global_message_factory = new DynamicMessageFactory(descriptor_pool->pool); + global_message_factory->SetDelegateToGeneratedFactory(true); } bool InitProto2MessageModule(PyObject *m) { @@ -2427,19 +2407,32 @@ bool InitProto2MessageModule(PyObject *m) { return false; } - // All three of these are actually set elsewhere, directly onto the child - // protocol buffer message class, but set them here as well to document that - // subclasses need to set these. + // DESCRIPTOR is set on each protocol buffer message class elsewhere, but set + // it here as well to document that subclasses need to set it. PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, kDESCRIPTOR, Py_None); - PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, - k_extensions_by_name, Py_None); - PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, - k_extensions_by_number, Py_None); + // Subclasses with message extensions will override _extensions_by_name and + // _extensions_by_number with fresh mutable dictionaries in AddDescriptors. + // All other classes can share this same immutable mapping. + ScopedPyObjectPtr empty_dict(PyDict_New()); + if (empty_dict == NULL) { + return false; + } + ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict)); + if (immutable_dict == NULL) { + return false; + } + if (PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, + k_extensions_by_name, immutable_dict) < 0) { + return false; + } + if (PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, + k_extensions_by_number, immutable_dict) < 0) { + return false; + } PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>( &google::protobuf::python::CMessage_Type)); - google::protobuf::python::RepeatedScalarContainer_Type.tp_new = PyType_GenericNew; google::protobuf::python::RepeatedScalarContainer_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&google::protobuf::python::RepeatedScalarContainer_Type) < 0) { @@ -2450,7 +2443,6 @@ bool InitProto2MessageModule(PyObject *m) { reinterpret_cast<PyObject*>( &google::protobuf::python::RepeatedScalarContainer_Type)); - google::protobuf::python::RepeatedCompositeContainer_Type.tp_new = PyType_GenericNew; google::protobuf::python::RepeatedCompositeContainer_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&google::protobuf::python::RepeatedCompositeContainer_Type) < 0) { @@ -2462,7 +2454,6 @@ bool InitProto2MessageModule(PyObject *m) { reinterpret_cast<PyObject*>( &google::protobuf::python::RepeatedCompositeContainer_Type)); - google::protobuf::python::ExtensionDict_Type.tp_new = PyType_GenericNew; google::protobuf::python::ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&google::protobuf::python::ExtensionDict_Type) < 0) { return false; |