Skip to content

Drop python<3.9, support modern libraries #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Mar 23, 2025
Merged
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7b259fd
require at least py39, fix nodeps tests collection
lopuhin Mar 20, 2025
220a256
fix typos in github workflows
lopuhin Mar 20, 2025
1a38341
fix tests for indices_to_bool_mask
lopuhin Mar 20, 2025
fed9fed
fix has_intercept for OneVsRestClassifier
lopuhin Mar 20, 2025
c694898
fix get_feature_names
lopuhin Mar 20, 2025
f8990b6
rename get_feature_names methods to get_feature_names_out
lopuhin Mar 20, 2025
75da85b
pass test_explain_linear
lopuhin Mar 20, 2025
0c492af
fix lime, fix is_multiclass_classifier from the previous commit
lopuhin Mar 20, 2025
6573f65
fix target formatting
lopuhin Mar 20, 2025
20475de
fix warnings: remove multi_class='multinomial'
lopuhin Mar 22, 2025
c9fe612
fix remaining tests for sklearn weight explanation
lopuhin Mar 22, 2025
f0d0f2e
fix explain prediction for gradient boosting due to loss refactoring
lopuhin Mar 22, 2025
ac59cc7
fix permutation importance tests, raise min sklearn version to 1.6
lopuhin Mar 22, 2025
a92dab1
stop using bash in tox
lopuhin Mar 22, 2025
d19d648
fix lightning tests, remove add_bias
lopuhin Mar 22, 2025
b9f1be8
use a no-binary install of lightning to make sure it always builds
lopuhin Mar 22, 2025
6b7f8f7
move lightning to extras, disable keras tests
lopuhin Mar 22, 2025
49effea
try to fix lightning build on CI
lopuhin Mar 22, 2025
7f915b7
fix lightgbm tests
lopuhin Mar 22, 2025
e36149f
update type annotations for xgboost and lightgbm
lopuhin Mar 22, 2025
ec87bf0
fix xgboost deprecation errors
lopuhin Mar 22, 2025
482c7ce
update to last mypy version
lopuhin Mar 22, 2025
cbfa62c
remove six, more typing modernization
lopuhin Mar 22, 2025
e9cf301
mypy fixes
lopuhin Mar 22, 2025
87d5fea
fix and modernize types in base.py
lopuhin Mar 22, 2025
fe07ae2
fix and modernize types in eli5/formatters/image.py
lopuhin Mar 22, 2025
0105bfc
fix types in lime/samplers.py and sklearn_crfsuite/explain_weights.py
lopuhin Mar 22, 2025
e3399ad
ignore type errors in formatters/utils.py
lopuhin Mar 22, 2025
408f6f3
fix types in lightgbm, xgboost and sklean/explain_prediction
lopuhin Mar 22, 2025
f086924
fix and modernize types in formatters/as_dataframe.py
lopuhin Mar 22, 2025
91f13da
some doc build fixes
lopuhin Mar 22, 2025
ffc20a2
ignore warnings for now
lopuhin Mar 22, 2025
2badc3d
a more deterministic xor test
lopuhin Mar 23, 2025
ab85a17
use xgboost < 2.0.0 in tests, as newer xgboost does not work correctly
lopuhin Mar 23, 2025
cd3f5b6
fix is_classifier for older xgboost
lopuhin Mar 23, 2025
11f5367
add a warning about xgboost version support
lopuhin Mar 23, 2025
0756b9f
add a warning about keras requirements to the docs
lopuhin Mar 23, 2025
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
30 changes: 14 additions & 16 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -17,26 +17,24 @@ jobs:
fail-fast: false
matrix:
include:
- python-version: '3.6'
- python-version: '3.10'
tox-env: 'mypy'
- python-version: '3.9'
- python-version: '3.10'
tox-env: 'docs'
- python-version: '3.6'
tox-env: 'py36'
- python-version: '3.6'
tox-env: 'py36-nodeps'
- python-version: '3.6'
tox-env: 'py36-extra'
- python-version: '3.7'
tox-env: 'py37'
- python-version: '3.8'
tox-env: 'py38'
- python-version: '3.8'
tox-env: 'py38-nodeps'
- python-version: '3.9'
tox-env: 'py39'
- python-version: '3.9'
tox-env: 'py39-nodeps'
- python-version: '3.10'
tox-env: 'py310'
- python-version: '3.10'
tox-env: 'py310-nodeps'
- python-version: '3.10'
tox-env: 'py310-extra'
- python-version: '3.11'
tox-env: 'py311'
- python-version: '3.12'
tox-env: 'py312'
- python-version: '3.13'
tox-env: 'py313'

