PyInstaller (--onefile) के साथ डेटा फ़ाइलों को बंडल करना


107

मैं PyInstaller के साथ एक फ़ाइल EXE बनाने की कोशिश कर रहा हूं, जिसमें एक छवि और एक आइकन शामिल है। मैं अपने जीवन के लिए काम नहीं कर सकता --onefile

अगर मैं ऐसा --onedirकरता हूं तो सभी काम बहुत अच्छे से होते हैं। जब मैं उपयोग करता हूं --onefile, तो यह संदर्भित अतिरिक्त फ़ाइलों (संकलित EXE को चलाते समय) नहीं मिल सकता है। यह DLL और बाकी सब ठीक पाता है, न कि केवल दो इमेज।

मैंने EXE ( \Temp\_MEI95642\उदाहरण के लिए) चलाते समय टेम्प-डीआईआर में देखा है और फाइलें वास्तव में हैं। जब मैं EXE को उस अस्थायी-निर्देशिका में छोड़ता हूं तो यह उन्हें मिल जाता है। बहुत हैरान करनेवाला।

यह वही है जो मैंने .specफ़ाइल में जोड़ा है

a.datas += [('images/icon.ico', 'D:\\[workspace]\\App\\src\\images\\icon.ico',  'DATA'),
('images/loaderani.gif','D:\\[workspace]\\App\\src\\images\\loaderani.gif','DATA')]     

मुझे यह जोड़ना चाहिए कि मैंने उन्हें सबफ़ोल्डर्स में नहीं डालने की कोशिश की है, इससे कोई फर्क नहीं पड़ा।

संपादित करें: PyInstaller अपडेट के कारण नए उत्तर को सही के रूप में चिह्नित किया गया।


11
आपको बहुत - बहुत धन्यवाद! यहाँ लाइन में ( a.datas += ...) वास्तव में अभी मेरी मदद की। pyinstaller प्रलेखन का उपयोग करने के बारे में बात करता है, COLLECTलेकिन उपयोग करते समय बाइनरी में फाइल डालने में विफल रहता है--onefile
इगोर सेरेब्रनी

@IgorSerebryany: दूसरा! मैं सिर्फ एक ही समस्या थी।
हब्रो

जब मैं उपयोग करता हूं तो मेरा .exe क्रैश हो जाता है, अगर मैंने इस्तेमाल किया
iacopo

1
ध्यान में रखें कि अस्थायी फ़ोल्डर गायब हो जाते हैं जब निष्पादन खत्म, तो क्या है अंदर यह अपने कार्यक्रम में sys._MEIPASS के listdir डाल जाँच करने के लिए मुख्य
hithwen

क्या ट्री () सिंटैक्स का उपयोग करने का एक तरीका है जो मुझे जगह के आसपास दिखाई देता है?
फतुहोकू

जवाबों:


152

PyInstaller के नए संस्करण envअब चर सेट नहीं करते हैं, इसलिए शीश का उत्कृष्ट उत्तर काम नहीं करेगा। अब पथ इस प्रकार सेट हो गया sys._MEIPASS:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

10
मैं अजगर 2.7 के साथ pyinstaller 2 का उपयोग कर रहा हूं और मेरे पास _MEIPASS2envs में नहीं है , लेकिन sys._MEIPASSअच्छी तरह से काम करता है, इसलिए +1। मेरा सुझाव है:path = getattr(sys, '_MEIPASS', os.getcwd())
केबे

2
+1। उसके लिए धन्यवाद। थोड़ी देर के लिए _MEIPASS2 पर्यावरण चर का उपयोग करने की कोशिश कर रहा है, जाहिर है मैंने अपना कोड लिखा था जब यह अभी भी पर्यावरण चर था, क्योंकि मुझे याद है कि यह काम कर रहा है। अचानक, यह बंद हो गया, जब मैंने हाल ही में पुनर्नवीनीकरण किया।
फेविल ऑर्बिडिओस

8
मैं AttributeErrorअधिक सामान्य के बजाय पकड़ने की सलाह दूंगा Exception। मैं उन मुद्दों में भाग गया जहाँ मुझे sys आयात की याद आ रही थी और रास्ता चुपचाप डिफ़ॉल्ट हो गया था os.path.abspath
आरोन

