Skip to content
This repository was archived by the owner on Oct 5, 2025. It is now read-only.

Commit 04e1b45

Browse files
committed
2 parents e977e29 + f467696 commit 04e1b45

File tree

5 files changed

+175
-68
lines changed

5 files changed

+175
-68
lines changed

README.md

Lines changed: 72 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -47,61 +47,78 @@ Currently, the bot can answer the following questions. The numbers map directly
4747
9. "What is an expression tree?" by Jeremy Grifski
4848
10. "What is confidence building?" by Jeremy Grifski
4949
11. "What is the declared type of a variable?" by Jeremy Grifski
50-
12. "What is method overriding?" by Jeremy Grifski, Le Chang, Zihe Fang, Alexia Scarvelli, Tae Yeon Kim
51-
13. "What is method overloading?" by Jeremy Grifski
52-
14. "What is the implements relationship?" by Jeremy Grifski, Yibo Gan
53-
15. "What is the extends relationship?" by Jeremy Grifski
54-
16. "What is a mathematical string?" by Jeremy Grifski
55-
17. "What is mathematical string notation for concatenation?" by Jeremy Grifski
56-
18. "What is a parameter mode?" by Jeremy Grifski
57-
19. "What is restores mode?" by Jeremy Grifski
58-
20. "What is a queue?" by Jeremy Grifski
59-
21. "What is a set?" by Jeremy Grifski
60-
22. "What is a stack?" by Jeremy Grifski
61-
23. "What does FIFO mean?" by Jeremy Grifski
62-
24. "What does LIFO mean?" by Jeremy Grifski
63-
25. "What is the object type of a variable?" by Kelvin Nguyen
64-
26. "What is an immutable type?" by Jacob Skarsten, Ziqing Zhao
65-
27. "What is replaces mode?" by Shaan Patel
66-
28. "What is updates mode?" by Colin Russel
67-
29. "Are arrays immutable or mutable?" by Jessica Molitor
68-
30. "What is inheritance?" by Xingzhi Dai
69-
31. "What is clears mode?" by Ethan Chilton
70-
32. "What is the default parameter mode when none is specified in the method contract?" by Dan Brace
71-
33. "What is the drawback and/or problem with aliasing?" by Michael Grady
72-
34. "What is a superclass?" by Ben Janita
73-
35. "Will you be my girlfriend?" by Ben Janita
74-
36. "What is an interface?" by Chenmeinian Guo, Tim Keck
75-
37. "Is testing an expensive waste of time?" by Jason Su
76-
38. "What is the purpose of the queue data structure?" by Ying Liang
77-
39. "What is Recursion?" by Gani Sagiev, Tim Keck
78-
40. "What is the difference between unit and integration testing?" by Jacob Kolaczkowski
79-
41. "What is the difference between testing and debugging?" by John DiFilippo, Ahmed Mohamed
80-
42. "What is object-oriented-programming?" by Felix Ji
81-
43. "What type of method is a JUnit test case?" by Matthew Alfieri
82-
44. "What is aliasing?" by Yuhang Huang
83-
45. "Is XML a mutable or immutable type?" by Drishti Mittal
84-
46. "Is a string a mutable or immutable type?" by Grant McGeehen
85-
47. "What is the difference between copyFrom and transferFrom?" by Jashira Herrera Brito
86-
48. "What is the purpose of testing and what can it not prove?" by Nick Cheong
87-
49. "What does the method `.divide()` for NaturalNumber return?" by Kate Goertz
88-
50. "What is the benefit of interval halving?" by Ashir Faruq
89-
51. "What is mathematical induction?" by Om Amin
90-
52. "What is the Set data type?" by Luke Thompson
91-
53. "What is the correct expression to see if an integer is odd in Java?" by Kurt Wanner
92-
54. "What is XML?" by Tim Keck
93-
55. "What is mutability?" by Tim Keck
94-
56. "What is a comparator?" by Tim Keck
95-
57. "What is a method contract?" by Tim Keck
96-
58. "How do I trace a variable through a recursive method?" by Tim Keck
97-
59. "What is the difference between a remainder and a modulus?" by Darrel Jobin
98-
60. "What are the four parameter modes?" by Darrel Jobin
99-
61. "What are NaturalNumberKernal's three methods?" by Alyssa Wiegman, Catherine Wu
100-
62. "What is a procedure?" by Amit Bharathan
101-
63. "What is the implementer's role?" by Daniel Han
102-
64. "What is the Standard interface?" by Andrew Nida
103-
65. "What are some ways to iterate over non-ordered data structures like sets?" by Josh Grismer
104-
66. "Is restores mode a default parameter mode?" by Allen Zhang
50+
12. "What is the static type of a variable?" by Jeremy Grifski
51+
13. "What is method overriding?" by Jeremy Grifski, Le Chang, Zihe Fang, Alexia Scarvelli, Tae Yeon Kim
52+
14. "What is method overloading?" by Jeremy Grifski
53+
15. "What is the implements relationship?" by Jeremy Grifski, Yibo Gan
54+
16. "What is the extends relationship?" by Jeremy Grifski, Yi-You (Joseph) Chiu
55+
17. "What is a mathematical string?" by Jeremy Grifski
56+
18. "What is mathematical string notation for concatenation?" by Jeremy Grifski
57+
19. "What is a parameter mode?" by Jeremy Grifski
58+
20. "What is restores mode?" by Jeremy Grifski
59+
21. "What is a queue?" by Jeremy Grifski
60+
22. "What is a set?" by Jeremy Grifski
61+
23. "What is a stack?" by Jeremy Grifski
62+
24. "What does FIFO mean?" by Jeremy Grifski
63+
25. "What does LIFO mean?" by Jeremy Grifski
64+
26. "What is the object type of a variable?" by Kelvin Nguyen
65+
27. "What is an immutable type?" by Jacob Skarsten, Ziqing Zhao
66+
28. "What is replaces mode?" by Shaan Patel
67+
29. "What is updates mode?" by Colin Russel
68+
30. "Are arrays immutable or mutable?" by Jessica Molitor
69+
31. "What is inheritance?" by Xingzhi Dai
70+
32. "What is clears mode?" by Ethan Chilton
71+
33. "What is the default parameter mode when none is specified in the method contract?" by Dan Brace
72+
34. "What is the drawback and/or problem with aliasing?" by Michael Grady
73+
35. "What is a superclass?" by Ben Janita
74+
36. "Will you be my girlfriend?" by Ben Janita
75+
37. "What is an interface?" by Chenmeinian Guo, Tim Keck
76+
38. "Is testing an expensive waste of time?" by Jason Su
77+
39. "What is the purpose of the queue data structure?" by Ying Liang
78+
40. "What is Recursion?" by Gani Sagiev, Tim Keck
79+
41. "What is the difference between unit and integration testing?" by Jacob Kolaczkowski
80+
42. "What is the difference between testing and debugging?" by John DiFilippo, Ahmed Mohamed
81+
43. "What is object-oriented programming (OOP)?" by Felix Ji
82+
44. "What type of method is a JUnit test case?" by Matthew Alfieri
83+
45. "What is aliasing?" by Yuhang Huang
84+
46. "Is XMLTree a mutable or immutable type?" by Drishti Mittal
85+
47. "Is a string a mutable or immutable type?" by Grant McGeehen
86+
48. "What is the difference between copyFrom and transferFrom?" by Jashira Herrera Brito
87+
49. "What is the purpose of testing and what can it not prove?" by Nick Cheong
88+
50. "What does the method `.divide()` for NaturalNumber return?" by Kate Goertz
89+
51. "What is the benefit of interval halving?" by Ashir Faruq
90+
52. "What is mathematical induction?" by Om Amin
91+
53. "What is the Set data type?" by Luke Thompson
92+
54. "What is the correct expression to see if an integer is odd in Java?" by Kurt Wanner, Yi-You (Joseph) Chiu
93+
55. "What is XML?" by Tim Keck
94+
56. "What is mutability?" by Tim Keck
95+
57. "What is a comparator?" by Tim Keck
96+
58. "What is a method contract?" by Tim Keck
97+
59. "How do I trace a variable through a recursive method?" by Tim Keck
98+
60. "What is the difference between a remainder and a modulus?" by Darrel Jobin
99+
61. "What are the four parameter modes?" by Darrel Jobin
100+
62. "What are NaturalNumberKernel's three methods?" by Alyssa Wiegman, Catherine Wu
101+
63. "What is a procedure?" by Amit Bharathan
102+
64. "What is the implementer's role?" by Daniel Han
103+
65. "What is the Standard interface?" by Andrew Nida
104+
66. "What are some ways to iterate over non-ordered data structures like sets?" by Josh Grismer
105+
67. "Is restores mode a default parameter mode?" by Allen Zhang
106+
68. "What is the difference between parameter and argument?" by Lucas Curran
107+
69. "What is the difference between an expression and a statement?" by Peter Sung
108+
70. "What is API?" by Yingqi Gao
109+
71. "What is a boolean?" by Oliver Gwynn
110+
72. "What is the difference between a public and private method?" by Sammy Schwartz
111+
73. "What is design by contract for?" by Darin Renusch
112+
74. "What is RSS?" by Andy Vong
113+
75. "What is the difference between inheritance and polymorphism?" by Jatin Mamtani
114+
76. "What is a precondition?" by Akshaya Iyer
115+
77. "What is short-circuit evaluation?" by Junbo Chen
116+
78. "What makes two if statements independent?" by Jarrett Reeves, Jeremy Grifski
117+
79. "What is polymorphism?" by Angstrom Sarkar
118+
80. "Why can't interfaces have constructors?" by Yingqi Gao
119+
81. "What is abstraction?" by Yingqi Gao
120+
82. "What is the difference between interface and abstract class?" by Yingqi Gao
121+
83. "When should I use newInstance?" by Shivam Engineer
105122

