1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // Implements the DescriptorPool, which collects all descriptors.
9
10 #include <string>
11 #include <unordered_map>
12 #include <utility>
13 #include <vector>
14
15 #define PY_SSIZE_T_CLEAN
16 #include <Python.h>
17
18 #include "google/protobuf/descriptor.pb.h"
19 #include "absl/container/flat_hash_map.h"
20 #include "absl/status/status.h"
21 #include "absl/strings/str_cat.h"
22 #include "absl/strings/str_replace.h"
23 #include "absl/strings/string_view.h"
24 #include "google/protobuf/pyext/descriptor.h"
25 #include "google/protobuf/pyext/descriptor_database.h"
26 #include "google/protobuf/pyext/descriptor_pool.h"
27 #include "google/protobuf/pyext/message.h"
28 #include "google/protobuf/pyext/message_factory.h"
29 #include "google/protobuf/pyext/scoped_pyobject_ptr.h"
30
31 // Must be included last.
32 #include "google/protobuf/port_def.inc"
33
34 #define PyString_AsStringAndSize(ob, charpp, sizep) \
35 (PyUnicode_Check(ob) \
36 ? ((*(charpp) = const_cast<char*>( \
37 PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
38 ? -1 \
39 : 0) \
40 : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
41
42 namespace google {
43 namespace protobuf {
44 namespace python {
45
46 // A map to cache Python Pools per C++ pointer.
47 // Pointers are not owned here, and belong to the PyDescriptorPool.
48 static std::unordered_map<const DescriptorPool*, PyDescriptorPool*>*
49 descriptor_pool_map;
50
51 namespace cdescriptor_pool {
52
53 // Collects errors that occur during proto file building to allow them to be
54 // propagated in the python exception instead of only living in ERROR logs.
55 class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
56 public:
BuildFileErrorCollector()57 BuildFileErrorCollector() : error_message(""), had_errors_(false) {}
58
RecordError(absl::string_view filename,absl::string_view element_name,const Message * descriptor,ErrorLocation location,absl::string_view message)59 void RecordError(absl::string_view filename, absl::string_view element_name,
60 const Message* descriptor, ErrorLocation location,
61 absl::string_view message) override {
62 // Replicates the logging behavior that happens in the C++ implementation
63 // when an error collector is not passed in.
64 if (!had_errors_) {
65 absl::StrAppend(&error_message, "Invalid proto descriptor for file \"",
66 filename, "\":\n");
67 had_errors_ = true;
68 }
69 // As this only happens on failure and will result in the program not
70 // running at all, no effort is made to optimize this string manipulation.
71 absl::StrAppend(&error_message, " ", element_name, ": ", message, "\n");
72 }
73
Clear()74 void Clear() {
75 had_errors_ = false;
76 error_message = "";
77 }
78
79 std::string error_message;
80
81 private:
82 bool had_errors_;
83 };
84
85 // Create a Python DescriptorPool object, but does not fill the "pool"
86 // attribute.
_CreateDescriptorPool()87 static PyDescriptorPool* _CreateDescriptorPool() {
88 PyDescriptorPool* cpool = PyObject_GC_New(
89 PyDescriptorPool, &PyDescriptorPool_Type);
90 if (cpool == nullptr) {
91 return nullptr;
92 }
93
94 cpool->error_collector = nullptr;
95 cpool->underlay = nullptr;
96 cpool->database = nullptr;
97 cpool->is_owned = false;
98 cpool->is_mutable = false;
99
100 cpool->descriptor_options = new absl::flat_hash_map<const void*, PyObject*>();
101 cpool->descriptor_features =
102 new absl::flat_hash_map<const void*, PyObject*>();
103
104 cpool->py_message_factory = message_factory::NewMessageFactory(
105 &PyMessageFactory_Type, cpool);
106 if (cpool->py_message_factory == nullptr) {
107 Py_DECREF(cpool);
108 return nullptr;
109 }
110
111 PyObject_GC_Track(cpool);
112
113 return cpool;
114 }
115
116 // Create a Python DescriptorPool, using the given pool as an underlay:
117 // new messages will be added to a custom pool, not to the underlay.
118 //
119 // Ownership of the underlay is not transferred, its pointer should
120 // stay alive.
PyDescriptorPool_NewWithUnderlay(const DescriptorPool * underlay)121 static PyDescriptorPool* PyDescriptorPool_NewWithUnderlay(
122 const DescriptorPool* underlay) {
123 PyDescriptorPool* cpool = _CreateDescriptorPool();
124 if (cpool == nullptr) {
125 return nullptr;
126 }
127 cpool->pool = new DescriptorPool(underlay);
128 cpool->is_owned = true;
129 cpool->is_mutable = true;
130 cpool->underlay = underlay;
131
132 if (!descriptor_pool_map->insert(
133 std::make_pair(cpool->pool, cpool)).second) {
134 // Should never happen -- would indicate an internal error / bug.
135 PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
136 return nullptr;
137 }
138
139 return cpool;
140 }
141
PyDescriptorPool_NewWithDatabase(DescriptorDatabase * database,bool use_deprecated_legacy_json_field_conflicts)142 static PyDescriptorPool* PyDescriptorPool_NewWithDatabase(
143 DescriptorDatabase* database,
144 bool use_deprecated_legacy_json_field_conflicts) {
145 PyDescriptorPool* cpool = _CreateDescriptorPool();
146 if (cpool == nullptr) {
147 return nullptr;
148 }
149 DescriptorPool* pool;
150 if (database != nullptr) {
151 cpool->error_collector = new BuildFileErrorCollector();
152 pool = new DescriptorPool(database, cpool->error_collector);
153 cpool->is_mutable = false;
154 cpool->database = database;
155 } else {
156 pool = new DescriptorPool();
157 cpool->is_mutable = true;
158 }
159 if (use_deprecated_legacy_json_field_conflicts) {
160 PROTOBUF_IGNORE_DEPRECATION_START
161 pool->UseDeprecatedLegacyJsonFieldConflicts();
162 PROTOBUF_IGNORE_DEPRECATION_STOP
163 }
164 cpool->pool = pool;
165 cpool->is_owned = true;
166
167 if (!descriptor_pool_map->insert(std::make_pair(cpool->pool, cpool)).second) {
168 // Should never happen -- would indicate an internal error / bug.
169 PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
170 return nullptr;
171 }
172
173 return cpool;
174 }
175
176 // The public DescriptorPool constructor.
New(PyTypeObject * type,PyObject * args,PyObject * kwargs)177 static PyObject* New(PyTypeObject* type,
178 PyObject* args, PyObject* kwargs) {
179 int use_deprecated_legacy_json_field_conflicts = 0;
180 static const char* kwlist[] = {"descriptor_db", nullptr};
181 PyObject* py_database = nullptr;
182 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O",
183 const_cast<char**>(kwlist), &py_database)) {
184 return nullptr;
185 }
186 DescriptorDatabase* database = nullptr;
187 if (py_database && py_database != Py_None) {
188 database = new PyDescriptorDatabase(py_database);
189 }
190 return reinterpret_cast<PyObject*>(PyDescriptorPool_NewWithDatabase(
191 database, use_deprecated_legacy_json_field_conflicts));
192 }
193
Dealloc(PyObject * pself)194 static void Dealloc(PyObject* pself) {
195 PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
196 descriptor_pool_map->erase(self->pool);
197 Py_CLEAR(self->py_message_factory);
198 for (auto it = self->descriptor_options->begin();
199 it != self->descriptor_options->end(); ++it) {
200 Py_DECREF(it->second);
201 }
202 delete self->descriptor_options;
203 for (auto it = self->descriptor_features->begin();
204 it != self->descriptor_features->end(); ++it) {
205 Py_DECREF(it->second);
206 }
207 delete self->descriptor_features;
208 delete self->database;
209 if (self->is_owned) {
210 delete self->pool;
211 }
212 delete self->error_collector;
213 Py_TYPE(self)->tp_free(pself);
214 }
215
GcTraverse(PyObject * pself,visitproc visit,void * arg)216 static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
217 PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
218 Py_VISIT(self->py_message_factory);
219 return 0;
220 }
221
GcClear(PyObject * pself)222 static int GcClear(PyObject* pself) {
223 PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
224 Py_CLEAR(self->py_message_factory);
225 return 0;
226 }
227
SetErrorFromCollector(DescriptorPool::ErrorCollector * self,const char * name,const char * error_type)228 PyObject* SetErrorFromCollector(DescriptorPool::ErrorCollector* self,
229 const char* name, const char* error_type) {
230 BuildFileErrorCollector* error_collector =
231 reinterpret_cast<BuildFileErrorCollector*>(self);
232 if (error_collector && !error_collector->error_message.empty()) {
233 PyErr_Format(PyExc_KeyError, "Couldn't build file for %s %.200s\n%s",
234 error_type, name, error_collector->error_message.c_str());
235 error_collector->Clear();
236 return nullptr;
237 }
238 PyErr_Format(PyExc_KeyError, "Couldn't find %s %.200s", error_type, name);
239 return nullptr;
240 }
241
FindMessageByName(PyObject * self,PyObject * arg)242 static PyObject* FindMessageByName(PyObject* self, PyObject* arg) {
243 Py_ssize_t name_size;
244 char* name;
245 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
246 return nullptr;
247 }
248
249 const Descriptor* message_descriptor =
250 reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMessageTypeByName(
251 absl::string_view(name, name_size));
252
253 if (message_descriptor == nullptr) {
254 return SetErrorFromCollector(
255 reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
256 "message");
257 }
258
259
260 return PyMessageDescriptor_FromDescriptor(message_descriptor);
261 }
262
263
264
265
FindFileByName(PyObject * self,PyObject * arg)266 static PyObject* FindFileByName(PyObject* self, PyObject* arg) {
267 Py_ssize_t name_size;
268 char* name;
269 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
270 return nullptr;
271 }
272
273 PyDescriptorPool* py_pool = reinterpret_cast<PyDescriptorPool*>(self);
274 const FileDescriptor* file_descriptor =
275 py_pool->pool->FindFileByName(absl::string_view(name, name_size));
276
277 if (file_descriptor == nullptr) {
278 return SetErrorFromCollector(py_pool->error_collector, name, "file");
279 }
280 return PyFileDescriptor_FromDescriptor(file_descriptor);
281 }
282
FindFieldByName(PyDescriptorPool * self,PyObject * arg)283 PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) {
284 Py_ssize_t name_size;
285 char* name;
286 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
287 return nullptr;
288 }
289
290 const FieldDescriptor* field_descriptor =
291 self->pool->FindFieldByName(absl::string_view(name, name_size));
292 if (field_descriptor == nullptr) {
293 return SetErrorFromCollector(self->error_collector, name, "field");
294 }
295
296
297 return PyFieldDescriptor_FromDescriptor(field_descriptor);
298 }
299
FindFieldByNameMethod(PyObject * self,PyObject * arg)300 static PyObject* FindFieldByNameMethod(PyObject* self, PyObject* arg) {
301 return FindFieldByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
302 }
303
FindExtensionByName(PyDescriptorPool * self,PyObject * arg)304 PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
305 Py_ssize_t name_size;
306 char* name;
307 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
308 return nullptr;
309 }
310
311 const FieldDescriptor* field_descriptor =
312 self->pool->FindExtensionByName(absl::string_view(name, name_size));
313 if (field_descriptor == nullptr) {
314 return SetErrorFromCollector(self->error_collector, name,
315 "extension field");
316 }
317
318
319 return PyFieldDescriptor_FromDescriptor(field_descriptor);
320 }
321
FindExtensionByNameMethod(PyObject * self,PyObject * arg)322 static PyObject* FindExtensionByNameMethod(PyObject* self, PyObject* arg) {
323 return FindExtensionByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
324 }
325
FindEnumTypeByName(PyDescriptorPool * self,PyObject * arg)326 PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
327 Py_ssize_t name_size;
328 char* name;
329 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
330 return nullptr;
331 }
332
333 const EnumDescriptor* enum_descriptor =
334 self->pool->FindEnumTypeByName(absl::string_view(name, name_size));
335 if (enum_descriptor == nullptr) {
336 return SetErrorFromCollector(self->error_collector, name, "enum");
337 }
338
339
340 return PyEnumDescriptor_FromDescriptor(enum_descriptor);
341 }
342
FindEnumTypeByNameMethod(PyObject * self,PyObject * arg)343 static PyObject* FindEnumTypeByNameMethod(PyObject* self, PyObject* arg) {
344 return FindEnumTypeByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
345 }
346
FindOneofByName(PyDescriptorPool * self,PyObject * arg)347 PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
348 Py_ssize_t name_size;
349 char* name;
350 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
351 return nullptr;
352 }
353
354 const OneofDescriptor* oneof_descriptor =
355 self->pool->FindOneofByName(absl::string_view(name, name_size));
356 if (oneof_descriptor == nullptr) {
357 return SetErrorFromCollector(self->error_collector, name, "oneof");
358 }
359
360
361 return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
362 }
363
FindOneofByNameMethod(PyObject * self,PyObject * arg)364 static PyObject* FindOneofByNameMethod(PyObject* self, PyObject* arg) {
365 return FindOneofByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
366 }
367
FindServiceByName(PyObject * self,PyObject * arg)368 static PyObject* FindServiceByName(PyObject* self, PyObject* arg) {
369 Py_ssize_t name_size;
370 char* name;
371 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
372 return nullptr;
373 }
374
375 const ServiceDescriptor* service_descriptor =
376 reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
377 absl::string_view(name, name_size));
378 if (service_descriptor == nullptr) {
379 return SetErrorFromCollector(
380 reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
381 "service");
382 }
383
384
385 return PyServiceDescriptor_FromDescriptor(service_descriptor);
386 }
387
FindMethodByName(PyObject * self,PyObject * arg)388 static PyObject* FindMethodByName(PyObject* self, PyObject* arg) {
389 Py_ssize_t name_size;
390 char* name;
391 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
392 return nullptr;
393 }
394
395 const MethodDescriptor* method_descriptor =
396 reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMethodByName(
397 absl::string_view(name, name_size));
398 if (method_descriptor == nullptr) {
399 return SetErrorFromCollector(
400 reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
401 "method");
402 }
403
404
405 return PyMethodDescriptor_FromDescriptor(method_descriptor);
406 }
407
FindFileContainingSymbol(PyObject * self,PyObject * arg)408 static PyObject* FindFileContainingSymbol(PyObject* self, PyObject* arg) {
409 Py_ssize_t name_size;
410 char* name;
411 if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
412 return nullptr;
413 }
414
415 const FileDescriptor* file_descriptor =
416 reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileContainingSymbol(
417 absl::string_view(name, name_size));
418 if (file_descriptor == nullptr) {
419 return SetErrorFromCollector(
420 reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
421 "symbol");
422 }
423
424
425 return PyFileDescriptor_FromDescriptor(file_descriptor);
426 }
427
FindExtensionByNumber(PyObject * self,PyObject * args)428 static PyObject* FindExtensionByNumber(PyObject* self, PyObject* args) {
429 PyObject* message_descriptor;
430 int number;
431 if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
432 return nullptr;
433 }
434 const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(
435 message_descriptor);
436 if (descriptor == nullptr) {
437 return nullptr;
438 }
439
440 const FieldDescriptor* extension_descriptor =
441 reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByNumber(
442 descriptor, number);
443 if (extension_descriptor == nullptr) {
444 BuildFileErrorCollector* error_collector =
445 reinterpret_cast<BuildFileErrorCollector*>(
446 reinterpret_cast<PyDescriptorPool*>(self)->error_collector);
447 if (error_collector && !error_collector->error_message.empty()) {
448 PyErr_Format(PyExc_KeyError, "Couldn't build file for Extension %.d\n%s",
449 number, error_collector->error_message.c_str());
450 error_collector->Clear();
451 return nullptr;
452 }
453 PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
454 return nullptr;
455 }
456
457
458 return PyFieldDescriptor_FromDescriptor(extension_descriptor);
459 }
460
FindAllExtensions(PyObject * self,PyObject * arg)461 static PyObject* FindAllExtensions(PyObject* self, PyObject* arg) {
462 const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(arg);
463 if (descriptor == nullptr) {
464 return nullptr;
465 }
466
467 std::vector<const FieldDescriptor*> extensions;
468 reinterpret_cast<PyDescriptorPool*>(self)->pool->FindAllExtensions(
469 descriptor, &extensions);
470
471 ScopedPyObjectPtr result(PyList_New(extensions.size()));
472 if (result == nullptr) {
473 return nullptr;
474 }
475 for (int i = 0; i < extensions.size(); i++) {
476 PyObject* extension = PyFieldDescriptor_FromDescriptor(extensions[i]);
477 if (extension == nullptr) {
478 return nullptr;
479 }
480 PyList_SET_ITEM(result.get(), i, extension); // Steals the reference.
481 }
482 return result.release();
483 }
484
485 // The code below loads new Descriptors from a serialized FileDescriptorProto.
AddSerializedFile(PyObject * pself,PyObject * serialized_pb)486 static PyObject* AddSerializedFile(PyObject* pself, PyObject* serialized_pb) {
487 PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
488 char* message_type;
489 Py_ssize_t message_len;
490
491 if (self->database != nullptr) {
492 PyErr_SetString(
493 PyExc_ValueError,
494 "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
495 "Add your file to the underlying database.");
496 return nullptr;
497 }
498 if (!self->is_mutable) {
499 PyErr_SetString(
500 PyExc_ValueError,
501 "This DescriptorPool is not mutable and cannot add new definitions.");
502 return nullptr;
503 }
504
505 if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
506 return nullptr;
507 }
508
509 FileDescriptorProto file_proto;
510 if (!file_proto.ParseFromArray(message_type, message_len)) {
511 PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
512 return nullptr;
513 }
514
515 // If the file was already part of a C++ library, all its descriptors are in
516 // the underlying pool. No need to do anything else.
517 const FileDescriptor* generated_file = nullptr;
518 if (self->underlay) {
519 generated_file = self->underlay->FindFileByName(file_proto.name());
520 }
521 if (generated_file != nullptr) {
522 return PyFileDescriptor_FromDescriptorWithSerializedPb(
523 generated_file, serialized_pb);
524 }
525
526 BuildFileErrorCollector error_collector;
527 const FileDescriptor* descriptor =
528 // Pool is mutable, we can remove the "const".
529 const_cast<DescriptorPool*>(self->pool)
530 ->BuildFileCollectingErrors(file_proto, &error_collector);
531 if (descriptor == nullptr) {
532 PyErr_Format(PyExc_TypeError,
533 "Couldn't build proto file into descriptor pool!\n%s",
534 error_collector.error_message.c_str());
535 return nullptr;
536 }
537
538
539 return PyFileDescriptor_FromDescriptorWithSerializedPb(
540 descriptor, serialized_pb);
541 }
542
Add(PyObject * self,PyObject * file_descriptor_proto)543 static PyObject* Add(PyObject* self, PyObject* file_descriptor_proto) {
544 ScopedPyObjectPtr serialized_pb(
545 PyObject_CallMethod(file_descriptor_proto, "SerializeToString", nullptr));
546 if (serialized_pb == nullptr) {
547 return nullptr;
548 }
549 return AddSerializedFile(self, serialized_pb.get());
550 }
551
SetFeatureSetDefaults(PyObject * pself,PyObject * pdefaults)552 static PyObject* SetFeatureSetDefaults(PyObject* pself, PyObject* pdefaults) {
553 PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
554
555 if (!self->is_mutable) {
556 PyErr_SetString(
557 PyExc_RuntimeError,
558 "This DescriptorPool is not mutable and cannot add new definitions.");
559 return nullptr;
560 }
561
562 if (!PyObject_TypeCheck(pdefaults, CMessage_Type)) {
563 PyErr_Format(PyExc_TypeError,
564 "SetFeatureSetDefaults called with invalid type: got %s.",
565 Py_TYPE(pdefaults)->tp_name);
566 return nullptr;
567 }
568
569 CMessage* defaults = reinterpret_cast<CMessage*>(pdefaults);
570 if (defaults->message->GetDescriptor() !=
571 FeatureSetDefaults::GetDescriptor()) {
572 PyErr_Format(
573 PyExc_TypeError,
574 "SetFeatureSetDefaults called with invalid type: "
575 " got %s.",
576 std::string(defaults->message->GetDescriptor()->full_name()).c_str());
577 return nullptr;
578 }
579
580 absl::Status status =
581 const_cast<DescriptorPool*>(self->pool)
582 ->SetFeatureSetDefaults(
583 *reinterpret_cast<FeatureSetDefaults*>(defaults->message));
584 if (!status.ok()) {
585 PyErr_SetString(PyExc_ValueError, std::string(status.message()).c_str());
586 return nullptr;
587 }
588 Py_RETURN_NONE;
589 }
590
591 static PyMethodDef Methods[] = {
592 {"Add", Add, METH_O,
593 "Adds the FileDescriptorProto and its types to this pool."},
594 {"AddSerializedFile", AddSerializedFile, METH_O,
595 "Adds a serialized FileDescriptorProto to this pool."},
596 {"SetFeatureSetDefaults", SetFeatureSetDefaults, METH_O,
597 "Sets the default feature mappings used during the build."},
598
599 {"FindFileByName", FindFileByName, METH_O,
600 "Searches for a file descriptor by its .proto name."},
601 {"FindMessageTypeByName", FindMessageByName, METH_O,
602 "Searches for a message descriptor by full name."},
603 {"FindFieldByName", FindFieldByNameMethod, METH_O,
604 "Searches for a field descriptor by full name."},
605 {"FindExtensionByName", FindExtensionByNameMethod, METH_O,
606 "Searches for extension descriptor by full name."},
607 {"FindEnumTypeByName", FindEnumTypeByNameMethod, METH_O,
608 "Searches for enum type descriptor by full name."},
609 {"FindOneofByName", FindOneofByNameMethod, METH_O,
610 "Searches for oneof descriptor by full name."},
611 {"FindServiceByName", FindServiceByName, METH_O,
612 "Searches for service descriptor by full name."},
613 {"FindMethodByName", FindMethodByName, METH_O,
614 "Searches for method descriptor by full name."},
615
616 {"FindFileContainingSymbol", FindFileContainingSymbol, METH_O,
617 "Gets the FileDescriptor containing the specified symbol."},
618 {"FindExtensionByNumber", FindExtensionByNumber, METH_VARARGS,
619 "Gets the extension descriptor for the given number."},
620 {"FindAllExtensions", FindAllExtensions, METH_O,
621 "Gets all known extensions of the given message descriptor."},
622 {nullptr},
623 };
624
625 } // namespace cdescriptor_pool
626
627 PyTypeObject PyDescriptorPool_Type = {
628 PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
629 ".DescriptorPool", // tp_name
630 sizeof(PyDescriptorPool), // tp_basicsize
631 0, // tp_itemsize
632 cdescriptor_pool::Dealloc, // tp_dealloc
633 #if PY_VERSION_HEX < 0x03080000
634 nullptr, // tp_print
635 #else
636 0, // tp_vectorcall_offset
637 #endif
638 nullptr, // tp_getattr
639 nullptr, // tp_setattr
640 nullptr, // tp_compare
641 nullptr, // tp_repr
642 nullptr, // tp_as_number
643 nullptr, // tp_as_sequence
644 nullptr, // tp_as_mapping
645 nullptr, // tp_hash
646 nullptr, // tp_call
647 nullptr, // tp_str
648 nullptr, // tp_getattro
649 nullptr, // tp_setattro
650 nullptr, // tp_as_buffer
651 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags
652 "A Descriptor Pool", // tp_doc
653 cdescriptor_pool::GcTraverse, // tp_traverse
654 cdescriptor_pool::GcClear, // tp_clear
655 nullptr, // tp_richcompare
656 0, // tp_weaklistoffset
657 nullptr, // tp_iter
658 nullptr, // tp_iternext
659 cdescriptor_pool::Methods, // tp_methods
660 nullptr, // tp_members
661 nullptr, // tp_getset
662 nullptr, // tp_base
663 nullptr, // tp_dict
664 nullptr, // tp_descr_get
665 nullptr, // tp_descr_set
666 0, // tp_dictoffset
667 nullptr, // tp_init
668 nullptr, // tp_alloc
669 cdescriptor_pool::New, // tp_new
670 PyObject_GC_Del, // tp_free
671 };
672
673 // This is the DescriptorPool which contains all the definitions from the
674 // generated _pb2.py modules.
675 static PyDescriptorPool* python_generated_pool = nullptr;
676
InitDescriptorPool()677 bool InitDescriptorPool() {
678 if (PyType_Ready(&PyDescriptorPool_Type) < 0)
679 return false;
680
681 // The Pool of messages declared in Python libraries.
682 // generated_pool() contains all messages already linked in C++ libraries, and
683 // is used as underlay.
684 descriptor_pool_map =
685 new std::unordered_map<const DescriptorPool*, PyDescriptorPool*>;
686 python_generated_pool = cdescriptor_pool::PyDescriptorPool_NewWithUnderlay(
687 DescriptorPool::generated_pool());
688 if (python_generated_pool == nullptr) {
689 delete descriptor_pool_map;
690 return false;
691 }
692
693 // Register this pool to be found for C++-generated descriptors.
694 descriptor_pool_map->insert(
695 std::make_pair(DescriptorPool::generated_pool(),
696 python_generated_pool));
697
698 return true;
699 }
700
701 // The default DescriptorPool used everywhere in this module.
702 // Today it's the python_generated_pool.
703 // TODO: Remove all usages of this function: the pool should be
704 // derived from the context.
GetDefaultDescriptorPool()705 PyDescriptorPool* GetDefaultDescriptorPool() {
706 return python_generated_pool;
707 }
708
GetDescriptorPool_FromPool(const DescriptorPool * pool)709 PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) {
710 // Fast path for standard descriptors.
711 if (pool == python_generated_pool->pool ||
712 pool == DescriptorPool::generated_pool()) {
713 return python_generated_pool;
714 }
715 std::unordered_map<const DescriptorPool*, PyDescriptorPool*>::iterator it =
716 descriptor_pool_map->find(pool);
717 if (it == descriptor_pool_map->end()) {
718 PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool");
719 return nullptr;
720 }
721 return it->second;
722 }
723
PyDescriptorPool_FromPool(const DescriptorPool * pool)724 PyObject* PyDescriptorPool_FromPool(const DescriptorPool* pool) {
725 PyDescriptorPool* existing_pool = GetDescriptorPool_FromPool(pool);
726 if (existing_pool != nullptr) {
727 Py_INCREF(existing_pool);
728 return reinterpret_cast<PyObject*>(existing_pool);
729 } else {
730 PyErr_Clear();
731 }
732
733 PyDescriptorPool* cpool = cdescriptor_pool::_CreateDescriptorPool();
734 if (cpool == nullptr) {
735 return nullptr;
736 }
737 cpool->pool = const_cast<DescriptorPool*>(pool);
738 cpool->is_owned = false;
739 cpool->is_mutable = false;
740 cpool->underlay = nullptr;
741
742 if (!descriptor_pool_map->insert(std::make_pair(cpool->pool, cpool)).second) {
743 // Should never happen -- We already checked the existence above.
744 PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
745 return nullptr;
746 }
747
748 return reinterpret_cast<PyObject*>(cpool);
749 }
750
751 } // namespace python
752 } // namespace protobuf
753 } // namespace google
754
755 #include "google/protobuf/port_undef.inc"
756