Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions pycaret/containers/models/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.linear_model import LogisticRegression
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.linear_model import LogisticRegression
else:
from sklearn.linear_model import LogisticRegression
Expand Down Expand Up @@ -324,7 +326,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.neighbors import KNeighborsClassifier
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.neighbors import KNeighborsClassifier
else:
from sklearn.neighbors import KNeighborsClassifier
Expand Down Expand Up @@ -580,7 +584,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.svm import SVC
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.svm import SVC
else:
from sklearn.svm import SVC
Expand Down
8 changes: 6 additions & 2 deletions pycaret/containers/models/clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.cluster import KMeans
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.cluster import KMeans
else:
from sklearn.cluster import KMeans
Expand Down Expand Up @@ -340,7 +342,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.cluster import DBSCAN
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.cluster import DBSCAN
else:
from sklearn.cluster import DBSCAN
Expand Down
24 changes: 18 additions & 6 deletions pycaret/containers/models/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.linear_model import LinearRegression
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.linear_model import LinearRegression
else:
from sklearn.linear_model import LinearRegression
Expand Down Expand Up @@ -287,7 +289,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.linear_model import Lasso
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.linear_model import Lasso
else:
from sklearn.linear_model import Lasso
Expand Down Expand Up @@ -344,7 +348,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.linear_model import Ridge
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.linear_model import Ridge
else:
from sklearn.linear_model import Ridge
Expand Down Expand Up @@ -401,7 +407,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.linear_model import ElasticNet
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.linear_model import ElasticNet
else:
from sklearn.linear_model import ElasticNet
Expand Down Expand Up @@ -1004,7 +1012,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.svm import SVR
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.svm import SVR
else:
from sklearn.svm import SVR
Expand Down Expand Up @@ -1065,7 +1075,9 @@ def __init__(self, experiment):
if self.engine == "sklearn":
from sklearn.neighbors import KNeighborsRegressor
elif self.engine == "sklearnex":
if _check_soft_dependencies("sklearnex", extra=None, severity="warning"):
if _check_soft_dependencies(
"scikit-learn-intelex", extra=None, severity="warning"
):
from sklearnex.neighbors import KNeighborsRegressor
else:
from sklearn.neighbors import KNeighborsRegressor
Expand Down
10 changes: 5 additions & 5 deletions pycaret/containers/models/time_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,7 @@ def return_regressor_class(self):
if self.engine == "sklearn":
from sklearn.linear_model import LinearRegression
elif self.engine == "sklearnex":
_check_soft_dependencies("sklearnex", extra=None, severity="error")
_check_soft_dependencies("scikit-learn-intelex", extra=None, severity="error") # noqa: E501
from sklearnex.linear_model import LinearRegression

if self.gpu_param == "force":
Expand Down Expand Up @@ -1552,7 +1552,7 @@ def return_regressor_class(self):
if self.engine == "sklearn":
from sklearn.linear_model import ElasticNet
elif self.engine == "sklearnex":
_check_soft_dependencies("sklearnex", extra=None, severity="error")
_check_soft_dependencies("scikit-learn-intelex", extra=None, severity="error") # noqa: E501
from sklearnex.linear_model import ElasticNet

if self.gpu_param == "force":
Expand Down Expand Up @@ -1613,7 +1613,7 @@ def return_regressor_class(self):
if self.engine == "sklearn":
from sklearn.linear_model import Ridge
elif self.engine == "sklearnex":
_check_soft_dependencies("sklearnex", extra=None, severity="error")
_check_soft_dependencies("scikit-learn-intelex", extra=None, severity="error") # noqa: E501
from sklearnex.linear_model import Ridge

if self.gpu_param == "force":
Expand Down Expand Up @@ -1673,7 +1673,7 @@ def return_regressor_class(self):
if self.engine == "sklearn":
from sklearn.linear_model import Lasso
elif self.engine == "sklearnex":
_check_soft_dependencies("sklearnex", extra=None, severity="error")
_check_soft_dependencies("scikit-learn-intelex", extra=None, severity="error") # noqa: E501
from sklearnex.linear_model import Lasso

if self.gpu_param == "force":
Expand Down Expand Up @@ -2040,7 +2040,7 @@ def return_regressor_class(self):
if self.engine == "sklearn":
from sklearn.neighbors import KNeighborsRegressor
elif self.engine == "sklearnex":
_check_soft_dependencies("sklearnex", extra=None, severity="error")
_check_soft_dependencies("scikit-learn-intelex", extra=None, severity="error") # noqa: E501
from sklearnex.neighbors import KNeighborsRegressor

if self.gpu_param == "force":
Expand Down
150 changes: 37 additions & 113 deletions pycaret/utils/_dependencies.py
Original file line number Diff line number Diff line change
@@ -1,95 +1,20 @@
# Adapted from
# https://github.com/sktime/sktime/blob/v0.11.0/sktime/utils/validation/_dependencies.py

import sys
from distutils.version import LooseVersion
from importlib import import_module
from typing import Dict, Optional, Union
from typing import Optional

from importlib_metadata import distributions
from skbase.utils.dependencies import _check_soft_dependencies as _skbase_csd
from skbase.utils.dependencies._dependencies import _get_installed_packages

from pycaret.internal.logging import get_logger, redirect_output
from pycaret.internal.logging import get_logger

logger = get_logger()

INSTALLED_MODULES = None


def _try_import_and_get_module_version(
modname: str,
) -> Optional[Union[LooseVersion, bool]]:
"""Returns False if module is not installed, None if version is not available"""
try:
if modname in sys.modules:
mod = sys.modules[modname]
else:
if logger:
with redirect_output(logger):
mod = import_module(modname)
else:
mod = import_module(modname)
try:
ver = mod.__version__
except AttributeError:
# Version could not be obtained
ver = None
except ImportError:
ver = False
if ver:
ver = LooseVersion(ver)
return ver


# Based on packages_distributions() from importlib_metadata
def get_installed_modules() -> Dict[str, Optional[LooseVersion]]:
"""
Get installed modules and their versions from pip metadata.
"""
global INSTALLED_MODULES
if not INSTALLED_MODULES:
# Get all installed modules and their versions without
# needing to import them.
module_versions = {}
# top_level.txt contains information about modules
# in the package. It is not always present, in which case
# the assumption is that the package name is the module name.
# https://setuptools.pypa.io/en/latest/deprecated/python_eggs.html
for dist in distributions():
for pkg in (dist.read_text("top_level.txt") or "").split():
try:
ver = LooseVersion(dist.metadata["Version"])
except Exception:
ver = None
module_versions[pkg] = ver
INSTALLED_MODULES = module_versions
return INSTALLED_MODULES


def _get_module_version(modname: str) -> Optional[Union[LooseVersion, bool]]:
"""Will cache the version in INSTALLED_MODULES

Returns False if module is not installed."""
installed_modules = get_installed_modules()
if modname not in installed_modules:
# Fallback. This should never happen unless module is not present
installed_modules[modname] = _try_import_and_get_module_version(modname)
return installed_modules[modname]


def get_module_version(modname: str) -> Optional[LooseVersion]:
"""Raises a ValueError if module is not installed"""
version = _get_module_version(modname)
if version is False:
raise ValueError(f"Module '{modname}' is not installed.")
return version


def is_module_installed(modname: str) -> bool:
try:
get_module_version(modname)
return True
except ValueError:
return False
def get_module_version_str(modname: str) -> str:
"""Raises a ValueError if module is not installed"""
versions = _get_installed_packages()
return versions.get(modname, "Not installed")


def _check_soft_dependencies(
Expand All @@ -103,18 +28,28 @@ def _check_soft_dependencies(

Parameters
----------
package : str
Package to check
severity : str, optional
Whether to raise an error ("error") or just a warning message ("warning"),
by default "error"
packages : str
package name to check
str should be package name and/or package version specifications to check.
Must be a PEP 440 compatible specifier string, for a single package.
For instance, the PEP 440 compatible package name such as ``"pandas"``;
or a package requirement specifier string such as ``"pandas>1.2.3"``.

severity : str, "error" (default), "warning", "none"
whether the check should raise an error, a warning, or nothing

* "error" - raises a ``ModuleNotFoundError`` if one of packages is not installed
* "warning" - raises a warning if one of packages is not installed
function returns False if one of packages is not installed, otherwise True
* "none" - does not raise exception or warning
function returns False if one of packages is not installed, otherwise True

extra : Optional[str], optional
The 'extras' that will install this package, by default "all_extras".
If None, it means that the dependency is not available in optional
requirements file and must be installed by the user on their own.
install_name : Optional[str], optional
The package name to install, by default None
If none, the name in `package` argument is used

install_name : ignored, present only for backwards compatibility

Returns
-------
Expand All @@ -130,33 +65,22 @@ def _check_soft_dependencies(
RuntimeError
Is the severity argument is not one of the allowed values
"""
install_name = install_name or package
msg = (
f"\n'{package}' is a soft dependency and not included in the "
f"pycaret installation. Please run: `pip install {package}` to install. "
)
if extra is not None:
msg += (
f"\nAlternately, you can install {package} by running "
f"`pip install pycaret[{extra}]`"
)

package_available = is_module_installed(package)
package_available = _skbase_csd(package, severity=severity, msg=msg)

if package_available:
ver = get_module_version(package)
ver = get_module_version_str(package)
logger.info(
"Soft dependency imported: {k}: {stat}".format(k=package, stat=str(ver))
)
else:
msg = (
f"\n'{package}' is a soft dependency and not included in the "
f"pycaret installation. Please run: `pip install {install_name}` to install."
)
if extra is not None:
msg += f"\nAlternately, you can install this by running `pip install pycaret[{extra}]`"

if severity == "error":
logger.exception(f"{msg}")
raise ModuleNotFoundError(msg)
elif severity == "warning":
logger.warning(f"{msg}")
package_available = False
else:
raise RuntimeError(
"Error in calling _check_soft_dependencies, severity "
f'argument must be "error" or "warning", found "{severity}".'
)

return package_available
4 changes: 2 additions & 2 deletions pycaret/utils/_show_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import sys
from typing import Optional

from pycaret.utils._dependencies import get_module_version
from pycaret.utils._dependencies import get_module_version_str

required_deps = [
"pip",
Expand Down Expand Up @@ -127,7 +127,7 @@ def _get_deps_info(optional: bool = False, logger: Optional[logging.Logger] = No

for modname in deps:
try:
ver = get_module_version(modname)
ver = get_module_version_str(modname)
if not ver:
ver = "Installed but version unavailable"
except ValueError:
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ classifiers = [
# this set should be kept minimal!
dependencies = [
# Base
"packaging",
"scikit-base>=0.6.1",
"ipython>=5.5.0",
"ipywidgets>=7.6.5",
"tqdm>=4.62.0",
Expand Down
Loading