106123
---
107124

pymon.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import logging
12
import os
3+
import pathlib
4+
from logging.handlers import RotatingFileHandler
25

36
import discord
47
from discord import Message
@@ -8,9 +11,27 @@
811

912
import pymon_utils as utils
1013

11-
__version__ = "0.5.0"
14+
__version__ = "0.6.0"
1215

1316

17+
# Setup logging
18+
logs_path = pathlib.Path(
19+
os.path.abspath(os.path.dirname(__file__)),
20+
"logs"
21+
)
22+
logs_path.mkdir(parents=True, exist_ok=True)
23+
logging.basicConfig(
24+
handlers=[RotatingFileHandler(
25+
logs_path / "bot.log",
26+
backupCount=10,
27+
maxBytes=1000000
28+
)],
29+
level=logging.DEBUG,
30+
format='%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
31+
datefmt='%Y-%m-%d:%H:%M:%S',
32+
)
33+
log = logging.getLogger(__name__)
34+
1435
# Global variables
1536
client = commands.Bot(
1637
command_prefix=commands.when_mentioned_or("!"),
@@ -168,4 +189,5 @@ async def _refresh(ctx):
168189
await ctx.send(f"{len(diff)} queries modified and/or added.")
169190

170191

171-
client.run(os.environ.get("DISCORD_TOKEN"))
192+
if __name__ == '__main__':
193+
client.run(os.environ.get("DISCORD_TOKEN"))

pymon_utils.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import json
2+
import logging
23
import os
34
import string
45
from urllib.request import urlopen
56

67
from dotenv import load_dotenv
78

9+
log = logging.getLogger(__name__)
10+
811

912
def generate_keyword_mapping(queries: list) -> dict:
1013
"""
@@ -13,6 +16,7 @@ def generate_keyword_mapping(queries: list) -> dict:
1316
:param queries: a list of queries with responses
1417
:return: a dictionary of keywords to query indices
1518
"""
19+
log.debug(f"Generating keyword mapping from following list: {queries}")
1620
keyword_to_queries = dict()
1721
for i, question in enumerate(queries):
1822
if question.get('query'):
@@ -26,6 +30,7 @@ def generate_keyword_mapping(queries: list) -> dict:
2630
keyword_to_queries.setdefault(keyword, {})
2731
keyword_to_queries[keyword].setdefault(i, 0)
2832
keyword_to_queries[keyword][i] += 1
33+
log.debug(f"Generated keyword mapping as follows: {keyword_to_queries}")
2934
return keyword_to_queries
3035

3136

@@ -36,14 +41,16 @@ def generate_keywords(query: string) -> list:
3641
:param query: a search query
3742
:return: the list of keywords from that query
3843
"""
44+
log.debug(f"Generating keywords from following query: {query}")
3945
stop_words = ["", "is", "a", "the", "can",
4046
"i", "to", "in", "by", "from", "be", "of",
41-
"what", "where", "when", "why", "how", "which"]
47+
"what", "where", "when", "why", "how", "which", "and"]
4248
keywords = query \
4349
.translate(str.maketrans('', '', string.punctuation)) \
4450
.lower() \
4551
.split(" ")
4652
keywords = [word for word in keywords if word not in stop_words]
53+
log.debug(f"Generated list of keywords as follows: {keywords}")
4754
return keywords
4855

4956

@@ -55,14 +62,18 @@ def search(keyword_to_queries: dict, keywords: list) -> list:
5562
:param keywords: a list of keywords to lookup
5663
:return: a list of query indices
5764
"""
65+
log.debug(f"Searching for matching queries from the following list of keywords: {keywords}")
5866
query_count = dict()
5967
for keyword in keywords:
6068
query_indices = keyword_to_queries.get(keyword, {})
6169
for i, weight in query_indices.items():
6270
query_count.setdefault(i, 0)
6371
query_count[i] += weight
64-
best_matches = list(
65-
dict(sorted(query_count.items(), key=lambda item: item[1], reverse=True)).keys())
72+
log.debug(f"Generated dictionary of query counts: {query_count}")
73+
best_matches = list(dict(
74+
sorted(query_count.items(), key=lambda item: item[1], reverse=True)
75+
).keys())
76+
log.debug(f"Found closest matches as follows: {best_matches}")
6677
return best_matches
6778

6879

@@ -73,12 +84,14 @@ def generate_similar_queries(queries: list, keyword_to_queries: dict) -> None:
7384
:param queries: a list of queries
7485
:param keyword_to_queries: a mapping of keywords to query indices
7586
"""
87+
log.debug("Adding similar_queries field to queries list")
7688
for i, query in enumerate(queries):
7789
if i > 0:
7890
keywords = generate_keywords(query["query"])
7991
top_ids = search(keyword_to_queries, keywords)
8092
top_ids.remove(i)
8193
query["similar_queries"] = top_ids
94+
log.debug(f"Updated query to include similar queries: {query}")
8295

8396

8497
def create_md_link(url: string, text: string) -> string:
@@ -89,6 +102,7 @@ def create_md_link(url: string, text: string) -> string:
89102
:param text: the text to display
90103
:return: the markdown link
91104
"""
105+
log.debug(f"Creating markdown link from url ({url}) and text ({text}).")
92106
if url:
93107
return f"[{text}]({url})"
94108
return text
@@ -104,6 +118,7 @@ def load_knowledge() -> tuple[int, list]:
104118
:return: a tuple of the type of knowledge database and the
105119
knowledge database (0 for remote, 1 for local, 2 for default)
106120
"""
121+
log.debug("Loading Pymon's brain from knowledge path.")
107122
if path := os.environ.get("KNOWLEDGE_PATH"):
108123
try:
109124
data = urlopen(path).read().decode("utf-8")
@@ -123,6 +138,7 @@ def refresh_knowledge() -> tuple[list, dict]:
123138
:return: a tuple of the knowledge database and a mapping of
124139
keywords to query indices
125140
"""
141+
log.debug("Refreshes Pymon's brain assuming new data exists.")
126142
load_dotenv()
127143
_, queries = load_knowledge()
128144
keyword_mapping = generate_keyword_mapping(queries)
@@ -138,10 +154,12 @@ def generate_tags_set(queries: list) -> set:
138154
:param queries: the list of queries from Pymon's brain
139155
:return: a set of tags represented in Pymon's brain
140156
"""
157+
log.debug(f"Generating the unique set of tags from following list of queries: {queries}")
141158
tags = set()
142159
for query in queries:
143160
query_tags = query.get("tags", [])
144161
tags |= set(query_tags)
162+
log.debug(f"Generated list of unique tags as follows: {tags}")
145163
return tags
146164

147165

@@ -154,8 +172,10 @@ def get_queries_from_tag(queries: list, tag: str) -> list[tuple[int, dict]]:
154172
:param tag: a tag to lookup
155173
:return: a list of tuples in the form (query ID, query)
156174
"""
175+
log.debug(f"Getting set of queries that include the following tag: {tag}")
157176
matches = list()
158177
for i, query in enumerate(queries):
159178
if tag in query.get("tags", []):
160179
matches.append((i, query))
180+
log.debug(f"Found queries that match tag as follows: {matches}")
161181
return matches

0 commit comments

Comments
 (0)