2017-09-28 22 views
12

समस्या

मैं अपनी कंपनी के भीतर आंतरिक उपयोग के लिए आवेदन बनाने के लिए PyInstaller का उपयोग करने का प्रयास कर रहा हूं। स्क्रिप्ट एक काम कर रहे पायथन पर्यावरण से बहुत अच्छा काम करता है, लेकिन पैकेज में अनुवाद करते समय कुछ खो देता है।PyInstaller, कैसे एक बाहरी पैकेज कि पिप द्वारा स्थापित किया गया था से डेटा फ़ाइलों को शामिल करने के लिए?

मैं शामिल हैं और संदर्भ डेटा फ़ाइलों है कि मैं अपने आप को मेरे पैकेज में की जरूरत के लिए कैसे पता है, लेकिन मैं भी शामिल है या फ़ाइलों कि में आना चाहिए जब आयातित संदर्भित परेशानी हो रही हूँ।

मैं एक पिप-स्थापना योग्य पैकेज tk-tools कहा जाता है, जो पैनल की तरह प्रदर्शित करता है के लिए कुछ अच्छा चित्र शामिल हैं का उपयोग कर रहा (एल ई डी की तरह दिखता है)। - जो है, जहां मेरे वितरण स्थित है

DEBUG:aspen_comm.display:COM23 19200 
INFO:aspen_comm.display:adding pump 1 to the pump list: [1] 
DEBUG:aspen_comm.display:updating interrogation list: [1] 
Exception in Tkinter callback 
Traceback (most recent call last): 
    File "tkinter\__init__.py", line 1550, in __call__ 
    File "aspen_comm\display.py", line 206, in add 
    File "aspen_comm\display.py", line 121, in add 
    File "aspen_comm\display.py", line 271, in __init__ 
    File "aspen_comm\display.py", line 311, in __init__ 
    File "lib\site-packages\tk_tools\visual.py", line 277, in __init__ 
    File "lib\site-packages\tk_tools\visual.py", line 289, in to_grey 
    File "lib\site-packages\tk_tools\visual.py", line 284, in _load_new 
    File "tkinter\__init__.py", line 3394, in __init__ 
    File "tkinter\__init__.py", line 3350, in __init__ 
_tkinter.TclError: couldn't open "C:\_code\tools\python\aspen_comm\dist\aspen_comm\tk_tools\img/led-grey.png": no such file or directory 

मैं अंतिम पंक्ति में है कि निर्देशिका के भीतर देखा: समस्या यह है कि जब मैं एक pyinstaller स्क्रिप्ट, किसी भी समय है कि उन छवियों में से एक संदर्भित है बनाने के लिए, मैं कोई त्रुटि मिलती है - और पाया कि tk_tools निर्देशिका मौजूद नहीं है।

प्रश्न

मैं कैसे आयातित संकुल की डेटा फ़ाइलों को इकट्ठा करने के लिए pyinstaller पाने के लिए?

युक्ति फ़ाइल

वर्तमान में, मेरी datas खाली है। युक्ति फ़ाइल, pyinstaller -n aspen_comm aspen_comm/__main__.py के साथ बनाया:

# -*- mode: python -*- 

block_cipher = None 


a = Analysis(['aspen_comm\\__main__.py'], 
      pathex=['C:\\_code\\tools\\python\\aspen_comm'], 
      binaries=[], 
      datas=[], 
      hiddenimports=[], 
      hookspath=[], 
      runtime_hooks=[], 
      excludes=[], 
      win_no_prefer_redirects=False, 
      win_private_assemblies=False, 
      cipher=block_cipher) 

pyz = PYZ(a.pure, a.zipped_data, 
      cipher=block_cipher) 

exe = EXE(pyz, 
      a.scripts, 
      exclude_binaries=True, 
      name='aspen_comm', 
      debug=False, 
      strip=False, 
      upx=True, 
      console=True) 

coll = COLLECT(exe, 
       a.binaries, 
       a.zipfiles, 
       a.datas, 
       strip=False, 
       upx=True, 
       name='aspen_comm') 

