Source code for tidy3d.plugins.klayout.util
from __future__ import annotations
import os
import platform
from pathlib import Path
from shutil import which
from typing import Union
import tidy3d as td
[docs]
def check_installation(raise_error: bool = False) -> Union[str, None]:
"""Return the path to the KLayout executable if it is installed.
The executable is located by checking the system PATH and common platform-specific installation locations.
Parameters
----------
raise_error : bool
Whether to raise an error if KLayout is not found. If ``False``, a warning is shown.
Returns
-------
Union[str, None]
The path to the KLayout executable. If KLayout is not found, returns ``None``.
"""
path = _resolve_klayout_executable()
msg = "KLayout was not found. Please ensure KLayout is installed and added to your system PATH before running KLayout."
if path is None:
if raise_error:
raise RuntimeError(msg)
td.log.warning(msg)
return path
def _resolve_klayout_executable() -> Union[str, None]:
"""Return the path to the first platform-relevant KLayout executable we can find."""
system = platform.system().lower()
if system == "windows":
names = ("klayout_app.exe", "klayout.exe")
else: # macOS ("darwin") and Linux
names = ("klayout",)
for name in names:
resolved = which(name)
if resolved:
return resolved
for binary in _common_install_locations():
if binary.exists():
return str(binary)
return None
def _common_install_locations() -> tuple[Path, ...]:
"""Return possible platform-dependent installation paths for KLayout."""
home = Path.home()
system = platform.system().lower()
paths: list[Path] = []
if system == "darwin":
apps = [
Path("/Applications") / "KLayout.app" / "Contents" / "MacOS" / "klayout",
Path("/Applications") / "klayout.app" / "Contents" / "MacOS" / "klayout",
home / "Applications" / "KLayout.app" / "Contents" / "MacOS" / "klayout",
]
brew_bins = [
Path("/opt/homebrew/bin/klayout"),
Path("/usr/local/bin/klayout"),
]
paths.extend(apps + brew_bins)
elif system == "windows":
program_files = [
Path(os.environ.get("ProgramFiles", r"C:\\Program Files")),
Path(os.environ.get("ProgramFiles(x86)", r"C:\\Program Files (x86)")),
]
for root in program_files:
paths.extend(
[
root / "KLayout" / "klayout_app.exe",
root / "KLayout" / "klayout.exe",
]
)
local_programs = home / "AppData" / "Local" / "Programs" / "KLayout"
paths.extend(
[
local_programs / "klayout_app.exe",
local_programs / "klayout.exe",
]
)
else: # Linux and other Unix variants
paths.extend(
[
Path("/usr/bin/klayout"),
Path("/usr/local/bin/klayout"),
Path("/snap/bin/klayout"),
Path("/opt/klayout/klayout"),
home / ".local" / "bin" / "klayout",
]
)
seen = set()
unique_paths = []
for path in paths:
if path not in seen:
unique_paths.append(path)
seen.add(path)
return tuple(unique_paths)