Fixed or accounted for nearly all errors in message_test.
diff --git a/python/message.c b/python/message.c
index b0df698..fd0d37e 100644
--- a/python/message.c
+++ b/python/message.c
@@ -847,9 +847,12 @@
PyObject* ret = PyObject_GenericGetAttr(_self, attr);
if (ret) return ret;
- // If the attribute wasn't found, look for attributes on the class. But if a
- // different kind of error (other than AttributeError) was found, return that.
- if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ // Swallow AttributeError if it occurred and try again on the metaclass
+ // to pick up class attributes. But we have to special-case "Extensions"
+ // which affirmatively returns AttributeError when a message is not
+ // extendable.
+ if (PyErr_ExceptionMatches(PyExc_AttributeError) &&
+ strcmp(PyUpb_GetStrData(attr), "Extensions") != 0) {
PyErr_Clear();
return PyUpb_MessageMeta_GetAttr((PyObject*)Py_TYPE(_self), attr);
}
@@ -986,11 +989,14 @@
const upb_extreg* extreg = upb_symtab_extreg(upb_filedef_symtab(file));
const upb_msglayout* layout = upb_msgdef_layout(msgdef);
upb_arena* arena = PyUpb_Arena_Get(self->arena);
+ int options = 0;
+ PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
+ options |=
+ UPB_DECODE_MAXDEPTH(state->allow_oversize_protos ? UINT32_MAX : 100);
upb_DecodeStatus status =
- _upb_decode(buf, size, self->ptr.msg, layout, extreg, 0, arena);
+ _upb_decode(buf, size, self->ptr.msg, layout, extreg, options, arena);
Py_XDECREF(bytes);
if (status != kUpb_DecodeStatus_Ok) {
- PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
PyErr_Format(state->decode_error_class, "Error parsing message");
return NULL;
}
@@ -1183,6 +1189,8 @@
int options = 0;
if (check_required) options |= UPB_ENCODE_CHECKREQUIRED;
if (deterministic) options |= UPB_ENCODE_DETERMINISTIC;
+ // Python does not currently have any effective limit on serialization depth.
+ options |= UPB_ENCODE_MAXDEPTH(UINT32_MAX);
char* pb = upb_encode_ex(self->ptr.msg, layout, options, arena, &size);
PyObject* ret = NULL;
@@ -1248,10 +1256,6 @@
static PyGetSetDef PyUpb_CMessage_Getters[] = {
{"Extensions", PyUpb_CMessage_GetExtensionDict, NULL, "Extension dict"},
- /*
- {"_extensions_by_name", (getter)GetExtensionsByName, NULL},
- {"_extensions_by_number", (getter)GetExtensionsByNumber, NULL},
- */
{NULL}};
static PyMethodDef PyUpb_CMessage_Methods[] = {
diff --git a/python/minimal_test.py b/python/minimal_test.py
index 26d6553..01eef6e 100644
--- a/python/minimal_test.py
+++ b/python/minimal_test.py
@@ -32,6 +32,9 @@
from google.protobuf.internal import api_implementation
from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pool
+from google.protobuf import text_format
+from google.protobuf import message_factory
+from google.protobuf import message
from google.protobuf.internal import factory_test1_pb2
from google.protobuf.internal import factory_test2_pb2
from google.protobuf import descriptor_pb2
@@ -72,9 +75,35 @@
test_slice(11, 3, -2)
test_slice(11, 3, -3)
test_slice(10, 25, 4)
+
+ def testExtensionsErrors(self):
+ msg = unittest_pb2.TestAllTypes()
+ self.assertRaises(AttributeError, getattr, msg, 'Extensions')
#TestMessageExtension.test_descriptor_pool.__unittest_expecting_failure__ = True
+class OversizeProtosTest(unittest.TestCase):
+ def setUp(self):
+ msg = unittest_pb2.NestedTestAllTypes()
+ m = msg
+ for i in range(101):
+ m = m.child
+ m.Clear()
+ self.p_serialized = msg.SerializeToString()
+
+ def testAssertOversizeProto(self):
+ from google.protobuf.pyext._message import SetAllowOversizeProtos
+ SetAllowOversizeProtos(False)
+ q = unittest_pb2.NestedTestAllTypes()
+ with self.assertRaises(message.DecodeError):
+ q.ParseFromString(self.p_serialized)
+ print(q)
+
+ def testSucceedOversizeProto(self):
+ from google.protobuf.pyext._message import SetAllowOversizeProtos
+ SetAllowOversizeProtos(True)
+ q = unittest_pb2.NestedTestAllTypes()
+ q.ParseFromString(self.p_serialized)
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/python/pb_unit_tests/message_test_wrapper.py b/python/pb_unit_tests/message_test_wrapper.py
index 993f8e0..d73997b 100644
--- a/python/pb_unit_tests/message_test_wrapper.py
+++ b/python/pb_unit_tests/message_test_wrapper.py
@@ -26,28 +26,29 @@
from google.protobuf.internal import message_test
import unittest
-message_test.MessageTest.testBadUtf8String_proto2.__unittest_expecting_failure__ = True
-message_test.MessageTest.testBadUtf8String_proto3.__unittest_expecting_failure__ = True
+# We don't want to support extending repeated fields with nothing; this behavior
+# is marked for deprecation in the existing library.
message_test.MessageTest.testExtendFloatWithNothing_proto2.__unittest_expecting_failure__ = True
message_test.MessageTest.testExtendFloatWithNothing_proto3.__unittest_expecting_failure__ = True
message_test.MessageTest.testExtendInt32WithNothing_proto2.__unittest_expecting_failure__ = True
message_test.MessageTest.testExtendInt32WithNothing_proto3.__unittest_expecting_failure__ = True
message_test.MessageTest.testExtendStringWithNothing_proto2.__unittest_expecting_failure__ = True
message_test.MessageTest.testExtendStringWithNothing_proto3.__unittest_expecting_failure__ = True
+
+# Our float printing suffers from not having dtoa().
message_test.MessageTest.testFloatPrinting_proto2.__unittest_expecting_failure__ = True
message_test.MessageTest.testFloatPrinting_proto3.__unittest_expecting_failure__ = True
message_test.MessageTest.testHighPrecisionDoublePrinting_proto2.__unittest_expecting_failure__ = True
message_test.MessageTest.testHighPrecisionDoublePrinting_proto3.__unittest_expecting_failure__ = True
-message_test.MessageTest.testInsertRepeatedCompositeField_proto2.__unittest_expecting_failure__ = True
-message_test.MessageTest.testInsertRepeatedCompositeField_proto3.__unittest_expecting_failure__ = True
-message_test.Proto2Test.testExtensionsErrors.__unittest_expecting_failure__ = True
+
+# For these tests we are throwing the correct error, only the text of the error
+# message is a mismatch. For technical reasons around the limited API, matching
+# the existing error message exactly is not feasible.
+message_test.Proto3Test.testCopyFromBadType.__unittest_expecting_failure__ = True
+message_test.Proto3Test.testMergeFromBadType.__unittest_expecting_failure__ = True
+
message_test.Proto2Test.testPythonicInit.__unittest_expecting_failure__ = True
message_test.Proto2Test.test_documentation.__unittest_expecting_failure__ = True
-message_test.Proto3Test.testCopyFromBadType.__unittest_expecting_failure__ = True
-message_test.Proto3Test.testMapDeterministicSerialization.__unittest_expecting_failure__ = True
-message_test.Proto3Test.testMergeFromBadType.__unittest_expecting_failure__ = True
-message_test.OversizeProtosTest.testAssertOversizeProto.__unittest_expecting_failure__ = True
-message_test.OversizeProtosTest.testSucceedOversizeProto.__unittest_expecting_failure__ = True
if __name__ == '__main__':
unittest.main(module=message_test, verbosity=2)
diff --git a/python/pb_unit_tests/well_known_types_test_wrapper.py b/python/pb_unit_tests/well_known_types_test_wrapper.py
index 22a35d5..6ded8d4 100644
--- a/python/pb_unit_tests/well_known_types_test_wrapper.py
+++ b/python/pb_unit_tests/well_known_types_test_wrapper.py
@@ -26,7 +26,5 @@
from google.protobuf.internal import well_known_types_test
import unittest
-well_known_types_test.AnyTest.testPackDeterministic.__unittest_expecting_failure__ = True
-
if __name__ == '__main__':
unittest.main(module=well_known_types_test, verbosity=2)
diff --git a/python/protobuf.c b/python/protobuf.c
index c577281..8eb49a4 100644
--- a/python/protobuf.c
+++ b/python/protobuf.c
@@ -40,11 +40,28 @@
PyUpb_WeakMap_Free(s->obj_cache);
}
+PyObject* PyUpb_SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
+ if (!arg || !PyBool_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Argument to SetAllowOversizeProtos must be boolean");
+ return NULL;
+ }
+ PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
+ state->allow_oversize_protos = PyObject_IsTrue(arg);
+ Py_INCREF(arg);
+ return arg;
+}
+
+static PyMethodDef PyUpb_ModuleMethods[] = {
+ {"SetAllowOversizeProtos", PyUpb_SetAllowOversizeProtos, METH_O,
+ "Enable/disable oversize proto parsing."},
+ {NULL, NULL}};
+
static struct PyModuleDef module_def = {PyModuleDef_HEAD_INIT,
PYUPB_MODULE_NAME,
"Protobuf Module",
sizeof(PyUpb_ModuleState),
- NULL, // m_methods
+ PyUpb_ModuleMethods, // m_methods
NULL, // m_slots
NULL, // m_traverse
NULL, // m_clear
@@ -302,6 +319,7 @@
PyUpb_ModuleState *state = PyUpb_ModuleState_GetFromModule(m);
+ state->allow_oversize_protos = false;
state->wkt_bases = NULL;
state->obj_cache = PyUpb_WeakMap_New();
diff --git a/python/protobuf.h b/python/protobuf.h
index fa9785a..75c8e01 100644
--- a/python/protobuf.h
+++ b/python/protobuf.h
@@ -83,6 +83,7 @@
PyTypeObject *message_meta_type;
// From protobuf.c
+ bool allow_oversize_protos;
PyObject *wkt_bases;
PyTypeObject *arena_type;
PyUpb_WeakMap *obj_cache;