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
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies = [
"pydantic-settings>=2.4.0,<3",
"rdkit>=2024.9.1",
"scikit-learn>=1.9.0,<1.10",
"scipy>=1.11.1,<2",
"colorama>=0.4.6,<0.5",
"boruta>=0.4.3,<0.5",
"quantile-forest>=1.4.2,<2"
Expand Down Expand Up @@ -71,7 +72,7 @@ clustering = [

### TabPFN
tabpfn = [
"tabpfn==8.0.8",
"tabpfn==8.2.0",
"torch>=2.3.0,<3",
]

Expand Down
5 changes: 3 additions & 2 deletions src/mother/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ def __init__(self, extras_type: str, nested_error: Exception):
message: str = (
f"\n\n📦 {nested_error}\n\n"
+ f"{Style.DIM}# Have you tried running the following?{Style.RESET_ALL}\n"
+ f"$ {style}pip install 'mother[{extras_type}]'{Style.RESET_ALL} or\n"
+ f"$ {style}uv add 'mother[{extras_type}]'{Style.RESET_ALL}"
+ f"$ {style}pip install 'mother-ml[{extras_type}]'{Style.RESET_ALL} or\n"
+ f"$ {style}uv add mother-ml --extra {extras_type}{Style.RESET_ALL} or\n"
+ f"$ {style}uv sync --extra {extras_type}{Style.RESET_ALL}"
Comment on lines +12 to +14
)
super().__init__(message)

Expand Down
14 changes: 10 additions & 4 deletions src/mother/ml/models/m_tabpfn.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@

import numpy as np
import pandas as pd
import torch
from optuna.trial import Trial
from six import iteritems
from sklearn.base import BaseEstimator, TransformerMixin, clone
Expand All @@ -60,9 +59,16 @@
)
from sklearn.utils import check_array
from sklearn.utils.validation import check_is_fitted
from tabpfn import TabPFNClassifier, TabPFNRegressor
from tabpfn.constants import ModelVersion
from tabpfn.regressor import FullOutputDict

from mother.errors import ExtrasDependencyImportError

try:
import torch
from tabpfn import TabPFNClassifier, TabPFNRegressor
from tabpfn.constants import ModelVersion
Comment on lines +63 to +68
from tabpfn.regressor import FullOutputDict
except ImportError as import_error:
raise ExtrasDependencyImportError("tabpfn", import_error) from import_error

from mother.ml.core import AbstractMotherPipeline
from mother.ml.models import utils
Expand Down
39 changes: 37 additions & 2 deletions test/unit/test_errors.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import builtins
import importlib
import sys

import pytest

from mother.errors import ConfigurationError, ExtrasDependencyImportError


Expand All @@ -7,12 +13,41 @@ def test_extras_dependency_import_error():

assert isinstance(error, ExtrasDependencyImportError)
assert str(nested_error) in str(error)
assert "pip install 'mother[example]'" in str(error)
assert "uv add 'mother[example]'" in str(error)
assert "pip install 'mother-ml[example]'" in str(error)
assert "uv add mother-ml --extra example" in str(error)
assert "uv sync --extra example" in str(error)


def test_configuration_error():
error = ConfigurationError("Configuration is invalid")

assert isinstance(error, ConfigurationError)
assert str(error) == "Configuration is invalid"


@pytest.mark.parametrize(
("module_name", "import_error"),
[
("torch", ModuleNotFoundError("No module named 'torch'")),
("tabpfn", ImportError("tabpfn is incompatible with scikit-learn")),
],
ids=["missing-torch", "tabpfn-import-error"],
)
def test_tabpfn_optional_dependency_imports_raise_extras_error(monkeypatch, module_name, import_error):
target_module = "mother.ml.models.m_tabpfn"
sys.modules.pop(target_module, None)

original_import = builtins.__import__

def guarded_import(name, globals=None, locals=None, fromlist=(), level=0):
if name == module_name:
raise import_error
return original_import(name, globals, locals, fromlist, level)

monkeypatch.setattr(builtins, "__import__", guarded_import)

with pytest.raises(ExtrasDependencyImportError) as exc_info:
importlib.import_module(target_module)

assert str(import_error) in str(exc_info.value)
assert "mother-ml[tabpfn]" in str(exc_info.value)
76 changes: 8 additions & 68 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading