228 lines
5.5 KiB
Python
228 lines
5.5 KiB
Python
"""The knowledge base.
|
|
|
|
Knowledge
|
|
=========
|
|
|
|
It contains, for instance, known odd locations of version information for
|
|
particular modules (``VERSION_ATTRIBUTES``, ``VERSION_METHODS``)
|
|
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
import sysconfig
|
|
from typing import TYPE_CHECKING, Literal
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
|
|
PACKAGE_ALIASES = {
|
|
'vtkmodules': 'vtk',
|
|
'vtkmodules.all': 'vtk',
|
|
}
|
|
|
|
# Define unusual version locations
|
|
VERSION_ATTRIBUTES = {
|
|
'PyQt5': 'Qt.PYQT_VERSION_STR',
|
|
'sip': 'SIP_VERSION_STR',
|
|
}
|
|
|
|
|
|
def get_pyqt5_version() -> str:
|
|
"""Return the PyQt5 version."""
|
|
try:
|
|
from PyQt5.Qt import PYQT_VERSION_STR
|
|
except ImportError:
|
|
return 'Version unknown'
|
|
|
|
return PYQT_VERSION_STR
|
|
|
|
|
|
VERSION_METHODS: dict[str, Callable[[], str]] = {
|
|
'PyQt5': get_pyqt5_version,
|
|
}
|
|
|
|
|
|
# Check the environments
|
|
def in_ipython() -> bool:
|
|
"""Check if we are in a IPython environment.
|
|
|
|
Returns
|
|
-------
|
|
bool : True
|
|
``True`` when in an IPython environment.
|
|
|
|
"""
|
|
try:
|
|
__IPYTHON__ # noqa: B018
|
|
except NameError:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
def in_ipykernel() -> bool:
|
|
"""Check if in a ipykernel (most likely Jupyter) environment.
|
|
|
|
Warning:
|
|
-------
|
|
There is no way to tell if the code is being executed in a notebook
|
|
(Jupyter Notebook or Jupyter Lab) or a kernel is used but executed in a
|
|
QtConsole, or in an IPython console, or any other frontend GUI. However, if
|
|
`in_ipykernel` returns True, you are most likely in a Jupyter Notebook/Lab,
|
|
just keep it in mind that there are other possibilities.
|
|
|
|
Returns:
|
|
-------
|
|
bool : True if using an ipykernel
|
|
|
|
"""
|
|
ipykernel = False
|
|
if in_ipython():
|
|
try:
|
|
ipykernel: bool = type(get_ipython()).__module__.startswith('ipykernel.')
|
|
except NameError:
|
|
pass
|
|
return ipykernel
|
|
|
|
|
|
def get_standard_lib_modules() -> set[str]:
|
|
"""Return a set of the names of all modules in the standard library."""
|
|
site_path = Path(sysconfig.get_path('stdlib'))
|
|
if getattr(sys, 'frozen', False): # within pyinstaller
|
|
lib_path = site_path / '..'
|
|
if lib_path.is_dir():
|
|
names = lib_path.iterdir()
|
|
stdlib_pkgs = {p.stem for p in names if p.suffix == '.py'}
|
|
else:
|
|
stdlib_pkgs = {}
|
|
|
|
else:
|
|
names = site_path.iterdir()
|
|
stdlib_pkgs = {p.stem if p.suffix == '.py' else p.name for p in names}
|
|
|
|
return {
|
|
'python',
|
|
'sys',
|
|
'__builtin__',
|
|
'__builtins__',
|
|
'builtins',
|
|
'session',
|
|
'math',
|
|
'itertools',
|
|
'binascii',
|
|
'array',
|
|
'atexit',
|
|
'fcntl',
|
|
'errno',
|
|
'gc',
|
|
'time',
|
|
'unicodedata',
|
|
'mmap',
|
|
}.union(stdlib_pkgs)
|
|
|
|
|
|
def version_tuple(v: str) -> tuple[int, ...]:
|
|
"""Convert a version string to a tuple containing ints.
|
|
|
|
Non-numeric version strings will be converted to 0. For example:
|
|
``'0.28.0dev0'`` will be converted to ``'0.28.0'``
|
|
|
|
Returns
|
|
-------
|
|
ver_tuple : tuple
|
|
Length 3 tuple representing the major, minor, and patch
|
|
version.
|
|
|
|
"""
|
|
split_v = v.split('.')
|
|
while len(split_v) < 3:
|
|
split_v.append('0')
|
|
|
|
if len(split_v) > 3:
|
|
msg = 'Version strings containing more than three parts cannot be parsed'
|
|
raise ValueError(msg)
|
|
|
|
vals: list[int] = []
|
|
for item in split_v:
|
|
if item.isnumeric():
|
|
vals.append(int(item))
|
|
else:
|
|
vals.append(0)
|
|
|
|
return tuple(vals)
|
|
|
|
|
|
def meets_version(version: str, meets: str) -> bool:
|
|
"""Check if a version string meets a minimum version.
|
|
|
|
This is a simplified way to compare version strings. For a more robust
|
|
tool, please check out the ``packaging`` library:
|
|
|
|
https://github.com/pypa/packaging
|
|
|
|
Parameters
|
|
----------
|
|
version : str
|
|
Version string. For example ``'0.25.1'``.
|
|
|
|
meets : str
|
|
Version string. For example ``'0.25.2'``.
|
|
|
|
Returns
|
|
-------
|
|
newer : bool
|
|
True if version ``version`` is greater or equal to version ``meets``.
|
|
|
|
Examples
|
|
--------
|
|
>>> meets_version('0.25.1', '0.25.2')
|
|
False
|
|
|
|
>>> meets_version('0.26.0', '0.25.2')
|
|
True
|
|
|
|
"""
|
|
va = version_tuple(version)
|
|
vb = version_tuple(meets)
|
|
|
|
if len(va) != len(vb):
|
|
msg = 'Versions are not comparable.'
|
|
raise AssertionError(msg)
|
|
|
|
for i in range(len(va)):
|
|
if va[i] > vb[i]:
|
|
return True
|
|
if va[i] < vb[i]:
|
|
return False
|
|
|
|
# Arrived here if same version
|
|
return True
|
|
|
|
|
|
def get_filesystem_type() -> str | Literal[False]:
|
|
"""Get the type of the file system at the path of the scooby package."""
|
|
try:
|
|
import psutil # lazy-load see PR#85
|
|
except ImportError:
|
|
psutil = False
|
|
from pathlib import Path # lazy-load see PR#85
|
|
import platform # lazy-load see PR#85
|
|
|
|
# Skip Windows due to https://github.com/banesullivan/scooby/issues/75
|
|
fs_type: str | Literal[False]
|
|
if psutil and platform.system() != 'Windows':
|
|
# Code by https://stackoverflow.com/a/35291824/10504481
|
|
my_path = str(Path(__file__).resolve())
|
|
best_match = ''
|
|
fs_type = ''
|
|
for part in psutil.disk_partitions():
|
|
if my_path.startswith(part.mountpoint) and len(best_match) < len(part.mountpoint):
|
|
fs_type = part.fstype
|
|
best_match = part.mountpoint
|
|
else:
|
|
fs_type = False
|
|
return fs_type
|