From 863dde324fca7a09a608bc5a494de0f133fc7934 Mon Sep 17 00:00:00 2001 From: czgdp1807 Date: Fri, 10 Apr 2020 13:10:47 +0530 Subject: [PATCH 1/3] test for public api added --- pydatastructs/utils/misc_util.py | 33 +++++++++++++++++++ .../utils/tests/test_code_quality.py | 21 +++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/pydatastructs/utils/misc_util.py b/pydatastructs/utils/misc_util.py index 88b7a90e7..e789cf0fb 100644 --- a/pydatastructs/utils/misc_util.py +++ b/pydatastructs/utils/misc_util.py @@ -38,6 +38,10 @@ class TreeNode(Node): __slots__ = ['key', 'data', 'left', 'right', 'is_root', 'height', 'parent', 'size'] + @classmethod + def methods(cls): + return ['__new__', '__str__'] + def __new__(cls, key, data=None): obj = Node.__new__(cls) obj.data, obj.key = data, key @@ -81,6 +85,10 @@ class BinomialTreeNode(TreeNode): """ __slots__ = ['parent', 'key', 'children', 'data', 'is_root'] + @classmethod + def methods(cls): + return ['__new__', 'add_children', '__str__'] + def __new__(cls, key, data=None): from pydatastructs.linear_data_structures.arrays import DynamicOneDimensionalArray obj = Node.__new__(cls) @@ -132,6 +140,10 @@ class MAryTreeNode(TreeNode): """ __slots__ = ['key', 'children', 'data', 'is_root'] + @classmethod + def methods(cls): + return ['__new__', 'add_children', '__str__'] + def __new__(cls, key, data=None): from pydatastructs.linear_data_structures.arrays import DynamicOneDimensionalArray obj = Node.__new__(cls) @@ -169,6 +181,10 @@ class LinkedListNode(Node): addrs List of address of nodes to be assigned to each of the attributes in links. """ + @classmethod + def methods(cls): + return ['__new__', '__str__'] + def __new__(cls, key, data=None, links=['next'], addrs=[None]): obj = Node.__new__(cls) obj.key = key @@ -206,6 +222,11 @@ class AdjacencyListGraphNode(GraphNode): nodes of the current node. Optional, by default, None """ + @classmethod + def methods(cls): + return ['__new__', 'add_adjacent_node', + 'remove_adjacent_node'] + def __new__(cls, name, data=None, adjacency_list=None): obj = GraphNode.__new__(cls) obj.name, obj.data = str(name), data @@ -254,6 +275,10 @@ class AdjacencyMatrixGraphNode(GraphNode): """ __slots__ = ['name', 'data'] + @classmethod + def methods(cls): + return ['__new__'] + def __new__(cls, name, data=None): obj = GraphNode.__new__(cls) obj.name, obj.data, obj.is_connected = \ @@ -273,6 +298,10 @@ class GraphEdge(object): node2: GraphNode or it's child classes The target node of the edge. """ + @classmethod + def methods(cls): + return ['__new__', '__str__'] + def __new__(cls, node1, node2, value=None): obj = object.__new__(cls) obj.source, obj.target = node1, node2 @@ -298,6 +327,10 @@ class Set(object): __slots__ = ['parent', 'size', 'key', 'data'] + @classmethod + def methods(cls): + return ['__new__'] + def __new__(cls, key, data=None): obj = object.__new__(cls) obj.key = key diff --git a/pydatastructs/utils/tests/test_code_quality.py b/pydatastructs/utils/tests/test_code_quality.py index b2277c9ee..7bdc3527c 100644 --- a/pydatastructs/utils/tests/test_code_quality.py +++ b/pydatastructs/utils/tests/test_code_quality.py @@ -1,4 +1,4 @@ -import os, re, sys +import os, re, sys, pydatastructs, inspect def _list_files(): root_path = os.path.abspath( @@ -70,3 +70,22 @@ def test_presence_of_tabs(): "Configure your editor to use " \ "white spaces."%(line, file_path) file.close() + +def test_public_api(): + pyds = pydatastructs + public_api = dir(pydatastructs) + for name in public_api: + if inspect.isclass(getattr(pyds, name)): + _class = getattr(pyds, name) + mro = _class.__mro__ + must_methods = _class.methods() + for supercls in mro: + if supercls != _class: + for method in must_methods: + if hasattr(supercls, method) and \ + getattr(supercls, method) == \ + getattr(_class, method): + assert False, ("%s class doesn't " + "have %s method implemented."%( + _class, method + )) From 1aa4901a503355dd55709886550c6e296df31773 Mon Sep 17 00:00:00 2001 From: czgdp1807 Date: Mon, 20 Apr 2020 15:25:40 +0530 Subject: [PATCH 2/3] quality tests complete --- .coveragerc | 1 + .travis.yml | 2 +- pydatastructs/graphs/adjacency_list.py | 6 + pydatastructs/graphs/adjacency_matrix.py | 6 + .../linear_data_structures/arrays.py | 12 + .../linear_data_structures/linked_lists.py | 435 ++++-------------- .../tests/test_linked_lists.py | 48 +- .../binomial_trees.py | 4 + .../disjoint_set.py | 4 + .../miscellaneous_data_structures/queue.py | 32 +- .../miscellaneous_data_structures/stack.py | 18 +- pydatastructs/trees/binary_trees.py | 30 ++ pydatastructs/trees/heaps.py | 20 +- pydatastructs/trees/m_ary_trees.py | 4 + .../trees/space_partitioning_trees.py | 4 + .../utils/tests/test_code_quality.py | 39 +- 16 files changed, 297 insertions(+), 368 deletions(-) diff --git a/.coveragerc b/.coveragerc index 07491451b..ddf915a5d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -3,6 +3,7 @@ parallel = True source = pydatastructs omit = */tests/* + */setup.py [report] exclude_lines = diff --git a/.travis.yml b/.travis.yml index 3cdaff76f..a3f9c5f76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: - pip install -r requirements.txt script: - - python -m pytest --doctest-modules --cov=./ --cov-report=xml + - python -m pytest --doctest-modules --cov=./ --cov-report=xml -s after_success: - codecov diff --git a/pydatastructs/graphs/adjacency_list.py b/pydatastructs/graphs/adjacency_list.py index c38f482d1..75e380b37 100644 --- a/pydatastructs/graphs/adjacency_list.py +++ b/pydatastructs/graphs/adjacency_list.py @@ -23,6 +23,12 @@ def __new__(cls, *vertices): obj.edge_weights = dict() return obj + @classmethod + def methods(self): + return ['is_adjacent', 'neighbors', + 'add_vertex', 'remove_vertex', 'add_edge', + 'get_edge', 'remove_edge', '__new__'] + def is_adjacent(self, node1, node2): node1 = self.__getattribute__(node1) return hasattr(node1, node2) diff --git a/pydatastructs/graphs/adjacency_matrix.py b/pydatastructs/graphs/adjacency_matrix.py index 4460011ca..4b374b26c 100644 --- a/pydatastructs/graphs/adjacency_matrix.py +++ b/pydatastructs/graphs/adjacency_matrix.py @@ -26,6 +26,12 @@ def __new__(cls, *vertices): obj.edge_weights = dict() return obj + @classmethod + def methods(self): + return ['is_adjacent', 'neighbors', + 'add_edge', 'get_edge', 'remove_edge', + '__new__'] + def is_adjacent(self, node1, node2): node1, node2 = str(node1), str(node2) row = self.matrix.get(node1, dict()) diff --git a/pydatastructs/linear_data_structures/arrays.py b/pydatastructs/linear_data_structures/arrays.py index 7dce4b943..a1a55092f 100644 --- a/pydatastructs/linear_data_structures/arrays.py +++ b/pydatastructs/linear_data_structures/arrays.py @@ -109,6 +109,12 @@ def __new__(cls, dtype=NoneType, *args, **kwargs): return obj + @classmethod + def methods(cls): + return ['__new__', '__getitem__', + '__setitem__', 'fill', '__len__', + '__str__'] + def __getitem__(self, i): if i >= self._size or i < 0: raise IndexError("Index out of range.") @@ -215,6 +221,12 @@ def __new__(cls, dtype=NoneType, *args, **kwargs): obj._last_pos_filled = obj._num - 1 return obj + @classmethod + def methods(cls): + return ['__new__', '_modify', + 'append', 'delete', 'size', + '__str__', '__reversed__'] + def _modify(self, force=False): """ Contracts the array if Num(T)/Size(T) falls diff --git a/pydatastructs/linear_data_structures/linked_lists.py b/pydatastructs/linear_data_structures/linked_lists.py index 77b577ea6..eed58779d 100644 --- a/pydatastructs/linear_data_structures/linked_lists.py +++ b/pydatastructs/linear_data_structures/linked_lists.py @@ -100,8 +100,87 @@ def __getitem__(self, index): current_node: LinkedListNode The node at given index. """ + if index < 0: + index = self.size + index + + if index >= self.size: + raise IndexError('%d index is out of range.'%(index)) + + counter = 0 + current_node = self.head + while counter != index: + current_node = current_node.next + counter += 1 + return current_node + + def appendleft(self, key, data=None): + """ + Pushes a new node at the start i.e., + the left of the list. + + Parameters + ========== + + data + Any valid data to be stored in the node. + """ + self.insert_at(0, key, data) + + def append(self, key, data=None): + """ + Appends a new node at the end of the list. + + Parameters + ========== + + data + Any valid data to be stored in the node. + """ + self.insert_at(self.size, key, data) + + def insert_before(self, next_node, key, data=None): + """ + Inserts a new node before the next_node. + + Parameters + ========== + + next_node: LinkedListNode + The node before which the + new node is to be inserted. + + data + Any valid data to be stored in the node. + """ raise NotImplementedError('This is an abstract method') + def popleft(self): + """ + Extracts the Node from the left + i.e. start of the list. + + Returns + ======= + + old_head: LinkedListNode + The leftmost element of linked + list. + """ + return self.extract(0) + + def popright(self): + """ + Extracts the node from the right + of the linked list. + + Returns + ======= + + old_tail: LinkedListNode + The leftmost element of linked + list. + """ + return self.extract(-1) class DoublyLinkedList(LinkedList): """ @@ -118,7 +197,7 @@ class DoublyLinkedList(LinkedList): >>> dll.head.key 6 >>> dll.append(5) - >>> dll.append_left(2) + >>> dll.appendleft(2) >>> str(dll) "['2', '6', '5']" >>> dll[0].key = 7.2 @@ -142,45 +221,12 @@ def __new__(cls): obj.size = 0 return obj - def append_left(self, key, data=None): - """ - Pushes a new node at the start i.e., - the left of the list. - - Parameters - ========== - - data - Any valid data to be stored in the node. - """ - self.insert_at(0, key, data) - - def append(self, key, data=None): - """ - Appends a new node at the end of the list. - - Parameters - ========== - - data - Any valid data to be stored in the node. - """ - self.insert_at(self.size, key, data) + @classmethod + def methods(cls): + return ['__new__', 'insert_after', + 'insert_before', 'insert_at', 'extract'] def insert_after(self, prev_node, key, data=None): - """ - Inserts a new node after the prev_node. - - Parameters - ========== - - prev_node: LinkedListNode - The node after which the - new node is to be inserted. - - data - Any valid data to be stored in the node. - """ self.size += 1 new_node = LinkedListNode(key, data, links=['next', 'prev'], @@ -195,19 +241,6 @@ def insert_after(self, prev_node, key, data=None): self.tail = new_node def insert_before(self, next_node, key, data=None): - """ - Inserts a new node before the next_node. - - Parameters - ========== - - next_node: LinkedListNode - The node before which the - new node is to be inserted. - - data - Any valid data to be stored in the node. - """ self.size += 1 new_node = LinkedListNode(key, data, links=['next', 'prev'], @@ -221,18 +254,6 @@ def insert_before(self, next_node, key, data=None): self.head = new_node def insert_at(self, index, key, data=None): - """ - Inserts a new node at the input index. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - data - Any valid data to be stored in the node. - """ if self.size == 0 and (index in (0, -1)): index = 0 @@ -268,50 +289,7 @@ def insert_at(self, index, key, data=None): if new_node.prev is None: self.head = new_node - def pop_left(self): - """ - Extracts the Node from the left - i.e. start of the list. - - Returns - ======= - - old_head: LinkedListNode - The leftmost element of linked - list. - """ - return self.extract(0) - - def pop_right(self): - """ - Extracts the node from the right - of the linked list. - - Returns - ======= - - old_tail: LinkedListNode - The leftmost element of linked - list. - """ - return self.extract(-1) - def extract(self, index): - """ - Extracts the node at the index of the list. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - Returns - ======= - - current_node: LinkedListNode - The node at index i. - """ if self.is_empty: raise ValueError("The list is empty.") @@ -339,27 +317,6 @@ def extract(self, index): self.tail = current_node.prev return current_node - def __getitem__(self, index): - """ - Returns - ======= - - current_node: LinkedListNode - The node at given index. - """ - if index < 0: - index = self.size + index - - if index >= self.size: - raise IndexError('%d index is out of range.'%(index)) - - counter = 0 - current_node = self.head - while counter != index: - current_node = current_node.next - counter += 1 - return current_node - class SinglyLinkedList(LinkedList): """ Represents Singly Linked List @@ -375,7 +332,7 @@ class SinglyLinkedList(LinkedList): >>> sll.head.key 6 >>> sll.append(5) - >>> sll.append_left(2) + >>> sll.appendleft(2) >>> str(sll) "['2', '6', '5']" >>> sll[0].key = 7.2 @@ -399,45 +356,12 @@ def __new__(cls): obj.size = 0 return obj - def append_left(self, key, data=None): - """ - Pushes a new node at the start i.e., - the left of the list. - - Parameters - ========== - - data - Any valid data to be stored in the node. - """ - self.insert_at(0, key, data) - - def append(self, key, data=None): - """ - Appends a new node at the end of the list. - - Parameters - ========== - - data - Any valid data to be stored in the node. - """ - self.insert_at(self.size, key, data) + @classmethod + def methods(cls): + return ['insert_after', 'insert_at', + 'extract'] def insert_after(self, prev_node, key, data=None): - """ - Inserts a new node after the prev_node. - - Parameters - ========== - - prev_node: LinkedListNode - The node after which the - new node is to be inserted. - - data - Any valid data to be stored in the node. - """ self.size += 1 new_node = LinkedListNode(key, data, links=['next'], @@ -449,18 +373,6 @@ def insert_after(self, prev_node, key, data=None): self.tail = new_node def insert_at(self, index, key, data=None): - """ - Inserts a new node at the input index. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - data - Any valid data to be stored in the node. - """ if self.size == 0 and (index in (0, -1)): index = 0 @@ -493,50 +405,7 @@ def insert_at(self, index, key, data=None): if index == 0: self.head = new_node - def pop_left(self): - """ - Extracts the Node from the left - i.e. start of the list. - - Returns - ======= - - old_head: LinkedListNode - The leftmost element of linked - list. - """ - return self.extract(0) - - def pop_right(self): - """ - Extracts the node from the right - of the linked list. - - Returns - ======= - - old_tail: LinkedListNode - The leftmost element of linked - list. - """ - return self.extract(-1) - def extract(self, index): - """ - Extracts the node at the index of the list. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - Returns - ======= - - current_node: LinkedListNode - The node at index i. - """ if self.is_empty: raise ValueError("The list is empty.") @@ -562,27 +431,6 @@ def extract(self, index): self.tail = prev_node return current_node - def __getitem__(self, index): - """ - Returns - ======= - - current_node: LinkedListNode - The node at given index. - """ - if index < 0: - index = self.size + index - - if index >= self.size: - raise IndexError('%d index is out of range.'%(index)) - - counter = 0 - current_node = self.head - while counter != index: - current_node = current_node.next - counter += 1 - return current_node - class SinglyCircularLinkedList(SinglyLinkedList): """ Represents Singly Circular Linked List. @@ -599,7 +447,7 @@ class SinglyCircularLinkedList(SinglyLinkedList): >>> scll.head.key 6 >>> scll.append(5) - >>> scll.append_left(2) + >>> scll.appendleft(2) >>> str(scll) "['2', '6', '5']" >>> scll[0].key = 7.2 @@ -615,38 +463,17 @@ class SinglyCircularLinkedList(SinglyLinkedList): """ - def insert_after(self, prev_node, key, data=None): - """ - Inserts a new node after the prev_node. - - Parameters - ========== + @classmethod + def methods(cls): + return ['insert_after', 'insert_at', 'extract'] - prev_node: LinkedListNode - The node after which the - new node is to be inserted. - - data - Any valid data to be stored in the node. - """ + def insert_after(self, prev_node, key, data=None): super(SinglyCircularLinkedList, self).\ insert_after(prev_node, key, data) if prev_node.next.next == self.head: self.tail = prev_node.next def insert_at(self, index, key, data=None): - """ - Inserts a new node at the input index. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - data - Any valid data to be stored in the node. - """ super(SinglyCircularLinkedList, self).insert_at(index, key, data) if self.size == 1: self.head.next = self.head @@ -657,21 +484,6 @@ def insert_at(self, index, key, data=None): self.tail = new_node def extract(self, index): - """ - Extracts the node at the index of the list. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - Returns - ======= - - current_node: LinkedListNode - The node at index i. - """ node = super(SinglyCircularLinkedList, self).extract(index) if self.tail is None: self.head = None @@ -694,7 +506,7 @@ class DoublyCircularLinkedList(DoublyLinkedList): >>> dcll.head.key 6 >>> dcll.append(5) - >>> dcll.append_left(2) + >>> dcll.appendleft(2) >>> str(dcll) "['2', '6', '5']" >>> dcll[0].key = 7.2 @@ -709,57 +521,25 @@ class DoublyCircularLinkedList(DoublyLinkedList): .. [1] https://en.wikipedia.org/wiki/Doubly_linked_list#Circular_doubly_linked_lists """ - def insert_after(self, prev_node, key, data=None): - """ - Inserts a new node after the prev_node. - Parameters - ========== + @classmethod + def methods(cls): + return ['insert_after', 'insert_before', + 'insert_at', 'extract'] - prev_node: LinkedListNode - The node after which the - new node is to be inserted. - - data - Any valid data to be stored in the node. - """ + def insert_after(self, prev_node, key, data=None): super(DoublyCircularLinkedList, self)\ .insert_after(prev_node, key, data) if prev_node.next.next == self.head: self.tail = prev_node.next def insert_before(self, next_node, key, data=None): - """ - Inserts a new node before the next_node. - - Parameters - ========== - - next_node: LinkedListNode - The node before which the - new node is to be inserted. - - data - Any valid data to be stored in the node. - """ super(DoublyCircularLinkedList, self).\ insert_before(next_node, key, data) if next_node == self.head: self.head = next_node.prev def insert_at(self, index, key, data=None): - """ - Inserts a new node at the input index. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - data - Any valid data to be stored in the node. - """ super(DoublyCircularLinkedList, self).\ insert_at(index, key, data) if self.size == 1: @@ -775,21 +555,6 @@ def insert_at(self, index, key, data=None): self.head.prev = new_node def extract(self, index): - """ - Extracts the node at the index of the list. - - Parameters - ========== - - index: int - An integer satisfying python indexing properties. - - Returns - ======= - - current_node: LinkedListNode - The node at index i. - """ node = super(DoublyCircularLinkedList, self).extract(index) if self.tail is None: self.head = None diff --git a/pydatastructs/linear_data_structures/tests/test_linked_lists.py b/pydatastructs/linear_data_structures/tests/test_linked_lists.py index 6e5aa19de..c65f64011 100644 --- a/pydatastructs/linear_data_structures/tests/test_linked_lists.py +++ b/pydatastructs/linear_data_structures/tests/test_linked_lists.py @@ -6,9 +6,9 @@ def test_DoublyLinkedList(): random.seed(1000) dll = DoublyLinkedList() assert raises(IndexError, lambda: dll[2]) - dll.append_left(5) + dll.appendleft(5) dll.append(1) - dll.append_left(2) + dll.appendleft(2) dll.append(3) dll.insert_after(dll[-1], 4) dll.insert_after(dll[2], 6) @@ -17,8 +17,8 @@ def test_DoublyLinkedList(): dll.insert_at(0, 2) dll.insert_at(-1, 9) dll.extract(2) - assert dll.pop_left().key == 2 - assert dll.pop_right().key == 4 + assert dll.popleft().key == 2 + assert dll.popright().key == 4 assert dll.search(3) == dll[-2] assert dll.search(-1) is None dll[-2].key = 0 @@ -31,9 +31,9 @@ def test_DoublyLinkedList(): dll_copy.append(dll[i]) for i in range(len(dll)): if i%2 == 0: - dll.pop_left() + dll.popleft() else: - dll.pop_right() + dll.popright() assert str(dll) == "[]" for _ in range(len(dll_copy)): index = random.randint(0, len(dll_copy) - 1) @@ -45,17 +45,17 @@ def test_SinglyLinkedList(): random.seed(1000) sll = SinglyLinkedList() assert raises(IndexError, lambda: sll[2]) - sll.append_left(5) + sll.appendleft(5) sll.append(1) - sll.append_left(2) + sll.appendleft(2) sll.append(3) sll.insert_after(sll[1], 4) sll.insert_after(sll[-1], 6) sll.insert_at(0, 2) sll.insert_at(-1, 9) sll.extract(2) - assert sll.pop_left().key == 2 - assert sll.pop_right().key == 6 + assert sll.popleft().key == 2 + assert sll.popright().key == 6 sll[-2].key = 0 assert str(sll) == "['2', '4', '1', '0', '9']" assert len(sll) == 5 @@ -66,9 +66,9 @@ def test_SinglyLinkedList(): sll_copy.append(sll[i]) for i in range(len(sll)): if i%2 == 0: - sll.pop_left() + sll.popleft() else: - sll.pop_right() + sll.popright() assert str(sll) == "[]" for _ in range(len(sll_copy)): index = random.randint(0, len(sll_copy) - 1) @@ -80,17 +80,17 @@ def test_SinglyCircularLinkedList(): random.seed(1000) scll = SinglyCircularLinkedList() assert raises(IndexError, lambda: scll[2]) - scll.append_left(5) + scll.appendleft(5) scll.append(1) - scll.append_left(2) + scll.appendleft(2) scll.append(3) scll.insert_after(scll[1], 4) scll.insert_after(scll[-1], 6) scll.insert_at(0, 2) scll.insert_at(-1, 9) scll.extract(2) - assert scll.pop_left().key == 2 - assert scll.pop_right().key == 6 + assert scll.popleft().key == 2 + assert scll.popright().key == 6 assert scll.search(-1) is None scll[-2].key = 0 assert str(scll) == "['2', '4', '1', '0', '9']" @@ -102,9 +102,9 @@ def test_SinglyCircularLinkedList(): scll_copy.append(scll[i]) for i in range(len(scll)): if i%2 == 0: - scll.pop_left() + scll.popleft() else: - scll.pop_right() + scll.popright() assert str(scll) == "[]" for _ in range(len(scll_copy)): index = random.randint(0, len(scll_copy) - 1) @@ -116,9 +116,9 @@ def test_DoublyCircularLinkedList(): random.seed(1000) dcll = DoublyCircularLinkedList() assert raises(IndexError, lambda: dcll[2]) - dcll.append_left(5) + dcll.appendleft(5) dcll.append(1) - dcll.append_left(2) + dcll.appendleft(2) dcll.append(3) dcll.insert_after(dcll[-1], 4) dcll.insert_after(dcll[2], 6) @@ -127,8 +127,8 @@ def test_DoublyCircularLinkedList(): dcll.insert_at(0, 2) dcll.insert_at(-1, 9) dcll.extract(2) - assert dcll.pop_left().key == 2 - assert dcll.pop_right().key == 4 + assert dcll.popleft().key == 2 + assert dcll.popright().key == 4 dcll[-2].key = 0 assert str(dcll) == "['7', '5', '1', '6', '1', '0', '9']" assert len(dcll) == 7 @@ -139,9 +139,9 @@ def test_DoublyCircularLinkedList(): dcll_copy.append(dcll[i]) for i in range(len(dcll)): if i%2 == 0: - dcll.pop_left() + dcll.popleft() else: - dcll.pop_right() + dcll.popright() assert str(dcll) == "[]" for _ in range(len(dcll_copy)): index = random.randint(0, len(dcll_copy) - 1) diff --git a/pydatastructs/miscellaneous_data_structures/binomial_trees.py b/pydatastructs/miscellaneous_data_structures/binomial_trees.py index c76610e21..627c40fe7 100644 --- a/pydatastructs/miscellaneous_data_structures/binomial_trees.py +++ b/pydatastructs/miscellaneous_data_structures/binomial_trees.py @@ -49,6 +49,10 @@ def __new__(cls, root=None, order=None): obj.order = order return obj + @classmethod + def methods(cls): + return ['add_sub_tree', '__new__', 'is_empty'] + def add_sub_tree(self, other_tree): """ Adds a sub tree to current tree. diff --git a/pydatastructs/miscellaneous_data_structures/disjoint_set.py b/pydatastructs/miscellaneous_data_structures/disjoint_set.py index 984079a4b..2c2533a27 100644 --- a/pydatastructs/miscellaneous_data_structures/disjoint_set.py +++ b/pydatastructs/miscellaneous_data_structures/disjoint_set.py @@ -30,6 +30,10 @@ def __new__(cls): obj.tree = dict() return obj + @classmethod + def methods(cls): + return ['make_set', '__new__', 'find_root', 'union'] + def make_set(self, key, data=None): """ Adds a singleton set to the tree diff --git a/pydatastructs/miscellaneous_data_structures/queue.py b/pydatastructs/miscellaneous_data_structures/queue.py index 4b2cf451c..c7b9d302e 100644 --- a/pydatastructs/miscellaneous_data_structures/queue.py +++ b/pydatastructs/miscellaneous_data_structures/queue.py @@ -55,6 +55,10 @@ def __new__(cls, implementation='array', **kwargs): raise NotImplementedError( "%s hasn't been implemented yet."%(implementation)) + @classmethod + def methods(cls): + return ['__new__'] + def append(self, *args, **kwargs): raise NotImplementedError( "This is an abstract method.") @@ -87,6 +91,11 @@ def __new__(cls, items=None, dtype=NoneType): obj.front = 0 return obj + @classmethod + def methods(cls): + return ['__new__', 'append', 'popleft', 'rear', + 'is_empty', '__len__', '__str__'] + def append(self, x): if self.is_empty: self.front = 0 @@ -143,13 +152,18 @@ def __new__(cls, items=None): raise TypeError("Expected type: list/tuple") return obj + @classmethod + def methods(cls): + return ['__new__', 'append', 'popleft', 'rear', + 'is_empty', '__len__', '__str__', 'front', 'size'] + def append(self, x): self.queue.append(x) def popleft(self): if self.is_empty: raise IndexError("Queue is empty.") - return_value = self.queue.pop_left() + return_value = self.queue.popleft() return return_value @property @@ -234,6 +248,10 @@ def __new__(cls, implementation='binary_heap', **kwargs): "%s implementation is not currently supported " "by priority queue.") + @classmethod + def methods(cls): + return ['__new__'] + def push(self, value, priority): """ Pushes the value to the priority queue @@ -275,6 +293,10 @@ class LinkedListPriorityQueue(PriorityQueue): __slots__ = ['items', 'comp'] + @classmethod + def methods(cls): + return ['__new__', 'push', 'pop', 'peek', 'is_empty'] + def __new__(cls, comp): obj = object.__new__(cls) obj.items = SinglyLinkedList() @@ -317,6 +339,10 @@ class BinaryHeapPriorityQueue(PriorityQueue): __slots__ = ['items'] + @classmethod + def methods(cls): + return ['__new__', 'push', 'pop', 'peek', 'is_empty'] + def __new__(cls, comp): obj = object.__new__(cls) obj.items = BinaryHeap() @@ -344,6 +370,10 @@ class BinomialHeapPriorityQueue(PriorityQueue): __slots__ = ['items'] + @classmethod + def methods(cls): + return ['__new__', 'push', 'pop', 'peek', 'is_empty'] + def __new__(cls): obj = object.__new__(cls) obj.items = BinomialHeap() diff --git a/pydatastructs/miscellaneous_data_structures/stack.py b/pydatastructs/miscellaneous_data_structures/stack.py index 617bb3684..96df6cf02 100644 --- a/pydatastructs/miscellaneous_data_structures/stack.py +++ b/pydatastructs/miscellaneous_data_structures/stack.py @@ -58,6 +58,10 @@ def __new__(cls, implementation='array', **kwargs): raise NotImplementedError( "%s hasn't been implemented yet."%(implementation)) + @classmethod + def methods(cls): + return ['__new__'] + def push(self, *args, **kwargs): raise NotImplementedError( "This is an abstract method.") @@ -89,6 +93,11 @@ def __new__(cls, items=None, dtype=NoneType): obj.items = items return obj + @classmethod + def methods(cls): + return ['__new__', 'push', 'pop', 'is_emtpy', + 'peek', '__len__', '__str__'] + def push(self, x): if self.is_empty: self.items._dtype = type(x) @@ -136,13 +145,18 @@ def __new__(cls, items=None): raise TypeError("Expected type: list/tuple") return obj + @classmethod + def methods(cls): + return ['__new__', 'push', 'pop', 'is_emtpy', + 'peek', '__len__', '__str__'] + def push(self, x): - self.stack.append_left(x) + self.stack.appendleft(x) def pop(self): if self.is_empty: raise IndexError("Stack is empty") - return self.stack.pop_left() + return self.stack.popleft() @property def is_empty(self): diff --git a/pydatastructs/trees/binary_trees.py b/pydatastructs/trees/binary_trees.py index 33f368534..66a659c64 100644 --- a/pydatastructs/trees/binary_trees.py +++ b/pydatastructs/trees/binary_trees.py @@ -63,6 +63,10 @@ def __new__(cls, key=None, root_data=None, comp=None, obj.is_order_statistic = is_order_statistic return obj + @classmethod + def methods(cls): + return ['__new__', '__str__'] + def insert(self, key, data=None): """ Inserts data by the passed key using iterative @@ -194,6 +198,12 @@ class BinarySearchTree(BinaryTree): pydatastructs.trees.binary_tree.BinaryTree """ + + @classmethod + def methods(cls): + return ['insert', 'search', 'delete', 'select', + 'rank', 'lowest_common_ancestor'] + left_size = lambda self, node: self.tree[node.left].size \ if node.left is not None else 0 right_size = lambda self, node: self.tree[node.right].size \ @@ -648,6 +658,11 @@ class AVLTree(SelfBalancingBinaryTree): pydatastructs.trees.binary_trees.BinaryTree """ + + @classmethod + def methods(cls): + return ['insert', 'delete'] + left_height = lambda self, node: self.tree[node.left].height \ if node.left is not None else -1 right_height = lambda self, node: self.tree[node.right].height \ @@ -766,6 +781,11 @@ class SplayTree(SelfBalancingBinaryTree): .. [1] https://en.wikipedia.org/wiki/Splay_tree """ + + @classmethod + def methods(cls): + return ['insert', 'delete', 'join', 'split'] + def _zig(self, x, p): if self.tree[p].left == x: super(SplayTree, self)._right_rotate(p, x) @@ -931,6 +951,11 @@ class BinaryTreeTraversal(object): .. [1] https://en.wikipedia.org/wiki/Tree_traversal """ + @classmethod + def methods(cls): + return ['__new__', 'depth_first_search', + 'breadth_first_search'] + __slots__ = ['tree'] def __new__(cls, tree): @@ -1119,6 +1144,11 @@ def __new__(cls, array): obj.update(index, array[index]) return obj + @classmethod + def methods(cls): + return ['update', 'get_prefix_sum', + 'get_sum'] + def update(self, index, value): """ Updates value at the given index. diff --git a/pydatastructs/trees/heaps.py b/pydatastructs/trees/heaps.py index 45d0bc4eb..1fa0e88cd 100644 --- a/pydatastructs/trees/heaps.py +++ b/pydatastructs/trees/heaps.py @@ -95,6 +95,10 @@ def __new__(cls, elements=None, heap_property="min", d=4): obj._build() return obj + @classmethod + def methods(cls): + return ['__new__', 'insert', 'extract', '__str__', 'is_empty'] + def _build(self): for i in range(self._last_pos_filled + 1): self.heap[i]._leftmost, self.heap[i]._rightmost = \ @@ -261,6 +265,10 @@ def __new__(cls, elements=None, heap_property="min"): obj = DHeap.__new__(cls, elements, heap_property, 2) return obj + @classmethod + def methods(cls): + return ['__new__'] + class TernaryHeap(DHeap): """ @@ -321,6 +329,10 @@ def __new__(cls, elements=None, heap_property="min"): obj = DHeap.__new__(cls, elements, heap_property, 3) return obj + @classmethod + def methods(cls): + return ['__new__'] + class BinomialHeap(Heap): """ @@ -362,6 +374,12 @@ def __new__(cls, root_list=[]): obj.root_list = root_list return obj + @classmethod + def methods(cls): + return ['__new__', 'merge_tree', 'merge', 'insert', + 'find_minimum', 'is_emtpy', 'decrease_key', 'delete', + 'delete_minimum'] + def merge_tree(self, tree1, tree2): """ Merges two BinomialTree objects. @@ -495,7 +513,7 @@ def delete_minimum(self): @property def is_empty(self): - return len(self.root_list) == 0 + return not self.root_list def decrease_key(self, node, new_key): """ diff --git a/pydatastructs/trees/m_ary_trees.py b/pydatastructs/trees/m_ary_trees.py index 75b622515..8f4c2ac97 100644 --- a/pydatastructs/trees/m_ary_trees.py +++ b/pydatastructs/trees/m_ary_trees.py @@ -59,6 +59,10 @@ def __new__(cls, key=None, root_data=None, comp=None, obj.is_order_statistic = is_order_statistic return obj + @classmethod + def methods(cls): + return ['__new__', '__str__'] + def insert(self, key, data=None): """ Inserts data by the passed key using iterative diff --git a/pydatastructs/trees/space_partitioning_trees.py b/pydatastructs/trees/space_partitioning_trees.py index 5b5b03324..495c714bc 100644 --- a/pydatastructs/trees/space_partitioning_trees.py +++ b/pydatastructs/trees/space_partitioning_trees.py @@ -56,6 +56,10 @@ def __new__(cls, segs): obj.tree, obj.root_idx, obj.cache = [], None, False return obj + @classmethod + def methods(cls): + return ['build', 'query', '__str__'] + def _union(self, i1, i2): """ Helper function for taking union of two diff --git a/pydatastructs/utils/tests/test_code_quality.py b/pydatastructs/utils/tests/test_code_quality.py index 7bdc3527c..8dd444291 100644 --- a/pydatastructs/utils/tests/test_code_quality.py +++ b/pydatastructs/utils/tests/test_code_quality.py @@ -71,14 +71,45 @@ def test_presence_of_tabs(): "white spaces."%(line, file_path) file.close() +def _apis(): + import pydatastructs as pyds + return [ + pyds.graphs.adjacency_list.AdjacencyList, + pyds.graphs.adjacency_matrix.AdjacencyMatrix, + pyds.DoublyLinkedList, pyds.SinglyLinkedList, + pyds.SinglyCircularLinkedList, + pyds.DoublyCircularLinkedList, + pyds.OneDimensionalArray, + pyds.DynamicOneDimensionalArray, + pyds.trees.BinaryTree, pyds.BinarySearchTree, + pyds.AVLTree, pyds.SplayTree, pyds.BinaryTreeTraversal, + pyds.DHeap, pyds.BinaryHeap, pyds.TernaryHeap, pyds.BinomialHeap, + pyds.MAryTree, pyds.OneDimensionalSegmentTree, + pyds.Queue, pyds.miscellaneous_data_structures.queue.ArrayQueue, + pyds.miscellaneous_data_structures.queue.LinkedListQueue, + pyds.PriorityQueue, + pyds.miscellaneous_data_structures.queue.LinkedListPriorityQueue, + pyds.miscellaneous_data_structures.queue.BinaryHeapPriorityQueue, + pyds.miscellaneous_data_structures.queue.BinomialHeapPriorityQueue, + pyds.Stack, pyds.miscellaneous_data_structures.stack.ArrayStack, + pyds.miscellaneous_data_structures.stack.LinkedListStack, + pyds.DisjointSetForest, pyds.BinomialTree, pyds.TreeNode, pyds.MAryTreeNode, + pyds.LinkedListNode, pyds.BinomialTreeNode, pyds.AdjacencyListGraphNode, + pyds.AdjacencyMatrixGraphNode, pyds.GraphEdge, pyds.Set, pyds.BinaryIndexedTree] + def test_public_api(): pyds = pydatastructs - public_api = dir(pydatastructs) - for name in public_api: - if inspect.isclass(getattr(pyds, name)): - _class = getattr(pyds, name) + apis = _apis() + for name in apis: + if inspect.isclass(name): + _class = name mro = _class.__mro__ must_methods = _class.methods() + print("\n" + str(name)) + print("Methods Implemented") + print(must_methods) + print("Parent Classes") + print(mro[1:]) for supercls in mro: if supercls != _class: for method in must_methods: From 0e84710a520597736680961e6d2cc9e49ba459a5 Mon Sep 17 00:00:00 2001 From: czgdp1807 Date: Mon, 20 Apr 2020 15:30:26 +0530 Subject: [PATCH 3/3] added verbose logs --- pydatastructs/utils/tests/test_code_quality.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pydatastructs/utils/tests/test_code_quality.py b/pydatastructs/utils/tests/test_code_quality.py index 8dd444291..350100f5d 100644 --- a/pydatastructs/utils/tests/test_code_quality.py +++ b/pydatastructs/utils/tests/test_code_quality.py @@ -100,6 +100,8 @@ def _apis(): def test_public_api(): pyds = pydatastructs apis = _apis() + print("\n\nAPI Report") + print("==========") for name in apis: if inspect.isclass(name): _class = name