Completed
Push — master ( c5c112...117b26 )
by Ramon
14s queued 10s
created

nptyping._array_meta   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 62
dl 0
loc 88
rs 10
c 0
b 0
f 0
wmc 21

4 Methods

Rating   Name   Duplication   Size   Complexity  
A _Array.__new__() 0 2 1
A _ArrayMeta.__getitem__() 0 3 1
B _ArrayMeta.__instancecheck__() 0 22 7
D _Array._after_subscription() 0 37 12
1
"""
2
PRIVATE MODULE: do not import (from) it directly.
3
This module contains meta functionality for the ``Array`` type.
4
"""
5
from functools import lru_cache
6
import numpy as np
7
from typish import SubscriptableType
8
from typish._types import Ellipsis_, NoneType
9
10
11
class _ArrayMeta(SubscriptableType):
12
    # A Meta class for the Array class.
13
    @lru_cache()
14
    def __getitem__(self, item):
15
        return SubscriptableType.__getitem__(self, item)
16
17
    def __instancecheck__(self, inst):
18
        result = False
19
        if isinstance(inst, np.ndarray):
20
            result = True  # In case of an empty array or no _generic_type.
21
            rows = 0
22
            cols = 0
23
            if len(inst.shape) > 0:
24
                rows = inst.shape[0]
25
            if len(inst.shape) > 1:
26
                cols = inst.shape[1]
27
28
            if inst.size > 0 and self.generic_type:
29
                if isinstance(self.generic_type, tuple):
30
                    inst_dtypes = [inst.dtype[name] for name in inst.dtype.names]
31
                    cls_dtypes = [np.dtype(typ) for typ in self.generic_type]
32
                    result = inst_dtypes == cls_dtypes
33
                else:
34
                    result = isinstance(inst[0], self.generic_type)
35
                    result |= inst.dtype == np.dtype(self.generic_type)
36
                result &= self.rows is ... or self.rows == rows
37
                result &= self.cols is ... or self.cols == cols
38
        return result
39
40
41
class _Array(metaclass=_ArrayMeta):
42
    # This class exists to keep the Array class as clean as possible.
43
    _ROWCOL_TYPES = [int, Ellipsis_, NoneType]
44
    generic_type = None
45
    rows = ...
46
    cols = ...
47
48
    def __new__(cls, *args, **kwargs):
49
        raise TypeError("Cannot instantiate abstract class Array")
50
51
    @classmethod
52
    def _after_subscription(cls, item):
53
        if not isinstance(item, tuple):
54
            cls.generic_type = item
55
        else:
56
            if not len(item):
57
                raise TypeError('Parameter Array[...] cannot be empty')
58
59
            # Collect all elements in item that are types and keep track of
60
            # the index.
61
            cls.generic_type = tuple()
62
            for index, value in enumerate(item):
63
                if isinstance(value, type):
64
                    cls.generic_type += (value,)
65
                else:
66
                    break
67
            else:
68
                index += 1
0 ignored issues
show
introduced by
The variable index does not seem to be defined in case the for loop on line 62 is not entered. Are you sure this can never be the case?
Loading history...
69
70
            # If there is only one type defined before, then store that type
71
            # rather than a tuple.
72
            if len(cls.generic_type) == 1:
73
                cls.generic_type = cls.generic_type[0]
74
75
            if len(item) > index:
76
                if type(item[index]) not in cls._ROWCOL_TYPES:
77
                    raise TypeError('Unexpected type %s, expecting int or ... or None' % item[index])
78
                cls.rows = item[index] or ...
79
            index += 1
80
81
            if len(item) > index:
82
                if isinstance(cls.generic_type, tuple):
83
                    raise TypeError('You are not allowed to specify a column count, combined with multiple column '
84
                                    'types.')
85
                if type(item[index]) not in cls._ROWCOL_TYPES:
86
                    raise TypeError('Unexpected type %s, expecting int or ... or None' % item[index])
87
                cls.cols = item[index] or ...
88