পাইআইনস্টলারের সাথে ডেটা ফাইলগুলি বান্ডিলিং (--onefile)


107

আমি পাইআইনস্টলারের সাথে একটি ফাইল-ফাইল EXE তৈরি করার চেষ্টা করছি যা একটি চিত্র এবং একটি আইকন অন্তর্ভুক্ত করতে পারে। আমার জীবনের জন্য আমি এটির সাথে কাজ করতে পারি না --onefile

আমি যদি --onedirএটি করি তবে খুব ভাল কাজ করে। যখন আমি ব্যবহার করি --onefile, এটি রেফারেন্সযুক্ত অতিরিক্ত ফাইলগুলি খুঁজে পাবে না (সংকলিত EXE চালানোর সময়)। এটি ডিএলএল এবং সমস্ত কিছু সূক্ষ্মভাবে আবিষ্কার করে, কেবল দুটি চিত্র নয়।

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')]     

আমার যুক্ত করা উচিত যে আমি সেগুলি সাবফোল্ডারগুলিতেও রাখার চেষ্টা করেছি না, কোনও পার্থক্য হয়নি।

সম্পাদনা: পাইআইনস্টলার আপডেটের কারণে নতুন উত্তরটিকে সঠিক হিসাবে চিহ্নিত করা হয়েছে।


11
তোমাকে অনেক ধন্যবাদ! এখানে লাইনটি ( a.datas += ...) সত্যই আমাকে এখনই সহায়তা করেছে। পাইনস্টলারের ডকুমেন্টেশন ব্যবহারের বিষয়ে কথা বলে COLLECTতবে এটি ব্যবহারের সময় বাইনারিগুলিতে ফাইলগুলি ফেলতে ব্যর্থ হয়--onefile
ইগোর সেরিব্রায়ানি

@ ইগোরসিরিব্রায়নি: দ্বিতীয়! আমি ঠিক ঠিক একই সমস্যা ছিল।
হুব্রো

আমার .exe ক্র্যাশ হয় যখন আমি মেনু
বারটিতে

1
আমদানি শেষ হয়ে গেলে অস্থায়ী ফোল্ডারটি অদৃশ্য হয়ে যায় তা বিবেচনা করুন, সুতরাং এর ভিতরে কী রয়েছে তা পরীক্ষা করে দেখতে sys._MEIPASS আপনার প্রোগ্রামের প্রধান
হিথোইন

গাছটির বাক্য () সিনট্যাক্স ব্যবহারেরও কি এমন কোনও উপায় আছে যা আমি প্রায় চারপাশে দেখেছি?
ফতুহোকু

উত্তর:


152

পাইআইনস্টলারের আরও নতুন সংস্করণগুলি 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 এর সাথে ব্যবহার করছি এবং আমার _MEIPASS2enর্ষা নেই, তবে sys._MEIPASSভাল কাজ করছে, সুতরাং +১। আমি পরামর্শ দিচ্ছি:path = getattr(sys, '_MEIPASS', os.getcwd())
কেবিইচ

2
+1 টি। তার জন্য ধন্যবাদ. কিছু সময়ের জন্য _MEIPASS2 এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করার চেষ্টা করছি, স্পষ্টতই আমি আমার কোডটি তখনই লিখেছিলাম যখন এটি পরিবেশের পরিবর্তনশীল ছিল, কারণ আমি মনে করি এটি কাজ করে। হঠাৎ করেই, এটি থেমে গেছে, যখন আমি সম্প্রতি সংশোধন করেছি।
ফ্যাভিল অরবেদিওস

8
আমি AttributeErrorআরও সাধারণের পরিবর্তে ধরার পরামর্শ দেব Exception। আমি বিষয় যেখানে আমি sys আমদানি ও পথ চুপটি থেকে ডিফল্ট অনুপস্থিত ছিল গাড়ীতে আঘাত os.path.abspath
হারুন

আপনি আমার সমস্যা সমাধানে সহায়তা করতে সক্ষম হতে পারেন ।
ফিলিপ

