21
21
#include " absl/strings/numbers.h"
22
22
#include " absl/strings/str_replace.h"
23
23
#include " absl/strings/str_split.h"
24
+ #include " absl/strings/string_view.h"
24
25
#include " absl/types/optional.h"
25
26
#include " pybind11_protobuf/check_unknown_fields.h"
26
27
@@ -534,10 +535,8 @@ class PythonDescriptorPoolWrapper {
534
535
}
535
536
}
536
537
537
- py::object wire = py_file_descriptor.attr (" serialized_pb" );
538
- const char * bytes = PYBIND11_BYTES_AS_STRING (wire.ptr ());
539
- return output->ParsePartialFromArray (bytes,
540
- PYBIND11_BYTES_SIZE (wire.ptr ()));
538
+ return output->ParsePartialFromString (
539
+ PyBytesAsStringView (py_file_descriptor.attr (" serialized_pb" )));
541
540
}
542
541
543
542
py::object pool_; // never dereferenced.
@@ -549,6 +548,11 @@ class PythonDescriptorPoolWrapper {
549
548
550
549
} // namespace
551
550
551
+ absl::string_view PyBytesAsStringView (py::bytes py_bytes) {
552
+ return absl::string_view (PyBytes_AsString (py_bytes.ptr ()),
553
+ PyBytes_Size (py_bytes.ptr ()));
554
+ }
555
+
552
556
void InitializePybindProtoCastUtil () {
553
557
assert (PyGILState_Check ());
554
558
GlobalState::instance ();
@@ -593,7 +597,7 @@ const Message* PyProtoGetCppMessagePointer(py::handle src) {
593
597
#endif
594
598
}
595
599
596
- absl::optional<std::string> PyProtoDescriptorName (py::handle py_proto) {
600
+ absl::optional<std::string> PyProtoDescriptorFullName (py::handle py_proto) {
597
601
assert (PyGILState_Check ());
598
602
auto py_full_name = ResolveAttrs (py_proto, {" DESCRIPTOR" , " full_name" });
599
603
if (py_full_name) {
@@ -602,66 +606,42 @@ absl::optional<std::string> PyProtoDescriptorName(py::handle py_proto) {
602
606
return absl::nullopt;
603
607
}
604
608
605
- bool PyProtoIsCompatible (py::handle py_proto, const Descriptor* descriptor) {
606
- assert (PyGILState_Check ());
607
- if (descriptor->file ()->pool () != DescriptorPool::generated_pool ()) {
608
- // / This indicates that the C++ descriptor does not come from the C++
609
- // / DescriptorPool. This may happen if the C++ code has the same proto
610
- // / in different descriptor pools, perhaps from different shared objects,
611
- // / and could be result in undefined behavior.
612
- return false ;
613
- }
614
-
615
- auto py_descriptor = ResolveAttrs (py_proto, {" DESCRIPTOR" });
616
- if (!py_descriptor) {
617
- // Not a valid protobuf -- missing DESCRIPTOR.
618
- return false ;
619
- }
620
-
621
- // Test full_name equivalence.
622
- {
623
- auto py_full_name = ResolveAttrs (*py_descriptor, {" full_name" });
624
- if (!py_full_name) {
625
- // Not a valid protobuf -- missing DESCRIPTOR.full_name
626
- return false ;
627
- }
628
- auto full_name = CastToOptionalString (*py_full_name);
629
- if (!full_name || *full_name != descriptor->full_name ()) {
630
- // Name mismatch.
631
- return false ;
632
- }
633
- }
634
-
635
- // The C++ descriptor is compiled in (see above assert), so the py_proto
636
- // is expected to be from the global pool, i.e. the DESCRIPTOR.file.pool
637
- // instance is the global python pool, and not a custom pool.
638
- auto py_pool = ResolveAttrs (*py_descriptor, {" file" , " pool" });
639
- if (py_pool) {
640
- return py_pool->is (GlobalState::instance ()->global_pool ());
641
- }
642
-
643
- // The py_proto is missing a DESCRIPTOR.file.pool, but the name matches.
644
- // This will not happen with a native python implementation, but does
645
- // occur with the deprecated :proto_casters, and could happen with other
646
- // mocks. Returning true allows the caster to call PyProtoCopyToCProto.
647
- return true ;
609
+ bool PyProtoHasMatchingFullName (py::handle py_proto,
610
+ const Descriptor* descriptor) {
611
+ auto full_name = PyProtoDescriptorFullName (py_proto);
612
+ return full_name && *full_name == descriptor->full_name ();
648
613
}
649
614
650
- bool PyProtoCopyToCProto (py::handle py_proto, Message* message) {
651
- assert (PyGILState_Check ());
652
- auto serialize_fn = ResolveAttrMRO (py_proto, " SerializePartialToString" );
615
+ py::bytes PyProtoSerializePartialToString (py::handle py_proto,
616
+ bool raise_if_error) {
617
+ static const char * serialize_fn_name = " SerializePartialToString" ;
618
+ auto serialize_fn = ResolveAttrMRO (py_proto, serialize_fn_name);
653
619
if (!serialize_fn) {
654
- throw py::type_error (
655
- " SerializePartialToString method not found; is this a " +
656
- message->GetDescriptor ()->full_name ());
657
- }
658
- auto wire = (*serialize_fn)();
659
- const char * bytes = PYBIND11_BYTES_AS_STRING (wire.ptr ());
660
- if (!bytes) {
661
- throw py::type_error (" SerializePartialToString failed; is this a " +
662
- message->GetDescriptor ()->full_name ());
620
+ return py::object ();
621
+ }
622
+ auto serialized_bytes = py::reinterpret_steal<py::object>(
623
+ PyObject_CallObject (serialize_fn->ptr (), nullptr ));
624
+ if (!serialized_bytes) {
625
+ if (raise_if_error) {
626
+ std::string msg = py::repr (py_proto).cast <std::string>() + " ." +
627
+ serialize_fn_name + " () function call FAILED" ;
628
+ py::raise_from (PyExc_TypeError, msg.c_str ());
629
+ throw py::error_already_set ();
630
+ }
631
+ return py::object ();
632
+ }
633
+ if (!PyBytes_Check (serialized_bytes.ptr ())) {
634
+ if (raise_if_error) {
635
+ std::string msg = py::repr (py_proto).cast <std::string>() + " ." +
636
+ serialize_fn_name +
637
+ " () function call is expected to return bytes, but the "
638
+ " returned value is " +
639
+ py::repr (serialized_bytes).cast <std::string>();
640
+ throw py::type_error (msg);
641
+ }
642
+ return py::object ();
663
643
}
664
- return message-> ParsePartialFromArray (bytes, PYBIND11_BYTES_SIZE (wire. ptr ())) ;
644
+ return serialized_bytes ;
665
645
}
666
646
667
647
void CProtoCopyToPyProto (Message* message, py::handle py_proto) {
@@ -686,7 +666,8 @@ std::unique_ptr<Message> AllocateCProtoFromPythonSymbolDatabase(
686
666
assert (PyGILState_Check ());
687
667
auto pool = ResolveAttrs (src, {" DESCRIPTOR" , " file" , " pool" });
688
668
if (!pool) {
689
- throw py::type_error (" Object is not a valid protobuf" );
669
+ throw py::type_error (py::repr (src).cast <std::string>() +
670
+ " object is not a valid protobuf" );
690
671
}
691
672
692
673
auto pool_data =
0 commit comments