sdpython / cpyquickhelper

Compare 5104606 ... +2 ... 315f91e

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -3,26 +3,21 @@
Loading
3 3
@brief Addition for :epkg:`pandas`.
4 4
"""
5 5
from itertools import chain
6 -
from numpy import isnan, dtype, nan, array
6 +
import numpy
7 7
from pandas import Series
8 -
from pandas.api.extensions import register_series_accessor
8 +
from pandas.api.extensions import (
9 +
    register_series_accessor, ExtensionDtype, register_extension_dtype)
9 10
from pandas.arrays import PandasArray
10 11
from pandas.core.arrays.numpy_ import PandasDtype
11 12
from .weighted_number import WeightedDouble  # pylint: disable=E0611
12 13
13 14
14 -
class WeightedSeriesDtype(PandasDtype):
15 +
class WeightedSeriesDtype(ExtensionDtype):
15 16
    """
16 17
    Defines a custom type for a @see cl WeightedSeries.
17 18
    """
18 19
19 -
    dtype = dtype(WeightedDouble)
20 -
21 -
    def __init__(self):
22 -
        """
23 -
        Initializes dtype.
24 -
        """
25 -
        PandasDtype.__init__(self, dtype=dtype('c16'))
20 +
    dtype = numpy.dtype(WeightedDouble)
26 21
27 22
    def __str__(self):
28 23
        """
@@ -39,6 +34,10 @@
Loading
39 34
        """
40 35
        return WeightedSeriesDtype
41 36
37 +
    def __repr__(self):
38 +
        "usual"
39 +
        return "WeightedSeriesDtype()"
40 +
42 41
    @property
43 42
    def kind(self):
44 43
        # type () -> str
@@ -87,7 +86,7 @@
Loading
87 86
        elif len(val) == 2:
88 87
            val = float(val[0]), float(val[1])
89 88
        elif len(val) == 0 or (len(val) == 1 and val[0] == ''):
90 -
            val = nan
89 +
            val = numpy.nan
91 90
        else:  # pragma no cover
92 91
            raise TypeError("Unable to parse '{0}'".format(string))
93 92
        if isinstance(val, tuple):
@@ -96,6 +95,20 @@
Loading
96 95
            return WeightedDouble(val[0], val[1])
97 96
        return WeightedDouble(val)
98 97
98 +
    @classmethod
99 +
    def construct_array_type(cls):
100 +
        """
101 +
        Return the array type associated with this dtype.
102 +
103 +
        Returns
104 +
        -------
105 +
        type
106 +
        """
107 +
        return WeightedArray
108 +
109 +
110 +
register_extension_dtype(WeightedSeriesDtype)
111 +
99 112
100 113
@register_series_accessor("wdouble")
101 114
class WeightedDoubleAccessor:
@@ -122,13 +135,14 @@
Loading
122 135
123 136
    def isnan(self):
124 137
        "Tells if values are missing."
125 -
        return self._new_series(lambda s: isnan(s.value))
138 +
        return self._new_series(lambda s: numpy.isnan(s.value))
126 139
127 140
    def _new_series(self, fct):
128 141
        if len(self) == 0:  # pragma no cover
129 142
            raise ValueError("Series cannot be empty.")
130 143
        if isinstance(self.obj, WeightedArray) or isinstance(self.obj[0], WeightedDouble):
131 -
            return WeightedArray([fct(s) for s in self.obj], index=self.obj.index, dtype=float)
144 +
            return WeightedArray([fct(s) for s in self.obj],
145 +
                                 index=self.obj.index, dtype=float)
132 146
        raise TypeError(  # pragma no cover
133 147
            "Unexpected type, array is '{0}', first element is '{1}'".format(
134 148
                type(self.obj), type(self.obj[0])))
@@ -155,13 +169,12 @@
Loading
155 169
        """
156 170
        if hasattr(Series, attr):
157 171
            return getattr(self, attr)
158 -
        elif hasattr(WeightedDoubleAccessor, attr):
172 +
        if hasattr(WeightedDoubleAccessor, attr):
159 173
            obj = WeightedDoubleAccessor(self)
160 174
            return getattr(obj, attr)
161 -
        elif attr == '_ndarray':
162 -
            return array(self)
163 -
        else:
164 -
            raise AttributeError("Unkown attribute '{0}'".format(attr))
175 +
        if attr == '_ndarray':
176 +
            return numpy.array(self)
177 +
        raise AttributeError("Unkown attribute '{0}'".format(attr))
165 178
166 179
167 180
class WeightedArray(PandasArray):
@@ -179,9 +192,11 @@
Loading
179 192
        """
180 193
        if "data" in kwargs and isinstance(kwargs["data"], WeightedSeries):
181 194
            serie = kwargs["data"]
195 +
        elif len(args) == 1 and isinstance(args[0], numpy.ndarray):
196 +
            PandasArray.__init__(self, args[0])
182 197
        else:
183 198
            serie = WeightedSeries(*args, **kwargs)
184 -
        PandasArray.__init__(self, serie._ndarray)
199 +
            PandasArray.__init__(self, serie._ndarray)
185 200
186 201
    @property
187 202
    def dtype(self):
@@ -190,6 +205,14 @@
Loading
190 205
        """
191 206
        return self._dtype
192 207
208 +
    @property
209 +
    def name(self):
210 +
        """
211 +
        A string identifying the data type.
212 +
        Will be used for display in, e.g. ``Series.dtype``
213 +
        """
214 +
        return "WeightedArray"
215 +
193 216
    def __add__(self, other):
194 217
        "Addition"
195 218
        return WeightedArray([a + b for a, b in zip(self, other)])
@@ -208,7 +231,7 @@
Loading
208 231
209 232
    def isna(self):
210 233
        "is nan?"
211 -
        return array([isnan(s.value) for s in self])
234 +
        return numpy.array([numpy.isnan(s.value) for s in self])
212 235
213 236
    @classmethod
214 237
    def _concat_same_type(cls, to_concat):
@@ -229,3 +252,13 @@
Loading
229 252
                    "All arrays must be of type WeightedSeriesDtype not {}-{}".format(
230 253
                        type(s), type(s.dtype)))
231 254
        return WeightedArray(list(chain(*to_concat)))
255 +
256 +
    @classmethod
257 +
    def _from_sequence(cls, scalars, dtype=None, copy: bool = False) -> "PandasArray":
258 +
        if isinstance(dtype, PandasDtype):
259 +
            dtype = dtype._dtype
260 +
261 +
        result = numpy.asarray(scalars, dtype=dtype)
262 +
        if copy and result is scalars:
263 +
            result = result.copy()
264 +
        return cls(result)

Everything is accounted for!

No changes detected that need to be reviewed.
What changes does Codecov check for?
Lines, not adjusted in diff, that have changed coverage data.
Files that introduced coverage data that had none before.
Files that have missing coverage data that once were tracked.
Files Coverage
cpyquickhelper -1.35% 96.46%
Project Totals (9 files) 96.46%
Loading