1
_MEIPASS সেট না করা ক্ষেত্রে বর্তমানে চলমান ওয়ার্কিং ডিরেক্টরি ব্যবহার করা ভুল। আমার উত্তর দেখুন ।
জোনাথন রেইনহার্ট

51

পাইনস্টলারের সাহায্যে অস্থায়ী ফোল্ডারে আপনার ডেটা আনপ্যাক করা হয় এবং _MEIPASS2পরিবেশ ডিরেক্টরিতে এই ডিরেক্টরি পাথ সংরক্ষণ করা হয় । _MEIPASS2প্যাক-মোডে দির পেতে এবং আনপ্যাকড (বিকাশ) মোডে স্থানীয় ডিরেক্টরি ব্যবহার করতে, আমি এটি ব্যবহার করি:

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
এটি কীভাবে, কখন এবং কোথায় ব্যবহার করা হবে?
গিসিটল

4
আপনি পাইপি ইনস্টলারের সাথে সংকলন করার চেষ্টা করছেন .py ফাইলটিতে আপনার এই স্ক্রিপ্টটি ব্যবহার করা উচিত। .Spec ফাইলে এই কোড স্নিপেট রাখবেন না, এটি কার্যকর হবে না। আপনি যে পথটি সাধারণত লিখেছেন তার বিকল্প স্থির করে আপনার ফাইলগুলিতে অ্যাক্সেস করুন resource_path("file_to_be_accessed.mp3")। সতর্কতা অবলম্বন করুন যে পাইআইনস্টলারের বর্তমান সংস্করণটির জন্য আপনার সর্বোচ্চ 'উত্তরটি ব্যবহার করা উচিত।
এক্সিলারেশন-জি

1
এই উত্তরটি --one-fileবিকল্প ব্যবহারের ক্ষেত্রে নির্দিষ্ট ?
ফতুহোকু

আপনি আমার সমস্যা সমাধানে সহায়তা করতে সক্ষম হতে পারেন ।
ফিলিপ

_MEIPASS সেট না করা ক্ষেত্রে বর্তমানে চলমান ওয়ার্কিং ডিরেক্টরি ব্যবহার করা ভুল। আমার উত্তর দেখুন ।
জোনাথন রেইনহার্ট

30

অন্যান্য উত্তরগুলির সমস্ত ক্ষেত্রেই অ্যাপ্লিকেশন পাইআইনস্টল নয় (যেমন সেট করা নেই) সেই ক্ষেত্রে বর্তমান চলমান ডিরেক্টরিটি ব্যবহার করে 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'](ওএস এনভায়রনমেন্ট ব্যবহার করে) ডিরেক্টরি পাওয়ার একটি পুরানো পদ্ধতি ছিল। আফাইক sys._MEIPASSএখন একমাত্র সঠিক পদ্ধতি।
জোনাথন রাইনহার্ট

হ্যালো, resource_path()মূল স্ক্রিপ্টে থাকা অবস্থায় আপনার সমাধানটি ঠিকঠাক কাজ করে । পরিবর্তে এটি একটি মডিউলে লেখা যখন এটি কাজ করার কোন উপায় আছে? এখন পর্যন্ত, এটি ফোল্ডারে যেখানে মডিউলটি মূল নয়, সেখানে সংস্থান পেতে চেষ্টা করবে।
গুইমোট

1
@ গাইমোট শোনায় এই উত্তরটির কোডটি নকশাকৃতভাবে কাজ করছে: এটি মডিউলটিকে সরবরাহ করে যেগুলি এটি সরবরাহ করে কারণ এটি ব্যবহার করে __file__। আপনি যদি চান যে কোনও মডিউল তার নিজস্ব ক্ষেত্রের বাইরেও সংস্থানগুলি অ্যাক্সেস করতে সক্ষম হবে তবে আপনাকে প্রয়োগ করতে হবে যে আমদানি কোডটি আপনার মডিউলটি ব্যবহারের জন্য তাদের জন্য একটি পথ সরবরাহ করে, যেমন মডিউল দ্বারা "set_resource_location ()" কল সরবরাহ করে আমদানিকারী কলগুলি - পাইনাস্টলার ব্যবহার না করার সময় আপনার কীভাবে কাজ করা উচিত তা থেকে এটি কোনও আলাদা বলে মনে করবেন না।
বার্নি 4'19

