Initial commit of ExtensionDict.
diff --git a/python/BUILD b/python/BUILD
index 1e02677..9060d01 100644
--- a/python/BUILD
+++ b/python/BUILD
@@ -39,6 +39,8 @@
"descriptor_containers.h",
"descriptor_pool.c",
"descriptor_pool.h",
+ "extension_dict.c",
+ "extension_dict.h",
"map.c",
"map.h",
"message.c",
diff --git a/python/extension_dict.c b/python/extension_dict.c
new file mode 100644
index 0000000..a46dfc6
--- /dev/null
+++ b/python/extension_dict.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2009-2021, Google LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google LLC nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "python/extension_dict.h"
+
+#include "python/message.h"
+#include "python/protobuf.h"
+
+// -----------------------------------------------------------------------------
+// ExtensionDict
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ PyObject_HEAD
+ PyObject* msg; // Owning ref to our parent pessage.
+} PyUpb_ExtensionDict;
+
+PyObject* PyUpb_ExtensionDict_New(PyObject* msg) {
+ PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
+ PyUpb_ExtensionDict* ext_dict =
+ (void*)PyType_GenericAlloc(state->extension_dict_type, 0);
+ ext_dict->msg = msg;
+ Py_INCREF(ext_dict->msg);
+ return &ext_dict->ob_base;
+}
+
+static PyObject* PyUpb_ExtensionDict_FindExtensionByName(PyObject* _self,
+ PyObject* key) {
+ PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
+ const char* name = PyUpb_GetStrData(key);
+ const upb_msgdef* m = PyUpb_CMessage_GetMsgdef(self->msg);
+ const upb_filedef* file = upb_msgdef_file(m);
+ const upb_symtab* symtab = upb_filedef_symtab(file);
+ const upb_fielddef* ext = upb_symtab_lookupext(symtab, name);
+ if (ext) {
+ return PyUpb_FieldDescriptor_Get(ext);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static PyObject* PyUpb_ExtensionDict_FindExtensionByNumber(PyObject* _self,
+ PyObject* arg) {
+ PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
+ const upb_msgdef* m = PyUpb_CMessage_GetMsgdef(self->msg);
+ const upb_msglayout* l = upb_msgdef_layout(m);
+ const upb_filedef* file = upb_msgdef_file(m);
+ const upb_symtab* symtab = upb_filedef_symtab(file);
+ const upb_extreg* reg = upb_symtab_extreg(symtab);
+ int64_t number = PyLong_AsLong(arg);
+ const upb_msglayout_ext* ext =
+ (upb_msglayout_ext*)_upb_extreg_get(reg, l, number);
+ if (ext) {
+ const upb_fielddef* f = _upb_symtab_lookupextfield(symtab, ext);
+ return PyUpb_FieldDescriptor_Get(f);
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+static void PyUpb_ExtensionDict_Dealloc(PyUpb_ExtensionDict* self) {
+ PyUpb_CMessage_ClearExtensionDict(self->msg);
+ Py_DECREF(self->msg);
+ PyUpb_Dealloc(self);
+}
+
+static Py_ssize_t PyUpb_ExtensionDict_Length(PyObject* _self) {
+ PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
+ upb_msg* msg = PyUpb_CMessage_GetIfReified(self->msg);
+ return msg ? upb_msg_extcount(msg) : 0;
+}
+
+static PyObject* PyUpb_ExtensionDict_Subscript(PyObject* _self, PyObject* key) {
+ PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
+ const upb_fielddef* f = PyUpb_FieldDescriptor_GetDef(key);
+ if (!f) return NULL;
+ if (!upb_fielddef_isextension(f)) {
+ return PyErr_Format(PyExc_KeyError, "Field %s is not an extension\n",
+ upb_fielddef_fullname(f));
+ }
+ return PyUpb_CMessage_GetFieldValue(self->msg, f);
+}
+
+int PyUpb_ExtensionDict_AssignSubscript(PyObject* _self, PyObject* key,
+ PyObject* val) {
+ PyUpb_ExtensionDict* self = (PyUpb_ExtensionDict*)_self;
+ const upb_fielddef* f = PyUpb_FieldDescriptor_GetDef(key);
+ if (!f) return -1;
+ if (!upb_fielddef_isextension(f)) {
+ PyErr_Format(PyExc_KeyError, "Field %s is not an extension\n",
+ upb_fielddef_fullname(f));
+ return -1;
+ }
+ return PyUpb_CMessage_SetFieldValue(self->msg, f, val);
+}
+
+static PyMethodDef PyUpb_ExtensionDict_Methods[] = {
+ {"_FindExtensionByName", PyUpb_ExtensionDict_FindExtensionByName, METH_O,
+ "Finds an extension by name."},
+ {"_FindExtensionByNumber", PyUpb_ExtensionDict_FindExtensionByNumber,
+ METH_O, "Finds an extension by number."},
+ {NULL, NULL},
+};
+
+static PyType_Slot PyUpb_ExtensionDict_Slots[] = {
+ {Py_tp_dealloc, PyUpb_ExtensionDict_Dealloc},
+ {Py_tp_methods, PyUpb_ExtensionDict_Methods},
+ //{Py_tp_getset, PyUpb_ExtensionDict_Getters},
+ //{Py_tp_hash, PyObject_HashNotImplemented},
+ //{Py_tp_richcompare, PyUpb_ExtensionDict_RichCompare},
+ //{Py_tp_iter, PyUpb_ExtensionDict_GetIter},
+ {Py_sq_length, PyUpb_ExtensionDict_Length},
+ //{Py_sq_contains, PyUpb_ExtensionDict_Contains},
+ {Py_mp_length, PyUpb_ExtensionDict_Length},
+ {Py_mp_subscript, PyUpb_ExtensionDict_Subscript},
+ {Py_mp_ass_subscript, PyUpb_ExtensionDict_AssignSubscript},
+ {0, NULL}};
+
+static PyType_Spec PyUpb_ExtensionDict_Spec = {
+ PYUPB_MODULE_NAME ".ExtensionDict", // tp_name
+ sizeof(PyUpb_ExtensionDict), // tp_basicsize
+ 0, // tp_itemsize
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ PyUpb_ExtensionDict_Slots,
+};
+
+// -----------------------------------------------------------------------------
+// ExtensionIterator
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ PyObject_HEAD
+ PyObject* arena;
+} PyUpb_ExtensionIterator;
+
+static void PyUpb_ExtensionIterator_Dealloc(PyUpb_ExtensionDict* self) {
+ PyUpb_Dealloc(self);
+}
+
+static PyType_Slot PyUpb_ExtensionIterator_Slots[] = {
+ {Py_tp_dealloc, PyUpb_ExtensionIterator_Dealloc},
+ {Py_tp_iter, PyObject_SelfIter},
+ //{Py_tp_iter, PyUpb_ExtensionIterator_GetIter},
+ //{Py_tp_iternext, PyUpb_ExtensionIterator_IterNext},
+ {0, NULL}};
+
+static PyType_Spec PyUpb_ExtensionIterator_Spec = {
+ PYUPB_MODULE_NAME ".ExtensionIterator", // tp_name
+ sizeof(PyUpb_ExtensionDict), // tp_basicsize
+ 0, // tp_itemsize
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ PyUpb_ExtensionIterator_Slots,
+};
+
+// -----------------------------------------------------------------------------
+// Top Level
+// -----------------------------------------------------------------------------
+
+bool PyUpb_InitExtensionDict(PyObject* m) {
+ PyUpb_ModuleState* s = PyUpb_ModuleState_GetFromModule(m);
+
+ s->extension_dict_type = PyUpb_AddClass(m, &PyUpb_ExtensionDict_Spec);
+ s->extension_iterator_type = PyUpb_AddClass(m, &PyUpb_ExtensionIterator_Spec);
+
+ return s->extension_dict_type && s->extension_iterator_type;
+}
diff --git a/python/extension_dict.h b/python/extension_dict.h
new file mode 100644
index 0000000..f8a8fc4
--- /dev/null
+++ b/python/extension_dict.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009-2021, Google LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google LLC nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PYUPB_EXTENSION_DICT_H__
+#define PYUPB_EXTENSION_DICT_H__
+
+#include <stdbool.h>
+
+#include "python/python.h"
+
+PyObject* PyUpb_ExtensionDict_New(PyObject* msg);
+
+bool PyUpb_InitExtensionDict(PyObject* m);
+
+#endif // PYUPB_EXTENSION_DICT_H__
diff --git a/python/message.c b/python/message.c
index 5ca51d7..b0df698 100644
--- a/python/message.c
+++ b/python/message.c
@@ -29,6 +29,7 @@
#include "python/convert.h"
#include "python/descriptor.h"
+#include "python/extension_dict.h"
#include "python/map.h"
#include "python/repeated.h"
#include "upb/def.h"
@@ -1241,11 +1242,8 @@
return NULL;
}
- // TODO(haberman): re-enable when ExtensionDict is checked in.
- // self->ext_dict = PyUpb_ExtensionDict_New(_self);
- // return self->ext_dict;
- PyErr_SetString(PyExc_NotImplementedError, "get extension dict");
- return NULL;
+ self->ext_dict = PyUpb_ExtensionDict_New(_self);
+ return self->ext_dict;
}
static PyGetSetDef PyUpb_CMessage_Getters[] = {
diff --git a/python/pb_unit_tests/generator_test_wrapper.py b/python/pb_unit_tests/generator_test_wrapper.py
index ea78705..92435cb 100644
--- a/python/pb_unit_tests/generator_test_wrapper.py
+++ b/python/pb_unit_tests/generator_test_wrapper.py
@@ -26,7 +26,6 @@
from google.protobuf.internal import generator_test
import unittest
-generator_test.GeneratorTest.testBadIdentifiers.__unittest_expecting_failure__ = True
generator_test.GeneratorTest.testExtensionScope.__unittest_expecting_failure__ = True
generator_test.GeneratorTest.testMessageWithCustomOptions.__unittest_expecting_failure__ = True
generator_test.GeneratorTest.testOneof.__unittest_expecting_failure__ = True
diff --git a/python/pb_unit_tests/json_format_test_wrapper.py b/python/pb_unit_tests/json_format_test_wrapper.py
index 8a929bd..fa72856 100644
--- a/python/pb_unit_tests/json_format_test_wrapper.py
+++ b/python/pb_unit_tests/json_format_test_wrapper.py
@@ -32,7 +32,6 @@
json_format_test.JsonFormatTest.testDurationMessage.__unittest_expecting_failure__ = True
json_format_test.JsonFormatTest.testEmptyMessageToJson.__unittest_expecting_failure__ = True
json_format_test.JsonFormatTest.testExtensionSerializationDictMatchesProto3Spec.__unittest_expecting_failure__ = True
-json_format_test.JsonFormatTest.testExtensionSerializationDictMatchesProto3SpecMore.__unittest_expecting_failure__ = True
json_format_test.JsonFormatTest.testExtensionSerializationJsonMatchesProto3Spec.__unittest_expecting_failure__ = True
json_format_test.JsonFormatTest.testExtensionToDictAndBack.__unittest_expecting_failure__ = True
json_format_test.JsonFormatTest.testExtensionToDictAndBackWithScalar.__unittest_expecting_failure__ = True
diff --git a/python/pb_unit_tests/keywords_test_wrapper.py b/python/pb_unit_tests/keywords_test_wrapper.py
index bca227e..1863b88 100644
--- a/python/pb_unit_tests/keywords_test_wrapper.py
+++ b/python/pb_unit_tests/keywords_test_wrapper.py
@@ -26,8 +26,5 @@
from google.protobuf.internal import keywords_test
import unittest
-keywords_test.KeywordsConflictTest.testExtension.__unittest_expecting_failure__ = True
-keywords_test.KeywordsConflictTest.testExtensionForNestedMessage.__unittest_expecting_failure__ = True
-
if __name__ == '__main__':
unittest.main(module=keywords_test, verbosity=2)
diff --git a/python/pb_unit_tests/message_test_wrapper.py b/python/pb_unit_tests/message_test_wrapper.py
index 198769f..323067c 100644
--- a/python/pb_unit_tests/message_test_wrapper.py
+++ b/python/pb_unit_tests/message_test_wrapper.py
@@ -55,7 +55,6 @@
message_test.Proto2Test.testExtensionsErrors.__unittest_expecting_failure__ = True
message_test.Proto2Test.testGoldenExtensions.__unittest_expecting_failure__ = True
message_test.Proto2Test.testGoldenPackedExtensions.__unittest_expecting_failure__ = True
-message_test.Proto2Test.testMergeFromExtensions.__unittest_expecting_failure__ = True
message_test.Proto2Test.testParsingMerge.__unittest_expecting_failure__ = True
message_test.Proto2Test.testPickleIncompleteProto.__unittest_expecting_failure__ = True
message_test.Proto2Test.testPythonicInit.__unittest_expecting_failure__ = True
diff --git a/python/pb_unit_tests/reflection_test_wrapper.py b/python/pb_unit_tests/reflection_test_wrapper.py
index a9eff07..a80d239 100644
--- a/python/pb_unit_tests/reflection_test_wrapper.py
+++ b/python/pb_unit_tests/reflection_test_wrapper.py
@@ -26,12 +26,6 @@
from google.protobuf.internal import reflection_test
import unittest
-reflection_test.ByteSizeTest.testCacheInvalidationForNonrepeatedMessage.__unittest_expecting_failure__ = True
-reflection_test.ByteSizeTest.testCacheInvalidationForNonrepeatedScalar.__unittest_expecting_failure__ = True
-reflection_test.ByteSizeTest.testCacheInvalidationForRepeatedMessage.__unittest_expecting_failure__ = True
-reflection_test.ByteSizeTest.testCacheInvalidationForRepeatedScalar.__unittest_expecting_failure__ = True
-reflection_test.ByteSizeTest.testExtensions.__unittest_expecting_failure__ = True
-reflection_test.ByteSizeTest.testPackedExtensions.__unittest_expecting_failure__ = True
reflection_test.ByteSizeTest.testRepeatedCompositesDelete.__unittest_expecting_failure__ = True
reflection_test.ByteSizeTest.testRepeatedScalarsRemove.__unittest_expecting_failure__ = True
reflection_test.ClassAPITest.testMakeClassWithNestedDescriptor.__unittest_expecting_failure__ = True
@@ -40,17 +34,12 @@
reflection_test.OptionsTest.testMessageOptions.__unittest_expecting_failure__ = True
reflection_test.OptionsTest.testPackedOptions.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testClear.__unittest_expecting_failure__ = True
-reflection_test.Proto2ReflectionTest.testDisconnectionAfterClearingEmptyMessage.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testExtensionContainsError.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testExtensionDelete.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testExtensionFailureModes.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testExtensionIter.__unittest_expecting_failure__ = True
-reflection_test.Proto2ReflectionTest.testHasBitsForAncestorsOfExtendedMessage.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testIsInitialized.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testListFieldsAndExtensions.__unittest_expecting_failure__ = True
-reflection_test.Proto2ReflectionTest.testMergeFromExtensionsNestedMessage.__unittest_expecting_failure__ = True
-reflection_test.Proto2ReflectionTest.testMergeFromExtensionsRepeated.__unittest_expecting_failure__ = True
-reflection_test.Proto2ReflectionTest.testMergeFromExtensionsSingular.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testNestedExtensions.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testRepeatedCompositeConstructor.__unittest_expecting_failure__ = True
reflection_test.Proto2ReflectionTest.testRepeatedCompositeRemove.__unittest_expecting_failure__ = True
@@ -108,7 +97,6 @@
reflection_test.SerializationTest.testInitRequiredForeignKwargs.__unittest_expecting_failure__ = True
reflection_test.SerializationTest.testInitRequiredKwargs.__unittest_expecting_failure__ = True
reflection_test.SerializationTest.testMessageSetWireFormat.__unittest_expecting_failure__ = True
-reflection_test.SerializationTest.testMessageSetWireFormatUnknownExtension.__unittest_expecting_failure__ = True
reflection_test.SerializationTest.testParsePackedFromUnpacked.__unittest_expecting_failure__ = True
reflection_test.SerializationTest.testParseUnpackedFromPacked.__unittest_expecting_failure__ = True
reflection_test.SerializationTest.testSerializeAllExtensions.__unittest_expecting_failure__ = True
diff --git a/python/pb_unit_tests/text_format_test_wrapper.py b/python/pb_unit_tests/text_format_test_wrapper.py
index 1f8f065..db7cf93 100644
--- a/python/pb_unit_tests/text_format_test_wrapper.py
+++ b/python/pb_unit_tests/text_format_test_wrapper.py
@@ -41,12 +41,8 @@
text_format_test.OnlyWorksWithProto2RightNowTests.testPrintMapUsingCppImplementation.__unittest_expecting_failure__ = True
text_format_test.OnlyWorksWithProto2RightNowTests.testPrintUnknownFields.__unittest_expecting_failure__ = True
text_format_test.Proto2Tests.testExtensionInsideAnyMessage.__unittest_expecting_failure__ = True
-text_format_test.Proto2Tests.testMergeDuplicateExtensionScalars.__unittest_expecting_failure__ = True
text_format_test.Proto2Tests.testParseAllExtensions.__unittest_expecting_failure__ = True
text_format_test.Proto2Tests.testParseAllowedUnknownExtension.__unittest_expecting_failure__ = True
-text_format_test.Proto2Tests.testParseBadExtension.__unittest_expecting_failure__ = True
-text_format_test.Proto2Tests.testParseDuplicateExtensionMessages.__unittest_expecting_failure__ = True
-text_format_test.Proto2Tests.testParseDuplicateExtensionScalars.__unittest_expecting_failure__ = True
text_format_test.Proto2Tests.testParseGoldenExtensions.__unittest_expecting_failure__ = True
text_format_test.Proto2Tests.testParseMap.__unittest_expecting_failure__ = True
text_format_test.Proto2Tests.testParseMessageByFieldNumber.__unittest_expecting_failure__ = True
diff --git a/python/protobuf.c b/python/protobuf.c
index 19fc36f..c577281 100644
--- a/python/protobuf.c
+++ b/python/protobuf.c
@@ -30,6 +30,7 @@
#include "python/descriptor.h"
#include "python/descriptor_containers.h"
#include "python/descriptor_pool.h"
+#include "python/extension_dict.h"
#include "python/map.h"
#include "python/message.h"
#include "python/repeated.h"
@@ -305,7 +306,8 @@
state->obj_cache = PyUpb_WeakMap_New();
if (!PyUpb_InitDescriptorContainers(m) || !PyUpb_InitDescriptorPool(m) ||
- !PyUpb_InitDescriptor(m) || !PyUpb_InitArena(m) || !PyUpb_Map_Init(m) ||
+ !PyUpb_InitDescriptor(m) || !PyUpb_InitArena(m) ||
+ !PyUpb_InitExtensionDict(m) || !PyUpb_Map_Init(m) ||
!PyUpb_InitMessage(m) || !PyUpb_Repeated_Init(m)) {
Py_DECREF(m);
return NULL;
diff --git a/python/protobuf.h b/python/protobuf.h
index 6fe04b5..fa9785a 100644
--- a/python/protobuf.h
+++ b/python/protobuf.h
@@ -64,6 +64,10 @@
// From descriptor_pool.c
PyTypeObject *descriptor_pool_type;
+ // From extension_dict.c
+ PyTypeObject* extension_dict_type;
+ PyTypeObject* extension_iterator_type;
+
// From map.c
PyTypeObject* map_iterator_type;
PyTypeObject* message_map_container_type;