Coverage for qdscreen/compat.py: 17%
81 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-17 11:02 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-17 11:02 +0000
1import sys
3PY2 = sys.version_info < (3,)
4if PY2: 4 ↛ 6line 4 didn't jump to line 6, because the condition on line 4 was never true
5 # Python 2 is not happy with our package having the same name, we need dynamic import
6 import importlib
8 try:
9 # try old sklearn first, we are on python 2
10 sklearn_ft_base = importlib.import_module("sklearn.feature_selection.base")
11 except ImportError:
12 sklearn_ft_base = importlib.import_module("sklearn.feature_selection")
14 SelectorMixin = sklearn_ft_base.SelectorMixin
16 sklearn_base = importlib.import_module("sklearn.base")
17 BaseEstimator = sklearn_base.BaseEstimator
19else:
20 # Normal imports on python 3
21 try:
22 from sklearn.feature_selection import SelectorMixin
23 except ImportError: # older sklearn
24 from sklearn.feature_selection.base import SelectorMixin
26 from sklearn.base import BaseEstimator
29try:
30 BaseEstimator._get_tags
31except AttributeError:
32 import inspect
34 _DEFAULT_TAGS = {
35 'non_deterministic': False,
36 'requires_positive_X': False,
37 'requires_positive_y': False,
38 'X_types': ['2darray'],
39 'poor_score': False,
40 'no_validation': False,
41 'multioutput': False,
42 "allow_nan": False,
43 'stateless': False,
44 'multilabel': False,
45 '_skip_test': False,
46 '_xfail_checks': False,
47 'multioutput_only': False,
48 'binary_only': False,
49 'requires_fit': True,
50 'requires_y': False,
51 }
53 def _more_tags(self):
54 return _DEFAULT_TAGS
56 def _get_tags(self):
57 collected_tags = {}
58 for base_class in reversed(inspect.getmro(self.__class__)):
59 if hasattr(base_class, '_more_tags'):
60 # need the if because mixins might not have _more_tags
61 # but might do redundant work in estimators
62 # (i.e. calling more tags on BaseEstimator multiple times)
63 more_tags = base_class._more_tags(self)
64 collected_tags.update(more_tags)
65 return collected_tags
67 # set the missing methods
68 BaseEstimator._more_tags = _more_tags
69 BaseEstimator._get_tags = _get_tags
71try:
72 BaseEstimator._validate_data
73except AttributeError:
74 if PY2:
75 # Python 2 is not happy with our package having the same name, we need dynamic import
76 import importlib
78 sklearn_ut_val = importlib.import_module("sklearn.utils.validation")
79 check_X_y = sklearn_ut_val.check_X_y
80 check_array = sklearn_ut_val.check_array
81 else:
82 # normal import on python 3
83 from sklearn.utils.validation import check_X_y, check_array
85 def _validate_data(self, X, y=None, reset=True,
86 validate_separately=False, **check_params):
87 """Validate input data and set or check the `n_features_in_` attribute.
89 Parameters
90 ----------
91 X : {array-like, sparse matrix, dataframe} of shape \
92 (n_samples, n_features)
93 The input samples.
94 y : array-like of shape (n_samples,), default=None
95 The targets. If None, `check_array` is called on `X` and
96 `check_X_y` is called otherwise.
97 reset : bool, default=True
98 Whether to reset the `n_features_in_` attribute.
99 If False, the input will be checked for consistency with data
100 provided when reset was last True.
101 validate_separately : False or tuple of dicts, default=False
102 Only used if y is not None.
103 If False, call validate_X_y(). Else, it must be a tuple of kwargs
104 to be used for calling check_array() on X and y respectively.
105 **check_params : kwargs
106 Parameters passed to :func:`sklearn.utils.check_array` or
107 :func:`sklearn.utils.check_X_y`. Ignored if validate_separately
108 is not False.
110 Returns
111 -------
112 out : {ndarray, sparse matrix} or tuple of these
113 The validated input. A tuple is returned if `y` is not None.
114 """
116 if y is None:
117 # note: for some reason our patch above does not add this tag,
118 # there is still a KeyError if we use self._get_tags()['requires_y']
119 if self._get_tags().get('requires_y', False):
120 raise ValueError(
121 "This {} estimator "
122 "requires y to be passed, but the target y is None."
123 ).__format__(self.__class__.__name__)
124 X = check_array(X, **check_params)
125 out = X
126 else:
127 if validate_separately:
128 # We need this because some estimators validate X and y
129 # separately, and in general, separately calling check_array()
130 # on X and y isn't equivalent to just calling check_X_y()
131 # :(
132 check_X_params, check_y_params = validate_separately
133 X = check_array(X, **check_X_params)
134 y = check_array(y, **check_y_params)
135 else:
136 X, y = check_X_y(X, y, **check_params)
137 out = X, y
139 if check_params.get('ensure_2d', True):
140 self._check_n_features(X, reset=reset)
142 return out
144 # set the missing method
145 BaseEstimator._validate_data = _validate_data
148try:
149 BaseEstimator._check_n_features
150except AttributeError:
151 def _check_n_features(self, X, reset):
152 """Set the `n_features_in_` attribute, or check against it.
154 Parameters
155 ----------
156 X : {ndarray, sparse matrix} of shape (n_samples, n_features)
157 The input samples.
158 reset : bool
159 If True, the `n_features_in_` attribute is set to `X.shape[1]`.
160 Else, the attribute must already exist and the function checks
161 that it is equal to `X.shape[1]`.
162 """
163 n_features = X.shape[1]
165 if reset:
166 self.n_features_in_ = n_features
167 else:
168 if not hasattr(self, 'n_features_in_'):
169 raise RuntimeError(
170 "The reset parameter is False but there is no "
171 "n_features_in_ attribute. Is this estimator fitted?"
172 )
173 if n_features != self.n_features_in_:
174 raise ValueError(
175 'X has {} features, but this {} is expecting {} features '
176 'as input.'.format(n_features, self.__class__.__name__,
177 self.n_features_in_)
178 )
180 # set the missing method
181 BaseEstimator._check_n_features = _check_n_features
184PY2 = sys.version_info < (3, 0)
187def encode_if_py2(fun):
188 """
189 A decorator to use typically on __str__ and __repr__ methods if they return unicode literal string, so that
190 under python 2 their result is encoded into utf-8 to avoir a
191 UnicodeEncodeError: ... codec can't encode characters in position ...
193 :param fun:
194 :return:
195 """
196 if PY2: 196 ↛ 197line 196 didn't jump to line 197, because the condition on line 196 was never true
197 def new_fun(*args, **kwargs):
198 return fun(*args, **kwargs).encode("utf-8")
199 return new_fun
200 else:
201 return fun
204def python_2_unicode_compatible(klass):
205 """
206 A decorator that defines __unicode__ and __str__ methods under Python 2.
207 Under Python 3 it does nothing.
209 To support Python 2 and 3 with a single code base, define a __str__ method
210 returning text and apply this decorator to the class.
211 """
212 if PY2:
213 if '__str__' not in klass.__dict__:
214 raise ValueError("@python_2_unicode_compatible cannot be applied "
215 "to %s because it doesn't define __str__()." %
216 klass.__name__)
217 klass.__unicode__ = klass.__str__
218 def __str__(self):
219 return self.__unicode__().encode('utf-8')
221 klass.__str__ = __str__
222 return klass