Skip to content

Commit a05c57d

Browse files
Mark sequence containers as Py_TPFLAGS_SEQUENCE, enabling pattern matching
PEP634 introduces structural pattern matching. This works out of the box for most parts of protobuf messages, but fails for sequence matching (defined in https://peps.python.org/pep-0634/#sequence-patterns). This is caused by the underlying containers missing the newly introduced Py_TPFLAGS_SEQUENCE flag (see python/cpython@069e81a). This simply adds the flag, making the following fall into the first case: ``` message = test_pb2.TestMessage(int_sequence=(1, 2, 3)) match message: case test_pb2.TestMessage(int_sequence=(1, *rest)): print(f"message.int_sequence is a seq starting with 1, ending in {rest}") case _: print(f"No case on 'int_sequence' matched! Value: {message.int_sequence}") ``` PiperOrigin-RevId: 524326722
1 parent a1ba8d2 commit a05c57d

File tree

2 files changed

+43
-35
lines changed

2 files changed

+43
-35
lines changed

python/google/protobuf/pyext/repeated_composite_container.cc

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -549,22 +549,26 @@ PyTypeObject RepeatedCompositeContainer_Type = {
549549
#if PY_VERSION_HEX >= 0x03080000
550550
0, // tp_vectorcall_offset
551551
#else
552-
nullptr, // tp_print
552+
nullptr, // tp_print
553+
#endif
554+
nullptr, // tp_getattr
555+
nullptr, // tp_setattr
556+
nullptr, // tp_compare
557+
repeated_composite_container::ToStr, // tp_repr
558+
nullptr, // tp_as_number
559+
&repeated_composite_container::SqMethods, // tp_as_sequence
560+
&repeated_composite_container::MpMethods, // tp_as_mapping
561+
PyObject_HashNotImplemented, // tp_hash
562+
nullptr, // tp_call
563+
nullptr, // tp_str
564+
nullptr, // tp_getattro
565+
nullptr, // tp_setattro
566+
nullptr, // tp_as_buffer
567+
#if PY_VERSION_HEX >= 0x030A0000
568+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_SEQUENCE, // tp_flags
569+
#else
570+
Py_TPFLAGS_DEFAULT, // tp_flags
553571
#endif
554-
nullptr, // tp_getattr
555-
nullptr, // tp_setattr
556-
nullptr, // tp_compare
557-
repeated_composite_container::ToStr, // tp_repr
558-
nullptr, // tp_as_number
559-
&repeated_composite_container::SqMethods, // tp_as_sequence
560-
&repeated_composite_container::MpMethods, // tp_as_mapping
561-
PyObject_HashNotImplemented, // tp_hash
562-
nullptr, // tp_call
563-
nullptr, // tp_str
564-
nullptr, // tp_getattro
565-
nullptr, // tp_setattro
566-
nullptr, // tp_as_buffer
567-
Py_TPFLAGS_DEFAULT, // tp_flags
568572
"A Repeated scalar container", // tp_doc
569573
nullptr, // tp_traverse
570574
nullptr, // tp_clear

python/google/protobuf/pyext/repeated_scalar_container.cc

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -728,29 +728,33 @@ static PyMethodDef Methods[] = {
728728

729729
PyTypeObject RepeatedScalarContainer_Type = {
730730
PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
731-
".RepeatedScalarContainer", // tp_name
732-
sizeof(RepeatedScalarContainer), // tp_basicsize
733-
0, // tp_itemsize
734-
repeated_scalar_container::Dealloc, // tp_dealloc
731+
".RepeatedScalarContainer", // tp_name
732+
sizeof(RepeatedScalarContainer), // tp_basicsize
733+
0, // tp_itemsize
734+
repeated_scalar_container::Dealloc, // tp_dealloc
735735
#if PY_VERSION_HEX >= 0x03080000
736-
0, // tp_vectorcall_offset
736+
0, // tp_vectorcall_offset
737737
#else
738-
nullptr, // tp_print
738+
nullptr, // tp_print
739+
#endif
740+
nullptr, // tp_getattr
741+
nullptr, // tp_setattr
742+
nullptr, // tp_compare
743+
repeated_scalar_container::ToStr, // tp_repr
744+
nullptr, // tp_as_number
745+
&repeated_scalar_container::SqMethods, // tp_as_sequence
746+
&repeated_scalar_container::MpMethods, // tp_as_mapping
747+
PyObject_HashNotImplemented, // tp_hash
748+
nullptr, // tp_call
749+
nullptr, // tp_str
750+
nullptr, // tp_getattro
751+
nullptr, // tp_setattro
752+
nullptr, // tp_as_buffer
753+
#if PY_VERSION_HEX >= 0x030A0000
754+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_SEQUENCE, // tp_flags
755+
#else
756+
Py_TPFLAGS_DEFAULT, // tp_flags
739757
#endif
740-
nullptr, // tp_getattr
741-
nullptr, // tp_setattr
742-
nullptr, // tp_compare
743-
repeated_scalar_container::ToStr, // tp_repr
744-
nullptr, // tp_as_number
745-
&repeated_scalar_container::SqMethods, // tp_as_sequence
746-
&repeated_scalar_container::MpMethods, // tp_as_mapping
747-
PyObject_HashNotImplemented, // tp_hash
748-
nullptr, // tp_call
749-
nullptr, // tp_str
750-
nullptr, // tp_getattro
751-
nullptr, // tp_setattro
752-
nullptr, // tp_as_buffer
753-
Py_TPFLAGS_DEFAULT, // tp_flags
754758
"A Repeated scalar container", // tp_doc
755759
nullptr, // tp_traverse
756760
nullptr, // tp_clear

0 commit comments

Comments
 (0)