Repository: WenjieZ/TSCV (language: python)

Issue:
Import error with latest sklearn version
Hi guys, this issue occured after the upgrade to 1.1.3


ImportError: cannot import name '_pprint' from 'sklearn.base'

```
/.venv/lib/python3.10/site-packages/tscv/_split.py:19 in      │
│ <module>                                                                                         │
│                                                                                                  │
│    16 import numpy as np                                                                         │
│    17 from sklearn.utils import indexable                                                        │
│    18 from sklearn.utils.validation import _num_samples, check_consistent_length                 │
│ ❱  19 from sklearn.base import _pprint                                                           │
│    20 from sklearn.utils import _safe_indexing                                                   │
│    21                                                                                            │
│    22                                       
```

Could you please fix it ?

Kind regards,
Jim


Discussion / hints:
It seems like sklearn moved _pprint to a different place in latest 1.3 version:

**to be removed:** from sklearn.base import _pprint (doesn't exist anymore)
**to be added:** from sklearn.utils import _pprint (seems to be the new location?)

Best regards,
Jim

Hi, @teneon, thank you for bringing this to my attention. 

The function `_pprint` desired has been moved to `sklearn.model_selection`. The solution would be either I import from there or I write my version of `_pprint`.

Fix patch:
diff --git a/.travis.yml b/.travis.yml
index 94d34a9..f1af4dd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ cache:
 matrix:
   include:
     - env: PYTHON_VERSION="3.6" SKLEARN_VERSION="0.22"
-    - env: PYTHON_VERSION="3.9" SKLEARN_VERSION="0.24"
+    - env: PYTHON_VERSION="3.11" SKLEARN_VERSION="1.2"
 
 install:
   # install miniconda
diff --git a/LICENSE b/LICENSE
index dbfab02..a75b50b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,6 @@
 BSD 3-Clause License
 
-Copyright (c) 2019, Wenjie Zheng
-Copyright (c) 2007–2019 The scikit-learn developers.
+Copyright (c) 2019, 2021, 2023 Wenjie Zheng
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/appveyor.yml b/appveyor.yml
index 56b4e91..5b46a2c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -8,13 +8,15 @@ environment:
     # The list here is complete (excluding Python 2.6, which
     # isn't covered by this document) at the time of writing.
 
-#    - PYTHON: "C:\\Miniconda3-x64"
-#      PYTHON_VERSION: "3.6.x"
-#      PYTHON_ARCH: "64"
-#      SKLEARN_VERSION: "0.22"
-
     - PYTHON: "C:\\Miniconda3-x64"
+      PYTHON_VERSION: "3.7"
+      PYTHON_ARCH: "64"
+      SKLEARN_VERSION: "0.22"
+
+    - PYTHON: "C:\\Miniconda38-x64"
+      PYTHON_VERSION: "3.8"
       PYTHON_ARCH: "64"
+      SKLEARN_VERSION: "1.2"
 
 install:
   # Prepend miniconda installed Python to the PATH of this build
diff --git a/doc/conf.py b/doc/conf.py
index 280b5c9..9af8206 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -84,7 +84,7 @@
 
 # General information about the project.
 project = u'Time Series Cross-Validation'
-copyright = u'2019, 2021, Wenjie Zheng'
+copyright = u'2019, 2021, 2023, Wenjie Zheng'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/setup.py b/setup.py
index c5c892d..3f1a654 100644
--- a/setup.py
+++ b/setup.py
@@ -50,6 +50,8 @@ def get_version(rel_path):
                  'Programming Language :: Python :: 3.7',
                  'Programming Language :: Python :: 3.8',
                  'Programming Language :: Python :: 3.9',
+                 'Programming Language :: Python :: 3.10',
+                 'Programming Language :: Python :: 3.11',
                  ],
     python_requires=">=3.6",
     install_requires=['numpy>=1.13.3', 'scikit-learn>=0.22']
diff --git a/tscv/__init__.py b/tscv/__init__.py
index d5b59c0..b3d235f 100644
--- a/tscv/__init__.py
+++ b/tscv/__init__.py
@@ -6,7 +6,7 @@
 from ._split import gap_train_test_split
 
 