@ বার্নি ইঙ্গিতটির জন্য ধন্যবাদ! আমি এই লাইন বরাবর কিছু চেষ্টা করব।
গুইমোট

14

সম্ভবত আমি একটি পদক্ষেপ মিস করেছি বা কিছু ভুল করেছি তবে যে পদ্ধতিগুলি উপরে রয়েছে সেগুলি পাইআইনস্টলারের সাথে ডেটা ফাইলকে একটি এক্সি ফাইলগুলিতে বান্ডিল করেনি। আমি যে পদক্ষেপগুলি করেছি তা ভাগ করে নিতে দিন।

  1. পদক্ষেপ: সায় এবং ওএস মডিউল আমদানি করে আপনার পাই ফাইলটিতে উপরের একটি পদ্ধতি লিখুন। আমি উভয় চেষ্টা করেছিলাম। শেষটি হ'ল:

    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-madepec 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. পদক্ষেপ: আমি উপরের পদক্ষেপগুলি অনুসরণ করেছি, তারপরে স্পেক ফাইলটি সংরক্ষণ করেছি। শেষ পর্যন্ত কনসোলটি খুলুন এবং লিখুন, পাইইনস্টলার ফাইল.স্পেক (আমার ক্ষেত্রে, ফাইল = রূপান্তরকারী-জিইআই)।

উপসংহার: ডিস্ট ফোল্ডারে একাধিক ফাইল রয়েছে।

দ্রষ্টব্য: আমি পাইথন 3.5 ব্যবহার করছি।

সম্পাদনা: অবশেষে এটি জোনাথন রাইনহার্টের পদ্ধতিতে কাজ করে।

  1. পদক্ষেপ: সাইল ও ওএস আমদানি করে আপনার পাইথন ফাইলে নীচের কোডগুলি যুক্ত করুন।

    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 ফাইলটি খুলুন এবং a.datas অ্যারে সংযোজন করুন এবং এপিকে ক্লাসে আইকনটি যুক্ত করুন, যা 3 য় ধাপে সম্পাদনার আগে উপরে দেওয়া হয়েছিল।
  6. পদক্ষেপ: পাথ ফাইলটি সংরক্ষণ এবং প্রস্থান করুন। আপনার ফোল্ডারে যান যা স্পেক এবং পাই ফাইল অন্তর্ভুক্ত করে। আবার কনসোল উইন্ডোটি খুলুন এবং নীচের কমান্ডটি টাইপ করুন:

        pyinstaller your_file.spec

6. পদক্ষেপের পরে আপনার একটি ফাইল ব্যবহারের জন্য প্রস্তুত।


ধন্যবাদ @ দিলড! এমন নয় যে a.datasপদক্ষেপ 5 থেকে অ্যারের স্ট্রিং tuples লাগে, দেখতে pythonhosted.org/PyInstaller/spec-files.html#adding-data-files রেফারেন্সের জন্য।
ইয়ান ক্যাম্পবেল

দুঃখিত, আমি আপনার বার্তার একটি অংশও বুঝতে পারি না পাশাপাশি আমার দুর্বল ইংরেজি বলে আমিও ইচ্ছুক। সেই অংশটি হ'ল "আডাটাস ...." না , আপনি কি লিখতে চেয়েছিলেন যে আ.দাতাস ... " অ্যাডটাস অ্যারেতে স্ট্রিং যুক্ত করার বিষয়ে আমি যা লিখেছিলাম তাতে কিছু ভুল আছে?
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