आप मेरी समस्या को हल करने में मदद करने में सक्षम हो सकते हैं ।
फिलिप

1
उस मामले में वर्तमान कार्यशील निर्देशिका का उपयोग करना जहां _MEIPASS सेट नहीं है, गलत है। मेरा जवाब देखिए ।
जोनाथन रेनहार्ट

51

pyinstaller आपके डेटा को एक अस्थायी फ़ोल्डर में अनपैक करता है, और इस निर्देशिका पथ को _MEIPASS2पर्यावरण चर में संग्रहीत करता है। _MEIPASS2पैक-मोड में dir पाने के लिए और unpacked (विकास) मोड में स्थानीय निर्देशिका का उपयोग करने के लिए, मैं इसका उपयोग करता हूं:

def resource_path(relative):
    return os.path.join(
        os.environ.get(
            "_MEIPASS2",
            os.path.abspath(".")
        ),
        relative
    )

आउटपुट:

# in development
>>> resource_path("app_icon.ico")
"/home/shish/src/my_app/app_icon.ico"

# in production
>>> resource_path("app_icon.ico")
"/tmp/_MEI34121/app_icon.ico"

10
कैसे, कब, और कहां कोई उपयोग करेगा?
15 सितंबर को gseattle

4
आपको इस स्क्रिप्ट का उपयोग उन .py फ़ाइल में करना चाहिए जिसे आप PyInstaller के साथ संकलित करने का प्रयास कर रहे हैं। इस कोड स्निपेट को .spec फ़ाइल में न डालें, जो काम नहीं करेगा। सामान्य रूप से आपके द्वारा टाइप किए गए पथ को प्रतिस्थापित करके अपनी फ़ाइलों तक पहुंचें resource_path("file_to_be_accessed.mp3")। सावधान रहें कि आपको PyInstaller के वर्तमान संस्करण के लिए अधिकतम 'उत्तर का उपयोग करना चाहिए।
एक्सिलरेशन-जी

1
क्या यह उत्तर --one-fileविकल्प का उपयोग करने के लिए विशिष्ट है ?
फतुहोकू

आप मेरी समस्या को हल करने में मदद करने में सक्षम हो सकते हैं ।
फिलिप

उस मामले में वर्तमान कार्यशील निर्देशिका का उपयोग करना जहां _MEIPASS सेट नहीं है, गलत है। मेरा जवाब देखिए ।
जोनाथन रेनहार्ट

30

अन्य सभी जवाब उस स्थिति में वर्तमान कार्यशील निर्देशिका का उपयोग करते हैं जहां आवेदन PyInstalled नहीं है (यानी sys._MEIPASSसेट नहीं है)। यह गलत है, क्योंकि यह आपको अपने आवेदन को निर्देशिका से अलग करने से रोकता है, जहां आपकी स्क्रिप्ट है।

एक बेहतर समाधान:

import sys
import os

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

धन्यवाद जॉन, आपके कार्य ने मुझे आज एक समस्या को हल करने में मदद की। मेरे पास बस एक सवाल है। क्यों कुछ _MEIPASS के बजाय _MEIPASS2 लिखते हैं? जब मैंने पहले 2 जोड़ने की कोशिश की, तो यह काम नहीं किया।
अहमद अब्देलखेल

मुझे लगता है कि os.env['_MEIPASS2'](ओएस वातावरण का उपयोग करके) निर्देशिका प्राप्त करने का एक पुराना तरीका था। AFAIK sys._MEIPASSअब केवल सही विधि है।
जोनाथन रेनहार्ट

नमस्कार, resource_path()मुख्य स्क्रिप्ट में होने पर आपका समाधान ठीक है। क्या इसके बजाय एक मॉड्यूल में लिखे जाने पर इसे काम करने का कोई तरीका है? अब तक, यह उस फ़ोल्डर में संसाधन प्राप्त करने की कोशिश करेगा जहां मॉड्यूल मुख्य नहीं है।
Guimoute

1
@Guimoute लगता है कि इस उत्तर में कोड डिजाइन के रूप में काम कर रहा है: यह संसाधनों को उस मॉड्यूल को स्थानीय करता है जो इसे प्रदान करता है क्योंकि यह उपयोग करता है __file__। यदि आप चाहते हैं कि एक मॉड्यूल अपने दायरे से बाहर संसाधनों का उपयोग करने में सक्षम हो तो आपको यह लागू करना होगा कि आयात कोड आपके मॉड्यूल को उपयोग करने के लिए उन्हें एक मार्ग प्रदान करता है, जैसे कि मॉड्यूल एक "set_resource_location ()" कॉल को प्रदान करता है जो मॉड्यूल आयातक कॉल - यह नहीं सोचते कि यह किसी भी तरह से अलग है कि आपको pyinstaller का उपयोग नहीं करते समय कैसे काम करना चाहिए।
बरनी

@ कर्ण संकेत के लिए धन्यवाद! मैं उन पंक्तियों के साथ कुछ कोशिश करूँगा।
ग्विमौटे

14

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

  1. चरण: उपर्युक्त विधियों में से एक को sys और os मॉड्यूल आयात करने के साथ अपनी py फ़ाइल में लिखें। मैंने दोनों की कोशिश की। पिछले एक है:

    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
  2. चरण: फ़ाइल.स्पेक फ़ाइल बनाने के लिए कंसोल पर, pyi-makepec file.py लिखें ।

  3. चरण: नीचे दी गई डेटा फ़ाइलों को जोड़ने के लिए नोटपैड ++ के साथ ओपन, file.spec:

    a = Analysis(['C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.py'],
                 pathex=['C:\\Users\\TCK\\Desktop\\Projeler'],
                 binaries=[],
                 datas=[],
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher)
    #Add the file like the below example
    a.datas += [('Converter-GUI.ico', 'C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico', 'DATA')]
    pyz = PYZ(a.pure, a.zipped_data,
         cipher=block_cipher)
    exe = EXE(pyz,
              a.scripts,
              exclude_binaries=True,
              name='Converter-GUI',
              debug=False,
              strip=False,
              upx=True,
              #Turn the console option False if you don't want to see the console while executing the program.
              console=False,
              #Add an icon to the program.
              icon='C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico')
    
    coll = COLLECT(exe,
                   a.binaries,
                   a.zipfiles,
                   a.datas,
                   strip=False,
                   upx=True,
                   name='Converter-GUI')
  4. चरण: मैंने उपरोक्त चरणों का पालन किया, फिर कल्पना फ़ाइल को सहेजा। अंत में कंसोल खोला और लिखा, pyinstaller file.spec (मेरे मामले में, फ़ाइल = कनवर्टर-जीयूआई)।

निष्कर्ष: डिस्टर्ब फोल्डर में अभी भी एक से अधिक फाइल हैं।

नोट: मैं पायथन 3.5 का उपयोग कर रहा हूं।

EDIT: अंत में यह जोनाथन रेनहार्ट की विधि के साथ काम करता है

  1. चरण: नीचे दिए गए कोडों को अपने अजगर फ़ाइल में sys और os आयात करके जोड़ें।

    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
  2. चरण: अपनी फ़ाइल के पथ को जोड़ने के साथ उपरोक्त फ़ंक्शन को कॉल करें:

    image_path = resource_path("Converter-GUI.ico")
  3. चरण: उपरोक्त चर लिखें जो फ़ंक्शन को कॉल करता है जहां आपके कोड को पथ की आवश्यकता है। मेरे मामले में यह है:

        self.window.iconbitmap(image_path)
  4. चरण: अपनी पायथन फ़ाइल की समान निर्देशिका में कंसोल खोलें, नीचे दिए गए कोड लिखें:

        pyinstaller --onefile your_file.py
  5. चरण: पायथन फ़ाइल की .spec फ़ाइल खोलें और aatatas ऐरे को जोड़ें और आइकन को exe वर्ग में जोड़ें, जो 3'rd चरण में संपादन से पहले ऊपर दिया गया था।
  6. चरण: पथ फ़ाइल सहेजें और बाहर निकलें। अपने फ़ोल्डर पर जाएं जिसमें कल्पना और py फ़ाइल शामिल है। कंसोल विंडो फिर से खोलें और नीचे कमांड टाइप करें:

        pyinstaller your_file.spec

6. चरण के बाद आपकी एक फ़ाइल उपयोग के लिए तैयार है।


धन्यवाद @ दोस्त! ऐसा नहीं है कि a.datasचरण 5 से सरणी तार के tuples लेता है, pythonhosted.org/PyInstaller/spec-files.html#adding-data-files देखें ।
इयान कैंपबेल

क्षमा करें, मैं आपके संदेश का एक हिस्सा समझ नहीं पा रहा हूं क्योंकि मैं अपनी कमजोर अंग्रेजी की वजह से कामना करता हूं। वह हिस्सा है "नहीं है कि a.datas ...." , क्या आप लिखना चाहते हैं कि 'a.datas ... " क्या मैंने a.datas सरणी में तार जोड़ने के बारे में जो कुछ लिखा है उसमें कुछ गड़बड़ है?
dildeolupbiten

ऊप्स! यह ध्यान रखना चाहिए कि ... हां, टाइपो के बारे में क्षमा करें। आपके कदमों ने मेरे लिए बहुत अच्छा काम किया :), मैं इस जानकारी को उनके दस्तावेज में या कहीं और नहीं खोज पाया।
इवान कैंपबेल

8

सुझाव के अनुसार मेरे सभी पथ कोड को फिर से लिखने के बजाय, मैंने कार्य निर्देशिका बदल दी:

if getattr(sys, 'frozen', False):
    os.chdir(sys._MEIPASS)

बस अपने कोड की शुरुआत में उन दो पंक्तियों को जोड़ दें, आप बाकी को छोड़ सकते हैं।


2
नहीं। अच्छे अनुप्रयोगों को शायद ही कभी कार्यशील निर्देशिका को बदलना चाहिए। बेहतर तरीके हैं।
जोनाथन रेनहार्ट

3

स्वीकार किए गए उत्तर के लिए थोड़ा संशोधन।

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)

    return os.path.join(os.path.abspath("."), relative_path)

उस मामले में वर्तमान कार्यशील निर्देशिका का उपयोग करना जहां _MEIPASS सेट नहीं है, गलत है। मेरा जवाब देखिए ।
जोनाथन रेनहार्ट

1

सबसे आम शिकायत / प्रश्न मैंने wrt PyInstaller देखा है "मेरा कोड एक डेटा फ़ाइल नहीं पा सकता है, जिसे मैंने निश्चित रूप से बंडल में शामिल किया है, वह कहाँ है?", और यह देखना आसान नहीं है कि आपका कोड क्या / कहाँ है? खोज रहा है क्योंकि निकाले गए कोड एक अस्थायी स्थान पर है और इसे बाहर निकलने पर हटा दिया जाता है। यह देखने के लिए कोड को जोड़ें कि आपके वनफाइल में क्या शामिल है और @Jonathon Reinhart का उपयोग करके यह कहाँ हैresource_path()

for root, dirs, files in os.walk(resource_path("")):
    print(root)
    for file in files:
        print( "  ",file)

0

मैंने मौजूदा जवाबों को भ्रामक पाया और जहां समस्या है, वहां काम करने के लिए लंबा समय लिया। यहाँ मुझे मिली हर चीज़ का संकलन है।

जब मैं अपना ऐप चलाता हूं, तो मुझे एक त्रुटि मिलती है Failed to execute script foo(यदि foo.pyमुख्य फ़ाइल है)। इसका निवारण करने के लिए, PyInstaller को --noconsole(या main.specबदलने के लिए संपादित करें console=False=> console=True) के साथ न चलाएं । इसके साथ, निष्पादन योग्य को कमांड-लाइन से चलाएं, और आपको विफलता दिखाई देगी।

जांच करने वाली पहली बात यह है कि यह आपकी अतिरिक्त फ़ाइलों को सही ढंग से पैकेजिंग कर रहा है। ('x', 'x')यदि आप फ़ोल्डर xको शामिल करना चाहते हैं तो आपको ट्यूपल्स को जोड़ना चाहिए ।

इसके क्रैश होने के बाद, ठीक पर क्लिक न करें। यदि आप विंडोज पर हैं, तो आप सर्च एवरीथिंग का उपयोग कर सकते हैं । अपनी फ़ाइलों में से एक के लिए देखो (जैसे। sword.png)। आपको अस्थायी पथ ढूंढना चाहिए जहां यह फ़ाइलों को अनपैक करता है (जैसे। C:\Users\ashes999\AppData\Local\Temp\_MEI157682\images\sword.png)। आप इस निर्देशिका को ब्राउज़ कर सकते हैं और सुनिश्चित कर सकते हैं कि इसमें सब कुछ शामिल है। यदि आप इसे इस तरह नहीं पा सकते हैं, तो कुछ main.exe.manifest(विंडोज) या python35.dll(यदि आप पायथन 3.5 का उपयोग कर रहे हैं) की तरह देखें।

