repeated_composite_container.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: anuraag@google.com (Anuraag Agrawal)
  31. // Author: tibell@google.com (Johan Tibell)
  32. #include <google/protobuf/pyext/repeated_composite_container.h>
  33. #include <memory>
  34. #ifndef _SHARED_PTR_H
  35. #include <google/protobuf/stubs/shared_ptr.h>
  36. #endif
  37. #include <google/protobuf/stubs/logging.h>
  38. #include <google/protobuf/stubs/common.h>
  39. #include <google/protobuf/descriptor.h>
  40. #include <google/protobuf/dynamic_message.h>
  41. #include <google/protobuf/message.h>
  42. #include <google/protobuf/pyext/descriptor.h>
  43. #include <google/protobuf/pyext/descriptor_pool.h>
  44. #include <google/protobuf/pyext/message.h>
  45. #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
  46. #if PY_MAJOR_VERSION >= 3
  47. #define PyInt_Check PyLong_Check
  48. #define PyInt_AsLong PyLong_AsLong
  49. #define PyInt_FromLong PyLong_FromLong
  50. #endif
  51. namespace google {
  52. namespace protobuf {
  53. namespace python {
  54. namespace repeated_composite_container {
  55. // TODO(tibell): We might also want to check:
  56. // GOOGLE_CHECK_NOTNULL((self)->owner.get());
  57. #define GOOGLE_CHECK_ATTACHED(self) \
  58. do { \
  59. GOOGLE_CHECK_NOTNULL((self)->message); \
  60. GOOGLE_CHECK_NOTNULL((self)->parent_field_descriptor); \
  61. } while (0);
  62. #define GOOGLE_CHECK_RELEASED(self) \
  63. do { \
  64. GOOGLE_CHECK((self)->owner.get() == NULL); \
  65. GOOGLE_CHECK((self)->message == NULL); \
  66. GOOGLE_CHECK((self)->parent_field_descriptor == NULL); \
  67. GOOGLE_CHECK((self)->parent == NULL); \
  68. } while (0);
  69. // ---------------------------------------------------------------------
  70. // len()
  71. static Py_ssize_t Length(RepeatedCompositeContainer* self) {
  72. Message* message = self->message;
  73. if (message != NULL) {
  74. return message->GetReflection()->FieldSize(*message,
  75. self->parent_field_descriptor);
  76. } else {
  77. // The container has been released (i.e. by a call to Clear() or
  78. // ClearField() on the parent) and thus there's no message.
  79. return PyList_GET_SIZE(self->child_messages);
  80. }
  81. }
  82. // Returns 0 if successful; returns -1 and sets an exception if
  83. // unsuccessful.
  84. static int UpdateChildMessages(RepeatedCompositeContainer* self) {
  85. if (self->message == NULL)
  86. return 0;
  87. // A MergeFrom on a parent message could have caused extra messages to be
  88. // added in the underlying protobuf so add them to our list. They can never
  89. // be removed in such a way so there's no need to worry about that.
  90. Py_ssize_t message_length = Length(self);
  91. Py_ssize_t child_length = PyList_GET_SIZE(self->child_messages);
  92. Message* message = self->message;
  93. const Reflection* reflection = message->GetReflection();
  94. for (Py_ssize_t i = child_length; i < message_length; ++i) {
  95. const Message& sub_message = reflection->GetRepeatedMessage(
  96. *(self->message), self->parent_field_descriptor, i);
  97. CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init,
  98. sub_message.GetDescriptor());
  99. ScopedPyObjectPtr py_cmsg(reinterpret_cast<PyObject*>(cmsg));
  100. if (cmsg == NULL) {
  101. return -1;
  102. }
  103. cmsg->owner = self->owner;
  104. cmsg->message = const_cast<Message*>(&sub_message);
  105. cmsg->parent = self->parent;
  106. if (PyList_Append(self->child_messages, py_cmsg) < 0) {
  107. return -1;
  108. }
  109. }
  110. return 0;
  111. }
  112. // ---------------------------------------------------------------------
  113. // add()
  114. static PyObject* AddToAttached(RepeatedCompositeContainer* self,
  115. PyObject* args,
  116. PyObject* kwargs) {
  117. GOOGLE_CHECK_ATTACHED(self);
  118. if (UpdateChildMessages(self) < 0) {
  119. return NULL;
  120. }
  121. if (cmessage::AssureWritable(self->parent) == -1)
  122. return NULL;
  123. Message* message = self->message;
  124. Message* sub_message =
  125. message->GetReflection()->AddMessage(message,
  126. self->parent_field_descriptor);
  127. CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init,
  128. sub_message->GetDescriptor());
  129. if (cmsg == NULL)
  130. return NULL;
  131. cmsg->owner = self->owner;
  132. cmsg->message = sub_message;
  133. cmsg->parent = self->parent;
  134. if (cmessage::InitAttributes(cmsg, kwargs) < 0) {
  135. Py_DECREF(cmsg);
  136. return NULL;
  137. }
  138. PyObject* py_cmsg = reinterpret_cast<PyObject*>(cmsg);
  139. if (PyList_Append(self->child_messages, py_cmsg) < 0) {
  140. Py_DECREF(py_cmsg);
  141. return NULL;
  142. }
  143. return py_cmsg;
  144. }
  145. static PyObject* AddToReleased(RepeatedCompositeContainer* self,
  146. PyObject* args,
  147. PyObject* kwargs) {
  148. GOOGLE_CHECK_RELEASED(self);
  149. // Create a new Message detached from the rest.
  150. PyObject* py_cmsg = PyEval_CallObjectWithKeywords(
  151. self->subclass_init, NULL, kwargs);
  152. if (py_cmsg == NULL)
  153. return NULL;
  154. if (PyList_Append(self->child_messages, py_cmsg) < 0) {
  155. Py_DECREF(py_cmsg);
  156. return NULL;
  157. }
  158. return py_cmsg;
  159. }
  160. PyObject* Add(RepeatedCompositeContainer* self,
  161. PyObject* args,
  162. PyObject* kwargs) {
  163. if (self->message == NULL)
  164. return AddToReleased(self, args, kwargs);
  165. else
  166. return AddToAttached(self, args, kwargs);
  167. }
  168. // ---------------------------------------------------------------------
  169. // extend()
  170. PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) {
  171. cmessage::AssureWritable(self->parent);
  172. if (UpdateChildMessages(self) < 0) {
  173. return NULL;
  174. }
  175. ScopedPyObjectPtr iter(PyObject_GetIter(value));
  176. if (iter == NULL) {
  177. PyErr_SetString(PyExc_TypeError, "Value must be iterable");
  178. return NULL;
  179. }
  180. ScopedPyObjectPtr next;
  181. while ((next.reset(PyIter_Next(iter))) != NULL) {
  182. if (!PyObject_TypeCheck(next, &CMessage_Type)) {
  183. PyErr_SetString(PyExc_TypeError, "Not a cmessage");
  184. return NULL;
  185. }
  186. ScopedPyObjectPtr new_message(Add(self, NULL, NULL));
  187. if (new_message == NULL) {
  188. return NULL;
  189. }
  190. CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get());
  191. if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next)) == NULL) {
  192. return NULL;
  193. }
  194. }
  195. if (PyErr_Occurred()) {
  196. return NULL;
  197. }
  198. Py_RETURN_NONE;
  199. }
  200. PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other) {
  201. if (UpdateChildMessages(self) < 0) {
  202. return NULL;
  203. }
  204. return Extend(self, other);
  205. }
  206. PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice) {
  207. if (UpdateChildMessages(self) < 0) {
  208. return NULL;
  209. }
  210. // Just forward the call to the subscript-handling function of the
  211. // list containing the child messages.
  212. return PyObject_GetItem(self->child_messages, slice);
  213. }
  214. int AssignSubscript(RepeatedCompositeContainer* self,
  215. PyObject* slice,
  216. PyObject* value) {
  217. if (UpdateChildMessages(self) < 0) {
  218. return -1;
  219. }
  220. if (value != NULL) {
  221. PyErr_SetString(PyExc_TypeError, "does not support assignment");
  222. return -1;
  223. }
  224. // Delete from the underlying Message, if any.
  225. if (self->parent != NULL) {
  226. if (cmessage::InternalDeleteRepeatedField(self->parent,
  227. self->parent_field_descriptor,
  228. slice,
  229. self->child_messages) < 0) {
  230. return -1;
  231. }
  232. } else {
  233. Py_ssize_t from;
  234. Py_ssize_t to;
  235. Py_ssize_t step;
  236. Py_ssize_t length = Length(self);
  237. Py_ssize_t slicelength;
  238. if (PySlice_Check(slice)) {
  239. #if PY_MAJOR_VERSION >= 3
  240. if (PySlice_GetIndicesEx(slice,
  241. #else
  242. if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice),
  243. #endif
  244. length, &from, &to, &step, &slicelength) == -1) {
  245. return -1;
  246. }
  247. return PySequence_DelSlice(self->child_messages, from, to);
  248. } else if (PyInt_Check(slice) || PyLong_Check(slice)) {
  249. from = to = PyLong_AsLong(slice);
  250. if (from < 0) {
  251. from = to = length + from;
  252. }
  253. return PySequence_DelItem(self->child_messages, from);
  254. }
  255. }
  256. return 0;
  257. }
  258. static PyObject* Remove(RepeatedCompositeContainer* self, PyObject* value) {
  259. if (UpdateChildMessages(self) < 0) {
  260. return NULL;
  261. }
  262. Py_ssize_t index = PySequence_Index(self->child_messages, value);
  263. if (index == -1) {
  264. return NULL;
  265. }
  266. ScopedPyObjectPtr py_index(PyLong_FromLong(index));
  267. if (AssignSubscript(self, py_index, NULL) < 0) {
  268. return NULL;
  269. }
  270. Py_RETURN_NONE;
  271. }
  272. static PyObject* RichCompare(RepeatedCompositeContainer* self,
  273. PyObject* other,
  274. int opid) {
  275. if (UpdateChildMessages(self) < 0) {
  276. return NULL;
  277. }
  278. if (!PyObject_TypeCheck(other, &RepeatedCompositeContainer_Type)) {
  279. PyErr_SetString(PyExc_TypeError,
  280. "Can only compare repeated composite fields "
  281. "against other repeated composite fields.");
  282. return NULL;
  283. }
  284. if (opid == Py_EQ || opid == Py_NE) {
  285. // TODO(anuraag): Don't make new lists just for this...
  286. ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
  287. if (full_slice == NULL) {
  288. return NULL;
  289. }
  290. ScopedPyObjectPtr list(Subscript(self, full_slice));
  291. if (list == NULL) {
  292. return NULL;
  293. }
  294. ScopedPyObjectPtr other_list(
  295. Subscript(
  296. reinterpret_cast<RepeatedCompositeContainer*>(other), full_slice));
  297. if (other_list == NULL) {
  298. return NULL;
  299. }
  300. return PyObject_RichCompare(list, other_list, opid);
  301. } else {
  302. Py_INCREF(Py_NotImplemented);
  303. return Py_NotImplemented;
  304. }
  305. }
  306. // ---------------------------------------------------------------------
  307. // sort()
  308. static void ReorderAttached(RepeatedCompositeContainer* self) {
  309. Message* message = self->message;
  310. const Reflection* reflection = message->GetReflection();
  311. const FieldDescriptor* descriptor = self->parent_field_descriptor;
  312. const Py_ssize_t length = Length(self);
  313. // Since Python protobuf objects are never arena-allocated, adding and
  314. // removing message pointers to the underlying array is just updating
  315. // pointers.
  316. for (Py_ssize_t i = 0; i < length; ++i)
  317. reflection->ReleaseLast(message, descriptor);
  318. for (Py_ssize_t i = 0; i < length; ++i) {
  319. CMessage* py_cmsg = reinterpret_cast<CMessage*>(
  320. PyList_GET_ITEM(self->child_messages, i));
  321. reflection->AddAllocatedMessage(message, descriptor, py_cmsg->message);
  322. }
  323. }
  324. // Returns 0 if successful; returns -1 and sets an exception if
  325. // unsuccessful.
  326. static int SortPythonMessages(RepeatedCompositeContainer* self,
  327. PyObject* args,
  328. PyObject* kwds) {
  329. ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort"));
  330. if (m == NULL)
  331. return -1;
  332. if (PyObject_Call(m, args, kwds) == NULL)
  333. return -1;
  334. if (self->message != NULL) {
  335. ReorderAttached(self);
  336. }
  337. return 0;
  338. }
  339. static PyObject* Sort(RepeatedCompositeContainer* self,
  340. PyObject* args,
  341. PyObject* kwds) {
  342. // Support the old sort_function argument for backwards
  343. // compatibility.
  344. if (kwds != NULL) {
  345. PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function");
  346. if (sort_func != NULL) {
  347. // Must set before deleting as sort_func is a borrowed reference
  348. // and kwds might be the only thing keeping it alive.
  349. PyDict_SetItemString(kwds, "cmp", sort_func);
  350. PyDict_DelItemString(kwds, "sort_function");
  351. }
  352. }
  353. if (UpdateChildMessages(self) < 0) {
  354. return NULL;
  355. }
  356. if (SortPythonMessages(self, args, kwds) < 0) {
  357. return NULL;
  358. }
  359. Py_RETURN_NONE;
  360. }
  361. // ---------------------------------------------------------------------
  362. static PyObject* Item(RepeatedCompositeContainer* self, Py_ssize_t index) {
  363. if (UpdateChildMessages(self) < 0) {
  364. return NULL;
  365. }
  366. Py_ssize_t length = Length(self);
  367. if (index < 0) {
  368. index = length + index;
  369. }
  370. PyObject* item = PyList_GetItem(self->child_messages, index);
  371. if (item == NULL) {
  372. return NULL;
  373. }
  374. Py_INCREF(item);
  375. return item;
  376. }
  377. static PyObject* Pop(RepeatedCompositeContainer* self,
  378. PyObject* args) {
  379. Py_ssize_t index = -1;
  380. if (!PyArg_ParseTuple(args, "|n", &index)) {
  381. return NULL;
  382. }
  383. PyObject* item = Item(self, index);
  384. if (item == NULL) {
  385. PyErr_Format(PyExc_IndexError,
  386. "list index (%zd) out of range",
  387. index);
  388. return NULL;
  389. }
  390. ScopedPyObjectPtr py_index(PyLong_FromSsize_t(index));
  391. if (AssignSubscript(self, py_index, NULL) < 0) {
  392. return NULL;
  393. }
  394. return item;
  395. }
  396. // Release field of parent message and transfer the ownership to target.
  397. void ReleaseLastTo(CMessage* parent,
  398. const FieldDescriptor* field,
  399. CMessage* target) {
  400. GOOGLE_CHECK_NOTNULL(parent);
  401. GOOGLE_CHECK_NOTNULL(field);
  402. GOOGLE_CHECK_NOTNULL(target);
  403. shared_ptr<Message> released_message(
  404. parent->message->GetReflection()->ReleaseLast(parent->message, field));
  405. // TODO(tibell): Deal with proto1.
  406. target->parent = NULL;
  407. target->parent_field_descriptor = NULL;
  408. target->message = released_message.get();
  409. target->read_only = false;
  410. cmessage::SetOwner(target, released_message);
  411. }
  412. // Called to release a container using
  413. // ClearField('container_field_name') on the parent.
  414. int Release(RepeatedCompositeContainer* self) {
  415. if (UpdateChildMessages(self) < 0) {
  416. PyErr_WriteUnraisable(PyBytes_FromString("Failed to update released "
  417. "messages"));
  418. return -1;
  419. }
  420. Message* message = self->message;
  421. const FieldDescriptor* field = self->parent_field_descriptor;
  422. // The reflection API only lets us release the last message in a
  423. // repeated field. Therefore we iterate through the children
  424. // starting with the last one.
  425. const Py_ssize_t size = PyList_GET_SIZE(self->child_messages);
  426. GOOGLE_DCHECK_EQ(size, message->GetReflection()->FieldSize(*message, field));
  427. for (Py_ssize_t i = size - 1; i >= 0; --i) {
  428. CMessage* child_cmessage = reinterpret_cast<CMessage*>(
  429. PyList_GET_ITEM(self->child_messages, i));
  430. ReleaseLastTo(self->parent, field, child_cmessage);
  431. }
  432. // Detach from containing message.
  433. self->parent = NULL;
  434. self->parent_field_descriptor = NULL;
  435. self->message = NULL;
  436. self->owner.reset();
  437. return 0;
  438. }
  439. int SetOwner(RepeatedCompositeContainer* self,
  440. const shared_ptr<Message>& new_owner) {
  441. GOOGLE_CHECK_ATTACHED(self);
  442. self->owner = new_owner;
  443. const Py_ssize_t n = PyList_GET_SIZE(self->child_messages);
  444. for (Py_ssize_t i = 0; i < n; ++i) {
  445. PyObject* msg = PyList_GET_ITEM(self->child_messages, i);
  446. if (cmessage::SetOwner(reinterpret_cast<CMessage*>(msg), new_owner) == -1) {
  447. return -1;
  448. }
  449. }
  450. return 0;
  451. }
  452. // The private constructor of RepeatedCompositeContainer objects.
  453. PyObject *NewContainer(
  454. CMessage* parent,
  455. const FieldDescriptor* parent_field_descriptor,
  456. PyObject *concrete_class) {
  457. if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
  458. return NULL;
  459. }
  460. RepeatedCompositeContainer* self =
  461. reinterpret_cast<RepeatedCompositeContainer*>(
  462. PyType_GenericAlloc(&RepeatedCompositeContainer_Type, 0));
  463. if (self == NULL) {
  464. return NULL;
  465. }
  466. self->message = parent->message;
  467. self->parent = parent;
  468. self->parent_field_descriptor = parent_field_descriptor;
  469. self->owner = parent->owner;
  470. Py_INCREF(concrete_class);
  471. self->subclass_init = concrete_class;
  472. self->child_messages = PyList_New(0);
  473. return reinterpret_cast<PyObject*>(self);
  474. }
  475. static void Dealloc(RepeatedCompositeContainer* self) {
  476. Py_CLEAR(self->child_messages);
  477. Py_CLEAR(self->subclass_init);
  478. // TODO(tibell): Do we need to call delete on these objects to make
  479. // sure their destructors are called?
  480. self->owner.reset();
  481. Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
  482. }
  483. static PySequenceMethods SqMethods = {
  484. (lenfunc)Length, /* sq_length */
  485. 0, /* sq_concat */
  486. 0, /* sq_repeat */
  487. (ssizeargfunc)Item /* sq_item */
  488. };
  489. static PyMappingMethods MpMethods = {
  490. (lenfunc)Length, /* mp_length */
  491. (binaryfunc)Subscript, /* mp_subscript */
  492. (objobjargproc)AssignSubscript,/* mp_ass_subscript */
  493. };
  494. static PyMethodDef Methods[] = {
  495. { "add", (PyCFunction) Add, METH_VARARGS | METH_KEYWORDS,
  496. "Adds an object to the repeated container." },
  497. { "extend", (PyCFunction) Extend, METH_O,
  498. "Adds objects to the repeated container." },
  499. { "pop", (PyCFunction)Pop, METH_VARARGS,
  500. "Removes an object from the repeated container and returns it." },
  501. { "remove", (PyCFunction) Remove, METH_O,
  502. "Removes an object from the repeated container." },
  503. { "sort", (PyCFunction) Sort, METH_VARARGS | METH_KEYWORDS,
  504. "Sorts the repeated container." },
  505. { "MergeFrom", (PyCFunction) MergeFrom, METH_O,
  506. "Adds objects to the repeated container." },
  507. { NULL, NULL }
  508. };
  509. } // namespace repeated_composite_container
  510. PyTypeObject RepeatedCompositeContainer_Type = {
  511. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  512. FULL_MODULE_NAME ".RepeatedCompositeContainer", // tp_name
  513. sizeof(RepeatedCompositeContainer), // tp_basicsize
  514. 0, // tp_itemsize
  515. (destructor)repeated_composite_container::Dealloc, // tp_dealloc
  516. 0, // tp_print
  517. 0, // tp_getattr
  518. 0, // tp_setattr
  519. 0, // tp_compare
  520. 0, // tp_repr
  521. 0, // tp_as_number
  522. &repeated_composite_container::SqMethods, // tp_as_sequence
  523. &repeated_composite_container::MpMethods, // tp_as_mapping
  524. PyObject_HashNotImplemented, // tp_hash
  525. 0, // tp_call
  526. 0, // tp_str
  527. 0, // tp_getattro
  528. 0, // tp_setattro
  529. 0, // tp_as_buffer
  530. Py_TPFLAGS_DEFAULT, // tp_flags
  531. "A Repeated scalar container", // tp_doc
  532. 0, // tp_traverse
  533. 0, // tp_clear
  534. (richcmpfunc)repeated_composite_container::RichCompare, // tp_richcompare
  535. 0, // tp_weaklistoffset
  536. 0, // tp_iter
  537. 0, // tp_iternext
  538. repeated_composite_container::Methods, // tp_methods
  539. 0, // tp_members
  540. 0, // tp_getset
  541. 0, // tp_base
  542. 0, // tp_dict
  543. 0, // tp_descr_get
  544. 0, // tp_descr_set
  545. 0, // tp_dictoffset
  546. 0, // tp_init
  547. };
  548. } // namespace python
  549. } // namespace protobuf
  550. } // namespace google