Skip to content

Commit 9c75f28

Browse files
committed
bug fixes & improvements
- Resolved bugs where tags were getting reset by by computing in-degree and out-degree - getInsights() interfaced with analyze.py - Minor updates Glad I learned Graph Theory 😅
1 parent d2d43cd commit 9c75f28

File tree

4 files changed

+78
-49
lines changed

4 files changed

+78
-49
lines changed

plagcheck/analyze.py

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
1+
"""
2+
analyze.py
3+
====================================
4+
The Analysis Module for Moss
5+
(For info. on how this works contact [email protected])
6+
"""
7+
8+
19
class Node:
2-
"""A Single Sdubmitted file"""
10+
"""A Single Submitted file"""
311

412
def __init__(self, name):
513
self.name = name
6-
self.perc = []
714
self.tag = None
815
self.links = []
916

1017

1118
class Mgroups:
12-
"""A directed graph consisting all individual solutions"""
19+
"""A Disconnected directed graph consisting all individual solutions"""
1320

1421
linkCount = 0
1522

@@ -18,30 +25,48 @@ def __init__(self):
1825
self.nodeCount = 0
1926

2027
def relatesTo(self, P1, P2, node1, node2):
21-
node_dict = {}
28+
"""Set a path between two file nodes"""
29+
node_obj_dict = {}
2230

2331
for r in self.nodes:
24-
node_dict[r.name] = r
32+
node_obj_dict[r.name] = r
2533

26-
if node1 in node_dict.keys() and node2 in node_dict.keys():
27-
if P1 < P2 and (node_dict[node1].tag and node_dict[node2].tag not in ["D", "C"]):
28-
node_dict[node1].tag = "D"
29-
node_dict[node2].tag = "C"
30-
node_dict[node1].links.append(node_dict[node2])
34+
if node1 in node_obj_dict.keys() and node2 in node_obj_dict.keys():
35+
if P1 < P2:
36+
node_obj_dict[node1].links.append(node_obj_dict[node2])
3137
elif P1 > P2:
32-
node_dict[node1].tag = "C"
33-
node_dict[node2].tag = "D"
34-
node_dict[node2].links.append(node_dict[node1])
38+
node_obj_dict[node2].links.append(node_obj_dict[node1])
3539
else:
36-
node_dict[node1].tag = "DC"
37-
node_dict[node2].tag = "DC"
38-
node_dict[node1].links.append(node_dict[node2])
40+
node_obj_dict[node1].links.append(node_obj_dict[node2])
3941

40-
node_dict[node1].perc.append(P1)
41-
node_dict[node2].perc.append(P2)
4242
Mgroups.linkCount += 1
4343

44+
def __indegree(self, node: Node):
45+
indegree_count = 0
46+
for n in self.nodes:
47+
for link in n.links:
48+
if link.name == node.name:
49+
indegree_count += 1
50+
return indegree_count
51+
52+
def __outdegree(self, node: Node):
53+
return len(node.links)
54+
55+
def set_tags(self):
56+
"""Assign appropriate tag to a Node"""
57+
for node in self.nodes:
58+
in_degree = self.__indegree(node)
59+
out_degree = self.__outdegree(node)
60+
61+
if in_degree == 0 and out_degree > 0:
62+
node.tag = "D"
63+
elif in_degree > 0 and out_degree == 0:
64+
node.tag = "C"
65+
elif in_degree != 0 and out_degree != 0:
66+
node.tag = "DC"
67+
4468
def createNodes(self, node_set: set):
69+
"""Create multiple nodes at the same time"""
4570
for n in node_set:
4671
self.addNode(n)
4772

@@ -52,15 +77,16 @@ def addNode(self, name: str):
5277
self.nodeCount += 1
5378
return node
5479

55-
def allNodes(self):
80+
def displayNodes(self):
5681
return [r.name for r in self.nodes]
5782

5883
def displayTags(self):
84+
"""Display Nodes with their Tags"""
5985
for node in self.nodes:
6086
print("{}, tag = {}".format(node.name, node.tag))
6187

6288
def d2c(self):
63-
# All Direct Distributor to Culprit paths
89+
"""All Direct Distributor to Culprit paths"""
6490
paths = []
6591
for node in self.nodes:
6692
for link in node.links:
@@ -69,7 +95,7 @@ def d2c(self):
6995
return paths
7096

7197
def d2dc(self):
72-
# All Direct Distributor to potential Distributor-Culprit paths
98+
"""All Direct Distributor to potential Distributor-Culprit paths"""
7399
paths = []
74100
for node in self.nodes:
75101
for link in node.links:
@@ -78,7 +104,7 @@ def d2dc(self):
78104
return paths
79105

