147 lines
5.2 KiB
Python
147 lines
5.2 KiB
Python
"""
|
|
On some systems such as Mac and AppImage (Linux) the python extension suffix does not match the
|
|
cpython suffix used by the embedded python interpreter.
|
|
|
|
This class creates symlinks for all .so files in dest folder that match the current python embedded suffix.
|
|
|
|
For example a file named ``indexers.cpython-38-x86_64-linux-gnu.so`` would be symlinked to ``indexers.cpython-3.8.so``.
|
|
This renaming allows the python interpreter to find the import.
|
|
"""
|
|
from __future__ import annotations
|
|
from typing import List
|
|
from pathlib import Path
|
|
from importlib import machinery
|
|
import easymacro as app
|
|
|
|
|
|
class LinkCPython:
|
|
def __init__(self, pth: str) -> None:
|
|
"""
|
|
Constructor
|
|
|
|
Args:
|
|
pth (str): Path to site-packages folder.
|
|
"""
|
|
self._current_suffix = self._get_current_suffix()
|
|
app.debug("CPythonLink.__init__")
|
|
self._link_root = Path(pth)
|
|
if not self._link_root.exists():
|
|
raise FileNotFoundError(f"Path does not exist {self._link_root}")
|
|
app.debug("CPythonLink.__init__ done")
|
|
|
|
def _get_current_suffix(self) -> str:
|
|
"""Gets suffix currently used by the embedded python interpreter such as ``cpython-3.8``"""
|
|
for suffix in machinery.EXTENSION_SUFFIXES:
|
|
if suffix.startswith(".cpython-") and suffix.endswith(".so"):
|
|
# remove leading . and trailing .so
|
|
return suffix[1:][:-3]
|
|
return ""
|
|
|
|
def _get_all_files(self, path: Path) -> List[Path]:
|
|
return [p for p in path.glob(f"**/*{self.file_suffix}.so") if p.is_file()]
|
|
|
|
def _get_all_links(self, path: Path) -> List[Path]:
|
|
return [p for p in path.glob(f"**/*{self.current_suffix}.so") if p.is_symlink()]
|
|
|
|
def _create_symlink(self, src: Path, dst: Path, overwrite: bool) -> None:
|
|
if dst.is_symlink():
|
|
if overwrite:
|
|
app.debug(f"Removing existing symlink {dst}")
|
|
dst.unlink()
|
|
else:
|
|
app.debug(f"Symlink already exists {dst}")
|
|
return
|
|
dst.symlink_to(src)
|
|
app.debug(f"Created symlink {dst} -> {src}")
|
|
|
|
def _find_current_installed_suffix(self, path: Path) -> str:
|
|
"""
|
|
Finds the current suffix from the current installed python so files such as ``cpython-38-x86_64-linux-gnu``.
|
|
|
|
Args:
|
|
path (Path): Path to search in. Usually site-packages.
|
|
|
|
Returns:
|
|
str: suffix if found, otherwise empty string.
|
|
"""
|
|
return next(
|
|
(str(p).rsplit(".", 2)[1] for p in path.glob("**/*.cpython-*.so") if not p.is_symlink()),
|
|
"",
|
|
)
|
|
|
|
def link(self, overwrite:bool = False) -> None:
|
|
"""
|
|
Creates symlinks for all .so files in site-packages that match the current suffix.
|
|
|
|
Args:
|
|
overwrite (bool, optional): Override any existing sys links. Defaults to False.
|
|
"""
|
|
app.debug("CPythonLink.link starting")
|
|
if not self._link_root:
|
|
app.debug("No site-packages found")
|
|
return
|
|
if not self.file_suffix:
|
|
app.debug("No current file suffix found")
|
|
return
|
|
if not self._link_root.exists():
|
|
app.debug(f"Site-packages does not exist {self._link_root}")
|
|
return
|
|
app.debug(f"Python current suffix: {self._current_suffix}")
|
|
app.debug(f"Found file suffix: {self.file_suffix}")
|
|
files = self._get_all_files(self._link_root)
|
|
if not files:
|
|
app.debug(f"No files found in {self._link_root}")
|
|
return
|
|
cp_old = self.file_suffix
|
|
cp_new = self._current_suffix
|
|
if cp_old == cp_new:
|
|
app.debug(f"Suffixes match, no need to link: {cp_old} == {cp_new}")
|
|
return
|
|
|
|
for file in files:
|
|
ln_name = file.name.replace(cp_old, cp_new)
|
|
src = file
|
|
if not src.is_absolute():
|
|
src = file.resolve()
|
|
dst = src.parent / ln_name
|
|
self._create_symlink(src, dst, overwrite)
|
|
app.debug("CPythonLink.link done")
|
|
|
|
def unlink(self) -> None:
|
|
"""Unlinks all broken sys links"""
|
|
links = self._get_all_links(self._link_root)
|
|
if not links:
|
|
app.debug(f"No links found in {self._link_root}")
|
|
return
|
|
for link in links:
|
|
if not link.exists():
|
|
app.debug(f"Removing broken symlink {link}")
|
|
link.unlink()
|
|
|
|
|
|
# region Properties
|
|
@property
|
|
def cpy_name(self) -> str:
|
|
"""Gets/Sets CPython name, e.g. cpython-3.8"""
|
|
return self._current_suffix
|
|
|
|
@cpy_name.setter
|
|
def cpy_name(self, value: str) -> None:
|
|
self._current_suffix = value
|
|
|
|
@property
|
|
def current_suffix(self) -> str:
|
|
"""Current Suffix such as ``cpython-3.8``"""
|
|
return self._current_suffix
|
|
|
|
@property
|
|
def file_suffix(self) -> str:
|
|
"""Current Suffix such as ``cpython-38-x86_64-linux-gnu``"""
|
|
try:
|
|
return self._file_suffix
|
|
except AttributeError:
|
|
self._file_suffix = self._find_current_installed_suffix(self._link_root)
|
|
return self._file_suffix
|
|
|
|
# endregion Properties
|