[build-system] # Note for maintainers: this numpy constraint is specific to wheels for PyPI. See: # https://numpy.org/doc/stable/dev/depending_on_numpy.html#numpy-2-abi-handling requires = [ "scikit-build-core>=0.10.0", "setuptools-scm>=8.0", "numpy>=2.0", "packaging>20.9", "nanobind>=2.0.0", ] build-backend = "scikit_build_core.build" [project] name = "shap" description = "A unified approach to explain the output of any machine learning model." readme = "README.md" license = {text = "MIT License"} authors = [ {name = "Scott Lundberg", email = "slund1@cs.washington.edu"}, ] requires-python = ">=3.12" dependencies = [ 'numpy>=2', 'scipy', 'scikit-learn', 'pandas', 'tqdm>=4.27.0', 'packaging>20.9', 'slicer==0.0.8', 'numba<0.63; sys_platform == "darwin" and platform_machine == "x86_64"', # numba 0.63+ dropped macOS x86_64 wheels, see numba/numba#10187 'numba; sys_platform != "darwin" or platform_machine != "x86_64"', 'llvmlite<0.46; sys_platform == "darwin" and platform_machine == "x86_64"', # llvmlite 0.46+ dropped macOS x86_64 wheels, see numba/numba#10187 'llvmlite; sys_platform != "darwin" or platform_machine != "x86_64"', 'cloudpickle', ] classifiers = [ "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Operating System :: Unix", "Operating System :: MacOS", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: MIT License", ] dynamic = ["version"] [dependency-groups] plots = ["matplotlib", "ipython"] download-datasets = [ # Dependencies needed to download datasets for testing # scikit-learn is already in core dependencies, but listed here for clarity "scikit-learn", ] docs = [ {include-group = "plots"}, "numpydoc", "sphinx_rtd_theme", "sphinx", "nbsphinx", "sphinx_github_changelog", "myst-parser", "requests", "ipywidgets", # For tqdm in notebooks ] test-core = [ "pytest", "pytest-mpl", "pytest-cov", "mypy", "pre-commit", "ruff", ] test = [ {include-group = "test-core"}, "xgboost", "lightgbm", 'catboost; python_version < "3.14"', # TODO: pending 3.14 support 'gpboost==1.6.3.1; python_version < "3.14"', # TODO: pending 3.14 support, see GH #4210 "ngboost", "pyspark", "pyod", "transformers < 4.54.0", # TODO: fix once tests pass for 4.54.0 "tf-keras", "protobuf", # See GH #3046 'torch<=2.11.0; python_version < "3.14"', # TODO: pending 3.14 support, see GH #5016 'torchvision; python_version < "3.14"', # TODO: pending 3.14 support 'tensorflow; python_version < "3.14"', # TODO: pending 3.14 support "sentencepiece", "opencv-python", # Constraint to prevent the combination of tf<2.15 and numpy>=2.0. # See GH #3707, #3768, 3922 "numpy>=2.0", "causalml>=0.15.5", # causalml imports private sklearn.ensemble._forest internals (DOUBLE, DTYPE, MAX_INT) # that were removed in scikit-learn 1.9. See https://github.com/uber/causalml/issues/926 "scikit-learn<1.9", "selenium", # needed to test the javascript based plots ] nbtest = [ "jupyter", "nbconvert", "nbformat", "nlp", "transformers", "datasets", "keras", "nbtest-plugin", "nbtest-gen", "nbtest-lab-extension" ] [project.urls] Repository = 'http://github.com/shap/shap' Documentation = 'https://shap.readthedocs.io/en/latest/index.html' "Release Notes" = 'https://shap.readthedocs.io/en/latest/release_notes.html' [tool.uv] cache-keys = [ { file = "shap/cext/*.cc" }, { file = "shap/cext/*.cu" }, { file = "shap/cext/*.h" }, { file = "shap/cutils/*.cpp" }, { file = "shap/cutils/*.h" }, { file = "CMakeLists.txt" }, ] [tool.mypy] check_untyped_defs = true disallow_untyped_calls = false disallow_untyped_defs = false disallow_incomplete_defs = false exclude = ["shap/benchmark/*", "tests/benchmark/*", "shap/_cutils.pyi"] # NOTE: numpy.typing.mypy_plugin is deprecated in NumPy 2.3+ and will be removed in a future release # plugins = ["numpy.typing.mypy_plugin"] [[tool.mypy.overrides]] # Disable some checks from certain shap modules # TODO: get these passing! # NOTE: Modules with added type hints have been removed from this list module = [ # "shap.explainers._additive", # NOW TYPE CHECKED - type hints added "shap.explainers._deep.deep_pytorch", "shap.explainers._deep.deep_tf", # "shap.explainers._exact", # NOW TYPE CHECKED - type hints added # "shap.explainers._explainer", # NOW TYPE CHECKED - type hints added # "shap.explainers._gradient", # NOW TYPE CHECKED - type hints added # "shap.explainers._kernel", # NOW TYPE CHECKED - type hints added # "shap.explainers._linear", # NOW TYPE CHECKED - type hints added # "shap.explainers._partition", # NOW TYPE CHECKED - type hints added # "shap.explainers._permutation", # NOW TYPE CHECKED - type hints added # "shap.explainers._sampling", # NOW TYPE CHECKED - type hints added # "shap.explainers._tree", # NOW TYPE CHECKED - type hints added # "shap.explainers._coalition", # NOW TYPE CHECKED - type hints added # "shap.explainers.other._random", # NOW TYPE CHECKED - type hints added "shap.explainers.pytree", "shap.explainers.tf_utils", # "shap.maskers._composite", # NOW TYPE CHECKED - type hints added # "shap.maskers._fixed", # NOW TYPE CHECKED - type hints added "shap.maskers._image", # "shap.maskers._masker", # NOW TYPE CHECKED - type hints added "shap.maskers._tabular", "shap.maskers._text", "shap.plots._benchmark", "shap.plots._force_matplotlib", "shap.plots._force", "shap.plots._text", "shap.plots._waterfall", ] check_untyped_defs = false [[tool.mypy.overrides]] # Ignore missing types for 3rd party libraries module = [ "catboost.*", "cloudpickle", "cv2", "IPython.*", "lightgbm.*", "lime.*", "numba", "pandas", "pyod.*", "pyspark.*", "scipy.*", "sklearn.*", "slicer", "tensorflow.*", "transformers.*", "torch.*", "tqdm.*", "xgboost.*", "causalml.*", "selenium.*", ] ignore_missing_imports = true [tool.setuptools_scm] version_file = "shap/_version.py" # Use "no-local-version" so dev releases are compatibile with PyPI local_scheme = "no-local-version" [tool.scikit-build] # List of packages to include in the wheel wheel.packages = [ 'shap', 'shap.cext', 'shap.explainers', 'shap.explainers.other', 'shap.explainers._deep', 'shap.plots', 'shap.plots.colors', 'shap.plots.resources', 'shap.benchmark', 'shap.maskers', 'shap.utils', 'shap.actions', 'shap.models', ] metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" sdist.include = ["shap/_version.py"] sdist.exclude = ["docs/", "notebooks/", ".claude/", "appveyor/"] # Protect the configuration against future changes in scikit-build-core minimum-version = "build-system.requires" # Setuptools-style build caching in a local directory build-dir = "build/{wheel_tag}" # Exclude C/C++/CUDA source files from the wheel (compiled .so is sufficient) wheel.exclude = ["**/*.cc", "**/*.cpp", "**/*.h", "**/*.cu"] # Build stable ABI wheels for CPython 3.12+ wheel.py-api = "cp312" [tool.pytest.ini_options] addopts = "--mpl -m 'not xslow'" mpl-default-style = "default" testpaths = ["tests"] filterwarnings = [ # Ignore warnings that are entirely from 3rd party libs outside our control "ignore:.*distutils Version classes are deprecated.*:DeprecationWarning:.*pandas.*", "ignore:.*typing.io is deprecated.*:DeprecationWarning:.*pyspark.*", "ignore:.*is_datetime64tz_dtype is deprecated.*:DeprecationWarning:.*pyspark.*", "ignore:.*'force_all_finite' was renamed to 'ensure_all_finite' in 1.6.*:FutureWarning:.*sklearn.*", ] markers = ["xslow: mark test as extremely slow (not run unless explicitly requested)"] [tool.ruff] # Careful: when running on pre-commit, ruff's "include" and "exclude" config # options are ignored! So, instead of "exclude", use the "per-file-ignores" # config to always disable linting for specific files. include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"] extend-exclude = ["**/tree_shap_paper/**", "docs/user_studies/*"] line-length = 120 [tool.ruff.lint] select = [ "F", # pyflakes "I", # isort "ISC", # string literal concatenation. "UP", # pyupgrade "E", # pycodestyle "W", # warning "D", # pydocstyle "NPY", # Numpy "SIM101", # flake8-simplify "FA", # future annotations "TCH", # Move type only imports to type-checking condition. # D417 # undocumented parameter. FIXME: get this passing ] ignore = [ # Recommended rules to disable when using ruff formatter: # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules "D206", "D300", "E111", "E114", "E117", "E501", "W191", # pydocstyle issues not yet fixed "D100", # Missing docstring in public module "D101", # Missing docstring in public class "D102", # Missing docstring in public method "D103", # Missing docstring in public function "D104", # Missing docstring in public package "D105", # Missing docstring in magic method "D205", # 1 blank line required between summary line and description "D400", # First line should end with a period "D401", # First line of docstring should be in imperative mood: "A basic partial dependence plot function." "D404", # First word of the docstring should not be "This" "NPY002", # Allow numpy RandomState objects in tests ] [tool.ruff.lint.pydocstyle] convention = "numpy" [tool.ruff.lint.per-file-ignores] # Don't apply linting/formatting to vendored code "shap/explainers/other/_maple.py" = ["ALL"] # Ignore notebooks in user_studies, which are not maintained "docs/user_studies/*.ipynb" = ["ALL"] # Ignore SHAP Paper, as it is an unmaintained record of a published paper "notebooks/tabular_examples/tree_based_models/tree_shap_paper/*" = ["ALL"] # Disable some unwanted rules on Jupyter notebooks "*.ipynb" = ["D", "E703", "E402"] # Allow trailing semicolons, allow imports not at top # Ignore pycodestyle in tests "tests/*py" = ["D"] [tool.coverage.run] source_pkgs = ["shap"] omit = ["shap/benchmark/*"] [tool.coverage.paths] combine = ["shap", "*/site-packages/shap"] [tool.cibuildwheel] # TODO: Should we use uv as build frontend for faster builds? # build-frontend = "uv" # Restrict the set of builds to mirror the wheels available in scipy. See #3028 # skip cp314-macosx_x86_64 due to lack of numba and llvmlite support # skip *t (free-threaded builds) since dependencies like llvmlite don't support it yet skip = [ "cp314-macosx_x86_64", "cp314t-manylinux_x86_64", "cp314t-macosx_x86_64", "cp314t-win_amd64", ] build-verbosity = 2 # Change import-mode to ensure we test against installed package, not local project test-command = "pytest -v {project}/tests --import-mode=append" test-groups = ["test-core", "plots"] # skip tests on *-musllinux*" since llvmlite and numba do not provide musllinux wheels test-skip = "*-musllinux*" [tool.cibuildwheel.linux] archs = ["x86_64", "aarch64"] [tool.cibuildwheel.windows] # TODO: Should we support Windows ARM64 too? archs = ["AMD64"] [tool.cibuildwheel.macos] # TODO: Should we build universal2 wheels for macOS to reduce wheel count? archs = ["x86_64", "arm64"] [tool.cibuildwheel.macos.environment] # Needed for C++17 support MACOSX_DEPLOYMENT_TARGET = "10.13"