जब मैं /build/aspen_comm/out00-Analysis.toc और /build/aspen_comm/out00-PYZ.toc भीतर देखो, मैं एक प्रविष्टि है जैसे कि यह tk_tools पैकेज नहीं मिला लग रहा है कि लगता है। इसके अतिरिक्त, tk_tools पैकेज है कि डेटा फ़ाइलों को खोजने की बात करने से पहले पूरी तरह से काम की विशेषताएं हैं, इसलिए मुझे पता है कि इसे कहीं आयातित हो रही है, मैं बस जहां पता नहीं है। जब मैं tk_tools के लिए खोज करते हैं, मैं फ़ाइल संरचना के भीतर यह करने के लिए कोई संदर्भ पा सकते हैं।

मैं भी एक ही परिणाम के साथ --hidden-imports विकल्प की कोशिश की है।

आंशिक समाधान

मैं 'मैन्युअली' सभी कार्यों Analysis में datas = [('C:\\_virtualenv\\aspen\\Lib\\site-packages\\tk_tools\\img\\', 'tk_tools\\img\\')] और datas=datas का उपयोग कर, तो कल्पना फ़ाइल का पथ जोड़ देते हैं तो अपेक्षा के अनुरूप। यह काम करेगा, लेकिन मैं बजाय PyInstaller पैकेज डेटा ढूंढूँगा क्योंकि यह स्पष्ट रूप से स्थापित है। मैं एक समाधान की तलाश में रहूंगा, लेकिन - इस पल के लिए - मैं शायद इस गैर-आदर्श कामकाज का उपयोग करूंगा।

आप पैकेज का नियंत्रण है ...

तो फिर तुम सबपैकेज पर stringify उपयोग कर सकते हैं, लेकिन यह केवल काम करता है अगर यह अपने स्वयं के पैकेज है।

+0

यदि मैं सही ढंग से समझता हूं, तो आप इस https://stackoverflow.com/a/31966932/4724196 जैसे समाधान के अलावा क्या चाहते हैं, 'tk_tools' निर्भरता स्थैतिक फ़ाइलों के लिए एक ऑटो डिस्कवरी विधि है, क्या यह सही है? – HassenPy

+0

@HassenPy हां, लेकिन मुझे संदेह है कि ऑटो-डिस्कवरी पहले से ही PyInstaller पैकेज का हिस्सा है, मुझे इसके लिए सही वाक्यविन्यास नहीं मिला है। आपके द्वारा लिंक किए गए समाधान में अभी भी '.spec' फ़ाइल में कोडित स्थिर फ़ाइलों के लिए पूर्ण पथ है। मैं इस धारणा के तहत था कि 'पाइप स्थापित' पैकेज को थोड़ा प्रयास के साथ PyInstaller में खींचा जाना चाहिए, लेकिन जाहिर है ऐसा नहीं है। ध्यान देने के लिए आपको धन्यवाद! – slightlynybbled

उत्तर

1

संपादित

जोड़े को और अधिक स्थायी रूप से इस समस्या को हल करने के लिए, मैं एक पिप-स्थापना योग्य पैकेज है जो एक फ़ाइल या निर्देशिका लेने के लिए और यह एक अजगर स्ट्रिंग में बदल जाएगा stringify बुलाया बनाया ताकि इस तरह के pyinstaller उन्हें पहचान के रूप में संकुल देशी पायथन फाइलों के रूप में।

project page देखें, प्रतिक्रिया का स्वागत है!


मूल उत्तर

जवाब थोड़ा गोल चक्कर और तरीका है कि tk_tools pyinstaller बजाय पैक किया जाता है के साथ सौदा है। जैसे छवि डेटा के रूप में - -

किसी ने हाल ही में मुझे एक ऐसी तकनीक है जिसमें बाइनरी डेटा के बारे में पता एक base64 स्ट्रिंग के रूप में संग्रहित किया जा सकता:

with open(img_path, 'rb') as f: 
    encoded_string = base64.encode(f.read()) 

