nptyping.types._number   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 230
Duplicated Lines 64.35 %

Importance

Changes 0
Metric Value
eloc 123
dl 148
loc 230
rs 9.92
c 0
b 0
f 0
wmc 31

11 Methods

Rating   Name   Duplication   Size   Complexity  
A _NumberMeta.__eq__() 2 2 1
A Number.bits() 7 7 1
A UInt.type_of() 9 9 1
A Number._after_subscription() 16 16 4
A _NumberMeta.__subclasscheck__() 10 10 4
A _NumberMeta.__hash__() 5 5 2
A Int.fitting() 12 12 3
A _NumberMeta.__instancecheck__() 8 8 3
A Float.type_of() 0 9 1
A UInt.fitting() 12 12 3
A Int.type_of() 9 9 1

4 Functions

Rating   Name   Duplication   Size   Complexity  
A _is_a() 0 3 1
A _is_number_type() 0 5 1
A _is_numpy_or_python_type_subclass_of() 16 16 4
A _is_number_subclass_of() 0 9 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
from inspect import getmro
2
from typing import (
3
    Any,
4
    Type,
5
    Union,
6
)
7
8
import numpy
9
from typish import Literal
10
11
from nptyping.types._nptype import NPType, SimpleNPTypeMeta
12
13
DEFAULT_INT_BITS = numpy.dtype(int).itemsize * 8
14
DEFAULT_FLOAT_BITS = numpy.dtype(float).itemsize * 8
15
16
17 View Code Duplication
class _NumberMeta(SimpleNPTypeMeta):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
18
    """
19
    Super metaclass for the Number class.
20
    """
21
    base = None
22
    npbase = None
23
    _bits = None
24
    _hashes = {}
25
    _repr_args = None
26
27
    def __eq__(cls, other):
28
        return hash(cls) == hash(other)
29
30
    def __hash__(cls):
31
        key = (cls.base, cls.npbase, cls._bits)
32
        if key not in cls._hashes:
33
            cls._hashes[key] = int(numpy.prod([hash(elem) for elem in key]))
34
        return cls._hashes[key]
35
36
    def __instancecheck__(cls, instance: Any) -> bool:
37
        from nptyping.functions._get_type import get_type
38
39
        if cls == instance or type(instance) in (int, float):
40
            # Covers Python types.
41
            return True
42
43
        return issubclass(get_type(instance), cls)
44
45
    def __subclasscheck__(cls, subclass: type) -> bool:
46
        result = False
47
        if cls == subclass:
48
            result = True
49
        elif _is_a(subclass, Number):
50
            # Cover nptyping number types.
51
            result = _is_number_subclass_of(subclass, cls)
52
        elif _is_number_type(subclass):
53
            result = _is_numpy_or_python_type_subclass_of(subclass, cls)
54
        return result
55
56
57 View Code Duplication
class Number(NPType, metaclass=_NumberMeta):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
58
    """
59
    Superclass for number types (integers and floating point numbers). Can be
60
    optionally given the number of bits.
61
    """
62
    base = None
63
    npbase = None
64
    _bits = None
65
    _repr_args = None
66
67
    @classmethod
68
    def _after_subscription(cls, args: Any) -> None:
69
        if isinstance(args, tuple):
70
            cls.base = args[0]
71
            cls.npbase = args[1]
72
            return
73
74
        if not isinstance(args, int):
75
            raise TypeError('Number takes only an int as generic type. '
76
                            'Given: {}'.format(type(args).__name__))
77
78
        cls._bits = args
79
        cls._repr_args = args
80
81
        if not hasattr(numpy, '{}{}'.format(cls.base.__name__, cls._bits)):
82
            raise TypeError('Unsupported number of bits: {}'.format(args))
83
84
    @classmethod
85
    def bits(cls) -> Union[int, Literal[Any]]:
86
        """
87
        Return the number of bits of this Number type.
88
        :return: the number of bits or Any.
89
        """
90
        return cls._bits
91
92
93 View Code Duplication
class Int(Number[int, numpy.signedinteger]):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
94
    """
95
    A (signed) numpy int. Can be given the number of bits optionally.
96
97
    >>> Int[32]
98
    Int[32]
99
    """
100
101
    @classmethod
102
    def type_of(cls, obj: Any) -> Type['Int']:
