Skip to content

Commit

Permalink
Mark sequence containers as Py_TPFLAGS_SEQUENCE, enabling pattern mat…
Browse files Browse the repository at this point in the history
…ching

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
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Apr 14, 2023
1 parent a1ba8d2 commit a05c57d
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 35 deletions.
34 changes: 19 additions & 15 deletions python/google/protobuf/pyext/repeated_composite_container.cc
Original file line number Diff line number Diff line change
Expand Up @@ -549,22 +549,26 @@ PyTypeObject RepeatedCompositeContainer_Type = {
#if PY_VERSION_HEX >= 0x03080000
0, // tp_vectorcall_offset
#else
nullptr, // tp_print
nullptr, // tp_print
#endif
nullptr, // tp_getattr
nullptr, // tp_setattr
nullptr, // tp_compare
repeated_composite_container::ToStr, // tp_repr
nullptr, // tp_as_number
&repeated_composite_container::SqMethods, // tp_as_sequence
&repeated_composite_container::MpMethods, // tp_as_mapping
PyObject_HashNotImplemented, // tp_hash
nullptr, // tp_call
nullptr, // tp_str
nullptr, // tp_getattro
nullptr, // tp_setattro
nullptr, // tp_as_buffer
#if PY_VERSION_HEX >= 0x030A0000
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_SEQUENCE, // tp_flags
#else
Py_TPFLAGS_DEFAULT, // tp_flags
#endif
nullptr, // tp_getattr
nullptr, // tp_setattr
nullptr, // tp_compare
repeated_composite_container::ToStr, // tp_repr
nullptr, // tp_as_number
&repeated_composite_container::SqMethods, // tp_as_sequence
&repeated_composite_container::MpMethods, // tp_as_mapping
PyObject_HashNotImplemented, // tp_hash
nullptr, // tp_call
nullptr, // tp_str
nullptr, // tp_getattro
nullptr, // tp_setattro
nullptr, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"A Repeated scalar container", // tp_doc
nullptr, // tp_traverse
nullptr, // tp_clear
Expand Down
44 changes: 24 additions & 20 deletions python/google/protobuf/pyext/repeated_scalar_container.cc
Original file line number Diff line number Diff line change
Expand Up @@ -728,29 +728,33 @@ static PyMethodDef Methods[] = {

PyTypeObject RepeatedScalarContainer_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
".RepeatedScalarContainer", // tp_name
sizeof(RepeatedScalarContainer), // tp_basicsize
0, // tp_itemsize
repeated_scalar_container::Dealloc, // tp_dealloc
".RepeatedScalarContainer", // tp_name
sizeof(RepeatedScalarContainer), // tp_basicsize
0, // tp_itemsize
repeated_scalar_container::Dealloc, // tp_dealloc
#if PY_VERSION_HEX >= 0x03080000
0, // tp_vectorcall_offset
0, // tp_vectorcall_offset
#else
nullptr, // tp_print
nullptr, // tp_print
#endif
nullptr, // tp_getattr
nullptr, // tp_setattr
nullptr, // tp_compare
repeated_scalar_container::ToStr, // tp_repr
nullptr, // tp_as_number
&repeated_scalar_container::SqMethods, // tp_as_sequence
&repeated_scalar_container::MpMethods, // tp_as_mapping
PyObject_HashNotImplemented, // tp_hash
nullptr, // tp_call
nullptr, // tp_str
nullptr, // tp_getattro
nullptr, // tp_setattro
nullptr, // tp_as_buffer
#if PY_VERSION_HEX >= 0x030A0000
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_SEQUENCE, // tp_flags
#else
Py_TPFLAGS_DEFAULT, // tp_flags
#endif
nullptr, // tp_getattr
nullptr, // tp_setattr
nullptr, // tp_compare
repeated_scalar_container::ToStr, // tp_repr
nullptr, // tp_as_number
&repeated_scalar_container::SqMethods, // tp_as_sequence
&repeated_scalar_container::MpMethods, // tp_as_mapping
PyObject_HashNotImplemented, // tp_hash
nullptr, // tp_call
nullptr, // tp_str
nullptr, // tp_getattro
nullptr, // tp_setattro
nullptr, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"A Repeated scalar container", // tp_doc
nullptr, // tp_traverse
nullptr, // tp_clear
Expand Down

0 comments on commit a05c57d

Please sign in to comment.