इनकोडिंग स्ट्रिंग वास्तव में डेटा संग्रहीत करता है। यदि मूल पैकेज पैकेज फ़ाइलों को छवि फ़ाइलों के बजाए तारों के रूप में संग्रहीत करता है और स्ट्रिंग चर के रूप में उस डेटा के साथ एक पायथन फ़ाइल बनाता है, तो पैकेज में केवल बाइनरी डेटा को उस फ़ॉर्म में शामिल करना संभव है जो pyinstaller मिलेगा और हस्तक्षेप के बिना पता लगाओ।

पर विचार करें नीचे कार्य:

def create_image_string(img_path): 
    """ 
    creates the base64 encoded string from the image path 
    and returns the (filename, data) as a tuple 
    """ 

    with open(img_path, 'rb') as f: 
     encoded_string = base64.b64encode(f.read()) 

    file_name = os.path.basename(img_path).split('.')[0] 
    file_name = file_name.replace('-', '_') 

    return file_name, encoded_string 


def archive_image_files(): 
    """ 
    Reads all files in 'images' directory and saves them as 
    encoded strings accessible as python variables. The image 
    at images/my_image.png can now be found in tk_tools/images.py 
    with a variable name of my_image 
    """ 

    destination_path = "tk_tools" 
    py_file = '' 

    for root, dirs, files in os.walk("images"): 
     for name in files: 
      img_path = os.path.join(root, name) 
      file_name, file_string = create_image_string(img_path) 

      py_file += '{} = {}\n'.format(file_name, file_string) 

    py_file += '\n' 

    with open(os.path.join(destination_path, 'images.py'), 'w') as f: 
     f.write(py_file) 

तो archive_image_files() (पहिया निर्माण और स्थापना के दौरान), सेटअप फ़ाइल के भीतर रखा जाता तो <package_name>/images.py अपने आप बन जाता कभी भी सेटअप स्क्रिप्ट चलाया जाता है।

मैं निकट भविष्य में इस तकनीक पर सुधार कर सकता हूं। आपकी सहायता के लिए आप सभी को धन्यवाद,

जे

1

निम्नलिखित कोड imgs बुलाया बंडल एप्लिकेशन के शीर्ष स्तर में एक फ़ोल्डर में अपने निर्देशिका में सभी PNG फ़ाइलें डाल देंगे:

datas=[("C:\\_code\\tools\\python\\aspen_comm\\dist\\aspen_comm\\tk_tools\\img\\*.png", "imgs")], 

तब आप अपने कोड में os.path.join("imgs", "your_image.png") के साथ उन्हें संदर्भित कर सकते हैं।

+0

पथ 'सी: \ _ कोड \ उपकरण \ python \ aspen_comm \ dist \ aspen_comm' मौजूद है, लेकिन इसमें कोई निर्देशिका नहीं है जिसे 'tk_tools' कहा जाता है, इसलिए इस समाधान को इस समय व्यवहार्य नहीं है। देखने के लिए धन्यवाद! – slightlynybbled

+0

मुझे गलत समझा जाना चाहिए। तब आपकी छवियां कहां हैं? – Steampunkery

+0

छवियों को स्थापित किया जाता है जब 'tk_tools' पाइप के साथ स्थापित किया जाता है, इसलिए वे पाइथन वर्चुअल वातावरण में स्थित होते हैं।मैं उम्मीद कर रहा था कि ऑटो-डिस्कवरी फीचर यह पता लगाएगी कि फाइलें 'tk_tools' के भीतर स्थित थीं, फिर उन्हें खींचें। – slightlynybbled

0

मैं इस तथ्य का लाभ लेने कि कल्पना फ़ाइल पायथन कोड का निष्पादित करता है के द्वारा इस हल किया। आप PyInstaller बिल्ड चरण के दौरान गतिशील रूप से पैकेज की जड़ प्राप्त कर सकते हैं और datas सूची में उस मान का उपयोग कर सकते हैं। मेरे मामले में मैं अपने .spec फाइल में कुछ इस तरह है:

import os 
import importlib 

package_imports = [['package_name', ['file0', 'file1']] 

datas = [] 
for package, files in package_imports: 
    proot = os.path.dirname(importlib.import_module(package).__file__) 
    datas.extend((os.path.join(proot, f), package) for f in files) 

और Analysis करने के लिए एक पैरामीटर के रूप में जिसके परिणामस्वरूप datas सूची का उपयोग करें।

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

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