यदि इंस्टॉलर में सब कुछ शामिल है, तो अगली संभावित समस्या फ़ाइल I / O है: आपका पायथन कोड निष्पादन योग्य निर्देशिका में, अस्थायी निर्देशिका के बजाय, फ़ाइलों के लिए देख रहा है।

इसे ठीक करने के लिए, इस प्रश्न पर कोई भी उत्तर काम करता है। व्यक्तिगत रूप से, मुझे उन सभी को काम करने का एक मिश्रण मिला: अपनी मुख्य प्रविष्टि-बिंदु फ़ाइल में सशर्त रूप से पहली बात निर्देशिका बदलें, और बाकी सब कुछ इस प्रकार काम करता है:

if hasattr(sys, '_MEIPASS'): os.chdir(sys._MEIPASS)


1
माफ़ करना। लेकिन निर्देशिकाओं को बदलना कभी सही उत्तर नहीं है। यदि कोई उपयोगकर्ता एप्लिकेशन को पथ प्रदान करता है, तो वे इसे वर्तमान निर्देशिका के सापेक्ष होने की उम्मीद करते हैं। अगर आप इसे बदलते हैं, तो यह गलत होगा।
जोनाथन रेनहार्ट

0

यदि आप अभी भी अस्थायी निर्देशिका के बजाय अपने निष्पादन योग्य के सापेक्ष फाइलें डालने की कोशिश कर रहे हैं, तो आपको इसे स्वयं कॉपी करने की आवश्यकता है। इस तरह मैंने इसे पूरा किया।

https://stackoverflow.com/a/59415662/999943

आप उस फ़ाइल में एक चरण जोड़ते हैं जो DISTPATH ​​वैरिएबल पर एक फाइल सिस्टम कॉपी करता है।

उम्मीद है की वो मदद करदे।


0

मैं इस मुद्दे से लंबे समय से (अच्छी तरह से, बहुत लंबे समय से) निपट रहा हूं । मैंने लगभग हर स्रोत को खोजा है लेकिन चीजें मेरे सिर में एक पैटर्न में नहीं मिल रही थीं।

अंत में, मुझे लगता है कि मैंने सटीक चरणों का पालन किया है, मैं साझा करना चाहता था।

ध्यान दें कि, मेरा उत्तर इस प्रश्न पर दूसरों के उत्तरों पर सुझाव का उपयोग करता है।

अजगर परियोजना के लिए एक स्टैंडअलोन निष्पादन योग्य कैसे बनाया जाए।

मान लें, हमारे पास एक project_folder है और फ़ाइल ट्री इस प्रकार है:

project_folder/
    main.py
    xxx.py # modules
    xxx.py # modules
    sound/ # directory containing the sound files
    img/ # directory containing the image files
    venv/ # if using a venv

सबसे पहले, मान लें कि आपने अपने रास्तों sound/और img/फ़ोल्डरों को चर में sound_dirऔर img_dirनिम्नानुसार परिभाषित किया है:

img_dir = os.path.join(os.path.dirname(__file__), "img")
sound_dir = os.path.join(os.path.dirname(__file__), "sound")

आपको उन्हें बदलना होगा, इस प्रकार है:

img_dir = resource_path("img")
sound_dir = resource_path("sound")

जहाँ, resource_path()आपकी स्क्रिप्ट के शीर्ष में इस प्रकार परिभाषित किया गया है:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

वर्चुअल एनवी को सक्रिय करें यदि कोई वेनव का उपयोग कर रहा है,

Pyinstaller स्थापित करें यदि आप अभी तक, द्वारा नहीं pip3 install pyinstaller:।

भागो: pyi-makespec --onefile main.pyसंकलन और निर्माण प्रक्रिया के लिए कल्पना फ़ाइल बनाने के लिए।

इससे फ़ाइल पदानुक्रम बदल जाएगा:

