Home | History | Annotate | Download | only in pyext
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      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 
     31 // Author: petar (at) google.com (Petar Petrov)
     32 
     33 #include <Python.h>
     34 #include <string>
     35 
     36 #include <google/protobuf/pyext/python_descriptor.h>
     37 #include <google/protobuf/descriptor.pb.h>
     38 
     39 #define C(str) const_cast<char*>(str)
     40 
     41 namespace google {
     42 namespace protobuf {
     43 namespace python {
     44 
     45 
     46 static void CFieldDescriptorDealloc(CFieldDescriptor* self);
     47 
     48 static google::protobuf::DescriptorPool* g_descriptor_pool = NULL;
     49 
     50 static PyObject* CFieldDescriptor_GetFullName(
     51     CFieldDescriptor* self, void *closure) {
     52   Py_XINCREF(self->full_name);
     53   return self->full_name;
     54 }
     55 
     56 static PyObject* CFieldDescriptor_GetName(
     57     CFieldDescriptor *self, void *closure) {
     58   Py_XINCREF(self->name);
     59   return self->name;
     60 }
     61 
     62 static PyObject* CFieldDescriptor_GetCppType(
     63     CFieldDescriptor *self, void *closure) {
     64   Py_XINCREF(self->cpp_type);
     65   return self->cpp_type;
     66 }
     67 
     68 static PyObject* CFieldDescriptor_GetLabel(
     69     CFieldDescriptor *self, void *closure) {
     70   Py_XINCREF(self->label);
     71   return self->label;
     72 }
     73 
     74 static PyObject* CFieldDescriptor_GetID(
     75     CFieldDescriptor *self, void *closure) {
     76   Py_XINCREF(self->id);
     77   return self->id;
     78 }
     79 
     80 
     81 static PyGetSetDef CFieldDescriptorGetters[] = {
     82   { C("full_name"),
     83     (getter)CFieldDescriptor_GetFullName, NULL, "Full name", NULL},
     84   { C("name"),
     85     (getter)CFieldDescriptor_GetName, NULL, "last name", NULL},
     86   { C("cpp_type"),
     87     (getter)CFieldDescriptor_GetCppType, NULL, "C++ Type", NULL},
     88   { C("label"),
     89     (getter)CFieldDescriptor_GetLabel, NULL, "Label", NULL},
     90   { C("id"),
     91     (getter)CFieldDescriptor_GetID, NULL, "ID", NULL},
     92   {NULL}
     93 };
     94 
     95 PyTypeObject CFieldDescriptor_Type = {
     96   PyObject_HEAD_INIT(&PyType_Type)
     97   0,
     98   C("google.protobuf.internal."
     99     "_net_proto2___python."
    100     "CFieldDescriptor"),                // tp_name
    101   sizeof(CFieldDescriptor),             // tp_basicsize
    102   0,                                    // tp_itemsize
    103   (destructor)CFieldDescriptorDealloc,  // tp_dealloc
    104   0,                                    // tp_print
    105   0,                                    // tp_getattr
    106   0,                                    // tp_setattr
    107   0,                                    // tp_compare
    108   0,                                    // tp_repr
    109   0,                                    // tp_as_number
    110   0,                                    // tp_as_sequence
    111   0,                                    // tp_as_mapping
    112   0,                                    // tp_hash
    113   0,                                    // tp_call
    114   0,                                    // tp_str
    115   0,                                    // tp_getattro
    116   0,                                    // tp_setattro
    117   0,                                    // tp_as_buffer
    118   Py_TPFLAGS_DEFAULT,                   // tp_flags
    119   C("A Field Descriptor"),              // tp_doc
    120   0,                                    // tp_traverse
    121   0,                                    // tp_clear
    122   0,                                    // tp_richcompare
    123   0,                                    // tp_weaklistoffset
    124   0,                                    // tp_iter
    125   0,                                    // tp_iternext
    126   0,                                    // tp_methods
    127   0,                                    // tp_members
    128   CFieldDescriptorGetters,              // tp_getset
    129   0,                                    // tp_base
    130   0,                                    // tp_dict
    131   0,                                    // tp_descr_get
    132   0,                                    // tp_descr_set
    133   0,                                    // tp_dictoffset
    134   0,                                    // tp_init
    135   PyType_GenericAlloc,                  // tp_alloc
    136   PyType_GenericNew,                    // tp_new
    137   PyObject_Del,                         // tp_free
    138 };
    139 
    140 static void CFieldDescriptorDealloc(CFieldDescriptor* self) {
    141   Py_DECREF(self->full_name);
    142   Py_DECREF(self->name);
    143   Py_DECREF(self->cpp_type);
    144   Py_DECREF(self->label);
    145   Py_DECREF(self->id);
    146   self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
    147 }
    148 
    149 typedef struct {
    150   PyObject_HEAD
    151 
    152   const google::protobuf::DescriptorPool* pool;
    153 } CDescriptorPool;
    154 
    155 static void CDescriptorPoolDealloc(CDescriptorPool* self);
    156 
    157 static PyObject* CDescriptorPool_NewCDescriptor(
    158     const google::protobuf::FieldDescriptor* field_descriptor) {
    159   CFieldDescriptor* cfield_descriptor = PyObject_New(
    160       CFieldDescriptor, &CFieldDescriptor_Type);
    161   if (cfield_descriptor == NULL) {
    162     return NULL;
    163   }
    164   cfield_descriptor->descriptor = field_descriptor;
    165 
    166   cfield_descriptor->full_name = PyString_FromString(
    167       field_descriptor->full_name().c_str());
    168   cfield_descriptor->name = PyString_FromString(
    169       field_descriptor->name().c_str());
    170   cfield_descriptor->cpp_type = PyLong_FromLong(field_descriptor->cpp_type());
    171   cfield_descriptor->label = PyLong_FromLong(field_descriptor->label());
    172   cfield_descriptor->id = PyLong_FromVoidPtr(cfield_descriptor);
    173   return reinterpret_cast<PyObject*>(cfield_descriptor);
    174 }
    175 
    176 static PyObject* CDescriptorPool_FindFieldByName(
    177     CDescriptorPool* self, PyObject* arg) {
    178   const char* full_field_name = PyString_AsString(arg);
    179   if (full_field_name == NULL) {
    180     return NULL;
    181   }
    182 
    183   const google::protobuf::FieldDescriptor* field_descriptor = NULL;
    184 
    185   field_descriptor = self->pool->FindFieldByName(full_field_name);
    186 
    187 
    188   if (field_descriptor == NULL) {
    189     PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
    190                  full_field_name);
    191     return NULL;
    192   }
    193 
    194   return CDescriptorPool_NewCDescriptor(field_descriptor);
    195 }
    196 
    197 static PyObject* CDescriptorPool_FindExtensionByName(
    198     CDescriptorPool* self, PyObject* arg) {
    199   const char* full_field_name = PyString_AsString(arg);
    200   if (full_field_name == NULL) {
    201     return NULL;
    202   }
    203 
    204   const google::protobuf::FieldDescriptor* field_descriptor =
    205       self->pool->FindExtensionByName(full_field_name);
    206   if (field_descriptor == NULL) {
    207     PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
    208                  full_field_name);
    209     return NULL;
    210   }
    211 
    212   return CDescriptorPool_NewCDescriptor(field_descriptor);
    213 }
    214 
    215 static PyMethodDef CDescriptorPoolMethods[] = {
    216   { C("FindFieldByName"),
    217     (PyCFunction)CDescriptorPool_FindFieldByName,
    218     METH_O,
    219     C("Searches for a field descriptor by full name.") },
    220   { C("FindExtensionByName"),
    221     (PyCFunction)CDescriptorPool_FindExtensionByName,
    222     METH_O,
    223     C("Searches for extension descriptor by full name.") },
    224   {NULL}
    225 };
    226 
    227 PyTypeObject CDescriptorPool_Type = {
    228   PyObject_HEAD_INIT(&PyType_Type)
    229   0,
    230   C("google.protobuf.internal."
    231     "_net_proto2___python."
    232     "CFieldDescriptor"),               // tp_name
    233   sizeof(CDescriptorPool),             // tp_basicsize
    234   0,                                   // tp_itemsize
    235   (destructor)CDescriptorPoolDealloc,  // tp_dealloc
    236   0,                                   // tp_print
    237   0,                                   // tp_getattr
    238   0,                                   // tp_setattr
    239   0,                                   // tp_compare
    240   0,                                   // tp_repr
    241   0,                                   // tp_as_number
    242   0,                                   // tp_as_sequence
    243   0,                                   // tp_as_mapping
    244   0,                                   // tp_hash
    245   0,                                   // tp_call
    246   0,                                   // tp_str
    247   0,                                   // tp_getattro
    248   0,                                   // tp_setattro
    249   0,                                   // tp_as_buffer
    250   Py_TPFLAGS_DEFAULT,                  // tp_flags
    251   C("A Descriptor Pool"),              // tp_doc
    252   0,                                   // tp_traverse
    253   0,                                   // tp_clear
    254   0,                                   // tp_richcompare
    255   0,                                   // tp_weaklistoffset
    256   0,                                   // tp_iter
    257   0,                                   // tp_iternext
    258   CDescriptorPoolMethods,              // tp_methods
    259   0,                                   // tp_members
    260   0,                                   // tp_getset
    261   0,                                   // tp_base
    262   0,                                   // tp_dict
    263   0,                                   // tp_descr_get
    264   0,                                   // tp_descr_set
    265   0,                                   // tp_dictoffset
    266   0,                                   // tp_init
    267   PyType_GenericAlloc,                 // tp_alloc
    268   PyType_GenericNew,                   // tp_new
    269   PyObject_Del,                        // tp_free
    270 };
    271 
    272 static void CDescriptorPoolDealloc(CDescriptorPool* self) {
    273   self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
    274 }
    275 
    276 google::protobuf::DescriptorPool* GetDescriptorPool() {
    277   if (g_descriptor_pool == NULL) {
    278     g_descriptor_pool = new google::protobuf::DescriptorPool(
    279         google::protobuf::DescriptorPool::generated_pool());
    280   }
    281   return g_descriptor_pool;
    282 }
    283 
    284 PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args) {
    285   CDescriptorPool* cdescriptor_pool = PyObject_New(
    286       CDescriptorPool, &CDescriptorPool_Type);
    287   if (cdescriptor_pool == NULL) {
    288     return NULL;
    289   }
    290   cdescriptor_pool->pool = GetDescriptorPool();
    291   return reinterpret_cast<PyObject*>(cdescriptor_pool);
    292 }
    293 
    294 PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) {
    295   char* message_type;
    296   Py_ssize_t message_len;
    297 
    298   if (PyString_AsStringAndSize(arg, &message_type, &message_len) < 0) {
    299     return NULL;
    300   }
    301 
    302   google::protobuf::FileDescriptorProto file_proto;
    303   if (!file_proto.ParseFromArray(message_type, message_len)) {
    304     PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
    305     return NULL;
    306   }
    307 
    308   if (google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
    309       file_proto.name()) != NULL) {
    310     Py_RETURN_NONE;
    311   }
    312 
    313   const google::protobuf::FileDescriptor* descriptor = GetDescriptorPool()->BuildFile(
    314       file_proto);
    315   if (descriptor == NULL) {
    316     PyErr_SetString(PyExc_TypeError,
    317                     "Couldn't build proto file into descriptor pool!");
    318     return NULL;
    319   }
    320 
    321   Py_RETURN_NONE;
    322 }
    323 
    324 bool InitDescriptor() {
    325   CFieldDescriptor_Type.tp_new = PyType_GenericNew;
    326   if (PyType_Ready(&CFieldDescriptor_Type) < 0)
    327     return false;
    328 
    329   CDescriptorPool_Type.tp_new = PyType_GenericNew;
    330   if (PyType_Ready(&CDescriptorPool_Type) < 0)
    331     return false;
    332   return true;
    333 }
    334 
    335 }  // namespace python
    336 }  // namespace protobuf
    337 }  // namespace google
    338