Passed
Push — main ( 520e83...b06663 )
by Douglas
01:43
created

pocketutils.core.iterators.SeqIterator.seq()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
import abc
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
from collections.abc import Iterator as _Iterator
3
from typing import Iterable, Sequence, Tuple, TypeVar
4
5
import numpy as np
0 ignored issues
show
introduced by
Unable to import 'numpy'
Loading history...
6
7
T = TypeVar("T")
0 ignored issues
show
Coding Style Naming introduced by
Class name "T" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
8
IX = TypeVar("IX")
9
10
11
class SizedIterator(_Iterator[T], metaclass=abc.ABCMeta):
12
    """
13
    An iterator with size and progress.
14
    """
15
16
    def position(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
17
        raise NotImplementedError()
18
19
    def total(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
20
        raise NotImplementedError()
21
22
    def remaining(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
23
        return self.total() - self.position()
24
25
    def has_next(self) -> bool:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
26
        return self.position() < self.total()
27
28
    def __len__(self) -> int:
29
        return self.total()
30
31
    def __repr__(self):
32
        return f"It({self.position()}/{self.total()})"
33
34
    def __str__(self):
35
        return repr(self)
36
37
38
class SeqIterator(SizedIterator[T]):
39
    """
40
    A concrete SizedIterator backed by a list.
41
    """
42
43
    def __init__(self, it: Iterable[T]):
0 ignored issues
show
Coding Style Naming introduced by
Argument name "it" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
44
        self.__seq, self.__i, self.__current = list(it), 0, None
45
46
    @property
47
    def seq(self) -> Sequence[T]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
48
        return self.__seq
49
50
    def reset(self) -> None:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
51
        self.__i, self.__current = 0, None
52
53
    def peek(self) -> T:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
54
        return self.__seq[self.__i]
55
56
    def position(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
57
        return self.__i
58
59
    def total(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
60
        return len(self.__seq)
61
62
    def __next__(self) -> T:
63
        try:
64
            self.current = self.__seq[self.__i]
0 ignored issues
show
Coding Style introduced by
The attribute current was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
65
        except IndexError:
66
            raise StopIteration(f"Size is {len(self)}")
67
        self.__i += 1
68
        return self.current
69
70
71
class TieredIterator(SeqIterator[Tuple[IX]]):
72
    """
73
    A SizedIterator that iterates over every tuples of combination from multiple sequences.
74
75
    Example:
76
        >>> it = TieredIterator([[1, 2, 3], [5, 6]])
77
        >>> list(it)
78
        [(1,5), (1,6), (2,5), (2,6), (3,5), (3,6)]
79
    """
80
81
    # noinspection PyMissingConstructor
82
    def __init__(self, sequence: Sequence[Sequence[IX]]):
83
        self.__seqs = list([SeqIterator(s) for s in reversed(sequence)])
84
        self.__total = 0 if len(self.seqs) == 0 else int(np.product([i.total() for i in self.seqs]))
85
        self.__i = 0
86
87
    @property
88
    def seqs(self) -> Sequence[SeqIterator[IX]]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
89
        return self.__seqs
90
91
    def position(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
92
        return self.__i
93
94
    def total(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
95
        return self.__total
96
97
    def __next__(self) -> Tuple[IX]:
98
        if not self.has_next():
99
            raise StopIteration(f"Length is {self.total()}")
100
        t = tuple((seq.peek() for seq in reversed(self.seqs)))
0 ignored issues
show
Coding Style Naming introduced by
Variable name "t" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Comprehensibility Best Practice introduced by
The variable seq does not seem to be defined.
Loading history...
101
        self.__set(0)
102
        self.__i += 1
103
        return t
104
105
    def __set(self, i: int):
106
        seq = self.seqs[i]
107
        if seq.remaining() > 1:
108
            next(seq)
109
        else:
110
            seq.reset()
111
            # to avoid index error for last case, after which self.has_next() is False
112
            if i < len(self.seqs) - 1:
113
                self.__set(i + 1)  # recurse
114
115
    def __repr__(self):
116
        sizes = ", ".join([f"{it.current}/{it.total()}" for it in self.seqs])
117
        return f"Iter({sizes})"
118
119
    def __str__(self):
120
        return repr(self)
121
122
123
__all__ = ["SizedIterator", "SeqIterator", "TieredIterator"]
124