80106
def dc2c(self):
81-
# All potential Distributor-Culprit to direct Culprit paths
107+
"""All potential Distributor-Culprit to direct Culprit paths"""
82108
paths = []
83109
for node in self.nodes:
84110
for link in node.links:
@@ -87,27 +113,9 @@ def dc2c(self):
87113
return paths
88114

89115
def __repr__(self):
116+
"""Pretty prints the graph"""
90117
paths = ""
91118
for node in self.nodes:
92119
for link in node.links:
93120
paths += "{0} --> {1}\n".format(node.name, link.name)
94121
return paths
95-
96-
97-
# mg = Mgroups()
98-
# mg.createNodes({'1', '2', '3', '4', '5', '6', '7'})
99-
100-
# mg.relatesTo(45, 88, '3', '1')
101-
# mg.relatesTo(46, 90, '3', '2')
102-
# mg.relatesTo(34, 64, '3', '4')
103-
# mg.relatesTo(34, 64, '3', '5')
104-
# mg.relatesTo(64, 66, '4', '2')
105-
# mg.relatesTo(64, 66, '5', '2')
106-
# mg.relatesTo(94, 94, '4', '5')
107-
# mg.relatesTo(33, 61, '7', '6')
108-
109-
# print(mg)
110-
# print(mg.allNodes())
111-
# print("D to C paths\n", mg.d2c())
112-
# print("D to DC paths\n", mg.d2dc())
113-
# print("DC to C paths\n", mg.dc2c())

plagcheck/plagcheck.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import collections
77
import mosspy
88
from bs4 import BeautifulSoup as bs
9+
from plagcheck.analyze import Mgroups
910

1011
HEADERS = {"User-Agent": "Mozilla/5.0"}
1112

@@ -82,7 +83,6 @@ def __extract_info(self) -> Results:
8283
percentage_file2=perc_str_to_int(perc2),
8384
no_of_lines_matched=int(col3.text.strip()),
8485
lines_matched=lines,
85-
# lines_matched=self.__get_line_numbers(col1.a.get("href")),
8686
)
8787
results.append(result_dict)
8888
return results
@@ -132,7 +132,7 @@ def getResults(self) -> Tuple[str, Results]:
132132
return self.moss_results
133133

134134
def getShareScores(self):
135-
"""Share Score Insights WIP"""
135+
"""Share Score Insights"""
136136
similar_code_files = []
137137
for result in self.moss_results:
138138
similar_code_files.append(result['file1'])
@@ -142,3 +142,26 @@ def getShareScores(self):
142142
share_score = collections.Counter(similar_code_files)
143143

144144
return dict(share_score)
145+
146+
def getInsights(self):
147+
"""Analysis for Moss"""
148+
mg = Mgroups()
149+
similar_code_files = set()
150+
insights = {}
151+
152+
for r in self.moss_results:
153+
similar_code_files.add(r['file1'])
154+
similar_code_files.add(r['file2'])
155+
156+
mg.createNodes(similar_code_files)
157+
158+
for r in self.moss_results:
159+
mg.relatesTo(r['percentage_file1'], r['percentage_file2'], r['file1'], r['file2'])
160+
161+
mg.set_tags()
162+
163+
insights["DtoC Paths"] = mg.d2c()
164+
insights["DtoDC Paths"] = mg.d2dc()
165+
insights["DCtoC Paths"] = mg.dc2c()
166+
167+
return insights

plagcheck/plagcheck_test.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44

55
def test_check():
66
"""General test"""
7-
program_files = ["testfiles/test_python.py", "testfiles/test_python3.py"]
8-
language = "python"
7+
language = "java"
98
userid = "1"
109
temp = plagcheck.check(language, userid)
11-
temp.addFile("testfiles/test_python.py")
12-
temp.addFile("testfiles/test_python3.py")
10+
temp.addFilesByWildCard("testfiles/test_java*.java")
1311
temp.submit()
1412
results = temp.getResults()
1513

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
license="MIT",
1010
author="Bhupesh Varshney",
1111
author_email="[email protected]",
12-
description="Check your programs for plagiarism",
13-
keywords="moss plagiarism mosspy cheat",
12+
description="Moss scraper with powerful insights",
13+
keywords="moss plagiarism analysis cheat mosspy",
1414
long_description=long_description,
1515
long_description_content_type="text/markdown",
1616
url="https://github.com/codeclassroom/PlagCheck",

0 commit comments

Comments
 (0)