diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b1c28aa..4138273 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - name: Set up Python diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 97337a0..faa2db3 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -34,6 +34,7 @@ jobs: cp310-manylinux_x86_64 cp310-manylinux_aarch64 cp310-macosx_x86_64 cp310-win_amd64 cp311-manylinux_x86_64 cp311-manylinux_aarch64 cp311-macosx_x86_64 cp311-win_amd64 cp312-manylinux_x86_64 cp312-manylinux_aarch64 cp312-macosx_x86_64 cp312-win_amd64 + cp313-manylinux_x86_64 cp313-manylinux_aarch64 cp313-macosx_x86_64 cp313-win_amd64 - name: Store artifacts uses: actions/upload-artifact@v4 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ffcc612..cfe0b3c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/ambv/black - rev: 20.8b1 + rev: 24.8.0 hooks: - id: black language_version: python3 diff --git a/build_tools/requirements.txt b/build_tools/requirements.txt index 6fb9f1a..b462779 100644 --- a/build_tools/requirements.txt +++ b/build_tools/requirements.txt @@ -1,10 +1,10 @@ -r ../requirements.txt pytest pre-commit -black==20.8b1 +black==24.8.0 click==8.0.3 flake8==3.8.4 pytest-cov lightgbm xgboost -cython>=0.28.5 +cython>=3.0,<3.1 diff --git a/deepforest/_binner.py b/deepforest/_binner.py index 35fd797..a3aeeaf 100644 --- a/deepforest/_binner.py +++ b/deepforest/_binner.py @@ -5,7 +5,6 @@ https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/ensemble/_hist_gradient_boosting/binning.py """ - __all__ = ["Binner"] import numpy as np diff --git a/deepforest/_estimator.py b/deepforest/_estimator.py index c8ce2dc..a620122 100644 --- a/deepforest/_estimator.py +++ b/deepforest/_estimator.py @@ -1,6 +1,5 @@ """A wrapper on the base estimator for the naming consistency.""" - __all__ = ["Estimator"] import numpy as np diff --git a/deepforest/_io.py b/deepforest/_io.py index c840f43..689bf44 100644 --- a/deepforest/_io.py +++ b/deepforest/_io.py @@ -3,7 +3,6 @@ class is designed to support the partial mode in deep forest. """ - __all__ = ["Buffer"] import os diff --git a/deepforest/_layer.py b/deepforest/_layer.py index e0015fc..227c2a2 100644 --- a/deepforest/_layer.py +++ b/deepforest/_layer.py @@ -1,6 +1,5 @@ """Implementation of the cascade layer in deep forest.""" - __all__ = [ "BaseCascadeLayer", "ClassificationCascadeLayer", diff --git a/deepforest/_utils.py b/deepforest/_utils.py index c985edd..984ba87 100644 --- a/deepforest/_utils.py +++ b/deepforest/_utils.py @@ -1,6 +1,5 @@ """Implement utilities used in deep forest.""" - import numpy as np from datetime import datetime diff --git a/deepforest/cascade.py b/deepforest/cascade.py index ee1b894..1feb43f 100644 --- a/deepforest/cascade.py +++ b/deepforest/cascade.py @@ -1,6 +1,5 @@ """Implementation of Deep Forest.""" - __all__ = ["CascadeForestClassifier", "CascadeForestRegressor"] import numbers @@ -770,10 +769,12 @@ def fit(self, X, y, sample_weight=None): X, y = check_X_y( X, y, - multi_output=True - if type_of_target(y) - in ("continuous-multioutput", "multiclass-multioutput") - else False, + multi_output=( + True + if type_of_target(y) + in ("continuous-multioutput", "multiclass-multioutput") + else False + ), ) self._check_input(X, y) @@ -1427,10 +1428,12 @@ def fit(self, X, y, sample_weight=None): X, y = check_X_y( X, y, - multi_output=True - if type_of_target(y) - in ("continuous-multioutput", "multiclass-multioutput") - else False, + multi_output=( + True + if type_of_target(y) + in ("continuous-multioutput", "multiclass-multioutput") + else False + ), ) # Check the input for classification y = self._encode_class_labels(y) @@ -1639,10 +1642,12 @@ def fit(self, X, y, sample_weight=None): X, y = check_X_y( X, y, - multi_output=True - if type_of_target(y) - in ("continuous-multioutput", "multiclass-multioutput") - else False, + multi_output=( + True + if type_of_target(y) + in ("continuous-multioutput", "multiclass-multioutput") + else False + ), ) # Check the input for regression diff --git a/deepforest/forest.py b/deepforest/forest.py index 10eb127..342778b 100644 --- a/deepforest/forest.py +++ b/deepforest/forest.py @@ -5,7 +5,6 @@ https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/ensemble/_forest.py """ - __all__ = [ "RandomForestClassifier", "RandomForestRegressor", @@ -618,7 +617,11 @@ def predict_proba(self, X): for j in np.atleast_1d(self.n_classes_) ] lock = threading.Lock() - Parallel(n_jobs=n_jobs, verbose=self.verbose, require="sharedmem",)( + Parallel( + n_jobs=n_jobs, + verbose=self.verbose, + require="sharedmem", + )( delayed(_accumulate_prediction)( self.features[i], self.thresholds[i], @@ -801,7 +804,11 @@ def predict(self, X): # Parallel loop lock = threading.Lock() - Parallel(n_jobs=n_jobs, verbose=self.verbose, require="sharedmem",)( + Parallel( + n_jobs=n_jobs, + verbose=self.verbose, + require="sharedmem", + )( delayed(_accumulate_prediction)( self.features[i], self.thresholds[i], diff --git a/deepforest/tree/_splitter.pyx b/deepforest/tree/_splitter.pyx index f0a15b9..7b29cc5 100644 --- a/deepforest/tree/_splitter.pyx +++ b/deepforest/tree/_splitter.pyx @@ -939,7 +939,7 @@ cdef class BaseSparseSplitter(Splitter): end_negative, start_positive) -cdef int compare_SIZE_t(const void* a, const void* b) nogil: +cdef int compare_SIZE_t(const void* a, const void* b) noexcept nogil: """Comparison function for sort.""" return ((a)[0] - (b)[0]) diff --git a/deepforest/tree/_tree.pyx b/deepforest/tree/_tree.pyx index 5be7a2e..05d3430 100644 --- a/deepforest/tree/_tree.pyx +++ b/deepforest/tree/_tree.pyx @@ -32,6 +32,7 @@ cdef extern from "numpy/arrayobject.h": int nd, np.npy_intp* dims, np.npy_intp* strides, void* data, int flags, object obj) + int PyArray_SetBaseObject(np.ndarray arr, PyObject* obj) # ============================================================================= # Types and constants @@ -137,8 +138,8 @@ cdef class DepthFirstTreeBuilder(TreeBuilder): cdef int init_leaf_capacity if tree.max_depth <= 10: - init_internal_capacity = (2 ** (tree.max_depth + 1)) - 1 - init_leaf_capacity = (2 ** (tree.max_depth + 1)) - 1 + init_internal_capacity = (1 << (tree.max_depth + 1)) - 1 + init_leaf_capacity = (1 << (tree.max_depth + 1)) - 1 else: init_internal_capacity = 2047 init_leaf_capacity = 2047 @@ -905,7 +906,7 @@ cdef class Tree: cdef np.ndarray arr arr = np.PyArray_SimpleNewFromData(3, shape, np.NPY_DOUBLE, self.value) Py_INCREF(self) - arr.base = self + PyArray_SetBaseObject(arr, self) return arr cdef np.ndarray _get_node_ndarray(self): @@ -924,7 +925,7 @@ cdef class Tree: arr = PyArray_NewFromDescr( np.ndarray, NODE_DTYPE, 1, shape, strides, self.nodes, - np.NPY_DEFAULT, None) + 0, None) Py_INCREF(self) - arr.base = self + PyArray_SetBaseObject(arr, self) return arr diff --git a/deepforest/tree/tree.py b/deepforest/tree/tree.py index bdb4b41..1d882d7 100644 --- a/deepforest/tree/tree.py +++ b/deepforest/tree/tree.py @@ -5,7 +5,6 @@ https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/tree/_classes.py """ - __all__ = [ "DecisionTreeClassifier", "DecisionTreeRegressor", diff --git a/deepforest/utils/kfoldwrapper.py b/deepforest/utils/kfoldwrapper.py index 61b47ff..250c85f 100644 --- a/deepforest/utils/kfoldwrapper.py +++ b/deepforest/utils/kfoldwrapper.py @@ -2,7 +2,6 @@ Implementation of the estimator wrapper to support customized base estimators. """ - __all__ = ["KFoldWrapper"] import copy diff --git a/pyproject.toml b/pyproject.toml index 9ac5189..e6bfbc1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,8 +2,8 @@ requires = [ "setuptools>=61,<70", "wheel", - "numpy==1.26.4", - "Cython>=0.28.5,<3.0", + "numpy>=2.1.1,<3", + "Cython>=3.0,<3.1", "oldest-supported-numpy", "scipy>=1.3.2", ] diff --git a/requirements.txt b/requirements.txt index 749d1ee..89a2b1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy>=1.14.6 +numpy>=1.21,<3 scipy>=1.1.0 joblib>=0.11 scikit-learn>=1.0 \ No newline at end of file diff --git a/setup.py b/setup.py index 7bab9e0..d3e2a99 100644 --- a/setup.py +++ b/setup.py @@ -104,17 +104,18 @@ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development", "Topic :: Scientific/Engineering", "Operating System :: Microsoft :: Windows", "Operating System :: Unix", ], - python_requires=">=3.10", + python_requires=">=3.10,<3.14", install_requires=[ - "numpy>=1.14.6,<2.0", + "numpy>=1.21,<3", "scipy>=1.1.0", "joblib>=0.11", "scikit-learn>=1.0,<1.6", ], - setup_requires=["cython", "numpy>=1.21,<2.0"], + setup_requires=["Cython>=3.0,<3.1", "numpy>=1.21,<3"], )