steps:
- uses: actions/checkout@v2
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Changelog
=========

0.14.0 (?)
-------------------

* drop support for python 3.6, 3.7, 3.8
* add support for python 3.11, 3.12, 3.13

0.13.0 (2022-05-11)
-------------------

11 changes: 0 additions & 11 deletions _ci/runtests_default.sh

This file was deleted.

10 changes: 0 additions & 10 deletions _ci/runtests_default_with_crfsuite.sh

This file was deleted.

12 changes: 0 additions & 12 deletions _ci/runtests_extra.sh

This file was deleted.

13 changes: 0 additions & 13 deletions _ci/runtests_nodeps.sh

This file was deleted.

4 changes: 2 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -4,5 +4,5 @@ sphinx_rtd_theme
ipython
scipy
numpy > 1.9.0
scikit-learn >= 0.20
typing
pandas
scikit-learn >= 1.6.0
6 changes: 3 additions & 3 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ def __getattr__(cls, name):
'keras.models',
'keras.layers',
'keras.preprocessing.image',
'pandas',
# 'pandas',
'PIL',
'matplotlib',
'matplotlib.pyplot',
@@ -69,7 +69,7 @@ def __getattr__(cls, name):

def setup(app):
# see https://github.com/snide/sphinx_rtd_theme/issues/117
app.add_stylesheet("rtfd_overrides.css")
app.add_css_file("rtfd_overrides.css")

suppress_warnings = ['image.nonlocal_uri']

@@ -123,7 +123,7 @@ def setup(app):
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = 'en'

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
2 changes: 1 addition & 1 deletion docs/source/libraries/keras.rst
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ Keras_ is "a high-level neural networks API, written in Python and capable of ru
Keras can be used for many Machine Learning tasks, and it has support for both popular
and experimental neural network architectures.

Note: only TensorFlow 1.x is supported, recommended Keras version is 2.3.1 or earlier.
Note: only TensorFlow 1.x is supported, recommended Keras version is 2.3.1 or earlier, and eli5 version 0.13 or earlier, as you can't install TensorFlow 1.x on Python 3.9+ which is required for eli5 0.14+

.. _Keras: https://keras.io/

4 changes: 3 additions & 1 deletion docs/source/libraries/xgboost.rst
Original file line number Diff line number Diff line change
@@ -6,7 +6,9 @@ XGBoost
XGBoost_ is a popular Gradient Boosting library with Python interface.
eli5 supports :func:`eli5.explain_weights` and :func:`eli5.explain_prediction`
for XGBClassifer_, XGBRegressor_ and Booster_ estimators. It is tested for
xgboost >= 0.6a2.
xgboost >= 0.6a2 and < 2.0.0.
Versions starting from 2.0.0 likely produce incorrect results in
:func:`eli5.explain_prediction`, and will issue a warning.

.. _XGBoost: https://github.com/dmlc/xgboost
.. _XGBClassifer: https://xgboost.readthedocs.io/en/latest/python/python_api.html#xgboost.XGBClassifier
58 changes: 22 additions & 36 deletions eli5/_feature_names.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import re
import six
from typing import (
Any, Iterable, Iterator, Tuple, Sized, List, Optional, Dict,
Union, Callable, Pattern
)
Any, Iterable, Iterator, Sized, Optional, Union, Callable, Pattern)