project_folder/
    main.py
    xxx.py # modules
    xxx.py # modules
    sound/ # directory containing the sound files
    img/ # directory containing the image files
    venv/ # if using a venv
    main.spec

खोलें (एक edior के साथ) main.spec:

इसके शीर्ष पर, सम्मिलित करें:

added_files = [

("sound", "sound"),
("img", "img")

]

फिर, की लाइन को बदलने datas=[],के लिएdatas=added_files,

यहांmain.spec देखे गए कार्यों के विवरण के लिए

Daud pyinstaller --onefile main.spec

और है कि सभी, आप चला सकते हैं mainमें project_folder/distकहीं से भी, अपने फ़ोल्डर में कुछ और बिना। आप केवल उस mainफ़ाइल को वितरित कर सकते हैं । यह अब, एक सच स्टैंडअलोन है


@JonathonReinhart यदि आप अभी भी आसपास हैं, तो मैं आपको सूचित करना चाहता था कि मैंने अपने उत्तर में आपके फ़ंक्शन का उपयोग किया है।
मुयुसन

0

मैक्स और इस पोस्ट के उत्कृष्ट उत्तर का उपयोग करके छवियों या ध्वनि और मेरे स्वयं के अनुसंधान / परीक्षण जैसी अतिरिक्त डेटा फ़ाइलों को जोड़ने के बारे में, मुझे लगा है कि मेरा मानना ​​है कि ऐसी फ़ाइलों को जोड़ने का सबसे आसान तरीका है।

आप एक जीवित उदाहरण देखने के लिए चाहते हैं, तो मेरी भंडार है यहाँ GitHub पर।

नोट: यह pyinstaller के साथ --onefileया -Fकमांड का उपयोग करने के लिए संकलित करने के लिए है ।

मेरा वातावरण इस प्रकार है।


समस्या को 2 चरणों में हल करना

समस्या को हल करने के लिए हमें विशेष रूप से Pyinstaller को बताने की ज़रूरत है कि हमारे पास अतिरिक्त फ़ाइलें हैं जिन्हें एप्लिकेशन के साथ "बंडल" करने की आवश्यकता है।

हमें एक 'सापेक्ष' पथ का उपयोग करने की भी आवश्यकता है , इसलिए जब यह पायथन स्क्रिप्ट या फ्रोजन EXE के रूप में चल रहा हो तो एप्लिकेशन ठीक से चल सकता है।

उस कहा जा रहा है के साथ हम एक समारोह है कि हमें रिश्तेदार रास्ते की अनुमति देता है की जरूरत है। मैक्स पोस्ट किए गए फ़ंक्शन का उपयोग करके हम आसानी से रिश्तेदार पथ को हल कर सकते हैं।

def img_resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

हम उपरोक्त फ़ंक्शन का उपयोग इस तरह से करेंगे ताकि एप्लिकेशन आइकन तब दिखाई दे जब ऐप या तो स्क्रिप्ट या फ्रोजन EXE के रूप में चल रहा हो।

icon_path = img_resource_path("app/img/app_icon.ico")
root.wm_iconbitmap(icon_path)

अगला कदम यह है कि हमें Pyinstaller को यह निर्देश देने की आवश्यकता है कि यह संकलन करते समय अतिरिक्त फ़ाइलों को कहां खोजना है ताकि जब एप्लिकेशन चलाया जाए, तो वे अस्थायी निर्देशिका में निर्मित हों।

हम इस मुद्दे को दो तरीकों से हल कर सकते हैं जैसा कि दस्तावेज़ में दिखाया गया है , लेकिन मैं व्यक्तिगत रूप से अपनी खुद की .spec फ़ाइल का प्रबंधन करना पसंद करता हूं ताकि हम इसे करने जा रहे हैं।

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

जोड़ा_फाइल्स अनिवार्य रूप से एक सूची है, जिसमें टपल की भूमिका है, मेरे मामले में मैं केवल एक SINGLE छवि जोड़ना चाहता हूं, लेकिन आप कई ico जोड़ सकते हैं, png या jpg का उपयोग कर('app/img/*.ico', 'app/img')सकते हैं आप एक और tuple भी बना सकते हैं जैसेadded_files = [ (), (), ()]कि कई आयात करना

