Skip to content

Commit

Permalink
Add Tuple classes to pycommons-lang (#20)
Browse files Browse the repository at this point in the history
* Add Tuple classes to pycommons-lang

* Add Unittests - Pair and Triple

* Fix code format
  • Loading branch information
shashankrnr32 authored Jul 13, 2023
1 parent 833601f commit 85cfecc
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 0 deletions.
4 changes: 4 additions & 0 deletions pycommons/lang/tuple/__init__.py
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"]
91 changes: 91 additions & 0 deletions pycommons/lang/tuple/pair.py
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
96 changes: 96 additions & 0 deletions pycommons/lang/tuple/triple.py
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.
47 changes: 47 additions & 0 deletions tests/pycommons/lang/tuple/test_pair.py
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)
53 changes: 53 additions & 0 deletions tests/pycommons/lang/tuple/test_triple.py
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)

0 comments on commit 85cfecc

Please sign in to comment.