পাইআইনস্টলারের সবচেয়ে সাধারণ অভিযোগ / প্রশ্ন যা আমি পাইছি "হ'ল আমার কোড কোনও ডেটা ফাইল খুঁজে পাচ্ছে না যা আমি অবশ্যই বান্ডলে অন্তর্ভুক্ত করেছি, এটি কোথায়?", এবং আপনার কোডটি কোথায় / কোথায় তা দেখতে সহজ হয় না অনুসন্ধান করা হচ্ছে কারণ নিষ্কাশিত কোডটি একটি অস্থায়ী স্থানে থাকে এবং যখন এটি বের হয় তখন তা সরানো হয়। আপনার জোনাফাইলের মধ্যে কী অন্তর্ভুক্ত রয়েছে এবং এটি কোথায় রয়েছে তা দেখতে এই বিট কোড যুক্ত করুন , @ জোনাথন রেইনহার্টস ব্যবহার করে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মূল ফাইল হয়)। এটির সমস্যা সমাধানের জন্য, --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/
    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

খোলা (একটি প্রান্ত সহ) main.spec:

এর শীর্ষে, inোকান:

added_files = [

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

]

তারপর, লাইন পরিবর্তন datas=[],করতেdatas=added_files,

এখানেmain.spec দেখুন অপারেশন বিশদ জন্য

চালান pyinstaller --onefile main.spec

আর যে সব, আপনি চালাতে পারেন mainমধ্যে project_folder/distযে কোন জায়গা থেকে, তার ফোল্ডারে অন্য কিছু করেও। আপনি কেবল সেই mainফাইলটি বিতরণ করতে পারেন । এটি এখন, একটি সত্য স্ট্যান্ডেলোন


@ জোনাথনরাইনহার্ট যদি আপনি এখনও আশেপাশে থাকেন তবে আমি আপনাকে জানাতে চাই যে আমি আমার উত্তরে আপনার ফাংশনটি ব্যবহার করেছি।
ময়ুস্তান

0

চিত্র এবং শব্দ এবং আমার নিজের গবেষণা / পরীক্ষার মতো অতিরিক্ত ডেটা ফাইল যুক্ত করার বিষয়ে ম্যাক্স এবং এই পোস্টের দুর্দান্ত উত্তরটি ব্যবহার করে , আমি বিশ্বাস করি যে এই জাতীয় ফাইলগুলি যুক্ত করার সবচেয়ে সহজ উপায় আমি কী বিশ্বাস করি।

আপনি যদি কোনও জীবন্ত উদাহরণ দেখতে চান তবে আমার সংগ্রহশালাটি এখানে গিটহাবটিতে রয়েছে।

নোট: এই ব্যবহার সংকলন জন্য --onefileবা -Fpyinstaller সঙ্গে কমান্ড।

আমার পরিবেশটি নিম্নরূপ।


2 টি পদক্ষেপে সমস্যা সমাধান করা

সমস্যাটি সমাধান করার জন্য আমাদের পিনস্টলারের কাছে বিশেষভাবে বলতে হবে যে আমাদের কাছে অতিরিক্ত ফাইল রয়েছে যা অ্যাপ্লিকেশনটির সাথে "বান্ডিল" করা দরকার।

আমাদের একটি 'আপেক্ষিক' পথও ব্যবহার করা দরকার , যাতে পাইথন স্ক্রিপ্ট বা হিমায়িত 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)

পরবর্তী পদক্ষেপটি হ'ল পাইনিস্টলারের নির্দেশ দেওয়া দরকার যে এটি সংকলন করার সময় অতিরিক্ত ফাইলগুলি কোথায় সন্ধান করতে হবে যাতে যখন অ্যাপ্লিকেশনটি চালানো হয় তখন তারা অস্থায়ী ডিরেক্টরিতে তৈরি হয়।

ডকুমেন্টেশনে দেখানো হিসাবে আমরা এই সমস্যাটি দুটি উপায়ে সমাধান করতে পারি , তবে আমি ব্যক্তিগতভাবে আমার নিজের .spec ফাইল পরিচালনা করতে পছন্দ করি যাতে আমরা এটি কীভাবে চলছি।

