mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-23 21:11:08 +00:00
Ruff pandas vet (#10281)
* Python linting: Add ruff rules for Pandas-vet and Pytest-style * updating DIRECTORY.md --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
This commit is contained in:
parent
d5323dbaee
commit
3f094fe49d
|
@ -51,7 +51,7 @@ repos:
|
||||||
- id: validate-pyproject
|
- id: validate-pyproject
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.5.1
|
rev: v1.6.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
args:
|
args:
|
||||||
|
|
|
@ -532,6 +532,7 @@
|
||||||
* [Logistic Regression](machine_learning/logistic_regression.py)
|
* [Logistic Regression](machine_learning/logistic_regression.py)
|
||||||
* Loss Functions
|
* Loss Functions
|
||||||
* [Binary Cross Entropy](machine_learning/loss_functions/binary_cross_entropy.py)
|
* [Binary Cross Entropy](machine_learning/loss_functions/binary_cross_entropy.py)
|
||||||
|
* [Categorical Cross Entropy](machine_learning/loss_functions/categorical_cross_entropy.py)
|
||||||
* [Huber Loss](machine_learning/loss_functions/huber_loss.py)
|
* [Huber Loss](machine_learning/loss_functions/huber_loss.py)
|
||||||
* [Mean Squared Error](machine_learning/loss_functions/mean_squared_error.py)
|
* [Mean Squared Error](machine_learning/loss_functions/mean_squared_error.py)
|
||||||
* [Mfcc](machine_learning/mfcc.py)
|
* [Mfcc](machine_learning/mfcc.py)
|
||||||
|
|
|
@ -83,7 +83,8 @@ def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
|
||||||
(1, -2, 3)
|
(1, -2, 3)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
assert a >= 0 and b >= 0
|
assert a >= 0
|
||||||
|
assert b >= 0
|
||||||
|
|
||||||
if b == 0:
|
if b == 0:
|
||||||
d, x, y = a, 1, 0
|
d, x, y = a, 1, 0
|
||||||
|
@ -92,7 +93,8 @@ def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
|
||||||
x = q
|
x = q
|
||||||
y = p - q * (a // b)
|
y = p - q * (a // b)
|
||||||
|
|
||||||
assert a % d == 0 and b % d == 0
|
assert a % d == 0
|
||||||
|
assert b % d == 0
|
||||||
assert d == a * x + b * y
|
assert d == a * x + b * y
|
||||||
|
|
||||||
return (d, x, y)
|
return (d, x, y)
|
||||||
|
|
|
@ -38,7 +38,8 @@ class XORCipher:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# precondition
|
# precondition
|
||||||
assert isinstance(key, int) and isinstance(content, str)
|
assert isinstance(key, int)
|
||||||
|
assert isinstance(content, str)
|
||||||
|
|
||||||
key = key or self.__key or 1
|
key = key or self.__key or 1
|
||||||
|
|
||||||
|
@ -56,7 +57,8 @@ class XORCipher:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# precondition
|
# precondition
|
||||||
assert isinstance(key, int) and isinstance(content, list)
|
assert isinstance(key, int)
|
||||||
|
assert isinstance(content, list)
|
||||||
|
|
||||||
key = key or self.__key or 1
|
key = key or self.__key or 1
|
||||||
|
|
||||||
|
@ -74,7 +76,8 @@ class XORCipher:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# precondition
|
# precondition
|
||||||
assert isinstance(key, int) and isinstance(content, str)
|
assert isinstance(key, int)
|
||||||
|
assert isinstance(content, str)
|
||||||
|
|
||||||
key = key or self.__key or 1
|
key = key or self.__key or 1
|
||||||
|
|
||||||
|
@ -99,7 +102,8 @@ class XORCipher:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# precondition
|
# precondition
|
||||||
assert isinstance(key, int) and isinstance(content, str)
|
assert isinstance(key, int)
|
||||||
|
assert isinstance(content, str)
|
||||||
|
|
||||||
key = key or self.__key or 1
|
key = key or self.__key or 1
|
||||||
|
|
||||||
|
@ -125,7 +129,8 @@ class XORCipher:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# precondition
|
# precondition
|
||||||
assert isinstance(file, str) and isinstance(key, int)
|
assert isinstance(file, str)
|
||||||
|
assert isinstance(key, int)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(file) as fin, open("encrypt.out", "w+") as fout:
|
with open(file) as fin, open("encrypt.out", "w+") as fout:
|
||||||
|
@ -148,7 +153,8 @@ class XORCipher:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# precondition
|
# precondition
|
||||||
assert isinstance(file, str) and isinstance(key, int)
|
assert isinstance(file, str)
|
||||||
|
assert isinstance(key, int)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(file) as fin, open("decrypt.out", "w+") as fout:
|
with open(file) as fin, open("decrypt.out", "w+") as fout:
|
||||||
|
|
|
@ -57,7 +57,8 @@ def decimal_to_hexadecimal(decimal: float) -> str:
|
||||||
>>> decimal_to_hexadecimal(-256) == hex(-256)
|
>>> decimal_to_hexadecimal(-256) == hex(-256)
|
||||||
True
|
True
|
||||||
"""
|
"""
|
||||||
assert type(decimal) in (int, float) and decimal == int(decimal)
|
assert isinstance(decimal, (int, float))
|
||||||
|
assert decimal == int(decimal)
|
||||||
decimal = int(decimal)
|
decimal = int(decimal)
|
||||||
hexadecimal = ""
|
hexadecimal = ""
|
||||||
negative = False
|
negative = False
|
||||||
|
|
|
@ -12,6 +12,8 @@ from __future__ import annotations
|
||||||
import unittest
|
import unittest
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterator
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
def __init__(self, label: int, parent: Node | None) -> None:
|
def __init__(self, label: int, parent: Node | None) -> None:
|
||||||
|
@ -78,7 +80,7 @@ class BinarySearchTree:
|
||||||
node.right = self._put(node.right, label, node)
|
node.right = self._put(node.right, label, node)
|
||||||
else:
|
else:
|
||||||
msg = f"Node with label {label} already exists"
|
msg = f"Node with label {label} already exists"
|
||||||
raise Exception(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
@ -95,14 +97,14 @@ class BinarySearchTree:
|
||||||
>>> node = t.search(3)
|
>>> node = t.search(3)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: Node with label 3 does not exist
|
ValueError: Node with label 3 does not exist
|
||||||
"""
|
"""
|
||||||
return self._search(self.root, label)
|
return self._search(self.root, label)
|
||||||
|
|
||||||
def _search(self, node: Node | None, label: int) -> Node:
|
def _search(self, node: Node | None, label: int) -> Node:
|
||||||
if node is None:
|
if node is None:
|
||||||
msg = f"Node with label {label} does not exist"
|
msg = f"Node with label {label} does not exist"
|
||||||
raise Exception(msg)
|
raise ValueError(msg)
|
||||||
else:
|
else:
|
||||||
if label < node.label:
|
if label < node.label:
|
||||||
node = self._search(node.left, label)
|
node = self._search(node.left, label)
|
||||||
|
@ -124,7 +126,7 @@ class BinarySearchTree:
|
||||||
>>> t.remove(3)
|
>>> t.remove(3)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: Node with label 3 does not exist
|
ValueError: Node with label 3 does not exist
|
||||||
"""
|
"""
|
||||||
node = self.search(label)
|
node = self.search(label)
|
||||||
if node.right and node.left:
|
if node.right and node.left:
|
||||||
|
@ -179,7 +181,7 @@ class BinarySearchTree:
|
||||||
try:
|
try:
|
||||||
self.search(label)
|
self.search(label)
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_max_label(self) -> int:
|
def get_max_label(self) -> int:
|
||||||
|
@ -190,7 +192,7 @@ class BinarySearchTree:
|
||||||
>>> t.get_max_label()
|
>>> t.get_max_label()
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: Binary search tree is empty
|
ValueError: Binary search tree is empty
|
||||||
|
|
||||||
>>> t.put(8)
|
>>> t.put(8)
|
||||||
>>> t.put(10)
|
>>> t.put(10)
|
||||||
|
@ -198,7 +200,7 @@ class BinarySearchTree:
|
||||||
10
|
10
|
||||||
"""
|
"""
|
||||||
if self.root is None:
|
if self.root is None:
|
||||||
raise Exception("Binary search tree is empty")
|
raise ValueError("Binary search tree is empty")
|
||||||
|
|
||||||
node = self.root
|
node = self.root
|
||||||
while node.right is not None:
|
while node.right is not None:
|
||||||
|
@ -214,7 +216,7 @@ class BinarySearchTree:
|
||||||
>>> t.get_min_label()
|
>>> t.get_min_label()
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Exception: Binary search tree is empty
|
ValueError: Binary search tree is empty
|
||||||
|
|
||||||
>>> t.put(8)
|
>>> t.put(8)
|
||||||
>>> t.put(10)
|
>>> t.put(10)
|
||||||
|
@ -222,7 +224,7 @@ class BinarySearchTree:
|
||||||
8
|
8
|
||||||
"""
|
"""
|
||||||
if self.root is None:
|
if self.root is None:
|
||||||
raise Exception("Binary search tree is empty")
|
raise ValueError("Binary search tree is empty")
|
||||||
|
|
||||||
node = self.root
|
node = self.root
|
||||||
while node.left is not None:
|
while node.left is not None:
|
||||||
|
@ -359,7 +361,7 @@ class BinarySearchTreeTest(unittest.TestCase):
|
||||||
assert t.root.left.left.parent == t.root.left
|
assert t.root.left.left.parent == t.root.left
|
||||||
assert t.root.left.left.label == 1
|
assert t.root.left.left.label == 1
|
||||||
|
|
||||||
with self.assertRaises(Exception): # noqa: B017
|
with pytest.raises(ValueError):
|
||||||
t.put(1)
|
t.put(1)
|
||||||
|
|
||||||
def test_search(self) -> None:
|
def test_search(self) -> None:
|
||||||
|
@ -371,7 +373,7 @@ class BinarySearchTreeTest(unittest.TestCase):
|
||||||
node = t.search(13)
|
node = t.search(13)
|
||||||
assert node.label == 13
|
assert node.label == 13
|
||||||
|
|
||||||
with self.assertRaises(Exception): # noqa: B017
|
with pytest.raises(ValueError):
|
||||||
t.search(2)
|
t.search(2)
|
||||||
|
|
||||||
def test_remove(self) -> None:
|
def test_remove(self) -> None:
|
||||||
|
@ -517,7 +519,7 @@ class BinarySearchTreeTest(unittest.TestCase):
|
||||||
assert t.get_max_label() == 14
|
assert t.get_max_label() == 14
|
||||||
|
|
||||||
t.empty()
|
t.empty()
|
||||||
with self.assertRaises(Exception): # noqa: B017
|
with pytest.raises(ValueError):
|
||||||
t.get_max_label()
|
t.get_max_label()
|
||||||
|
|
||||||
def test_get_min_label(self) -> None:
|
def test_get_min_label(self) -> None:
|
||||||
|
@ -526,7 +528,7 @@ class BinarySearchTreeTest(unittest.TestCase):
|
||||||
assert t.get_min_label() == 1
|
assert t.get_min_label() == 1
|
||||||
|
|
||||||
t.empty()
|
t.empty()
|
||||||
with self.assertRaises(Exception): # noqa: B017
|
with pytest.raises(ValueError):
|
||||||
t.get_min_label()
|
t.get_min_label()
|
||||||
|
|
||||||
def test_inorder_traversal(self) -> None:
|
def test_inorder_traversal(self) -> None:
|
||||||
|
|
|
@ -65,14 +65,14 @@ _add_with_resize_down = [
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"operations",
|
"operations",
|
||||||
(
|
[
|
||||||
pytest.param(_add_items, id="add items"),
|
pytest.param(_add_items, id="add items"),
|
||||||
pytest.param(_overwrite_items, id="overwrite items"),
|
pytest.param(_overwrite_items, id="overwrite items"),
|
||||||
pytest.param(_delete_items, id="delete items"),
|
pytest.param(_delete_items, id="delete items"),
|
||||||
pytest.param(_access_absent_items, id="access absent items"),
|
pytest.param(_access_absent_items, id="access absent items"),
|
||||||
pytest.param(_add_with_resize_up, id="add with resize up"),
|
pytest.param(_add_with_resize_up, id="add with resize up"),
|
||||||
pytest.param(_add_with_resize_down, id="add with resize down"),
|
pytest.param(_add_with_resize_down, id="add with resize down"),
|
||||||
),
|
],
|
||||||
)
|
)
|
||||||
def test_hash_map_is_the_same_as_dict(operations):
|
def test_hash_map_is_the_same_as_dict(operations):
|
||||||
my = HashMap(initial_block_size=4)
|
my = HashMap(initial_block_size=4)
|
||||||
|
|
|
@ -124,7 +124,8 @@ class CircularLinkedList:
|
||||||
if not 0 <= index < len(self):
|
if not 0 <= index < len(self):
|
||||||
raise IndexError("list index out of range.")
|
raise IndexError("list index out of range.")
|
||||||
|
|
||||||
assert self.head is not None and self.tail is not None
|
assert self.head is not None
|
||||||
|
assert self.tail is not None
|
||||||
delete_node: Node = self.head
|
delete_node: Node = self.head
|
||||||
if self.head == self.tail: # Just one node
|
if self.head == self.tail: # Just one node
|
||||||
self.head = self.tail = None
|
self.head = self.tail = None
|
||||||
|
@ -137,7 +138,8 @@ class CircularLinkedList:
|
||||||
for _ in range(index - 1):
|
for _ in range(index - 1):
|
||||||
assert temp is not None
|
assert temp is not None
|
||||||
temp = temp.next
|
temp = temp.next
|
||||||
assert temp is not None and temp.next is not None
|
assert temp is not None
|
||||||
|
assert temp.next is not None
|
||||||
delete_node = temp.next
|
delete_node = temp.next
|
||||||
temp.next = temp.next.next
|
temp.next = temp.next.next
|
||||||
if index == len(self) - 1: # Delete at tail
|
if index == len(self) - 1: # Delete at tail
|
||||||
|
|
|
@ -73,7 +73,8 @@ def test_median_filter():
|
||||||
|
|
||||||
def test_sobel_filter():
|
def test_sobel_filter():
|
||||||
grad, theta = sob.sobel_filter(gray)
|
grad, theta = sob.sobel_filter(gray)
|
||||||
assert grad.any() and theta.any()
|
assert grad.any()
|
||||||
|
assert theta.any()
|
||||||
|
|
||||||
|
|
||||||
def test_sepia():
|
def test_sepia():
|
||||||
|
|
|
@ -22,6 +22,8 @@ import unittest
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from typing import Generic, TypeVar
|
from typing import Generic, TypeVar
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,9 +187,9 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyList,
|
directed_graph: GraphAdjacencyList,
|
||||||
edge: list[int],
|
edge: list[int],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertTrue(undirected_graph.contains_edge(edge[0], edge[1]))
|
assert undirected_graph.contains_edge(edge[0], edge[1])
|
||||||
self.assertTrue(undirected_graph.contains_edge(edge[1], edge[0]))
|
assert undirected_graph.contains_edge(edge[1], edge[0])
|
||||||
self.assertTrue(directed_graph.contains_edge(edge[0], edge[1]))
|
assert directed_graph.contains_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def __assert_graph_edge_does_not_exist_check(
|
def __assert_graph_edge_does_not_exist_check(
|
||||||
self,
|
self,
|
||||||
|
@ -195,9 +197,9 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyList,
|
directed_graph: GraphAdjacencyList,
|
||||||
edge: list[int],
|
edge: list[int],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertFalse(undirected_graph.contains_edge(edge[0], edge[1]))
|
assert not undirected_graph.contains_edge(edge[0], edge[1])
|
||||||
self.assertFalse(undirected_graph.contains_edge(edge[1], edge[0]))
|
assert not undirected_graph.contains_edge(edge[1], edge[0])
|
||||||
self.assertFalse(directed_graph.contains_edge(edge[0], edge[1]))
|
assert not directed_graph.contains_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def __assert_graph_vertex_exists_check(
|
def __assert_graph_vertex_exists_check(
|
||||||
self,
|
self,
|
||||||
|
@ -205,8 +207,8 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyList,
|
directed_graph: GraphAdjacencyList,
|
||||||
vertex: int,
|
vertex: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertTrue(undirected_graph.contains_vertex(vertex))
|
assert undirected_graph.contains_vertex(vertex)
|
||||||
self.assertTrue(directed_graph.contains_vertex(vertex))
|
assert directed_graph.contains_vertex(vertex)
|
||||||
|
|
||||||
def __assert_graph_vertex_does_not_exist_check(
|
def __assert_graph_vertex_does_not_exist_check(
|
||||||
self,
|
self,
|
||||||
|
@ -214,13 +216,13 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyList,
|
directed_graph: GraphAdjacencyList,
|
||||||
vertex: int,
|
vertex: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertFalse(undirected_graph.contains_vertex(vertex))
|
assert not undirected_graph.contains_vertex(vertex)
|
||||||
self.assertFalse(directed_graph.contains_vertex(vertex))
|
assert not directed_graph.contains_vertex(vertex)
|
||||||
|
|
||||||
def __generate_random_edges(
|
def __generate_random_edges(
|
||||||
self, vertices: list[int], edge_pick_count: int
|
self, vertices: list[int], edge_pick_count: int
|
||||||
) -> list[list[int]]:
|
) -> list[list[int]]:
|
||||||
self.assertTrue(edge_pick_count <= len(vertices))
|
assert edge_pick_count <= len(vertices)
|
||||||
|
|
||||||
random_source_vertices: list[int] = random.sample(
|
random_source_vertices: list[int] = random.sample(
|
||||||
vertices[0 : int(len(vertices) / 2)], edge_pick_count
|
vertices[0 : int(len(vertices) / 2)], edge_pick_count
|
||||||
|
@ -281,8 +283,8 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
self.__assert_graph_edge_exists_check(
|
self.__assert_graph_edge_exists_check(
|
||||||
undirected_graph, directed_graph, edge
|
undirected_graph, directed_graph, edge
|
||||||
)
|
)
|
||||||
self.assertFalse(undirected_graph.directed)
|
assert not undirected_graph.directed
|
||||||
self.assertTrue(directed_graph.directed)
|
assert directed_graph.directed
|
||||||
|
|
||||||
def test_contains_vertex(self) -> None:
|
def test_contains_vertex(self) -> None:
|
||||||
random_vertices: list[int] = random.sample(range(101), 20)
|
random_vertices: list[int] = random.sample(range(101), 20)
|
||||||
|
@ -297,12 +299,8 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
|
|
||||||
# Test contains_vertex
|
# Test contains_vertex
|
||||||
for num in range(101):
|
for num in range(101):
|
||||||
self.assertEqual(
|
assert (num in random_vertices) == undirected_graph.contains_vertex(num)
|
||||||
num in random_vertices, undirected_graph.contains_vertex(num)
|
assert (num in random_vertices) == directed_graph.contains_vertex(num)
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
num in random_vertices, directed_graph.contains_vertex(num)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_add_vertices(self) -> None:
|
def test_add_vertices(self) -> None:
|
||||||
random_vertices: list[int] = random.sample(range(101), 20)
|
random_vertices: list[int] = random.sample(range(101), 20)
|
||||||
|
@ -507,9 +505,9 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
) = self.__generate_graphs(20, 0, 100, 4)
|
) = self.__generate_graphs(20, 0, 100, 4)
|
||||||
|
|
||||||
for vertex in random_vertices:
|
for vertex in random_vertices:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.add_vertex(vertex)
|
undirected_graph.add_vertex(vertex)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.add_vertex(vertex)
|
directed_graph.add_vertex(vertex)
|
||||||
|
|
||||||
def test_remove_vertex_exception_check(self) -> None:
|
def test_remove_vertex_exception_check(self) -> None:
|
||||||
|
@ -522,9 +520,9 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
|
|
||||||
for i in range(101):
|
for i in range(101):
|
||||||
if i not in random_vertices:
|
if i not in random_vertices:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.remove_vertex(i)
|
undirected_graph.remove_vertex(i)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.remove_vertex(i)
|
directed_graph.remove_vertex(i)
|
||||||
|
|
||||||
def test_add_edge_exception_check(self) -> None:
|
def test_add_edge_exception_check(self) -> None:
|
||||||
|
@ -536,9 +534,9 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
) = self.__generate_graphs(20, 0, 100, 4)
|
) = self.__generate_graphs(20, 0, 100, 4)
|
||||||
|
|
||||||
for edge in random_edges:
|
for edge in random_edges:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.add_edge(edge[0], edge[1])
|
undirected_graph.add_edge(edge[0], edge[1])
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.add_edge(edge[0], edge[1])
|
directed_graph.add_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def test_remove_edge_exception_check(self) -> None:
|
def test_remove_edge_exception_check(self) -> None:
|
||||||
|
@ -560,9 +558,9 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
more_random_edges.append(edge)
|
more_random_edges.append(edge)
|
||||||
|
|
||||||
for edge in more_random_edges:
|
for edge in more_random_edges:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.remove_edge(edge[0], edge[1])
|
undirected_graph.remove_edge(edge[0], edge[1])
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.remove_edge(edge[0], edge[1])
|
directed_graph.remove_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def test_contains_edge_exception_check(self) -> None:
|
def test_contains_edge_exception_check(self) -> None:
|
||||||
|
@ -574,14 +572,14 @@ class TestGraphAdjacencyList(unittest.TestCase):
|
||||||
) = self.__generate_graphs(20, 0, 100, 4)
|
) = self.__generate_graphs(20, 0, 100, 4)
|
||||||
|
|
||||||
for vertex in random_vertices:
|
for vertex in random_vertices:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.contains_edge(vertex, 102)
|
undirected_graph.contains_edge(vertex, 102)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.contains_edge(vertex, 102)
|
directed_graph.contains_edge(vertex, 102)
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.contains_edge(103, 102)
|
undirected_graph.contains_edge(103, 102)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.contains_edge(103, 102)
|
directed_graph.contains_edge(103, 102)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ import unittest
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from typing import Generic, TypeVar
|
from typing import Generic, TypeVar
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
|
@ -203,9 +205,9 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyMatrix,
|
directed_graph: GraphAdjacencyMatrix,
|
||||||
edge: list[int],
|
edge: list[int],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertTrue(undirected_graph.contains_edge(edge[0], edge[1]))
|
assert undirected_graph.contains_edge(edge[0], edge[1])
|
||||||
self.assertTrue(undirected_graph.contains_edge(edge[1], edge[0]))
|
assert undirected_graph.contains_edge(edge[1], edge[0])
|
||||||
self.assertTrue(directed_graph.contains_edge(edge[0], edge[1]))
|
assert directed_graph.contains_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def __assert_graph_edge_does_not_exist_check(
|
def __assert_graph_edge_does_not_exist_check(
|
||||||
self,
|
self,
|
||||||
|
@ -213,9 +215,9 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyMatrix,
|
directed_graph: GraphAdjacencyMatrix,
|
||||||
edge: list[int],
|
edge: list[int],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertFalse(undirected_graph.contains_edge(edge[0], edge[1]))
|
assert not undirected_graph.contains_edge(edge[0], edge[1])
|
||||||
self.assertFalse(undirected_graph.contains_edge(edge[1], edge[0]))
|
assert not undirected_graph.contains_edge(edge[1], edge[0])
|
||||||
self.assertFalse(directed_graph.contains_edge(edge[0], edge[1]))
|
assert not directed_graph.contains_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def __assert_graph_vertex_exists_check(
|
def __assert_graph_vertex_exists_check(
|
||||||
self,
|
self,
|
||||||
|
@ -223,8 +225,8 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyMatrix,
|
directed_graph: GraphAdjacencyMatrix,
|
||||||
vertex: int,
|
vertex: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertTrue(undirected_graph.contains_vertex(vertex))
|
assert undirected_graph.contains_vertex(vertex)
|
||||||
self.assertTrue(directed_graph.contains_vertex(vertex))
|
assert directed_graph.contains_vertex(vertex)
|
||||||
|
|
||||||
def __assert_graph_vertex_does_not_exist_check(
|
def __assert_graph_vertex_does_not_exist_check(
|
||||||
self,
|
self,
|
||||||
|
@ -232,13 +234,13 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
directed_graph: GraphAdjacencyMatrix,
|
directed_graph: GraphAdjacencyMatrix,
|
||||||
vertex: int,
|
vertex: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.assertFalse(undirected_graph.contains_vertex(vertex))
|
assert not undirected_graph.contains_vertex(vertex)
|
||||||
self.assertFalse(directed_graph.contains_vertex(vertex))
|
assert not directed_graph.contains_vertex(vertex)
|
||||||
|
|
||||||
def __generate_random_edges(
|
def __generate_random_edges(
|
||||||
self, vertices: list[int], edge_pick_count: int
|
self, vertices: list[int], edge_pick_count: int
|
||||||
) -> list[list[int]]:
|
) -> list[list[int]]:
|
||||||
self.assertTrue(edge_pick_count <= len(vertices))
|
assert edge_pick_count <= len(vertices)
|
||||||
|
|
||||||
random_source_vertices: list[int] = random.sample(
|
random_source_vertices: list[int] = random.sample(
|
||||||
vertices[0 : int(len(vertices) / 2)], edge_pick_count
|
vertices[0 : int(len(vertices) / 2)], edge_pick_count
|
||||||
|
@ -300,8 +302,8 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
undirected_graph, directed_graph, edge
|
undirected_graph, directed_graph, edge
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertFalse(undirected_graph.directed)
|
assert not undirected_graph.directed
|
||||||
self.assertTrue(directed_graph.directed)
|
assert directed_graph.directed
|
||||||
|
|
||||||
def test_contains_vertex(self) -> None:
|
def test_contains_vertex(self) -> None:
|
||||||
random_vertices: list[int] = random.sample(range(101), 20)
|
random_vertices: list[int] = random.sample(range(101), 20)
|
||||||
|
@ -316,12 +318,8 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
|
|
||||||
# Test contains_vertex
|
# Test contains_vertex
|
||||||
for num in range(101):
|
for num in range(101):
|
||||||
self.assertEqual(
|
assert (num in random_vertices) == undirected_graph.contains_vertex(num)
|
||||||
num in random_vertices, undirected_graph.contains_vertex(num)
|
assert (num in random_vertices) == directed_graph.contains_vertex(num)
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
num in random_vertices, directed_graph.contains_vertex(num)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_add_vertices(self) -> None:
|
def test_add_vertices(self) -> None:
|
||||||
random_vertices: list[int] = random.sample(range(101), 20)
|
random_vertices: list[int] = random.sample(range(101), 20)
|
||||||
|
@ -526,9 +524,9 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
) = self.__generate_graphs(20, 0, 100, 4)
|
) = self.__generate_graphs(20, 0, 100, 4)
|
||||||
|
|
||||||
for vertex in random_vertices:
|
for vertex in random_vertices:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.add_vertex(vertex)
|
undirected_graph.add_vertex(vertex)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.add_vertex(vertex)
|
directed_graph.add_vertex(vertex)
|
||||||
|
|
||||||
def test_remove_vertex_exception_check(self) -> None:
|
def test_remove_vertex_exception_check(self) -> None:
|
||||||
|
@ -541,9 +539,9 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
|
|
||||||
for i in range(101):
|
for i in range(101):
|
||||||
if i not in random_vertices:
|
if i not in random_vertices:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.remove_vertex(i)
|
undirected_graph.remove_vertex(i)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.remove_vertex(i)
|
directed_graph.remove_vertex(i)
|
||||||
|
|
||||||
def test_add_edge_exception_check(self) -> None:
|
def test_add_edge_exception_check(self) -> None:
|
||||||
|
@ -555,9 +553,9 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
) = self.__generate_graphs(20, 0, 100, 4)
|
) = self.__generate_graphs(20, 0, 100, 4)
|
||||||
|
|
||||||
for edge in random_edges:
|
for edge in random_edges:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.add_edge(edge[0], edge[1])
|
undirected_graph.add_edge(edge[0], edge[1])
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.add_edge(edge[0], edge[1])
|
directed_graph.add_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def test_remove_edge_exception_check(self) -> None:
|
def test_remove_edge_exception_check(self) -> None:
|
||||||
|
@ -579,9 +577,9 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
more_random_edges.append(edge)
|
more_random_edges.append(edge)
|
||||||
|
|
||||||
for edge in more_random_edges:
|
for edge in more_random_edges:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.remove_edge(edge[0], edge[1])
|
undirected_graph.remove_edge(edge[0], edge[1])
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.remove_edge(edge[0], edge[1])
|
directed_graph.remove_edge(edge[0], edge[1])
|
||||||
|
|
||||||
def test_contains_edge_exception_check(self) -> None:
|
def test_contains_edge_exception_check(self) -> None:
|
||||||
|
@ -593,14 +591,14 @@ class TestGraphMatrix(unittest.TestCase):
|
||||||
) = self.__generate_graphs(20, 0, 100, 4)
|
) = self.__generate_graphs(20, 0, 100, 4)
|
||||||
|
|
||||||
for vertex in random_vertices:
|
for vertex in random_vertices:
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.contains_edge(vertex, 102)
|
undirected_graph.contains_edge(vertex, 102)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.contains_edge(vertex, 102)
|
directed_graph.contains_edge(vertex, 102)
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
undirected_graph.contains_edge(103, 102)
|
undirected_graph.contains_edge(103, 102)
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
directed_graph.contains_edge(103, 102)
|
directed_graph.contains_edge(103, 102)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ class SHA256HashTest(unittest.TestCase):
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
msg = bytes("Test String", "utf-8")
|
msg = bytes("Test String", "utf-8")
|
||||||
self.assertEqual(SHA256(msg).hash, hashlib.sha256(msg).hexdigest())
|
assert SHA256(msg).hash == hashlib.sha256(msg).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from knapsack import greedy_knapsack as kp
|
from knapsack import greedy_knapsack as kp
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +18,7 @@ class TestClass(unittest.TestCase):
|
||||||
profit = [10, 20, 30, 40, 50, 60]
|
profit = [10, 20, 30, 40, 50, 60]
|
||||||
weight = [2, 4, 6, 8, 10, 12]
|
weight = [2, 4, 6, 8, 10, 12]
|
||||||
max_weight = 100
|
max_weight = 100
|
||||||
self.assertEqual(kp.calc_profit(profit, weight, max_weight), 210)
|
assert kp.calc_profit(profit, weight, max_weight) == 210
|
||||||
|
|
||||||
def test_negative_max_weight(self):
|
def test_negative_max_weight(self):
|
||||||
"""
|
"""
|
||||||
|
@ -26,7 +28,7 @@ class TestClass(unittest.TestCase):
|
||||||
# profit = [10, 20, 30, 40, 50, 60]
|
# profit = [10, 20, 30, 40, 50, 60]
|
||||||
# weight = [2, 4, 6, 8, 10, 12]
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
# max_weight = -15
|
# max_weight = -15
|
||||||
self.assertRaisesRegex(ValueError, "max_weight must greater than zero.")
|
pytest.raises(ValueError, match="max_weight must greater than zero.")
|
||||||
|
|
||||||
def test_negative_profit_value(self):
|
def test_negative_profit_value(self):
|
||||||
"""
|
"""
|
||||||
|
@ -36,7 +38,7 @@ class TestClass(unittest.TestCase):
|
||||||
# profit = [10, -20, 30, 40, 50, 60]
|
# profit = [10, -20, 30, 40, 50, 60]
|
||||||
# weight = [2, 4, 6, 8, 10, 12]
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
# max_weight = 15
|
# max_weight = 15
|
||||||
self.assertRaisesRegex(ValueError, "Weight can not be negative.")
|
pytest.raises(ValueError, match="Weight can not be negative.")
|
||||||
|
|
||||||
def test_negative_weight_value(self):
|
def test_negative_weight_value(self):
|
||||||
"""
|
"""
|
||||||
|
@ -46,7 +48,7 @@ class TestClass(unittest.TestCase):
|
||||||
# profit = [10, 20, 30, 40, 50, 60]
|
# profit = [10, 20, 30, 40, 50, 60]
|
||||||
# weight = [2, -4, 6, -8, 10, 12]
|
# weight = [2, -4, 6, -8, 10, 12]
|
||||||
# max_weight = 15
|
# max_weight = 15
|
||||||
self.assertRaisesRegex(ValueError, "Profit can not be negative.")
|
pytest.raises(ValueError, match="Profit can not be negative.")
|
||||||
|
|
||||||
def test_null_max_weight(self):
|
def test_null_max_weight(self):
|
||||||
"""
|
"""
|
||||||
|
@ -56,7 +58,7 @@ class TestClass(unittest.TestCase):
|
||||||
# profit = [10, 20, 30, 40, 50, 60]
|
# profit = [10, 20, 30, 40, 50, 60]
|
||||||
# weight = [2, 4, 6, 8, 10, 12]
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
# max_weight = null
|
# max_weight = null
|
||||||
self.assertRaisesRegex(ValueError, "max_weight must greater than zero.")
|
pytest.raises(ValueError, match="max_weight must greater than zero.")
|
||||||
|
|
||||||
def test_unequal_list_length(self):
|
def test_unequal_list_length(self):
|
||||||
"""
|
"""
|
||||||
|
@ -66,9 +68,7 @@ class TestClass(unittest.TestCase):
|
||||||
# profit = [10, 20, 30, 40, 50]
|
# profit = [10, 20, 30, 40, 50]
|
||||||
# weight = [2, 4, 6, 8, 10, 12]
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
# max_weight = 100
|
# max_weight = 100
|
||||||
self.assertRaisesRegex(
|
pytest.raises(IndexError, match="The length of profit and weight must be same.")
|
||||||
IndexError, "The length of profit and weight must be same."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -20,12 +20,12 @@ class Test(unittest.TestCase):
|
||||||
val = [0]
|
val = [0]
|
||||||
w = [0]
|
w = [0]
|
||||||
c = len(val)
|
c = len(val)
|
||||||
self.assertEqual(k.knapsack(cap, w, val, c), 0)
|
assert k.knapsack(cap, w, val, c) == 0
|
||||||
|
|
||||||
val = [60]
|
val = [60]
|
||||||
w = [10]
|
w = [10]
|
||||||
c = len(val)
|
c = len(val)
|
||||||
self.assertEqual(k.knapsack(cap, w, val, c), 0)
|
assert k.knapsack(cap, w, val, c) == 0
|
||||||
|
|
||||||
def test_easy_case(self):
|
def test_easy_case(self):
|
||||||
"""
|
"""
|
||||||
|
@ -35,7 +35,7 @@ class Test(unittest.TestCase):
|
||||||
val = [1, 2, 3]
|
val = [1, 2, 3]
|
||||||
w = [3, 2, 1]
|
w = [3, 2, 1]
|
||||||
c = len(val)
|
c = len(val)
|
||||||
self.assertEqual(k.knapsack(cap, w, val, c), 5)
|
assert k.knapsack(cap, w, val, c) == 5
|
||||||
|
|
||||||
def test_knapsack(self):
|
def test_knapsack(self):
|
||||||
"""
|
"""
|
||||||
|
@ -45,7 +45,7 @@ class Test(unittest.TestCase):
|
||||||
val = [60, 100, 120]
|
val = [60, 100, 120]
|
||||||
w = [10, 20, 30]
|
w = [10, 20, 30]
|
||||||
c = len(val)
|
c = len(val)
|
||||||
self.assertEqual(k.knapsack(cap, w, val, c), 220)
|
assert k.knapsack(cap, w, val, c) == 220
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -200,7 +200,8 @@ def unit_basis_vector(dimension: int, pos: int) -> Vector:
|
||||||
at index 'pos' (indexing at 0)
|
at index 'pos' (indexing at 0)
|
||||||
"""
|
"""
|
||||||
# precondition
|
# precondition
|
||||||
assert isinstance(dimension, int) and (isinstance(pos, int))
|
assert isinstance(dimension, int)
|
||||||
|
assert isinstance(pos, int)
|
||||||
ans = [0] * dimension
|
ans = [0] * dimension
|
||||||
ans[pos] = 1
|
ans[pos] = 1
|
||||||
return Vector(ans)
|
return Vector(ans)
|
||||||
|
@ -213,11 +214,9 @@ def axpy(scalar: float, x: Vector, y: Vector) -> Vector:
|
||||||
computes the axpy operation
|
computes the axpy operation
|
||||||
"""
|
"""
|
||||||
# precondition
|
# precondition
|
||||||
assert (
|
assert isinstance(x, Vector)
|
||||||
isinstance(x, Vector)
|
assert isinstance(y, Vector)
|
||||||
and isinstance(y, Vector)
|
assert isinstance(scalar, (int, float))
|
||||||
and (isinstance(scalar, (int, float)))
|
|
||||||
)
|
|
||||||
return x * scalar + y
|
return x * scalar + y
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
def schur_complement(
|
def schur_complement(
|
||||||
|
@ -70,14 +71,14 @@ class TestSchurComplement(unittest.TestCase):
|
||||||
det_a = np.linalg.det(a)
|
det_a = np.linalg.det(a)
|
||||||
det_s = np.linalg.det(s)
|
det_s = np.linalg.det(s)
|
||||||
|
|
||||||
self.assertAlmostEqual(det_x, det_a * det_s)
|
assert np.is_close(det_x, det_a * det_s)
|
||||||
|
|
||||||
def test_improper_a_b_dimensions(self) -> None:
|
def test_improper_a_b_dimensions(self) -> None:
|
||||||
a = np.array([[1, 2, 1], [2, 1, 2], [3, 2, 4]])
|
a = np.array([[1, 2, 1], [2, 1, 2], [3, 2, 4]])
|
||||||
b = np.array([[0, 3], [3, 0], [2, 3]])
|
b = np.array([[0, 3], [3, 0], [2, 3]])
|
||||||
c = np.array([[2, 1], [6, 3]])
|
c = np.array([[2, 1], [6, 3]])
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
schur_complement(a, b, c)
|
schur_complement(a, b, c)
|
||||||
|
|
||||||
def test_improper_b_c_dimensions(self) -> None:
|
def test_improper_b_c_dimensions(self) -> None:
|
||||||
|
@ -85,7 +86,7 @@ class TestSchurComplement(unittest.TestCase):
|
||||||
b = np.array([[0, 3], [3, 0], [2, 3]])
|
b = np.array([[0, 3], [3, 0], [2, 3]])
|
||||||
c = np.array([[2, 1, 3], [6, 3, 5]])
|
c = np.array([[2, 1, 3], [6, 3, 5]])
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
schur_complement(a, b, c)
|
schur_complement(a, b, c)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ This file contains the test-suite for the linear algebra library.
|
||||||
"""
|
"""
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from .lib import (
|
from .lib import (
|
||||||
Matrix,
|
Matrix,
|
||||||
Vector,
|
Vector,
|
||||||
|
@ -24,8 +26,8 @@ class Test(unittest.TestCase):
|
||||||
test for method component()
|
test for method component()
|
||||||
"""
|
"""
|
||||||
x = Vector([1, 2, 3])
|
x = Vector([1, 2, 3])
|
||||||
self.assertEqual(x.component(0), 1)
|
assert x.component(0) == 1
|
||||||
self.assertEqual(x.component(2), 3)
|
assert x.component(2) == 3
|
||||||
_ = Vector()
|
_ = Vector()
|
||||||
|
|
||||||
def test_str(self) -> None:
|
def test_str(self) -> None:
|
||||||
|
@ -33,14 +35,14 @@ class Test(unittest.TestCase):
|
||||||
test for method toString()
|
test for method toString()
|
||||||
"""
|
"""
|
||||||
x = Vector([0, 0, 0, 0, 0, 1])
|
x = Vector([0, 0, 0, 0, 0, 1])
|
||||||
self.assertEqual(str(x), "(0,0,0,0,0,1)")
|
assert str(x) == "(0,0,0,0,0,1)"
|
||||||
|
|
||||||
def test_size(self) -> None:
|
def test_size(self) -> None:
|
||||||
"""
|
"""
|
||||||
test for method size()
|
test for method size()
|
||||||
"""
|
"""
|
||||||
x = Vector([1, 2, 3, 4])
|
x = Vector([1, 2, 3, 4])
|
||||||
self.assertEqual(len(x), 4)
|
assert len(x) == 4
|
||||||
|
|
||||||
def test_euclidean_length(self) -> None:
|
def test_euclidean_length(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -50,10 +52,10 @@ class Test(unittest.TestCase):
|
||||||
y = Vector([1, 2, 3, 4, 5])
|
y = Vector([1, 2, 3, 4, 5])
|
||||||
z = Vector([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
z = Vector([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||||
w = Vector([1, -1, 1, -1, 2, -3, 4, -5])
|
w = Vector([1, -1, 1, -1, 2, -3, 4, -5])
|
||||||
self.assertAlmostEqual(x.euclidean_length(), 2.236, 3)
|
assert x.euclidean_length() == pytest.approx(2.236, abs=1e-3)
|
||||||
self.assertAlmostEqual(y.euclidean_length(), 7.416, 3)
|
assert y.euclidean_length() == pytest.approx(7.416, abs=1e-3)
|
||||||
self.assertEqual(z.euclidean_length(), 0)
|
assert z.euclidean_length() == 0
|
||||||
self.assertAlmostEqual(w.euclidean_length(), 7.616, 3)
|
assert w.euclidean_length() == pytest.approx(7.616, abs=1e-3)
|
||||||
|
|
||||||
def test_add(self) -> None:
|
def test_add(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -61,9 +63,9 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
x = Vector([1, 2, 3])
|
x = Vector([1, 2, 3])
|
||||||
y = Vector([1, 1, 1])
|
y = Vector([1, 1, 1])
|
||||||
self.assertEqual((x + y).component(0), 2)
|
assert (x + y).component(0) == 2
|
||||||
self.assertEqual((x + y).component(1), 3)
|
assert (x + y).component(1) == 3
|
||||||
self.assertEqual((x + y).component(2), 4)
|
assert (x + y).component(2) == 4
|
||||||
|
|
||||||
def test_sub(self) -> None:
|
def test_sub(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -71,9 +73,9 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
x = Vector([1, 2, 3])
|
x = Vector([1, 2, 3])
|
||||||
y = Vector([1, 1, 1])
|
y = Vector([1, 1, 1])
|
||||||
self.assertEqual((x - y).component(0), 0)
|
assert (x - y).component(0) == 0
|
||||||
self.assertEqual((x - y).component(1), 1)
|
assert (x - y).component(1) == 1
|
||||||
self.assertEqual((x - y).component(2), 2)
|
assert (x - y).component(2) == 2
|
||||||
|
|
||||||
def test_mul(self) -> None:
|
def test_mul(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -82,20 +84,20 @@ class Test(unittest.TestCase):
|
||||||
x = Vector([1, 2, 3])
|
x = Vector([1, 2, 3])
|
||||||
a = Vector([2, -1, 4]) # for test of dot product
|
a = Vector([2, -1, 4]) # for test of dot product
|
||||||
b = Vector([1, -2, -1])
|
b = Vector([1, -2, -1])
|
||||||
self.assertEqual(str(x * 3.0), "(3.0,6.0,9.0)")
|
assert str(x * 3.0) == "(3.0,6.0,9.0)"
|
||||||
self.assertEqual((a * b), 0)
|
assert a * b == 0
|
||||||
|
|
||||||
def test_zero_vector(self) -> None:
|
def test_zero_vector(self) -> None:
|
||||||
"""
|
"""
|
||||||
test for global function zero_vector()
|
test for global function zero_vector()
|
||||||
"""
|
"""
|
||||||
self.assertEqual(str(zero_vector(10)).count("0"), 10)
|
assert str(zero_vector(10)).count("0") == 10
|
||||||
|
|
||||||
def test_unit_basis_vector(self) -> None:
|
def test_unit_basis_vector(self) -> None:
|
||||||
"""
|
"""
|
||||||
test for global function unit_basis_vector()
|
test for global function unit_basis_vector()
|
||||||
"""
|
"""
|
||||||
self.assertEqual(str(unit_basis_vector(3, 1)), "(0,1,0)")
|
assert str(unit_basis_vector(3, 1)) == "(0,1,0)"
|
||||||
|
|
||||||
def test_axpy(self) -> None:
|
def test_axpy(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -103,7 +105,7 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
x = Vector([1, 2, 3])
|
x = Vector([1, 2, 3])
|
||||||
y = Vector([1, 0, 1])
|
y = Vector([1, 0, 1])
|
||||||
self.assertEqual(str(axpy(2, x, y)), "(3,4,7)")
|
assert str(axpy(2, x, y)) == "(3,4,7)"
|
||||||
|
|
||||||
def test_copy(self) -> None:
|
def test_copy(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -111,7 +113,7 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
x = Vector([1, 0, 0, 0, 0, 0])
|
x = Vector([1, 0, 0, 0, 0, 0])
|
||||||
y = x.copy()
|
y = x.copy()
|
||||||
self.assertEqual(str(x), str(y))
|
assert str(x) == str(y)
|
||||||
|
|
||||||
def test_change_component(self) -> None:
|
def test_change_component(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -120,14 +122,14 @@ class Test(unittest.TestCase):
|
||||||
x = Vector([1, 0, 0])
|
x = Vector([1, 0, 0])
|
||||||
x.change_component(0, 0)
|
x.change_component(0, 0)
|
||||||
x.change_component(1, 1)
|
x.change_component(1, 1)
|
||||||
self.assertEqual(str(x), "(0,1,0)")
|
assert str(x) == "(0,1,0)"
|
||||||
|
|
||||||
def test_str_matrix(self) -> None:
|
def test_str_matrix(self) -> None:
|
||||||
"""
|
"""
|
||||||
test for Matrix method str()
|
test for Matrix method str()
|
||||||
"""
|
"""
|
||||||
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
||||||
self.assertEqual("|1,2,3|\n|2,4,5|\n|6,7,8|\n", str(a))
|
assert str(a) == "|1,2,3|\n|2,4,5|\n|6,7,8|\n"
|
||||||
|
|
||||||
def test_minor(self) -> None:
|
def test_minor(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -137,7 +139,7 @@ class Test(unittest.TestCase):
|
||||||
minors = [[-3, -14, -10], [-5, -10, -5], [-2, -1, 0]]
|
minors = [[-3, -14, -10], [-5, -10, -5], [-2, -1, 0]]
|
||||||
for x in range(a.height()):
|
for x in range(a.height()):
|
||||||
for y in range(a.width()):
|
for y in range(a.width()):
|
||||||
self.assertEqual(minors[x][y], a.minor(x, y))
|
assert minors[x][y] == a.minor(x, y)
|
||||||
|
|
||||||
def test_cofactor(self) -> None:
|
def test_cofactor(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -147,14 +149,14 @@ class Test(unittest.TestCase):
|
||||||
cofactors = [[-3, 14, -10], [5, -10, 5], [-2, 1, 0]]
|
cofactors = [[-3, 14, -10], [5, -10, 5], [-2, 1, 0]]
|
||||||
for x in range(a.height()):
|
for x in range(a.height()):
|
||||||
for y in range(a.width()):
|
for y in range(a.width()):
|
||||||
self.assertEqual(cofactors[x][y], a.cofactor(x, y))
|
assert cofactors[x][y] == a.cofactor(x, y)
|
||||||
|
|
||||||
def test_determinant(self) -> None:
|
def test_determinant(self) -> None:
|
||||||
"""
|
"""
|
||||||
test for Matrix method determinant()
|
test for Matrix method determinant()
|
||||||
"""
|
"""
|
||||||
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
||||||
self.assertEqual(-5, a.determinant())
|
assert a.determinant() == -5
|
||||||
|
|
||||||
def test__mul__matrix(self) -> None:
|
def test__mul__matrix(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -162,8 +164,8 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
a = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]], 3, 3)
|
a = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]], 3, 3)
|
||||||
x = Vector([1, 2, 3])
|
x = Vector([1, 2, 3])
|
||||||
self.assertEqual("(14,32,50)", str(a * x))
|
assert str(a * x) == "(14,32,50)"
|
||||||
self.assertEqual("|2,4,6|\n|8,10,12|\n|14,16,18|\n", str(a * 2))
|
assert str(a * 2) == "|2,4,6|\n|8,10,12|\n|14,16,18|\n"
|
||||||
|
|
||||||
def test_change_component_matrix(self) -> None:
|
def test_change_component_matrix(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -171,14 +173,14 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
||||||
a.change_component(0, 2, 5)
|
a.change_component(0, 2, 5)
|
||||||
self.assertEqual("|1,2,5|\n|2,4,5|\n|6,7,8|\n", str(a))
|
assert str(a) == "|1,2,5|\n|2,4,5|\n|6,7,8|\n"
|
||||||
|
|
||||||
def test_component_matrix(self) -> None:
|
def test_component_matrix(self) -> None:
|
||||||
"""
|
"""
|
||||||
test for Matrix method component()
|
test for Matrix method component()
|
||||||
"""
|
"""
|
||||||
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
||||||
self.assertEqual(7, a.component(2, 1), 0.01)
|
assert a.component(2, 1) == 7, 0.01
|
||||||
|
|
||||||
def test__add__matrix(self) -> None:
|
def test__add__matrix(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -186,7 +188,7 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
||||||
b = Matrix([[1, 2, 7], [2, 4, 5], [6, 7, 10]], 3, 3)
|
b = Matrix([[1, 2, 7], [2, 4, 5], [6, 7, 10]], 3, 3)
|
||||||
self.assertEqual("|2,4,10|\n|4,8,10|\n|12,14,18|\n", str(a + b))
|
assert str(a + b) == "|2,4,10|\n|4,8,10|\n|12,14,18|\n"
|
||||||
|
|
||||||
def test__sub__matrix(self) -> None:
|
def test__sub__matrix(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -194,15 +196,14 @@ class Test(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
a = Matrix([[1, 2, 3], [2, 4, 5], [6, 7, 8]], 3, 3)
|
||||||
b = Matrix([[1, 2, 7], [2, 4, 5], [6, 7, 10]], 3, 3)
|
b = Matrix([[1, 2, 7], [2, 4, 5], [6, 7, 10]], 3, 3)
|
||||||
self.assertEqual("|0,0,-4|\n|0,0,0|\n|0,0,-2|\n", str(a - b))
|
assert str(a - b) == "|0,0,-4|\n|0,0,0|\n|0,0,-2|\n"
|
||||||
|
|
||||||
def test_square_zero_matrix(self) -> None:
|
def test_square_zero_matrix(self) -> None:
|
||||||
"""
|
"""
|
||||||
test for global function square_zero_matrix()
|
test for global function square_zero_matrix()
|
||||||
"""
|
"""
|
||||||
self.assertEqual(
|
assert str(square_zero_matrix(5)) == (
|
||||||
"|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|\n",
|
"|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|\n"
|
||||||
str(square_zero_matrix(5)),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,7 @@ def test_linear_discriminant_analysis() -> None:
|
||||||
dimensions = 2
|
dimensions = 2
|
||||||
|
|
||||||
# Assert that the function raises an AssertionError if dimensions > classes
|
# Assert that the function raises an AssertionError if dimensions > classes
|
||||||
with pytest.raises(AssertionError) as error_info:
|
with pytest.raises(AssertionError) as error_info: # noqa: PT012
|
||||||
projected_data = linear_discriminant_analysis(
|
projected_data = linear_discriminant_analysis(
|
||||||
features, labels, classes, dimensions
|
features, labels, classes, dimensions
|
||||||
)
|
)
|
||||||
|
@ -185,7 +185,7 @@ def test_principal_component_analysis() -> None:
|
||||||
dimensions = 2
|
dimensions = 2
|
||||||
expected_output = np.array([[6.92820323, 8.66025404, 10.39230485], [3.0, 3.0, 3.0]])
|
expected_output = np.array([[6.92820323, 8.66025404, 10.39230485], [3.0, 3.0, 3.0]])
|
||||||
|
|
||||||
with pytest.raises(AssertionError) as error_info:
|
with pytest.raises(AssertionError) as error_info: # noqa: PT012
|
||||||
output = principal_component_analysis(features, dimensions)
|
output = principal_component_analysis(features, dimensions)
|
||||||
if not np.allclose(expected_output, output):
|
if not np.allclose(expected_output, output):
|
||||||
raise AssertionError
|
raise AssertionError
|
||||||
|
|
|
@ -128,7 +128,7 @@ def plot_heterogeneity(heterogeneity, k):
|
||||||
def kmeans(
|
def kmeans(
|
||||||
data, k, initial_centroids, maxiter=500, record_heterogeneity=None, verbose=False
|
data, k, initial_centroids, maxiter=500, record_heterogeneity=None, verbose=False
|
||||||
):
|
):
|
||||||
"""This function runs k-means on given data and initial set of centroids.
|
"""Runs k-means on given data and initial set of centroids.
|
||||||
maxiter: maximum number of iterations to run.(default=500)
|
maxiter: maximum number of iterations to run.(default=500)
|
||||||
record_heterogeneity: (optional) a list, to store the history of heterogeneity
|
record_heterogeneity: (optional) a list, to store the history of heterogeneity
|
||||||
as function of iterations
|
as function of iterations
|
||||||
|
@ -195,20 +195,20 @@ if False: # change to true to run this test case.
|
||||||
|
|
||||||
|
|
||||||
def report_generator(
|
def report_generator(
|
||||||
df: pd.DataFrame, clustering_variables: np.ndarray, fill_missing_report=None
|
predicted: pd.DataFrame, clustering_variables: np.ndarray, fill_missing_report=None
|
||||||
) -> pd.DataFrame:
|
) -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
Generates a clustering report. This function takes 2 arguments as input:
|
Generate a clustering report given these two arguments:
|
||||||
df - dataframe with predicted cluster column
|
predicted - dataframe with predicted cluster column
|
||||||
fill_missing_report - dictionary of rules on how we are going to fill in missing
|
fill_missing_report - dictionary of rules on how we are going to fill in missing
|
||||||
values for final generated report (not included in modelling);
|
values for final generated report (not included in modelling);
|
||||||
>>> data = pd.DataFrame()
|
>>> predicted = pd.DataFrame()
|
||||||
>>> data['numbers'] = [1, 2, 3]
|
>>> predicted['numbers'] = [1, 2, 3]
|
||||||
>>> data['col1'] = [0.5, 2.5, 4.5]
|
>>> predicted['col1'] = [0.5, 2.5, 4.5]
|
||||||
>>> data['col2'] = [100, 200, 300]
|
>>> predicted['col2'] = [100, 200, 300]
|
||||||
>>> data['col3'] = [10, 20, 30]
|
>>> predicted['col3'] = [10, 20, 30]
|
||||||
>>> data['Cluster'] = [1, 1, 2]
|
>>> predicted['Cluster'] = [1, 1, 2]
|
||||||
>>> report_generator(data, ['col1', 'col2'], 0)
|
>>> report_generator(predicted, ['col1', 'col2'], 0)
|
||||||
Features Type Mark 1 2
|
Features Type Mark 1 2
|
||||||
0 # of Customers ClusterSize False 2.000000 1.000000
|
0 # of Customers ClusterSize False 2.000000 1.000000
|
||||||
1 % of Customers ClusterProportion False 0.666667 0.333333
|
1 % of Customers ClusterProportion False 0.666667 0.333333
|
||||||
|
@ -226,11 +226,11 @@ def report_generator(
|
||||||
"""
|
"""
|
||||||
# Fill missing values with given rules
|
# Fill missing values with given rules
|
||||||
if fill_missing_report:
|
if fill_missing_report:
|
||||||
df = df.fillna(value=fill_missing_report)
|
predicted = predicted.fillna(value=fill_missing_report)
|
||||||
df["dummy"] = 1
|
predicted["dummy"] = 1
|
||||||
numeric_cols = df.select_dtypes(np.number).columns
|
numeric_cols = predicted.select_dtypes(np.number).columns
|
||||||
report = (
|
report = (
|
||||||
df.groupby(["Cluster"])[ # construct report dataframe
|
predicted.groupby(["Cluster"])[ # construct report dataframe
|
||||||
numeric_cols
|
numeric_cols
|
||||||
] # group by cluster number
|
] # group by cluster number
|
||||||
.agg(
|
.agg(
|
||||||
|
@ -267,46 +267,43 @@ def report_generator(
|
||||||
.rename(index=str, columns={"level_0": "Features", "level_1": "Type"})
|
.rename(index=str, columns={"level_0": "Features", "level_1": "Type"})
|
||||||
) # rename columns
|
) # rename columns
|
||||||
# calculate the size of cluster(count of clientID's)
|
# calculate the size of cluster(count of clientID's)
|
||||||
|
# avoid SettingWithCopyWarning
|
||||||
clustersize = report[
|
clustersize = report[
|
||||||
(report["Features"] == "dummy") & (report["Type"] == "count")
|
(report["Features"] == "dummy") & (report["Type"] == "count")
|
||||||
].copy() # avoid SettingWithCopyWarning
|
].copy()
|
||||||
clustersize.Type = (
|
# rename created predicted cluster to match report column names
|
||||||
"ClusterSize" # rename created cluster df to match report column names
|
clustersize.Type = "ClusterSize"
|
||||||
)
|
|
||||||
clustersize.Features = "# of Customers"
|
clustersize.Features = "# of Customers"
|
||||||
|
# calculating the proportion of cluster
|
||||||
clusterproportion = pd.DataFrame(
|
clusterproportion = pd.DataFrame(
|
||||||
clustersize.iloc[:, 2:].values
|
clustersize.iloc[:, 2:].to_numpy() / clustersize.iloc[:, 2:].to_numpy().sum()
|
||||||
/ clustersize.iloc[:, 2:].values.sum() # calculating the proportion of cluster
|
|
||||||
)
|
)
|
||||||
clusterproportion[
|
# rename created predicted cluster to match report column names
|
||||||
"Type"
|
clusterproportion["Type"] = "% of Customers"
|
||||||
] = "% of Customers" # rename created cluster df to match report column names
|
|
||||||
clusterproportion["Features"] = "ClusterProportion"
|
clusterproportion["Features"] = "ClusterProportion"
|
||||||
cols = clusterproportion.columns.tolist()
|
cols = clusterproportion.columns.tolist()
|
||||||
cols = cols[-2:] + cols[:-2]
|
cols = cols[-2:] + cols[:-2]
|
||||||
clusterproportion = clusterproportion[cols] # rearrange columns to match report
|
clusterproportion = clusterproportion[cols] # rearrange columns to match report
|
||||||
clusterproportion.columns = report.columns
|
clusterproportion.columns = report.columns
|
||||||
|
# generating dataframe with count of nan values
|
||||||
a = pd.DataFrame(
|
a = pd.DataFrame(
|
||||||
abs(
|
abs(
|
||||||
report[report["Type"] == "count"].iloc[:, 2:].values
|
report[report["Type"] == "count"].iloc[:, 2:].to_numpy()
|
||||||
- clustersize.iloc[:, 2:].values
|
- clustersize.iloc[:, 2:].to_numpy()
|
||||||
)
|
)
|
||||||
) # generating df with count of nan values
|
)
|
||||||
a["Features"] = 0
|
a["Features"] = 0
|
||||||
a["Type"] = "# of nan"
|
a["Type"] = "# of nan"
|
||||||
a.Features = report[
|
# filling values in order to match report
|
||||||
report["Type"] == "count"
|
a.Features = report[report["Type"] == "count"].Features.tolist()
|
||||||
].Features.tolist() # filling values in order to match report
|
|
||||||
cols = a.columns.tolist()
|
cols = a.columns.tolist()
|
||||||
cols = cols[-2:] + cols[:-2]
|
cols = cols[-2:] + cols[:-2]
|
||||||
a = a[cols] # rearrange columns to match report
|
a = a[cols] # rearrange columns to match report
|
||||||
a.columns = report.columns # rename columns to match report
|
a.columns = report.columns # rename columns to match report
|
||||||
report = report.drop(
|
# drop count values except for cluster size
|
||||||
report[report.Type == "count"].index
|
report = report.drop(report[report.Type == "count"].index)
|
||||||
) # drop count values except for cluster size
|
# concat report with cluster size and nan values
|
||||||
report = pd.concat(
|
report = pd.concat([report, a, clustersize, clusterproportion], axis=0)
|
||||||
[report, a, clustersize, clusterproportion], axis=0
|
|
||||||
) # concat report with cluster size and nan values
|
|
||||||
report["Mark"] = report["Features"].isin(clustering_variables)
|
report["Mark"] = report["Features"].isin(clustering_variables)
|
||||||
cols = report.columns.tolist()
|
cols = report.columns.tolist()
|
||||||
cols = cols[0:2] + cols[-1:] + cols[2:-1]
|
cols = cols[0:2] + cols[-1:] + cols[2:-1]
|
||||||
|
|
|
@ -67,8 +67,8 @@ class TestLeastCommonMultiple(unittest.TestCase):
|
||||||
slow_result = least_common_multiple_slow(first_num, second_num)
|
slow_result = least_common_multiple_slow(first_num, second_num)
|
||||||
fast_result = least_common_multiple_fast(first_num, second_num)
|
fast_result = least_common_multiple_fast(first_num, second_num)
|
||||||
with self.subTest(i=i):
|
with self.subTest(i=i):
|
||||||
self.assertEqual(slow_result, self.expected_results[i])
|
assert slow_result == self.expected_results[i]
|
||||||
self.assertEqual(fast_result, self.expected_results[i])
|
assert fast_result == self.expected_results[i]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -28,7 +28,9 @@ def modular_division(a: int, b: int, n: int) -> int:
|
||||||
4
|
4
|
||||||
|
|
||||||
"""
|
"""
|
||||||
assert n > 1 and a > 0 and greatest_common_divisor(a, n) == 1
|
assert n > 1
|
||||||
|
assert a > 0
|
||||||
|
assert greatest_common_divisor(a, n) == 1
|
||||||
(d, t, s) = extended_gcd(n, a) # Implemented below
|
(d, t, s) = extended_gcd(n, a) # Implemented below
|
||||||
x = (b * s) % n
|
x = (b * s) % n
|
||||||
return x
|
return x
|
||||||
|
@ -86,7 +88,8 @@ def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
|
||||||
** extended_gcd function is used when d = gcd(a,b) is required in output
|
** extended_gcd function is used when d = gcd(a,b) is required in output
|
||||||
|
|
||||||
"""
|
"""
|
||||||
assert a >= 0 and b >= 0
|
assert a >= 0
|
||||||
|
assert b >= 0
|
||||||
|
|
||||||
if b == 0:
|
if b == 0:
|
||||||
d, x, y = a, 1, 0
|
d, x, y = a, 1, 0
|
||||||
|
@ -95,7 +98,8 @@ def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
|
||||||
x = q
|
x = q
|
||||||
y = p - q * (a // b)
|
y = p - q * (a // b)
|
||||||
|
|
||||||
assert a % d == 0 and b % d == 0
|
assert a % d == 0
|
||||||
|
assert b % d == 0
|
||||||
assert d == a * x + b * y
|
assert d == a * x + b * y
|
||||||
|
|
||||||
return (d, x, y)
|
return (d, x, y)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
import math
|
import math
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
def is_prime(number: int) -> bool:
|
def is_prime(number: int) -> bool:
|
||||||
"""Checks to see if a number is a prime in O(sqrt(n)).
|
"""Checks to see if a number is a prime in O(sqrt(n)).
|
||||||
|
@ -50,33 +52,31 @@ def is_prime(number: int) -> bool:
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
def test_primes(self):
|
def test_primes(self):
|
||||||
self.assertTrue(is_prime(2))
|
assert is_prime(2)
|
||||||
self.assertTrue(is_prime(3))
|
assert is_prime(3)
|
||||||
self.assertTrue(is_prime(5))
|
assert is_prime(5)
|
||||||
self.assertTrue(is_prime(7))
|
assert is_prime(7)
|
||||||
self.assertTrue(is_prime(11))
|
assert is_prime(11)
|
||||||
self.assertTrue(is_prime(13))
|
assert is_prime(13)
|
||||||
self.assertTrue(is_prime(17))
|
assert is_prime(17)
|
||||||
self.assertTrue(is_prime(19))
|
assert is_prime(19)
|
||||||
self.assertTrue(is_prime(23))
|
assert is_prime(23)
|
||||||
self.assertTrue(is_prime(29))
|
assert is_prime(29)
|
||||||
|
|
||||||
def test_not_primes(self):
|
def test_not_primes(self):
|
||||||
with self.assertRaises(AssertionError):
|
with pytest.raises(AssertionError):
|
||||||
is_prime(-19)
|
is_prime(-19)
|
||||||
self.assertFalse(
|
assert not is_prime(
|
||||||
is_prime(0),
|
0
|
||||||
"Zero doesn't have any positive factors, primes must have exactly two.",
|
), "Zero doesn't have any positive factors, primes must have exactly two."
|
||||||
)
|
assert not is_prime(
|
||||||
self.assertFalse(
|
1
|
||||||
is_prime(1),
|
), "One only has 1 positive factor, primes must have exactly two."
|
||||||
"One only has 1 positive factor, primes must have exactly two.",
|
assert not is_prime(2 * 2)
|
||||||
)
|
assert not is_prime(2 * 3)
|
||||||
self.assertFalse(is_prime(2 * 2))
|
assert not is_prime(3 * 3)
|
||||||
self.assertFalse(is_prime(2 * 3))
|
assert not is_prime(3 * 5)
|
||||||
self.assertFalse(is_prime(3 * 3))
|
assert not is_prime(3 * 5 * 7)
|
||||||
self.assertFalse(is_prime(3 * 5))
|
|
||||||
self.assertFalse(is_prime(3 * 5 * 7))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -114,7 +114,8 @@ class Matrix:
|
||||||
|
|
||||||
# Validation
|
# Validation
|
||||||
assert isinstance(another, Matrix)
|
assert isinstance(another, Matrix)
|
||||||
assert self.row == another.row and self.column == another.column
|
assert self.row == another.row
|
||||||
|
assert self.column == another.column
|
||||||
|
|
||||||
# Add
|
# Add
|
||||||
result = Matrix(self.row, self.column)
|
result = Matrix(self.row, self.column)
|
||||||
|
@ -225,7 +226,8 @@ class Matrix:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Size validation
|
# Size validation
|
||||||
assert isinstance(u, Matrix) and isinstance(v, Matrix)
|
assert isinstance(u, Matrix)
|
||||||
|
assert isinstance(v, Matrix)
|
||||||
assert self.row == self.column == u.row == v.row # u, v should be column vector
|
assert self.row == self.column == u.row == v.row # u, v should be column vector
|
||||||
assert u.column == v.column == 1 # u, v should be column vector
|
assert u.column == v.column == 1 # u, v should be column vector
|
||||||
|
|
||||||
|
|
|
@ -31,14 +31,14 @@ stream_handler = logging.StreamHandler(sys.stdout)
|
||||||
logger.addHandler(stream_handler)
|
logger.addHandler(stream_handler)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mat_ops
|
@pytest.mark.mat_ops()
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
|
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
|
||||||
)
|
)
|
||||||
def test_addition(mat1, mat2):
|
def test_addition(mat1, mat2):
|
||||||
if (np.array(mat1)).shape < (2, 2) or (np.array(mat2)).shape < (2, 2):
|
if (np.array(mat1)).shape < (2, 2) or (np.array(mat2)).shape < (2, 2):
|
||||||
|
logger.info(f"\n\t{test_addition.__name__} returned integer")
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
logger.info(f"\n\t{test_addition.__name__} returned integer")
|
|
||||||
matop.add(mat1, mat2)
|
matop.add(mat1, mat2)
|
||||||
elif (np.array(mat1)).shape == (np.array(mat2)).shape:
|
elif (np.array(mat1)).shape == (np.array(mat2)).shape:
|
||||||
logger.info(f"\n\t{test_addition.__name__} with same matrix dims")
|
logger.info(f"\n\t{test_addition.__name__} with same matrix dims")
|
||||||
|
@ -46,19 +46,19 @@ def test_addition(mat1, mat2):
|
||||||
theo = matop.add(mat1, mat2)
|
theo = matop.add(mat1, mat2)
|
||||||
assert theo == act
|
assert theo == act
|
||||||
else:
|
else:
|
||||||
|
logger.info(f"\n\t{test_addition.__name__} with different matrix dims")
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
logger.info(f"\n\t{test_addition.__name__} with different matrix dims")
|
|
||||||
matop.add(mat1, mat2)
|
matop.add(mat1, mat2)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mat_ops
|
@pytest.mark.mat_ops()
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
|
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
|
||||||
)
|
)
|
||||||
def test_subtraction(mat1, mat2):
|
def test_subtraction(mat1, mat2):
|
||||||
if (np.array(mat1)).shape < (2, 2) or (np.array(mat2)).shape < (2, 2):
|
if (np.array(mat1)).shape < (2, 2) or (np.array(mat2)).shape < (2, 2):
|
||||||
|
logger.info(f"\n\t{test_subtraction.__name__} returned integer")
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
logger.info(f"\n\t{test_subtraction.__name__} returned integer")
|
|
||||||
matop.subtract(mat1, mat2)
|
matop.subtract(mat1, mat2)
|
||||||
elif (np.array(mat1)).shape == (np.array(mat2)).shape:
|
elif (np.array(mat1)).shape == (np.array(mat2)).shape:
|
||||||
logger.info(f"\n\t{test_subtraction.__name__} with same matrix dims")
|
logger.info(f"\n\t{test_subtraction.__name__} with same matrix dims")
|
||||||
|
@ -66,12 +66,12 @@ def test_subtraction(mat1, mat2):
|
||||||
theo = matop.subtract(mat1, mat2)
|
theo = matop.subtract(mat1, mat2)
|
||||||
assert theo == act
|
assert theo == act
|
||||||
else:
|
else:
|
||||||
|
logger.info(f"\n\t{test_subtraction.__name__} with different matrix dims")
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
logger.info(f"\n\t{test_subtraction.__name__} with different matrix dims")
|
|
||||||
assert matop.subtract(mat1, mat2)
|
assert matop.subtract(mat1, mat2)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mat_ops
|
@pytest.mark.mat_ops()
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
|
("mat1", "mat2"), [(mat_a, mat_b), (mat_c, mat_d), (mat_d, mat_e), (mat_f, mat_h)]
|
||||||
)
|
)
|
||||||
|
@ -86,33 +86,33 @@ def test_multiplication(mat1, mat2):
|
||||||
theo = matop.multiply(mat1, mat2)
|
theo = matop.multiply(mat1, mat2)
|
||||||
assert theo == act
|
assert theo == act
|
||||||
else:
|
else:
|
||||||
|
logger.info(
|
||||||
|
f"\n\t{test_multiplication.__name__} does not meet dim requirements"
|
||||||
|
)
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
logger.info(
|
|
||||||
f"\n\t{test_multiplication.__name__} does not meet dim requirements"
|
|
||||||
)
|
|
||||||
assert matop.subtract(mat1, mat2)
|
assert matop.subtract(mat1, mat2)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mat_ops
|
@pytest.mark.mat_ops()
|
||||||
def test_scalar_multiply():
|
def test_scalar_multiply():
|
||||||
act = (3.5 * np.array(mat_a)).tolist()
|
act = (3.5 * np.array(mat_a)).tolist()
|
||||||
theo = matop.scalar_multiply(mat_a, 3.5)
|
theo = matop.scalar_multiply(mat_a, 3.5)
|
||||||
assert theo == act
|
assert theo == act
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mat_ops
|
@pytest.mark.mat_ops()
|
||||||
def test_identity():
|
def test_identity():
|
||||||
act = (np.identity(5)).tolist()
|
act = (np.identity(5)).tolist()
|
||||||
theo = matop.identity(5)
|
theo = matop.identity(5)
|
||||||
assert theo == act
|
assert theo == act
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mat_ops
|
@pytest.mark.mat_ops()
|
||||||
@pytest.mark.parametrize("mat", [mat_a, mat_b, mat_c, mat_d, mat_e, mat_f])
|
@pytest.mark.parametrize("mat", [mat_a, mat_b, mat_c, mat_d, mat_e, mat_f])
|
||||||
def test_transpose(mat):
|
def test_transpose(mat):
|
||||||
if (np.array(mat)).shape < (2, 2):
|
if (np.array(mat)).shape < (2, 2):
|
||||||
|
logger.info(f"\n\t{test_transpose.__name__} returned integer")
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
logger.info(f"\n\t{test_transpose.__name__} returned integer")
|
|
||||||
matop.transpose(mat)
|
matop.transpose(mat)
|
||||||
else:
|
else:
|
||||||
act = (np.transpose(mat)).tolist()
|
act = (np.transpose(mat)).tolist()
|
||||||
|
|
|
@ -147,39 +147,39 @@ def generate_random_hands(number_of_hands: int = 100):
|
||||||
return (generate_random_hand() for _ in range(number_of_hands))
|
return (generate_random_hand() for _ in range(number_of_hands))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("hand, expected", TEST_FLUSH)
|
@pytest.mark.parametrize(("hand", "expected"), TEST_FLUSH)
|
||||||
def test_hand_is_flush(hand, expected):
|
def test_hand_is_flush(hand, expected):
|
||||||
assert PokerHand(hand)._is_flush() == expected
|
assert PokerHand(hand)._is_flush() == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("hand, expected", TEST_STRAIGHT)
|
@pytest.mark.parametrize(("hand", "expected"), TEST_STRAIGHT)
|
||||||
def test_hand_is_straight(hand, expected):
|
def test_hand_is_straight(hand, expected):
|
||||||
assert PokerHand(hand)._is_straight() == expected
|
assert PokerHand(hand)._is_straight() == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("hand, expected, card_values", TEST_FIVE_HIGH_STRAIGHT)
|
@pytest.mark.parametrize(("hand", "expected", "card_values"), TEST_FIVE_HIGH_STRAIGHT)
|
||||||
def test_hand_is_five_high_straight(hand, expected, card_values):
|
def test_hand_is_five_high_straight(hand, expected, card_values):
|
||||||
player = PokerHand(hand)
|
player = PokerHand(hand)
|
||||||
assert player._is_five_high_straight() == expected
|
assert player._is_five_high_straight() == expected
|
||||||
assert player._card_values == card_values
|
assert player._card_values == card_values
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("hand, expected", TEST_KIND)
|
@pytest.mark.parametrize(("hand", "expected"), TEST_KIND)
|
||||||
def test_hand_is_same_kind(hand, expected):
|
def test_hand_is_same_kind(hand, expected):
|
||||||
assert PokerHand(hand)._is_same_kind() == expected
|
assert PokerHand(hand)._is_same_kind() == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("hand, expected", TEST_TYPES)
|
@pytest.mark.parametrize(("hand", "expected"), TEST_TYPES)
|
||||||
def test_hand_values(hand, expected):
|
def test_hand_values(hand, expected):
|
||||||
assert PokerHand(hand)._hand_type == expected
|
assert PokerHand(hand)._hand_type == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("hand, other, expected", TEST_COMPARE)
|
@pytest.mark.parametrize(("hand", "other", "expected"), TEST_COMPARE)
|
||||||
def test_compare_simple(hand, other, expected):
|
def test_compare_simple(hand, other, expected):
|
||||||
assert PokerHand(hand).compare_with(PokerHand(other)) == expected
|
assert PokerHand(hand).compare_with(PokerHand(other)) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("hand, other, expected", generate_random_hands())
|
@pytest.mark.parametrize(("hand", "other", "expected"), generate_random_hands())
|
||||||
def test_compare_random(hand, other, expected):
|
def test_compare_random(hand, other, expected):
|
||||||
assert PokerHand(hand).compare_with(PokerHand(other)) == expected
|
assert PokerHand(hand).compare_with(PokerHand(other)) == expected
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ ignore = [ # `ruff rule S101` for a description of that rule
|
||||||
"PLW0120", # `else` clause on loop without a `break` statement -- FIX ME
|
"PLW0120", # `else` clause on loop without a `break` statement -- FIX ME
|
||||||
"PLW060", # Using global for `{name}` but no assignment is done -- DO NOT FIX
|
"PLW060", # Using global for `{name}` but no assignment is done -- DO NOT FIX
|
||||||
"PLW2901", # PLW2901: Redefined loop variable -- FIX ME
|
"PLW2901", # PLW2901: Redefined loop variable -- FIX ME
|
||||||
|
"PT011", # `pytest.raises(Exception)` is too broad, set the `match` parameter or use a more specific exception
|
||||||
|
"PT018", # Assertion should be broken down into multiple parts
|
||||||
"RUF00", # Ambiguous unicode character and other rules
|
"RUF00", # Ambiguous unicode character and other rules
|
||||||
"RUF100", # Unused `noqa` directive -- FIX ME
|
"RUF100", # Unused `noqa` directive -- FIX ME
|
||||||
"S101", # Use of `assert` detected -- DO NOT FIX
|
"S101", # Use of `assert` detected -- DO NOT FIX
|
||||||
|
@ -37,6 +39,7 @@ select = [ # https://beta.ruff.rs/docs/rules
|
||||||
"BLE", # flake8-blind-except
|
"BLE", # flake8-blind-except
|
||||||
"C4", # flake8-comprehensions
|
"C4", # flake8-comprehensions
|
||||||
"C90", # McCabe cyclomatic complexity
|
"C90", # McCabe cyclomatic complexity
|
||||||
|
"DJ", # flake8-django
|
||||||
"DTZ", # flake8-datetimez
|
"DTZ", # flake8-datetimez
|
||||||
"E", # pycodestyle
|
"E", # pycodestyle
|
||||||
"EM", # flake8-errmsg
|
"EM", # flake8-errmsg
|
||||||
|
@ -52,9 +55,11 @@ select = [ # https://beta.ruff.rs/docs/rules
|
||||||
"ISC", # flake8-implicit-str-concat
|
"ISC", # flake8-implicit-str-concat
|
||||||
"N", # pep8-naming
|
"N", # pep8-naming
|
||||||
"NPY", # NumPy-specific rules
|
"NPY", # NumPy-specific rules
|
||||||
|
"PD", # pandas-vet
|
||||||
"PGH", # pygrep-hooks
|
"PGH", # pygrep-hooks
|
||||||
"PIE", # flake8-pie
|
"PIE", # flake8-pie
|
||||||
"PL", # Pylint
|
"PL", # Pylint
|
||||||
|
"PT", # flake8-pytest-style
|
||||||
"PYI", # flake8-pyi
|
"PYI", # flake8-pyi
|
||||||
"RSE", # flake8-raise
|
"RSE", # flake8-raise
|
||||||
"RUF", # Ruff-specific rules
|
"RUF", # Ruff-specific rules
|
||||||
|
@ -70,11 +75,8 @@ select = [ # https://beta.ruff.rs/docs/rules
|
||||||
# "ANN", # flake8-annotations # FIX ME?
|
# "ANN", # flake8-annotations # FIX ME?
|
||||||
# "COM", # flake8-commas
|
# "COM", # flake8-commas
|
||||||
# "D", # pydocstyle -- FIX ME?
|
# "D", # pydocstyle -- FIX ME?
|
||||||
# "DJ", # flake8-django
|
|
||||||
# "ERA", # eradicate -- DO NOT FIX
|
# "ERA", # eradicate -- DO NOT FIX
|
||||||
# "FBT", # flake8-boolean-trap # FIX ME
|
# "FBT", # flake8-boolean-trap # FIX ME
|
||||||
# "PD", # pandas-vet
|
|
||||||
# "PT", # flake8-pytest-style
|
|
||||||
# "PTH", # flake8-use-pathlib # FIX ME
|
# "PTH", # flake8-use-pathlib # FIX ME
|
||||||
# "Q", # flake8-quotes
|
# "Q", # flake8-quotes
|
||||||
# "RET", # flake8-return # FIX ME?
|
# "RET", # flake8-return # FIX ME?
|
||||||
|
|
|
@ -71,7 +71,8 @@ if __name__ == "__main__":
|
||||||
pattern = "abc1abc12"
|
pattern = "abc1abc12"
|
||||||
text1 = "alskfjaldsabc1abc1abc12k23adsfabcabc"
|
text1 = "alskfjaldsabc1abc1abc12k23adsfabcabc"
|
||||||
text2 = "alskfjaldsk23adsfabcabc"
|
text2 = "alskfjaldsk23adsfabcabc"
|
||||||
assert knuth_morris_pratt(text1, pattern) and knuth_morris_pratt(text2, pattern)
|
assert knuth_morris_pratt(text1, pattern)
|
||||||
|
assert knuth_morris_pratt(text2, pattern)
|
||||||
|
|
||||||
# Test 2)
|
# Test 2)
|
||||||
pattern = "ABABX"
|
pattern = "ABABX"
|
||||||
|
|
|
@ -60,7 +60,8 @@ def test_rabin_karp() -> None:
|
||||||
pattern = "abc1abc12"
|
pattern = "abc1abc12"
|
||||||
text1 = "alskfjaldsabc1abc1abc12k23adsfabcabc"
|
text1 = "alskfjaldsabc1abc1abc12k23adsfabcabc"
|
||||||
text2 = "alskfjaldsk23adsfabcabc"
|
text2 = "alskfjaldsk23adsfabcabc"
|
||||||
assert rabin_karp(pattern, text1) and not rabin_karp(pattern, text2)
|
assert rabin_karp(pattern, text1)
|
||||||
|
assert not rabin_karp(pattern, text2)
|
||||||
|
|
||||||
# Test 2)
|
# Test 2)
|
||||||
pattern = "ABABX"
|
pattern = "ABABX"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user