fix: use conda run instead of direct python for DLL loading

Every approach to manually replicating conda's DLL environment from
Python code or batch PATH manipulation has failed. conda run activates
the environment exactly like "conda activate botty" — setting PATH,
running activate.d scripts, and properly resolving all transitive DLL
dependencies for tesseract51.dll.

run_botty.bat now derives conda.exe from the botty python.exe path
(two levels up: envs/botty -> envs -> miniforge3 -> Scripts/conda.exe)
and uses "conda run -n botty --no-capture-output python src/main.py".

install.bat smoke test now uses "%CONDA_EXE% run -n botty python -c ..."
which already has CONDA_EXE set from the install step.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
alex
2026-05-24 14:37:14 +02:00
co-authored by Claude Sonnet 4.6
parent bdd6247342
commit e1c18faf26
2 changed files with 23 additions and 18 deletions
+4 -10
View File
@@ -91,27 +91,21 @@ exit /b 1
:env_created
echo Botty Python: %PYTHON%
:: Prepend conda DLL dirs to PATH at the process level so the Windows DLL
:: loader finds tesseract51.dll's transitive deps (leptonica, zlib, etc.)
:: when ctypes loads it. os.environ['PATH'] set from inside Python is too late.
for %%F in ("%PYTHON%") do set "_CONDA_ENV=%%~dpF"
set "_CONDA_ENV=%_CONDA_ENV:~0,-1%"
set "PATH=%_CONDA_ENV%\Library\bin;%_CONDA_ENV%\Library\mingw-w64\bin;%_CONDA_ENV%\Library\usr\bin;%PATH%"
:: --- Force-reinstall the tesserocr wheel so the correct binary is always used ---
echo.
echo Installing tesserocr wheel...
"%PYTHON%" -m pip install --force-reinstall "%~dp0dependencies\tesserocr-2.5.2-cp310-cp310-win_amd64.whl" >nul 2>&1
:: --- Smoke test: import key dependencies ---
:: --- Smoke test via conda run (activates the full env like "conda activate botty") ---
:: This is the only reliable way to ensure all DLL transitive deps are resolved.
echo.
echo Verifying dependencies...
"%PYTHON%" -c "import os,sys,ctypes;d=[x for x in [os.path.join(sys.prefix,'Library',s) for s in ['bin','mingw-w64\\bin','usr\\bin']] if os.path.isdir(x)];[os.add_dll_directory(x) for x in d];f=ctypes.windll.kernel32.LoadLibraryExW;f.restype=ctypes.c_void_p;f.argtypes=[ctypes.c_wchar_p,ctypes.c_void_p,ctypes.c_ulong];[f(os.path.join(x,'tesseract51.dll'),None,0x1000) for x in d if os.path.isfile(os.path.join(x,'tesseract51.dll'))];import cv2,mss,numpy,tesserocr,discord,transitions,rapidfuzz" >nul 2>&1
"%CONDA_EXE%" run -n botty python -c "import cv2,mss,numpy,tesserocr,discord,transitions,rapidfuzz" >nul 2>&1
if %errorlevel% neq 0 (
echo.
echo WARNING: Dependency check failed. Running diagnostics...
echo.
"%PYTHON%" -c "import os,sys,ctypes;lb=os.path.join(sys.prefix,'Library','bin');dlls=[f for f in (os.listdir(lb) if os.path.isdir(lb) else []) if any(k in f.lower() for k in ['tess','lepton'])];print(' Tesseract DLLs in Library/bin:',dlls or 'NONE');d=[x for x in [os.path.join(sys.prefix,'Library',s) for s in ['bin','mingw-w64\\bin','usr\\bin']] if os.path.isdir(x)];[os.add_dll_directory(x) for x in d];f=ctypes.windll.kernel32.LoadLibraryExW;f.restype=ctypes.c_void_p;f.argtypes=[ctypes.c_wchar_p,ctypes.c_void_p,ctypes.c_ulong];t=os.path.join(lb,'tesseract51.dll');h=f(t,None,0x1000) if os.path.isfile(t) else None;print(' LoadLibraryExW tesseract51.dll:','OK' if h else 'FAILED');import tesserocr;print(' tesserocr import: OK')" 2>&1
"%CONDA_EXE%" run -n botty python -c "import tesserocr; print(' tesserocr: OK')" 2>&1
echo.
echo *** Do NOT run "pip install tesserocr" manually - it builds from source and
echo *** will always fail on Windows. Re-run install.bat to fix dependencies.
+19 -8
View File
@@ -1,17 +1,28 @@
@echo off
setlocal
setlocal enabledelayedexpansion
set "BOTTY_DIR=%~dp0"
cd /d "%BOTTY_DIR%"
call "%BOTTY_DIR%find_python.bat"
:: Prepend conda DLL dirs to PATH at the process level so the Windows DLL
:: loader finds tesseract51.dll's transitive deps (leptonica, zlib, etc.)
:: when ctypes loads it. os.environ['PATH'] set from inside Python is too late.
for %%F in ("%PYTHON%") do set "_CONDA_ENV=%%~dpF"
set "_CONDA_ENV=%_CONDA_ENV:~0,-1%"
set "PATH=%_CONDA_ENV%\Library\bin;%_CONDA_ENV%\Library\mingw-w64\bin;%_CONDA_ENV%\Library\usr\bin;%PATH%"
:: Derive conda.exe from the botty python.exe path:
:: envs\botty\python.exe -> envs\botty -> envs -> miniforge3 -> Scripts\conda.exe
for %%F in ("%PYTHON%") do set "_ENV=%%~dpF"
set "_ENV=%_ENV:~0,-1%"
for %%F in ("%_ENV%") do set "_ENVS=%%~dpF"
set "_ENVS=%_ENVS:~0,-1%"
for %%F in ("%_ENVS%") do set "_ROOT=%%~dpF"
set "_ROOT=%_ROOT:~0,-1%"
set "_CONDA=%_ROOT%\Scripts\conda.exe"
echo Launching Botty ...
%PYTHON% "%BOTTY_DIR%src\main.py"
if exist "%_CONDA%" (
:: conda run activates the full environment (PATH, DLL dirs, etc.)
:: exactly like "conda activate botty" - guaranteed to find all DLLs.
"%_CONDA%" run -n botty --no-capture-output python "%BOTTY_DIR%src\main.py"
) else (
echo WARNING: conda.exe not found at %_CONDA%, falling back to direct launch.
"%PYTHON%" "%BOTTY_DIR%src\main.py"
)
pause