-__version__ = '0.2.dev'
+__version__ = '0.1.3'
 
 __all__ = ['GapCrossValidator',
            'GapLeavePOut',
diff --git a/tscv/_split.py b/tscv/_split.py
index 31e6521..f092ac3 100644
--- a/tscv/_split.py
+++ b/tscv/_split.py
@@ -14,10 +14,9 @@
 from inspect import signature
 
 import numpy as np
-from sklearn.utils import indexable
+from sklearn.utils import indexable, _safe_indexing
 from sklearn.utils.validation import _num_samples, check_consistent_length
-from sklearn.base import _pprint
-from sklearn.utils import _safe_indexing
+from sklearn.model_selection._split import _build_repr
 
 
 __all__ = ['GapCrossValidator',
@@ -30,39 +29,6 @@
 SINGLETON_WARNING = "Too few samples. Some training set is a singleton."
 
 
-def _build_repr(self):
-    # XXX This is ported from scikit-learn
-    cls = self.__class__
-    init = getattr(cls.__init__, 'deprecated_original', cls.__init__)
-    # Ignore varargs, kw and default values and pop self
-    init_signature = signature(init)
-    # Consider the constructor parameters excluding 'self'
-    if init is object.__init__:
-        args = []
-    else:
-        args = sorted([p.name for p in init_signature.parameters.values()
-                       if p.name != 'self' and p.kind != p.VAR_KEYWORD])
-    class_name = self.__class__.__name__
-    params = dict()
-    for key in args:
-        # We need deprecation warnings to always be on in order to
-        # catch deprecated param values.
-        # This is set in utils/__init__.py but it gets overwritten
-        # when running under python3 somehow.
-        warnings.simplefilter("always", DeprecationWarning)
-        try:
-            with warnings.catch_warnings(record=True) as w:
-                value = getattr(self, key, None)
-            if len(w) and w[0].category == DeprecationWarning:
-                # if the parameter is deprecated, don't show it
-                continue
-        finally:
-            warnings.filters.pop(0)
-        params[key] = value
-
-    return '%s(%s)' % (class_name, _pprint(params, offset=len(class_name)))
-
-
 class GapCrossValidator(metaclass=ABCMeta):
     """Base class for all gap cross-validators
 
@@ -212,6 +178,7 @@ class GapLeavePOut(GapCrossValidator):
     TRAIN: [4] TEST: [1 2]
     TRAIN: [0] TEST: [2 3]
     TRAIN: [0 1] TEST: [3 4]
+
     """
 
     def __init__(self, p, gap_before=0, gap_after=0):
@@ -431,7 +398,9 @@ def gap_train_test_split(*arrays, **options):
     [4]
     >>> gap_train_test_split(list(range(10)), gap_size=0.1)
     [[0, 1, 2, 3, 4, 5, 6], [8, 9]]
+
     """
+
     n_arrays = len(arrays)
     if n_arrays == 0:
         raise ValueError("At least one array required as input")
@@ -521,9 +490,6 @@ class GapWalkForward:
     >>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]])
     >>> y = np.array([1, 2, 3, 4, 5, 6])
     >>> cv = GapWalkForward(n_splits=5)
-    >>> print(cv)
-    GapWalkForward(gap_size=0, max_train_size=None, n_splits=5,
-                   rollback_size=0, test_size=None)
     >>> for train_index, test_index in cv.split(X):
     ...    print("TRAIN:", train_index, "TEST:", test_index)
     ...    X_train, X_test = X[train_index], X[test_index]
@@ -727,6 +693,7 @@ class GapRollForward:
     TRAIN: [0 1 2] TEST: [5 6 7]
     TRAIN: [2 3 4] TEST: [7 8 9]
     TRAIN: [4 5 6] TEST: [9]
+
     """
     def __init__(self, *, min_train_size=0, max_train_size=np.inf,
                  min_test_size=1, max_test_size=1,


Test patch:
diff --git a/tscv/tests/test_split.py b/tscv/tests/test_split.py
index 2b43ec0..96e7b42 100644
--- a/tscv/tests/test_split.py
+++ b/tscv/tests/test_split.py
@@ -9,7 +9,6 @@
 from numpy.testing import assert_array_equal
 from sklearn.utils._testing import ignore_warnings
 
-from tscv._split import _build_repr
 from tscv import GapCrossValidator
 from tscv import GapLeavePOut
 from tscv import GapKFold
@@ -18,19 +17,6 @@
 from tscv import gap_train_test_split
 
 
-def test_build_repr():
-    class MockSplitter:
-        def __init__(self, a, b=0, c=None):
-            self.a = a
-            self.b = b
-            self.c = c
-
-        def __repr__(self):
-            return _build_repr(self)
-
-    assert repr(MockSplitter(5, 6)) == "MockSplitter(a=5, b=6, c=None)"
-
-
 def test_gap_cross_validator():
     # Create a dummy subclass for the test
     class testCV(GapCrossValidator):