import numpy as np
import scipy.sparse as sp
@@ -14,15 +11,14 @@ class FeatureNames(Sized, Iterable):
A list-like object with feature names. It allows
feature names for unknown features to be generated using
a provided template, and to avoid making copies of large objects
in get_feature_names.
in get_feature_names_out.
"""
def __init__(self,
feature_names=None,
bias_name=None, # type: str
unkn_template=None, # type: str
n_features=None, # type: int
bias_name: Optional[str] = None,
unkn_template: Optional[str] = None,
n_features: Optional[int] = None,
):
# type: (...) -> None
if not (feature_names is not None or
(unkn_template is not None and n_features)):
raise ValueError(
@@ -39,20 +35,17 @@ def __init__(self,
'unkn_template should be set for sparse features')
self.feature_names = feature_names
self.unkn_template = unkn_template
self.n_features = n_features or len(feature_names) # type: int
self.n_features: int = n_features or len(feature_names)
self.bias_name = bias_name

def __repr__(self):
# type: () -> str
def __repr__(self) -> str:
return '<FeatureNames: {} features {} bias>'.format(
self.n_features, 'with' if self.has_bias else 'without')

def __len__(self):
# type: () -> int
def __len__(self) -> int:
return self.n_features + int(self.has_bias)

def __iter__(self):
# type: () -> Iterator[str]
def __iter__(self) -> Iterator[str]:
return (self[i] for i in range(len(self)))

def __getitem__(self, idx):
@@ -69,10 +62,10 @@ def __getitem__(self, idx):
return self.unkn_template % idx
raise IndexError('Feature index out of range')

def _slice(self, aslice):
# type: (slice) -> Any
def _slice(self, aslice: slice):
if isinstance(self.feature_names, (list, np.ndarray)):
# Fast path without going through __getitem__
lst: Union[list, np.ndarray]
if self.has_bias:
lst = list(self.feature_names)
lst.append(self.bias_name)
@@ -84,29 +77,26 @@ def _slice(self, aslice):
return [self[idx] for idx in indices]

@property
def has_bias(self):
# type: () -> bool
def has_bias(self) -> bool:
return self.bias_name is not None

@property
def bias_idx(self):
# type: () -> Optional[int]
def bias_idx(self) -> Optional[int]:
if self.has_bias:
return self.n_features
return None

def filtered(self, feature_filter, x=None):
# type: (Callable, Any) -> Tuple[FeatureNames, List[int]]
def filtered(self, feature_filter: Callable, x=None) -> tuple['FeatureNames', list[int]]:
""" Return feature names filtered by a regular expression
``feature_re``, and indices of filtered elements.
"""
indices = []
filtered_feature_names = []
indexed_names = None # type: Optional[Iterable[Tuple[int, Any]]]
indexed_names: Optional[Iterable[tuple[int, Any]]] = None
if isinstance(self.feature_names, (np.ndarray, list)):
indexed_names = enumerate(self.feature_names)
elif isinstance(self.feature_names, dict):
indexed_names = six.iteritems(self.feature_names)
indexed_names = self.feature_names.items()
elif self.feature_names is None:
indexed_names = []
assert indexed_names is not None
@@ -116,8 +106,7 @@ def filtered(self, feature_filter, x=None):
assert x.shape[0] == 1
flt = lambda nm, i: feature_filter(nm, x[0, i])
else:
# FIXME: mypy warns about x[i] because it thinks x can be None
flt = lambda nm, i: feature_filter(nm, x[i]) # type: ignore
flt = lambda nm, i: feature_filter(nm, x[i])
else:
flt = lambda nm, i: feature_filter(nm)

@@ -141,10 +130,9 @@ def filtered(self, feature_filter, x=None):

def handle_filter(self,
feature_filter,
feature_re, # type: Pattern[str]
x=None, # type: Any
):
# type: (...) -> Tuple[FeatureNames, Union[List[int], None]]
feature_re: Pattern[str],
x=None,
) -> tuple['FeatureNames', Union[list[int], None]]:
if feature_re is not None and feature_filter:
raise ValueError('pass either feature_filter or feature_re')
if feature_re is not None:
@@ -158,8 +146,7 @@ def handle_filter(self,
else:
return self, None

def add_feature(self, feature):
# type: (Any) -> int
def add_feature(self, feature) -> int:
""" Add a new feature name, return it's index.
"""
# A copy of self.feature_names is always made, because it might be
@@ -179,8 +166,7 @@ def add_feature(self, feature):
return idx


def _all_feature_names(name):
# type: (Union[str, bytes, List[Dict]]) -> List[str]
def _all_feature_names(name: Union[str, bytes, list[dict]]) -> list[str]:
""" All feature names for a feature: usually just the feature itself,
but can be several features for unhashed features with collisions.
"""
Loading