6

मेरे पास एक पायथन परियोजना है जो तैनाती के लिए setuptools का उपयोग करती है और मैं ज्यादातर परियोजना संरचना के संबंध में this guide का पालन करता हूं। परियोजना नेटवर्क संदेश प्रारूप को परिभाषित करने के लिए Google प्रोटोकॉल बफर का उपयोग करती है। मेरा मुख्य मुद्दा यह है कि setup.py को _pb2.py फ़ाइल में परिभाषाओं को बनाने के लिए संस्थापन के दौरान प्रोटोक-कंपाइलर को कैसे कॉल करें।प्रोटोकॉल बफर का उपयोग कर पाइथन प्रोजेक्ट, परिनियोजन मुद्दे

this question में सलाह के साथ परिणामस्वरूप _pb2.py फ़ाइलों को वितरित करने के लिए सलाह दी गई थी। हालांकि यह बहुत ही समान प्लेटफार्मों के लिए काम कर सकता है, मुझे कई मामलों में पाया गया है जहां यह काम नहीं करता है। उदाहरण के लिए, जब मैं मैक पर विकसित करता हूं जो एनाकोंडा पायथन का उपयोग करता है और परिणामी _pb2.py की प्रतिलिपि बनाता है, तो शेष परियोजना के साथ रास्पबेरी पाई रास्पियन पर चल रहा है, हमेशा _pb2.py मॉड्यूल से आने वाली आयात त्रुटियां होती हैं। हालांकि, अगर मैं पीआई पर ताज़ा रूप से .proto फ़ाइलों को संकलित करता हूं, तो परियोजना अपेक्षित काम करती है। इसलिए, संकलित फाइलों को वितरित करना एक विकल्प की तरह प्रतीत नहीं होता है।

यहां काम करने और सर्वोत्तम अभ्यास समाधान की तलाश करने की तरह। यह माना जा सकता है कि प्रोटोकॉल-कंपाइलर लक्ष्य मंच पर स्थापित है।

संपादित करें:

चूंकि लोग विफलता के कारण पूछते हैं। मैक पर, प्रोटोबफ संस्करण 2.6.1 है। और पीआई पर यह 2.4.1 है। जाहिर है, उत्पन्न प्रोटोकॉल संकलक आउटपुट द्वारा उपयोग की जाने वाली आंतरिक एपीआई बदल गई है। उत्पादन मूल रूप से है:

File "[...]network_manager.py", line 8, in <module> 
     import InstrumentControl.transports.serial_bridge_protocol_pb2 as protocol 
    File "[...]serial_bridge_protocol_pb2.py", line 9, in <module> 
     from google.protobuf import symbol_database as _symbol_database 
    ImportError: cannot import name symbol_database 
+0

मैं इसी तरह के मुद्दों था, और हमेशा पीआई पर संकलित। समस्या विभिन्न protobuf- संस्करणों से AFAIR उपजी है। तो - जो संस्करण आप संबंधित मशीनों पर की क्या ज़रूरत है, और आप एक ही करने के लिए उन्हें अपग्रेड नहीं कर सकते? – deets

+0

मैं वास्तव में उससे बचना चाहता हूं। मैं (संभवतः) उन मशीनों पर कर सकता हूं जिन्हें मैं नियंत्रित करता हूं लेकिन यह ऐसा करने का सही तरीका नहीं लगता है। और यह दूसरों को सॉफ़्टवेयर वितरित करते समय शायद विफल हो जाता है। उन्हें प्रोटोकॉल बफर का एक विशिष्ट संस्करण स्थापित करना जब उनका वर्तमान संस्करण (पुन: संकलन करके) का उपयोग किया जा सकता है, सही नहीं लगता है। – jan

+0

क्या आपने शोध किया - आयात त्रुटियों का क्या कारण बनता है? मैं पैकेजिंग _pb2.py फ़ाइलें रणनीति और आयात त्रुटि समस्याओं का शोध करना चुनूंगा। –

उत्तर

9

ठीक है, मैं अपने देव मशीन की तुलना में एक और मंच पर एक विशेष पुराने संस्करण स्थापित करने या आद्य फ़ाइलों को संकलित करने के उपयोगकर्ता की आवश्यकता के बिना समस्या हल हो जाती। यह this setup.py script from protobuf itself से प्रेरित है।

सबसे पहले, protoc पाया जा करने की जरूरत है, इस

# Find the Protocol Compiler. 
if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']): 
    protoc = os.environ['PROTOC'] 
else: 
    protoc = find_executable("protoc") 

का उपयोग कर यह फ़ंक्शन .proto फ़ाइल संकलन और उसी जगह _pb2.py रखा जाएगा किया जा सकता है। हालांकि, व्यवहार मनमाने ढंग से बदला जा सकता है।

def generate_proto(source): 
    """Invokes the Protocol Compiler to generate a _pb2.py from the given 
    .proto file. Does nothing if the output already exists and is newer than 
    the input.""" 

    output = source.replace(".proto", "_pb2.py") 

    if (not os.path.exists(output) or 
     (os.path.exists(source) and 
     os.path.getmtime(source) > os.path.getmtime(output))): 
    print "Generating %s..." % output 

    if not os.path.exists(source): 
     sys.stderr.write("Can't find required file: %s\n" % source) 
     sys.exit(-1) 

    if protoc == None: 
     sys.stderr.write(
      "Protocol buffers compiler 'protoc' not installed or not found.\n" 
     ) 
     sys.exit(-1) 

    protoc_command = [ protoc, "-I.", "--python_out=.", source ] 
    if subprocess.call(protoc_command) != 0: 
     sys.exit(-1) 

अगला, कक्षा _build_py और _clean प्रोटोकॉल बफर बनाने और सफाई करने के लिए व्युत्पन्न हैं।

# List of all .proto files 
proto_src = ['file1.proto', 'path/to/file2.proto'] 

class build_py(_build_py): 
    def run(self): 
    for f in proto_src: 
     generate_proto(f) 
    _build_py.run(self) 

class clean(_clean): 
    def run(self): 
    # Delete generated files in the code tree. 
    for (dirpath, dirnames, filenames) in os.walk("."): 
     for filename in filenames: 
     filepath = os.path.join(dirpath, filename) 
     if filepath.endswith("_pb2.py"): 
      os.remove(filepath) 
    # _clean is an old-style class, so super() doesn't work. 
    _clean.run(self) 

और अंत में, पैरामीटर

cmdclass = { 'clean': clean, 'build_py': build_py } 

सेटअप और सब कुछ करने के लिए कॉल काम करना चाहिए करने के लिए जोड़ा जाना चाहिए। अभी भी संभावित quirks के लिए जांच करनी है, लेकिन अब तक यह मैक और पीआई पर बेकार ढंग से काम करता है।

3

एक अन्य समाधान आपके एप्लिकेशन के साथ Protobuf पुस्तकालय बंडल करने, लक्ष्य मशीन पर स्थापित संस्करण का उपयोग करने के बजाय है। इस तरह आप जानते हैं कि आपके उत्पन्न कोड के साथ कोई संस्करण बेमेल है।

3

मैंने अभी इस कोड के सबसे अधिक भाग का उपयोग करने के लिए protobuf-setuptools पैकेज शुरू किया है। इसे अभी भी सुधार की जरूरत है, इसलिए किसी भी प्रतिक्रिया का स्वागत है!

इसे देखें: https://pypi.python.org/pypi/protobuf-setuptools

+0

अच्छा! मुझे उम्मीद है कि मैं इसे देख सकता हूं और इसे जल्द ही हमारे स्रोतों के साथ एकीकृत कर सकता हूं। – jan

+0

@jan मदद और सुधार करने में प्रसन्न होंगे। – pupssman

संबंधित मुद्दे