[python] PyInstaller (-onefile)로 데이터 파일 번들링
이미지와 아이콘을 포함하는 PyInstaller로 한 파일 EXE를 빌드하려고합니다. 나는 내 삶을 위해 그것을 작동시킬 수 없습니다 --onefile
.
내가 할 경우 --onedir
모든 것이 잘 작동합니다. 를 사용 --onefile
하면 참조 된 추가 파일을 찾을 수 없습니다 (컴파일 된 EXE를 실행할 때). 두 이미지가 아닌 DLL과 다른 모든 것을 찾습니다.
EXE ( \Temp\_MEI95642\
예를 들어)를 실행할 때 생성 된 temp-dir을 살펴 보았고 파일이 실제로 거기에 있습니다. 그 임시 디렉토리에 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 업데이트로 인해 최신 답변이 올바른 것으로 표시되었습니다.
답변
최신 버전의 PyInstaller는 env
더 이상 변수를 설정하지 않으므로 Shish의 탁월한 답변 이 작동하지 않습니다. 이제 경로는 다음과 같이 설정됩니다 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)
답변
pyinstaller는 데이터를 임시 폴더에 압축 해제하고이 디렉토리 경로를 _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"
답변
다른 모든 답변 은 응용 프로그램이 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)
답변
아마도 내가 한 단계를 놓쳤거나 뭔가 잘못했지만 위의 방법은 PyInstaller와 함께 데이터 파일을 하나의 exe 파일로 묶지 않았습니다. 내가 한 단계를 공유하겠습니다.
-
단계 : 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)
-
단계 : 콘솔에 pyi-makespec file.py 를 작성하여 file.spec 파일을 만듭니다.
-
단계 : Open, file.spec with Notepad ++ to add the data files like below :
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')
-
단계 : 위 단계를 따른 다음 사양 파일을 저장했습니다. 마침내 콘솔을 열고 pyinstaller file.spec (제 경우에는 file = Converter-GUI)을 작성합니다.
결론 : dist 폴더에는 여전히 하나 이상의 파일이 있습니다.
참고 : 저는 Python 3.5를 사용하고 있습니다.
편집 : 마지막으로 Jonathan Reinhart의 방법 으로 작동합니다 .
-
단계 : 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)
-
단계 : 파일 경로를 추가하여 위 함수를 호출합니다.
image_path = resource_path("Converter-GUI.ico")
-
단계 : 코드에 경로가 필요한 위치에 함수를 호출하는 위의 변수를 작성하십시오. 제 경우에는 다음과 같습니다.
self.window.iconbitmap(image_path)
-
단계 : Python 파일의 동일한 디렉토리에서 콘솔을 열고 아래와 같은 코드를 작성합니다.
pyinstaller --onefile your_file.py
- 단계 : python 파일의 .spec 파일을 열고 a.datas 배열을 추가하고 3 단계에서 편집하기 전에 위에 제공된 exe 클래스에 아이콘을 추가합니다.
-
단계 : 경로 파일을 저장하고 종료합니다. spec 및 py 파일이 포함 된 폴더로 이동하십시오. 콘솔 창을 다시 열고 아래 명령을 입력하십시오.
pyinstaller your_file.spec
6. 단계가 끝나면 하나의 파일을 사용할 수 있습니다.
답변
제안 된대로 모든 경로 코드를 다시 작성하는 대신 작업 디렉토리를 변경했습니다.
if getattr(sys, 'frozen', False):
os.chdir(sys._MEIPASS)
코드 시작 부분에이 두 줄을 추가하기 만하면 나머지는 그대로 둘 수 있습니다.
답변
허용되는 답변에 약간의 수정이 있습니다.
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)
답변
내가 wrt PyInstaller에서 본 가장 일반적인 불만 / 질문은 “내 코드가 번들에 확실히 포함 된 데이터 파일을 찾을 수 없습니다. 어디에 있습니까?”이며, 코드가 무엇인지, 어디에 있는지 쉽게 알 수 없습니다. 추출 된 코드가 임시 위치에 있고 종료시 제거되기 때문에 검색 중입니다. 코드의이 비트를 추가 참조 하여 onefile에 포함하고, @Jonathon 라인 하트의를 사용하여이되는 경우 어떤resource_path()
for root, dirs, files in os.walk(resource_path("")):
print(root)
for file in files:
print( " ",file)