टपल का पहला भाग यह निर्धारित करता है कि आप किस फ़ाइल या किस प्रकार की फ़ाइल को जोड़ना चाहते हैं और साथ ही साथ उन्हें कहाँ खोजें। इसे CTRL + C के रूप में सोचें

Tuple का दूसरा भाग Pyinstaller को बताता है, पथ 'ऐप / img /' बनाने के लिए और उस निर्देशिका में फ़ाइलों को उस स्थान पर रखें जहाँ जो भी अस्थायी निर्देशिका बनती है, जब आप .exe चलाते हैं। इसे CTRL + V के रूप में सोचें

के तहतa = Analysis([main... , मैंने सेट किया हैdatas=added_files, मूल रूप से यह हुआ करता था,datas=[]लेकिन हम चाहते हैं कि आयात की सूची अच्छी तरह से आयात की जाए, इसलिए हम अपने कस्टम आयात में पास होते हैं।

जब तक आप EXE के लिए विशिष्ट आइकन नहीं चाहते हैं, तब तक आपको ऐसा करने की आवश्यकता नहीं है, जिस फ़ाइल के विकल्प के साथ मैं exe के लिए अपने एप्लिकेशन आइकन को सेट करने के लिए Pyinstaller को बता रहा हूं icon='app\\img\\app_icon.ico'

added_files = [
    ('app/img/app_icon.ico','app/img/')
]
a = Analysis(['main.py'],
             pathex=['D:\\Github Repos\\Processes-Killer\\Process Killer'],
             binaries=[],
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='Process Killer',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True , uac_admin=True, icon='app\\img\\app_icon.ico')

EXE के लिए संकलन

मैं बहुत आलसी हूँ; मुझे उन चीजों को टाइप करना ज्यादा पसंद नहीं है, जो मुझे करनी हैं। मैंने एक .bat फ़ाइल बनाई है जिसे मैं बस क्लिक कर सकता हूं। आपको ऐसा करने की आवश्यकता नहीं है, यह कोड कमांड प्रॉम्प्ट शेल में ठीक इसके बिना चलेगा।

चूंकि .spec फ़ाइल में हमारी सभी संकलन सेटिंग और args (उर्फ विकल्प) शामिल हैं, इसलिए हमें केवल .spec फ़ाइल को Pyinstaller को देना होगा।

pyinstaller.exe "Process Killer.spec"

0

एक अन्य समाधान रनटाइम हुक बनाना है, जो आपके डेटा (फ़ाइलों / फ़ोल्डरों) को उस निर्देशिका में कॉपी (या स्थानांतरित) करेगा जिस पर निष्पादन योग्य संग्रहीत है। हुक एक साधारण अजगर फ़ाइल है जो आपके ऐप के निष्पादन से ठीक पहले लगभग कुछ भी कर सकता है। इसे सेट करने के लिए, आपको --runtime-hook=my_hook.pypyinstaller के विकल्प का उपयोग करना चाहिए । इसलिए, यदि आपका डेटा एक छवि फ़ोल्डर है, तो आपको कमांड चलाना चाहिए:

pyinstaller.py --onefile -F --add-data=images;images --runtime-hook=cp_images_hook.py main.py

Cp_images_hook.py कुछ इस तरह हो सकता है:

import sys
import os
import shutil

path = getattr(sys, '_MEIPASS', os.getcwd())

full_path = path+"\\images"
try:
    shutil.move(full_path, ".\\images")
except:
    print("Cannot create 'images' folder. Already exists.")

प्रत्येक निष्पादन से पहले छवियों के फ़ोल्डर को वर्तमान निर्देशिका (_MEIPASS फ़ोल्डर से) में स्थानांतरित कर दिया जाता है, इसलिए निष्पादन योग्य हमेशा उस तक पहुंच प्राप्त करेगा। इस तरह से आपके प्रोजेक्ट के कोड को संशोधित करने की कोई आवश्यकता नहीं है।

दूसरा उपाय

आप रनटाइम-हुक तंत्र का लाभ उठा सकते हैं और वर्तमान निर्देशिका को बदल सकते हैं, जो कुछ डेवलपर्स के अनुसार अच्छा अभ्यास नहीं है, लेकिन यह ठीक काम करता है।

हुक कोड नीचे पाया जा सकता है:

import sys
import os

path = getattr(sys, '_MEIPASS', os.getcwd())   
os.chdir(path)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.