v0.6.0 BigUpdate
This commit is contained in:
+48
-15
@@ -22,6 +22,11 @@ class OfficeInstall:
|
||||
python_path: str | None = None
|
||||
|
||||
|
||||
# First successful ``auto`` resolution is reused for the process lifetime so a
|
||||
# second convert does not re-probe Word and fall through to LibreOffice.
|
||||
_cached_auto_resolve: tuple[str, OfficeInstall] | None = None
|
||||
|
||||
|
||||
def _program_dirs(kind: str) -> list[Path]:
|
||||
roots: list[Path] = []
|
||||
for env in ("ProgramFiles", "ProgramFiles(x86)"):
|
||||
@@ -133,41 +138,69 @@ def detect_office_install(engine: str) -> OfficeInstall | None:
|
||||
return None
|
||||
|
||||
|
||||
def _detect_word() -> OfficeInstall | None:
|
||||
def _word_com_available() -> bool:
|
||||
"""True when pywin32 is importable and Word.Application is registered."""
|
||||
if sys.platform != "win32":
|
||||
return None
|
||||
return False
|
||||
try:
|
||||
import win32com.client # type: ignore
|
||||
import win32com.client # type: ignore # noqa: F401
|
||||
except ImportError:
|
||||
return None
|
||||
word = None
|
||||
return False
|
||||
try:
|
||||
word = win32com.client.DispatchEx("Word.Application")
|
||||
return OfficeInstall(engine="word", label="Microsoft Word")
|
||||
except Exception:
|
||||
import winreg
|
||||
|
||||
with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"Word.Application"):
|
||||
pass
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def _detect_word() -> OfficeInstall | None:
|
||||
if not _word_com_available():
|
||||
return None
|
||||
finally:
|
||||
if word is not None:
|
||||
try:
|
||||
word.Quit()
|
||||
except Exception:
|
||||
pass
|
||||
return OfficeInstall(engine="word", label="Microsoft Word")
|
||||
|
||||
|
||||
def _install_still_available(install: OfficeInstall) -> bool:
|
||||
if install.engine == "word":
|
||||
return _word_com_available()
|
||||
if install.soffice_path and install.python_path:
|
||||
return Path(install.soffice_path).is_file() and Path(install.python_path).is_file()
|
||||
return False
|
||||
|
||||
|
||||
def clear_office_engine_cache() -> None:
|
||||
"""Drop cached ``auto`` resolution (tests / long-running hosts)."""
|
||||
global _cached_auto_resolve
|
||||
_cached_auto_resolve = None
|
||||
|
||||
|
||||
def resolve_office_engine(mode: str) -> tuple[str | None, OfficeInstall | None]:
|
||||
"""
|
||||
Resolve ``mode`` to a concrete engine id and optional install record.
|
||||
|
||||
``auto`` tries Word, then LibreOffice, then OpenOffice.
|
||||
``auto`` tries Word, then LibreOffice, then OpenOffice. The first successful
|
||||
``auto`` pick is cached for subsequent calls in the same process.
|
||||
"""
|
||||
global _cached_auto_resolve
|
||||
|
||||
if mode not in OFFICE_ENGINE_MODES:
|
||||
mode = DEFAULT_OFFICE_ENGINE
|
||||
|
||||
if mode == "auto":
|
||||
if _cached_auto_resolve is not None:
|
||||
cached_engine, cached_install = _cached_auto_resolve
|
||||
if _install_still_available(cached_install):
|
||||
return _cached_auto_resolve
|
||||
_cached_auto_resolve = None
|
||||
|
||||
for candidate in ("word", "libre", "openoffice"):
|
||||
install = detect_office_install(candidate)
|
||||
if install is not None:
|
||||
_cached_auto_resolve = (candidate, install)
|
||||
return candidate, install
|
||||
_cached_auto_resolve = None
|
||||
return None, None
|
||||
|
||||
install = detect_office_install(mode)
|
||||
|
||||
Reference in New Issue
Block a user