def test_range_attributes() -> None: a = Array("1234", Range(10, "downto", 7)) assert a.range == Range(10, "downto", 7) assert a.left == 10 assert a.right == 7 assert a.direction == "downto" assert len(a) == 4
def test_array_construct() -> None: Array("1234") Array([1, 2, 3, 4]) with pytest.raises(TypeError): Array(object()) # type: ignore Array("1234", Range(1, "to", 4)) with pytest.raises(TypeError): Array("1234", object()) # type:ignore with pytest.raises(TypeError): Array(range=Range(0, "to", 1)) # type:ignore with pytest.raises(ValueError): Array("1234", Range(0, "to", 100))
def test_null_range() -> None: r = Range(1, "downto", 4) assert r.left == 1 assert r.direction == "downto" assert r.right == 4 assert len(r) == 0 assert list(r) == [] assert list(reversed(r)) == [] with pytest.raises(IndexError): r[0] assert 2 not in r with pytest.raises(ValueError): r.index(4) assert r.count(4) == 0
def __setitem__( self, item: Union[int, slice], value: Union[T, Iterable[T]] ) -> None: if isinstance(item, int): self._value[self._index(item)] = cast(T, value) elif isinstance(item, slice): if item.step is not None: raise IndexError("do not specify the step in the index") left = item.start if item.start is not None else self.left right = item.stop if item.stop is not None else self.right range = Range(left, self.direction, right) value = tuple(cast(Iterable[T], value)) if len(range) == 0: raise IndexError( f"slice '[{left}:{right}]' direction does not match array direction {self.direction!r}" ) if len(value) != len(range): raise ValueError( f"cannot fit value of length {len(value)} in slice [{left}:{right}]" ) left_idx = self._index(left) right_idx = self._index(right) self._value[left_idx : right_idx + 1] = value else: raise TypeError( f"expected index to be of type int or slice, not {type(item).__qualname__}" )
def test_conversions() -> None: t = range(10, 1, -1) r = Range.from_range(t) assert r.left == 10 assert r.right == 2 assert r.direction == "downto" assert r.to_range() == t
def test_indexing() -> None: a = Array("abcdef", Range(100, "to", 105)) assert a[101] == "b" b = a[104:] assert b == Array("ef") assert b.range == Range(104, "to", 105) b = a[:103] assert b == Array("abcd") assert b.range == Range(100, "to", 103) with pytest.raises(IndexError): a[1000] with pytest.raises(TypeError): a[0.1] # type: ignore with pytest.raises(IndexError): a[100:103:2] with pytest.raises(IndexError): a[103:100]
def __init__(self, value: Iterable[T_co], range: Optional[Range] = None) -> None: self._value = list(value) if range is None: self._range = Range(0, "to", len(self._value) - 1) else: self._range = range if len(self._value) != len(self._range): raise ValueError( f"value of length {len(self._value)} does not fit in {self._range!r}" )
def test_downto_range() -> None: r = Range(4, "downto", -3) assert r.left == 4 assert r.direction == "downto" assert r.right == -3 assert len(r) == 8 assert list(r) == [4, 3, 2, 1, 0, -1, -2, -3] assert list(reversed(r)) == [-3, -2, -1, 0, 1, 2, 3, 4] assert r[0] == 4 assert r[7] == -3 with pytest.raises(IndexError): r[8] assert r[3:7] == Range(1, "downto", -2) assert 0 in r assert 10 not in r assert r.index(2) == 2 with pytest.raises(ValueError): r.index(9) assert r.count(4) == 1 assert r.count(10) == 0
def test_to_range() -> None: r = Range(1, "to", 8) assert r.left == 1 assert r.direction == "to" assert r.right == 8 assert len(r) == 8 assert list(r) == [1, 2, 3, 4, 5, 6, 7, 8] assert list(reversed(r)) == [8, 7, 6, 5, 4, 3, 2, 1] assert r[0] == 1 assert r[7] == 8 with pytest.raises(IndexError): r[8] assert r[3:7] == Range(4, "to", 7) assert 8 in r assert 10 not in r assert r.index(7) == 6 with pytest.raises(ValueError): r.index(9) assert r.count(4) == 1 assert r.count(10) == 0
def __getitem__(self: Self, item: Union[int, slice]) -> Union[T_co, Self]: if isinstance(item, int): return cast(T_co, self._value[self._index(item)]) elif isinstance(item, slice): if item.step is not None: raise IndexError("do not specify the step in the index") left = item.start if item.start is not None else self.left right = item.stop if item.stop is not None else self.right range = Range(left, self.direction, right) if len(range) == 0: raise IndexError( f"slice '[{left}:{right}]' direction does not match array direction {self.direction!r}" ) left_idx = self._index(left) right_idx = self._index(right) return type(self)( value=self._value[left_idx : right_idx + 1], range=range, ) else: raise TypeError( f"expected index to be of type int or slice, not {type(item).__qualname__}" )
def test_bad_direction() -> None: with pytest.raises(ValueError): Range(1, "nope", 8)
def test_repr() -> None: r = Range(5, "to", 9) assert eval(repr(r)) == r
def test_bad_step() -> None: with pytest.raises(ValueError): Range.from_range(range(10, 5, -2))
def test_bad_bound() -> None: with pytest.raises(TypeError): Range(object(), "to", 8) # type: ignore
def test_equality() -> None: assert Array("1234") == Array("1234", Range(100, "to", 103)) assert Array("1234") != 1 assert 1 != Array("1234")
def test_bad_getitem() -> None: with pytest.raises(TypeError): Range(10, "downto", 4)["8"] # type: ignore
def test_bad_arguments() -> None: with pytest.raises(TypeError): Range(1, "to") # type: ignore
def test_equality() -> None: assert Range(7, "downto", -7) == Range(7, "downto", -7) assert Range(7, "downto", -7) != Range(0, "to", 8) assert Range(1, "to", 0) == Range(8, "to", -8) # null ranges are all equal? assert Range(1, "to", 4) != 789
def test_use_in_set() -> None: assert len({Range(1, "to", 8), Range(1, "to", 8)}) == 1 assert len({Range(1, "to", 8), Range(8, "downto", 1)}) == 2
def test_other_constructors() -> None: assert Range(1, 8) == Range(1, "to", 8) assert Range(3, -4) == Range(3, "downto", -4) assert Range(left=1, right=8) == Range(1, "to", 8) assert Range(left=3, right=-4) == Range(3, "downto", -4)
def test_uppercase_in_direction() -> None: r = Range(1, "TO", 8) assert r.direction == "to"