Как автоматически определить домашний путь PySpark из исполняемого файла PyInstaller?
В моей локальной среде разработки я могу легко запустить приложение PySpark, ничего не настраивая. Однако на сервере мы используем PyInstaller для развертывания EXE. PyInstaller не включает папку _internal
библиотек PySpark в исполняемый файл, поэтому мне приходится вручную указывать путь.
Вот фрагмент моего скрипта PyInstaller manage.py
:
# -*- mode: python ; coding: utf-8 -*-
# Analysis for manage.py
a_manage = Analysis(
['manage.py'],
pathex=['/app/app_name/app_name-backend-dev'],
# I tried adding .venv/lib/python3.11/site-packages to the pathex, but it didn't work
binaries=[
('/usr/lib/x86_64-linux-gnu/libpython3.11.so.1.0', './_internal/libpython3.11.so.1.0')
],
datas=[],
hiddenimports=[
# I tried adding pyspark imports, but it didn't work
'pyspark', 'pyspark.sql', 'pyspark.sql.session', 'pyspark.sql.functions', 'pyspark.sql.types', 'pyspark.sql.column',
'app_name2.apps', 'Crypto.Cipher', 'Crypto.Util.Padding', 'snakecase', 'cryptography.fernet',
'cryptography.hazmat.primitives', 'cryptography.hazmat.primitives.kdf.pbkdf2', 'apscheduler.triggers.cron',
'apscheduler.schedulers.background', 'apscheduler.events', 'oauth2_provider.contrib.rest_framework',
'app_name.apps', 'app_name.role_permissions', 'django_filters.rest_framework', 'app_name.urls',
'app_name.others.constants', 'app_name.models', 'app_name', 'sslserver'
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)
pyz_manage = PYZ(a_manage.pure)
exe_manage = EXE(
pyz_manage,
a_manage.scripts,
[],
exclude_binaries=True,
name='manage',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll_manage = COLLECT(
exe_manage,
a_manage.binaries,
a_manage.datas,
strip=False,
upx=True,
upx_exclude=[],
name='manage',
)
При попытке запустить исполняемый файл возникает следующая ошибка:
Traceback (most recent call last):
File "portal/operations/load_data/load_data.py", line 57, in start
File "portal/pyspark/operations.py", line 498, in get_session
File "pyspark/sql/session.py", line 497, in getOrCreate
File "pyspark/context.py", line 515, in getOrCreate
File "pyspark/context.py", line 201, in __init__
File "pyspark/context.py", line 436, in _ensure_initialized
File "pyspark/java_gateway.py", line 97, in launch_gateway
File "subprocess.py", line 1026, in __init__
File "subprocess.py", line 1955, in _execute_child
FileNotFoundError: [Errno 2] No such file or directory: '/home/rhythmflow/Desktop/Reconciliation/reconciliation-backend-v3/dist/manage/_internal/./bin/spark-submit'
Чтобы решить эту проблему, я создал глобальный .venv
в домашнем каталоге Linux и установил PySpark, используя pip install pyspark
.
Затем я вручную установил переменную окружения SPARK_HOME
:
SPARK_HOME = /home/user_name/.venv/lib/python3.11/site-packages/pyspark
И использовал его в своем коде следующим образом:
SPARK_HOME = env_var("SPARK_HOME")
SparkSession.builder.appName(app_name).config("spark.home", SPARK_HOME).getOrCreate()
Этот подход отлично работает в среде разработки, но я хочу упростить процесс и избежать ручного указания домашнего пути Spark.
Вопрос:
Есть ли способ автоматически определить домашний путь PySpark в исполняемом файле PyInstaller, чтобы не устанавливать вручную переменную окружения SPARK_HOME
?
Если вам нужен каталог, в который установлен pyspark, вы должны быть в состоянии сделать что-то вроде следующего:
import os
import pyspark
SPARK_HOME = os.path.dirname(pyspark.__file__)
The issue arises because PyInstaller packages the application into a standalone executable, but it does not include the PySpark library properly, resulting in a failure to find the SPARK_HOME path or the required PySpark binaries.
Steps to resolve the issue are:
Bundle PySpark with PyInstaller: Add the path to your PySpark library in the pathex argument of the Analysis
a_manage = Analysis( ['manage.py'], pathex=['/path/to/your/project', '/home/user_name/.venv/lib/python3.11/site-packages'], ... )
include the _internal folder and spark-submit binary in the binaries list:
binaries=[ ('/home/user_name/.venv/lib/python3.11/site-packages/pyspark/_internal/bin/spark-submit', 'bin'), ('/home/user_name/.venv/lib/python3.11/site-packages/pyspark/_internal/bin/spark-class', 'bin'), ],
more ... Step3: dynamically set SPARK_HOME in code
import os
import pyspark
# Automatically set SPARK_HOME
SPARK_HOME = os.path.dirname(pyspark.__file__)
os.environ['SPARK_HOME'] = SPARK_HOME
good luck :)