103
        """
104
        Return the NPType that corresponds to obj.
105
        :param obj: an int compatible object.
106
        :return: a Int type.
107
        """
108
        from nptyping.functions._get_type import get_type_int
109
        return get_type_int(obj)
110
111
    @staticmethod
112
    def fitting(number: int) -> Type['Int']:
113
        """
114
        Return the Int type that fits the given number.
115
        :param number: the number of which the Int type is to be found.
116
        :return: a type of Int.
117
        """
118
        bitlen = number.bit_length()
119
        for bits in [8, 16, 32, 64]:
120
            if bitlen <= bits - 1:  # subtract sign bit.
121
                break
122
        return Int[bits]
0 ignored issues
show
introduced by
The variable bits does not seem to be defined in case the for loop on line 119 is not entered. Are you sure this can never be the case?
Loading history...
123
124
125 View Code Duplication
class UInt(Number[int, numpy.unsignedinteger]):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
126
    """
127
    An unsigned numpy int. Can be given the number of bits optionally.
128
129
    >>> UInt[32]
130
    UInt[32]
131
    """
132
133
    @classmethod
134
    def type_of(cls, obj: Any) -> Type['UInt']:
135
        """
136
        Return the NPType that corresponds to obj.
137
        :param obj: an uint compatible object.
138
        :return: an UInt type.
139
        """
140
        from nptyping.functions._get_type import get_type_uint
141
        return get_type_uint(obj)
142
143
    @staticmethod
144
    def fitting(number: int) -> Type['UInt']:
145
        """
146
        Return the UInt type that fits the given number.
147
        :param number: the number of which the UInt type is to be found.
148
        :return: a type of UInt.
149
        """
150
        bitlen = number.bit_length()
151
        for bits in [8, 16, 32, 64]:
152
            if bitlen <= bits:
153
                break
154
        return UInt[bits]
0 ignored issues
show
introduced by
The variable bits does not seem to be defined in case the for loop on line 151 is not entered. Are you sure this can never be the case?
Loading history...
155
156
157
class Float(Number[float, numpy.floating]):
158
    """
159
    A numpy float. Can be given the number of bits optionally.
160
161
    >>> Float[32]
162
    Float[32]
163
    """
164
165
    @staticmethod
166
    def type_of(obj: Any) -> Type['Float']:
167
        """
168
        Return the NPType that corresponds to obj.
169
        :param obj: a float compatible object.
170
        :return: a Float type.
171
        """
172
        from nptyping.functions._get_type import get_type_float
173
        return get_type_float(obj)
174
175
176
def _is_a(this: Any, that: type) -> bool:
177
    # Return whether this is a subclass of that, considering the mro.
178
    return that in getmro(this)
179
180
181
def _is_number_subclass_of(
182
        subclass: Type[Number],
183
        superclass: Type[Number]) -> bool:
184
    # Return whether subclass (which must be a type of Number) subclasses
185
    # superclass.
186
    base_is_eq = (not superclass.npbase
187
                  or issubclass(subclass.npbase, superclass.npbase))
188
    bits_is_eq = not superclass.bits() or subclass.bits() == superclass.bits()
189
    return base_is_eq and bits_is_eq
190
191
192 View Code Duplication
def _is_numpy_or_python_type_subclass_of(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
193
        subclass: Any,
194
        superclass: Type[Number]) -> bool:
195
    # Return whether subclass (which must be a numpy type or a Python type)
196
    # subclasses superclass.
197
    if not superclass.npbase:
198
        # superclass is Number.
199
        result = True
200
    else:
201
        try:
202
            nptype = superclass.type_of(subclass)
203
        except TypeError:
204
            result = False
205
        else:
206
            result = issubclass(nptype, superclass)
207
    return result
208
209
210
def _is_number_type(type_: type) -> bool:
211
    # Return whether type_ is a numpy/Python number type.
212
    return (issubclass(type_, numpy.number)
213
            or issubclass(type_, int)
214
            or issubclass(type_, float))
215
216
217
Int8 = Int[8]
218
Int16 = Int[16]
219
Int32 = Int[32]
220
Int64 = Int[64]
221
222
UInt8 = UInt[8]
223
UInt16 = UInt[16]
224
UInt32 = UInt[32]
225
UInt64 = UInt[64]
226
227
Float16 = Float[16]
228
Float32 = Float[32]
229
Float64 = Float[64]
230