প্রথমত, আপনার কাছে অবশ্যই একটি .spec ফাইল থাকা উচিত। আমার ক্ষেত্রে, আমি pyinstallerঅতিরিক্ত আরগগুলি নিয়ে চালিয়ে যা প্রয়োজন তা তৈরি করতে সক্ষম হয়েছি , আপনি এখানে অতিরিক্ত আরগগুলি খুঁজে পেতে পারেন । এর কারণে, আমার স্পেক ফাইলটি আপনার চেয়ে কিছুটা আলাদা লাগতে পারে তবে আমি গুরুত্বপূর্ণ বিটগুলি ব্যাখ্যা করার পরে রেফারেন্সের জন্য এগুলি সব পোস্ট করছি।

যোগ_ফায়ালগুলি মূলত টুপলের সমন্বিত একটি তালিকা, আমার ক্ষেত্রে আমি কেবল একটি সাধারণ চিত্র যুক্ত করতে চাই, তবে আপনি একাধিক আইকোন, পিএনজি বা জেপিজির ব্যবহার যুক্ত('app/img/*.ico', 'app/img')করতে পারেনadded_files = [ (), (), ()]আপনি একাধিক আমদানি করারমতো আরও একটি টুপল তৈরিকরতে পারেন

টিউলের প্রথম অংশটি নির্ধারণ করে যে আপনি কোন ফাইল বা কোন ধরণের ফাইল যুক্ত করতে চান সেই সাথে তাদের কোথায় সন্ধান করবেন। এটি সিটিআরএল + সি হিসাবে ভাবেন

টিউলের দ্বিতীয় অংশটি পাইনস্টলারের কাছে বলে, পাথটি 'অ্যাপ / ইমগ /' তৈরি করতে এবং সেই ডিরেক্টরিতে ফাইলগুলি স্থাপন করতে আপনি যখন .exe রান করেন তখন যা কিছু টেম্প ডিরেক্টরি তৈরি হয় তার সাথে সম্পর্কিত। এটি সিটিআরএল + ভি হিসাবে ভাবেন

এর অধীনেa = Analysis([main... , আমি সেট করেছিdatas=added_files, মূলত এটি ব্যবহৃত হতdatas=[]তবে আমরা আমদানিগুলির তালিকাটি ভাল, আমদানি করতে চাই যাতে আমরা আমাদের কাস্টম আমদানিতে পাস করি।

EXE- র জন্য নির্দিষ্ট আইকন না চাইলে আপনাকে এগুলি করার দরকার নেই, অনুমিত ফাইলের নীচে আমি পাইনস্টলারকে বলছি বিকল্পটির সাথে এক্সের জন্য আমার অ্যাপ্লিকেশন আইকনটি সেট করতে 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 ফাইলটিতে আমাদের সমস্ত সংকলন সেটিংস এবং আরগগুলি (ওরফে বিকল্পগুলি) থাকে তবে আমাদের কেবল সেই .spec ফাইলটি পাইনস্টলারের কাছে দিতে হবে।

pyinstaller.exe "Process Killer.spec"

0

আরেকটি সমাধান হ'ল রানটাইম হুক করা, যা আপনার ডেটা (ফাইল / ফোল্ডারগুলি) এক্সিকিউটেবল সংরক্ষণযোগ্য ডিরেক্টরিতে অনুলিপি (বা স্থানান্তরিত) করবে। হুক একটি সাধারণ অজগর ফাইল যা আপনার অ্যাপ্লিকেশনটি প্রয়োগের ঠিক আগে, প্রায় কিছু করতে পারে। এটি সেট করার জন্য, আপনার --runtime-hook=my_hook.pyপিনস্টলারের বিকল্পটি ব্যবহার করা উচিত । সুতরাং, যদি আপনার ডেটা কোনও চিত্র ফোল্ডার হয় তবে আপনার কমান্ডটি চালানো উচিত:

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)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.