-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Tuple classes to pycommons-lang (#20)
* Add Tuple classes to pycommons-lang * Add Unittests - Pair and Triple * Fix code format
- Loading branch information
1 parent
833601f
commit 85cfecc
Showing
6 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from .pair import Pair, ImmutablePair, MutablePair | ||
from .triple import Triple, ImmutableTriple, MutableTriple | ||
|
||
__all__ = ["Pair", "ImmutablePair", "MutablePair", "Triple", "ImmutableTriple", "MutableTriple"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
from __future__ import annotations | ||
|
||
import typing | ||
from abc import ABC, abstractmethod | ||
from collections import UserList | ||
from typing import TypeVar, Generic, Union, Any | ||
|
||
_L = TypeVar("_L") | ||
_R = TypeVar("_R") | ||
|
||
|
||
class Pair(ABC, Generic[_L, _R]): | ||
@classmethod | ||
def of(cls, left: _L, right: _R) -> ImmutablePair[_L, _R]: | ||
return ImmutablePair(left, right) | ||
|
||
@property | ||
def left(self) -> _L: | ||
return typing.cast(_L, self[0]) | ||
|
||
@property | ||
def right(self) -> _R: | ||
return typing.cast(_R, self[1]) | ||
|
||
@property | ||
def key(self) -> _L: | ||
return self.left | ||
|
||
@property | ||
def value(self) -> _R: | ||
return self.right | ||
|
||
def get_left(self) -> _L: | ||
return self.left | ||
|
||
def get_right(self) -> _R: | ||
return self.right | ||
|
||
def get_key(self) -> _L: | ||
return self.left | ||
|
||
def get_value(self) -> _R: | ||
return self.right | ||
|
||
@abstractmethod | ||
def __getitem__(self, item: Any) -> Any: | ||
... # pragma: no cover | ||
|
||
def __str__(self) -> str: | ||
return self.to_string("({0}, {1})") | ||
|
||
def to_string(self, fmt: str) -> str: | ||
return fmt.format(self.left, self.right) | ||
|
||
|
||
class ImmutablePair(tuple, Pair[_L, _R], Generic[_L, _R]): # type: ignore | ||
def __getitem__(self, item: Any) -> Any: | ||
return typing.cast(Union[_L, _R], tuple.__getitem__(self, item)) | ||
|
||
def __new__(cls, left: _L, right: _R) -> ImmutablePair[_L, _R]: | ||
return super().__new__(cls, [left, right]) # type: ignore | ||
|
||
|
||
class MutablePair(UserList, Pair, Generic[_L, _R]): # type: ignore | ||
def __getitem__(self, item: Any) -> Any: | ||
return typing.cast(Union[_L, _R], UserList.__getitem__(self, item)) | ||
|
||
def __init__(self, left: _L, right: _R) -> None: | ||
super().__init__([left, right]) | ||
|
||
@property | ||
def left(self) -> _L: | ||
return typing.cast(_L, super().left) | ||
|
||
@left.setter | ||
def left(self, left: _L) -> None: | ||
self[0] = left | ||
|
||
@property | ||
def right(self) -> _R: | ||
return typing.cast(_R, super().right) | ||
|
||
@right.setter | ||
def right(self, right: _R) -> None: | ||
self[1] = right | ||
|
||
def set_left(self, key: _L) -> None: | ||
self.left = key | ||
|
||
def set_right(self, value: _R) -> None: | ||
self.right = value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
from __future__ import annotations | ||
|
||
import typing | ||
from abc import ABC, abstractmethod | ||
from collections import UserList | ||
from typing import TypeVar, Generic, Union, Tuple, Any | ||
|
||
_L = TypeVar("_L") | ||
_M = TypeVar("_M") | ||
_R = TypeVar("_R") | ||
|
||
|
||
class Triple(ABC, Generic[_L, _M, _R]): | ||
@classmethod | ||
def of(cls, left: _L, middle: _M, right: _R) -> ImmutableTriple[_L, _M, _R]: | ||
return ImmutableTriple(left, middle, right) | ||
|
||
@property | ||
def left(self) -> _L: | ||
return typing.cast(_L, self[0]) | ||
|
||
@property | ||
def middle(self) -> _M: | ||
return typing.cast(_M, self[1]) | ||
|
||
@property | ||
def right(self) -> _R: | ||
return typing.cast(_R, self[2]) | ||
|
||
def get_left(self) -> _L: | ||
return self.left | ||
|
||
def get_middle(self) -> _M: | ||
return self.middle | ||
|
||
def get_right(self) -> _R: | ||
return self.right | ||
|
||
@abstractmethod | ||
def __getitem__(self, item: Any) -> Any: # pragma: no cover | ||
... | ||
|
||
def __str__(self) -> str: | ||
return self.to_string("({0}, {1}, {2})") | ||
|
||
def to_string(self, fmt: str) -> str: | ||
return fmt.format(self.left, self.middle, self.right) | ||
|
||
|
||
class ImmutableTriple(Tuple, Triple[_L, _M, _R], Generic[_L, _M, _R]): # type: ignore | ||
def __getitem__(self, item: Any) -> Any: | ||
return typing.cast(Union[_L, _M, _R], tuple.__getitem__(self, item)) | ||
|
||
def __new__(cls, left: _L, middle: _M, right: _R) -> ImmutableTriple[_L, _M, _R]: | ||
return super().__new__(cls, [left, middle, right]) # type: ignore | ||
|
||
|
||
class MutableTriple(UserList, Triple[_L, _M, _R], Generic[_L, _M, _R]): # type: ignore | ||
def __getitem__(self, item: Any) -> Any: | ||
return typing.cast(Union[_L, _M, _R], UserList.__getitem__(self, item)) | ||
|
||
def __init__(self, left: _L, middle: _M, right: _R) -> None: | ||
super().__init__([left, middle, right]) | ||
|
||
@property | ||
def left(self) -> _L: | ||
return super().left | ||
|
||
@left.setter | ||
def left(self, left: _L) -> None: | ||
self[0] = left | ||
|
||
@property | ||
def middle(self) -> _M: | ||
return super().middle | ||
|
||
@middle.setter | ||
def middle(self, middle: _M) -> None: | ||
self[1] = middle | ||
|
||
@property | ||
def right(self) -> _R: | ||
return super().right | ||
|
||
@right.setter | ||
def right(self, right: _R) -> None: | ||
self[2] = right | ||
|
||
def set_left(self, left: _L) -> None: | ||
self.left = left | ||
|
||
def set_middle(self, middle: _M) -> None: | ||
self.middle = middle | ||
|
||
def set_right(self, right: _R) -> None: | ||
self.right = right |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from unittest import TestCase | ||
|
||
from pycommons.lang.tuple import Pair, MutablePair | ||
|
||
|
||
class TestImmutablePair(TestCase): | ||
def test_pair_methods(self): | ||
pair: Pair[int, int] = Pair.of(1, 6) | ||
self.assertEqual(1, pair.left) | ||
self.assertEqual(1, pair.get_left()) | ||
self.assertEqual(1, pair.get_key()) | ||
|
||
self.assertEqual(6, pair.right) | ||
self.assertEqual(6, pair.get_right()) | ||
self.assertEqual(6, pair.get_value()) | ||
|
||
self.assertEqual("(1, 6)", str(pair)) | ||
self.assertEqual("[1, 6]", pair.to_string("[{0}, {1}]")) | ||
|
||
|
||
class TestMutablePair(TestCase): | ||
def test_pair_methods(self): | ||
pair: MutablePair[int, int] = MutablePair(1, 6) | ||
self.assertEqual(1, pair.left) | ||
self.assertEqual(1, pair.get_left()) | ||
self.assertEqual(1, pair.key) | ||
self.assertEqual(1, pair.get_key()) | ||
|
||
self.assertEqual(6, pair.right) | ||
self.assertEqual(6, pair.get_right()) | ||
self.assertEqual(6, pair.value) | ||
self.assertEqual(6, pair.get_value()) | ||
|
||
self.assertEqual("(1, 6)", str(pair)) | ||
self.assertEqual("[1, 6]", pair.to_string("[{0}, {1}]")) | ||
|
||
pair.left = 2 | ||
self.assertEqual(2, pair.left) | ||
|
||
pair.right = 7 | ||
self.assertEqual(7, pair.right) | ||
|
||
pair.set_left(3) | ||
self.assertEqual(3, pair.left) | ||
|
||
pair.set_right(8) | ||
self.assertEqual(8, pair.right) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
from unittest import TestCase | ||
|
||
from pycommons.lang.tuple import Triple, MutableTriple | ||
|
||
|
||
class TestImmutableTriple(TestCase): | ||
def test_triple_methods(self): | ||
pair: Triple[int, int] = Triple.of(1, 5, 6) | ||
self.assertEqual(1, pair.left) | ||
self.assertEqual(1, pair.get_left()) | ||
|
||
self.assertEqual(5, pair.middle) | ||
self.assertEqual(5, pair.get_middle()) | ||
|
||
self.assertEqual(6, pair.right) | ||
self.assertEqual(6, pair.get_right()) | ||
|
||
self.assertEqual("(1, 5, 6)", str(pair)) | ||
self.assertEqual("[1, 5, 6]", pair.to_string("[{0}, {1}, {2}]")) | ||
|
||
|
||
class TestMutableTriple(TestCase): | ||
def test_triple_methods(self): | ||
pair: MutableTriple[int, int] = MutableTriple(1, 5, 6) | ||
self.assertEqual(1, pair.left) | ||
self.assertEqual(1, pair.get_left()) | ||
|
||
self.assertEqual(5, pair.middle) | ||
self.assertEqual(5, pair.get_middle()) | ||
|
||
self.assertEqual(6, pair.right) | ||
self.assertEqual(6, pair.get_right()) | ||
|
||
self.assertEqual("(1, 5, 6)", str(pair)) | ||
self.assertEqual("[1, 5, 6]", pair.to_string("[{0}, {1}, {2}]")) | ||
|
||
pair.left = 2 | ||
self.assertEqual(2, pair.left) | ||
|
||
pair.middle = 3 | ||
self.assertEqual(3, pair.middle) | ||
|
||
pair.right = 7 | ||
self.assertEqual(7, pair.right) | ||
|
||
pair.set_left(3) | ||
self.assertEqual(3, pair.left) | ||
|
||
pair.set_middle(0) | ||
self.assertEqual(0, pair.middle) | ||
|
||
pair.set_right(8) | ||
self.assertEqual(8, pair.right) |