fix: remove ctypes.WinDLL preload — use only os.add_dll_directory
ctypes.WinDLL uses LoadLibraryW which does NOT search user DLL dirs registered via os.add_dll_directory/AddDllDirectory. It was throwing FileNotFoundError and blocking the import before tesserocr was ever tried. Python 3.8+ loads .pyd files with LOAD_LIBRARY_SEARCH_USER_DIRS which DOES search user-registered dirs for the pyd and all its transitive DLL dependencies. os.add_dll_directory(Library\bin) alone is sufficient. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
d9383cc164
commit
77ad97022e
+5
-2
@@ -104,14 +104,17 @@ 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 ---
|
||||
:: Note: os.add_dll_directory (not ctypes.WinDLL) is the correct mechanism.
|
||||
:: Python 3.8+ loads .pyd files with LOAD_LIBRARY_SEARCH_USER_DIRS which
|
||||
:: searches user-registered dirs for the pyd AND all its transitive deps.
|
||||
echo.
|
||||
echo Verifying dependencies...
|
||||
"%PYTHON%" -c "import os,sys,ctypes;dirs=[d for d in [os.path.join(sys.prefix,'Library',x) for x in ['bin','mingw-w64\\bin','usr\\bin']] if os.path.isdir(d)];[os.add_dll_directory(d) for d in dirs];os.environ.__setitem__('PATH',os.pathsep.join(dirs)+os.pathsep+os.environ.get('PATH',''));t=os.path.join(sys.prefix,'Library','bin','tesseract51.dll');ctypes.WinDLL(t) if os.path.isfile(t) else None;import cv2,mss,numpy,tesserocr,discord,transitions,rapidfuzz" >nul 2>&1
|
||||
"%PYTHON%" -c "import os,sys;[os.add_dll_directory(d) for d in [os.path.join(sys.prefix,'Library',x) for x in ['bin','mingw-w64\\bin','usr\\bin']] if os.path.isdir(d)];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'); dirs=[d for d in [os.path.join(sys.prefix,'Library',x) for x in ['bin','mingw-w64\\bin','usr\\bin']] if os.path.isdir(d)]; [os.add_dll_directory(d) for d in dirs]; os.environ.__setitem__('PATH',os.pathsep.join(dirs)+os.pathsep+os.environ.get('PATH','')); t=os.path.join(lb,'tesseract51.dll'); r=ctypes.WinDLL(t) if os.path.isfile(t) else 'missing'; print(' ctypes tesseract51.dll:',type(r).__name__); __import__('tesserocr'); print(' tesserocr import: OK')" 2>&1
|
||||
"%PYTHON%" -c "import os,sys; 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'); [os.add_dll_directory(d) for d in [os.path.join(sys.prefix,'Library',x) for x in ['bin','mingw-w64\\bin','usr\\bin']] if os.path.isdir(d)]; import tesserocr; print(' tesserocr import: 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.
|
||||
|
||||
+8
-19
@@ -1,28 +1,17 @@
|
||||
import os
|
||||
import sys
|
||||
if os.name == 'nt':
|
||||
import ctypes
|
||||
# Collect all conda DLL dirs that exist
|
||||
_conda_dll_dirs = [d for d in [
|
||||
# Python 3.8+ loads .pyd files with LOAD_LIBRARY_SEARCH_USER_DIRS, which
|
||||
# searches directories registered via os.add_dll_directory() — including
|
||||
# all transitive DLL dependencies. This is the correct mechanism for
|
||||
# making tesserocr find tesseract51.dll and leptonica without conda activate.
|
||||
for _d in [
|
||||
os.path.join(sys.prefix, 'Library', 'bin'),
|
||||
os.path.join(sys.prefix, 'Library', 'mingw-w64', 'bin'),
|
||||
os.path.join(sys.prefix, 'Library', 'usr', 'bin'),
|
||||
] if os.path.isdir(d)]
|
||||
# 1) os.add_dll_directory: lets Python find tesserocr's direct deps when
|
||||
# loading the .pyd via LOAD_LIBRARY_SEARCH_USER_DIRS.
|
||||
for _d in _conda_dll_dirs:
|
||||
os.add_dll_directory(_d)
|
||||
# 2) Prepend to PATH: when ctypes.WinDLL loads tesseract51.dll by absolute
|
||||
# path, Windows resolves *that DLL's* own transitive deps (leptonica,
|
||||
# zlib, libpng, …) using the standard search order: app-dir → System32
|
||||
# → Windows-dir → cwd → PATH. Those libs live in Library\bin, not
|
||||
# System32, so without PATH they won't be found.
|
||||
os.environ['PATH'] = os.pathsep.join(_conda_dll_dirs) + os.pathsep + os.environ.get('PATH', '')
|
||||
# 3) Pre-load tesseract51.dll now (PATH is set, so all its deps resolve).
|
||||
# Once it's in the DLL cache the .pyd import below reuses it.
|
||||
_tess = os.path.join(sys.prefix, 'Library', 'bin', 'tesseract51.dll')
|
||||
if os.path.isfile(_tess):
|
||||
ctypes.WinDLL(_tess)
|
||||
]:
|
||||
if os.path.isdir(_d):
|
||||
os.add_dll_directory(_d)
|
||||
from tesserocr import PyTessBaseAPI, OEM
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
+6
-11
@@ -1,22 +1,17 @@
|
||||
# Fix: On Windows, Python 3.8+ requires os.add_dll_directory for conda-forge DLLs
|
||||
# that tesserocr depends on (tesseract51.dll, leptonica-1.78.0.dll).
|
||||
# This must run BEFORE any import that might trigger tesserocr loading.
|
||||
# os.add_dll_directory registers dirs with LOAD_LIBRARY_SEARCH_USER_DIRS,
|
||||
# which applies to the .pyd and all its transitive DLL dependencies.
|
||||
import os, sys
|
||||
if sys.platform == "win32":
|
||||
import ctypes
|
||||
_bundled = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "conda_env", "Library", "bin")
|
||||
_conda_dll_dirs = [d for d in [
|
||||
_bundled,
|
||||
for _d in [
|
||||
os.path.join(sys.prefix, "Library", "bin"),
|
||||
os.path.join(sys.prefix, "Library", "mingw-w64", "bin"),
|
||||
os.path.join(sys.prefix, "Library", "usr", "bin"),
|
||||
] if os.path.isdir(d)]
|
||||
for _d in _conda_dll_dirs:
|
||||
os.add_dll_directory(_d)
|
||||
os.environ['PATH'] = os.pathsep.join(_conda_dll_dirs) + os.pathsep + os.environ.get('PATH', '')
|
||||
_tess = os.path.join(sys.prefix, "Library", "bin", "tesseract51.dll")
|
||||
if os.path.isfile(_tess):
|
||||
ctypes.WinDLL(_tess)
|
||||
]:
|
||||
if os.path.isdir(_d):
|
||||
os.add_dll_directory(_d)
|
||||
|
||||
from dataclasses import dataclass
|
||||
from input_layer import keyboard
|
||||
|
||||
+5
-9
@@ -1,18 +1,14 @@
|
||||
# Fix: On Windows, Python 3.8+ requires os.add_dll_directory for conda-forge DLLs
|
||||
# that tesserocr depends on (tesseract51.dll, leptonica-1.78.0.dll).
|
||||
import os, sys
|
||||
if sys.platform == "win32":
|
||||
import ctypes
|
||||
_conda_dll_dirs = [d for d in [
|
||||
for _d in [
|
||||
os.path.join(sys.prefix, "Library", "bin"),
|
||||
os.path.join(sys.prefix, "Library", "mingw-w64", "bin"),
|
||||
os.path.join(sys.prefix, "Library", "usr", "bin"),
|
||||
] if os.path.isdir(d)]
|
||||
for _d in _conda_dll_dirs:
|
||||
os.add_dll_directory(_d)
|
||||
os.environ['PATH'] = os.pathsep.join(_conda_dll_dirs) + os.pathsep + os.environ.get('PATH', '')
|
||||
_tess = os.path.join(sys.prefix, "Library", "bin", "tesseract51.dll")
|
||||
if os.path.isfile(_tess):
|
||||
ctypes.WinDLL(_tess)
|
||||
]:
|
||||
if os.path.isdir(_d):
|
||||
os.add_dll_directory(_d)
|
||||
|
||||
from beautifultable import BeautifulTable
|
||||
import logging
|
||||
|
||||
Reference in New Issue
Block a user