- 
                Notifications
    
You must be signed in to change notification settings  - Fork 15.9k
 
Description
When a _pb2 is compiled with Cython, and the C++ backend of the Python library is turned on (as it now is on Linux for the PyPI deployed protobuf, as of 3.2.0), instantiating any message object gives an error. I am using Python 3.5. Here's an example of the error:
Traceback (most recent call last):
  File "bug.py", line 1, in <module>
    from addressbook_pb2 import Person
  File "addressbook_pb2.py", line 34, in init addressbook_pb2 (addressbook_pb2.c:1997)
    _descriptor.EnumValueDescriptor(
  File "/home/arthur/envs/default/lib/python3.5/site-packages/google/protobuf/descriptor.py", line 649, in __new__
    _message.Message._CheckCalledFromGeneratedFile()
TypeError: Descriptors should not be created directly, but only retrieved from their parent.
The immediate cause of the error is _CheckCalledFromGeneratedFile in google/protobuf/pyext/message.cc, which calls _CalledFromGeneratedFile in google/protobuf/pyext/descriptor.cc. I haven't looked any further than this, but my suspicion is raised by the strcmp against "_pb2.py" at the end of this function.  I think that for Cython the filename would end with "_pb2.c", but I'm not sure.
Just to be completely explicit, here are steps to reproduce:
- Create a new Python virtual environment with the relevant packages (I am just using grpio-tools for easy access to protoc):
 
pip install grpcio-tools==1.1.0 protobuf==3.2.0 Cython==0.25.2
- Generate a pb2:
 
wget https://raw.githubusercontent.com/google/protobuf/master/examples/addressbook.proto
python -m grpc_tools.protoc -I. addressbook.proto --python_out=.
- Cythonise and compile this file. The easiest way to do this is with a little setup.py:
 
from distutils.core import setup
from Cython.Build import cythonize
setup(name="bug", ext_modules = cythonize("addressbook_pb2.py"))
Then run: python setup.py build_ext --inplace
- Try to instantiate a message:
 
python -c 'from addressbook_pb2 import Person; p = Person()'