From a8a5de36f217cbfa980ade23bec3660acb101f2d Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Tue, 9 Oct 2018 02:50:06 -0400 Subject: [PATCH 1/5] idk --- Code/irc/banterbot.py | 3 +- Code/irc/madlibbot/madlibbot.py | 4 +- Code/irc/tildebot.py | 44 ++++------ Code/irc/util.py | 147 ++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 30 deletions(-) create mode 100644 Code/irc/util.py diff --git a/Code/irc/banterbot.py b/Code/irc/banterbot.py index 198e185..374c20e 100755 --- a/Code/irc/banterbot.py +++ b/Code/irc/banterbot.py @@ -28,6 +28,7 @@ import tumblr import xkcdApropos import wikiphilosophy import acronymFinder +import util from whosaid import whoSaid parser = OptionParser() @@ -266,7 +267,7 @@ def listen(botnick): if ircmsg[:4] == "PING": ping(ircmsg.split(" ")[1]) - formatted = formatter.format_message(ircmsg) + formatted = util.format_message(ircmsg) if "" == formatted: continue diff --git a/Code/irc/madlibbot/madlibbot.py b/Code/irc/madlibbot/madlibbot.py index 3e20153..c7b02ac 100755 --- a/Code/irc/madlibbot/madlibbot.py +++ b/Code/irc/madlibbot/madlibbot.py @@ -12,7 +12,7 @@ import time import re import operator -import msgformatter +from .. import util import madlib class State: @@ -215,7 +215,7 @@ def listen(botnick): if ircmsg[:4] == "PING": ping(ircmsg.split(" ")[1]) - formatted = msgformatter.format_message(ircmsg) + formatted = util.format_message(ircmsg) if "" == formatted: continue # print formatted diff --git a/Code/irc/tildebot.py b/Code/irc/tildebot.py index 252b059..fe10630 100755 --- a/Code/irc/tildebot.py +++ b/Code/irc/tildebot.py @@ -17,6 +17,7 @@ import mentions import pretty_date import inflect import puzzle +import util parser = OptionParser() @@ -36,23 +37,11 @@ JACKPOT_FILE = "tildejackpot.txt" JACKPOT_MIN = 3 DEBUG = False -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) - -def sendmsg(chan , msg): - ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n") - -def joinchan(chan): - ircsock.send("JOIN "+ chan +"\n") - def hello(): - ircsock.send("PRIVMSG "+ channel +" :Hello!\n") + util.sendmsg(ircsock, channel, "Hello!") def too_recent(time1, time2): - if(int(time1) - int(time2) < 60*60): - return True - else: - return False + return int(time1) - int(time2) < 60*60 def get_positive(): return random.choice(['Yes', 'Yep', 'Yeppers', 'Correct','You got it', 'Yeah', 'Right on', 'Uh-huh', 'Positive', 'Totally right', 'Close enough', 'That\'s it']) @@ -98,7 +87,7 @@ def get_prize(name, isHuman, bonus=0): def show_jackpot(channel): with open(JACKPOT_FILE, "r") as jackpotfile: jackpot = int(jackpotfile.readline().strip("\n")) - ircsock.send("PRiVMSG " + channel + " :The jackpot is currently " + p.number_to_words(jackpot) + " tildes!\n") + util.sendmsg(ircsock, channel, "The jackpot is currently {} tildes!".format(p.number_to_words(jackpot))) def give_tilde(channel, user, name, time, human, bonus=0): found = False @@ -111,15 +100,15 @@ def give_tilde(channel, user, name, time, human, bonus=0): if(person[0] == user): found = True if(too_recent(time, person[2]) and not DEBUG): - ircsock.send("PRIVMSG " + channel + " :" + name + " asked for a tilde too recently and " + get_bad_thing() + ". Try again later.\n") + util.sendmsg(ircsock, channel, "{} asked for a tilde too recently and {}. Try again later.".format(name, get_bad_thing())) else: prize = get_prize(name, human, bonus) score = person[0] + "&^%" + str(int(person[1]) + prize[0]) + "&^%" + time + "\n" - ircsock.send("PRIVMSG " + channel + " :" + prize[1] + "\n") + util.sendmsg(ircsock, channel, prize[1]) scorefile.write(score) if(not found): prize = get_prize(name, True, bonus) - ircsock.send("PRIVMSG " + channel + " :Welcome to the tilde game! Here's " + p.number_to_words(prize[0]+1) + " free tilde(s) to start you off.\n") + util.sendmsg(ircsock, channel, "Welcome to the tilde game! Here's {} free tilde(s) to start you off.".format(p.number_to_words(prize[0]+1))) scorefile.write(user + "&^%" + str(prize[0]+1) + "&^%" + time + "\n") def show_tildescore(channel, user, name): @@ -127,19 +116,19 @@ def show_tildescore(channel, user, name): for idx,score in enumerate(scorefile): person = score.strip("\n").split("&^%") if(person[0] == user): - ircsock.send("PRIVMSG " + channel + " :" + name + " has " + p.number_to_words(person[1]) + " tildes!\n") + util.sendmsg(ircsock, channel, "{} has {} tildes!".format(name, p.number_to_words(person[1]))) return #person has not played yet - ircsock.send("PRIVMSG " + channel + " :" + name + " has no tildes yet!\n") + util.sendmsg(ircsock, channel, "{} has no tildes yet!".format(name)) def challenge(channel, user, name, time): if(channel != "#bots" and not DEBUG): - ircsock.send("PRIVMSG " + channel + " :" + name + " is a meanie and gets no tildes. **Tildebot now only gives out tildes in the #bots channel.**\n") + util.sendmsg(ircsock, channel, "{} is a meanie and gets no tildes. **Tildebot now only gives out tildes in the #bots channel.**".format(name)) return global challenges; challenge = puzzle.make_puzzle(); challenges[user] = challenge[1:]; #challenges[USER] = [ANSWER, BONUS] - ircsock.send("PRIVMSG " + channel + " :" + name + ": " + challenge[0] + "\n") + util.sendmsg(ircsock, channel, "{}: {}".format(name, challenge[1])) def challenge_response(channel, user, name, time, msg): global challenges @@ -155,12 +144,13 @@ def challenge_response(channel, user, name, time, msg): def rollcall(channel): - ircsock.send("PRIVMSG "+ channel +" :tildebot reporting! I respond to !tilde !tildescore\n") + util.sendmsg(ircsock, channel, "tildebot reporting! I respond to !tilde !tildescore") def connect(server, channel, botnick): ircsock.connect((server, 6667)) - ircsock.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :krowbar\n") # user authentication - ircsock.send("NICK "+ botnick +"\n") + ircsock.send("USER {0} {0} {0} :krowbar\r\n".format(botnick)) # user authentication + ircsock.send("NICK {}\r\n".format(botnick)) + ircsock.send("MODE +B {}\r\n".format(botnick)) joinchan(channel) if(not DEBUG): @@ -182,7 +172,7 @@ def listen(): msg = msg.strip('\n\r') if msg[:4] == "PING": - ping(msg.split(" ")[1]) + util.ping(ircsock, msg) formatted = formatter.format_message(msg) @@ -214,7 +204,7 @@ def listen(): rollcall(channel) if msg[:4] == "PING": - ping(msg.split(" ")[1]) + util.ping(ircsock, msg) sys.stdout.flush() time.sleep(1) diff --git a/Code/irc/util.py b/Code/irc/util.py new file mode 100644 index 0000000..2a6a86e --- /dev/null +++ b/Code/irc/util.py @@ -0,0 +1,147 @@ +import time +import re + + +def ping(pong): + ircsock.send("PONG {}\n".format(pong.split(" ")[1])) + +def sendmsg(ircsock, chan , msg): + ircsock.send("PRIVMSG {} :{}\r\n".format(chan, msg)) + +def joinchan(ircsock, chan): + ircsock.send("JOIN {}\n".format(chan)) + +# integer number to english word conversion +# can be used for numbers as large as 999 vigintillion +# (vigintillion --> 10 to the power 60) +# tested with Python24 vegaseat 07dec2006 +def int2word(n): + """ + convert an integer number n into a string of english words + """ + # break the number into groups of 3 digits using slicing + # each group representing hundred, thousand, million, billion, ... + n3 = [] + r1 = "" + # create numeric string + ns = str(n) + for k in range(3, 33, 3): + r = ns[-k:] + q = len(ns) - k + # break if end of ns has been reached + if q < -2: + break + else: + if q >= 0: + n3.append(int(r[:3])) + elif q >= -1: + n3.append(int(r[:2])) + elif q >= -2: + n3.append(int(r[:1])) + r1 = r + + #print n3 # test + + # break each group of 3 digits into + # ones, tens/twenties, hundreds + # and form a string + nw = "" + for i, x in enumerate(n3): + b1 = x % 10 + b2 = (x % 100)//10 + b3 = (x % 1000)//100 + #print b1, b2, b3 # test + if x == 0: + continue # skip + else: + t = thousands[i] + if b2 == 0: + nw = ones[b1] + t + nw + elif b2 == 1: + nw = tens[b1] + t + nw + elif b2 > 1: + nw = twenties[b2] + ones[b1] + t + nw + if b3 > 0: + nw = ones[b3] + "hundred " + nw + return nw +############# globals ################ +ones = ["", "one ","two ","three ","four ", "five ", + "six ","seven ","eight ","nine "] +tens = ["ten ","eleven ","twelve ","thirteen ", "fourteen ", + "fifteen ","sixteen ","seventeen ","eighteen ","nineteen "] +twenties = ["","","twenty ","thirty ","forty ", + "fifty ","sixty ","seventy ","eighty ","ninety "] +thousands = ["","thousand ","million ", "billion ", "trillion ", + "quadrillion ", "quintillion ", "sextillion ", "septillion ","octillion ", + "nonillion ", "decillion ", "undecillion ", "duodecillion ", "tredecillion ", + "quattuordecillion ", "sexdecillion ", "septendecillion ", "octodecillion ", + "novemdecillion ", "vigintillion "] + +def format_message(message): + pattern = r'^:.*\!~(.*)@.* (.*) (.*) :(.*)' + now = int(time.time()) + matches = re.match(pattern, message) + if not matches: + return '' + + nick = matches.group(1).strip() + command = matches.group(2).strip() + channel = matches.group(3).strip() + message = matches.group(4).strip() + + return "%s\t%s\t%s\t%s\t%s" % (now, nick, command, channel, message) + +def get_users(): + # thanks, ~dan! + users = [] + with open("/etc/passwd", "r") as f: + for line in f: + if "/bin/bash" in line: + u = line.split(":")[0] # Grab all text before first ':' + users.append(u) + + return users + +def pretty_date(time=False): + """ + Get a datetime object or a int() Epoch timestamp and return a + pretty string like 'an hour ago', 'Yesterday', '3 months ago', + 'just now', etc + """ + from datetime import datetime + now = datetime.now() + if type(time) is int: + diff = now - datetime.fromtimestamp(time) + elif isinstance(time,datetime): + diff = now - time + elif not time: + diff = now - now + second_diff = diff.seconds + day_diff = diff.days + + if day_diff < 0: + return '' + + if day_diff == 0: + if second_diff < 10: + return "just now" + if second_diff < 60: + return str(second_diff) + " seconds ago" + if second_diff < 120: + return "a minute ago" + if second_diff < 3600: + return str(second_diff / 60) + " minutes ago" + if second_diff < 7200: + return "an hour ago" + if second_diff < 86400: + return str(second_diff / 3600) + " hours ago" + if day_diff == 1: + return "Yesterday" + if day_diff < 7: + return str(day_diff) + " days ago" + if day_diff < 31: + return str(day_diff / 7) + " weeks ago" + if day_diff < 365: + return str(day_diff / 30) + " months ago" + return str(day_diff / 365) + " years ago" + From 58753c723415344c78c95d8f43cde17af08450a4 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Fri, 5 Oct 2018 16:02:38 -0400 Subject: [PATCH 2/5] black --- Code/irc/acronymFinder.py | 149 +- Code/irc/banterbot.py | 497 +++-- Code/irc/defineWord.py | 38 +- Code/irc/dict_puzzle.py | 21 +- Code/irc/duckduckgo.py | 156 +- Code/irc/evil.py | 5 +- Code/irc/formatter.py | 16 - Code/irc/get_users.py | 5 +- Code/irc/inflect.py | 3223 ++++++++++++++++++---------- Code/irc/int2word.py | 86 +- Code/irc/madlibbot/madlib.py | 76 +- Code/irc/madlibbot/madlibbot.py | 137 +- Code/irc/madlibbot/msgformatter.py | 16 - Code/irc/names.py | 5 +- Code/irc/pretty_date.py | 71 +- Code/irc/puzzle.py | 247 ++- Code/irc/quote_bot.py | 173 +- Code/irc/quote_puzzle.py | 9 +- Code/irc/rainbow.py | 5 +- Code/irc/rhymesWith.py | 42 +- Code/irc/tilde_bot.py | 123 +- Code/irc/tildebot.py | 400 +++- Code/irc/topicbot.py | 318 +-- Code/irc/tumblr.py | 66 +- Code/irc/util.py | 170 +- Code/irc/wangbot.py | 339 ++- Code/irc/welch.py | 6 +- Code/irc/whosaid.py | 28 +- Code/irc/wikiphilosophy.py | 109 +- Code/irc/xkcdApropos.py | 16 +- Code/python/chatbesties.py | 142 +- Code/python/chatchecker.py | 22 +- Code/python/chatcloud.py | 49 +- Code/python/chatcloud2.py | 95 +- Code/python/chatstack.py | 43 +- Code/python/chatstats.py | 116 +- Code/python/mfp_watcher.py | 2 + Code/python/randomwords.py | 51 +- 38 files changed, 4549 insertions(+), 2523 deletions(-) delete mode 100644 Code/irc/formatter.py delete mode 100644 Code/irc/madlibbot/msgformatter.py diff --git a/Code/irc/acronymFinder.py b/Code/irc/acronymFinder.py index ed2d16f..5ed5f78 100644 --- a/Code/irc/acronymFinder.py +++ b/Code/irc/acronymFinder.py @@ -3,63 +3,98 @@ from bs4 import BeautifulSoup import random import string -dict = '/usr/share/dict/american-english' -(userId,token) = open("/home/krowbar/.secret/s4token").readline().rstrip().split(',') +dict = "/usr/share/dict/american-english" +(userId, token) = open("/home/krowbar/.secret/s4token").readline().rstrip().split(",") + def get_acros(word, silly, short): - acros = [] - url = "http://www.stands4.com/services/v2/abbr.php?uid=%s&tokenid=%s&term=%s" % (userId, token, word) - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html5lib') - results = soup.find_all('result') - #there are lots of cases where the same definition is repeated multiple times under different categories. this is dumb so we should do a little more work - defs = [] - for r in results: - rdef = r.find('definition').text - match = next((x for x in defs if x['definition'].lower() == rdef.lower()), None) - if match is not None: - #if we find a match, add the category to the existing categories and increase the score - match['categories'].append(((r.find('parentcategoryname').text + '\\') if r.find('parentcategoryname') else '') + r.find('categoryname').text) - match['score'] = str(float(match['score']) + float(r.find('score').text)) - else: #add a new item - defs.append({\ - 'term': r.find('term').text,\ - 'definition': r.find('definition').text,\ - 'categories': [((r.find('parentcategoryname').text + '\\') if r.find('parentcategoryname') else '') + r.find('categoryname').text],\ - 'score': r.find('score').text\ - }); + acros = [] + url = "http://www.stands4.com/services/v2/abbr.php?uid=%s&tokenid=%s&term=%s" % ( + userId, + token, + word, + ) + soup = BeautifulSoup(urllib.urlopen(url).read(), "html5lib") + results = soup.find_all("result") + # there are lots of cases where the same definition is repeated multiple times under different categories. this is dumb so we should do a little more work + defs = [] + for r in results: + rdef = r.find("definition").text + match = next((x for x in defs if x["definition"].lower() == rdef.lower()), None) + if match is not None: + # if we find a match, add the category to the existing categories and increase the score + match["categories"].append( + ( + (r.find("parentcategoryname").text + "\\") + if r.find("parentcategoryname") + else "" + ) + + r.find("categoryname").text + ) + match["score"] = str(float(match["score"]) + float(r.find("score").text)) + else: # add a new item + defs.append( + { + "term": r.find("term").text, + "definition": r.find("definition").text, + "categories": [ + ( + (r.find("parentcategoryname").text + "\\") + if r.find("parentcategoryname") + else "" + ) + + r.find("categoryname").text + ], + "score": r.find("score").text, + } + ) - for d in sorted(defs, key=lambda x:float(x['score']), reverse=True): - #print d; - if short is True: - acros.append("\"%s\"" % d['definition']) - else: - acros.append(("%s: \"%s\" (%s, score: %s)" % \ - (d['term'], d['definition'], ', '.join(d['categories']), d['score'])\ - ).encode('ascii', 'ignore')) - if silly is True: - newDef = [] - words = open(dict, 'r').readlines() - try: - for idx,letter in enumerate(word): - newWord = random.choice(\ - filter(lambda w: (idx is 0 or not w.strip().lower().endswith('\'s'))\ - and w.lower().startswith(letter.lower()), words)\ - ).strip() - print str(idx) + ' -> ' + newWord - newDef.append(newWord) - newWord = string.capwords(' '.join(newDef)) - if short is True: - acros.append("\"%s\"" % newWord) - else: - acros.append(("%s: \"%s\" (%s, score: %s)" % \ - (word.upper(), newWord, 'Tilde.town Original', '0')\ - ).encode('ascii', 'ignore')) - except IndexError: - acros.append("Future hazy, try again later: Tilde.town Error"); - if short is True: - shortList = acros[0:5] - if len(acros) > 5: - shortList.append(acros[-1]) - return [word.upper() + ': ' + ', '.join(shortList)] - else: - return acros + for d in sorted(defs, key=lambda x: float(x["score"]), reverse=True): + # print d; + if short is True: + acros.append('"%s"' % d["definition"]) + else: + acros.append( + ( + '%s: "%s" (%s, score: %s)' + % ( + d["term"], + d["definition"], + ", ".join(d["categories"]), + d["score"], + ) + ).encode("ascii", "ignore") + ) + if silly is True: + newDef = [] + words = open(dict, "r").readlines() + try: + for idx, letter in enumerate(word): + newWord = random.choice( + filter( + lambda w: (idx is 0 or not w.strip().lower().endswith("'s")) + and w.lower().startswith(letter.lower()), + words, + ) + ).strip() + print(str(idx) + " -> " + newWord) + newDef.append(newWord) + newWord = string.capwords(" ".join(newDef)) + if short is True: + acros.append('"%s"' % newWord) + else: + acros.append( + ( + '%s: "%s" (%s, score: %s)' + % (word.upper(), newWord, "Tilde.town Original", "0") + ).encode("ascii", "ignore") + ) + except IndexError: + acros.append("Future hazy, try again later: Tilde.town Error") + if short is True: + shortList = acros[0:5] + if len(acros) > 5: + shortList.append(acros[-1]) + return [word.upper() + ": " + ", ".join(shortList)] + else: + return acros diff --git a/Code/irc/banterbot.py b/Code/irc/banterbot.py index 374c20e..ce16a9f 100755 --- a/Code/irc/banterbot.py +++ b/Code/irc/banterbot.py @@ -33,28 +33,51 @@ from whosaid import whoSaid parser = OptionParser() -parser.add_option("-s", "--server", dest="server", default='127.0.0.1', - help="the server to connect to", metavar="SERVER") -parser.add_option("-c", "--channel", dest="channel", default='#bot_test', - help="the channel to join", metavar="CHANNEL") -parser.add_option("-n", "--nick", dest="nick", default='tildebot', - help="the nick to use", metavar="NICK") +parser.add_option( + "-s", + "--server", + dest="server", + default="127.0.0.1", + help="the server to connect to", + metavar="SERVER", +) +parser.add_option( + "-c", + "--channel", + dest="channel", + default="#bot_test", + help="the channel to join", + metavar="CHANNEL", +) +parser.add_option( + "-n", + "--nick", + dest="nick", + default="tildebot", + help="the nick to use", + metavar="NICK", +) (options, args) = parser.parse_args() p = inflect.engine() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) -def sendmsg(chan , msg): - ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n") +def ping(pong): + ircsock.send("PONG {}\n".format(pong)) + + +def sendmsg(chan, msg): + ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") + def joinchan(chan): - ircsock.send("JOIN "+ chan +"\n") + ircsock.send("JOIN " + chan + "\n") + def hello(): - ircsock.send("PRIVMSG "+ channel +" :Hello!\n") + ircsock.send("PRIVMSG " + channel + " :Hello!\n") + def score_banter(channel, user, messageText): score = 5 @@ -64,285 +87,421 @@ def score_banter(channel, user, messageText): for word in words: for bant in bantz: bword = bant.strip("\n").split("|") - if re.sub('[^a-z0-9]+','',word.lower()) == bword[0]: + if re.sub("[^a-z0-9]+", "", word.lower()) == bword[0]: score += int(bword[1]) - score += messageText.count('!') * 2 #hype is banter - score -= messageText.count('!!!') * 6 #too much hype is not banter - score += messageText.count('#') * 3 #hashs are mad bantz - score -= messageText.count('##') * 6 #but too many is garbage + score += messageText.count("!") * 2 # hype is banter + score -= messageText.count("!!!") * 6 # too much hype is not banter + score += messageText.count("#") * 3 # hashs are mad bantz + score -= messageText.count("##") * 6 # but too many is garbage - names = ['mate', 'lad', 'my best boy'] - compliment = ['top-drawer', 'top-shelf', 'bangin\'', 'legendary', 'smashing', 'incredible', 'impeccable', 'stunning'] + names = ["mate", "lad", "my best boy"] + compliment = [ + "top-drawer", + "top-shelf", + "bangin'", + "legendary", + "smashing", + "incredible", + "impeccable", + "stunning", + ] msg = "" if score > 100: - msg = "Truely " + random.choice(compliment).capitalize() + ", " + random.choice(names) \ - + "! That was some #banter! You earned a " + str(score) + " for that!" + msg = ( + "Truely " + + random.choice(compliment).capitalize() + + ", " + + random.choice(names) + + "! That was some #banter! You earned a " + + str(score) + + " for that!" + ) elif score > 50: - msg = random.choice(compliment).capitalize() + " #banter! You get a " + str(score) + " from me!" + msg = ( + random.choice(compliment).capitalize() + + " #banter! You get a " + + str(score) + + " from me!" + ) elif score > 10: - msg = random.choice(["acceptible", "reasonable", "passable"]).capitalize() + " #banter. You get a " + str(score) + msg = ( + random.choice(["acceptible", "reasonable", "passable"]).capitalize() + + " #banter. You get a " + + str(score) + ) else: - msg = "That " + random.choice(["was hardly", "was barely", "wasn't", "won't pass for", "was awful"]) \ - + " #banter" + random.choice([", lad",", lah",", boy","",""]) + ". I'll give you a " + str(score) + ". Maybe try again?" + msg = ( + "That " + + random.choice( + ["was hardly", "was barely", "wasn't", "won't pass for", "was awful"] + ) + + " #banter" + + random.choice([", lad", ", lah", ", boy", "", ""]) + + ". I'll give you a " + + str(score) + + ". Maybe try again?" + ) ircsock.send("PRIVMSG " + channel + " :" + msg + "\n") + def get_new_banter(channel, user): with open("/usr/share/dict/words", "r") as dict: - words = filter(lambda word:re.search(r"^[^']*$", word), dict.readlines()) - if(random.randint(0,1)): #look for *ant words - words = filter(lambda word:re.search(r"ant", word), words) + words = filter(lambda word: re.search(r"^[^']*$", word), dict.readlines()) + if random.randint(0, 1): # look for *ant words + words = filter(lambda word: re.search(r"ant", word), words) random.shuffle(words) word = words[0].strip("\n") - start = word.find('ant') - if(start == 0): - word = 'b' + word + start = word.find("ant") + if start == 0: + word = "b" + word else: - if('aeiou'.find(word[start]) > -1): #just append a 'b' - word = word[:start] + 'b' + word[start:] - else: #replace the letter with 'b' - word = word[:start-1] + 'b' + word[start:] - else: #look for ban* words - words = filter(lambda word:re.search(r"ban", word), words) + if "aeiou".find(word[start]) > -1: # just append a 'b' + word = word[:start] + "b" + word[start:] + else: # replace the letter with 'b' + word = word[: start - 1] + "b" + word[start:] + else: # look for ban* words + words = filter(lambda word: re.search(r"ban", word), words) random.shuffle(words) word = words[0].strip("\n") - end = word.find('ban') + 3 - if(end == len(word)): - word = word + 't' + end = word.find("ban") + 3 + if end == len(word): + word = word + "t" else: - if('aeiou'.find(word[end]) > -1): #just append 't' - word = word[:end] + 't' + word[end:] - else: #replace the letter with 'b' - word = word[:end] + 't' + word[end+1:] - ircsock.send("PRIVMSG " + channel + " :" + user + ": Here, why don't you try '" + word + "'?\n") + if "aeiou".find(word[end]) > -1: # just append 't' + word = word[:end] + "t" + word[end:] + else: # replace the letter with 'b' + word = word[:end] + "t" + word[end + 1 :] + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": Here, why don't you try '" + + word + + "'?\n" + ) + def get_rhymes(channel, user, text): word = "" - if(len(text.split(' ')) > 1): - word = text.split(' ')[1] + if len(text.split(" ")) > 1: + word = text.split(" ")[1] else: with open("/home/nossidge/poems/words_poetic.txt", "r") as words: word = random.choice(words.readlines()).strip("\n") rhymes = rhymeZone(word) - if(len(rhymes) == 0): - ircsock.send("PRIVMSG " + channel + " :" + user + ": Couldn't find anything that rhymes with '" + word + "' :(\n") + if len(rhymes) == 0: + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": Couldn't find anything that rhymes with '" + + word + + "' :(\n" + ) else: - ircsock.send("PRIVMSG " + channel + " :" + user + ": Here, these words rhyme with '" + word + "': " + ', '.join(rhymes) + "\n") + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": Here, these words rhyme with '" + + word + + "': " + + ", ".join(rhymes) + + "\n" + ) + def define_word(channel, user, text): word = "" defs = [] - if(len(text.split(' ')) > 1): - word = text.split(' ')[1] + if len(text.split(" ")) > 1: + word = text.split(" ")[1] defs = defWord(word) - if(len(defs) == 0): - ircsock.send("PRIVMSG " + channel + " :" + user + ": Couldn't find the definition of '" + word + "' :(\n") - elif(isinstance(defs, list)): + if len(defs) == 0: + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": Couldn't find the definition of '" + + word + + "' :(\n" + ) + elif isinstance(defs, list): for entry in defs: - ircsock.send("PRIVMSG " + channel + " :" + user + ": Define '" + word + "'" + entry[0:400] + "\n") + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": Define '" + + word + + "'" + + entry[0:400] + + "\n" + ) else: - ircsock.send("PRIVMSG " + channel + " :" + user + ": Define '" + word + "'" + defs[0:400] + "\n") + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": Define '" + + word + + "'" + + defs[0:400] + + "\n" + ) + def make_rainbow(channel, user, text): rbword = makeRainbow(text[9:]) ircsock.send("PRIVMSG " + channel + " :" + rbword + "\n") + def get_welch(channel): ircsock.send("PRIVMSG " + channel + " :" + welch.get_thing()[0:400] + "\n") + def get_evil(channel): evilThing = evil.get_thing() - for line in [evilThing[i:i+400] for i in range(0, len(evilThing), 400)]: - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + for line in [evilThing[i : i + 400] for i in range(0, len(evilThing), 400)]: + ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + def get_tumble(url, channel): tumble = tumblr.tumble(url) - for line in [tumble[i:i+400] for i in range(0, len(tumble), 400)]: + for line in [tumble[i : i + 400] for i in range(0, len(tumble), 400)]: ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + def get_xkcd(channel, text): links = xkcdApropos.xkcd(text[6:]) - joined_links = ', '.join(links) - for line in [joined_links[i:i+400] for i in range(0, len(joined_links), 400)]: + joined_links = ", ".join(links) + for line in [joined_links[i : i + 400] for i in range(0, len(joined_links), 400)]: ircsock.send("PRIVMSG " + channel + " :" + line + "\n") - #res = xkcdApropos.xkcd(text[6:]) - #ircsock.send("PRIVMSG " + channel + " :" + res + "\n") + # res = xkcdApropos.xkcd(text[6:]) + # ircsock.send("PRIVMSG " + channel + " :" + res + "\n") + def get_wphilosophy(channel, text): - steps = wikiphilosophy.get_philosophy_lower(text[17:]) - if not steps: - ircsock.send("PRIVMSG " + channel + " :Couldn't find a wikipedia entry for " + text + "\n") - else: - joined_steps = ' > '.join(steps) - if steps[-1] == 'Philosophy': - joined_steps += "!!!" - for line in [joined_steps[i:i+400] for i in range(0, len(joined_steps), 400)]: - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + steps = wikiphilosophy.get_philosophy_lower(text[17:]) + if not steps: + ircsock.send( + "PRIVMSG " + + channel + + " :Couldn't find a wikipedia entry for " + + text + + "\n" + ) + else: + joined_steps = " > ".join(steps) + if steps[-1] == "Philosophy": + joined_steps += "!!!" + for line in [ + joined_steps[i : i + 400] for i in range(0, len(joined_steps), 400) + ]: + ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + def figlet(channel, text): if not text: ircsock.send("PRIVMSG " + channel + " :No text given. :(\n") else: - lines = subprocess.Popen(["figlet", "-w140"] + text.split(' '), shell=False, stdout=subprocess.PIPE).stdout.read() - for line in lines.split('\n'): + lines = subprocess.Popen( + ["figlet", "-w140"] + text.split(" "), shell=False, stdout=subprocess.PIPE + ).stdout.read() + for line in lines.split("\n"): ircsock.send("PRIVMSG " + channel + " :" + line + "\n") - time.sleep(0.4) #to avoid channel throttle due to spamming + time.sleep(0.4) # to avoid channel throttle due to spamming + def toilet(channel, text): if not text: ircsock.send("PRIVMSG " + channel + " :No text given. :(\n") else: - lines = subprocess.Popen(["toilet", "-w140", "--irc"] + text.split(' '), shell=False, stdout=subprocess.PIPE).stdout.read() - for line in lines.split('\n'): + lines = subprocess.Popen( + ["toilet", "-w140", "--irc"] + text.split(" "), + shell=False, + stdout=subprocess.PIPE, + ).stdout.read() + for line in lines.split("\n"): ircsock.send("PRIVMSG " + channel + " :" + line + "\n") - time.sleep(0.4) #to avoid channel throttle due to spamming + time.sleep(0.4) # to avoid channel throttle due to spamming + def get_acronym(channel, text): - if not text: - ircsock.send("PRIVMSG " + channel + " :No text given :(\n") - else: - defs = acronymFinder.get_acros(text, True, True) - for d in defs[0:5]: #only the first five. they are already sorted by 'score' - ircsock.send("PRIVMSG " + channel + " :" + d.encode('utf-8') + "\n") - if len(defs) > 5: - ircsock.send("PRIVMSG " + channel + " :" + defs[-1] + "\n") + if not text: + ircsock.send("PRIVMSG " + channel + " :No text given :(\n") + else: + defs = acronymFinder.get_acros(text, True, True) + for d in defs[0:5]: # only the first five. they are already sorted by 'score' + ircsock.send("PRIVMSG " + channel + " :" + d.encode("utf-8") + "\n") + if len(defs) > 5: + ircsock.send("PRIVMSG " + channel + " :" + defs[-1] + "\n") + def get_whosaid(channel, text): - if not text: - ircsock.send("PRIVMSG " + channel + " :No text given :(\n") - else: - result = whoSaid(text) - date = datetime.date.fromtimestamp(result['timecutoff']) - dateStr = date.strftime('%B %d') - if not result['data']: - msg = 'Nobody said \'%s\' since %s' % (text, dateStr) + if not text: + ircsock.send("PRIVMSG " + channel + " :No text given :(\n") else: - msg = 'Since %s, %s said \'%s\' %d times' % (dateStr, result['data'][0][0], text, result['data'][0][1]) - if len(result['data']) > 1: - msg += ' and %s said it %d times' % (result['data'][1][0], result['data'][1][1]) - ircsock.send("PRIVMSG " + channel + " :" + msg + ".\n") + result = whoSaid(text) + date = datetime.date.fromtimestamp(result["timecutoff"]) + dateStr = date.strftime("%B %d") + if not result["data"]: + msg = "Nobody said '%s' since %s" % (text, dateStr) + else: + msg = "Since %s, %s said '%s' %d times" % ( + dateStr, + result["data"][0][0], + text, + result["data"][0][1], + ) + if len(result["data"]) > 1: + msg += " and %s said it %d times" % ( + result["data"][1][0], + result["data"][1][1], + ) + ircsock.send("PRIVMSG " + channel + " :" + msg + ".\n") + def get_notice(user, channel): ircsock.send("CNOTICE " + user + " " + channel + " :Notice me sempai!\n") + def get_water(user, channel, msg, botnick): if msg.find(botnick) == 0: ircsock.send("PRIVMSG " + channel + " :Fight me, " + user + "!\n") + def mug_off(channel): ircsock.send("PRIVMSG " + channel + " :u want some of this, m8?\n") + def rollcall(channel): - ircsock.send("PRIVMSG "+ channel +" :U wot m8? I score all the top drawer #banter and #bantz on this channel! \ + ircsock.send( + "PRIVMSG " + + channel + + " :U wot m8? I score all the top drawer #banter and #bantz on this channel! \ Find new top-shelf banter with !newbanter, !rhymes, and !define. \ Look up things with !acronym and !whosaid. \ Make your chatter #legend with !rainbow, !toilet, and !figlet. \ Find interesting things with !xkcd and !wiki-philosophy. \ - Get jokes with !welch and !evil\n") + Get jokes with !welch and !evil\n" + ) + def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :krowbar\n") # user authentication - ircsock.send("NICK "+ botnick +"\n") + ircsock.connect((server, 6667)) + ircsock.send( + "USER " + botnick + " " + botnick + " " + botnick + " :krowbar\n" + ) # user authentication + ircsock.send("NICK " + botnick + "\n") + + joinchan(channel) + joinchan("#bots") - joinchan(channel) - joinchan("#bots") def get_user_from_message(msg): - try: - i1 = msg.index(':') + 1 - i2 = msg.index('!') - return msg[i1:i2] - except ValueError: - return "" + try: + i1 = msg.index(":") + 1 + i2 = msg.index("!") + return msg[i1:i2] + except ValueError: + return "" + def listen(botnick): - while 1: + while 1: - ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip('\n\r') + ircmsg = ircsock.recv(2048) + ircmsg = ircmsg.strip("\n\r") - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) - formatted = util.format_message(ircmsg) + formatted = util.format_message(ircmsg) - if "" == formatted: - continue + if "" == formatted: + continue - # print formatted + # print formatted - split = formatted.split("\t") - #time = split[0] - user = split[1] - command = split[2] - channel = split[3] - messageText = split[4] + split = formatted.split("\t") + # time = split[0] + user = split[1] + command = split[2] + channel = split[3] + messageText = split[4] - if ircmsg.find("#banter") != -1 or ircmsg.find("#bantz") != -1: - score_banter(channel, user, messageText) + if ircmsg.find("#banter") != -1 or ircmsg.find("#bantz") != -1: + score_banter(channel, user, messageText) - if ircmsg.find(":!newbanter") != -1: - get_new_banter(channel, user) + if ircmsg.find(":!newbanter") != -1: + get_new_banter(channel, user) - if ircmsg.find(":!rhymes") != -1: - get_rhymes(channel, user, messageText) + if ircmsg.find(":!rhymes") != -1: + get_rhymes(channel, user, messageText) - if ircmsg.find(":!define") != -1: - define_word(channel, user, messageText) + if ircmsg.find(":!define") != -1: + define_word(channel, user, messageText) - if ircmsg.find(":!rainbow") != -1: - make_rainbow(channel, user, messageText) + if ircmsg.find(":!rainbow") != -1: + make_rainbow(channel, user, messageText) - if ircmsg.find(":!welch") != -1: - get_welch(channel) + if ircmsg.find(":!welch") != -1: + get_welch(channel) - if ircmsg.find(":!evil") != -1: - get_evil(channel) + if ircmsg.find(":!evil") != -1: + get_evil(channel) - if ircmsg.find(":!kjp") != -1: - get_tumble('http://kingjamesprogramming.tumblr.com', channel) + if ircmsg.find(":!kjp") != -1: + get_tumble("http://kingjamesprogramming.tumblr.com", channel) - if ircmsg.find(":!help") != -1: - get_tumble('http://thedoomthatcametopuppet.tumblr.com', channel) + if ircmsg.find(":!help") != -1: + get_tumble("http://thedoomthatcametopuppet.tumblr.com", channel) - if ircmsg.find(":!xkcd") != -1: - get_xkcd(channel, messageText) - if ircmsg.find(":!wiki-philosophy") != -1: - get_wphilosophy(channel, messageText); + if ircmsg.find(":!xkcd") != -1: + get_xkcd(channel, messageText) + if ircmsg.find(":!wiki-philosophy") != -1: + get_wphilosophy(channel, messageText) - if ircmsg.find(":!figlet") != -1: - figlet(channel, messageText[8:]) + if ircmsg.find(":!figlet") != -1: + figlet(channel, messageText[8:]) - if ircmsg.find(":!toilet") != -1: - toilet(channel, messageText[8:]) + if ircmsg.find(":!toilet") != -1: + toilet(channel, messageText[8:]) - if ircmsg.find(":!acronym") != -1: - get_acronym(channel, messageText[9:]) + if ircmsg.find(":!acronym") != -1: + get_acronym(channel, messageText[9:]) - if ircmsg.find(":!whosaid") != -1: - get_whosaid(channel, messageText[9:]) + if ircmsg.find(":!whosaid") != -1: + get_whosaid(channel, messageText[9:]) - if ircmsg.find(":!notice") != -1: - get_notice(user, channel) + if ircmsg.find(":!notice") != -1: + get_notice(user, channel) - if ircmsg.find(":!water") != -1: - get_water(user, channel, messageText[7:], botnick) + if ircmsg.find(":!water") != -1: + get_water(user, channel, messageText[7:], botnick) + if ircmsg.find(":!rollcall") != -1: + rollcall(channel) - if ircmsg.find(":!rollcall") != -1: - rollcall(channel) + if ircmsg.find(":" + botnick + ":") != -1: + mug_off(channel) - if ircmsg.find(":" + botnick + ":") != -1: - mug_off(channel) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + sys.stdout.flush() + time.sleep(1) - sys.stdout.flush() - time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect(options.server, options.channel, options.nick) diff --git a/Code/irc/defineWord.py b/Code/irc/defineWord.py index 1c78f9e..104e5cc 100644 --- a/Code/irc/defineWord.py +++ b/Code/irc/defineWord.py @@ -1,28 +1,34 @@ import urllib from bs4 import BeautifulSoup import random - + + def define(word): - defs = [] - url = 'http://www.merriam-webster.com/dictionary/%s' % word - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') - head = soup.find('div', id='headword') - if head: - for p in head.find_all('p'): - defs.append(p.text.encode('ascii', 'ignore')) - return defs + defs = [] + url = "http://www.merriam-webster.com/dictionary/%s" % word + soup = BeautifulSoup(urllib.urlopen(url).read(), "html.parser") + head = soup.find("div", id="headword") + if head: + for p in head.find_all("p"): + defs.append(p.text.encode("ascii", "ignore")) + return defs + key = open("/home/krowbar/.secret/key").readline().rstrip() -def defWord(word, short = True): + +def defWord(word, short=True): defs = [] - url = 'http://www.dictionaryapi.com/api/v1/references/collegiate/xml/%s?key=%s' % (word, key) - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html5lib') - entry = soup.find('entry') + url = "http://www.dictionaryapi.com/api/v1/references/collegiate/xml/%s?key=%s" % ( + word, + key, + ) + soup = BeautifulSoup(urllib.urlopen(url).read(), "html5lib") + entry = soup.find("entry") if entry: - for d in entry.find_all('dt'): - defs.append(d.text.encode('ascii', 'ignore')) + for d in entry.find_all("dt"): + defs.append(d.text.encode("ascii", "ignore")) if short: - return ' '.join(defs) + return " ".join(defs) else: return defs diff --git a/Code/irc/dict_puzzle.py b/Code/irc/dict_puzzle.py index 1d9c443..40233dd 100644 --- a/Code/irc/dict_puzzle.py +++ b/Code/irc/dict_puzzle.py @@ -6,6 +6,7 @@ p = inflect.engine() dictionary = "/usr/share/dict/american-english-small" BAD_WORDS_FILE = "badwords.txt" + def get_wordlist(): # I feel weird calling this "get_wordlist" when it's a generator without calling out that I do in fact realise it's weird - ~deltawitch with open(BAD_WORDS_FILE, "r") as fp: @@ -15,20 +16,29 @@ def get_wordlist(): if "'" not in word and word not in bad_words: yield word.rstrip() + def get_puzzle(): dict_words = list(get_wordlist()) words = random.sample(dict_words, 3) - key = random.randrange(0,3) #get values 1-3 - puzzle = "When alphebetized, what is the " + p.ordinal(p.number_to_words(key+1)) + " in " + ", ".join(words) + key = random.randrange(0, 3) # get values 1-3 + puzzle = ( + "When alphebetized, what is the " + + p.ordinal(p.number_to_words(key + 1)) + + " in " + + ", ".join(words) + ) words.sort() answer = words[key] return [answer, puzzle] -def get_anagram(maxlen = 6): - dict_words = [word for word in get_wordlist() if len(word) > 2 and len(word) <= maxlen+1] + +def get_anagram(maxlen=6): + dict_words = [ + word for word in get_wordlist() if len(word) > 2 and len(word) <= maxlen + 1 + ] word = random.choice(dict_words) while True: - anagram = ''.join(random.sample(word, len(word))) + anagram = "".join(random.sample(word, len(word))) if anagram != word: break puzzle = "Unscramble the following word: '" + anagram + "'" @@ -43,4 +53,5 @@ def get_anagram(maxlen = 6): return False # Ok, gotta actually check if it's a word now return any(guess == item for item in get_wordlist()) + return [answer_checker, puzzle] diff --git a/Code/irc/duckduckgo.py b/Code/irc/duckduckgo.py index 04ed1a5..25ecd03 100755 --- a/Code/irc/duckduckgo.py +++ b/Code/irc/duckduckgo.py @@ -6,7 +6,14 @@ import sys __version__ = 0.242 -def query(query, useragent='python-duckduckgo '+str(__version__), safesearch=True, html=False, meanings=True, **kwargs): +def query( + query, + useragent="python-duckduckgo " + str(__version__), + safesearch=True, + html=False, + meanings=True, + **kwargs +): """ Query DuckDuckGo, returning a Results object. @@ -28,22 +35,22 @@ def query(query, useragent='python-duckduckgo '+str(__version__), safesearch=Tru Any other keyword arguments are passed directly to DuckDuckGo as URL params. """ % __version__ - safesearch = '1' if safesearch else '-1' - html = '0' if html else '1' - meanings = '0' if meanings else '1' + safesearch = "1" if safesearch else "-1" + html = "0" if html else "1" + meanings = "0" if meanings else "1" params = { - 'q': query, - 'o': 'json', - 'kp': safesearch, - 'no_redirect': '1', - 'no_html': html, - 'd': meanings, - } + "q": query, + "o": "json", + "kp": safesearch, + "no_redirect": "1", + "no_html": html, + "d": meanings, + } params.update(kwargs) encparams = urllib.urlencode(params) - url = 'http://api.duckduckgo.com/?' + encparams + url = "http://api.duckduckgo.com/?" + encparams - request = urllib2.Request(url, headers={'User-Agent': useragent}) + request = urllib2.Request(url, headers={"User-Agent": useragent}) response = urllib2.urlopen(request) json = j.loads(response.read()) response.close() @@ -52,54 +59,56 @@ def query(query, useragent='python-duckduckgo '+str(__version__), safesearch=Tru class Results(object): - def __init__(self, json): - self.type = {'A': 'answer', 'D': 'disambiguation', - 'C': 'category', 'N': 'name', - 'E': 'exclusive', '': 'nothing'}.get(json.get('Type',''), '') + self.type = { + "A": "answer", + "D": "disambiguation", + "C": "category", + "N": "name", + "E": "exclusive", + "": "nothing", + }.get(json.get("Type", ""), "") self.json = json - self.api_version = None # compat + self.api_version = None # compat - self.heading = json.get('Heading', '') + self.heading = json.get("Heading", "") - self.results = [Result(elem) for elem in json.get('Results',[])] - self.related = [Result(elem) for elem in - json.get('RelatedTopics',[])] + self.results = [Result(elem) for elem in json.get("Results", [])] + self.related = [Result(elem) for elem in json.get("RelatedTopics", [])] self.abstract = Abstract(json) self.redirect = Redirect(json) self.definition = Definition(json) self.answer = Answer(json) - self.image = Image({'Result':json.get('Image','')}) + self.image = Image({"Result": json.get("Image", "")}) class Abstract(object): - def __init__(self, json): - self.html = json.get('Abstract', '') - self.text = json.get('AbstractText', '') - self.url = json.get('AbstractURL', '') - self.source = json.get('AbstractSource') + self.html = json.get("Abstract", "") + self.text = json.get("AbstractText", "") + self.url = json.get("AbstractURL", "") + self.source = json.get("AbstractSource") + class Redirect(object): - def __init__(self, json): - self.url = json.get('Redirect', '') + self.url = json.get("Redirect", "") + class Result(object): - def __init__(self, json): - self.topics = json.get('Topics', []) + self.topics = json.get("Topics", []) if self.topics: self.topics = [Result(t) for t in self.topics] return - self.html = json.get('Result') - self.text = json.get('Text') - self.url = json.get('FirstURL') + self.html = json.get("Result") + self.text = json.get("Text") + self.url = json.get("FirstURL") - icon_json = json.get('Icon') + icon_json = json.get("Icon") if icon_json is not None: self.icon = Image(icon_json) else: @@ -107,51 +116,61 @@ class Result(object): class Image(object): - def __init__(self, json): - self.url = json.get('Result') - self.height = json.get('Height', None) - self.width = json.get('Width', None) + self.url = json.get("Result") + self.height = json.get("Height", None) + self.width = json.get("Width", None) class Answer(object): - def __init__(self, json): - self.text = json.get('Answer') - self.type = json.get('AnswerType', '') + self.text = json.get("Answer") + self.type = json.get("AnswerType", "") + class Definition(object): def __init__(self, json): - self.text = json.get('Definition','') - self.url = json.get('DefinitionURL') - self.source = json.get('DefinitionSource') + self.text = json.get("Definition", "") + self.url = json.get("DefinitionURL") + self.source = json.get("DefinitionSource") -def get_zci(q, web_fallback=True, priority=['answer', 'abstract', 'related.0', 'definition'], urls=True, **kwargs): - '''A helper method to get a single (and hopefully the best) ZCI result. +def get_zci( + q, + web_fallback=True, + priority=["answer", "abstract", "related.0", "definition"], + urls=True, + **kwargs +): + """A helper method to get a single (and hopefully the best) ZCI result. priority=list can be used to set the order in which fields will be checked for answers. Use web_fallback=True to fall back to grabbing the first web result. passed to query. This method will fall back to 'Sorry, no results.' - if it cannot find anything.''' + if it cannot find anything.""" - ddg = query('\\'+q, **kwargs) - response = '' + ddg = query("\\" + q, **kwargs) + response = "" for p in priority: - ps = p.split('.') + ps = p.split(".") type = ps[0] index = int(ps[1]) if len(ps) > 1 else None result = getattr(ddg, type) - if index is not None: - if not hasattr(result, '__getitem__'): raise TypeError('%s field is not indexable' % type) + if index is not None: + if not hasattr(result, "__getitem__"): + raise TypeError("%s field is not indexable" % type) result = result[index] if len(result) > index else None - if not result: continue + if not result: + continue - if result.text: response = result.text - if result.text and hasattr(result,'url') and urls: - if result.url: response += ' (%s)' % result.url - if response: break + if result.text: + response = result.text + if result.text and hasattr(result, "url") and urls: + if result.url: + response += " (%s)" % result.url + if response: + break # if there still isn't anything, try to get the first web result if not response and web_fallback: @@ -159,21 +178,24 @@ def get_zci(q, web_fallback=True, priority=['answer', 'abstract', 'related.0', ' response = ddg.redirect.url # final fallback - if not response: - response = 'Sorry, no results.' + if not response: + response = "Sorry, no results." return response + def main(): if len(sys.argv) > 1: - q = query(' '.join(sys.argv[1:])) + q = query(" ".join(sys.argv[1:])) keys = q.json.keys() keys.sort() for key in keys: sys.stdout.write(key) - if type(q.json[key]) in [str,unicode]: print(':', q.json[key]) - else: - sys.stdout.write('\n') - for i in q.json[key]: print('\t',i) + if type(q.json[key]) in [str, unicode]: + print(":", q.json[key]) + else: + sys.stdout.write("\n") + for i in q.json[key]: + print("\t", i) else: - print('Usage: %s [query]' % sys.argv[0]) + print("Usage: %s [query]" % sys.argv[0]) diff --git a/Code/irc/evil.py b/Code/irc/evil.py index ac6af43..eecb7f6 100644 --- a/Code/irc/evil.py +++ b/Code/irc/evil.py @@ -1,6 +1,9 @@ import random + def get_thing(): file = "/home/krowbar/logs/evildata.txt" thing = "" - return "If I Ever Become an Evil Overlord: " + random.choice(list(open(file))).rstrip() + return ( + "If I Ever Become an Evil Overlord: " + random.choice(list(open(file))).rstrip() + ) diff --git a/Code/irc/formatter.py b/Code/irc/formatter.py deleted file mode 100644 index d438aca..0000000 --- a/Code/irc/formatter.py +++ /dev/null @@ -1,16 +0,0 @@ -import time -import re - -def format_message(message): - pattern = r'^:.*\!~(.*)@.* (.*) (.*) :(.*)' - now = int(time.time()) - matches = re.match(pattern, message) - if not matches: - return '' - - nick = matches.group(1).strip() - command = matches.group(2).strip() - channel = matches.group(3).strip() - message = matches.group(4).strip() - - return "%s\t%s\t%s\t%s\t%s" % (now, nick, command, channel, message) diff --git a/Code/irc/get_users.py b/Code/irc/get_users.py index 2b78b11..32a7381 100644 --- a/Code/irc/get_users.py +++ b/Code/irc/get_users.py @@ -1,5 +1,6 @@ # Return a list of users on this system + def get_users(): # thanks, ~dan! users = [] @@ -8,5 +9,5 @@ def get_users(): if "/bin/bash" in line: u = line.split(":")[0] # Grab all text before first ':' users.append(u) - - return users \ No newline at end of file + + return users diff --git a/Code/irc/inflect.py b/Code/irc/inflect.py index 64382a2..f2db66b 100644 --- a/Code/irc/inflect.py +++ b/Code/irc/inflect.py @@ -1,4 +1,4 @@ -''' +""" inflect.py: correctly generate plurals, ordinals, indefinite articles; convert numbers to words Copyright (C) 2010 Paul Dyson @@ -59,7 +59,7 @@ Exceptions: BadRcFileError BadGenderError -''' +""" from re import match, search, subn, IGNORECASE, VERBOSE from re import split as splitre @@ -94,12 +94,12 @@ class BadRcFileError(Exception): class BadGenderError(Exception): pass + __ver_major__ = 0 __ver_minor__ = 2 __ver_patch__ = 4 __ver_sub__ = "" -__version__ = "%d.%d.%d%s" % (__ver_major__, __ver_minor__, - __ver_patch__, __ver_sub__) +__version__ = "%d.%d.%d%s" % (__ver_major__, __ver_minor__, __ver_patch__, __ver_sub__) STDOUT_ON = False @@ -114,8 +114,8 @@ def enclose(s): return "(?:%s)" % s -def joinstem(cutpoint=0, words=''): - ''' +def joinstem(cutpoint=0, words=""): + """ join stem of each word in words into a string for regex each word is truncated at cutpoint cutpoint is usually negative indicating the number of letters to remove @@ -125,19 +125,19 @@ def joinstem(cutpoint=0, words=''): joinstem(-2, ["ephemeris", "iris", ".*itis"]) returns (?:ephemer|ir|.*it) - ''' - return enclose('|'.join(w[:cutpoint] for w in words)) + """ + return enclose("|".join(w[:cutpoint] for w in words)) def bysize(words): - ''' + """ take a list of words and return a dict of sets sorted by word length e.g. ret[3]=set(['ant', 'cat', 'dog', 'pig']) ret[4]=set(['frog', 'goat']) ret[5]=set(['horse']) ret[8]=set(['elephant']) - ''' + """ ret = {} for w in words: if len(w) not in ret: @@ -147,7 +147,7 @@ def bysize(words): def make_pl_si_lists(lst, plending, siendingsize, dojoinstem=True): - ''' + """ given a list of singular words: lst an ending to append to make the plural: plending the number of characters to remove from the singular before appending plending: siendingsize @@ -159,7 +159,7 @@ def make_pl_si_lists(lst, plending, siendingsize, dojoinstem=True): the pluralised words as a dict of sets sorted by word length: si_bysize the singular words as a dict of sets sorted by word length: pl_bysize if dojoinstem is True: a regular expression that matches any of the stems: stem - ''' + """ if siendingsize is not None: siendingsize = -siendingsize si_list = [w[:siendingsize] + plending for w in lst] @@ -176,89 +176,87 @@ def make_pl_si_lists(lst, plending, siendingsize, dojoinstem=True): pl_sb_irregular_s = { "corpus": "corpuses|corpora", - "opus": "opuses|opera", - "genus": "genera", + "opus": "opuses|opera", + "genus": "genera", "mythos": "mythoi", - "penis": "penises|penes", + "penis": "penises|penes", "testis": "testes", - "atlas": "atlases|atlantes", - "yes": "yeses", + "atlas": "atlases|atlantes", + "yes": "yeses", } pl_sb_irregular = { - "child": "children", - "brother": "brothers|brethren", - "loaf": "loaves", - "hoof": "hoofs|hooves", - "beef": "beefs|beeves", - "thief": "thiefs|thieves", - "money": "monies", - "mongoose": "mongooses", - "ox": "oxen", - "cow": "cows|kine", - "graffito": "graffiti", - "octopus": "octopuses|octopodes", - "genie": "genies|genii", - "ganglion": "ganglions|ganglia", - "trilby": "trilbys", - "turf": "turfs|turves", - "numen": "numina", - "atman": "atmas", - "occiput": "occiputs|occipita", + "child": "children", + "brother": "brothers|brethren", + "loaf": "loaves", + "hoof": "hoofs|hooves", + "beef": "beefs|beeves", + "thief": "thiefs|thieves", + "money": "monies", + "mongoose": "mongooses", + "ox": "oxen", + "cow": "cows|kine", + "graffito": "graffiti", + "octopus": "octopuses|octopodes", + "genie": "genies|genii", + "ganglion": "ganglions|ganglia", + "trilby": "trilbys", + "turf": "turfs|turves", + "numen": "numina", + "atman": "atmas", + "occiput": "occiputs|occipita", "sabretooth": "sabretooths", "sabertooth": "sabertooths", - "lowlife": "lowlifes", - "flatfoot": "flatfoots", + "lowlife": "lowlifes", + "flatfoot": "flatfoots", "tenderfoot": "tenderfoots", - "romany": "romanies", - "jerry": "jerries", - "mary": "maries", - "talouse": "talouses", - "blouse": "blouses", - "rom": "roma", - "carmen": "carmina", + "romany": "romanies", + "jerry": "jerries", + "mary": "maries", + "talouse": "talouses", + "blouse": "blouses", + "rom": "roma", + "carmen": "carmina", } pl_sb_irregular.update(pl_sb_irregular_s) # pl_sb_irregular_keys = enclose('|'.join(pl_sb_irregular.keys())) pl_sb_irregular_caps = { - 'Romany': 'Romanies', - 'Jerry': 'Jerrys', - 'Mary': 'Marys', - 'Rom': 'Roma', + "Romany": "Romanies", + "Jerry": "Jerrys", + "Mary": "Marys", + "Rom": "Roma", } -pl_sb_irregular_compound = { - "prima donna": "prima donnas|prime donne", -} +pl_sb_irregular_compound = {"prima donna": "prima donnas|prime donne"} si_sb_irregular = dict([(v, k) for (k, v) in pl_sb_irregular.items()]) keys = list(si_sb_irregular.keys()) for k in keys: - if '|' in k: - k1, k2 = k.split('|') + if "|" in k: + k1, k2 = k.split("|") si_sb_irregular[k1] = si_sb_irregular[k2] = si_sb_irregular[k] del si_sb_irregular[k] si_sb_irregular_caps = dict([(v, k) for (k, v) in pl_sb_irregular_caps.items()]) si_sb_irregular_compound = dict([(v, k) for (k, v) in pl_sb_irregular_compound.items()]) keys = list(si_sb_irregular_compound.keys()) for k in keys: - if '|' in k: - k1, k2 = k.split('|') - si_sb_irregular_compound[k1] = si_sb_irregular_compound[k2] = si_sb_irregular_compound[k] + if "|" in k: + k1, k2 = k.split("|") + si_sb_irregular_compound[k1] = si_sb_irregular_compound[ + k2 + ] = si_sb_irregular_compound[k] del si_sb_irregular_compound[k] # si_sb_irregular_keys = enclose('|'.join(si_sb_irregular.keys())) # Z's that don't double -pl_sb_z_zes_list = ( - "quartz", "topaz", -) +pl_sb_z_zes_list = ("quartz", "topaz") pl_sb_z_zes_bysize = bysize(pl_sb_z_zes_list) -pl_sb_ze_zes_list = ('snooze',) +pl_sb_ze_zes_list = ("snooze",) pl_sb_ze_zes_bysize = bysize(pl_sb_ze_zes_list) @@ -266,300 +264,573 @@ pl_sb_ze_zes_bysize = bysize(pl_sb_ze_zes_list) pl_sb_C_is_ides_complete = [ # GENERAL WORDS... - "ephemeris", "iris", "clitoris", - "chrysalis", "epididymis", + "ephemeris", + "iris", + "clitoris", + "chrysalis", + "epididymis", ] pl_sb_C_is_ides_endings = [ # INFLAMATIONS... - "itis", + "itis" ] -pl_sb_C_is_ides = joinstem(-2, pl_sb_C_is_ides_complete + ['.*%s' % w for w in pl_sb_C_is_ides_endings]) +pl_sb_C_is_ides = joinstem( + -2, pl_sb_C_is_ides_complete + [".*%s" % w for w in pl_sb_C_is_ides_endings] +) pl_sb_C_is_ides_list = pl_sb_C_is_ides_complete + pl_sb_C_is_ides_endings -(si_sb_C_is_ides_list, si_sb_C_is_ides_bysize, - pl_sb_C_is_ides_bysize) = make_pl_si_lists(pl_sb_C_is_ides_list, 'ides', 2, dojoinstem=False) +( + si_sb_C_is_ides_list, + si_sb_C_is_ides_bysize, + pl_sb_C_is_ides_bysize, +) = make_pl_si_lists(pl_sb_C_is_ides_list, "ides", 2, dojoinstem=False) # CLASSICAL "..a" -> "..ata" pl_sb_C_a_ata_list = ( - "anathema", "bema", "carcinoma", "charisma", "diploma", - "dogma", "drama", "edema", "enema", "enigma", "lemma", - "lymphoma", "magma", "melisma", "miasma", "oedema", - "sarcoma", "schema", "soma", "stigma", "stoma", "trauma", - "gumma", "pragma", + "anathema", + "bema", + "carcinoma", + "charisma", + "diploma", + "dogma", + "drama", + "edema", + "enema", + "enigma", + "lemma", + "lymphoma", + "magma", + "melisma", + "miasma", + "oedema", + "sarcoma", + "schema", + "soma", + "stigma", + "stoma", + "trauma", + "gumma", + "pragma", ) -(si_sb_C_a_ata_list, si_sb_C_a_ata_bysize, - pl_sb_C_a_ata_bysize, pl_sb_C_a_ata) = make_pl_si_lists(pl_sb_C_a_ata_list, 'ata', 1) +( + si_sb_C_a_ata_list, + si_sb_C_a_ata_bysize, + pl_sb_C_a_ata_bysize, + pl_sb_C_a_ata, +) = make_pl_si_lists(pl_sb_C_a_ata_list, "ata", 1) # UNCONDITIONAL "..a" -> "..ae" -pl_sb_U_a_ae_list = ( - "alumna", "alga", "vertebra", "persona" -) -(si_sb_U_a_ae_list, si_sb_U_a_ae_bysize, - pl_sb_U_a_ae_bysize, pl_sb_U_a_ae) = make_pl_si_lists(pl_sb_U_a_ae_list, 'e', None) +pl_sb_U_a_ae_list = ("alumna", "alga", "vertebra", "persona") +( + si_sb_U_a_ae_list, + si_sb_U_a_ae_bysize, + pl_sb_U_a_ae_bysize, + pl_sb_U_a_ae, +) = make_pl_si_lists(pl_sb_U_a_ae_list, "e", None) # CLASSICAL "..a" -> "..ae" pl_sb_C_a_ae_list = ( - "amoeba", "antenna", "formula", "hyperbola", - "medusa", "nebula", "parabola", "abscissa", - "hydra", "nova", "lacuna", "aurora", "umbra", - "flora", "fauna", + "amoeba", + "antenna", + "formula", + "hyperbola", + "medusa", + "nebula", + "parabola", + "abscissa", + "hydra", + "nova", + "lacuna", + "aurora", + "umbra", + "flora", + "fauna", ) -(si_sb_C_a_ae_list, si_sb_C_a_ae_bysize, - pl_sb_C_a_ae_bysize, pl_sb_C_a_ae) = make_pl_si_lists(pl_sb_C_a_ae_list, 'e', None) +( + si_sb_C_a_ae_list, + si_sb_C_a_ae_bysize, + pl_sb_C_a_ae_bysize, + pl_sb_C_a_ae, +) = make_pl_si_lists(pl_sb_C_a_ae_list, "e", None) # CLASSICAL "..en" -> "..ina" -pl_sb_C_en_ina_list = ( - "stamen", "foramen", "lumen", -) +pl_sb_C_en_ina_list = ("stamen", "foramen", "lumen") -(si_sb_C_en_ina_list, si_sb_C_en_ina_bysize, - pl_sb_C_en_ina_bysize, pl_sb_C_en_ina) = make_pl_si_lists(pl_sb_C_en_ina_list, 'ina', 2) +( + si_sb_C_en_ina_list, + si_sb_C_en_ina_bysize, + pl_sb_C_en_ina_bysize, + pl_sb_C_en_ina, +) = make_pl_si_lists(pl_sb_C_en_ina_list, "ina", 2) # UNCONDITIONAL "..um" -> "..a" pl_sb_U_um_a_list = ( - "bacterium", "agendum", "desideratum", "erratum", - "stratum", "datum", "ovum", "extremum", + "bacterium", + "agendum", + "desideratum", + "erratum", + "stratum", + "datum", + "ovum", + "extremum", "candelabrum", ) -(si_sb_U_um_a_list, si_sb_U_um_a_bysize, - pl_sb_U_um_a_bysize, pl_sb_U_um_a) = make_pl_si_lists(pl_sb_U_um_a_list, 'a', 2) +( + si_sb_U_um_a_list, + si_sb_U_um_a_bysize, + pl_sb_U_um_a_bysize, + pl_sb_U_um_a, +) = make_pl_si_lists(pl_sb_U_um_a_list, "a", 2) # CLASSICAL "..um" -> "..a" pl_sb_C_um_a_list = ( - "maximum", "minimum", "momentum", "optimum", - "quantum", "cranium", "curriculum", "dictum", - "phylum", "aquarium", "compendium", "emporium", - "enconium", "gymnasium", "honorarium", "interregnum", - "lustrum", "memorandum", "millennium", "rostrum", - "spectrum", "speculum", "stadium", "trapezium", - "ultimatum", "medium", "vacuum", "velum", - "consortium", "arboretum", + "maximum", + "minimum", + "momentum", + "optimum", + "quantum", + "cranium", + "curriculum", + "dictum", + "phylum", + "aquarium", + "compendium", + "emporium", + "enconium", + "gymnasium", + "honorarium", + "interregnum", + "lustrum", + "memorandum", + "millennium", + "rostrum", + "spectrum", + "speculum", + "stadium", + "trapezium", + "ultimatum", + "medium", + "vacuum", + "velum", + "consortium", + "arboretum", ) -(si_sb_C_um_a_list, si_sb_C_um_a_bysize, - pl_sb_C_um_a_bysize, pl_sb_C_um_a) = make_pl_si_lists(pl_sb_C_um_a_list, 'a', 2) +( + si_sb_C_um_a_list, + si_sb_C_um_a_bysize, + pl_sb_C_um_a_bysize, + pl_sb_C_um_a, +) = make_pl_si_lists(pl_sb_C_um_a_list, "a", 2) # UNCONDITIONAL "..us" -> "i" pl_sb_U_us_i_list = ( - "alumnus", "alveolus", "bacillus", "bronchus", - "locus", "nucleus", "stimulus", "meniscus", + "alumnus", + "alveolus", + "bacillus", + "bronchus", + "locus", + "nucleus", + "stimulus", + "meniscus", "sarcophagus", ) -(si_sb_U_us_i_list, si_sb_U_us_i_bysize, - pl_sb_U_us_i_bysize, pl_sb_U_us_i) = make_pl_si_lists(pl_sb_U_us_i_list, 'i', 2) +( + si_sb_U_us_i_list, + si_sb_U_us_i_bysize, + pl_sb_U_us_i_bysize, + pl_sb_U_us_i, +) = make_pl_si_lists(pl_sb_U_us_i_list, "i", 2) # CLASSICAL "..us" -> "..i" pl_sb_C_us_i_list = ( - "focus", "radius", "genius", - "incubus", "succubus", "nimbus", - "fungus", "nucleolus", "stylus", - "torus", "umbilicus", "uterus", - "hippopotamus", "cactus", + "focus", + "radius", + "genius", + "incubus", + "succubus", + "nimbus", + "fungus", + "nucleolus", + "stylus", + "torus", + "umbilicus", + "uterus", + "hippopotamus", + "cactus", ) -(si_sb_C_us_i_list, si_sb_C_us_i_bysize, - pl_sb_C_us_i_bysize, pl_sb_C_us_i) = make_pl_si_lists(pl_sb_C_us_i_list, 'i', 2) +( + si_sb_C_us_i_list, + si_sb_C_us_i_bysize, + pl_sb_C_us_i_bysize, + pl_sb_C_us_i, +) = make_pl_si_lists(pl_sb_C_us_i_list, "i", 2) # CLASSICAL "..us" -> "..us" (ASSIMILATED 4TH DECLENSION LATIN NOUNS) pl_sb_C_us_us = ( - "status", "apparatus", "prospectus", "sinus", - "hiatus", "impetus", "plexus", + "status", + "apparatus", + "prospectus", + "sinus", + "hiatus", + "impetus", + "plexus", ) pl_sb_C_us_us_bysize = bysize(pl_sb_C_us_us) # UNCONDITIONAL "..on" -> "a" pl_sb_U_on_a_list = ( - "criterion", "perihelion", "aphelion", - "phenomenon", "prolegomenon", "noumenon", - "organon", "asyndeton", "hyperbaton", + "criterion", + "perihelion", + "aphelion", + "phenomenon", + "prolegomenon", + "noumenon", + "organon", + "asyndeton", + "hyperbaton", ) -(si_sb_U_on_a_list, si_sb_U_on_a_bysize, - pl_sb_U_on_a_bysize, pl_sb_U_on_a) = make_pl_si_lists(pl_sb_U_on_a_list, 'a', 2) +( + si_sb_U_on_a_list, + si_sb_U_on_a_bysize, + pl_sb_U_on_a_bysize, + pl_sb_U_on_a, +) = make_pl_si_lists(pl_sb_U_on_a_list, "a", 2) # CLASSICAL "..on" -> "..a" -pl_sb_C_on_a_list = ( - "oxymoron", -) +pl_sb_C_on_a_list = ("oxymoron",) -(si_sb_C_on_a_list, si_sb_C_on_a_bysize, - pl_sb_C_on_a_bysize, pl_sb_C_on_a) = make_pl_si_lists(pl_sb_C_on_a_list, 'a', 2) +( + si_sb_C_on_a_list, + si_sb_C_on_a_bysize, + pl_sb_C_on_a_bysize, + pl_sb_C_on_a, +) = make_pl_si_lists(pl_sb_C_on_a_list, "a", 2) # CLASSICAL "..o" -> "..i" (BUT NORMALLY -> "..os") pl_sb_C_o_i = [ - "solo", "soprano", "basso", "alto", - "contralto", "tempo", "piano", "virtuoso", + "solo", + "soprano", + "basso", + "alto", + "contralto", + "tempo", + "piano", + "virtuoso", ] # list not tuple so can concat for pl_sb_U_o_os pl_sb_C_o_i_bysize = bysize(pl_sb_C_o_i) -si_sb_C_o_i_bysize = bysize(['%si' % w[:-1] for w in pl_sb_C_o_i]) +si_sb_C_o_i_bysize = bysize(["%si" % w[:-1] for w in pl_sb_C_o_i]) pl_sb_C_o_i_stems = joinstem(-1, pl_sb_C_o_i) # ALWAYS "..o" -> "..os" -pl_sb_U_o_os_complete = set(( - "ado", "ISO", "NATO", "NCO", "NGO", "oto", -)) -si_sb_U_o_os_complete = set('%ss' % w for w in pl_sb_U_o_os_complete) +pl_sb_U_o_os_complete = set(("ado", "ISO", "NATO", "NCO", "NGO", "oto")) +si_sb_U_o_os_complete = set("%ss" % w for w in pl_sb_U_o_os_complete) pl_sb_U_o_os_endings = [ - "aficionado", "aggro", - "albino", "allegro", "ammo", - "Antananarivo", "archipelago", "armadillo", - "auto", "avocado", "Bamako", - "Barquisimeto", "bimbo", "bingo", - "Biro", "bolero", "Bolzano", - "bongo", "Boto", "burro", - "Cairo", "canto", "cappuccino", - "casino", "cello", "Chicago", - "Chimango", "cilantro", "cochito", - "coco", "Colombo", "Colorado", - "commando", "concertino", "contango", - "credo", "crescendo", "cyano", - "demo", "ditto", "Draco", - "dynamo", "embryo", "Esperanto", - "espresso", "euro", "falsetto", - "Faro", "fiasco", "Filipino", - "flamenco", "furioso", "generalissimo", - "Gestapo", "ghetto", "gigolo", - "gizmo", "Greensboro", "gringo", - "Guaiabero", "guano", "gumbo", - "gyro", "hairdo", "hippo", - "Idaho", "impetigo", "inferno", - "info", "intermezzo", "intertrigo", - "Iquico", "jumbo", - "junto", "Kakapo", "kilo", - "Kinkimavo", "Kokako", "Kosovo", - "Lesotho", "libero", "libido", - "libretto", "lido", "Lilo", - "limbo", "limo", "lineno", - "lingo", "lino", "livedo", - "loco", "logo", "lumbago", - "macho", "macro", "mafioso", - "magneto", "magnifico", "Majuro", - "Malabo", "manifesto", "Maputo", - "Maracaibo", "medico", "memo", - "metro", "Mexico", "micro", - "Milano", "Monaco", "mono", - "Montenegro", "Morocco", "Muqdisho", + "aficionado", + "aggro", + "albino", + "allegro", + "ammo", + "Antananarivo", + "archipelago", + "armadillo", + "auto", + "avocado", + "Bamako", + "Barquisimeto", + "bimbo", + "bingo", + "Biro", + "bolero", + "Bolzano", + "bongo", + "Boto", + "burro", + "Cairo", + "canto", + "cappuccino", + "casino", + "cello", + "Chicago", + "Chimango", + "cilantro", + "cochito", + "coco", + "Colombo", + "Colorado", + "commando", + "concertino", + "contango", + "credo", + "crescendo", + "cyano", + "demo", + "ditto", + "Draco", + "dynamo", + "embryo", + "Esperanto", + "espresso", + "euro", + "falsetto", + "Faro", + "fiasco", + "Filipino", + "flamenco", + "furioso", + "generalissimo", + "Gestapo", + "ghetto", + "gigolo", + "gizmo", + "Greensboro", + "gringo", + "Guaiabero", + "guano", + "gumbo", + "gyro", + "hairdo", + "hippo", + "Idaho", + "impetigo", + "inferno", + "info", + "intermezzo", + "intertrigo", + "Iquico", + "jumbo", + "junto", + "Kakapo", + "kilo", + "Kinkimavo", + "Kokako", + "Kosovo", + "Lesotho", + "libero", + "libido", + "libretto", + "lido", + "Lilo", + "limbo", + "limo", + "lineno", + "lingo", + "lino", + "livedo", + "loco", + "logo", + "lumbago", + "macho", + "macro", + "mafioso", + "magneto", + "magnifico", + "Majuro", + "Malabo", + "manifesto", + "Maputo", + "Maracaibo", + "medico", + "memo", + "metro", + "Mexico", + "micro", + "Milano", + "Monaco", + "mono", + "Montenegro", + "Morocco", + "Muqdisho", "myo", - "neutrino", "Ningbo", - "octavo", "oregano", "Orinoco", - "Orlando", "Oslo", - "panto", "Paramaribo", "Pardusco", - "pedalo", "photo", "pimento", - "pinto", "pleco", "Pluto", - "pogo", "polo", "poncho", - "Porto-Novo", "Porto", "pro", - "psycho", "pueblo", "quarto", - "Quito", "rhino", "risotto", - "rococo", "rondo", "Sacramento", - "saddo", "sago", "salvo", - "Santiago", "Sapporo", "Sarajevo", - "scherzando", "scherzo", "silo", - "sirocco", "sombrero", "staccato", - "sterno", "stucco", "stylo", - "sumo", "Taiko", "techno", - "terrazzo", "testudo", "timpano", - "tiro", "tobacco", "Togo", - "Tokyo", "torero", "Torino", - "Toronto", "torso", "tremolo", - "typo", "tyro", "ufo", - "UNESCO", "vaquero", "vermicello", - "verso", "vibrato", "violoncello", - "Virgo", "weirdo", "WHO", - "WTO", "Yamoussoukro", "yo-yo", - "zero", "Zibo", + "neutrino", + "Ningbo", + "octavo", + "oregano", + "Orinoco", + "Orlando", + "Oslo", + "panto", + "Paramaribo", + "Pardusco", + "pedalo", + "photo", + "pimento", + "pinto", + "pleco", + "Pluto", + "pogo", + "polo", + "poncho", + "Porto-Novo", + "Porto", + "pro", + "psycho", + "pueblo", + "quarto", + "Quito", + "rhino", + "risotto", + "rococo", + "rondo", + "Sacramento", + "saddo", + "sago", + "salvo", + "Santiago", + "Sapporo", + "Sarajevo", + "scherzando", + "scherzo", + "silo", + "sirocco", + "sombrero", + "staccato", + "sterno", + "stucco", + "stylo", + "sumo", + "Taiko", + "techno", + "terrazzo", + "testudo", + "timpano", + "tiro", + "tobacco", + "Togo", + "Tokyo", + "torero", + "Torino", + "Toronto", + "torso", + "tremolo", + "typo", + "tyro", + "ufo", + "UNESCO", + "vaquero", + "vermicello", + "verso", + "vibrato", + "violoncello", + "Virgo", + "weirdo", + "WHO", + "WTO", + "Yamoussoukro", + "yo-yo", + "zero", + "Zibo", ] + pl_sb_C_o_i pl_sb_U_o_os_bysize = bysize(pl_sb_U_o_os_endings) -si_sb_U_o_os_bysize = bysize(['%ss' % w for w in pl_sb_U_o_os_endings]) +si_sb_U_o_os_bysize = bysize(["%ss" % w for w in pl_sb_U_o_os_endings]) # UNCONDITIONAL "..ch" -> "..chs" -pl_sb_U_ch_chs_list = ( - "czech", "eunuch", "stomach" -) +pl_sb_U_ch_chs_list = ("czech", "eunuch", "stomach") -(si_sb_U_ch_chs_list, si_sb_U_ch_chs_bysize, - pl_sb_U_ch_chs_bysize, pl_sb_U_ch_chs) = make_pl_si_lists(pl_sb_U_ch_chs_list, 's', None) +( + si_sb_U_ch_chs_list, + si_sb_U_ch_chs_bysize, + pl_sb_U_ch_chs_bysize, + pl_sb_U_ch_chs, +) = make_pl_si_lists(pl_sb_U_ch_chs_list, "s", None) # UNCONDITIONAL "..[ei]x" -> "..ices" -pl_sb_U_ex_ices_list = ( - "codex", "murex", "silex", -) -(si_sb_U_ex_ices_list, si_sb_U_ex_ices_bysize, - pl_sb_U_ex_ices_bysize, pl_sb_U_ex_ices) = make_pl_si_lists(pl_sb_U_ex_ices_list, 'ices', 2) +pl_sb_U_ex_ices_list = ("codex", "murex", "silex") +( + si_sb_U_ex_ices_list, + si_sb_U_ex_ices_bysize, + pl_sb_U_ex_ices_bysize, + pl_sb_U_ex_ices, +) = make_pl_si_lists(pl_sb_U_ex_ices_list, "ices", 2) -pl_sb_U_ix_ices_list = ( - "radix", "helix", -) -(si_sb_U_ix_ices_list, si_sb_U_ix_ices_bysize, - pl_sb_U_ix_ices_bysize, pl_sb_U_ix_ices) = make_pl_si_lists(pl_sb_U_ix_ices_list, 'ices', 2) +pl_sb_U_ix_ices_list = ("radix", "helix") +( + si_sb_U_ix_ices_list, + si_sb_U_ix_ices_bysize, + pl_sb_U_ix_ices_bysize, + pl_sb_U_ix_ices, +) = make_pl_si_lists(pl_sb_U_ix_ices_list, "ices", 2) # CLASSICAL "..[ei]x" -> "..ices" pl_sb_C_ex_ices_list = ( - "vortex", "vertex", "cortex", "latex", - "pontifex", "apex", "index", "simplex", + "vortex", + "vertex", + "cortex", + "latex", + "pontifex", + "apex", + "index", + "simplex", ) -(si_sb_C_ex_ices_list, si_sb_C_ex_ices_bysize, - pl_sb_C_ex_ices_bysize, pl_sb_C_ex_ices) = make_pl_si_lists(pl_sb_C_ex_ices_list, 'ices', 2) +( + si_sb_C_ex_ices_list, + si_sb_C_ex_ices_bysize, + pl_sb_C_ex_ices_bysize, + pl_sb_C_ex_ices, +) = make_pl_si_lists(pl_sb_C_ex_ices_list, "ices", 2) -pl_sb_C_ix_ices_list = ( - "appendix", -) +pl_sb_C_ix_ices_list = ("appendix",) -(si_sb_C_ix_ices_list, si_sb_C_ix_ices_bysize, - pl_sb_C_ix_ices_bysize, pl_sb_C_ix_ices) = make_pl_si_lists(pl_sb_C_ix_ices_list, 'ices', 2) +( + si_sb_C_ix_ices_list, + si_sb_C_ix_ices_bysize, + pl_sb_C_ix_ices_bysize, + pl_sb_C_ix_ices, +) = make_pl_si_lists(pl_sb_C_ix_ices_list, "ices", 2) # ARABIC: ".." -> "..i" -pl_sb_C_i_list = ( - "afrit", "afreet", "efreet", -) +pl_sb_C_i_list = ("afrit", "afreet", "efreet") -(si_sb_C_i_list, si_sb_C_i_bysize, - pl_sb_C_i_bysize, pl_sb_C_i) = make_pl_si_lists(pl_sb_C_i_list, 'i', None) +(si_sb_C_i_list, si_sb_C_i_bysize, pl_sb_C_i_bysize, pl_sb_C_i) = make_pl_si_lists( + pl_sb_C_i_list, "i", None +) # HEBREW: ".." -> "..im" -pl_sb_C_im_list = ( - "goy", "seraph", "cherub", -) +pl_sb_C_im_list = ("goy", "seraph", "cherub") -(si_sb_C_im_list, si_sb_C_im_bysize, - pl_sb_C_im_bysize, pl_sb_C_im) = make_pl_si_lists(pl_sb_C_im_list, 'im', None) +(si_sb_C_im_list, si_sb_C_im_bysize, pl_sb_C_im_bysize, pl_sb_C_im) = make_pl_si_lists( + pl_sb_C_im_list, "im", None +) # UNCONDITIONAL "..man" -> "..mans" @@ -576,91 +847,172 @@ pl_sb_U_man_mans_caps_list = """ Yokohaman Yuman """.split() -(si_sb_U_man_mans_list, si_sb_U_man_mans_bysize, - pl_sb_U_man_mans_bysize) = make_pl_si_lists(pl_sb_U_man_mans_list, 's', None, dojoinstem=False) -(si_sb_U_man_mans_caps_list, si_sb_U_man_mans_caps_bysize, - pl_sb_U_man_mans_caps_bysize) = make_pl_si_lists(pl_sb_U_man_mans_caps_list, 's', None, dojoinstem=False) +( + si_sb_U_man_mans_list, + si_sb_U_man_mans_bysize, + pl_sb_U_man_mans_bysize, +) = make_pl_si_lists(pl_sb_U_man_mans_list, "s", None, dojoinstem=False) +( + si_sb_U_man_mans_caps_list, + si_sb_U_man_mans_caps_bysize, + pl_sb_U_man_mans_caps_bysize, +) = make_pl_si_lists(pl_sb_U_man_mans_caps_list, "s", None, dojoinstem=False) pl_sb_uninflected_s_complete = [ # PAIRS OR GROUPS SUBSUMED TO A SINGULAR... - "breeches", "britches", "pajamas", "pyjamas", "clippers", "gallows", - "hijinks", "headquarters", "pliers", "scissors", "testes", "herpes", - "pincers", "shears", "proceedings", "trousers", - + "breeches", + "britches", + "pajamas", + "pyjamas", + "clippers", + "gallows", + "hijinks", + "headquarters", + "pliers", + "scissors", + "testes", + "herpes", + "pincers", + "shears", + "proceedings", + "trousers", # UNASSIMILATED LATIN 4th DECLENSION - - "cantus", "coitus", "nexus", - + "cantus", + "coitus", + "nexus", # RECENT IMPORTS... - "contretemps", "corps", "debris", + "contretemps", + "corps", + "debris", "siemens", - # DISEASES "mumps", - # MISCELLANEOUS OTHERS... - "diabetes", "jackanapes", "series", "species", "subspecies", "rabies", - "chassis", "innings", "news", "mews", "haggis", + "diabetes", + "jackanapes", + "series", + "species", + "subspecies", + "rabies", + "chassis", + "innings", + "news", + "mews", + "haggis", ] pl_sb_uninflected_s_endings = [ # RECENT IMPORTS... "ois", - # DISEASES "measles", ] -pl_sb_uninflected_s = pl_sb_uninflected_s_complete + ['.*%s' % w for w in pl_sb_uninflected_s_endings] +pl_sb_uninflected_s = pl_sb_uninflected_s_complete + [ + ".*%s" % w for w in pl_sb_uninflected_s_endings +] pl_sb_uninflected_herd = ( # DON'T INFLECT IN CLASSICAL MODE, OTHERWISE NORMAL INFLECTION - "wildebeest", "swine", "eland", "bison", "buffalo", - "elk", "rhinoceros", 'zucchini', - 'caribou', 'dace', 'grouse', 'guinea fowl', 'guinea-fowl', - 'haddock', 'hake', 'halibut', 'herring', 'mackerel', - 'pickerel', 'pike', 'roe', 'seed', 'shad', - 'snipe', 'teal', 'turbot', 'water fowl', 'water-fowl', + "wildebeest", + "swine", + "eland", + "bison", + "buffalo", + "elk", + "rhinoceros", + "zucchini", + "caribou", + "dace", + "grouse", + "guinea fowl", + "guinea-fowl", + "haddock", + "hake", + "halibut", + "herring", + "mackerel", + "pickerel", + "pike", + "roe", + "seed", + "shad", + "snipe", + "teal", + "turbot", + "water fowl", + "water-fowl", ) pl_sb_uninflected_complete = [ # SOME FISH AND HERD ANIMALS - "tuna", "salmon", "mackerel", "trout", - "bream", "sea-bass", "sea bass", "carp", "cod", "flounder", "whiting", + "tuna", + "salmon", + "mackerel", + "trout", + "bream", + "sea-bass", + "sea bass", + "carp", + "cod", + "flounder", + "whiting", "moose", - # OTHER ODDITIES - "graffiti", "djinn", 'samuri', - 'offspring', 'pence', 'quid', 'hertz', + "graffiti", + "djinn", + "samuri", + "offspring", + "pence", + "quid", + "hertz", ] + pl_sb_uninflected_s_complete # SOME WORDS ENDING IN ...s (OFTEN PAIRS TAKEN AS A WHOLE) pl_sb_uninflected_caps = [ # ALL NATIONALS ENDING IN -ese - "Portuguese", "Amoyese", "Borghese", "Congoese", "Faroese", - "Foochowese", "Genevese", "Genoese", "Gilbertese", "Hottentotese", - "Kiplingese", "Kongoese", "Lucchese", "Maltese", "Nankingese", - "Niasese", "Pekingese", "Piedmontese", "Pistoiese", "Sarawakese", - "Shavese", "Vermontese", "Wenchowese", "Yengeese", + "Portuguese", + "Amoyese", + "Borghese", + "Congoese", + "Faroese", + "Foochowese", + "Genevese", + "Genoese", + "Gilbertese", + "Hottentotese", + "Kiplingese", + "Kongoese", + "Lucchese", + "Maltese", + "Nankingese", + "Niasese", + "Pekingese", + "Piedmontese", + "Pistoiese", + "Sarawakese", + "Shavese", + "Vermontese", + "Wenchowese", + "Yengeese", ] pl_sb_uninflected_endings = [ # SOME FISH AND HERD ANIMALS "fish", - - "deer", "sheep", - + "deer", + "sheep", # ALL NATIONALS ENDING IN -ese - "nese", "rese", "lese", "mese", - + "nese", + "rese", + "lese", + "mese", # DISEASES "pox", - - # OTHER ODDITIES - 'craft', + "craft", ] + pl_sb_uninflected_s_endings # SOME WORDS ENDING IN ...s (OFTEN PAIRS TAKEN AS A WHOLE) @@ -671,208 +1023,530 @@ pl_sb_uninflected_bysize = bysize(pl_sb_uninflected_endings) # SINGULAR WORDS ENDING IN ...s (ALL INFLECT WITH ...es) pl_sb_singular_s_complete = [ - "acropolis", "aegis", "alias", "asbestos", "bathos", "bias", - "bronchitis", "bursitis", "caddis", "cannabis", - "canvas", "chaos", "cosmos", "dais", "digitalis", - "epidermis", "ethos", "eyas", "gas", "glottis", - "hubris", "ibis", "lens", "mantis", "marquis", "metropolis", - "pathos", "pelvis", "polis", "rhinoceros", - "sassafras", "trellis", + "acropolis", + "aegis", + "alias", + "asbestos", + "bathos", + "bias", + "bronchitis", + "bursitis", + "caddis", + "cannabis", + "canvas", + "chaos", + "cosmos", + "dais", + "digitalis", + "epidermis", + "ethos", + "eyas", + "gas", + "glottis", + "hubris", + "ibis", + "lens", + "mantis", + "marquis", + "metropolis", + "pathos", + "pelvis", + "polis", + "rhinoceros", + "sassafras", + "trellis", ] + pl_sb_C_is_ides_complete -pl_sb_singular_s_endings = [ - "ss", "us", -] + pl_sb_C_is_ides_endings +pl_sb_singular_s_endings = ["ss", "us"] + pl_sb_C_is_ides_endings pl_sb_singular_s_bysize = bysize(pl_sb_singular_s_endings) -si_sb_singular_s_complete = ['%ses' % w for w in pl_sb_singular_s_complete] -si_sb_singular_s_endings = ['%ses' % w for w in pl_sb_singular_s_endings] +si_sb_singular_s_complete = ["%ses" % w for w in pl_sb_singular_s_complete] +si_sb_singular_s_endings = ["%ses" % w for w in pl_sb_singular_s_endings] si_sb_singular_s_bysize = bysize(si_sb_singular_s_endings) -pl_sb_singular_s_es = [ - "[A-Z].*es", -] +pl_sb_singular_s_es = ["[A-Z].*es"] -pl_sb_singular_s = enclose('|'.join(pl_sb_singular_s_complete + - ['.*%s' % w for w in pl_sb_singular_s_endings] + - pl_sb_singular_s_es)) +pl_sb_singular_s = enclose( + "|".join( + pl_sb_singular_s_complete + + [".*%s" % w for w in pl_sb_singular_s_endings] + + pl_sb_singular_s_es + ) +) # PLURALS ENDING IN uses -> use -si_sb_ois_oi_case = ( - 'Bolshois', 'Hanois' -) +si_sb_ois_oi_case = ("Bolshois", "Hanois") -si_sb_uses_use_case = ( - 'Betelgeuses', 'Duses', 'Meuses', 'Syracuses', 'Toulouses', -) +si_sb_uses_use_case = ("Betelgeuses", "Duses", "Meuses", "Syracuses", "Toulouses") si_sb_uses_use = ( - 'abuses', 'applauses', 'blouses', - 'carouses', 'causes', 'chartreuses', 'clauses', - 'contuses', 'douses', 'excuses', 'fuses', - 'grouses', 'hypotenuses', 'masseuses', - 'menopauses', 'misuses', 'muses', 'overuses', 'pauses', - 'peruses', 'profuses', 'recluses', 'reuses', - 'ruses', 'souses', 'spouses', 'suffuses', 'transfuses', 'uses', + "abuses", + "applauses", + "blouses", + "carouses", + "causes", + "chartreuses", + "clauses", + "contuses", + "douses", + "excuses", + "fuses", + "grouses", + "hypotenuses", + "masseuses", + "menopauses", + "misuses", + "muses", + "overuses", + "pauses", + "peruses", + "profuses", + "recluses", + "reuses", + "ruses", + "souses", + "spouses", + "suffuses", + "transfuses", + "uses", ) si_sb_ies_ie_case = ( - 'Addies', 'Aggies', 'Allies', 'Amies', 'Angies', 'Annies', - 'Annmaries', 'Archies', 'Arties', 'Aussies', 'Barbies', - 'Barries', 'Basies', 'Bennies', 'Bernies', 'Berties', 'Bessies', - 'Betties', 'Billies', 'Blondies', 'Bobbies', 'Bonnies', - 'Bowies', 'Brandies', 'Bries', 'Brownies', 'Callies', - 'Carnegies', 'Carries', 'Cassies', 'Charlies', 'Cheries', - 'Christies', 'Connies', 'Curies', 'Dannies', 'Debbies', 'Dixies', - 'Dollies', 'Donnies', 'Drambuies', 'Eddies', 'Effies', 'Ellies', - 'Elsies', 'Eries', 'Ernies', 'Essies', 'Eugenies', 'Fannies', - 'Flossies', 'Frankies', 'Freddies', 'Gillespies', 'Goldies', - 'Gracies', 'Guthries', 'Hallies', 'Hatties', 'Hetties', - 'Hollies', 'Jackies', 'Jamies', 'Janies', 'Jannies', 'Jeanies', - 'Jeannies', 'Jennies', 'Jessies', 'Jimmies', 'Jodies', 'Johnies', - 'Johnnies', 'Josies', 'Julies', 'Kalgoorlies', 'Kathies', 'Katies', - 'Kellies', 'Kewpies', 'Kristies', 'Laramies', 'Lassies', 'Lauries', - 'Leslies', 'Lessies', 'Lillies', 'Lizzies', 'Lonnies', 'Lories', - 'Lorries', 'Lotties', 'Louies', 'Mackenzies', 'Maggies', 'Maisies', - 'Mamies', 'Marcies', 'Margies', 'Maries', 'Marjories', 'Matties', - 'McKenzies', 'Melanies', 'Mickies', 'Millies', 'Minnies', 'Mollies', - 'Mounties', 'Nannies', 'Natalies', 'Nellies', 'Netties', 'Ollies', - 'Ozzies', 'Pearlies', 'Pottawatomies', 'Reggies', 'Richies', 'Rickies', - 'Robbies', 'Ronnies', 'Rosalies', 'Rosemaries', 'Rosies', 'Roxies', - 'Rushdies', 'Ruthies', 'Sadies', 'Sallies', 'Sammies', 'Scotties', - 'Selassies', 'Sherries', 'Sophies', 'Stacies', 'Stefanies', 'Stephanies', - 'Stevies', 'Susies', 'Sylvies', 'Tammies', 'Terries', 'Tessies', - 'Tommies', 'Tracies', 'Trekkies', 'Valaries', 'Valeries', 'Valkyries', - 'Vickies', 'Virgies', 'Willies', 'Winnies', 'Wylies', 'Yorkies', + "Addies", + "Aggies", + "Allies", + "Amies", + "Angies", + "Annies", + "Annmaries", + "Archies", + "Arties", + "Aussies", + "Barbies", + "Barries", + "Basies", + "Bennies", + "Bernies", + "Berties", + "Bessies", + "Betties", + "Billies", + "Blondies", + "Bobbies", + "Bonnies", + "Bowies", + "Brandies", + "Bries", + "Brownies", + "Callies", + "Carnegies", + "Carries", + "Cassies", + "Charlies", + "Cheries", + "Christies", + "Connies", + "Curies", + "Dannies", + "Debbies", + "Dixies", + "Dollies", + "Donnies", + "Drambuies", + "Eddies", + "Effies", + "Ellies", + "Elsies", + "Eries", + "Ernies", + "Essies", + "Eugenies", + "Fannies", + "Flossies", + "Frankies", + "Freddies", + "Gillespies", + "Goldies", + "Gracies", + "Guthries", + "Hallies", + "Hatties", + "Hetties", + "Hollies", + "Jackies", + "Jamies", + "Janies", + "Jannies", + "Jeanies", + "Jeannies", + "Jennies", + "Jessies", + "Jimmies", + "Jodies", + "Johnies", + "Johnnies", + "Josies", + "Julies", + "Kalgoorlies", + "Kathies", + "Katies", + "Kellies", + "Kewpies", + "Kristies", + "Laramies", + "Lassies", + "Lauries", + "Leslies", + "Lessies", + "Lillies", + "Lizzies", + "Lonnies", + "Lories", + "Lorries", + "Lotties", + "Louies", + "Mackenzies", + "Maggies", + "Maisies", + "Mamies", + "Marcies", + "Margies", + "Maries", + "Marjories", + "Matties", + "McKenzies", + "Melanies", + "Mickies", + "Millies", + "Minnies", + "Mollies", + "Mounties", + "Nannies", + "Natalies", + "Nellies", + "Netties", + "Ollies", + "Ozzies", + "Pearlies", + "Pottawatomies", + "Reggies", + "Richies", + "Rickies", + "Robbies", + "Ronnies", + "Rosalies", + "Rosemaries", + "Rosies", + "Roxies", + "Rushdies", + "Ruthies", + "Sadies", + "Sallies", + "Sammies", + "Scotties", + "Selassies", + "Sherries", + "Sophies", + "Stacies", + "Stefanies", + "Stephanies", + "Stevies", + "Susies", + "Sylvies", + "Tammies", + "Terries", + "Tessies", + "Tommies", + "Tracies", + "Trekkies", + "Valaries", + "Valeries", + "Valkyries", + "Vickies", + "Virgies", + "Willies", + "Winnies", + "Wylies", + "Yorkies", ) si_sb_ies_ie = ( - 'aeries', 'baggies', 'belies', 'biggies', 'birdies', 'bogies', - 'bonnies', 'boogies', 'bookies', 'bourgeoisies', 'brownies', - 'budgies', 'caddies', 'calories', 'camaraderies', 'cockamamies', - 'collies', 'cookies', 'coolies', 'cooties', 'coteries', 'crappies', - 'curies', 'cutesies', 'dogies', 'eyrie', 'floozies', 'footsies', - 'freebies', 'genies', 'goalies', 'groupies', - 'hies', 'jalousies', 'junkies', - 'kiddies', 'laddies', 'lassies', 'lies', - 'lingeries', 'magpies', 'menageries', 'mommies', 'movies', 'neckties', - 'newbies', 'nighties', 'oldies', 'organdies', 'overlies', - 'pies', 'pinkies', 'pixies', 'potpies', 'prairies', - 'quickies', 'reveries', 'rookies', 'rotisseries', 'softies', 'sorties', - 'species', 'stymies', 'sweeties', 'ties', 'underlies', 'unties', - 'veggies', 'vies', 'yuppies', 'zombies', + "aeries", + "baggies", + "belies", + "biggies", + "birdies", + "bogies", + "bonnies", + "boogies", + "bookies", + "bourgeoisies", + "brownies", + "budgies", + "caddies", + "calories", + "camaraderies", + "cockamamies", + "collies", + "cookies", + "coolies", + "cooties", + "coteries", + "crappies", + "curies", + "cutesies", + "dogies", + "eyrie", + "floozies", + "footsies", + "freebies", + "genies", + "goalies", + "groupies", + "hies", + "jalousies", + "junkies", + "kiddies", + "laddies", + "lassies", + "lies", + "lingeries", + "magpies", + "menageries", + "mommies", + "movies", + "neckties", + "newbies", + "nighties", + "oldies", + "organdies", + "overlies", + "pies", + "pinkies", + "pixies", + "potpies", + "prairies", + "quickies", + "reveries", + "rookies", + "rotisseries", + "softies", + "sorties", + "species", + "stymies", + "sweeties", + "ties", + "underlies", + "unties", + "veggies", + "vies", + "yuppies", + "zombies", ) si_sb_oes_oe_case = ( - 'Chloes', 'Crusoes', 'Defoes', 'Faeroes', 'Ivanhoes', 'Joes', - 'McEnroes', 'Moes', 'Monroes', 'Noes', 'Poes', 'Roscoes', - 'Tahoes', 'Tippecanoes', 'Zoes', + "Chloes", + "Crusoes", + "Defoes", + "Faeroes", + "Ivanhoes", + "Joes", + "McEnroes", + "Moes", + "Monroes", + "Noes", + "Poes", + "Roscoes", + "Tahoes", + "Tippecanoes", + "Zoes", ) si_sb_oes_oe = ( - 'aloes', 'backhoes', 'canoes', - 'does', 'floes', 'foes', 'hoes', 'mistletoes', - 'oboes', 'pekoes', 'roes', 'sloes', - 'throes', 'tiptoes', 'toes', 'woes', + "aloes", + "backhoes", + "canoes", + "does", + "floes", + "foes", + "hoes", + "mistletoes", + "oboes", + "pekoes", + "roes", + "sloes", + "throes", + "tiptoes", + "toes", + "woes", ) -si_sb_z_zes = ( - "quartzes", "topazes", -) +si_sb_z_zes = ("quartzes", "topazes") -si_sb_zzes_zz = ( - 'buzzes', 'fizzes', 'frizzes', 'razzes' -) +si_sb_zzes_zz = ("buzzes", "fizzes", "frizzes", "razzes") si_sb_ches_che_case = ( - 'Andromaches', 'Apaches', 'Blanches', 'Comanches', - 'Nietzsches', 'Porsches', 'Roches', + "Andromaches", + "Apaches", + "Blanches", + "Comanches", + "Nietzsches", + "Porsches", + "Roches", ) si_sb_ches_che = ( - 'aches', 'avalanches', 'backaches', 'bellyaches', 'caches', - 'cloches', 'creches', 'douches', 'earaches', 'fiches', - 'headaches', 'heartaches', 'microfiches', - 'niches', 'pastiches', 'psyches', 'quiches', - 'stomachaches', 'toothaches', + "aches", + "avalanches", + "backaches", + "bellyaches", + "caches", + "cloches", + "creches", + "douches", + "earaches", + "fiches", + "headaches", + "heartaches", + "microfiches", + "niches", + "pastiches", + "psyches", + "quiches", + "stomachaches", + "toothaches", ) -si_sb_xes_xe = ( - 'annexes', 'axes', 'deluxes', 'pickaxes', -) +si_sb_xes_xe = ("annexes", "axes", "deluxes", "pickaxes") -si_sb_sses_sse_case = ( - 'Hesses', 'Jesses', 'Larousses', 'Matisses', -) +si_sb_sses_sse_case = ("Hesses", "Jesses", "Larousses", "Matisses") si_sb_sses_sse = ( - 'bouillabaisses', 'crevasses', 'demitasses', 'impasses', - 'mousses', 'posses', + "bouillabaisses", + "crevasses", + "demitasses", + "impasses", + "mousses", + "posses", ) si_sb_ves_ve_case = ( # *[nwl]ives -> [nwl]live - 'Clives', 'Palmolives', + "Clives", + "Palmolives", ) si_sb_ves_ve = ( # *[^d]eaves -> eave - 'interweaves', 'weaves', - + "interweaves", + "weaves", # *[nwl]ives -> [nwl]live - 'olives', - + "olives", # *[eoa]lves -> [eoa]lve - 'bivalves', 'dissolves', 'resolves', 'salves', 'twelves', 'valves', + "bivalves", + "dissolves", + "resolves", + "salves", + "twelves", + "valves", ) -plverb_special_s = enclose('|'.join( - [pl_sb_singular_s] + - pl_sb_uninflected_s + - list(pl_sb_irregular_s.keys()) + [ - '(.*[csx])is', - '(.*)ceps', - '[A-Z].*s', - ] -)) +plverb_special_s = enclose( + "|".join( + [pl_sb_singular_s] + + pl_sb_uninflected_s + + list(pl_sb_irregular_s.keys()) + + ["(.*[csx])is", "(.*)ceps", "[A-Z].*s"] + ) +) pl_sb_postfix_adj = { - 'general': ['(?!major|lieutenant|brigadier|adjutant|.*star)\S+'], - 'martial': ['court'], + "general": ["(?!major|lieutenant|brigadier|adjutant|.*star)\S+"], + "martial": ["court"], } for k in list(pl_sb_postfix_adj.keys()): pl_sb_postfix_adj[k] = enclose( - enclose('|'.join(pl_sb_postfix_adj[k])) + - "(?=(?:-|\\s+)%s)" % k) + enclose("|".join(pl_sb_postfix_adj[k])) + "(?=(?:-|\\s+)%s)" % k + ) -pl_sb_postfix_adj_stems = '(' + '|'.join(list(pl_sb_postfix_adj.values())) + ')(.*)' +pl_sb_postfix_adj_stems = "(" + "|".join(list(pl_sb_postfix_adj.values())) + ")(.*)" # PLURAL WORDS ENDING IS es GO TO SINGULAR is si_sb_es_is = ( - 'amanuenses', 'amniocenteses', 'analyses', 'antitheses', - 'apotheoses', 'arterioscleroses', 'atheroscleroses', 'axes', + "amanuenses", + "amniocenteses", + "analyses", + "antitheses", + "apotheoses", + "arterioscleroses", + "atheroscleroses", + "axes", # 'bases', # bases -> basis - 'catalyses', 'catharses', 'chasses', 'cirrhoses', - 'cocces', 'crises', 'diagnoses', 'dialyses', 'diereses', - 'electrolyses', 'emphases', 'exegeses', 'geneses', - 'halitoses', 'hydrolyses', 'hypnoses', 'hypotheses', 'hystereses', - 'metamorphoses', 'metastases', 'misdiagnoses', 'mitoses', - 'mononucleoses', 'narcoses', 'necroses', 'nemeses', 'neuroses', - 'oases', 'osmoses', 'osteoporoses', 'paralyses', 'parentheses', - 'parthenogeneses', 'periphrases', 'photosyntheses', 'probosces', - 'prognoses', 'prophylaxes', 'prostheses', 'preces', 'psoriases', - 'psychoanalyses', 'psychokineses', 'psychoses', 'scleroses', - 'scolioses', 'sepses', 'silicoses', 'symbioses', 'synopses', - 'syntheses', 'taxes', 'telekineses', 'theses', 'thromboses', - 'tuberculoses', 'urinalyses', + "catalyses", + "catharses", + "chasses", + "cirrhoses", + "cocces", + "crises", + "diagnoses", + "dialyses", + "diereses", + "electrolyses", + "emphases", + "exegeses", + "geneses", + "halitoses", + "hydrolyses", + "hypnoses", + "hypotheses", + "hystereses", + "metamorphoses", + "metastases", + "misdiagnoses", + "mitoses", + "mononucleoses", + "narcoses", + "necroses", + "nemeses", + "neuroses", + "oases", + "osmoses", + "osteoporoses", + "paralyses", + "parentheses", + "parthenogeneses", + "periphrases", + "photosyntheses", + "probosces", + "prognoses", + "prophylaxes", + "prostheses", + "preces", + "psoriases", + "psychoanalyses", + "psychokineses", + "psychoses", + "scleroses", + "scolioses", + "sepses", + "silicoses", + "symbioses", + "synopses", + "syntheses", + "taxes", + "telekineses", + "theses", + "thromboses", + "tuberculoses", + "urinalyses", ) pl_prep_list = """ @@ -881,31 +1555,42 @@ pl_prep_list = """ during except for from in into near of off on onto out over since till to under until unto upon with""".split() -pl_prep_list_da = pl_prep_list + ['de', 'du', 'da'] +pl_prep_list_da = pl_prep_list + ["de", "du", "da"] pl_prep_bysize = bysize(pl_prep_list_da) -pl_prep = enclose('|'.join(pl_prep_list_da)) +pl_prep = enclose("|".join(pl_prep_list_da)) -pl_sb_prep_dual_compound = r'(.*?)((?:-|\s+)(?:' + pl_prep + r')(?:-|\s+))a(?:-|\s+)(.*)' +pl_sb_prep_dual_compound = ( + r"(.*?)((?:-|\s+)(?:" + pl_prep + r")(?:-|\s+))a(?:-|\s+)(.*)" +) -singular_pronoun_genders = set(['neuter', - 'feminine', - 'masculine', - 'gender-neutral', - 'feminine or masculine', - 'masculine or feminine']) +singular_pronoun_genders = set( + [ + "neuter", + "feminine", + "masculine", + "gender-neutral", + "feminine or masculine", + "masculine or feminine", + ] +) pl_pron_nom = { # NOMINATIVE REFLEXIVE - "i": "we", "myself": "ourselves", - "you": "you", "yourself": "yourselves", - "she": "they", "herself": "themselves", - "he": "they", "himself": "themselves", - "it": "they", "itself": "themselves", - "they": "they", "themself": "themselves", - + "i": "we", + "myself": "ourselves", + "you": "you", + "yourself": "yourselves", + "she": "they", + "herself": "themselves", + "he": "they", + "himself": "themselves", + "it": "they", + "itself": "themselves", + "they": "they", + "themself": "themselves", # POSSESSIVE "mine": "ours", "yours": "yours", @@ -916,56 +1601,62 @@ pl_pron_nom = { } si_pron = {} -si_pron['nom'] = dict([(v, k) for (k, v) in pl_pron_nom.items()]) -si_pron['nom']['we'] = 'I' +si_pron["nom"] = dict([(v, k) for (k, v) in pl_pron_nom.items()]) +si_pron["nom"]["we"] = "I" pl_pron_acc = { # ACCUSATIVE REFLEXIVE - "me": "us", "myself": "ourselves", - "you": "you", "yourself": "yourselves", - "her": "them", "herself": "themselves", - "him": "them", "himself": "themselves", - "it": "them", "itself": "themselves", - "them": "them", "themself": "themselves", + "me": "us", + "myself": "ourselves", + "you": "you", + "yourself": "yourselves", + "her": "them", + "herself": "themselves", + "him": "them", + "himself": "themselves", + "it": "them", + "itself": "themselves", + "them": "them", + "themself": "themselves", } -pl_pron_acc_keys = enclose('|'.join(list(pl_pron_acc.keys()))) +pl_pron_acc_keys = enclose("|".join(list(pl_pron_acc.keys()))) pl_pron_acc_keys_bysize = bysize(list(pl_pron_acc.keys())) -si_pron['acc'] = dict([(v, k) for (k, v) in pl_pron_acc.items()]) +si_pron["acc"] = dict([(v, k) for (k, v) in pl_pron_acc.items()]) for thecase, plur, gend, sing in ( - ('nom', 'they', 'neuter', 'it'), - ('nom', 'they', 'feminine', 'she'), - ('nom', 'they', 'masculine', 'he'), - ('nom', 'they', 'gender-neutral', 'they'), - ('nom', 'they', 'feminine or masculine', 'she or he'), - ('nom', 'they', 'masculine or feminine', 'he or she'), - ('nom', 'themselves', 'neuter', 'itself'), - ('nom', 'themselves', 'feminine', 'herself'), - ('nom', 'themselves', 'masculine', 'himself'), - ('nom', 'themselves', 'gender-neutral', 'themself'), - ('nom', 'themselves', 'feminine or masculine', 'herself or himself'), - ('nom', 'themselves', 'masculine or feminine', 'himself or herself'), - ('nom', 'theirs', 'neuter', 'its'), - ('nom', 'theirs', 'feminine', 'hers'), - ('nom', 'theirs', 'masculine', 'his'), - ('nom', 'theirs', 'gender-neutral', 'theirs'), - ('nom', 'theirs', 'feminine or masculine', 'hers or his'), - ('nom', 'theirs', 'masculine or feminine', 'his or hers'), - ('acc', 'them', 'neuter', 'it'), - ('acc', 'them', 'feminine', 'her'), - ('acc', 'them', 'masculine', 'him'), - ('acc', 'them', 'gender-neutral', 'them'), - ('acc', 'them', 'feminine or masculine', 'her or him'), - ('acc', 'them', 'masculine or feminine', 'him or her'), - ('acc', 'themselves', 'neuter', 'itself'), - ('acc', 'themselves', 'feminine', 'herself'), - ('acc', 'themselves', 'masculine', 'himself'), - ('acc', 'themselves', 'gender-neutral', 'themself'), - ('acc', 'themselves', 'feminine or masculine', 'herself or himself'), - ('acc', 'themselves', 'masculine or feminine', 'himself or herself'), + ("nom", "they", "neuter", "it"), + ("nom", "they", "feminine", "she"), + ("nom", "they", "masculine", "he"), + ("nom", "they", "gender-neutral", "they"), + ("nom", "they", "feminine or masculine", "she or he"), + ("nom", "they", "masculine or feminine", "he or she"), + ("nom", "themselves", "neuter", "itself"), + ("nom", "themselves", "feminine", "herself"), + ("nom", "themselves", "masculine", "himself"), + ("nom", "themselves", "gender-neutral", "themself"), + ("nom", "themselves", "feminine or masculine", "herself or himself"), + ("nom", "themselves", "masculine or feminine", "himself or herself"), + ("nom", "theirs", "neuter", "its"), + ("nom", "theirs", "feminine", "hers"), + ("nom", "theirs", "masculine", "his"), + ("nom", "theirs", "gender-neutral", "theirs"), + ("nom", "theirs", "feminine or masculine", "hers or his"), + ("nom", "theirs", "masculine or feminine", "his or hers"), + ("acc", "them", "neuter", "it"), + ("acc", "them", "feminine", "her"), + ("acc", "them", "masculine", "him"), + ("acc", "them", "gender-neutral", "them"), + ("acc", "them", "feminine or masculine", "her or him"), + ("acc", "them", "masculine or feminine", "him or her"), + ("acc", "themselves", "neuter", "itself"), + ("acc", "themselves", "feminine", "herself"), + ("acc", "themselves", "masculine", "himself"), + ("acc", "themselves", "gender-neutral", "themself"), + ("acc", "themselves", "feminine or masculine", "herself or himself"), + ("acc", "themselves", "masculine or feminine", "himself or herself"), ): try: si_pron[thecase][plur][gend] = sing @@ -974,8 +1665,8 @@ for thecase, plur, gend, sing in ( si_pron[thecase][plur][gend] = sing -si_pron_acc_keys = enclose('|'.join(list(si_pron['acc'].keys()))) -si_pron_acc_keys_bysize = bysize(list(si_pron['acc'].keys())) +si_pron_acc_keys = enclose("|".join(list(si_pron["acc"].keys()))) +si_pron_acc_keys_bysize = bysize(list(si_pron["acc"].keys())) def get_si_pron(thecase, word, gender): @@ -988,83 +1679,130 @@ def get_si_pron(thecase, word, gender): except TypeError: return sing # answer independent of gender + plverb_irregular_pres = { # 1st PERS. SING. 2ND PERS. SING. 3RD PERS. SINGULAR # 3RD PERS. (INDET.) - "am": "are", "are": "are", "is": "are", - "was": "were", "were": "were", "was": "were", - "have": "have", "have": "have", "has": "have", - "do": "do", "do": "do", "does": "do", + "am": "are", + "are": "are", + "is": "are", + "was": "were", + "were": "were", + "was": "were", + "have": "have", + "have": "have", + "has": "have", + "do": "do", + "do": "do", + "does": "do", } plverb_ambiguous_pres = { # 1st PERS. SING. 2ND PERS. SING. 3RD PERS. SINGULAR # 3RD PERS. (INDET.) - "act": "act", "act": "act", "acts": "act", - "blame": "blame", "blame": "blame", "blames": "blame", - "can": "can", "can": "can", "can": "can", - "must": "must", "must": "must", "must": "must", - "fly": "fly", "fly": "fly", "flies": "fly", - "copy": "copy", "copy": "copy", "copies": "copy", - "drink": "drink", "drink": "drink", "drinks": "drink", - "fight": "fight", "fight": "fight", "fights": "fight", - "fire": "fire", "fire": "fire", "fires": "fire", - "like": "like", "like": "like", "likes": "like", - "look": "look", "look": "look", "looks": "look", - "make": "make", "make": "make", "makes": "make", - "reach": "reach", "reach": "reach", "reaches": "reach", - "run": "run", "run": "run", "runs": "run", - "sink": "sink", "sink": "sink", "sinks": "sink", - "sleep": "sleep", "sleep": "sleep", "sleeps": "sleep", - "view": "view", "view": "view", "views": "view", + "act": "act", + "act": "act", + "acts": "act", + "blame": "blame", + "blame": "blame", + "blames": "blame", + "can": "can", + "can": "can", + "can": "can", + "must": "must", + "must": "must", + "must": "must", + "fly": "fly", + "fly": "fly", + "flies": "fly", + "copy": "copy", + "copy": "copy", + "copies": "copy", + "drink": "drink", + "drink": "drink", + "drinks": "drink", + "fight": "fight", + "fight": "fight", + "fights": "fight", + "fire": "fire", + "fire": "fire", + "fires": "fire", + "like": "like", + "like": "like", + "likes": "like", + "look": "look", + "look": "look", + "looks": "look", + "make": "make", + "make": "make", + "makes": "make", + "reach": "reach", + "reach": "reach", + "reaches": "reach", + "run": "run", + "run": "run", + "runs": "run", + "sink": "sink", + "sink": "sink", + "sinks": "sink", + "sleep": "sleep", + "sleep": "sleep", + "sleeps": "sleep", + "view": "view", + "view": "view", + "views": "view", } -plverb_ambiguous_pres_keys = enclose('|'.join(list(plverb_ambiguous_pres.keys()))) +plverb_ambiguous_pres_keys = enclose("|".join(list(plverb_ambiguous_pres.keys()))) plverb_irregular_non_pres = ( - "did", "had", "ate", "made", "put", - "spent", "fought", "sank", "gave", "sought", - "shall", "could", "ought", "should", + "did", + "had", + "ate", + "made", + "put", + "spent", + "fought", + "sank", + "gave", + "sought", + "shall", + "could", + "ought", + "should", ) -plverb_ambiguous_non_pres = enclose('|'.join(( - "thought", "saw", "bent", "will", "might", "cut", -))) +plverb_ambiguous_non_pres = enclose( + "|".join(("thought", "saw", "bent", "will", "might", "cut")) +) # "..oes" -> "..oe" (the rest are "..oes" -> "o") -pl_v_oes_oe = ('canoes', 'floes', 'oboes', 'roes', 'throes', 'woes') -pl_v_oes_oe_endings_size4 = ('hoes', 'toes') -pl_v_oes_oe_endings_size5 = ('shoes') +pl_v_oes_oe = ("canoes", "floes", "oboes", "roes", "throes", "woes") +pl_v_oes_oe_endings_size4 = ("hoes", "toes") +pl_v_oes_oe_endings_size5 = "shoes" -pl_count_zero = ( - "0", "no", "zero", "nil" -) +pl_count_zero = ("0", "no", "zero", "nil") -pl_count_one = ( - "1", "a", "an", "one", "each", "every", "this", "that", -) +pl_count_one = ("1", "a", "an", "one", "each", "every", "this", "that") -pl_adj_special = { - "a": "some", "an": "some", - "this": "these", "that": "those", -} +pl_adj_special = {"a": "some", "an": "some", "this": "these", "that": "those"} -pl_adj_special_keys = enclose('|'.join(list(pl_adj_special.keys()))) +pl_adj_special_keys = enclose("|".join(list(pl_adj_special.keys()))) pl_adj_poss = { - "my": "our", - "your": "your", - "its": "their", - "her": "their", - "his": "their", + "my": "our", + "your": "your", + "its": "their", + "her": "their", + "his": "their", "their": "their", } -pl_adj_poss_keys = enclose('|'.join(list(pl_adj_poss.keys()))) +pl_adj_poss_keys = enclose("|".join(list(pl_adj_poss.keys()))) # 2. INDEFINITE ARTICLES @@ -1083,81 +1821,100 @@ A_abbrev = r""" # 'y' FOLLOWED BY A CONSONANT. ANY OTHER Y-CONSONANT PREFIX THEREFORE # IMPLIES AN ABBREVIATION. -A_y_cons = 'y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)' +A_y_cons = "y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)" # EXCEPTIONS TO EXCEPTIONS -A_explicit_a = enclose('|'.join(( - "unabomber", "unanimous", "US", -))) +A_explicit_a = enclose("|".join(("unabomber", "unanimous", "US"))) -A_explicit_an = enclose('|'.join(( - "euler", - "hour(?!i)", "heir", "honest", "hono[ur]", - "mpeg", -))) +A_explicit_an = enclose( + "|".join(("euler", "hour(?!i)", "heir", "honest", "hono[ur]", "mpeg")) +) -A_ordinal_an = enclose('|'.join(( - "[aefhilmnorsx]-?th", -))) +A_ordinal_an = enclose("|".join(("[aefhilmnorsx]-?th",))) -A_ordinal_a = enclose('|'.join(( - "[bcdgjkpqtuvwyz]-?th", -))) +A_ordinal_a = enclose("|".join(("[bcdgjkpqtuvwyz]-?th",))) # NUMERICAL INFLECTIONS nth = { - 0: 'th', - 1: 'st', - 2: 'nd', - 3: 'rd', - 4: 'th', - 5: 'th', - 6: 'th', - 7: 'th', - 8: 'th', - 9: 'th', - 11: 'th', - 12: 'th', - 13: 'th', + 0: "th", + 1: "st", + 2: "nd", + 3: "rd", + 4: "th", + 5: "th", + 6: "th", + 7: "th", + 8: "th", + 9: "th", + 11: "th", + 12: "th", + 13: "th", } -ordinal = dict(ty='tieth', - one='first', - two='second', - three='third', - five='fifth', - eight='eighth', - nine='ninth', - twelve='twelfth') +ordinal = dict( + ty="tieth", + one="first", + two="second", + three="third", + five="fifth", + eight="eighth", + nine="ninth", + twelve="twelfth", +) -ordinal_suff = '|'.join(list(ordinal.keys())) +ordinal_suff = "|".join(list(ordinal.keys())) # NUMBERS -unit = ['', 'one', 'two', 'three', 'four', 'five', - 'six', 'seven', 'eight', 'nine'] -teen = ['ten', 'eleven', 'twelve', 'thirteen', 'fourteen', - 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'] -ten = ['', '', 'twenty', 'thirty', 'forty', - 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'] -mill = [' ', ' thousand', ' million', ' billion', ' trillion', ' quadrillion', - ' quintillion', ' sextillion', ' septillion', ' octillion', - ' nonillion', ' decillion'] +unit = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"] +teen = [ + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", + "eighteen", + "nineteen", +] +ten = [ + "", + "", + "twenty", + "thirty", + "forty", + "fifty", + "sixty", + "seventy", + "eighty", + "ninety", +] +mill = [ + " ", + " thousand", + " million", + " billion", + " trillion", + " quadrillion", + " quintillion", + " sextillion", + " septillion", + " octillion", + " nonillion", + " decillion", +] # SUPPORT CLASSICAL PLURALIZATIONS def_classical = dict( - all=False, - zero=False, - herd=False, - names=True, - persons=False, - ancient=False, + all=False, zero=False, herd=False, names=True, persons=False, ancient=False ) all_classical = dict((k, True) for k in list(def_classical.keys())) @@ -1178,7 +1935,6 @@ no_classical = dict((k, False) for k in list(def_classical.keys())) class engine: - def __init__(self): self.classical_dict = def_classical.copy() @@ -1189,33 +1945,34 @@ class engine: self.pl_adj_user_defined = [] self.si_sb_user_defined = [] self.A_a_user_defined = [] - self.thegender = 'neuter' + self.thegender = "neuter" - deprecated_methods = dict(pl='plural', - plnoun='plural_noun', - plverb='plural_verb', - pladj='plural_adj', - sinoun='single_noun', - prespart='present_participle', - numwords='number_to_words', - plequal='compare', - plnounequal='compare_nouns', - plverbequal='compare_verbs', - pladjequal='compare_adjs', - wordlist='join', - ) + deprecated_methods = dict( + pl="plural", + plnoun="plural_noun", + plverb="plural_verb", + pladj="plural_adj", + sinoun="single_noun", + prespart="present_participle", + numwords="number_to_words", + plequal="compare", + plnounequal="compare_nouns", + plverbequal="compare_verbs", + pladjequal="compare_adjs", + wordlist="join", + ) def __getattr__(self, meth): if meth in self.deprecated_methods: - print3('%s() deprecated, use %s()' % (meth, self.deprecated_methods[meth])) + print3("%s() deprecated, use %s()" % (meth, self.deprecated_methods[meth])) raise DeprecationWarning raise AttributeError def defnoun(self, singular, plural): - ''' + """ Set the noun plural of singular to plural. - ''' + """ self.checkpat(singular) self.checkpatplural(plural) self.pl_sb_user_defined.extend((singular, plural)) @@ -1223,12 +1980,12 @@ class engine: return 1 def defverb(self, s1, p1, s2, p2, s3, p3): - ''' + """ Set the verb plurals for s1, s2 and s3 to p1, p2 and p3 respectively. Where 1, 2 and 3 represent the 1st, 2nd and 3rd person forms of the verb. - ''' + """ self.checkpat(s1) self.checkpat(s2) self.checkpat(s3) @@ -1239,49 +1996,49 @@ class engine: return 1 def defadj(self, singular, plural): - ''' + """ Set the adjective plural of singular to plural. - ''' + """ self.checkpat(singular) self.checkpatplural(plural) self.pl_adj_user_defined.extend((singular, plural)) return 1 def defa(self, pattern): - ''' + """ Define the indefinate article as 'a' for words matching pattern. - ''' + """ self.checkpat(pattern) - self.A_a_user_defined.extend((pattern, 'a')) + self.A_a_user_defined.extend((pattern, "a")) return 1 def defan(self, pattern): - ''' + """ Define the indefinate article as 'an' for words matching pattern. - ''' + """ self.checkpat(pattern) - self.A_a_user_defined.extend((pattern, 'an')) + self.A_a_user_defined.extend((pattern, "an")) return 1 def checkpat(self, pattern): - ''' + """ check for errors in a regex pattern - ''' + """ if pattern is None: return try: - match(pattern, '') + match(pattern, "") except reerror: print3("\nBad user-defined singular pattern:\n\t%s\n" % pattern) raise BadUserDefinedPatternError def checkpatplural(self, pattern): - ''' + """ check for errors in a regex replace pattern - ''' + """ return # can't find a pattern that doesn't pass the following test: # if pattern is None: @@ -1294,11 +2051,13 @@ class engine: def ud_match(self, word, wordlist): for i in range(len(wordlist) - 2, -2, -2): # backwards through even elements - mo = search(r'^%s$' % wordlist[i], word, IGNORECASE) + mo = search(r"^%s$" % wordlist[i], word, IGNORECASE) if mo: if wordlist[i + 1] is None: return None - pl = resub(r'\$(\d+)', r'\\1', wordlist[i + 1]) # change $n to \n for expand + pl = resub( + r"\$(\d+)", r"\\1", wordlist[i + 1] + ) # change $n to \n for expand return mo.expand(pl) return None @@ -1324,8 +2083,8 @@ class engine: if not kwargs: self.classical_dict = all_classical.copy() return - if 'all' in kwargs: - if kwargs['all']: + if "all" in kwargs: + if kwargs["all"]: self.classical_dict = all_classical.copy() else: self.classical_dict = no_classical.copy() @@ -1337,14 +2096,14 @@ class engine: raise UnknownClassicalModeError def num(self, count=None, show=None): # (;$count,$show) - ''' + """ Set the number to be used in other method calls. Returns count. Set show to False to return '' instead. - ''' + """ if count is not None: try: self.persistent_count = int(count) @@ -1354,10 +2113,10 @@ class engine: return str(count) else: self.persistent_count = None - return '' + return "" def gender(self, gender): - ''' + """ set the gender for the singular of plural pronouns can be one of: @@ -1367,95 +2126,95 @@ class engine: 'gender-neutral' ('they' -> 'they') 'feminine or masculine' ('they' -> 'she or he') 'masculine or feminine' ('they' -> 'he or she') - ''' + """ if gender in singular_pronoun_genders: self.thegender = gender else: raise BadGenderError def nummo(self, matchobject): - ''' + """ num but take a matchobject use groups 1 and 2 in matchobject - ''' + """ return self.num(matchobject.group(1), matchobject.group(2)) def plmo(self, matchobject): - ''' + """ plural but take a matchobject use groups 1 and 3 in matchobject - ''' + """ return self.plural(matchobject.group(1), matchobject.group(3)) def plnounmo(self, matchobject): - ''' + """ plural_noun but take a matchobject use groups 1 and 3 in matchobject - ''' + """ return self.plural_noun(matchobject.group(1), matchobject.group(3)) def plverbmo(self, matchobject): - ''' + """ plural_verb but take a matchobject use groups 1 and 3 in matchobject - ''' + """ return self.plural_verb(matchobject.group(1), matchobject.group(3)) def pladjmo(self, matchobject): - ''' + """ plural_adj but take a matchobject use groups 1 and 3 in matchobject - ''' + """ return self.plural_adj(matchobject.group(1), matchobject.group(3)) def sinounmo(self, matchobject): - ''' + """ singular_noun but take a matchobject use groups 1 and 3 in matchobject - ''' + """ return self.singular_noun(matchobject.group(1), matchobject.group(3)) def amo(self, matchobject): - ''' + """ A but take a matchobject use groups 1 and 3 in matchobject - ''' + """ if matchobject.group(3) is None: return self.a(matchobject.group(1)) return self.a(matchobject.group(1), matchobject.group(3)) def nomo(self, matchobject): - ''' + """ NO but take a matchobject use groups 1 and 3 in matchobject - ''' + """ return self.no(matchobject.group(1), matchobject.group(3)) def ordinalmo(self, matchobject): - ''' + """ ordinal but take a matchobject use group 1 - ''' + """ return self.ordinal(matchobject.group(1)) def numwordsmo(self, matchobject): - ''' + """ number_to_words but take a matchobject use group 1 - ''' + """ return self.number_to_words(matchobject.group(1)) def prespartmo(self, matchobject): - ''' + """ prespart but take a matchobject use group 1 - ''' + """ return self.present_participle(matchobject.group(1)) -# 0. PERFORM GENERAL INFLECTIONS IN A STRING + # 0. PERFORM GENERAL INFLECTIONS IN A STRING def inflect(self, text): - ''' + """ Perform inflections in a string. e.g. inflect('The plural of cat is plural(cat)') returns @@ -1464,54 +2223,76 @@ class engine: can use plural, plural_noun, plural_verb, plural_adj, singular_noun, a, an, no, ordinal, number_to_words and prespart - ''' + """ save_persistent_count = self.persistent_count sections = splitre(r"(num\([^)]*\))", text) inflection = [] for section in sections: - (section, count) = subn(r"num\(\s*?(?:([^),]*)(?:,([^)]*))?)?\)", self.nummo, section) + (section, count) = subn( + r"num\(\s*?(?:([^),]*)(?:,([^)]*))?)?\)", self.nummo, section + ) if not count: total = -1 while total: (section, total) = subn( r"(?x)\bplural \( ([^),]*) (, ([^)]*) )? \) ", - self.plmo, section) + self.plmo, + section, + ) (section, count) = subn( r"(?x)\bplural_noun \( ([^),]*) (, ([^)]*) )? \) ", - self.plnounmo, section) + self.plnounmo, + section, + ) total += count (section, count) = subn( r"(?x)\bplural_verb \( ([^),]*) (, ([^)]*) )? \) ", - self.plverbmo, section) + self.plverbmo, + section, + ) total += count (section, count) = subn( r"(?x)\bplural_adj \( ([^),]*) (, ([^)]*) )? \) ", - self.pladjmo, section) + self.pladjmo, + section, + ) total += count (section, count) = subn( r"(?x)\bsingular_noun \( ([^),]*) (, ([^)]*) )? \) ", - self.sinounmo, section) + self.sinounmo, + section, + ) total += count (section, count) = subn( r"(?x)\ban? \( ([^),]*) (, ([^)]*) )? \) ", - self.amo, section) + self.amo, + section, + ) total += count (section, count) = subn( r"(?x)\bno \( ([^),]*) (, ([^)]*) )? \) ", - self.nomo, section) + self.nomo, + section, + ) total += count (section, count) = subn( r"(?x)\bordinal \( ([^)]*) \) ", - self.ordinalmo, section) + self.ordinalmo, + section, + ) total += count (section, count) = subn( r"(?x)\bnumber_to_words \( ([^)]*) \) ", - self.numwordsmo, section) + self.numwordsmo, + section, + ) total += count (section, count) = subn( r"(?x)\bpresent_participle \( ([^)]*) \) ", - self.prespartmo, section) + self.prespartmo, + section, + ) total += count inflection.append(section) @@ -1519,67 +2300,66 @@ class engine: self.persistent_count = save_persistent_count return "".join(inflection) -# ## PLURAL SUBROUTINES + # ## PLURAL SUBROUTINES def postprocess(self, orig, inflected): """ FIX PEDANTRY AND CAPITALIZATION :-) """ - if '|' in inflected: - inflected = inflected.split('|')[self.classical_dict['all']] + if "|" in inflected: + inflected = inflected.split("|")[self.classical_dict["all"]] if orig == "I": return inflected if orig == orig.upper(): return inflected.upper() if orig[0] == orig[0].upper(): - return '%s%s' % (inflected[0].upper(), - inflected[1:]) + return "%s%s" % (inflected[0].upper(), inflected[1:]) return inflected def partition_word(self, text): - mo = search(r'\A(\s*)(.+?)(\s*)\Z', text) + mo = search(r"\A(\s*)(.+?)(\s*)\Z", text) try: return mo.group(1), mo.group(2), mo.group(3) except AttributeError: # empty string - return '', '', '' + return "", "", "" -# def pl(self, *args, **kwds): -# print 'pl() deprecated, use plural()' -# raise DeprecationWarning -# return self.plural(*args, **kwds) -# -# def plnoun(self, *args, **kwds): -# print 'plnoun() deprecated, use plural_noun()' -# raise DeprecationWarning -# return self.plural_noun(*args, **kwds) -# -# def plverb(self, *args, **kwds): -# print 'plverb() deprecated, use plural_verb()' -# raise DeprecationWarning -# return self.plural_verb(*args, **kwds) -# -# def pladj(self, *args, **kwds): -# print 'pladj() deprecated, use plural_adj()' -# raise DeprecationWarning -# return self.plural_adj(*args, **kwds) -# -# def sinoun(self, *args, **kwds): -# print 'sinoun() deprecated, use singular_noun()' -# raise DeprecationWarning -# return self.singular_noun(*args, **kwds) -# -# def prespart(self, *args, **kwds): -# print 'prespart() deprecated, use present_participle()' -# raise DeprecationWarning -# return self.present_participle(*args, **kwds) -# -# def numwords(self, *args, **kwds): -# print 'numwords() deprecated, use number_to_words()' -# raise DeprecationWarning -# return self.number_to_words(*args, **kwds) + # def pl(self, *args, **kwds): + # print 'pl() deprecated, use plural()' + # raise DeprecationWarning + # return self.plural(*args, **kwds) + # + # def plnoun(self, *args, **kwds): + # print 'plnoun() deprecated, use plural_noun()' + # raise DeprecationWarning + # return self.plural_noun(*args, **kwds) + # + # def plverb(self, *args, **kwds): + # print 'plverb() deprecated, use plural_verb()' + # raise DeprecationWarning + # return self.plural_verb(*args, **kwds) + # + # def pladj(self, *args, **kwds): + # print 'pladj() deprecated, use plural_adj()' + # raise DeprecationWarning + # return self.plural_adj(*args, **kwds) + # + # def sinoun(self, *args, **kwds): + # print 'sinoun() deprecated, use singular_noun()' + # raise DeprecationWarning + # return self.singular_noun(*args, **kwds) + # + # def prespart(self, *args, **kwds): + # print 'prespart() deprecated, use present_participle()' + # raise DeprecationWarning + # return self.present_participle(*args, **kwds) + # + # def numwords(self, *args, **kwds): + # print 'numwords() deprecated, use number_to_words()' + # raise DeprecationWarning + # return self.number_to_words(*args, **kwds) def plural(self, text, count=None): - ''' + """ Return the plural of text. If count supplied, then return text if count is one of: @@ -1588,19 +2368,20 @@ class engine: Whitespace at the start and end is preserved. - ''' + """ pre, word, post = self.partition_word(text) if not word: return text plural = self.postprocess( word, - self._pl_special_adjective(word, count) or - self._pl_special_verb(word, count) or - self._plnoun(word, count)) + self._pl_special_adjective(word, count) + or self._pl_special_verb(word, count) + or self._plnoun(word, count), + ) return "%s%s%s" % (pre, plural, post) def plural_noun(self, text, count=None): - ''' + """ Return the plural of text, where text is a noun. If count supplied, then return text if count is one of: @@ -1609,7 +2390,7 @@ class engine: Whitespace at the start and end is preserved. - ''' + """ pre, word, post = self.partition_word(text) if not word: return text @@ -1617,7 +2398,7 @@ class engine: return "%s%s%s" % (pre, plural, post) def plural_verb(self, text, count=None): - ''' + """ Return the plural of text, where text is a verb. If count supplied, then return text if count is one of: @@ -1626,16 +2407,18 @@ class engine: Whitespace at the start and end is preserved. - ''' + """ pre, word, post = self.partition_word(text) if not word: return text - plural = self.postprocess(word, self._pl_special_verb(word, count) or - self._pl_general_verb(word, count)) + plural = self.postprocess( + word, + self._pl_special_verb(word, count) or self._pl_general_verb(word, count), + ) return "%s%s%s" % (pre, plural, post) def plural_adj(self, text, count=None): - ''' + """ Return the plural of text, where text is an adjective. If count supplied, then return text if count is one of: @@ -1644,7 +2427,7 @@ class engine: Whitespace at the start and end is preserved. - ''' + """ pre, word, post = self.partition_word(text) if not word: return text @@ -1652,7 +2435,7 @@ class engine: return "%s%s%s" % (pre, plural, post) def compare(self, word1, word2): - ''' + """ compare word1 and word2 for equality regardless of plurality return values: @@ -1662,14 +2445,15 @@ class engine: p:p - word1 and word2 are two different plural forms of the one word False - otherwise - ''' + """ return ( - self._plequal(word1, word2, self.plural_noun) or - self._plequal(word1, word2, self.plural_verb) or - self._plequal(word1, word2, self.plural_adj)) + self._plequal(word1, word2, self.plural_noun) + or self._plequal(word1, word2, self.plural_verb) + or self._plequal(word1, word2, self.plural_adj) + ) def compare_nouns(self, word1, word2): - ''' + """ compare word1 and word2 for equality regardless of plurality word1 and word2 are to be treated as nouns @@ -1680,11 +2464,11 @@ class engine: p:p - word1 and word2 are two different plural forms of the one word False - otherwise - ''' + """ return self._plequal(word1, word2, self.plural_noun) def compare_verbs(self, word1, word2): - ''' + """ compare word1 and word2 for equality regardless of plurality word1 and word2 are to be treated as verbs @@ -1695,11 +2479,11 @@ class engine: p:p - word1 and word2 are two different plural forms of the one word False - otherwise - ''' + """ return self._plequal(word1, word2, self.plural_verb) def compare_adjs(self, word1, word2): - ''' + """ compare word1 and word2 for equality regardless of plurality word1 and word2 are to be treated as adjectives @@ -1710,11 +2494,11 @@ class engine: p:p - word1 and word2 are two different plural forms of the one word False - otherwise - ''' + """ return self._plequal(word1, word2, self.plural_adj) def singular_noun(self, text, count=None, gender=None): - ''' + """ Return the singular of text, where text is a plural noun. If count supplied, then return the singular if count is one of: @@ -1723,13 +2507,15 @@ class engine: Whitespace at the start and end is preserved. - ''' + """ pre, word, post = self.partition_word(text) if not word: return text sing = self._sinoun(word, count=count, gender=gender) if sing is not False: - plural = self.postprocess(word, self._sinoun(word, count=count, gender=gender)) + plural = self.postprocess( + word, self._sinoun(word, count=count, gender=gender) + ) return "%s%s%s" % (pre, plural, post) return False @@ -1786,19 +2572,19 @@ class engine: (pl_sb_C_ix_ices, "ixes", "ices"), (pl_sb_C_i, "s", "i"), (pl_sb_C_im, "s", "im"), - ('.*eau', "s", "x"), - ('.*ieu', "s", "x"), - ('.*tri', "xes", "ces"), - ('.{2,}[yia]n', "xes", "ges") + (".*eau", "s", "x"), + (".*ieu", "s", "x"), + (".*tri", "xes", "ces"), + (".{2,}[yia]n", "xes", "ges"), ): if self._pl_reg_plurals(pair, stems, end1, end2): return True return False def _pl_check_plurals_adj(self, word1, word2): -# VERSION: tuple in endswith requires python 2.5 - word1a = word1[:word1.rfind("'")] if word1.endswith(("'s", "'")) else '' - word2a = word2[:word2.rfind("'")] if word2.endswith(("'s", "'")) else '' + # VERSION: tuple in endswith requires python 2.5 + word1a = word1[: word1.rfind("'")] if word1.endswith(("'s", "'")) else "" + word2a = word2[: word2.rfind("'")] if word2.endswith(("'s", "'")) else "" # TODO: BUG? report upstream. I don't think you should chop off the s' # word1b = word1[:-2] if word1.endswith("s'") else '' # word2b = word2[:-2] if word2.endswith("s'") else '' @@ -1807,8 +2593,10 @@ class engine: # then they return False because they are the same. Need to fix this. if word1a: - if word2a and (self._pl_check_plurals_N(word1a, word2a) - or self._pl_check_plurals_N(word2a, word1a)): + if word2a and ( + self._pl_check_plurals_N(word1a, word2a) + or self._pl_check_plurals_N(word2a, word1a) + ): return True # if word2b and ( self._pl_check_plurals_N(word1a, word2b) # or self._pl_check_plurals_N(word2b, word1a) ): @@ -1829,30 +2617,39 @@ class engine: count = self.persistent_count if count is not None: - count = 1 if ((str(count) in pl_count_one) or - (self.classical_dict['zero'] and str(count).lower() in pl_count_zero)) else 2 + count = ( + 1 + if ( + (str(count) in pl_count_one) + or ( + self.classical_dict["zero"] + and str(count).lower() in pl_count_zero + ) + ) + else 2 + ) else: - count = '' + count = "" return count # @profile def _plnoun(self, word, count=None): count = self.get_count(count) -# DEFAULT TO PLURAL + # DEFAULT TO PLURAL if count == 1: return word -# HANDLE USER-DEFINED NOUNS + # HANDLE USER-DEFINED NOUNS value = self.ud_match(word, self.pl_sb_user_defined) if value is not None: return value -# HANDLE EMPTY WORD, SINGULAR COUNT AND UNINFLECTED PLURALS + # HANDLE EMPTY WORD, SINGULAR COUNT AND UNINFLECTED PLURALS - if word == '': + if word == "": return word lowerword = word.lower() @@ -1867,46 +2664,58 @@ class engine: if lowerword[-k:] in v: return word - if (self.classical_dict['herd'] and lowerword in pl_sb_uninflected_herd): + if self.classical_dict["herd"] and lowerword in pl_sb_uninflected_herd: return word -# HANDLE COMPOUNDS ("Governor General", "mother-in-law", "aide-de-camp", ETC.) + # HANDLE COMPOUNDS ("Governor General", "mother-in-law", "aide-de-camp", ETC.) mo = search(r"^(?:%s)$" % pl_sb_postfix_adj_stems, word, IGNORECASE) - if mo and mo.group(2) != '': + if mo and mo.group(2) != "": return "%s%s" % (self._plnoun(mo.group(1), 2), mo.group(2)) - if ' a ' in lowerword or '-a-' in lowerword: + if " a " in lowerword or "-a-" in lowerword: mo = search(r"^(?:%s)$" % pl_sb_prep_dual_compound, word, IGNORECASE) - if mo and mo.group(2) != '' and mo.group(3) != '': - return "%s%s%s" % (self._plnoun(mo.group(1), 2), - mo.group(2), - self._plnoun(mo.group(3))) + if mo and mo.group(2) != "" and mo.group(3) != "": + return "%s%s%s" % ( + self._plnoun(mo.group(1), 2), + mo.group(2), + self._plnoun(mo.group(3)), + ) - lowersplit = lowerword.split(' ') + lowersplit = lowerword.split(" ") if len(lowersplit) >= 3: for numword in range(1, len(lowersplit) - 1): if lowersplit[numword] in pl_prep_list_da: - return ' '.join( - lowersplit[:numword - 1] + - [self._plnoun(lowersplit[numword - 1], 2)] + lowersplit[numword:]) + return " ".join( + lowersplit[: numword - 1] + + [self._plnoun(lowersplit[numword - 1], 2)] + + lowersplit[numword:] + ) - lowersplit = lowerword.split('-') + lowersplit = lowerword.split("-") if len(lowersplit) >= 3: for numword in range(1, len(lowersplit) - 1): if lowersplit[numword] in pl_prep_list_da: - return ' '.join( - lowersplit[:numword - 1] + - [self._plnoun(lowersplit[numword - 1], 2) + - '-' + lowersplit[numword] + '-']) + ' '.join(lowersplit[(numword + 1):]) + return " ".join( + lowersplit[: numword - 1] + + [ + self._plnoun(lowersplit[numword - 1], 2) + + "-" + + lowersplit[numword] + + "-" + ] + ) + " ".join(lowersplit[(numword + 1) :]) -# HANDLE PRONOUNS + # HANDLE PRONOUNS for k, v in pl_pron_acc_keys_bysize.items(): if lowerword[-k:] in v: # ends with accusivate pronoun for pk, pv in pl_prep_bysize.items(): if lowerword[:pk] in pv: # starts with a prep - if lowerword.split() == [lowerword[:pk], lowerword[-k:]]: # only whitespace in between + if lowerword.split() == [ + lowerword[:pk], + lowerword[-k:], + ]: # only whitespace in between return lowerword[:-k] + pl_pron_acc[lowerword[-k:]] try: @@ -1919,7 +2728,7 @@ class engine: except KeyError: pass -# HANDLE ISOLATED IRREGULAR PLURALS + # HANDLE ISOLATED IRREGULAR PLURALS wordsplit = word.split() wordlast = wordsplit[-1] @@ -1927,97 +2736,99 @@ class engine: if wordlast in list(pl_sb_irregular_caps.keys()): llen = len(wordlast) - return '%s%s' % (word[:-llen], - pl_sb_irregular_caps[wordlast]) + return "%s%s" % (word[:-llen], pl_sb_irregular_caps[wordlast]) if lowerwordlast in list(pl_sb_irregular.keys()): llen = len(lowerwordlast) - return '%s%s' % (word[:-llen], - pl_sb_irregular[lowerwordlast]) + return "%s%s" % (word[:-llen], pl_sb_irregular[lowerwordlast]) - if (' '.join(wordsplit[-2:])).lower() in list(pl_sb_irregular_compound.keys()): - llen = len(' '.join(wordsplit[-2:])) # TODO: what if 2 spaces between these words? - return '%s%s' % (word[:-llen], - pl_sb_irregular_compound[(' '.join(wordsplit[-2:])).lower()]) + if (" ".join(wordsplit[-2:])).lower() in list(pl_sb_irregular_compound.keys()): + llen = len( + " ".join(wordsplit[-2:]) + ) # TODO: what if 2 spaces between these words? + return "%s%s" % ( + word[:-llen], + pl_sb_irregular_compound[(" ".join(wordsplit[-2:])).lower()], + ) - if lowerword[-3:] == 'quy': - return word[:-1] + 'ies' + if lowerword[-3:] == "quy": + return word[:-1] + "ies" - if lowerword[-6:] == 'person': - if self.classical_dict['persons']: - return word + 's' + if lowerword[-6:] == "person": + if self.classical_dict["persons"]: + return word + "s" else: - return word[:-4] + 'ople' + return word[:-4] + "ople" -# HANDLE FAMILIES OF IRREGULAR PLURALS + # HANDLE FAMILIES OF IRREGULAR PLURALS - if lowerword[-3:] == 'man': + if lowerword[-3:] == "man": for k, v in pl_sb_U_man_mans_bysize.items(): if lowerword[-k:] in v: - return word + 's' + return word + "s" for k, v in pl_sb_U_man_mans_caps_bysize.items(): if word[-k:] in v: - return word + 's' - return word[:-3] + 'men' - if lowerword[-5:] == 'mouse': - return word[:-5] + 'mice' - if lowerword[-5:] == 'louse': - return word[:-5] + 'lice' - if lowerword[-5:] == 'goose': - return word[:-5] + 'geese' - if lowerword[-5:] == 'tooth': - return word[:-5] + 'teeth' - if lowerword[-4:] == 'foot': - return word[:-4] + 'feet' + return word + "s" + return word[:-3] + "men" + if lowerword[-5:] == "mouse": + return word[:-5] + "mice" + if lowerword[-5:] == "louse": + return word[:-5] + "lice" + if lowerword[-5:] == "goose": + return word[:-5] + "geese" + if lowerword[-5:] == "tooth": + return word[:-5] + "teeth" + if lowerword[-4:] == "foot": + return word[:-4] + "feet" - if lowerword == 'die': - return 'dice' + if lowerword == "die": + return "dice" -# HANDLE UNASSIMILATED IMPORTS + # HANDLE UNASSIMILATED IMPORTS - if lowerword[-4:] == 'ceps': + if lowerword[-4:] == "ceps": return word - if lowerword[-4:] == 'zoon': - return word[:-2] + 'a' - if lowerword[-3:] in ('cis', 'sis', 'xis'): - return word[:-2] + 'es' + if lowerword[-4:] == "zoon": + return word[:-2] + "a" + if lowerword[-3:] in ("cis", "sis", "xis"): + return word[:-2] + "es" for lastlet, d, numend, post in ( - ('h', pl_sb_U_ch_chs_bysize, None, 's'), - ('x', pl_sb_U_ex_ices_bysize, -2, 'ices'), - ('x', pl_sb_U_ix_ices_bysize, -2, 'ices'), - ('m', pl_sb_U_um_a_bysize, -2, 'a'), - ('s', pl_sb_U_us_i_bysize, -2, 'i'), - ('n', pl_sb_U_on_a_bysize, -2, 'a'), - ('a', pl_sb_U_a_ae_bysize, None, 'e'), + ("h", pl_sb_U_ch_chs_bysize, None, "s"), + ("x", pl_sb_U_ex_ices_bysize, -2, "ices"), + ("x", pl_sb_U_ix_ices_bysize, -2, "ices"), + ("m", pl_sb_U_um_a_bysize, -2, "a"), + ("s", pl_sb_U_us_i_bysize, -2, "i"), + ("n", pl_sb_U_on_a_bysize, -2, "a"), + ("a", pl_sb_U_a_ae_bysize, None, "e"), ): if lowerword[-1] == lastlet: # this test to add speed for k, v in d.items(): if lowerword[-k:] in v: return word[:numend] + post -# HANDLE INCOMPLETELY ASSIMILATED IMPORTS + # HANDLE INCOMPLETELY ASSIMILATED IMPORTS - if (self.classical_dict['ancient']): - if lowerword[-4:] == 'trix': - return word[:-1] + 'ces' - if lowerword[-3:] in ('eau', 'ieu'): - return word + 'x' - if lowerword[-3:] in ('ynx', 'inx', 'anx') and len(word) > 4: - return word[:-1] + 'ges' + if self.classical_dict["ancient"]: + if lowerword[-4:] == "trix": + return word[:-1] + "ces" + if lowerword[-3:] in ("eau", "ieu"): + return word + "x" + if lowerword[-3:] in ("ynx", "inx", "anx") and len(word) > 4: + return word[:-1] + "ges" for lastlet, d, numend, post in ( - ('n', pl_sb_C_en_ina_bysize, -2, 'ina'), - ('x', pl_sb_C_ex_ices_bysize, -2, 'ices'), - ('x', pl_sb_C_ix_ices_bysize, -2, 'ices'), - ('m', pl_sb_C_um_a_bysize, -2, 'a'), - ('s', pl_sb_C_us_i_bysize, -2, 'i'), - ('s', pl_sb_C_us_us_bysize, None, ''), - ('a', pl_sb_C_a_ae_bysize, None, 'e'), - ('a', pl_sb_C_a_ata_bysize, None, 'ta'), - ('s', pl_sb_C_is_ides_bysize, -1, 'des'), - ('o', pl_sb_C_o_i_bysize, -1, 'i'), - ('n', pl_sb_C_on_a_bysize, -2, 'a'), + ("n", pl_sb_C_en_ina_bysize, -2, "ina"), + ("x", pl_sb_C_ex_ices_bysize, -2, "ices"), + ("x", pl_sb_C_ix_ices_bysize, -2, "ices"), + ("m", pl_sb_C_um_a_bysize, -2, "a"), + ("s", pl_sb_C_us_i_bysize, -2, "i"), + ("s", pl_sb_C_us_us_bysize, None, ""), + ("a", pl_sb_C_a_ae_bysize, None, "e"), + ("a", pl_sb_C_a_ata_bysize, None, "ta"), + ("s", pl_sb_C_is_ides_bysize, -1, "des"), + ("o", pl_sb_C_o_i_bysize, -1, "i"), + ("n", pl_sb_C_on_a_bysize, -2, "a"), ): if lowerword[-1] == lastlet: # this test to add speed for k, v in d.items(): @@ -2025,117 +2836,116 @@ class engine: return word[:numend] + post for d, numend, post in ( - (pl_sb_C_i_bysize, None, 'i'), - (pl_sb_C_im_bysize, None, 'im'), + (pl_sb_C_i_bysize, None, "i"), + (pl_sb_C_im_bysize, None, "im"), ): for k, v in d.items(): if lowerword[-k:] in v: return word[:numend] + post -# HANDLE SINGULAR NOUNS ENDING IN ...s OR OTHER SILIBANTS + # HANDLE SINGULAR NOUNS ENDING IN ...s OR OTHER SILIBANTS if lowerword in pl_sb_singular_s_complete: - return word + 'es' + return word + "es" for k, v in pl_sb_singular_s_bysize.items(): if lowerword[-k:] in v: - return word + 'es' + return word + "es" - if lowerword[-2:] == 'es' and word[0] == word[0].upper(): - return word + 'es' + if lowerword[-2:] == "es" and word[0] == word[0].upper(): + return word + "es" -# Wouldn't special words -# ending with 's' always have been caught, regardless of them starting -# with a capital letter (i.e. being names) -# It makes sense below to do this for words ending in 'y' so that -# Sally -> Sallys. But not sure it makes sense here. Where is the case -# of a word ending in s that is caught here and would otherwise have been -# caught below? -# -# removing it as I can't find a case that executes it -# TODO: check this again -# -# if (self.classical_dict['names']): -# mo = search(r"([A-Z].*s)$", word) -# if mo: -# return "%ses" % mo.group(1) + # Wouldn't special words + # ending with 's' always have been caught, regardless of them starting + # with a capital letter (i.e. being names) + # It makes sense below to do this for words ending in 'y' so that + # Sally -> Sallys. But not sure it makes sense here. Where is the case + # of a word ending in s that is caught here and would otherwise have been + # caught below? + # + # removing it as I can't find a case that executes it + # TODO: check this again + # + # if (self.classical_dict['names']): + # mo = search(r"([A-Z].*s)$", word) + # if mo: + # return "%ses" % mo.group(1) - if lowerword[-1] == 'z': + if lowerword[-1] == "z": for k, v in pl_sb_z_zes_bysize.items(): if lowerword[-k:] in v: - return word + 'es' + return word + "es" - if lowerword[-2:-1] != 'z': - return word + 'zes' + if lowerword[-2:-1] != "z": + return word + "zes" - if lowerword[-2:] == 'ze': + if lowerword[-2:] == "ze": for k, v in pl_sb_ze_zes_bysize.items(): if lowerword[-k:] in v: - return word + 's' + return word + "s" - if lowerword[-2:] in ('ch', 'sh', 'zz', 'ss') or lowerword[-1] == 'x': - return word + 'es' + if lowerword[-2:] in ("ch", "sh", "zz", "ss") or lowerword[-1] == "x": + return word + "es" -# ## (r"(.*)(us)$", "%s%ses"), TODO: why is this commented? + # ## (r"(.*)(us)$", "%s%ses"), TODO: why is this commented? -# HANDLE ...f -> ...ves + # HANDLE ...f -> ...ves - if lowerword[-3:] in ('elf', 'alf', 'olf'): - return word[:-1] + 'ves' - if lowerword[-3:] == 'eaf' and lowerword[-4:-3] != 'd': - return word[:-1] + 'ves' - if lowerword[-4:] in ('nife', 'life', 'wife'): - return word[:-2] + 'ves' - if lowerword[-3:] == 'arf': - return word[:-1] + 'ves' + if lowerword[-3:] in ("elf", "alf", "olf"): + return word[:-1] + "ves" + if lowerword[-3:] == "eaf" and lowerword[-4:-3] != "d": + return word[:-1] + "ves" + if lowerword[-4:] in ("nife", "life", "wife"): + return word[:-2] + "ves" + if lowerword[-3:] == "arf": + return word[:-1] + "ves" -# HANDLE ...y + # HANDLE ...y - if lowerword[-1] == 'y': - if lowerword[-2:-1] in 'aeiou' or len(word) == 1: - return word + 's' + if lowerword[-1] == "y": + if lowerword[-2:-1] in "aeiou" or len(word) == 1: + return word + "s" - if (self.classical_dict['names']): - if lowerword[-1] == 'y' and word[0] == word[0].upper(): - return word + 's' + if self.classical_dict["names"]: + if lowerword[-1] == "y" and word[0] == word[0].upper(): + return word + "s" - return word[:-1] + 'ies' + return word[:-1] + "ies" -# HANDLE ...o + # HANDLE ...o if lowerword in pl_sb_U_o_os_complete: - return word + 's' + return word + "s" for k, v in pl_sb_U_o_os_bysize.items(): if lowerword[-k:] in v: - return word + 's' + return word + "s" - if lowerword[-2:] in ('ao', 'eo', 'io', 'oo', 'uo'): - return word + 's' + if lowerword[-2:] in ("ao", "eo", "io", "oo", "uo"): + return word + "s" - if lowerword[-1] == 'o': - return word + 'es' + if lowerword[-1] == "o": + return word + "es" -# OTHERWISE JUST ADD ...s + # OTHERWISE JUST ADD ...s return "%ss" % word def _pl_special_verb(self, word, count=None): - if (self.classical_dict['zero'] and - str(count).lower() in pl_count_zero): - return False + if self.classical_dict["zero"] and str(count).lower() in pl_count_zero: + return False count = self.get_count(count) if count == 1: return word -# HANDLE USER-DEFINED VERBS + # HANDLE USER-DEFINED VERBS value = self.ud_match(word, self.pl_v_user_defined) if value is not None: return value -# HANDLE IRREGULAR PRESENT TENSE (SIMPLE AND COMPOUND) + # HANDLE IRREGULAR PRESENT TENSE (SIMPLE AND COMPOUND) lowerword = word.lower() try: @@ -2144,58 +2954,67 @@ class engine: return False # word is '' if firstword in list(plverb_irregular_pres.keys()): - return "%s%s" % (plverb_irregular_pres[firstword], word[len(firstword):]) + return "%s%s" % (plverb_irregular_pres[firstword], word[len(firstword) :]) -# HANDLE IRREGULAR FUTURE, PRETERITE AND PERFECT TENSES + # HANDLE IRREGULAR FUTURE, PRETERITE AND PERFECT TENSES if firstword in plverb_irregular_non_pres: return word -# HANDLE PRESENT NEGATIONS (SIMPLE AND COMPOUND) + # HANDLE PRESENT NEGATIONS (SIMPLE AND COMPOUND) - if firstword.endswith("n't") and firstword[:-3] in list(plverb_irregular_pres.keys()): - return "%sn't%s" % (plverb_irregular_pres[firstword[:-3]], word[len(firstword):]) + if firstword.endswith("n't") and firstword[:-3] in list( + plverb_irregular_pres.keys() + ): + return "%sn't%s" % ( + plverb_irregular_pres[firstword[:-3]], + word[len(firstword) :], + ) if firstword.endswith("n't"): return word -# HANDLE SPECIAL CASES + # HANDLE SPECIAL CASES mo = search(r"^(%s)$" % plverb_special_s, word) if mo: return False if search(r"\s", word): return False - if lowerword == 'quizzes': - return 'quiz' + if lowerword == "quizzes": + return "quiz" -# HANDLE STANDARD 3RD PERSON (CHOP THE ...(e)s OFF SINGLE WORDS) + # HANDLE STANDARD 3RD PERSON (CHOP THE ...(e)s OFF SINGLE WORDS) - if lowerword[-4:] in ('ches', 'shes', 'zzes', 'sses') or \ - lowerword[-3:] == 'xes': + if ( + lowerword[-4:] in ("ches", "shes", "zzes", "sses") + or lowerword[-3:] == "xes" + ): return word[:-2] -# # mo = search(r"^(.*)([cs]h|[x]|zz|ss)es$", -# # word, IGNORECASE) -# # if mo: -# # return "%s%s" % (mo.group(1), mo.group(2)) + # # mo = search(r"^(.*)([cs]h|[x]|zz|ss)es$", + # # word, IGNORECASE) + # # if mo: + # # return "%s%s" % (mo.group(1), mo.group(2)) - if lowerword[-3:] == 'ies' and len(word) > 3: - return lowerword[:-3] + 'y' + if lowerword[-3:] == "ies" and len(word) > 3: + return lowerword[:-3] + "y" - if (lowerword in pl_v_oes_oe or - lowerword[-4:] in pl_v_oes_oe_endings_size4 or - lowerword[-5:] in pl_v_oes_oe_endings_size5): - return word[:-1] + if ( + lowerword in pl_v_oes_oe + or lowerword[-4:] in pl_v_oes_oe_endings_size4 + or lowerword[-5:] in pl_v_oes_oe_endings_size5 + ): + return word[:-1] - if lowerword.endswith('oes') and len(word) > 3: + if lowerword.endswith("oes") and len(word) > 3: return lowerword[:-2] mo = search(r"^(.*[^s])s$", word, IGNORECASE) if mo: return mo.group(1) -# OTHERWISE, A REGULAR VERB (HANDLE ELSEWHERE) + # OTHERWISE, A REGULAR VERB (HANDLE ELSEWHERE) return False @@ -2205,19 +3024,19 @@ class engine: if count == 1: return word -# HANDLE AMBIGUOUS PRESENT TENSES (SIMPLE AND COMPOUND) + # HANDLE AMBIGUOUS PRESENT TENSES (SIMPLE AND COMPOUND) mo = search(r"^(%s)((\s.*)?)$" % plverb_ambiguous_pres_keys, word, IGNORECASE) if mo: return "%s%s" % (plverb_ambiguous_pres[mo.group(1).lower()], mo.group(2)) -# HANDLE AMBIGUOUS PRETERITE AND PERFECT TENSES + # HANDLE AMBIGUOUS PRETERITE AND PERFECT TENSES mo = search(r"^(%s)((\s.*)?)$" % plverb_ambiguous_non_pres, word, IGNORECASE) if mo: return word -# OTHERWISE, 1st OR 2ND PERSON IS UNINFLECTED + # OTHERWISE, 1st OR 2ND PERSON IS UNINFLECTED return word @@ -2227,34 +3046,31 @@ class engine: if count == 1: return word -# HANDLE USER-DEFINED ADJECTIVES + # HANDLE USER-DEFINED ADJECTIVES value = self.ud_match(word, self.pl_adj_user_defined) if value is not None: return value -# HANDLE KNOWN CASES + # HANDLE KNOWN CASES - mo = search(r"^(%s)$" % pl_adj_special_keys, - word, IGNORECASE) + mo = search(r"^(%s)$" % pl_adj_special_keys, word, IGNORECASE) if mo: return "%s" % (pl_adj_special[mo.group(1).lower()]) -# HANDLE POSSESSIVES + # HANDLE POSSESSIVES - mo = search(r"^(%s)$" % pl_adj_poss_keys, - word, IGNORECASE) + mo = search(r"^(%s)$" % pl_adj_poss_keys, word, IGNORECASE) if mo: return "%s" % (pl_adj_poss[mo.group(1).lower()]) - mo = search(r"^(.*)'s?$", - word) + mo = search(r"^(.*)'s?$", word) if mo: pl = self.plural_noun(mo.group(1)) - trailing_s = "" if pl[-1] == 's' else "s" + trailing_s = "" if pl[-1] == "s" else "s" return "%s'%s" % (pl, trailing_s) -# OTHERWISE, NO IDEA + # OTHERWISE, NO IDEA return False @@ -2262,12 +3078,12 @@ class engine: def _sinoun(self, word, count=None, gender=None): count = self.get_count(count) -# DEFAULT TO PLURAL + # DEFAULT TO PLURAL if count == 2: return word -# SET THE GENDER + # SET THE GENDER try: if gender is None: @@ -2277,15 +3093,15 @@ class engine: except (TypeError, IndexError): raise BadGenderError -# HANDLE USER-DEFINED NOUNS + # HANDLE USER-DEFINED NOUNS value = self.ud_match(word, self.si_sb_user_defined) if value is not None: return value -# HANDLE EMPTY WORD, SINGULAR COUNT AND UNINFLECTED PLURALS + # HANDLE EMPTY WORD, SINGULAR COUNT AND UNINFLECTED PLURALS - if word == '': + if word == "": return word lowerword = word.lower() @@ -2303,13 +3119,13 @@ class engine: if lowerword[-k:] in v: return word - if (self.classical_dict['herd'] and lowerword in pl_sb_uninflected_herd): + if self.classical_dict["herd"] and lowerword in pl_sb_uninflected_herd: return word -# HANDLE COMPOUNDS ("Governor General", "mother-in-law", "aide-de-camp", ETC.) + # HANDLE COMPOUNDS ("Governor General", "mother-in-law", "aide-de-camp", ETC.) mo = search(r"^(?:%s)$" % pl_sb_postfix_adj_stems, word, IGNORECASE) - if mo and mo.group(2) != '': + if mo and mo.group(2) != "": return "%s%s" % (self._sinoun(mo.group(1), 1, gender=gender), mo.group(2)) # how to reverse this one? @@ -2319,43 +3135,55 @@ class engine: # mo.group(2), # self._sinoun(mo.group(3), 1)) - lowersplit = lowerword.split(' ') + lowersplit = lowerword.split(" ") if len(lowersplit) >= 3: for numword in range(1, len(lowersplit) - 1): if lowersplit[numword] in pl_prep_list_da: - return ' '.join(lowersplit[:numword - 1] + - [self._sinoun(lowersplit[numword - 1], 1, gender=gender)] + - lowersplit[numword:]) + return " ".join( + lowersplit[: numword - 1] + + [self._sinoun(lowersplit[numword - 1], 1, gender=gender)] + + lowersplit[numword:] + ) - lowersplit = lowerword.split('-') + lowersplit = lowerword.split("-") if len(lowersplit) >= 3: for numword in range(1, len(lowersplit) - 1): if lowersplit[numword] in pl_prep_list_da: - return ' '.join( - lowersplit[:numword - 1] + - [self._sinoun(lowersplit[numword - 1], 1, gender=gender) + - '-' + lowersplit[numword] + '-']) + ' '.join(lowersplit[(numword + 1):]) + return " ".join( + lowersplit[: numword - 1] + + [ + self._sinoun(lowersplit[numword - 1], 1, gender=gender) + + "-" + + lowersplit[numword] + + "-" + ] + ) + " ".join(lowersplit[(numword + 1) :]) -# HANDLE PRONOUNS + # HANDLE PRONOUNS for k, v in si_pron_acc_keys_bysize.items(): if lowerword[-k:] in v: # ends with accusivate pronoun for pk, pv in pl_prep_bysize.items(): if lowerword[:pk] in pv: # starts with a prep - if lowerword.split() == [lowerword[:pk], lowerword[-k:]]: # only whitespace in between - return lowerword[:-k] + get_si_pron('acc', lowerword[-k:], gender) + if lowerword.split() == [ + lowerword[:pk], + lowerword[-k:], + ]: # only whitespace in between + return lowerword[:-k] + get_si_pron( + "acc", lowerword[-k:], gender + ) try: - return get_si_pron('nom', word.lower(), gender) + return get_si_pron("nom", word.lower(), gender) except KeyError: pass try: - return get_si_pron('acc', word.lower(), gender) + return get_si_pron("acc", word.lower(), gender) except KeyError: pass -# HANDLE ISOLATED IRREGULAR PLURALS + # HANDLE ISOLATED IRREGULAR PLURALS wordsplit = word.split() wordlast = wordsplit[-1] @@ -2363,127 +3191,132 @@ class engine: if wordlast in list(si_sb_irregular_caps.keys()): llen = len(wordlast) - return '%s%s' % (word[:-llen], - si_sb_irregular_caps[wordlast]) + return "%s%s" % (word[:-llen], si_sb_irregular_caps[wordlast]) if lowerwordlast in list(si_sb_irregular.keys()): llen = len(lowerwordlast) - return '%s%s' % (word[:-llen], - si_sb_irregular[lowerwordlast]) + return "%s%s" % (word[:-llen], si_sb_irregular[lowerwordlast]) - if (' '.join(wordsplit[-2:])).lower() in list(si_sb_irregular_compound.keys()): - llen = len(' '.join(wordsplit[-2:])) # TODO: what if 2 spaces between these words? - return '%s%s' % (word[:-llen], - si_sb_irregular_compound[(' '.join(wordsplit[-2:])).lower()]) + if (" ".join(wordsplit[-2:])).lower() in list(si_sb_irregular_compound.keys()): + llen = len( + " ".join(wordsplit[-2:]) + ) # TODO: what if 2 spaces between these words? + return "%s%s" % ( + word[:-llen], + si_sb_irregular_compound[(" ".join(wordsplit[-2:])).lower()], + ) - if lowerword[-5:] == 'quies': - return word[:-3] + 'y' + if lowerword[-5:] == "quies": + return word[:-3] + "y" - if lowerword[-7:] == 'persons': + if lowerword[-7:] == "persons": return word[:-1] - if lowerword[-6:] == 'people': - return word[:-4] + 'rson' + if lowerword[-6:] == "people": + return word[:-4] + "rson" -# HANDLE FAMILIES OF IRREGULAR PLURALS + # HANDLE FAMILIES OF IRREGULAR PLURALS - if lowerword[-4:] == 'mans': + if lowerword[-4:] == "mans": for k, v in si_sb_U_man_mans_bysize.items(): if lowerword[-k:] in v: return word[:-1] for k, v in si_sb_U_man_mans_caps_bysize.items(): if word[-k:] in v: return word[:-1] - if lowerword[-3:] == 'men': - return word[:-3] + 'man' - if lowerword[-4:] == 'mice': - return word[:-4] + 'mouse' - if lowerword[-4:] == 'lice': - return word[:-4] + 'louse' - if lowerword[-5:] == 'geese': - return word[:-5] + 'goose' - if lowerword[-5:] == 'teeth': - return word[:-5] + 'tooth' - if lowerword[-4:] == 'feet': - return word[:-4] + 'foot' + if lowerword[-3:] == "men": + return word[:-3] + "man" + if lowerword[-4:] == "mice": + return word[:-4] + "mouse" + if lowerword[-4:] == "lice": + return word[:-4] + "louse" + if lowerword[-5:] == "geese": + return word[:-5] + "goose" + if lowerword[-5:] == "teeth": + return word[:-5] + "tooth" + if lowerword[-4:] == "feet": + return word[:-4] + "foot" - if lowerword == 'dice': - return 'die' + if lowerword == "dice": + return "die" -# HANDLE UNASSIMILATED IMPORTS + # HANDLE UNASSIMILATED IMPORTS - if lowerword[-4:] == 'ceps': + if lowerword[-4:] == "ceps": return word - if lowerword[-3:] == 'zoa': - return word[:-1] + 'on' + if lowerword[-3:] == "zoa": + return word[:-1] + "on" for lastlet, d, numend, post in ( - ('s', si_sb_U_ch_chs_bysize, -1, ''), - ('s', si_sb_U_ex_ices_bysize, -4, 'ex'), - ('s', si_sb_U_ix_ices_bysize, -4, 'ix'), - ('a', si_sb_U_um_a_bysize, -1, 'um'), - ('i', si_sb_U_us_i_bysize, -1, 'us'), - ('a', si_sb_U_on_a_bysize, -1, 'on'), - ('e', si_sb_U_a_ae_bysize, -1, ''), + ("s", si_sb_U_ch_chs_bysize, -1, ""), + ("s", si_sb_U_ex_ices_bysize, -4, "ex"), + ("s", si_sb_U_ix_ices_bysize, -4, "ix"), + ("a", si_sb_U_um_a_bysize, -1, "um"), + ("i", si_sb_U_us_i_bysize, -1, "us"), + ("a", si_sb_U_on_a_bysize, -1, "on"), + ("e", si_sb_U_a_ae_bysize, -1, ""), ): if lowerword[-1] == lastlet: # this test to add speed for k, v in d.items(): if lowerword[-k:] in v: return word[:numend] + post -# HANDLE INCOMPLETELY ASSIMILATED IMPORTS + # HANDLE INCOMPLETELY ASSIMILATED IMPORTS - if (self.classical_dict['ancient']): + if self.classical_dict["ancient"]: - if lowerword[-6:] == 'trices': - return word[:-3] + 'x' - if lowerword[-4:] in ('eaux', 'ieux'): + if lowerword[-6:] == "trices": + return word[:-3] + "x" + if lowerword[-4:] in ("eaux", "ieux"): return word[:-1] - if lowerword[-5:] in ('ynges', 'inges', 'anges') and len(word) > 6: - return word[:-3] + 'x' + if lowerword[-5:] in ("ynges", "inges", "anges") and len(word) > 6: + return word[:-3] + "x" for lastlet, d, numend, post in ( - ('a', si_sb_C_en_ina_bysize, -3, 'en'), - ('s', si_sb_C_ex_ices_bysize, -4, 'ex'), - ('s', si_sb_C_ix_ices_bysize, -4, 'ix'), - ('a', si_sb_C_um_a_bysize, -1, 'um'), - ('i', si_sb_C_us_i_bysize, -1, 'us'), - ('s', pl_sb_C_us_us_bysize, None, ''), - ('e', si_sb_C_a_ae_bysize, -1, ''), - ('a', si_sb_C_a_ata_bysize, -2, ''), - ('s', si_sb_C_is_ides_bysize, -3, 's'), - ('i', si_sb_C_o_i_bysize, -1, 'o'), - ('a', si_sb_C_on_a_bysize, -1, 'on'), - ('m', si_sb_C_im_bysize, -2, ''), - ('i', si_sb_C_i_bysize, -1, ''), + ("a", si_sb_C_en_ina_bysize, -3, "en"), + ("s", si_sb_C_ex_ices_bysize, -4, "ex"), + ("s", si_sb_C_ix_ices_bysize, -4, "ix"), + ("a", si_sb_C_um_a_bysize, -1, "um"), + ("i", si_sb_C_us_i_bysize, -1, "us"), + ("s", pl_sb_C_us_us_bysize, None, ""), + ("e", si_sb_C_a_ae_bysize, -1, ""), + ("a", si_sb_C_a_ata_bysize, -2, ""), + ("s", si_sb_C_is_ides_bysize, -3, "s"), + ("i", si_sb_C_o_i_bysize, -1, "o"), + ("a", si_sb_C_on_a_bysize, -1, "on"), + ("m", si_sb_C_im_bysize, -2, ""), + ("i", si_sb_C_i_bysize, -1, ""), ): if lowerword[-1] == lastlet: # this test to add speed for k, v in d.items(): if lowerword[-k:] in v: return word[:numend] + post -# HANDLE PLURLS ENDING IN uses -> use + # HANDLE PLURLS ENDING IN uses -> use - if (lowerword[-6:] == 'houses' or - word in si_sb_uses_use_case or - lowerword in si_sb_uses_use): + if ( + lowerword[-6:] == "houses" + or word in si_sb_uses_use_case + or lowerword in si_sb_uses_use + ): return word[:-1] -# HANDLE PLURLS ENDING IN ies -> ie + # HANDLE PLURLS ENDING IN ies -> ie if word in si_sb_ies_ie_case or lowerword in si_sb_ies_ie: return word[:-1] -# HANDLE PLURLS ENDING IN oes -> oe + # HANDLE PLURLS ENDING IN oes -> oe - if (lowerword[-5:] == 'shoes' or - word in si_sb_oes_oe_case or - lowerword in si_sb_oes_oe): + if ( + lowerword[-5:] == "shoes" + or word in si_sb_oes_oe_case + or lowerword in si_sb_oes_oe + ): return word[:-1] -# HANDLE SINGULAR NOUNS ENDING IN ...s OR OTHER SILIBANTS + # HANDLE SINGULAR NOUNS ENDING IN ...s OR OTHER SILIBANTS - if (word in si_sb_sses_sse_case or - lowerword in si_sb_sses_sse): + if word in si_sb_sses_sse_case or lowerword in si_sb_sses_sse: return word[:-1] if lowerword in si_sb_singular_s_complete: @@ -2493,24 +3326,24 @@ class engine: if lowerword[-k:] in v: return word[:-2] - if lowerword[-4:] == 'eses' and word[0] == word[0].upper(): + if lowerword[-4:] == "eses" and word[0] == word[0].upper(): return word[:-2] -# Wouldn't special words -# ending with 's' always have been caught, regardless of them starting -# with a capital letter (i.e. being names) -# It makes sense below to do this for words ending in 'y' so that -# Sally -> Sallys. But not sure it makes sense here. Where is the case -# of a word ending in s that is caught here and would otherwise have been -# caught below? -# -# removing it as I can't find a case that executes it -# TODO: check this again -# -# if (self.classical_dict['names']): -# mo = search(r"([A-Z].*ses)$", word) -# if mo: -# return "%s" % mo.group(1) + # Wouldn't special words + # ending with 's' always have been caught, regardless of them starting + # with a capital letter (i.e. being names) + # It makes sense below to do this for words ending in 'y' so that + # Sally -> Sallys. But not sure it makes sense here. Where is the case + # of a word ending in s that is caught here and would otherwise have been + # caught below? + # + # removing it as I can't find a case that executes it + # TODO: check this again + # + # if (self.classical_dict['names']): + # mo = search(r"([A-Z].*ses)$", word) + # if mo: + # return "%s" % mo.group(1) if lowerword in si_sb_z_zes: return word[:-2] @@ -2518,55 +3351,53 @@ class engine: if lowerword in si_sb_zzes_zz: return word[:-2] - if lowerword[-4:] == 'zzes': + if lowerword[-4:] == "zzes": return word[:-3] - if (word in si_sb_ches_che_case or - lowerword in si_sb_ches_che): + if word in si_sb_ches_che_case or lowerword in si_sb_ches_che: return word[:-1] - if lowerword[-4:] in ('ches', 'shes'): + if lowerword[-4:] in ("ches", "shes"): return word[:-2] if lowerword in si_sb_xes_xe: return word[:-1] - if lowerword[-3:] == 'xes': + if lowerword[-3:] == "xes": return word[:-2] -# (r"(.*)(us)es$", "%s%s"), TODO: why is this commented? + # (r"(.*)(us)es$", "%s%s"), TODO: why is this commented? -# HANDLE ...f -> ...ves + # HANDLE ...f -> ...ves - if (word in si_sb_ves_ve_case or - lowerword in si_sb_ves_ve): + if word in si_sb_ves_ve_case or lowerword in si_sb_ves_ve: return word[:-1] - if lowerword[-3:] == 'ves': - if lowerword[-5:-3] in ('el', 'al', 'ol'): - return word[:-3] + 'f' - if lowerword[-5:-3] == 'ea' and word[-6:-5] != 'd': - return word[:-3] + 'f' - if lowerword[-5:-3] in ('ni', 'li', 'wi'): - return word[:-3] + 'fe' - if lowerword[-5:-3] == 'ar': - return word[:-3] + 'f' + if lowerword[-3:] == "ves": + if lowerword[-5:-3] in ("el", "al", "ol"): + return word[:-3] + "f" + if lowerword[-5:-3] == "ea" and word[-6:-5] != "d": + return word[:-3] + "f" + if lowerword[-5:-3] in ("ni", "li", "wi"): + return word[:-3] + "fe" + if lowerword[-5:-3] == "ar": + return word[:-3] + "f" -# HANDLE ...y + # HANDLE ...y - if lowerword[-2:] == 'ys': - if len(lowerword) > 2 and lowerword[-3] in 'aeiou': + if lowerword[-2:] == "ys": + if len(lowerword) > 2 and lowerword[-3] in "aeiou": return word[:-1] - if (self.classical_dict['names']): - if lowerword[-2:] == 'ys' and word[0] == word[0].upper(): + if self.classical_dict["names"]: + if lowerword[-2:] == "ys" and word[0] == word[0].upper(): return word[:-1] - if lowerword[-3:] == 'ies': - return word[:-3] + 'y' + if lowerword[-3:] == "ies": + return word[:-3] + "y" -# HANDLE ...o + # HANDLE ...o - if lowerword[-2:] == 'os': + if lowerword[-2:] == "os": if lowerword in si_sb_U_o_os_complete: return word[:-1] @@ -2575,30 +3406,30 @@ class engine: if lowerword[-k:] in v: return word[:-1] - if lowerword[-3:] in ('aos', 'eos', 'ios', 'oos', 'uos'): + if lowerword[-3:] in ("aos", "eos", "ios", "oos", "uos"): return word[:-1] - if lowerword[-3:] == 'oes': + if lowerword[-3:] == "oes": return word[:-2] -# UNASSIMILATED IMPORTS FINAL RULE + # UNASSIMILATED IMPORTS FINAL RULE if word in si_sb_es_is: - return word[:-2] + 'is' + return word[:-2] + "is" -# OTHERWISE JUST REMOVE ...s + # OTHERWISE JUST REMOVE ...s - if lowerword[-1] == 's': + if lowerword[-1] == "s": return word[:-1] -# COULD NOT FIND SINGULAR + # COULD NOT FIND SINGULAR return False -# ADJECTIVES + # ADJECTIVES def a(self, text, count=1): - ''' + """ Return the appropriate indefinite article followed by text. The indefinite article is either 'a' or 'an'. @@ -2608,9 +3439,8 @@ class engine: Whitespace at the start and end is preserved. - ''' - mo = search(r"\A(\s*)(?:an?\s+)?(.+?)(\s*)\Z", - text, IGNORECASE) + """ + mo = search(r"\A(\s*)(?:an?\s+)?(.+?)(\s*)\Z", text, IGNORECASE) if mo: word = mo.group(2) if not word: @@ -2619,7 +3449,7 @@ class engine: post = mo.group(3) result = self._indef_article(word, count) return "%s%s%s" % (pre, result, post) - return '' + return "" an = a @@ -2629,90 +3459,87 @@ class engine: if mycount != 1: return "%s %s" % (count, word) -# HANDLE USER-DEFINED VARIANTS + # HANDLE USER-DEFINED VARIANTS value = self.ud_match(word, self.A_a_user_defined) if value is not None: return "%s %s" % (value, word) -# HANDLE ORDINAL FORMS + # HANDLE ORDINAL FORMS + + for a in ((r"^(%s)" % A_ordinal_a, "a"), (r"^(%s)" % A_ordinal_an, "an")): + mo = search(a[0], word, IGNORECASE) + if mo: + return "%s %s" % (a[1], word) + + # HANDLE SPECIAL CASES for a in ( - (r"^(%s)" % A_ordinal_a, "a"), - (r"^(%s)" % A_ordinal_an, "an"), + (r"^(%s)" % A_explicit_an, "an"), + (r"^[aefhilmnorsx]$", "an"), + (r"^[bcdgjkpqtuvwyz]$", "a"), ): mo = search(a[0], word, IGNORECASE) if mo: return "%s %s" % (a[1], word) -# HANDLE SPECIAL CASES + # HANDLE ABBREVIATIONS for a in ( - (r"^(%s)" % A_explicit_an, "an"), - (r"^[aefhilmnorsx]$", "an"), - (r"^[bcdgjkpqtuvwyz]$", "a"), - ): - mo = search(a[0], word, IGNORECASE) - if mo: - return "%s %s" % (a[1], word) - -# HANDLE ABBREVIATIONS - - for a in ( - (r"(%s)" % A_abbrev, "an", VERBOSE), - (r"^[aefhilmnorsx][.-]", "an", IGNORECASE), - (r"^[a-z][.-]", "a", IGNORECASE), + (r"(%s)" % A_abbrev, "an", VERBOSE), + (r"^[aefhilmnorsx][.-]", "an", IGNORECASE), + (r"^[a-z][.-]", "a", IGNORECASE), ): mo = search(a[0], word, a[2]) if mo: return "%s %s" % (a[1], word) -# HANDLE CONSONANTS + # HANDLE CONSONANTS mo = search(r"^[^aeiouy]", word, IGNORECASE) if mo: return "a %s" % word -# HANDLE SPECIAL VOWEL-FORMS + # HANDLE SPECIAL VOWEL-FORMS for a in ( - (r"^e[uw]", "a"), - (r"^onc?e\b", "a"), - (r"^onetime\b", "a"), - (r"^uni([^nmd]|mo)", "a"), - (r"^u[bcfghjkqrst][aeiou]", "a"), - (r"^ukr", "a"), - (r"^(%s)" % A_explicit_a, "a"), + (r"^e[uw]", "a"), + (r"^onc?e\b", "a"), + (r"^onetime\b", "a"), + (r"^uni([^nmd]|mo)", "a"), + (r"^u[bcfghjkqrst][aeiou]", "a"), + (r"^ukr", "a"), + (r"^(%s)" % A_explicit_a, "a"), ): mo = search(a[0], word, IGNORECASE) if mo: return "%s %s" % (a[1], word) -# HANDLE SPECIAL CAPITALS + # HANDLE SPECIAL CAPITALS mo = search(r"^U[NK][AIEO]?", word) if mo: return "a %s" % word -# HANDLE VOWELS + # HANDLE VOWELS mo = search(r"^[aeiou]", word, IGNORECASE) if mo: return "an %s" % word -# HANDLE y... (BEFORE CERTAIN CONSONANTS IMPLIES (UNNATURALIZED) "i.." SOUND) + # HANDLE y... (BEFORE CERTAIN CONSONANTS IMPLIES (UNNATURALIZED) "i.." SOUND) mo = search(r"^(%s)" % A_y_cons, word, IGNORECASE) if mo: return "an %s" % word -# OTHERWISE, GUESS "a" + # OTHERWISE, GUESS "a" return "a %s" % word -# 2. TRANSLATE ZERO-QUANTIFIED $word TO "no plural($word)" + # 2. TRANSLATE ZERO-QUANTIFIED $word TO "no plural($word)" def no(self, text, count=None): - ''' + """ If count is 0, no, zero or nil, return 'no' followed by the plural of text. @@ -2726,7 +3553,7 @@ class engine: Whitespace at the start and end is preserved. - ''' + """ if count is None and self.persistent_count is not None: count = self.persistent_count @@ -2742,39 +3569,39 @@ class engine: else: return "%s%s %s%s" % (pre, count, self.plural(word, count), post) -# PARTICIPLES + # PARTICIPLES def present_participle(self, word): - ''' + """ Return the present participle for word. word is the 3rd person singular verb. - ''' + """ plv = self.plural_verb(word, 2) for pat, repl in ( - (r"ie$", r"y"), - (r"ue$", r"u"), # TODO: isn't ue$ -> u encompassed in the following rule? - (r"([auy])e$", r"\g<1>"), - (r"ski$", r"ski"), - (r"[^b]i$", r""), - (r"^(are|were)$", r"be"), - (r"^(had)$", r"hav"), - (r"^(hoe)$", r"\g<1>"), - (r"([^e])e$", r"\g<1>"), - (r"er$", r"er"), - (r"([^aeiou][aeiouy]([bdgmnprst]))$", "\g<1>\g<2>"), + (r"ie$", r"y"), + (r"ue$", r"u"), # TODO: isn't ue$ -> u encompassed in the following rule? + (r"([auy])e$", r"\g<1>"), + (r"ski$", r"ski"), + (r"[^b]i$", r""), + (r"^(are|were)$", r"be"), + (r"^(had)$", r"hav"), + (r"^(hoe)$", r"\g<1>"), + (r"([^e])e$", r"\g<1>"), + (r"er$", r"er"), + (r"([^aeiou][aeiouy]([bdgmnprst]))$", "\g<1>\g<2>"), ): (ans, num) = subn(pat, repl, plv) if num: return "%sing" % ans return "%sing" % ans -# NUMERICAL INFLECTIONS + # NUMERICAL INFLECTIONS def ordinal(self, num): - ''' + """ Return the ordinal of num. num can be an integer or text @@ -2782,15 +3609,17 @@ class engine: e.g. ordinal(1) returns '1st' ordinal('one') returns 'first' - ''' + """ if match(r"\d", str(num)): try: num % 2 n = num except TypeError: - if '.' in str(num): + if "." in str(num): try: - n = int(num[-1]) # numbers after decimal, so only need last one for ordinal + n = int( + num[-1] + ) # numbers after decimal, so only need last one for ordinal except ValueError: # ends with '.', so need to use whole string n = int(num[:-1]) else: @@ -2819,31 +3648,35 @@ class engine: def tenfn(self, tens, units, mindex=0): if tens != 1: - return "%s%s%s%s" % (ten[tens], - '-' if tens and units else '', - unit[units], - self.millfn(mindex)) + return "%s%s%s%s" % ( + ten[tens], + "-" if tens and units else "", + unit[units], + self.millfn(mindex), + ) return "%s%s" % (teen[units], mill[mindex]) def hundfn(self, hundreds, tens, units, mindex): if hundreds: - return "%s hundred%s%s%s, " % (unit[hundreds], # use unit not unitfn as simpler - " %s " % self.number_args['andword'] if tens or units else '', - self.tenfn(tens, units), - self.millfn(mindex)) + return "%s hundred%s%s%s, " % ( + unit[hundreds], # use unit not unitfn as simpler + " %s " % self.number_args["andword"] if tens or units else "", + self.tenfn(tens, units), + self.millfn(mindex), + ) if tens or units: return "%s%s, " % (self.tenfn(tens, units), self.millfn(mindex)) - return '' + return "" def group1sub(self, mo): units = int(mo.group(1)) if units == 1: - return " %s, " % self.number_args['one'] + return " %s, " % self.number_args["one"] elif units: # TODO: bug one and zero are padded with a space but other numbers aren't. check this in perl return "%s, " % unit[units] else: - return " %s, " % self.number_args['zero'] + return " %s, " % self.number_args["zero"] def group1bsub(self, mo): units = int(mo.group(1)) @@ -2851,7 +3684,7 @@ class engine: # TODO: bug one and zero are padded with a space but other numbers aren't. check this in perl return "%s, " % unit[units] else: - return " %s, " % self.number_args['zero'] + return " %s, " % self.number_args["zero"] def group2sub(self, mo): tens = int(mo.group(1)) @@ -2859,30 +3692,32 @@ class engine: if tens: return "%s, " % self.tenfn(tens, units) if units: - return " %s %s, " % (self.number_args['zero'], unit[units]) - return " %s %s, " % (self.number_args['zero'], self.number_args['zero']) + return " %s %s, " % (self.number_args["zero"], unit[units]) + return " %s %s, " % (self.number_args["zero"], self.number_args["zero"]) def group3sub(self, mo): hundreds = int(mo.group(1)) tens = int(mo.group(2)) units = int(mo.group(3)) if hundreds == 1: - hunword = " %s" % self.number_args['one'] + hunword = " %s" % self.number_args["one"] elif hundreds: hunword = "%s" % unit[hundreds] # TODO: bug one and zero are padded with a space but other numbers aren't. check this in perl else: - hunword = " %s" % self.number_args['zero'] + hunword = " %s" % self.number_args["zero"] if tens: tenword = self.tenfn(tens, units) elif units: - tenword = " %s %s" % (self.number_args['zero'], unit[units]) + tenword = " %s %s" % (self.number_args["zero"], unit[units]) else: - tenword = " %s %s" % (self.number_args['zero'], self.number_args['zero']) + tenword = " %s %s" % (self.number_args["zero"], self.number_args["zero"]) return "%s %s, " % (hunword, tenword) def hundsub(self, mo): - ret = self.hundfn(int(mo.group(1)), int(mo.group(2)), int(mo.group(3)), self.mill_count) + ret = self.hundfn( + int(mo.group(1)), int(mo.group(2)), int(mo.group(3)), self.mill_count + ) self.mill_count += 1 return ret @@ -2912,11 +3747,11 @@ class engine: num = resub(r"(\d)(\d)", self.group2sub, num, 1) num = resub(r"(\d)", self.group1sub, num, 1) elif int(num) == 0: - num = self.number_args['zero'] + num = self.number_args["zero"] elif int(num) == 1: - num = self.number_args['one'] + num = self.number_args["one"] else: - num = num.lstrip().lstrip('0') + num = num.lstrip().lstrip("0") self.mill_count = 0 # surely there's a better way to do the next bit mo = search(r"(\d)(\d)(\d)(?=\D*\Z)", num) @@ -2928,31 +3763,39 @@ class engine: return num def blankfn(self, mo): - ''' do a global blank replace + """ do a global blank replace TODO: surely this can be done with an option to resub rather than this fn - ''' - return '' + """ + return "" def commafn(self, mo): - ''' do a global ',' replace + """ do a global ',' replace TODO: surely this can be done with an option to resub rather than this fn - ''' - return ',' + """ + return "," def spacefn(self, mo): - ''' do a global ' ' replace + """ do a global ' ' replace TODO: surely this can be done with an option to resub rather than this fn - ''' - return ' ' + """ + return " " - def number_to_words(self, num, wantlist=False, - group=0, comma=',', andword='and', - zero='zero', one='one', decimal='point', - threshold=None): - ''' + def number_to_words( + self, + num, + wantlist=False, + group=0, + comma=",", + andword="and", + zero="zero", + one="one", + decimal="point", + threshold=None, + ): + """ Return a number in words. group = 1, 2 or 3 to group numbers before turning into words @@ -2965,14 +3808,14 @@ class engine: threshold: numbers above threshold not turned into words parameters not remembered from last call. Departure from Perl version. - ''' + """ self.number_args = dict(andword=andword, zero=zero, one=one) - num = '%s' % num + num = "%s" % num # Handle "stylistic" conversions (up to a given threshold)... - if (threshold is not None and float(num) > threshold): - spnum = num.split('.', 1) - while (comma): + if threshold is not None and float(num) > threshold: + spnum = num.split(".", 1) + while comma: (spnum[0], n) = subn(r"(\d)(\d{3}(?:,|\Z))", r"\1,\2", spnum[0]) if n == 0: break @@ -2984,23 +3827,23 @@ class engine: if group < 0 or group > 3: raise BadChunkingOptionError nowhite = num.lstrip() - if nowhite[0] == '+': + if nowhite[0] == "+": sign = "plus" - elif nowhite[0] == '-': + elif nowhite[0] == "-": sign = "minus" else: sign = "" - myord = (num[-2:] in ('st', 'nd', 'rd', 'th')) + myord = num[-2:] in ("st", "nd", "rd", "th") if myord: num = num[:-2] finalpoint = False if decimal: if group != 0: - chunks = num.split('.') + chunks = num.split(".") else: - chunks = num.split('.', 1) - if chunks[-1] == '': # remove blank string if nothing after decimal + chunks = num.split(".", 1) + if chunks[-1] == "": # remove blank string if nothing after decimal chunks = chunks[:-1] finalpoint = True # add 'point' to end of output else: @@ -3009,7 +3852,7 @@ class engine: first = 1 loopstart = 0 - if chunks[0] == '': + if chunks[0] == "": first = 0 if len(chunks) > 1: loopstart = 1 @@ -3021,12 +3864,12 @@ class engine: if chunk == "": chunk = "0" - if group == 0 and (first == 0 or first == ''): + if group == 0 and (first == 0 or first == ""): chunk = self.enword(chunk, 1) else: chunk = self.enword(chunk, group) - if chunk[-2:] == ', ': + if chunk[-2:] == ", ": chunk = chunk[:-2] chunk = resub(r"\s+,", self.commafn, chunk) @@ -3036,7 +3879,7 @@ class engine: # chunk = resub(r"(\A\s|\s\Z)", self.blankfn, chunk) chunk = chunk.strip() if first: - first = '' + first = "" chunks[i] = chunk numchunks = [] @@ -3047,10 +3890,11 @@ class engine: # TODO: can this be just one re as it is in perl? mo = search(r"(%s)\Z" % ordinal_suff, numchunks[-1]) if mo: - numchunks[-1] = resub(r"(%s)\Z" % ordinal_suff, ordinal[mo.group(1)], - numchunks[-1]) + numchunks[-1] = resub( + r"(%s)\Z" % ordinal_suff, ordinal[mo.group(1)], numchunks[-1] + ) else: - numchunks[-1] += 'th' + numchunks[-1] += "th" for chunk in chunks[1:]: numchunks.append(decimal) @@ -3065,10 +3909,10 @@ class engine: numchunks = [sign] + numchunks return numchunks elif group: - signout = "%s " % sign if sign else '' + signout = "%s " % sign if sign else "" return "%s%s" % (signout, ", ".join(numchunks)) else: - signout = "%s " % sign if sign else '' + signout = "%s " % sign if sign else "" num = "%s%s" % (signout, numchunks.pop(0)) if decimal is None: first = True @@ -3084,11 +3928,18 @@ class engine: num += " %s" % nc return num -# Join words with commas and a trailing 'and' (when appropriate)... + # Join words with commas and a trailing 'and' (when appropriate)... - def join(self, words, sep=None, sep_spaced=True, - final_sep=None, conj='and', conj_spaced=True): - ''' + def join( + self, + words, + sep=None, + sep_spaced=True, + final_sep=None, + conj="and", + conj_spaced=True, + ): + """ Join words into a list. e.g. join(['ant', 'bee', 'fly']) returns 'ant, bee, and fly' @@ -3099,32 +3950,32 @@ class engine: final_sep: final separator. default ',', unless ',' is in the list then ';' conj_spaced: boolean. Should conj have spaces around it - ''' + """ if not words: return "" if len(words) == 1: return words[0] if conj_spaced: - if conj == '': - conj = ' ' + if conj == "": + conj = " " else: - conj = ' %s ' % conj + conj = " %s " % conj if len(words) == 2: return "%s%s%s" % (words[0], conj, words[1]) if sep is None: - if ',' in ''.join(words): - sep = ';' + if "," in "".join(words): + sep = ";" else: - sep = ',' + sep = "," if final_sep is None: final_sep = sep final_sep = "%s%s" % (final_sep, conj) if sep_spaced: - sep += ' ' + sep += " " return "%s%s%s" % (sep.join(words[0:-1]), final_sep, words[-1]) diff --git a/Code/irc/int2word.py b/Code/irc/int2word.py index eaf5dba..8c2e532 100644 --- a/Code/irc/int2word.py +++ b/Code/irc/int2word.py @@ -19,25 +19,25 @@ def int2word(n): if q < -2: break else: - if q >= 0: + if q >= 0: n3.append(int(r[:3])) elif q >= -1: n3.append(int(r[:2])) elif q >= -2: n3.append(int(r[:1])) r1 = r - - #print n3 # test - + + # print n3 # test + # break each group of 3 digits into # ones, tens/twenties, hundreds # and form a string nw = "" for i, x in enumerate(n3): b1 = x % 10 - b2 = (x % 100)//10 - b3 = (x % 1000)//100 - #print b1, b2, b3 # test + b2 = (x % 100) // 10 + b3 = (x % 1000) // 100 + # print b1, b2, b3 # test if x == 0: continue # skip else: @@ -51,15 +51,65 @@ def int2word(n): if b3 > 0: nw = ones[b3] + "hundred " + nw return nw + + ############# globals ################ -ones = ["", "one ","two ","three ","four ", "five ", - "six ","seven ","eight ","nine "] -tens = ["ten ","eleven ","twelve ","thirteen ", "fourteen ", - "fifteen ","sixteen ","seventeen ","eighteen ","nineteen "] -twenties = ["","","twenty ","thirty ","forty ", - "fifty ","sixty ","seventy ","eighty ","ninety "] -thousands = ["","thousand ","million ", "billion ", "trillion ", - "quadrillion ", "quintillion ", "sextillion ", "septillion ","octillion ", - "nonillion ", "decillion ", "undecillion ", "duodecillion ", "tredecillion ", - "quattuordecillion ", "sexdecillion ", "septendecillion ", "octodecillion ", - "novemdecillion ", "vigintillion "] +ones = [ + "", + "one ", + "two ", + "three ", + "four ", + "five ", + "six ", + "seven ", + "eight ", + "nine ", +] +tens = [ + "ten ", + "eleven ", + "twelve ", + "thirteen ", + "fourteen ", + "fifteen ", + "sixteen ", + "seventeen ", + "eighteen ", + "nineteen ", +] +twenties = [ + "", + "", + "twenty ", + "thirty ", + "forty ", + "fifty ", + "sixty ", + "seventy ", + "eighty ", + "ninety ", +] +thousands = [ + "", + "thousand ", + "million ", + "billion ", + "trillion ", + "quadrillion ", + "quintillion ", + "sextillion ", + "septillion ", + "octillion ", + "nonillion ", + "decillion ", + "undecillion ", + "duodecillion ", + "tredecillion ", + "quattuordecillion ", + "sexdecillion ", + "septendecillion ", + "octodecillion ", + "novemdecillion ", + "vigintillion ", +] diff --git a/Code/irc/madlibbot/madlib.py b/Code/irc/madlibbot/madlib.py index cbcc512..63ffefb 100755 --- a/Code/irc/madlibbot/madlib.py +++ b/Code/irc/madlibbot/madlib.py @@ -8,15 +8,20 @@ import re p = inflect.engine() file_pattern = "/home/*/madlibs/*.madlib" -file_regex = re.compile(r'^/home/(.*?)/.*/([^/]*)\.madlib$') -word_regex = re.compile(r'{{(.*?)(#.*?)?(\|.*)?}}') -word_replace_regex = re.compile(r'^(.*)#(\d*)$') +file_regex = re.compile(r"^/home/(.*?)/.*/([^/]*)\.madlib$") +word_regex = re.compile(r"{{(.*?)(#.*?)?(\|.*)?}}") +word_replace_regex = re.compile(r"^(.*)#(\d*)$") # Take a file path and return a tuple with the title and original path def munge_story(file_name): match = re.match(file_regex, file_name) count = count_words_file(file_name) - return ("'" + match.group(2).replace('_', ' ') + "' by ~" + match.group(1), match.group(0), count) + return ( + "'" + match.group(2).replace("_", " ") + "' by ~" + match.group(1), + match.group(0), + count, + ) + # Retrive a list of all madlib story files def find_stories(limit=999, shuffle=False): @@ -27,25 +32,28 @@ def find_stories(limit=999, shuffle=False): files = files[:limit] return map(munge_story, files) + # Count the number of replacable words in the story def count_words(story): # words that have a '#' part and match should only be counted once count = 0 repeats = [] for match in re.finditer(word_regex, story): - if match.group(2) is None: #the '#' part + if match.group(2) is None: # the '#' part count += 1 elif match.group(1) + match.group(2) not in repeats: count += 1 repeats.append(match.group(1) + match.group(2)) return count + # Count the number of replacable words in the story when given a file path def count_words_file(storyPath): with open(storyPath, "r") as storyFile: story = storyFile.read() return count_words(story) + # Get the next replaceable word in the story. Includes full token and just the word # If you specify rand as True, it will get a random word instead of the next one def find_next_word(story, rand=False): @@ -58,19 +66,27 @@ def find_next_word(story, rand=False): return (match.group(0), match.group(1)) + # Using a query phrase, replace a word and return the entire story body def replace_word(story, query, word): rquery = word_regex.search(query) # '{{foo#bar|baz|bang}}' => ('foo', '#bar', '|baz|bang') - pipes = [p.lower() for p in (rquery.group(3) if rquery.group(3) is not None else '').strip('|').split('|')] + pipes = [ + p.lower() + for p in (rquery.group(3) if rquery.group(3) is not None else "") + .strip("|") + .split("|") + ] munged_word = process_pipes(word, pipes) story = story.replace(query, munged_word, 1) - if rquery.group(2) is not None: #if there is a '#' part we replace all instances - print "Looking for {{" + rquery.group(1) + rquery.group(2) + ".*?}}" - others = re.findall(r'{{' + rquery.group(1) + rquery.group(2) + '.*?}}', story) + if rquery.group(2) is not None: # if there is a '#' part we replace all instances + print("Looking for {{" + rquery.group(1) + rquery.group(2) + ".*?}}") + others = re.findall(r"{{" + rquery.group(1) + rquery.group(2) + ".*?}}", story) if len(others) > 0: - story = replace_word(story, others[0], word) #iteratively replace the next instance + story = replace_word( + story, others[0], word + ) # iteratively replace the next instance return story @@ -80,17 +96,18 @@ def process_pipes(word, pipes): for pipe in pipes: try: word = { - 'upper': lambda word: word.upper(), - 'lower': lambda word: word.lower(), - 'title': lambda word: word.title(), - 'numeric': lambda word: p.number_to_words(word), - 'ordinal': lambda word: p.ordinal(word), - collections.defaultdict: lambda word: word - }[pipe](word) + "upper": lambda word: word.upper(), + "lower": lambda word: word.lower(), + "title": lambda word: word.title(), + "numeric": lambda word: p.number_to_words(word), + "ordinal": lambda word: p.ordinal(word), + collections.defaultdict: lambda word: word, + }[pipe](word) except Exception: - pass # just keep going if an error occurs processing a pipe + pass # just keep going if an error occurs processing a pipe return word + # A helper function that will split the story up into chat-printable lengths def yield_lines(line, max_size): words = [] @@ -101,17 +118,18 @@ def yield_lines(line, max_size): while len(word) > max_size: splitsize = max_size - words_length - 1 words.append(word[:splitsize] + "-") - yield ' '.join(words) + yield " ".join(words) words = [] words_length = 0 word = word[splitsize:] if words_length + len(word) + 1 > max_size: - yield ' '.join(words) + yield " ".join(words) words = [] words_length = 0 words.append(word) - words_length += len(word) + 1 # For the space - yield ' '.join(words) # For any words left over + words_length += len(word) + 1 # For the space + yield " ".join(words) # For any words left over + # Open a story file and ask for the parts def make_story(storyFile): @@ -119,23 +137,24 @@ def make_story(storyFile): story = storyFile.read() match = word_regex.search(story) while match is not None: - word = raw_input('Give me {}: '.format(match.group(1))) - print "Replacing '{}' with '{}'".format(match.group(0), word) - print story + word = raw_input("Give me {}: ".format(match.group(1))) + print("Replacing '{}' with '{}'".format(match.group(0), word)) + print(story) story = re.sub(match.group(0), word, story, 1) match = word_regex.search(story) - print story + print(story) + def start(): stories = find_stories(20, True) if len(stories) == 0: - print "Sorry, no stories found. :/" + print("Sorry, no stories found. :/") return input = -1 while input < 0 or input >= len(stories): for idx, story in enumerate(stories): - print "[{}] {}".format(idx, story[0]) + print("[{}] {}".format(idx, story[0])) input = raw_input("Which story would you like?: ") try: # Try to convert the string input into a number @@ -147,5 +166,6 @@ def start(): # Call make_story with the file path of the selected story make_story(stories[input][1]) + if __name__ == "__main__": start() diff --git a/Code/irc/madlibbot/madlibbot.py b/Code/irc/madlibbot/madlibbot.py index c7b02ac..5f6934e 100755 --- a/Code/irc/madlibbot/madlibbot.py +++ b/Code/irc/madlibbot/madlibbot.py @@ -15,33 +15,56 @@ import operator from .. import util import madlib + class State: - idle = 0 # When the bot is started and after it has finished a story - thinking = 1 # I intentionally speed throttle this bot so it feels a little more natural - story_selection = 2 # When the bot is waiting for a user input for story selection - word_input = 3 # When the bot is waiting for user input after prompted for a word + idle = 0 # When the bot is started and after it has finished a story + thinking = ( + 1 + ) # I intentionally speed throttle this bot so it feels a little more natural + story_selection = 2 # When the bot is waiting for a user input for story selection + word_input = 3 # When the bot is waiting for user input after prompted for a word + # Globals -MAX_LINE = 80 # The maximum number of characters in a line -MAX_STORIES = 5 # The maximum number of stories a user can pick from -THROTTLE_FACTOR = 1 # A factor by which all sleep event durations will be multiplied +MAX_LINE = 80 # The maximum number of characters in a line +MAX_STORIES = 5 # The maximum number of stories a user can pick from +THROTTLE_FACTOR = 1 # A factor by which all sleep event durations will be multiplied # Allow madlbibbot to run multiple simultaneous stories -state = {} # The current state of the bot -stories = {} # The list of stories available to users -story = {} # The madlib story currently being worked on -nextword = {} # The word that the bot is currently expecting data for +state = {} # The current state of the bot +stories = {} # The list of stories available to users +story = {} # The madlib story currently being worked on +nextword = {} # The word that the bot is currently expecting data for parser = OptionParser() -parser.add_option("-s", "--server", dest="server", default='127.0.0.1', - help="the server to connect to", metavar="SERVER") -parser.add_option("-c", "--channel", dest="channel", default='#madlibs', - help="the channel to join", metavar="CHANNEL") -parser.add_option("-n", "--nick", dest="nick", default='madlibbot', - help="the nick to use", metavar="NICK") +parser.add_option( + "-s", + "--server", + dest="server", + default="127.0.0.1", + help="the server to connect to", + metavar="SERVER", +) +parser.add_option( + "-c", + "--channel", + dest="channel", + default="#madlibs", + help="the channel to join", + metavar="CHANNEL", +) +parser.add_option( + "-n", + "--nick", + dest="nick", + default="madlibbot", + help="the nick to use", + metavar="NICK", +) (options, args) = parser.parse_args() + def resetGlobals(channel=""): global state global stories @@ -59,6 +82,7 @@ def resetGlobals(channel=""): story[channel] = "" nextword[channel] = {} + def get_stories(channel, botnick): global state global stories @@ -73,9 +97,13 @@ def get_stories(channel, botnick): for idx, story in enumerate(stories[channel]): sendmsg(channel, "[{}] {} ({} words)".format(idx, story[0], story[2])) time.sleep(0.5 * THROTTLE_FACTOR) - sendmsg(channel, "Please select a story by index by saying '{}: ':".format(botnick)) + sendmsg( + channel, + "Please select a story by index by saying '{}: ':".format(botnick), + ) state[channel] = State.story_selection + # Handle user input when the bot is directly addressed def handle_bot_msg(channel, msg, botnick): global state @@ -100,11 +128,13 @@ def handle_bot_msg(channel, msg, botnick): else: state[channel] = State.idle + # Handle how to quit the game def quit_game(channel): resetGlobals(channel) sendmsg(channel, "Ok, quitting the current game.") + # Handle user input when we are in story selection mode def handle_story_selection(channel, msg, botnick): global stories @@ -115,16 +145,19 @@ def handle_story_selection(channel, msg, botnick): sendmsg(channel, "Selection out of bounds. Try again!") return time.sleep(1 * THROTTLE_FACTOR) - sendmsg(channel, "Give me a second to load up {}".format(stories[channel][imsg][0])) + sendmsg( + channel, "Give me a second to load up {}".format(stories[channel][imsg][0]) + ) with open(stories[channel][imsg][1], "r") as storyFile: story[channel] = storyFile.read() - stories[channel] = {} # Clear out the saved selectable stories in memory + stories[channel] = {} # Clear out the saved selectable stories in memory story_start(channel, botnick) except ValueError: sendmsg(channel, "Invalid selection. Try again!") state[channel] = State.story_selection + # Handle when a story is being started def story_start(channel, botnick): global story @@ -132,12 +165,18 @@ def story_start(channel, botnick): global nextword state[channel] = State.thinking - sendmsg(channel, "Alright! Let's get started! Say '{}: ' to give me words.".format(botnick)) + sendmsg( + channel, + "Alright! Let's get started! Say '{}: ' to give me words.".format( + botnick + ), + ) nextword[channel] = madlib.find_next_word(story[channel], True) time.sleep(0.5 * THROTTLE_FACTOR) sendmsg(channel, "Give me {}:".format(nextword[channel][1])) state[channel] = State.word_input + # Handle user input when we have asked the user for input and are expecting a # response def handle_story_step(channel, msg): @@ -146,7 +185,7 @@ def handle_story_step(channel, msg): global nextword state[channel] = State.thinking - word = nextword[channel] #madlib.find_next_word(story[channel]) + word = nextword[channel] # madlib.find_next_word(story[channel]) if word is not None: story[channel] = madlib.replace_word(story[channel], nextword[channel][0], msg) time.sleep(1 * THROTTLE_FACTOR) @@ -155,62 +194,86 @@ def handle_story_step(channel, msg): if nextword[channel] is None: finish_story(channel) return - #else + # else count = madlib.count_words(story[channel]) - sendmsg(channel, "Thanks! Now give me {} ({} words left)".format(nextword[channel][1], count)) + sendmsg( + channel, + "Thanks! Now give me {} ({} words left)".format(nextword[channel][1], count), + ) state[channel] = State.word_input + # Finish the story def finish_story(channel): global state global story - sendmsg(channel, "Ok, here's the story..."); - sendmsg(channel, '=' * MAX_LINE) + sendmsg(channel, "Ok, here's the story...") + sendmsg(channel, "=" * MAX_LINE) for line in story[channel].splitlines(): for part in madlib.yield_lines(line, MAX_LINE): time.sleep(0.6 * THROTTLE_FACTOR) sendmsg(channel, part) - padlen = (MAX_LINE - 9)/2 + padlen = (MAX_LINE - 9) / 2 mod = (MAX_LINE - 9) % 2 - sendmsg(channel, '=' * padlen + ' THE END ' + '=' * (padlen + mod)) + sendmsg(channel, "=" * padlen + " THE END " + "=" * (padlen + mod)) story[channel] = "" state[channel] = State.idle + # System things def ping(pong): ircsock.send("PONG {}\n".format(pong)) -def sendmsg(chan , msg): + +def sendmsg(chan, msg): ircsock.send("PRIVMSG {} :{}\n".format(chan, msg)) + def joinchan(chan): global state state[chan] = State.idle ircsock.send("JOIN {}\n".format(chan)) + def rollcall(channel, botnick): global state if channel not in state: state[channel] = State.idle if state[channel] == State.idle: - sendmsg(channel, "Do you like MadLibs? Start a collaborative story by saying '{}: startgame'".format(botnick)) + sendmsg( + channel, + "Do you like MadLibs? Start a collaborative story by saying '{}: startgame'".format( + botnick + ), + ) else: - sendmsg(channel, "A game is already in progress. Say '{}: ' to provide me with the next word or '{}: !quit' to stop the current game".format(botnick, botnick)) + sendmsg( + channel, + "A game is already in progress. Say '{}: ' to provide me with the next word or '{}: !quit' to stop the current game".format( + botnick, botnick + ), + ) + def connect(server, channel, botnick): ircsock.connect((server, 6667)) - ircsock.send("USER {} {} {} :krowbar\n".format(botnick, botnick, botnick)) # user authentication + ircsock.send( + "USER {} {} {} :krowbar\n".format(botnick, botnick, botnick) + ) # user authentication ircsock.send("NICK {}\n".format(botnick)) joinchan(channel) + def listen(botnick): - botmsgre = re.compile('^{}\:?\s*(.*)$'.format(botnick)) # re to strip the bot's name from a message + botmsgre = re.compile( + "^{}\:?\s*(.*)$".format(botnick) + ) # re to strip the bot's name from a message while 1: ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip('\n\r') + ircmsg = ircmsg.strip("\n\r") if ircmsg[:4] == "PING": ping(ircmsg.split(" ")[1]) @@ -227,7 +290,10 @@ def listen(botnick): channel = split[3] message = split[4] - if message.startswith("!rollcall") == True or message.startswith("!help") == True: + if ( + message.startswith("!rollcall") == True + or message.startswith("!help") == True + ): rollcall(channel, botnick) elif message.startswith(botnick) == True: botmsg = botmsgre.match(message).group(1) @@ -236,6 +302,7 @@ def listen(botnick): sys.stdout.flush() time.sleep(1 * THROTTLE_FACTOR) + ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect(options.server, options.channel, options.nick) listen(options.nick) diff --git a/Code/irc/madlibbot/msgformatter.py b/Code/irc/madlibbot/msgformatter.py deleted file mode 100644 index d438aca..0000000 --- a/Code/irc/madlibbot/msgformatter.py +++ /dev/null @@ -1,16 +0,0 @@ -import time -import re - -def format_message(message): - pattern = r'^:.*\!~(.*)@.* (.*) (.*) :(.*)' - now = int(time.time()) - matches = re.match(pattern, message) - if not matches: - return '' - - nick = matches.group(1).strip() - command = matches.group(2).strip() - channel = matches.group(3).strip() - message = matches.group(4).strip() - - return "%s\t%s\t%s\t%s\t%s" % (now, nick, command, channel, message) diff --git a/Code/irc/names.py b/Code/irc/names.py index bb4a109..89be86a 100644 --- a/Code/irc/names.py +++ b/Code/irc/names.py @@ -1,7 +1,8 @@ #!/usr/bin/python import json -names_file='/home/jumblesale/Code/canonical_names/canonical_names.json' +names_file = "/home/jumblesale/Code/canonical_names/canonical_names.json" + def get_name(name): try: @@ -12,4 +13,4 @@ def get_name(name): except KeyError: return name except IOError: - return name # if we didn't already + return name # if we didn't already diff --git a/Code/irc/pretty_date.py b/Code/irc/pretty_date.py index d8f670e..80a8966 100644 --- a/Code/irc/pretty_date.py +++ b/Code/irc/pretty_date.py @@ -1,42 +1,43 @@ def pretty_date(time=False): - """ + """ Get a datetime object or a int() Epoch timestamp and return a pretty string like 'an hour ago', 'Yesterday', '3 months ago', 'just now', etc """ - from datetime import datetime - now = datetime.now() - if type(time) is int: - diff = now - datetime.fromtimestamp(time) - elif isinstance(time,datetime): - diff = now - time - elif not time: - diff = now - now - second_diff = diff.seconds - day_diff = diff.days + from datetime import datetime - if day_diff < 0: - return '' + now = datetime.now() + if type(time) is int: + diff = now - datetime.fromtimestamp(time) + elif isinstance(time, datetime): + diff = now - time + elif not time: + diff = now - now + second_diff = diff.seconds + day_diff = diff.days - if day_diff == 0: - if second_diff < 10: - return "just now" - if second_diff < 60: - return str(second_diff) + " seconds ago" - if second_diff < 120: - return "a minute ago" - if second_diff < 3600: - return str(second_diff / 60) + " minutes ago" - if second_diff < 7200: - return "an hour ago" - if second_diff < 86400: - return str(second_diff / 3600) + " hours ago" - if day_diff == 1: - return "Yesterday" - if day_diff < 7: - return str(day_diff) + " days ago" - if day_diff < 31: - return str(day_diff / 7) + " weeks ago" - if day_diff < 365: - return str(day_diff / 30) + " months ago" - return str(day_diff / 365) + " years ago" + if day_diff < 0: + return "" + + if day_diff == 0: + if second_diff < 10: + return "just now" + if second_diff < 60: + return str(second_diff) + " seconds ago" + if second_diff < 120: + return "a minute ago" + if second_diff < 3600: + return str(second_diff / 60) + " minutes ago" + if second_diff < 7200: + return "an hour ago" + if second_diff < 86400: + return str(second_diff / 3600) + " hours ago" + if day_diff == 1: + return "Yesterday" + if day_diff < 7: + return str(day_diff) + " days ago" + if day_diff < 31: + return str(day_diff / 7) + " weeks ago" + if day_diff < 365: + return str(day_diff / 30) + " months ago" + return str(day_diff / 365) + " years ago" diff --git a/Code/irc/puzzle.py b/Code/irc/puzzle.py index 98ae47c..e58deed 100644 --- a/Code/irc/puzzle.py +++ b/Code/irc/puzzle.py @@ -8,85 +8,176 @@ p = inflect.engine() primes = [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71] fuzz_amount = 3 + def make_puzzle(obfuscate=True): - answer = 0 - bonus = 0 - puzzle = random.choice(["Prove you're not a robot: ", "Are you a robot?: ", "Anti-bot check: ", "Counter-cnd0rphant measures: ", "Cosn0k countermeasures: ", "Anti-tilde7hief precautions: "]) - puzzle += random.choice(["What is", "How many is", "What do you get from", "What do you get with", "What is the value of", "Can you answer", "Can you tell me"]) - puzzle += " " - roll = random.randrange(0,18) - var1 = random.randrange(1,10) - var2 = random.randrange(1,10) - var3 = random.randrange(1,20) - var4 = random.randrange(1,20) - let1_ord = random.randrange(ord('a'), ord('z')+1) + answer = 0 + bonus = 0 + puzzle = random.choice( + [ + "Prove you're not a robot: ", + "Are you a robot?: ", + "Anti-bot check: ", + "Counter-cnd0rphant measures: ", + "Cosn0k countermeasures: ", + "Anti-tilde7hief precautions: ", + ] + ) + puzzle += random.choice( + [ + "What is", + "How many is", + "What do you get from", + "What do you get with", + "What is the value of", + "Can you answer", + "Can you tell me", + ] + ) + puzzle += " " + roll = random.randrange(0, 18) + var1 = random.randrange(1, 10) + var2 = random.randrange(1, 10) + var3 = random.randrange(1, 20) + var4 = random.randrange(1, 20) + let1_ord = random.randrange(ord("a"), ord("z") + 1) - if roll == 0: - answer = var1 + var2 - puzzle += p.number_to_words(var1) + " " + random.choice(["and", "plus", "sum", "add"]) + " " + p.number_to_words(var2) + if roll == 0: + answer = var1 + var2 + puzzle += ( + p.number_to_words(var1) + + " " + + random.choice(["and", "plus", "sum", "add"]) + + " " + + p.number_to_words(var2) + ) - elif roll == 1: - answer = var1 * var2 - puzzle += p.number_to_words(var1) + " " + random.choice(["times", "multiply", "multiplied by", "product"]) + " " + p.number_to_words(var2) - elif roll == 2: - if var2 > var1: - var1,var2 = var2,var1 - answer = var1 - var2 - puzzle += p.number_to_words(var1) + " " + random.choice(["minus", "subtract", "take away", "less"]) + " " + p.number_to_words(var2) - elif roll == 3: - if var2 > var1: - var1,var2 = var2,var1 - answer = var1 * 2 / var2 - puzzle += p.number_to_words(var1*2) + " " + random.choice(["divided by", "over"]) + " " + p.number_to_words(var2) + " (no remainder)" - elif roll == 4: - answer = var1 ** var2 - puzzle += p.number_to_words(var1) + " to the " + p.ordinal(p.number_to_words(var2)) + " power" - elif roll == 5: - p1 = random.choice(primes) - p2 = random.choice(primes) - def answer(guess): - # Check the the numbers entered are correct, regardless of order - # or surrounding whitespace. - attempt = sorted(word.strip() for word in guess.split(",")) - correct = sorted([str(p1), str(p2)]) - return attempt == correct - bonus = 1 - puzzle += p.number_to_words(p1 * p2) + " when factored into its two primes (answer in the form of the two primes with a comma between)" - elif roll == 6: - prime = random.choice(primes) - answer = prime % var1 - puzzle += p.number_to_words(prime) + " modulus " + p.number_to_words(var1) - elif roll == 7: - if let1_ord + var1 > ord('z'): - let1_ord -= var1 - answer = chr(let1_ord + var1) - puzzle = "What letter comes " + p.number_to_words(var1) + " letters after '" + chr(let1_ord) + "'" - obfuscate = False - elif roll == 8: - if let1_ord - var1 < ord('a'): - let1_ord += var1 - answer = chr(let1_ord - var1) - puzzle = "What letter comes " + p.number_to_words(var1) + " letters before '" + chr(let1_ord) + "'" - obfuscate = False - elif roll == 9: - answer, puzzle = quote_puzzle.get_quote() - obfuscate = False - elif roll == 10: - answer = str(min(var1, var2, var3, var4)) - puzzle = "What is the " + random.choice(["smallest", "lowest"]) + " of " + p.number_to_words(var1) + ", " + p.number_to_words(var2) + ", " + p.number_to_words(var3) + ", and " + p.number_to_words(var4) - elif roll == 11: - answer = str(max(var1, var2, var3, var4)) - puzzle = "What is the " + random.choice(["biggest", "largest"]) + " of " + p.number_to_words(var1) + ", " + p.number_to_words(var2) + ", " + p.number_to_words(var3) + ", and " + p.number_to_words(var4) - elif roll <= 14: #12-14 - answer, puzzle = dict_puzzle.get_puzzle() - obfuscate = False - elif roll <= 17: #15-17 - answer, puzzle = dict_puzzle.get_anagram() - obfuscate = False + elif roll == 1: + answer = var1 * var2 + puzzle += ( + p.number_to_words(var1) + + " " + + random.choice(["times", "multiply", "multiplied by", "product"]) + + " " + + p.number_to_words(var2) + ) + elif roll == 2: + if var2 > var1: + var1, var2 = var2, var1 + answer = var1 - var2 + puzzle += ( + p.number_to_words(var1) + + " " + + random.choice(["minus", "subtract", "take away", "less"]) + + " " + + p.number_to_words(var2) + ) + elif roll == 3: + if var2 > var1: + var1, var2 = var2, var1 + answer = var1 * 2 / var2 + puzzle += ( + p.number_to_words(var1 * 2) + + " " + + random.choice(["divided by", "over"]) + + " " + + p.number_to_words(var2) + + " (no remainder)" + ) + elif roll == 4: + answer = var1 ** var2 + puzzle += ( + p.number_to_words(var1) + + " to the " + + p.ordinal(p.number_to_words(var2)) + + " power" + ) + elif roll == 5: + p1 = random.choice(primes) + p2 = random.choice(primes) - puzzle += "?" - if obfuscate == True: - for _ in range(fuzz_amount): - idx = random.randrange(len(puzzle)-1) #get between 0 and string length - puzzle = ''.join([puzzle[0:idx], chr(random.randint(33,126)), puzzle[idx+1:]]) - return [puzzle, answer, bonus] + def answer(guess): + # Check the the numbers entered are correct, regardless of order + # or surrounding whitespace. + attempt = sorted(word.strip() for word in guess.split(",")) + correct = sorted([str(p1), str(p2)]) + return attempt == correct + + bonus = 1 + puzzle += ( + p.number_to_words(p1 * p2) + + " when factored into its two primes (answer in the form of the two primes with a comma between)" + ) + elif roll == 6: + prime = random.choice(primes) + answer = prime % var1 + puzzle += p.number_to_words(prime) + " modulus " + p.number_to_words(var1) + elif roll == 7: + if let1_ord + var1 > ord("z"): + let1_ord -= var1 + answer = chr(let1_ord + var1) + puzzle = ( + "What letter comes " + + p.number_to_words(var1) + + " letters after '" + + chr(let1_ord) + + "'" + ) + obfuscate = False + elif roll == 8: + if let1_ord - var1 < ord("a"): + let1_ord += var1 + answer = chr(let1_ord - var1) + puzzle = ( + "What letter comes " + + p.number_to_words(var1) + + " letters before '" + + chr(let1_ord) + + "'" + ) + obfuscate = False + elif roll == 9: + answer, puzzle = quote_puzzle.get_quote() + obfuscate = False + elif roll == 10: + answer = str(min(var1, var2, var3, var4)) + puzzle = ( + "What is the " + + random.choice(["smallest", "lowest"]) + + " of " + + p.number_to_words(var1) + + ", " + + p.number_to_words(var2) + + ", " + + p.number_to_words(var3) + + ", and " + + p.number_to_words(var4) + ) + elif roll == 11: + answer = str(max(var1, var2, var3, var4)) + puzzle = ( + "What is the " + + random.choice(["biggest", "largest"]) + + " of " + + p.number_to_words(var1) + + ", " + + p.number_to_words(var2) + + ", " + + p.number_to_words(var3) + + ", and " + + p.number_to_words(var4) + ) + elif roll <= 14: # 12-14 + answer, puzzle = dict_puzzle.get_puzzle() + obfuscate = False + elif roll <= 17: # 15-17 + answer, puzzle = dict_puzzle.get_anagram() + obfuscate = False + + puzzle += "?" + if obfuscate == True: + for _ in range(fuzz_amount): + idx = random.randrange(len(puzzle) - 1) # get between 0 and string length + puzzle = "".join( + [puzzle[0:idx], chr(random.randint(33, 126)), puzzle[idx + 1 :]] + ) + return [puzzle, answer, bonus] diff --git a/Code/irc/quote_bot.py b/Code/irc/quote_bot.py index 8dec7cc..f17f8f5 100755 --- a/Code/irc/quote_bot.py +++ b/Code/irc/quote_bot.py @@ -13,106 +13,149 @@ import formatter parser = OptionParser() -parser.add_option("-s", "--server", dest="server", default='127.0.0.1', - help="the server to connect to", metavar="SERVER") -parser.add_option("-c", "--channel", dest="channel", default='#tildetown', - help="the channel to join", metavar="CHANNEL") -parser.add_option("-n", "--nick", dest="nick", default='quote_bot', - help="the nick to use", metavar="NICK") +parser.add_option( + "-s", + "--server", + dest="server", + default="127.0.0.1", + help="the server to connect to", + metavar="SERVER", +) +parser.add_option( + "-c", + "--channel", + dest="channel", + default="#tildetown", + help="the channel to join", + metavar="CHANNEL", +) +parser.add_option( + "-n", + "--nick", + dest="nick", + default="quote_bot", + help="the nick to use", + metavar="NICK", +) (options, args) = parser.parse_args() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) -def sendmsg(chan , msg): - ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n") +def ping(pong): + ircsock.send("PONG {}\n".format(pong)) + + +def sendmsg(chan, msg): + ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") + def joinchan(chan): - ircsock.send("JOIN "+ chan +"\n") + ircsock.send("JOIN " + chan + "\n") + def hello(): - ircsock.send("PRIVMSG "+ channel +" :Hello!\n") + ircsock.send("PRIVMSG " + channel + " :Hello!\n") + def random_quote(channel): - quote = os.popen("/home/frs/quotes/randquote.py").read() - if len(quote) >= 256: - quote = quote[:253] + '...' - ircsock.send("PRIVMSG "+ channel +" :" + quote + "\n") + quote = os.popen("/home/frs/quotes/randquote.py").read() + if len(quote) >= 256: + quote = quote[:253] + "..." + ircsock.send("PRIVMSG " + channel + " :" + quote + "\n") + def haiku(channel): - h = os.popen("haiku").read().replace("\n", " // ") - ircsock.send("PRIVMSG "+ channel +" :" + h + "\n") + h = os.popen("haiku").read().replace("\n", " // ") + ircsock.send("PRIVMSG " + channel + " :" + h + "\n") + def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :This bot is a result of a tutoral covered on http://shellium.org/wiki.\n") # user authentication - ircsock.send("NICK "+ botnick +"\n") + ircsock.connect((server, 6667)) + ircsock.send( + "USER " + + botnick + + " " + + botnick + + " " + + botnick + + " :This bot is a result of a tutoral covered on http://shellium.org/wiki.\n" + ) # user authentication + ircsock.send("NICK " + botnick + "\n") + + joinchan(channel) - joinchan(channel) def get_user_from_message(msg): - try: - i1 = msg.index(':') + 1 - i2 = msg.index('!') - return msg[i1:i2] - except ValueError: - return "" + try: + i1 = msg.index(":") + 1 + i2 = msg.index("!") + return msg[i1:i2] + except ValueError: + return "" + def say_mentions(user, message): - nick = get_user_from_message(message) - menschns = os.popen("/home/karlen/bin/mensch -u %s -t 24 -z +0" % (user)).read().replace("\t", ": ").split("\n") - for mention in menschns: - if not "" == mention: - toSend = "PRIVMSG "+ nick + " :" + mention + "\n" - if len(toSend) >= 256: - toSend = toSend[:253] + '...' - ircsock.send(toSend) + nick = get_user_from_message(message) + menschns = ( + os.popen("/home/karlen/bin/mensch -u %s -t 24 -z +0" % (user)) + .read() + .replace("\t", ": ") + .split("\n") + ) + for mention in menschns: + if not "" == mention: + toSend = "PRIVMSG " + nick + " :" + mention + "\n" + if len(toSend) >= 256: + toSend = toSend[:253] + "..." + ircsock.send(toSend) + def say_chatty(channel): - chattyOut = os.popen("/home/karlen/bin/chatty").read().split("\n") - for line in chattyOut: - if line: - ircsock.send("PRIVMSG "+ channel + " :" + line + "\n") + chattyOut = os.popen("/home/karlen/bin/chatty").read().split("\n") + for line in chattyOut: + if line: + ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + def listen(): - while 1: + while 1: - ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip('\n\r') + ircmsg = ircsock.recv(2048) + ircmsg = ircmsg.strip("\n\r") - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) - formatted = formatter.format_message(ircmsg) + formatted = formatter.format_message(ircmsg) - if "" == formatted: - continue + if "" == formatted: + continue - print formatted + print(formatted) - split = formatted.split("\t") - time = split[0] - user = split[1] - messageText = split[2] + split = formatted.split("\t") + time = split[0] + user = split[1] + messageText = split[2] - if ircmsg.find(":!quote") != -1: - random_quote(options.channel) + if ircmsg.find(":!quote") != -1: + random_quote(options.channel) - if ircmsg.find(":!mentions") != -1: - say_mentions(user, ircmsg) + if ircmsg.find(":!mentions") != -1: + say_mentions(user, ircmsg) - if ircmsg.find(":!chatty") != -1: - say_chatty(options.channel) + if ircmsg.find(":!chatty") != -1: + say_chatty(options.channel) - if ircmsg.find(":!haiku") != -1: - haiku(options.channel) + if ircmsg.find(":!haiku") != -1: + haiku(options.channel) - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) + + sys.stdout.flush() + time.sleep(1) - sys.stdout.flush() - time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect(options.server, options.channel, options.nick) diff --git a/Code/irc/quote_puzzle.py b/Code/irc/quote_puzzle.py index e3acda2..3a64901 100644 --- a/Code/irc/quote_puzzle.py +++ b/Code/irc/quote_puzzle.py @@ -3,10 +3,11 @@ import re quotefile = "/home/karlen/irc/quotes.txt" + def get_quote(): quotes = open(quotefile, "r").read().split("---") - quote,attr = random.choice(quotes).strip().splitlines() - quote = quote[:200] #get only the first 200 chars - word = random.choice([q for q in quote.split(' ') if len(q) > 1]) + quote, attr = random.choice(quotes).strip().splitlines() + quote = quote[:200] # get only the first 200 chars + word = random.choice([q for q in quote.split(" ") if len(q) > 1]) quote = quote.replace(word, re.sub(r"[a-zA-Z]", "_", word)) - return [word, "Fill in the blank: \"" + quote + "\" " + attr] + return [word, 'Fill in the blank: "' + quote + '" ' + attr] diff --git a/Code/irc/rainbow.py b/Code/irc/rainbow.py index ba0990a..f439bb6 100644 --- a/Code/irc/rainbow.py +++ b/Code/irc/rainbow.py @@ -1,16 +1,17 @@ import random + def makeRainbow(word): word = word or "RAINBOW" output = "" - rb = ["5","7","8","3","12","13","6"] + rb = ["5", "7", "8", "3", "12", "13", "6"] bg = "01" idx = random.randrange(0, len(rb)) for l in word: if l == " ": - output += ' ' + output += " " else: output += "\x03" + rb[idx % len(rb)] + "," + bg + l idx += 1 diff --git a/Code/irc/rhymesWith.py b/Code/irc/rhymesWith.py index fba0d81..6d19ea1 100644 --- a/Code/irc/rhymesWith.py +++ b/Code/irc/rhymesWith.py @@ -1,25 +1,39 @@ import urllib -#from lxml.html import fromstring + +# from lxml.html import fromstring from bs4 import BeautifulSoup import random - + + def getRhymes(word): - words = [] - url = 'http://www.rhymer.com/RhymingDictionaryLast/%s.html' % word - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') - - for t in soup.find_all('table', 'table'): - words.append(random.choice([w for w in t.text.split('\n') if w not in [u'', u'\xa0'] and '-' not in w])) - return words + words = [] + url = "http://www.rhymer.com/RhymingDictionaryLast/%s.html" % word + soup = BeautifulSoup(urllib.urlopen(url).read(), "html.parser") + + for t in soup.find_all("table", "table"): + words.append( + random.choice( + [ + w + for w in t.text.split("\n") + if w not in [u"", u"\xa0"] and "-" not in w + ] + ) + ) + return words + def rhymeZone(word): words = [] - url = 'http://rhymezone.com/r/rhyme.cgi?Word=%s&typeofrhyme=perfect&org1=syl&org2=l&org3=y' % word - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') + url = ( + "http://rhymezone.com/r/rhyme.cgi?Word=%s&typeofrhyme=perfect&org1=syl&org2=l&org3=y" + % word + ) + soup = BeautifulSoup(urllib.urlopen(url).read(), "html.parser") - for t in soup.find_all('a', 'd'): + for t in soup.find_all("a", "d"): w = t.text.rstrip() - if w not in [u'', u'\xa0'] and '?' not in t: - words.append(w.encode('ascii', 'ignore')) + if w not in [u"", u"\xa0"] and "?" not in t: + words.append(w.encode("ascii", "ignore")) random.shuffle(words) return words[0:5] diff --git a/Code/irc/tilde_bot.py b/Code/irc/tilde_bot.py index 046711a..ec6cba4 100755 --- a/Code/irc/tilde_bot.py +++ b/Code/irc/tilde_bot.py @@ -13,76 +13,111 @@ import formatter parser = OptionParser() -parser.add_option("-s", "--server", dest="server", default='127.0.0.1', - help="the server to connect to", metavar="SERVER") -parser.add_option("-c", "--channel", dest="channel", default='#bot_test', - help="the channel to join", metavar="CHANNEL") -parser.add_option("-n", "--nick", dest="nick", default='tilde_bot', - help="the nick to use", metavar="NICK") +parser.add_option( + "-s", + "--server", + dest="server", + default="127.0.0.1", + help="the server to connect to", + metavar="SERVER", +) +parser.add_option( + "-c", + "--channel", + dest="channel", + default="#bot_test", + help="the channel to join", + metavar="CHANNEL", +) +parser.add_option( + "-n", + "--nick", + dest="nick", + default="tilde_bot", + help="the nick to use", + metavar="NICK", +) (options, args) = parser.parse_args() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) -def sendmsg(chan , msg): - ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n") +def ping(pong): + ircsock.send("PONG {}\n".format(pong)) + + +def sendmsg(chan, msg): + ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") + def joinchan(chan): - ircsock.send("JOIN "+ chan +"\n") + ircsock.send("JOIN " + chan + "\n") + def hello(): - ircsock.send("PRIVMSG "+ channel +" :Hello!\n") + ircsock.send("PRIVMSG " + channel + " :Hello!\n") + def tilde(channel, user, time): - #h = os.popen("haiku").read().replace("\n", " // ") - msg = time + ":" + user - print msg - ircsock.send("PRIVMSG "+ channel +" :" + msg + "\n") + # h = os.popen("haiku").read().replace("\n", " // ") + msg = time + ":" + user + print(msg) + ircsock.send("PRIVMSG " + channel + " :" + msg + "\n") + def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :This bot is a result of a tutoral covered on http://shellium.org/wiki.\n") # user authentication - ircsock.send("NICK "+ botnick +"\n") + ircsock.connect((server, 6667)) + ircsock.send( + "USER " + + botnick + + " " + + botnick + + " " + + botnick + + " :This bot is a result of a tutoral covered on http://shellium.org/wiki.\n" + ) # user authentication + ircsock.send("NICK " + botnick + "\n") + + joinchan(channel) - joinchan(channel) def get_user_from_message(msg): - try: - i1 = msg.index(':') + 1 - i2 = msg.index('!') - return msg[i1:i2] - except ValueError: - return "" + try: + i1 = msg.index(":") + 1 + i2 = msg.index("!") + return msg[i1:i2] + except ValueError: + return "" + def listen(): - while 1: + while 1: - ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip('\n\r') + ircmsg = ircsock.recv(2048) + ircmsg = ircmsg.strip("\n\r") - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) - formatted = formatter.format_message(ircmsg) + formatted = formatter.format_message(ircmsg) - if "" == formatted: - continue + if "" == formatted: + continue - print formatted + print(formatted) - split = formatted.split("\t") - time = split[0] - user = split[1] - messageText = split[2] + split = formatted.split("\t") + time = split[0] + user = split[1] + messageText = split[2] - if ircmsg.find(":!tilde") != -1: - tilde(options.channel, user, time) + if ircmsg.find(":!tilde") != -1: + tilde(options.channel, user, time) - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) + + sys.stdout.flush() - sys.stdout.flush() ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect(options.server, options.channel, options.nick) diff --git a/Code/irc/tildebot.py b/Code/irc/tildebot.py index fe10630..1b61938 100755 --- a/Code/irc/tildebot.py +++ b/Code/irc/tildebot.py @@ -21,12 +21,30 @@ import util parser = OptionParser() -parser.add_option("-s", "--server", dest="server", default='127.0.0.1', - help="the server to connect to", metavar="SERVER") -parser.add_option("-c", "--channel", dest="channel", default='#bot_test', - help="the channel to join", metavar="CHANNEL") -parser.add_option("-n", "--nick", dest="nick", default='tildebot', - help="the nick to use", metavar="NICK") +parser.add_option( + "-s", + "--server", + dest="server", + default="127.0.0.1", + help="the server to connect to", + metavar="SERVER", +) +parser.add_option( + "-c", + "--channel", + dest="channel", + default="#bot_test", + help="the channel to join", + metavar="CHANNEL", +) +parser.add_option( + "-n", + "--nick", + dest="nick", + default="tildebot", + help="the nick to use", + metavar="NICK", +) (options, args) = parser.parse_args() @@ -37,57 +55,198 @@ JACKPOT_FILE = "tildejackpot.txt" JACKPOT_MIN = 3 DEBUG = False + def hello(): - util.sendmsg(ircsock, channel, "Hello!") + util.sendmsg(ircsock, channel, "Hello!") + def too_recent(time1, time2): - return int(time1) - int(time2) < 60*60 + return int(time1) - int(time2) < 60 * 60 + def get_positive(): - return random.choice(['Yes', 'Yep', 'Yeppers', 'Correct','You got it', 'Yeah', 'Right on', 'Uh-huh', 'Positive', 'Totally right', 'Close enough', 'That\'s it']) + return random.choice( + [ + "Yes", + "Yep", + "Yeppers", + "Correct", + "You got it", + "Yeah", + "Right on", + "Uh-huh", + "Positive", + "Totally right", + "Close enough", + "That's it", + ] + ) + def get_negative(): - return random.choice(['No', 'Nope', 'Sorry', 'Wrong', 'Nuh-uh', 'Negatory', 'Incorrect', 'Not today', 'Try again', 'Maybe later', 'Probably not', 'Answer hazy', 'Not quite',\ - 'Not even close']) + return random.choice( + [ + "No", + "Nope", + "Sorry", + "Wrong", + "Nuh-uh", + "Negatory", + "Incorrect", + "Not today", + "Try again", + "Maybe later", + "Probably not", + "Answer hazy", + "Not quite", + "Not even close", + ] + ) + def get_superlative(score): if score > 4: - return random.choice(["super cool", "totally rad", "extraordinary", "dynomite", "#topdrawer", "a #TopLad", "the cat's meow", "a tilde town hero", "my favorite person", "incredibly lucky",\ - "unbelievable", "a tilde town hunk", "could bring all the boys to the yard", "worth twice their weight in gold", "the hero we need", "no ordinary townie"]); + return random.choice( + [ + "super cool", + "totally rad", + "extraordinary", + "dynomite", + "#topdrawer", + "a #TopLad", + "the cat's meow", + "a tilde town hero", + "my favorite person", + "incredibly lucky", + "unbelievable", + "a tilde town hunk", + "could bring all the boys to the yard", + "worth twice their weight in gold", + "the hero we need", + "no ordinary townie", + ] + ) elif score > 2: - return random.choice(["really cool", "pretty neat", "rather nice", "a dynamic doggo", "radical", "intense", "pretty lucky", "knows the territory", "has what it takes", "has mad skillz",\ - "going the distance", "a hard worker", "my sunshine", "ready to rumble"]); + return random.choice( + [ + "really cool", + "pretty neat", + "rather nice", + "a dynamic doggo", + "radical", + "intense", + "pretty lucky", + "knows the territory", + "has what it takes", + "has mad skillz", + "going the distance", + "a hard worker", + "my sunshine", + "ready to rumble", + ] + ) else: - return random.choice(["cool", "nice", "acceptible", "good enough", "a promising pupper", "better than a horse", "swell", "a little lucky", "just credible", "my friend", "probably not a robot",\ - "valuable to the team"]); + return random.choice( + [ + "cool", + "nice", + "acceptible", + "good enough", + "a promising pupper", + "better than a horse", + "swell", + "a little lucky", + "just credible", + "my friend", + "probably not a robot", + "valuable to the team", + ] + ) + def get_bad_thing(): - return random.choice(["is a meanie", "mugs me right off", "is worse than a horse", "smells like a ghost", "probably didn't bathe today", "didn't guess hard enough", "isn't lucky",\ - "smells of elderberries", "should reconsider their life choices", "did't believe in the heart of the tilde", "came to the wrong chat channel", "should have stopped while they were ahead",\ - "requires annotations from an authoratative source", "could have been a contender", "spreads vicious rumors", "drank my milkshake", "is probably cheating", "is trying too hard"]); + return random.choice( + [ + "is a meanie", + "mugs me right off", + "is worse than a horse", + "smells like a ghost", + "probably didn't bathe today", + "didn't guess hard enough", + "isn't lucky", + "smells of elderberries", + "should reconsider their life choices", + "did't believe in the heart of the tilde", + "came to the wrong chat channel", + "should have stopped while they were ahead", + "requires annotations from an authoratative source", + "could have been a contender", + "spreads vicious rumors", + "drank my milkshake", + "is probably cheating", + "is trying too hard", + ] + ) + def get_prize(name, isHuman, bonus=0): - prizes = [1] * 8 + [2] * 4 + [3] * 2 + [5] * isHuman #no 5pt prize for non-humans + prizes = [1] * 8 + [2] * 4 + [3] * 2 + [5] * isHuman # no 5pt prize for non-humans prize = random.choice(prizes) + bonus - if(random.randint(1,10) > 6 - 4 * isHuman): #80% of the time it's a normal prize (40% for not humans) - return [prize, name + ": " + (get_positive() if isHuman else get_negative()) + "! You are " + get_superlative(prize) + " and get " + p.number_to_words(prize) + " tildes!"] - else: #20% of the time its a jackpot situation + if ( + random.randint(1, 10) > 6 - 4 * isHuman + ): # 80% of the time it's a normal prize (40% for not humans) + return [ + prize, + name + + ": " + + (get_positive() if isHuman else get_negative()) + + "! You are " + + get_superlative(prize) + + " and get " + + p.number_to_words(prize) + + " tildes!", + ] + else: # 20% of the time its a jackpot situation with open(JACKPOT_FILE, "r+") as jackpotfile: jackpot = int(jackpotfile.readline().strip("\n")) jackpotfile.seek(0) jackpotfile.truncate() - if(random.randint(1,10) > 1 or not isHuman): #90% of the time it's a non-prize. non-humans never win jackpot - new_jackpot = jackpot+max(1,prize) - jackpotfile.write(str(new_jackpot)) #increase the jackpot by the prize size - return [0, name + " " + get_bad_thing() + " and gets no tildes! (Jackpot is now " + str(new_jackpot) + " tildes)"] - else: #hit jackpot! + if ( + random.randint(1, 10) > 1 or not isHuman + ): # 90% of the time it's a non-prize. non-humans never win jackpot + new_jackpot = jackpot + max(1, prize) + jackpotfile.write( + str(new_jackpot) + ) # increase the jackpot by the prize size + return [ + 0, + name + + " " + + get_bad_thing() + + " and gets no tildes! (Jackpot is now " + + str(new_jackpot) + + " tildes)", + ] + else: # hit jackpot! jackpotfile.write(str(JACKPOT_MIN)) - return [jackpot, name + " hit the jackpot and won **" + p.number_to_words(jackpot) + " tildes!**"] + return [ + jackpot, + name + + " hit the jackpot and won **" + + p.number_to_words(jackpot) + + " tildes!**", + ] + def show_jackpot(channel): with open(JACKPOT_FILE, "r") as jackpotfile: jackpot = int(jackpotfile.readline().strip("\n")) - util.sendmsg(ircsock, channel, "The jackpot is currently {} tildes!".format(p.number_to_words(jackpot))) + util.sendmsg( + ircsock, + channel, + "The jackpot is currently {} tildes!".format(p.number_to_words(jackpot)), + ) + def give_tilde(channel, user, name, time, human, bonus=0): found = False @@ -97,117 +256,158 @@ def give_tilde(channel, user, name, time, human, bonus=0): scorefile.truncate() for score in scores: person = score.strip("\n").split("&^%") - if(person[0] == user): + if person[0] == user: found = True - if(too_recent(time, person[2]) and not DEBUG): - util.sendmsg(ircsock, channel, "{} asked for a tilde too recently and {}. Try again later.".format(name, get_bad_thing())) + if too_recent(time, person[2]) and not DEBUG: + util.sendmsg( + ircsock, + channel, + "{} asked for a tilde too recently and {}. Try again later.".format( + name, get_bad_thing() + ), + ) else: prize = get_prize(name, human, bonus) - score = person[0] + "&^%" + str(int(person[1]) + prize[0]) + "&^%" + time + "\n" + score = ( + person[0] + + "&^%" + + str(int(person[1]) + prize[0]) + + "&^%" + + time + + "\n" + ) util.sendmsg(ircsock, channel, prize[1]) scorefile.write(score) - if(not found): + if not found: prize = get_prize(name, True, bonus) - util.sendmsg(ircsock, channel, "Welcome to the tilde game! Here's {} free tilde(s) to start you off.".format(p.number_to_words(prize[0]+1))) - scorefile.write(user + "&^%" + str(prize[0]+1) + "&^%" + time + "\n") + util.sendmsg( + ircsock, + channel, + "Welcome to the tilde game! Here's {} free tilde(s) to start you off.".format( + p.number_to_words(prize[0] + 1) + ), + ) + scorefile.write(user + "&^%" + str(prize[0] + 1) + "&^%" + time + "\n") + def show_tildescore(channel, user, name): with open(SCORE_FILE, "r") as scorefile: - for idx,score in enumerate(scorefile): + for idx, score in enumerate(scorefile): person = score.strip("\n").split("&^%") - if(person[0] == user): - util.sendmsg(ircsock, channel, "{} has {} tildes!".format(name, p.number_to_words(person[1]))) + if person[0] == user: + util.sendmsg( + ircsock, + channel, + "{} has {} tildes!".format(name, p.number_to_words(person[1])), + ) return - #person has not played yet + # person has not played yet util.sendmsg(ircsock, channel, "{} has no tildes yet!".format(name)) + def challenge(channel, user, name, time): - if(channel != "#bots" and not DEBUG): - util.sendmsg(ircsock, channel, "{} is a meanie and gets no tildes. **Tildebot now only gives out tildes in the #bots channel.**".format(name)) + if channel != "#bots" and not DEBUG: + util.sendmsg( + ircsock, + channel, + "{} is a meanie and gets no tildes. **Tildebot now only gives out tildes in the #bots channel.**".format( + name + ), + ) return - global challenges; - challenge = puzzle.make_puzzle(); - challenges[user] = challenge[1:]; #challenges[USER] = [ANSWER, BONUS] + global challenges + challenge = puzzle.make_puzzle() + challenges[user] = challenge[1:] + # challenges[USER] = [ANSWER, BONUS] util.sendmsg(ircsock, channel, "{}: {}".format(name, challenge[1])) + def challenge_response(channel, user, name, time, msg): global challenges - print(msg); - if(challenges.has_key(user)): + print(msg) + if challenges.has_key(user): answer, bonus = challenges[user] - if((callable(answer) and answer(msg.lower())) or (msg.lower() == str(answer).lower() or msg == p.number_to_words(answer))): - give_tilde(channel, user, name, time, True, bonus); + if (callable(answer) and answer(msg.lower())) or ( + msg.lower() == str(answer).lower() or msg == p.number_to_words(answer) + ): + give_tilde(channel, user, name, time, True, bonus) else: - give_tilde(channel, user, name, time, False, 0); - del challenges[user]; #delete the user from challenges either way - + give_tilde(channel, user, name, time, False, 0) + del challenges[user] + # delete the user from challenges either way def rollcall(channel): - util.sendmsg(ircsock, channel, "tildebot reporting! I respond to !tilde !tildescore") + util.sendmsg( + ircsock, channel, "tildebot reporting! I respond to !tilde !tildescore" + ) + def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send("USER {0} {0} {0} :krowbar\r\n".format(botnick)) # user authentication - ircsock.send("NICK {}\r\n".format(botnick)) - ircsock.send("MODE +B {}\r\n".format(botnick)) + ircsock.connect((server, 6667)) + ircsock.send("USER {0} {0} {0} :krowbar\r\n".format(botnick)) # user authentication + ircsock.send("NICK {}\r\n".format(botnick)) + ircsock.send("MODE +B {}\r\n".format(botnick)) + + joinchan(channel) + if not DEBUG: + joinchan("#bots") - joinchan(channel) - if(not DEBUG): - joinchan("#bots") def get_user_from_message(msg): - try: - i1 = msg.index(':') + 1 - i2 = msg.index('!') - return msg[i1:i2] - except ValueError: - return "" + try: + i1 = msg.index(":") + 1 + i2 = msg.index("!") + return msg[i1:i2] + except ValueError: + return "" + def listen(): - while 1: + while 1: - ircmsg = ircsock.recv(2048) - for msg in ircmsg.split('\n'): - msg = msg.strip('\n\r') + ircmsg = ircsock.recv(2048) + for msg in ircmsg.split("\n"): + msg = msg.strip("\n\r") - if msg[:4] == "PING": - util.ping(ircsock, msg) + if msg[:4] == "PING": + util.ping(ircsock, msg) - formatted = formatter.format_message(msg) + formatted = formatter.format_message(msg) - if "" == formatted: - continue + if "" == formatted: + continue - # print formatted + # print formatted - split = formatted.split("\t") - iTime = split[0] - user = split[1] - name = names.get_name(user) - command = split[2] - channel = split[3] - messageText = split[4] + split = formatted.split("\t") + iTime = split[0] + user = split[1] + name = names.get_name(user) + command = split[2] + channel = split[3] + messageText = split[4] - if msg.find(":!tildescore") != -1: - show_tildescore(channel, user, name) - elif msg.find(":!tilde") != -1 and not challenges.has_key(user): - challenge(channel, user, name, iTime) - elif challenges.has_key(user) and (channel == "#bots" or DEBUG): - challenge_response(channel, user, name, iTime, messageText) - #give_tilde(channel, user, name, iTime) + if msg.find(":!tildescore") != -1: + show_tildescore(channel, user, name) + elif msg.find(":!tilde") != -1 and not challenges.has_key(user): + challenge(channel, user, name, iTime) + elif challenges.has_key(user) and (channel == "#bots" or DEBUG): + challenge_response(channel, user, name, iTime, messageText) + # give_tilde(channel, user, name, iTime) - if msg.find(":!jackpot") != -1: - show_jackpot(channel) + if msg.find(":!jackpot") != -1: + show_jackpot(channel) - if msg.find(":!rollcall") != -1: - rollcall(channel) + if msg.find(":!rollcall") != -1: + rollcall(channel) - if msg[:4] == "PING": - util.ping(ircsock, msg) + if msg[:4] == "PING": + util.ping(ircsock, msg) + + sys.stdout.flush() + time.sleep(1) - sys.stdout.flush() - time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect(options.server, options.channel, options.nick) diff --git a/Code/irc/topicbot.py b/Code/irc/topicbot.py index 2f11aa4..19e4739 100755 --- a/Code/irc/topicbot.py +++ b/Code/irc/topicbot.py @@ -19,179 +19,255 @@ import names parser = OptionParser() -parser.add_option("-s", "--server", dest="server", default='127.0.0.1', - help="the server to connect to", metavar="SERVER") -parser.add_option("-c", "--channel", dest="channel", default='#bot_test', - help="the channel to join", metavar="CHANNEL") -parser.add_option("-n", "--nick", dest="nick", default='topicbot', - help="the nick to use", metavar="NICK") +parser.add_option( + "-s", + "--server", + dest="server", + default="127.0.0.1", + help="the server to connect to", + metavar="SERVER", +) +parser.add_option( + "-c", + "--channel", + dest="channel", + default="#bot_test", + help="the channel to join", + metavar="CHANNEL", +) +parser.add_option( + "-n", + "--nick", + dest="nick", + default="topicbot", + help="the nick to use", + metavar="NICK", +) (options, args) = parser.parse_args() p = inflect.engine() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) -def sendmsg(chan , msg): - ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n") +def ping(pong): + ircsock.send("PONG {}\n".format(pong)) + + +def sendmsg(chan, msg): + ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") + def joinchan(chan): - ircsock.send("JOIN "+ chan +"\n") + ircsock.send("JOIN " + chan + "\n") + def hello(): - ircsock.send("PRIVMSG "+ channel +" :Hello!\n") + ircsock.send("PRIVMSG " + channel + " :Hello!\n") + def get_topic(channel, user, time): - #topic scores are saved as &^%&^% - with open("topicscores.txt", "r") as scorefile: - scores = scorefile.readlines() - userscore = 1 - found = False - with open("topicscores.txt", "w") as scorefile: - for idx,score in enumerate(scores): - data = score.strip("\n").split("&^%") - if(data[0] == user): - found = True - userscore = int(data[1])+1 - scores[idx] = data[0] + "&^%" + str(userscore) + "&^%" + data[2] + "\n" - scorefile.writelines(scores) - if(not found): - scorefile.write(user + "&^%1&^%0\n") + # topic scores are saved as &^%&^% + with open("topicscores.txt", "r") as scorefile: + scores = scorefile.readlines() + userscore = 1 + found = False + with open("topicscores.txt", "w") as scorefile: + for idx, score in enumerate(scores): + data = score.strip("\n").split("&^%") + if data[0] == user: + found = True + userscore = int(data[1]) + 1 + scores[idx] = data[0] + "&^%" + str(userscore) + "&^%" + data[2] + "\n" + scorefile.writelines(scores) + if not found: + scorefile.write(user + "&^%1&^%0\n") + with open("topics_" + channel + ".txt", "r") as topics: + topic = topics.readlines()[-1].strip("\n").split("&^%", 3) + byuser = names.get_name(topic[1]) + ircsock.send( + "PRIVMSG " + + channel + + " :I've told you " + + p.number_to_words(userscore) + + " times! It's \"" + + topic[2] + + '" (Set by ' + + byuser + + " " + + pretty_date.pretty_date(int(topic[0])) + + ")\n" + ) - with open("topics_" + channel + ".txt", "r") as topics: - topic = topics.readlines()[-1].strip("\n").split("&^%", 3) - byuser = names.get_name(topic[1]) - ircsock.send("PRIVMSG "+ channel +" :I've told you " + p.number_to_words(userscore) + " times! It's \"" + topic[2] + "\" (Set by " + byuser + " " + pretty_date.pretty_date(int(topic[0])) + ")\n") def count_topic(channel, user, time, msg): - with open("topics_" + channel + ".txt", "a") as topics: - topics.write(time + "&^%" + user + "&^%" + msg + "\n") - with open("topicscores.txt", "r") as scorefile: - scores = scorefile.readlines() - userscore = 1 - found = False - with open("topicscores.txt", "w") as scorefile: - for idx,score in enumerate(scores): - data = score.strip("\n").split("&^%") - if(data[0] == user): - found = True - userscore = int(data[2])+1 - scores[idx] = data[0] + "&^%" + data[1] + "&^%" + str(userscore) + "\n" - scorefile.writelines(scores) - if(not found): - scorefile.write(user + "&^%0&^%1") - ircsock.send("PRIVMSG "+ channel +" :" + user + " has changed the topic " + p.number_to_words(userscore) + " times!\n") + with open("topics_" + channel + ".txt", "a") as topics: + topics.write(time + "&^%" + user + "&^%" + msg + "\n") + with open("topicscores.txt", "r") as scorefile: + scores = scorefile.readlines() + userscore = 1 + found = False + with open("topicscores.txt", "w") as scorefile: + for idx, score in enumerate(scores): + data = score.strip("\n").split("&^%") + if data[0] == user: + found = True + userscore = int(data[2]) + 1 + scores[idx] = data[0] + "&^%" + data[1] + "&^%" + str(userscore) + "\n" + scorefile.writelines(scores) + if not found: + scorefile.write(user + "&^%0&^%1") + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + " has changed the topic " + + p.number_to_words(userscore) + + " times!\n" + ) + def set_topic(channel, user, time, msg): - ircsock.send("TOPIC "+ channel +" :" + msg + "\n") - count_topic(channel, user, time, msg) + ircsock.send("TOPIC " + channel + " :" + msg + "\n") + count_topic(channel, user, time, msg) + def random_topic(channel, user, time, setTopic=False): with open("randomtopics.txt") as rtopics: - msg = random.choice(rtopics.readlines()).strip("\n") - if(setTopic): - set_topic(channel, user, time, msg) - else: - ircsock.send("PRIVMSG "+channel +" :Suggested Topic: " + msg + "\n") + msg = random.choice(rtopics.readlines()).strip("\n") + if setTopic: + set_topic(channel, user, time, msg) + else: + ircsock.send("PRIVMSG " + channel + " :Suggested Topic: " + msg + "\n") + def rollcall(channel): - ircsock.send("PRIVMSG "+ channel +" :topicbot reporting! I respond to !topic !settopic !suggesttopic !thistory\n") + ircsock.send( + "PRIVMSG " + + channel + + " :topicbot reporting! I respond to !topic !settopic !suggesttopic !thistory\n" + ) + def topic_score(channel): - ircsock.send("PRIVMSG "+ channel +" :Not implemented yet") + ircsock.send("PRIVMSG " + channel + " :Not implemented yet") + def topic_scores(channel): - ircsock.send("PRIVMSG "+ channel +" :Not implemented yet") + ircsock.send("PRIVMSG " + channel + " :Not implemented yet") + def topic_history(channel, user, count): - try: - iCount = int(count.split()[1]) - except (ValueError, IndexError) as e: - iCount = 3 - if(iCount > 10): - iCount = 10 - if(iCount < 1): - iCount = 3 - with open("topics_" + channel + ".txt", "r") as topicsfile: - #topics = topicsfile.readlines()[-iCount:].reverse() - ircsock.send("PRIVMSG "+ channel +" :Ok, here were the last " + p.number_to_words(iCount) + " topics\n") - for idx,topic in enumerate(reversed(topicsfile.readlines()[-iCount:])): - topic = topic.strip("\n").split("&^%", 3) - byuser = names.get_name(topic[1]) - ircsock.send("PRIVMSG "+ channel +" :" + str(idx+1) + ": \"" + topic[2] + "\" (Set by " + byuser + " " + pretty_date.pretty_date(int(topic[0])) + ")\n") + try: + iCount = int(count.split()[1]) + except (ValueError, IndexError) as e: + iCount = 3 + if iCount > 10: + iCount = 10 + if iCount < 1: + iCount = 3 + with open("topics_" + channel + ".txt", "r") as topicsfile: + # topics = topicsfile.readlines()[-iCount:].reverse() + ircsock.send( + "PRIVMSG " + + channel + + " :Ok, here were the last " + + p.number_to_words(iCount) + + " topics\n" + ) + for idx, topic in enumerate(reversed(topicsfile.readlines()[-iCount:])): + topic = topic.strip("\n").split("&^%", 3) + byuser = names.get_name(topic[1]) + ircsock.send( + "PRIVMSG " + + channel + + " :" + + str(idx + 1) + + ': "' + + topic[2] + + '" (Set by ' + + byuser + + " " + + pretty_date.pretty_date(int(topic[0])) + + ")\n" + ) def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :krowbar\n") # user authentication - ircsock.send("NICK "+ botnick +"\n") + ircsock.connect((server, 6667)) + ircsock.send( + "USER " + botnick + " " + botnick + " " + botnick + " :krowbar\n" + ) # user authentication + ircsock.send("NICK " + botnick + "\n") + + joinchan(channel) + joinchan("#bots") - joinchan(channel) - joinchan("#bots") def get_user_from_message(msg): - try: - i1 = msg.index(':') + 1 - i2 = msg.index('!') - return msg[i1:i2] - except ValueError: - return "" + try: + i1 = msg.index(":") + 1 + i2 = msg.index("!") + return msg[i1:i2] + except ValueError: + return "" + def listen(): - while 1: + while 1: - ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip('\n\r') + ircmsg = ircsock.recv(2048) + ircmsg = ircmsg.strip("\n\r") - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) - formatted = formatter.format_message(ircmsg) + formatted = formatter.format_message(ircmsg) - if "" == formatted: - continue + if "" == formatted: + continue - # print formatted + # print formatted - split = formatted.split("\t") - msgtime = split[0] - user = split[1] - command = split[2] - channel = split[3] - messageText = split[4] + split = formatted.split("\t") + msgtime = split[0] + user = split[1] + command = split[2] + channel = split[3] + messageText = split[4] - if(command == "TOPIC" and user != options.nick): - count_topic(channel,user, msgtime, messageText) + if command == "TOPIC" and user != options.nick: + count_topic(channel, user, msgtime, messageText) - if ircmsg.find(":!topic") != -1: - get_topic(channel, user, msgtime) + if ircmsg.find(":!topic") != -1: + get_topic(channel, user, msgtime) - if ircmsg.find(":!settopic") != -1: - set_topic(channel, user, msgtime, messageText[10:]) + if ircmsg.find(":!settopic") != -1: + set_topic(channel, user, msgtime, messageText[10:]) - if ircmsg.find(":!tscores") != -1: - topic_scores(channel) - elif ircmsg.find(":!tscores") != -1: - topic_score(channel) + if ircmsg.find(":!tscores") != -1: + topic_scores(channel) + elif ircmsg.find(":!tscores") != -1: + topic_score(channel) - if ircmsg.find(":!randomtopic") != -1: - random_topic(channel, user, msgtime, True) - if ircmsg.find(":!suggesttopic") != -1: - random_topic(channel,user,msgtime, False) + if ircmsg.find(":!randomtopic") != -1: + random_topic(channel, user, msgtime, True) + if ircmsg.find(":!suggesttopic") != -1: + random_topic(channel, user, msgtime, False) - if ircmsg.find(":!thistory") != -1: - topic_history(channel, user, messageText) + if ircmsg.find(":!thistory") != -1: + topic_history(channel, user, messageText) - if ircmsg.find(":!rollcall") != -1: - rollcall(channel) + if ircmsg.find(":!rollcall") != -1: + rollcall(channel) - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) + + sys.stdout.flush() + time.sleep(1) - sys.stdout.flush() - time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect(options.server, options.channel, options.nick) diff --git a/Code/irc/tumblr.py b/Code/irc/tumblr.py index 89c6165..f835878 100644 --- a/Code/irc/tumblr.py +++ b/Code/irc/tumblr.py @@ -2,30 +2,48 @@ import urllib from bs4 import BeautifulSoup import random import re - + + def tumble(url): - #Find the max pages - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') - pages = soup.findAll('span', 'page-numbers')[0].text.split('/')[1] #this could totally fail several ways - tries = 3 - while True: - try: - page = random.randrange(1, int(pages)+1) + # Find the max pages + soup = BeautifulSoup(urllib.urlopen(url).read(), "html.parser") + pages = soup.findAll("span", "page-numbers")[0].text.split("/")[ + 1 + ] # this could totally fail several ways + tries = 3 + while True: + try: + page = random.randrange(1, int(pages) + 1) - #Parse a page - soup = BeautifulSoup(urllib.urlopen(url + '/page/' + str(page)).read(), 'html.parser') - article = random.choice(soup.findAll('article')) - quote = article.find('blockquote').text.replace('\n',''); - if len(article.find('footer').findAll('ul')) > 1: - quote += re.sub('\n+', ' ', article.find('footer').findAll('ul')[0].text); #the hash tags - quote += '(' + re.sub('\n+', ' ', article.find('footer').findAll('ul')[1].text) + ')'; #and the date and notes - else: - quote += '(' + re.sub('\n+', ' ', article.find('footer').findAll('ul')[0].text) + ')'; #just the date and notes + # Parse a page + soup = BeautifulSoup( + urllib.urlopen(url + "/page/" + str(page)).read(), "html.parser" + ) + article = random.choice(soup.findAll("article")) + quote = article.find("blockquote").text.replace("\n", "") + if len(article.find("footer").findAll("ul")) > 1: + quote += re.sub( + "\n+", " ", article.find("footer").findAll("ul")[0].text + ) + # the hash tags + quote += ( + "(" + + re.sub("\n+", " ", article.find("footer").findAll("ul")[1].text) + + ")" + ) + # and the date and notes + else: + quote += ( + "(" + + re.sub("\n+", " ", article.find("footer").findAll("ul")[0].text) + + ")" + ) + # just the date and notes - return quote.encode('ascii', 'ignore') - except: #sometimes we fail. let's retry a few times - if tries == 0: - return '' - else: - tries -= 1 - break + return quote.encode("ascii", "ignore") + except: # sometimes we fail. let's retry a few times + if tries == 0: + return "" + else: + tries -= 1 + break diff --git a/Code/irc/util.py b/Code/irc/util.py index 2a6a86e..f8e4ad3 100644 --- a/Code/irc/util.py +++ b/Code/irc/util.py @@ -5,12 +5,15 @@ import re def ping(pong): ircsock.send("PONG {}\n".format(pong.split(" ")[1])) -def sendmsg(ircsock, chan , msg): + +def sendmsg(ircsock, chan, msg): ircsock.send("PRIVMSG {} :{}\r\n".format(chan, msg)) + def joinchan(ircsock, chan): ircsock.send("JOIN {}\n".format(chan)) + # integer number to english word conversion # can be used for numbers as large as 999 vigintillion # (vigintillion --> 10 to the power 60) @@ -32,7 +35,7 @@ def int2word(n): if q < -2: break else: - if q >= 0: + if q >= 0: n3.append(int(r[:3])) elif q >= -1: n3.append(int(r[:2])) @@ -40,7 +43,7 @@ def int2word(n): n3.append(int(r[:1])) r1 = r - #print n3 # test + # print n3 # test # break each group of 3 digits into # ones, tens/twenties, hundreds @@ -48,9 +51,9 @@ def int2word(n): nw = "" for i, x in enumerate(n3): b1 = x % 10 - b2 = (x % 100)//10 - b3 = (x % 1000)//100 - #print b1, b2, b3 # test + b2 = (x % 100) // 10 + b3 = (x % 1000) // 100 + # print b1, b2, b3 # test if x == 0: continue # skip else: @@ -64,33 +67,85 @@ def int2word(n): if b3 > 0: nw = ones[b3] + "hundred " + nw return nw + + ############# globals ################ -ones = ["", "one ","two ","three ","four ", "five ", - "six ","seven ","eight ","nine "] -tens = ["ten ","eleven ","twelve ","thirteen ", "fourteen ", - "fifteen ","sixteen ","seventeen ","eighteen ","nineteen "] -twenties = ["","","twenty ","thirty ","forty ", - "fifty ","sixty ","seventy ","eighty ","ninety "] -thousands = ["","thousand ","million ", "billion ", "trillion ", - "quadrillion ", "quintillion ", "sextillion ", "septillion ","octillion ", - "nonillion ", "decillion ", "undecillion ", "duodecillion ", "tredecillion ", - "quattuordecillion ", "sexdecillion ", "septendecillion ", "octodecillion ", - "novemdecillion ", "vigintillion "] +ones = [ + "", + "one ", + "two ", + "three ", + "four ", + "five ", + "six ", + "seven ", + "eight ", + "nine ", +] +tens = [ + "ten ", + "eleven ", + "twelve ", + "thirteen ", + "fourteen ", + "fifteen ", + "sixteen ", + "seventeen ", + "eighteen ", + "nineteen ", +] +twenties = [ + "", + "", + "twenty ", + "thirty ", + "forty ", + "fifty ", + "sixty ", + "seventy ", + "eighty ", + "ninety ", +] +thousands = [ + "", + "thousand ", + "million ", + "billion ", + "trillion ", + "quadrillion ", + "quintillion ", + "sextillion ", + "septillion ", + "octillion ", + "nonillion ", + "decillion ", + "undecillion ", + "duodecillion ", + "tredecillion ", + "quattuordecillion ", + "sexdecillion ", + "septendecillion ", + "octodecillion ", + "novemdecillion ", + "vigintillion ", +] + def format_message(message): - pattern = r'^:.*\!~(.*)@.* (.*) (.*) :(.*)' + pattern = r"^:.*\!~(.*)@.* (.*) (.*) :(.*)" now = int(time.time()) matches = re.match(pattern, message) if not matches: - return '' + return "" - nick = matches.group(1).strip() - command = matches.group(2).strip() - channel = matches.group(3).strip() + nick = matches.group(1).strip() + command = matches.group(2).strip() + channel = matches.group(3).strip() message = matches.group(4).strip() return "%s\t%s\t%s\t%s\t%s" % (now, nick, command, channel, message) + def get_users(): # thanks, ~dan! users = [] @@ -102,46 +157,47 @@ def get_users(): return users + def pretty_date(time=False): - """ + """ Get a datetime object or a int() Epoch timestamp and return a pretty string like 'an hour ago', 'Yesterday', '3 months ago', 'just now', etc """ - from datetime import datetime - now = datetime.now() - if type(time) is int: - diff = now - datetime.fromtimestamp(time) - elif isinstance(time,datetime): - diff = now - time - elif not time: - diff = now - now - second_diff = diff.seconds - day_diff = diff.days + from datetime import datetime - if day_diff < 0: - return '' + now = datetime.now() + if type(time) is int: + diff = now - datetime.fromtimestamp(time) + elif isinstance(time, datetime): + diff = now - time + elif not time: + diff = now - now + second_diff = diff.seconds + day_diff = diff.days - if day_diff == 0: - if second_diff < 10: - return "just now" - if second_diff < 60: - return str(second_diff) + " seconds ago" - if second_diff < 120: - return "a minute ago" - if second_diff < 3600: - return str(second_diff / 60) + " minutes ago" - if second_diff < 7200: - return "an hour ago" - if second_diff < 86400: - return str(second_diff / 3600) + " hours ago" - if day_diff == 1: - return "Yesterday" - if day_diff < 7: - return str(day_diff) + " days ago" - if day_diff < 31: - return str(day_diff / 7) + " weeks ago" - if day_diff < 365: - return str(day_diff / 30) + " months ago" - return str(day_diff / 365) + " years ago" + if day_diff < 0: + return "" + if day_diff == 0: + if second_diff < 10: + return "just now" + if second_diff < 60: + return str(second_diff) + " seconds ago" + if second_diff < 120: + return "a minute ago" + if second_diff < 3600: + return str(second_diff / 60) + " minutes ago" + if second_diff < 7200: + return "an hour ago" + if second_diff < 86400: + return str(second_diff / 3600) + " hours ago" + if day_diff == 1: + return "Yesterday" + if day_diff < 7: + return str(day_diff) + " days ago" + if day_diff < 31: + return str(day_diff / 7) + " weeks ago" + if day_diff < 365: + return str(day_diff / 30) + " months ago" + return str(day_diff / 365) + " years ago" diff --git a/Code/irc/wangbot.py b/Code/irc/wangbot.py index a28ab25..ad32d31 100755 --- a/Code/irc/wangbot.py +++ b/Code/irc/wangbot.py @@ -20,12 +20,30 @@ import inflect parser = OptionParser() -parser.add_option("-s", "--server", dest="server", default='127.0.0.1', - help="the server to connect to", metavar="SERVER") -parser.add_option("-c", "--channel", dest="channel", default='#bot_test', - help="the channel to join", metavar="CHANNEL") -parser.add_option("-n", "--nick", dest="nick", default='numberwang_bot', - help="the nick to use", metavar="NICK") +parser.add_option( + "-s", + "--server", + dest="server", + default="127.0.0.1", + help="the server to connect to", + metavar="SERVER", +) +parser.add_option( + "-c", + "--channel", + dest="channel", + default="#bot_test", + help="the channel to join", + metavar="CHANNEL", +) +parser.add_option( + "-n", + "--nick", + dest="nick", + default="numberwang_bot", + help="the nick to use", + metavar="NICK", +) (options, args) = parser.parse_args() @@ -43,116 +61,194 @@ guesses = 0 lastGuesser = "" currentScores = {} + def resetGlobals(): - global roundsLeft - global bonusRound - global guesses - global lastGuesser - global currentScores - roundsLeft = 0 - bonusRound = 0 - guesses = 0 - lastGuesser = "" - currentScores.clear() + global roundsLeft + global bonusRound + global guesses + global lastGuesser + global currentScores + roundsLeft = 0 + bonusRound = 0 + guesses = 0 + lastGuesser = "" + currentScores.clear() def ping(pong): - ircsock.send("PONG {}\n".format(pong)) + ircsock.send("PONG {}\n".format(pong)) + + +def sendmsg(chan, msg): + ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") -def sendmsg(chan , msg): - ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n") def joinchan(chan): - ircsock.send("JOIN "+ chan +"\n") + ircsock.send("JOIN " + chan + "\n") + def hello(): - ircsock.send("PRIVMSG "+ channel +" :Hello!\n") + ircsock.send("PRIVMSG " + channel + " :Hello!\n") + def start_numberwang(channel, user): - if(channel != "#bots"): - ircsock.send("PRIVMSG " + channel + " :Numberwang has been disabled for " + channel + " due to spamminess. Please join " + GOOD_CHAN + " to start a game.\n") + if channel != "#bots": + ircsock.send( + "PRIVMSG " + + channel + + " :Numberwang has been disabled for " + + channel + + " due to spamminess. Please join " + + GOOD_CHAN + + " to start a game.\n" + ) return - print user + " started a game" + print(user + " started a game") resetGlobals() ircsock.send("PRIVMSG " + channel + " :It's time for Numberwang!\n") time.sleep(1) ircsock.send("PRIVMSG " + channel + " :Here's how to play:\n") ircsock.send("PRIVMSG " + channel + " :1. There are 10 rounds\n") - ircsock.send("PRIVMSG " + channel + " :2. Each round lasts 10 seconds. You're up against the clock!\n") - ircsock.send("PRIVMSG " + channel + " :3. Play your numbers, as long as they're between 0 and 99.\n") + ircsock.send( + "PRIVMSG " + + channel + + " :2. Each round lasts 10 seconds. You're up against the clock!\n" + ) + ircsock.send( + "PRIVMSG " + + channel + + " :3. Play your numbers, as long as they're between 0 and 99.\n" + ) ircsock.send("PRIVMSG " + channel + " :4. That's Numberwang!\n") time.sleep(2) ircsock.send("PRIVMSG " + channel + " :Let's get started!\n") global roundsLeft global bonusRound - roundsLeft = random.randint(MIN_ROUNDS,MAX_ROUNDS) - bonusRound = random.randint(2,roundsLeft-1) - print "There will be " + str(roundsLeft) + " rounds with the bonus on round " + str(roundsLeft - bonusRound + 1) + roundsLeft = random.randint(MIN_ROUNDS, MAX_ROUNDS) + bonusRound = random.randint(2, roundsLeft - 1) + print( + "There will be " + + str(roundsLeft) + + " rounds with the bonus on round " + + str(roundsLeft - bonusRound + 1) + ) + def print_scores(channel): scoreStrs = [] first = True for name in currentScores: - scoreStrs.append(name + " is " + ("also " if not first and random.randint(1,3) == 3 else "") + "on " + str(currentScores[name])) + scoreStrs.append( + name + + " is " + + ("also " if not first and random.randint(1, 3) == 3 else "") + + "on " + + str(currentScores[name]) + ) first = False ircsock.send("PRIVMSG " + channel + " :" + p.join(scoreStrs) + "!\n") + def guess_numberwang(channel, user, messageText): global guesses global lastGuesser global currentScores global roundsLeft - print user + " guessed '" + messageText + "'" - guess = re.sub('[^0-9]','',messageText.split()[0]) #must have a number in the first 'word' - if(guess): - if(LIMIT_GUESSING and user == lastGuesser): - ircsock.send("PRIVMSG " + channel + " :" + user + ", you just guessed! Give another player a try!\n") + print(user + " guessed '" + messageText + "'") + guess = re.sub( + "[^0-9]", "", messageText.split()[0] + ) # must have a number in the first 'word' + if guess: + if LIMIT_GUESSING and user == lastGuesser: + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ", you just guessed! Give another player a try!\n" + ) else: guesses += 1 lastGuesser = user ###CORRECT GUESS### - if(random.randint(0,10) > 10 - guesses): #the more guesses, the higher the probability + if ( + random.randint(0, 10) > 10 - guesses + ): # the more guesses, the higher the probability guesses = 0 lastGuesser = "" - ircsock.send("PRIVMSG " + channel + " :" + user + ": THAT'S NUMBERWANG!\n") - points = random.randint(2,10) * (random.randint(2,4) if roundsLeft == bonusRound else 1) + ircsock.send( + "PRIVMSG " + channel + " :" + user + ": THAT'S NUMBERWANG!\n" + ) + points = random.randint(2, 10) * ( + random.randint(2, 4) if roundsLeft == bonusRound else 1 + ) if user in currentScores.keys(): currentScores[user] += points else: currentScores[user] = points roundsLeft -= 1 time.sleep(2) - if(roundsLeft == 0): - ircsock.send("PRIVMSG " + channel + " :Numberwang is now over. Thank you for playing!\n") + if roundsLeft == 0: + ircsock.send( + "PRIVMSG " + + channel + + " :Numberwang is now over. Thank you for playing!\n" + ) ircsock.send("PRIVMSG " + channel + " :Final scores:\n") print_scores(channel) save_scores() else: print_scores(channel) newRoundStr = "" - if(roundsLeft == 1): + if roundsLeft == 1: newRoundStr += "The last round is Wangernumb!" - elif(roundsLeft == bonusRound): + elif roundsLeft == bonusRound: newRoundStr += "**Bonus Round!**" else: newRoundStr += "New Round!" - if(random.randint(1,10) > 8): + if random.randint(1, 10) > 8: newRoundStr += " Let's rotate the board!" - ircsock.send("PRIVMSG " + channel + " :" + newRoundStr + " Start guessing!\n") - + ircsock.send( + "PRIVMSG " + channel + " :" + newRoundStr + " Start guessing!\n" + ) ###INCORRECT GUESS### else: - ircsock.send("PRIVMSG " + channel + " :" + random.choice(["Sorry", "I'm sorry", "No", "Nope"]) + ", " + user + ", " \ - + random.choice(["that's not", "that is not", "that isn't", "that is not", "that won't make", "that will not make"])\ - + " Numberwang!\n") + ircsock.send( + "PRIVMSG " + + channel + + " :" + + random.choice(["Sorry", "I'm sorry", "No", "Nope"]) + + ", " + + user + + ", " + + random.choice( + [ + "that's not", + "that is not", + "that isn't", + "that is not", + "that won't make", + "that will not make", + ] + ) + + " Numberwang!\n" + ) + def stop_numberwang(channel, user): - print user + " stopped a game" + print(user + " stopped a game") resetGlobals() - ircsock.send("PRIVMSG " + channel + " :Numberwang has been stopped. No points have been awarded. " + user + " is such a party pooper!\n") + ircsock.send( + "PRIVMSG " + + channel + + " :Numberwang has been stopped. No points have been awarded. " + + user + + " is such a party pooper!\n" + ) + def save_scores(): with open(SCORE_FILE, "r+") as scorefile: @@ -162,16 +258,22 @@ def save_scores(): for line in scores: for name in currentScores: score = line.strip("\n").split("&^%") - if(score[0] == name): - line = score[0] + "&^%" + str(int(score[1]) + currentScores[name]) + "\n" + if score[0] == name: + line = ( + score[0] + + "&^%" + + str(int(score[1]) + currentScores[name]) + + "\n" + ) del currentScores[name] break scorefile.write(line) - for name in currentScores: #new wangers + for name in currentScores: # new wangers line = name + "&^%" + str(currentScores[name]) + "\n" scorefile.write(line) + def show_highscores(channel): with open(SCORE_FILE, "r") as scorefile: scores = [] @@ -182,83 +284,116 @@ def show_highscores(channel): ircsock.send("PRIVMSG " + channel + " : ====TOP WANGERS====\n") for score in scores: - ircsock.send("PRIVMSG " + channel + " :== ~" + score[1] + " (" + str(score[0]) + " points!) ==\n") + ircsock.send( + "PRIVMSG " + + channel + + " :== ~" + + score[1] + + " (" + + str(score[0]) + + " points!) ==\n" + ) def show_user_score(channel, user): with open(SCORE_FILE, "r") as scorefile: for line in scorefile.readlines(): score = line.strip("\n").split("&^%") - if(user == score[0]): - ircsock.send("PRIVMSG " + channel + " :" + user + ": Your global numberwang score is " + str(score[1]) + "!\n") + if user == score[0]: + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": Your global numberwang score is " + + str(score[1]) + + "!\n" + ) return - #if we don't find a score line - ircsock.send("PRIVMSG " + channel + " :" + user + ": You haven't scored any points yet!\n") + # if we don't find a score line + ircsock.send( + "PRIVMSG " + + channel + + " :" + + user + + ": You haven't scored any points yet!\n" + ) + def rollcall(channel): - ircsock.send("PRIVMSG "+ channel +" :Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers\n") + ircsock.send( + "PRIVMSG " + + channel + + " :Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers\n" + ) + def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :krowbar\n") # user authentication - ircsock.send("NICK "+ botnick +"\n") + ircsock.connect((server, 6667)) + ircsock.send( + "USER " + botnick + " " + botnick + " " + botnick + " :krowbar\n" + ) # user authentication + ircsock.send("NICK " + botnick + "\n") + + joinchan(channel) + joinchan(GOOD_CHAN) - joinchan(channel) - joinchan(GOOD_CHAN) def get_user_from_message(msg): - try: - i1 = msg.index(':') + 1 - i2 = msg.index('!') - return msg[i1:i2] - except ValueError: - return "" + try: + i1 = msg.index(":") + 1 + i2 = msg.index("!") + return msg[i1:i2] + except ValueError: + return "" + def listen(): - while 1: + while 1: - ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip('\n\r') + ircmsg = ircsock.recv(2048) + ircmsg = ircmsg.strip("\n\r") - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) - formatted = formatter.format_message(ircmsg) + formatted = formatter.format_message(ircmsg) - if "" == formatted: - continue + if "" == formatted: + continue - # print formatted + # print formatted - split = formatted.split("\t") - time = split[0] - user = split[1] - command = split[2] - channel = split[3] - messageText = split[4] + split = formatted.split("\t") + time = split[0] + user = split[1] + command = split[2] + channel = split[3] + messageText = split[4] - if ircmsg.find(":!numberwang") != -1 and roundsLeft == 0: - start_numberwang(channel, user) + if ircmsg.find(":!numberwang") != -1 and roundsLeft == 0: + start_numberwang(channel, user) - if channel == GOOD_CHAN: - if ircmsg.find(":!wangernumb") != -1 and roundsLeft > 0: - stop_numberwang(channel, user) - if roundsLeft > 0: - guess_numberwang(channel, user, messageText) + if channel == GOOD_CHAN: + if ircmsg.find(":!wangernumb") != -1 and roundsLeft > 0: + stop_numberwang(channel, user) + if roundsLeft > 0: + guess_numberwang(channel, user, messageText) - if ircmsg.find(":!topwangers") != -1: - show_highscores(channel) - if ircmsg.find(":!myscore") != -1: - show_user_score(channel, user) + if ircmsg.find(":!topwangers") != -1: + show_highscores(channel) + if ircmsg.find(":!myscore") != -1: + show_user_score(channel, user) - if ircmsg.find(":!rollcall") != -1: - rollcall(channel) + if ircmsg.find(":!rollcall") != -1: + rollcall(channel) - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + if ircmsg[:4] == "PING": + ping(ircmsg.split(" ")[1]) + + sys.stdout.flush() + time.sleep(1) - sys.stdout.flush() - time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect(options.server, options.channel, options.nick) diff --git a/Code/irc/welch.py b/Code/irc/welch.py index eacf87b..563d96b 100644 --- a/Code/irc/welch.py +++ b/Code/irc/welch.py @@ -1,6 +1,10 @@ import random + def get_thing(): file = "/home/krowbar/logs/welchdata.txt" thing = "" - return "Thing Mr. Welch can no longer do in a RPG #" + random.choice(list(open(file))).rstrip() + return ( + "Thing Mr. Welch can no longer do in a RPG #" + + random.choice(list(open(file))).rstrip() + ) diff --git a/Code/irc/whosaid.py b/Code/irc/whosaid.py index 32ab7a4..468aae8 100755 --- a/Code/irc/whosaid.py +++ b/Code/irc/whosaid.py @@ -8,20 +8,22 @@ import operator MAX_NODES = 5 logfile = "/home/jumblesale/Code/irc/log" -timeCutoff = calendar.timegm(time.gmtime()) - (3 * 7 * 24 * 60 * 60) #3 weeks +timeCutoff = calendar.timegm(time.gmtime()) - (3 * 7 * 24 * 60 * 60) # 3 weeks nameFix = { - 'jumblesal': 'jumblesale', - 'hardmath1': 'kc', - 'hardmath123': 'kc', - 'bendorphan': 'endorphant', - 'endorphan': 'endorphant', - 'synergian': 'synergiance' - } + "jumblesal": "jumblesale", + "hardmath1": "kc", + "hardmath123": "kc", + "bendorphan": "endorphant", + "endorphan": "endorphant", + "synergian": "synergiance", +} + + def whoSaid(word): word = word.lower() - userData = {} #hash keyed by "user" that contains a hash of mentioned other users with count - #Get a list of all user names by checking the logs for people who have said things + userData = {} # hash keyed by "user" that contains a hash of mentioned other users with count + # Get a list of all user names by checking the logs for people who have said things with open(logfile, "r") as log: for line in log: try: @@ -32,12 +34,12 @@ def whoSaid(word): else: user = user.lower() except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse + continue # There are some bad lines in the log file that we'll ignore if we can't parse - if time > timeCutoff and message[0] is not '!' and word in message.lower(): + if time > timeCutoff and message[0] is not "!" and word in message.lower(): if user in userData: userData[user] += 1 else: userData[user] = 1 userData = sorted(userData.items(), key=operator.itemgetter(1), reverse=True) - return {'timecutoff': timeCutoff, 'data': userData} + return {"timecutoff": timeCutoff, "data": userData} diff --git a/Code/irc/wikiphilosophy.py b/Code/irc/wikiphilosophy.py index d4170c9..4b31359 100644 --- a/Code/irc/wikiphilosophy.py +++ b/Code/irc/wikiphilosophy.py @@ -1,50 +1,79 @@ import urllib from bs4 import BeautifulSoup import random - -def get_philosophy(word, max_steps=20): - step_words = [word] - steps = 0 - url = 'https://en.wikipedia.org/wiki/%s' % word - while steps < max_steps: - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') - title = soup.find('h1', id='firstHeading') - content = soup.find('div', id='mw-content-text') - if not content: - break - item = [item for item in content.find_all('a') if not item.get('class') and not item.get('target') and item.get('title') and not 'Wikipedia:' in item.get('title') and not 'Category:' in item.get('title') and not 'Help:' in item.get('title') and not 'Portal:' in item.get('title') and not 'Special:' in item.get('title') and not 'Talk:' in item.get('title') and not 'Template:' in item.get('title') and not 'File:' in item.get('title') and 'Edit section:' not in item.get('title') and 'Commons:' not in item.get('title') and not item.get('title') in step_words][0] - step_words.append(item.get('title')) - #print item.get('title') + "\n" - url = 'https://en.wikipedia.org%s' % item.get('href') - steps += 1 - return step_words + +def get_philosophy(word, max_steps=20): + step_words = [word] + steps = 0 + + url = "https://en.wikipedia.org/wiki/%s" % word + while steps < max_steps: + soup = BeautifulSoup(urllib.urlopen(url).read(), "html.parser") + title = soup.find("h1", id="firstHeading") + content = soup.find("div", id="mw-content-text") + if not content: + break + item = [ + item + for item in content.find_all("a") + if not item.get("class") + and not item.get("target") + and item.get("title") + and not "Wikipedia:" in item.get("title") + and not "Category:" in item.get("title") + and not "Help:" in item.get("title") + and not "Portal:" in item.get("title") + and not "Special:" in item.get("title") + and not "Talk:" in item.get("title") + and not "Template:" in item.get("title") + and not "File:" in item.get("title") + and "Edit section:" not in item.get("title") + and "Commons:" not in item.get("title") + and not item.get("title") in step_words + ][0] + step_words.append(item.get("title")) + # print item.get('title') + "\n" + url = "https://en.wikipedia.org%s" % item.get("href") + steps += 1 + return step_words + def containsAny(str, set): return 1 in [c in str for c in set] + def get_philosophy_lower(word, max_steps=20): - step_words = [word] - steps = 0 - - url = 'https://en.wikipedia.org/wiki/%s' % word - while steps < max_steps: - soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') - title = soup.find('h1', id='firstHeading') - content = soup.find('div', id='mw-content-text') - if not content: - break - links = [item for item in content.find_all('a') if not item.get('class') and item.text and item.text[0].islower() and not containsAny(item.text, ':()') and item.get('title') and not containsAny(item.get('title'), ':()') and not item.get('title') in step_words] - if not links: - step_words.append("(dead end)") - break - item = links[0] #grab the first good link item - #print "Checking %s %s" % (item.get('title'), item.text) - step_words.append(item.get('title')) - if item.get('title') == 'Philosophy': - break - #print item.get('title') + "\n" - url = 'https://en.wikipedia.org%s' % item.get('href') - steps += 1 - return step_words + step_words = [word] + steps = 0 + url = "https://en.wikipedia.org/wiki/%s" % word + while steps < max_steps: + soup = BeautifulSoup(urllib.urlopen(url).read(), "html.parser") + title = soup.find("h1", id="firstHeading") + content = soup.find("div", id="mw-content-text") + if not content: + break + links = [ + item + for item in content.find_all("a") + if not item.get("class") + and item.text + and item.text[0].islower() + and not containsAny(item.text, ":()") + and item.get("title") + and not containsAny(item.get("title"), ":()") + and not item.get("title") in step_words + ] + if not links: + step_words.append("(dead end)") + break + item = links[0] # grab the first good link item + # print "Checking %s %s" % (item.get('title'), item.text) + step_words.append(item.get("title")) + if item.get("title") == "Philosophy": + break + # print item.get('title') + "\n" + url = "https://en.wikipedia.org%s" % item.get("href") + steps += 1 + return step_words diff --git a/Code/irc/xkcdApropos.py b/Code/irc/xkcdApropos.py index ee9dd55..166785b 100644 --- a/Code/irc/xkcdApropos.py +++ b/Code/irc/xkcdApropos.py @@ -2,17 +2,19 @@ import duckduckgo import urllib from bs4 import BeautifulSoup + def xkcd(query): - res = duckduckgo.get_zci('site:xkcd.com ' + query); - title = ""; - try: #ddg returns a url for these searches. i want a title as well - title = BeautifulSoup(urllib.urlopen(res).read(), 'html.parser').title.text + res = duckduckgo.get_zci("site:xkcd.com " + query) + title = "" + try: # ddg returns a url for these searches. i want a title as well + title = BeautifulSoup(urllib.urlopen(res).read(), "html.parser").title.text except: - pass #just swallow the error. maybe the result wasn't a url or something else bad happened - return [(((title + ' - ') if title else '') + res).encode('ascii', 'ignore')] + pass # just swallow the error. maybe the result wasn't a url or something else bad happened + return [(((title + " - ") if title else "") + res).encode("ascii", "ignore")] + # never mind, blocked by ddg -#def xkcd_links(query): +# def xkcd_links(query): # url = "https://duckduckgo.com/html/?q=site%3Axkcd.com+" + query.replace(' ', '+') # soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') # items = soup.find_all("a", class_="result__a") diff --git a/Code/python/chatbesties.py b/Code/python/chatbesties.py index beb34f6..bdbfca0 100755 --- a/Code/python/chatbesties.py +++ b/Code/python/chatbesties.py @@ -11,29 +11,29 @@ import operator MAX_NODES = 4 logfile = "/home/archangelic/irc/log" -#logfile = "/home/jumblesale/Code/irc/log" +# logfile = "/home/jumblesale/Code/irc/log" outfile = "/home/krowbar/logs/chatBesties.json" outCircle = "/home/krowbar/logs/chatcircle.json" -timePeriod = calendar.timegm(time.gmtime()) - (2 * 7 * 24 * 60 * 60) #2 weeks +timePeriod = calendar.timegm(time.gmtime()) - (2 * 7 * 24 * 60 * 60) # 2 weeks -userData = {} #hash keyed by "user" that contains a hash of mentioned other users with count +userData = {} # hash keyed by "user" that contains a hash of mentioned other users with count nameFix = { - 'jumblesal': 'jumblesale', - 'hardmath1': 'kc', - 'hardmath123': 'kc', - 'bendorphan': 'endorphant', - 'endorphan': 'endorphant', - 'synergian': 'synergiance' - } + "jumblesal": "jumblesale", + "hardmath1": "kc", + "hardmath123": "kc", + "bendorphan": "endorphant", + "endorphan": "endorphant", + "synergian": "synergiance", +} users = [] -#Get a list of all user names by checking the logs for people who have said things +# Get a list of all user names by checking the logs for people who have said things with open(logfile, "r") as log: for line in log: try: time, user, message = line.split("\t", 3) if int(time) < timePeriod: - continue #only add users who have spoken in the last period + continue # only add users who have spoken in the last period if nameFix.has_key(user): user = nameFix[user] else: @@ -42,73 +42,105 @@ with open(logfile, "r") as log: if user not in users: users.append(user) except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse + continue # There are some bad lines in the log file that we'll ignore if we can't parse d3data = {} -d3data['nodes'] = [] +d3data["nodes"] = [] -#re-read the log and this time look for instances of user names in messages +# re-read the log and this time look for instances of user names in messages with open(logfile, "r") as log: for line in log: try: time, user, message = line.split("\t", 3) if int(time) < timePeriod: - continue #only consider the past three weeks of chats + continue # only consider the past three weeks of chats if nameFix.has_key(user): user = nameFix[user] else: user = user.lower() except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse - for word in message.split(' '): - word = re.sub('[^A-Za-z0-9]+', '', word) - if word in users: #SOMEONE MENTIONED SOMEONE - if userData.has_key(user): #This user is already set up - if userData[user]['data'].has_key(word): #This user has mentioned this person before - userData[user]['data'][word] += 1 - else: #This user never mentioned this person before - userData[user]['data'][word] = 1 - #give both the target and mentioner a point - else: #This user was never set up - userData[user] = {} #make it a dictionary! - userData[user]['data'] = {} - userData[user]['data'][word] = 1 - userData[user]['score'] = 0 - userData[user]['id'] = len(d3data['nodes']) #so we know how to match people during the links phase - d3data['nodes'].append({"name": user, "group": 1}) - if not userData.has_key(word): #check if the target has not been set up + continue # There are some bad lines in the log file that we'll ignore if we can't parse + for word in message.split(" "): + word = re.sub("[^A-Za-z0-9]+", "", word) + if word in users: # SOMEONE MENTIONED SOMEONE + if userData.has_key(user): # This user is already set up + if userData[user]["data"].has_key( + word + ): # This user has mentioned this person before + userData[user]["data"][word] += 1 + else: # This user never mentioned this person before + userData[user]["data"][word] = 1 + # give both the target and mentioner a point + else: # This user was never set up + userData[user] = {} # make it a dictionary! + userData[user]["data"] = {} + userData[user]["data"][word] = 1 + userData[user]["score"] = 0 + userData[user]["id"] = len( + d3data["nodes"] + ) # so we know how to match people during the links phase + d3data["nodes"].append({"name": user, "group": 1}) + if not userData.has_key( + word + ): # check if the target has not been set up userData[word] = {} - userData[word]['data'] = {} - userData[word]['score'] = 0 - userData[word]['id'] = len(d3data['nodes']) - d3data['nodes'].append({"name": word, "group": 1}) - userData[user]['score'] += 1 - userData[word]['score'] += 1 + userData[word]["data"] = {} + userData[word]["score"] = 0 + userData[word]["id"] = len(d3data["nodes"]) + d3data["nodes"].append({"name": word, "group": 1}) + userData[user]["score"] += 1 + userData[word]["score"] += 1 -d3data['links'] = [] -#Now connect all the pople to their stuff +d3data["links"] = [] +# Now connect all the pople to their stuff for user, values in userData.iteritems(): - #give the user a 'group' based on their total score - d3data['nodes'][values['id']]['group'] = int(math.ceil(math.log(values['score']))) - besties = sorted(values['data'].items(), key=operator.itemgetter(1), reverse=True)[0:MAX_NODES] #ONLY the top besties + # give the user a 'group' based on their total score + d3data["nodes"][values["id"]]["group"] = int(math.ceil(math.log(values["score"]))) + besties = sorted(values["data"].items(), key=operator.itemgetter(1), reverse=True)[ + 0:MAX_NODES + ] # ONLY the top besties for target, score in besties: try: - print "Adding link from " + user + " (" + str(values['id']) + ") to " + target + " (" + str(userData[target]['id']) + ") with strength " + str(score) - d3data['links'].append({"source": values['id'], "target": userData[target]['id'], "value": math.ceil(math.sqrt(score))*2 }) + print( + "Adding link from " + + user + + " (" + + str(values["id"]) + + ") to " + + target + + " (" + + str(userData[target]["id"]) + + ") with strength " + + str(score) + ) + d3data["links"].append( + { + "source": values["id"], + "target": userData[target]["id"], + "value": math.ceil(math.sqrt(score)) * 2, + } + ) except KeyError: - print "! Error when trying to link " + user + " to " + target + print("! Error when trying to link " + user + " to " + target) continue - if len(values['data']) > MAX_NODES: - print " ...ignoring " + str(len(values['data']) - MAX_NODES) + " more connections from " + user + if len(values["data"]) > MAX_NODES: + print( + " ...ignoring " + + str(len(values["data"]) - MAX_NODES) + + " more connections from " + + user + ) d3Circle = {} -d3Circle['names'] = [''] * len(userData) -d3Circle['matrix'] = [[0] * len(userData)] * len(userData) +d3Circle["names"] = [""] * len(userData) +d3Circle["matrix"] = [[0] * len(userData)] * len(userData) for user, values in userData.iteritems(): - d3Circle['names'][values['id']] = user - for name, score in values['data'].iteritems(): - d3Circle['matrix'][values['id']][userData[name]['id']] = score if score > 1 else 0 + d3Circle["names"][values["id"]] = user + for name, score in values["data"].iteritems(): + d3Circle["matrix"][values["id"]][userData[name]["id"]] = ( + score if score > 1 else 0 + ) with open(outfile + ".tmp", "w") as tmpFile: tmpFile.write(json.dumps(d3data)) diff --git a/Code/python/chatchecker.py b/Code/python/chatchecker.py index f8c1ebe..c4f16ea 100755 --- a/Code/python/chatchecker.py +++ b/Code/python/chatchecker.py @@ -6,10 +6,10 @@ import calendar import shutil logfile = "/home/archangelic/irc/log" -#logfile = "/home/jumblesale/Code/irc/log" +# logfile = "/home/jumblesale/Code/irc/log" outfile = "/home/krowbar/logs/userData.json" -userData = {} #hash keyed by "user" that contains an array of timestamps -#we only care about recent chats, let's say for the past couple weeks +userData = {} # hash keyed by "user" that contains an array of timestamps +# we only care about recent chats, let's say for the past couple weeks oneWeek = 7 * 24 * 60 * 60 fiveMinutes = 5 * 60 timeCutoff = calendar.timegm(time.gmtime()) - (5 * oneWeek) @@ -20,17 +20,17 @@ with open(logfile, "r") as log: time, user, message = line.split("\t", 3) time = int(time) except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse + continue # There are some bad lines in the log file that we'll ignore if we can't parse if time > timeCutoff: - #standardize all times into a single "week" - #time %= oneWeek - #if the user already exists in the list + # standardize all times into a single "week" + # time %= oneWeek + # if the user already exists in the list if user in userData: if time < userData[user][-1] + fiveMinutes: - continue #only record times that are at least five minutes apart - userData[user].append(time) #append the new time - else: #if they are new - userData[user] = [time] #create a new list + continue # only record times that are at least five minutes apart + userData[user].append(time) # append the new time + else: # if they are new + userData[user] = [time] # create a new list with open(outfile + ".tmp", "w") as tmpFile: tmpFile.write(json.dumps(userData)) shutil.move(outfile + ".tmp", outfile) diff --git a/Code/python/chatcloud.py b/Code/python/chatcloud.py index c045b9c..2d4764b 100755 --- a/Code/python/chatcloud.py +++ b/Code/python/chatcloud.py @@ -7,22 +7,27 @@ import re import shutil logfile = "/home/archangelic/irc/log" -#logfile = "/home/jumblesale/Code/irc/log" +# logfile = "/home/jumblesale/Code/irc/log" outfile = "/home/krowbar/logs/chatcloud.json" -#outfile = "/home/krowbar/logs/chatcloud_2016_10.json" +# outfile = "/home/krowbar/logs/chatcloud_2016_10.json" bannedUsersFile = "/home/krowbar/Code/python/bannedUsers" bannedWordsFile = "/home/krowbar/Code/python/bannedWords" -wordData = {} # keyed by "word" that contains a count -#we only care about recent chats, let's say for the past sixteen hours +wordData = {} # keyed by "word" that contains a count +# we only care about recent chats, let's say for the past sixteen hours timeTo = calendar.timegm(time.gmtime()) -#timeTo = calendar.timegm(time.strptime("1 Nov 16", "%d %b %y")) +# timeTo = calendar.timegm(time.strptime("1 Nov 16", "%d %b %y")) timeCutoff = timeTo - (16 * 60 * 60) -#timeCutoff = calendar.timegm(time.strptime("1 Oct 16", "%d %b %y")) -print "Generating word cloud based off words from " + str(timeCutoff) + " to " + str(timeTo) -minOccurance = 3 #we'll have to reduce the minOccurances if we reduce the timeCutoff -minLength = 3 #number of letters long +# timeCutoff = calendar.timegm(time.strptime("1 Oct 16", "%d %b %y")) +print( + "Generating word cloud based off words from " + + str(timeCutoff) + + " to " + + str(timeTo) +) +minOccurance = 3 # we'll have to reduce the minOccurances if we reduce the timeCutoff +minLength = 3 # number of letters long bannedWords = open(bannedWordsFile).read().splitlines() bannedUsers = open(bannedUsersFile).read().splitlines() @@ -32,24 +37,28 @@ with open(logfile, "r") as log: time, user, message = line.split("\t", 3) time = int(time) except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse + continue # There are some bad lines in the log file that we'll ignore if we can't parse if user in bannedUsers: - continue #We don't care what they say + continue # We don't care what they say if time >= timeCutoff and time <= timeTo: - #print "Processing line from " + user + " at " + str(time) - for word in re.sub('[\'\"\`\/\\;:,.?!*&^\-()<>\{\}|_\[\]0-9]', ' ', message).lower().split(): - #changing symbols into spaces instead of stripping them avoids compounded words + # print "Processing line from " + user + " at " + str(time) + for word in ( + re.sub("['\"\`\/\\;:,.?!*&^\-()<>\{\}|_\[\]0-9]", " ", message) + .lower() + .split() + ): + # changing symbols into spaces instead of stripping them avoids compounded words if len(word) < minLength or word in bannedWords: - #print "Rejecting " + word + # print "Rejecting " + word continue - #if the word already exists in the list + # if the word already exists in the list if word in wordData: wordData[word] += 1 - else: #if they are new + else: # if they are new wordData[word] = 1 - #print "Added word: " + word -wordData = {i:wordData[i] for i in wordData if wordData[i] >= minOccurance } -if(len(wordData) == 0): + # print "Added word: " + word +wordData = {i: wordData[i] for i in wordData if wordData[i] >= minOccurance} +if len(wordData) == 0: wordData = {"NOTHING": 1, "INTERESTING": 1, "TODAY": 1} with open(outfile + ".tmp", "w") as tmpFile: tmpFile.write(json.dumps(wordData)) diff --git a/Code/python/chatcloud2.py b/Code/python/chatcloud2.py index bc8ece0..d4d971a 100755 --- a/Code/python/chatcloud2.py +++ b/Code/python/chatcloud2.py @@ -10,27 +10,66 @@ import logging, sys logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) -parser = argparse.ArgumentParser(description='Generate word cloud data based off of irc chat logs') -parser.add_argument('-logfile', help='irc log file to read from', default='/home/archangelic/irc/log') -parser.add_argument('-outfile', help='output file to write to', default='') +parser = argparse.ArgumentParser( + description="Generate word cloud data based off of irc chat logs" +) +parser.add_argument( + "-logfile", help="irc log file to read from", default="/home/archangelic/irc/log" +) +parser.add_argument("-outfile", help="output file to write to", default="") -parser.add_argument('-timeend', type=int, help='end time of the word cloud (in epoch time)', default=calendar.timegm(time.gmtime())) -parser.add_argument('-timestart', type=int, help='start time of the word cloud (in epoch time)', default=-1) +parser.add_argument( + "-timeend", + type=int, + help="end time of the word cloud (in epoch time)", + default=calendar.timegm(time.gmtime()), +) +parser.add_argument( + "-timestart", + type=int, + help="start time of the word cloud (in epoch time)", + default=-1, +) -parser.add_argument('-bannedUsersFile', help='file containing list of banned users', default='/home/krowbar/Code/python/bannedUsers') -parser.add_argument('-bannedWordsFile', help='file containing list of banned words', default='/home/krowbar/Code/python/bannedWords') +parser.add_argument( + "-bannedUsersFile", + help="file containing list of banned users", + default="/home/krowbar/Code/python/bannedUsers", +) +parser.add_argument( + "-bannedWordsFile", + help="file containing list of banned words", + default="/home/krowbar/Code/python/bannedWords", +) -parser.add_argument('-minLength', type=int, help='minimum size of words to include in the cloud', default=3) -parser.add_argument('-minOccurrence', type=int, help='the minimum occurence of a word to include it in the cloud', default=3) +parser.add_argument( + "-minLength", + type=int, + help="minimum size of words to include in the cloud", + default=3, +) +parser.add_argument( + "-minOccurrence", + type=int, + help="the minimum occurence of a word to include it in the cloud", + default=3, +) args = parser.parse_args() -wordData = {} # keyed by "word" that contains a count -#we only care about recent chats, let's say for the past sixteen hours +wordData = {} # keyed by "word" that contains a count +# we only care about recent chats, let's say for the past sixteen hours -args.timestart = args.timestart if args.timestart != -1 else args.timeend - (16 * 60 * 60) -#timeCutoff = calendar.timegm(time.strptime("1 Oct 16", "%d %b %y")) -logging.info("Generating word cloud based off words from " + str(args.timestart) + " to " + str(args.timeend)) +args.timestart = ( + args.timestart if args.timestart != -1 else args.timeend - (16 * 60 * 60) +) +# timeCutoff = calendar.timegm(time.strptime("1 Oct 16", "%d %b %y")) +logging.info( + "Generating word cloud based off words from " + + str(args.timestart) + + " to " + + str(args.timeend) +) bannedWords = open(args.bannedWordsFile).read().splitlines() bannedUsers = open(args.bannedUsersFile).read().splitlines() @@ -41,27 +80,31 @@ with open(args.logfile, "r") as log: time, user, message = line.split("\t", 3) time = int(time) except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse + continue # There are some bad lines in the log file that we'll ignore if we can't parse if user in bannedUsers: - continue #We don't care what they say + continue # We don't care what they say if time >= args.timestart and time <= args.timeend: - #print "Processing line from " + user + " at " + str(time) - for word in re.sub('[\'\"\`\/\\;:,.?!*&^\-()<>\{\}|_\[\]0-9]', ' ', message).lower().split(): - #changing symbols into spaces instead of stripping them avoids compounded words + # print "Processing line from " + user + " at " + str(time) + for word in ( + re.sub("['\"\`\/\\;:,.?!*&^\-()<>\{\}|_\[\]0-9]", " ", message) + .lower() + .split() + ): + # changing symbols into spaces instead of stripping them avoids compounded words if len(word) < args.minLength or word in bannedWords: - #print "Rejecting " + word + # print "Rejecting " + word continue - #if the word already exists in the list + # if the word already exists in the list if word in wordData: wordData[word] += 1 - else: #if they are new + else: # if they are new wordData[word] = 1 - #print "Added word: " + word -wordData = {i:wordData[i] for i in wordData if wordData[i] >= args.minOccurrence } + # print "Added word: " + word +wordData = {i: wordData[i] for i in wordData if wordData[i] >= args.minOccurrence} if len(wordData) == 0: wordData = {"NOTHING": 1, "INTERESTING": 1, "TODAY": 1} -if args.outfile == '': - print json.dumps(wordData) +if args.outfile == "": + print(json.dumps(wordData)) else: with open(args.outfile + ".tmp", "w") as tmpFile: tmpFile.write(json.dumps(wordData)) diff --git a/Code/python/chatstack.py b/Code/python/chatstack.py index 2480acc..b4099af 100755 --- a/Code/python/chatstack.py +++ b/Code/python/chatstack.py @@ -6,10 +6,13 @@ import calendar import shutil logfile = "/home/archangelic/irc/log" -#logfile = "/home/jumblesale/Code/irc/log" +# logfile = "/home/jumblesale/Code/irc/log" outfile = "/home/krowbar/logs/chatStack.json" -chatData = { 'hours': [], 'regions': {} } #hash keyed by "region" and then hour that counts chat instances -#we only care about recent chats, let's say for the past couple weeks +chatData = { + "hours": [], + "regions": {}, +} # hash keyed by "region" and then hour that counts chat instances +# we only care about recent chats, let's say for the past couple weeks oneHour = 60 * 60 oneWeek = 7 * 24 * 60 * 60 timeNow = calendar.timegm(time.gmtime()) @@ -17,38 +20,50 @@ timeCutoff = calendar.timegm(time.gmtime()) - (2 * oneWeek) # this will eventually represent each region users are from def getAllRegions(): - return ['unknown'] + return ["unknown"] + # this will provide a way to look up what region a user is from def getRegion(user): - return 'unknown' + return "unknown" + # populate the hours array with time 1 hour away from each other startTime = timeCutoff while startTime < timeNow: - chatData['hours'].append(startTime) + chatData["hours"].append(startTime) startTime += oneHour # populate the regions array with blank data for each region for region in getAllRegions(): - chatData['regions'][region] = { 'name': region, 'values': [0] * len(chatData['hours']) } + chatData["regions"][region] = { + "name": region, + "values": [0] * len(chatData["hours"]), + } with open(logfile, "r") as log: - hourIdx = 0 # starting with the oldest time slot, we will count instances of user chatting + hourIdx = ( + 0 + ) # starting with the oldest time slot, we will count instances of user chatting for line in log: try: time, user, message = line.split("\t", 3) time = int(time) except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse + continue # There are some bad lines in the log file that we'll ignore if we can't parse if time > timeCutoff: region = getRegion(user) - while time > chatData['hours'][hourIdx] + oneHour: # we are past the current hour idx, move ahead until we find the right idx - hourIdx += 1; - if hourIdx >= len(chatData['hours']): - break; #uh oh! somehow we are parsing a line from the future! we're in pretty bad shape! + while ( + time > chatData["hours"][hourIdx] + oneHour + ): # we are past the current hour idx, move ahead until we find the right idx + hourIdx += 1 + if hourIdx >= len(chatData["hours"]): + break + # uh oh! somehow we are parsing a line from the future! we're in pretty bad shape! # hourIdx should now be a good value - chatData['regions'][region]['values'][hourIdx] += 1 # increment the user region's count for the current hour + chatData["regions"][region]["values"][ + hourIdx + ] += 1 # increment the user region's count for the current hour with open(outfile + ".tmp", "w") as tmpFile: tmpFile.write(json.dumps(chatData)) diff --git a/Code/python/chatstats.py b/Code/python/chatstats.py index 0b40f60..88d5b63 100755 --- a/Code/python/chatstats.py +++ b/Code/python/chatstats.py @@ -7,25 +7,25 @@ import shutil import re logfile = "/home/archangelic/irc/log" -#logfile = "/home/jumblesale/Code/irc/log" +# logfile = "/home/jumblesale/Code/irc/log" outfile = "/home/krowbar/logs/chatStats.json" -userData = {} #hash keyed by "user" that contains a start timestamp, last timestamp, last said string, chat count, letter count, and word count - #also now happy emotes and sad emotes +userData = {} # hash keyed by "user" that contains a start timestamp, last timestamp, last said string, chat count, letter count, and word count +# also now happy emotes and sad emotes rejectRegexp = "http[s]?://|[0-9]{2}[;:][0-9]{2}" happyRegexp = ":[-]?[])}]" sadRegexp = ":[-]?[[({]" nameFix = { - 'archangel': 'archangelic', - 'jumblesal': 'jumblesale', - 'hardmath1': 'kc', - 'hardmath123': 'kc', - 'bendorphan': 'endorphant', - 'endorphan': 'endorphant', - 'synergian': 'synergiance' - } + "archangel": "archangelic", + "jumblesal": "jumblesale", + "hardmath1": "kc", + "hardmath123": "kc", + "bendorphan": "endorphant", + "endorphan": "endorphant", + "synergian": "synergiance", +} with open(logfile, "r") as log: - lastUser = ""; + lastUser = "" currentStreak = 1 for line in log: try: @@ -36,66 +36,70 @@ with open(logfile, "r") as log: else: user = user.lower() except ValueError: - continue #There are some bad lines in the log file that we'll ignore if we can't parse + continue # There are some bad lines in the log file that we'll ignore if we can't parse if user in userData: - day = time / 86400 #seconds in a day - if userData[user]['startTime'] == 0: - userData[user]['startTime'] = time - if userData[user]['lastDay'] != day: - userData[user]['daysActive'] += 1 - userData[user]['lastDay'] = day + day = time / 86400 # seconds in a day + if userData[user]["startTime"] == 0: + userData[user]["startTime"] = time + if userData[user]["lastDay"] != day: + userData[user]["daysActive"] += 1 + userData[user]["lastDay"] = day if lastUser == user: currentStreak += 1 - if currentStreak > userData[user]['streak']: - userData[user]['streak'] = currentStreak + if currentStreak > userData[user]["streak"]: + userData[user]["streak"] = currentStreak else: currentStreak = 1 - if userData[user]['lastMention']: - resTime = time - userData[user]['lastMention'] - userData[user]['responseTime'] += min(resTime, 7200) #cap the value at 2hrs, things get skewed toward the high end otherwise - userData[user]['lastMention'] = 0 + if userData[user]["lastMention"]: + resTime = time - userData[user]["lastMention"] + userData[user]["responseTime"] += min( + resTime, 7200 + ) # cap the value at 2hrs, things get skewed toward the high end otherwise + userData[user]["lastMention"] = 0 - userData[user]['endTime'] = time - #userData[user]['lastSaid'] = message - userData[user]['lineCount'] += 1 - userData[user]['wordCount'] += len(message.split()) - userData[user]['charCount'] += len(message) - else: #if they are new + userData[user]["endTime"] = time + # userData[user]['lastSaid'] = message + userData[user]["lineCount"] += 1 + userData[user]["wordCount"] += len(message.split()) + userData[user]["charCount"] += len(message) + else: # if they are new userData[user] = {} - userData[user]['startTime'] = time - userData[user]['endTime'] = time - #userData[user]['lastSaid'] = message - userData[user]['lineCount'] = 1 - userData[user]['wordCount'] = len(message.split()) - userData[user]['charCount'] = len(message) - userData[user]['daysActive'] = 1 - userData[user]['lastDay'] = time / 86400 - userData[user]['streak'] = 1 - userData[user]['mentions'] = 0 - userData[user]['lastMention'] = 0 - userData[user]['responseTime'] = 0 - userData[user]['botUse'] = 0 - userData[user]['happyEmotes'] = 0 - userData[user]['sadEmotes'] = 0 + userData[user]["startTime"] = time + userData[user]["endTime"] = time + # userData[user]['lastSaid'] = message + userData[user]["lineCount"] = 1 + userData[user]["wordCount"] = len(message.split()) + userData[user]["charCount"] = len(message) + userData[user]["daysActive"] = 1 + userData[user]["lastDay"] = time / 86400 + userData[user]["streak"] = 1 + userData[user]["mentions"] = 0 + userData[user]["lastMention"] = 0 + userData[user]["responseTime"] = 0 + userData[user]["botUse"] = 0 + userData[user]["happyEmotes"] = 0 + userData[user]["sadEmotes"] = 0 - lastUser = user; - if message.rstrip() and message[0] == '!': - userData[user]['botUse'] += 1 + lastUser = user + if message.rstrip() and message[0] == "!": + userData[user]["botUse"] += 1 if not re.search(rejectRegexp, message): if re.search(happyRegexp, message): - userData[user]['happyEmotes'] += 1 + userData[user]["happyEmotes"] += 1 if re.search(sadRegexp, message): - userData[user]['sadEmotes'] += 1 + userData[user]["sadEmotes"] += 1 try: - if message.rstrip() and message.split()[0][-1] == ':': #last character of first word + if ( + message.rstrip() and message.split()[0][-1] == ":" + ): # last character of first word name = message.split()[0][0:-1] if user != name and userData.has_key(name): - userData[name]['mentions'] += 1 - if not userData[name]['lastMention']: - userData[name]['lastMention'] = time + userData[name]["mentions"] += 1 + if not userData[name]["lastMention"]: + userData[name]["lastMention"] = time except IndexError: - print '##' + message + '##' + print("##" + message + "##") continue diff --git a/Code/python/mfp_watcher.py b/Code/python/mfp_watcher.py index 65ba610..eea3a77 100644 --- a/Code/python/mfp_watcher.py +++ b/Code/python/mfp_watcher.py @@ -1,4 +1,6 @@ import urllib from bs4 import BeautifulSoup + def get_track(): + pass diff --git a/Code/python/randomwords.py b/Code/python/randomwords.py index 1e56466..4f4802a 100755 --- a/Code/python/randomwords.py +++ b/Code/python/randomwords.py @@ -4,26 +4,45 @@ import random import sys import argparse -parser = argparse.ArgumentParser(description='Print some random dictionary words.') -parser.add_argument('-d', dest='dictionary', metavar='DICT', - help='supply a dictionary', default='/usr/share/dict/american-english-large') -parser.add_argument('-c', dest='count', type=int, - help='specify how many words you want per line', default=10) -parser.add_argument('-l', dest='lines', type=int, - help='specify how many lines of random words you want', default=1) -parser.add_argument('--no-appos', action='store_true', - help='remove words with appostrophes') -parser.add_argument('--no-proper', action='store_true', - help='remove words that start with a capital letter') +parser = argparse.ArgumentParser(description="Print some random dictionary words.") +parser.add_argument( + "-d", + dest="dictionary", + metavar="DICT", + help="supply a dictionary", + default="/usr/share/dict/american-english-large", +) +parser.add_argument( + "-c", + dest="count", + type=int, + help="specify how many words you want per line", + default=10, +) +parser.add_argument( + "-l", + dest="lines", + type=int, + help="specify how many lines of random words you want", + default=1, +) +parser.add_argument( + "--no-appos", action="store_true", help="remove words with appostrophes" +) +parser.add_argument( + "--no-proper", + action="store_true", + help="remove words that start with a capital letter", +) args = parser.parse_args() -#print args +# print args with open(args.dictionary, "r") as wordsfile: words = wordsfile.readlines() - if(args.no_appos): - words[:] = [word for word in words if word.find('\'') == -1] - if(args.no_proper): + if args.no_appos: + words[:] = [word for word in words if word.find("'") == -1] + if args.no_proper: words[:] = [word for word in words if not word[0].isupper()] for _ in range(0, args.lines): - print ' '.join([w.strip("\n") for w in random.sample(words, args.count)]) + print(" ".join([w.strip("\n") for w in random.sample(words, args.count)])) From 99cf1c582221d2143b09641b4fd005287aa5dbdc Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 8 Oct 2018 17:19:07 -0400 Subject: [PATCH 3/5] format strings and server:port connections --- Code/irc/banterbot.py | 217 +++++++++------------------- Code/irc/get_users.py | 13 -- Code/irc/madlibbot/madlibbot.py | 21 +-- Code/irc/names.py | 16 --- Code/irc/pretty_date.py | 43 ------ Code/irc/quote_bot.py | 56 ++------ Code/irc/rainbow.py | 19 --- Code/irc/run_wang.sh | 2 +- Code/irc/systemd/tildebot.service | 2 +- Code/irc/tildebot.py | 73 +++------- Code/irc/util.py | 49 ++++++- Code/irc/wangbot.py | 229 +++++++++++------------------- Code/irc/whosaid.py | 4 +- Code/python/chatbesties.py | 4 +- Code/python/chatstats.py | 4 +- 15 files changed, 241 insertions(+), 511 deletions(-) delete mode 100644 Code/irc/get_users.py delete mode 100644 Code/irc/names.py delete mode 100644 Code/irc/pretty_date.py delete mode 100644 Code/irc/rainbow.py diff --git a/Code/irc/banterbot.py b/Code/irc/banterbot.py index ce16a9f..9c48ed0 100755 --- a/Code/irc/banterbot.py +++ b/Code/irc/banterbot.py @@ -13,10 +13,6 @@ import subprocess import time import datetime -import formatter -import get_users -import mentions -import pretty_date import inflect from rhymesWith import getRhymes from rhymesWith import rhymeZone @@ -37,7 +33,7 @@ parser.add_option( "-s", "--server", dest="server", - default="127.0.0.1", + default="127.0.0.1:6667", help="the server to connect to", metavar="SERVER", ) @@ -63,20 +59,12 @@ parser.add_option( p = inflect.engine() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) - - -def sendmsg(chan, msg): - ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") - - def joinchan(chan): - ircsock.send("JOIN " + chan + "\n") + ircsock.send("JOIN " + chan + "\r\n") def hello(): - ircsock.send("PRIVMSG " + channel + " :Hello!\n") + util.sendmsg(ircsoc, channel, "Hello!") def score_banter(channel, user, messageText): @@ -109,42 +97,27 @@ def score_banter(channel, user, messageText): msg = "" if score > 100: - msg = ( - "Truely " - + random.choice(compliment).capitalize() - + ", " - + random.choice(names) - + "! That was some #banter! You earned a " - + str(score) - + " for that!" + msg = "Truely {}, {}! That was some #banter! You earned a {} for that!".format( + random.choice(compliment).capitalize(), random.choice(names), score ) elif score > 50: - msg = ( - random.choice(compliment).capitalize() - + " #banter! You get a " - + str(score) - + " from me!" + msg = "{} #banter! You get a {} from me!".format( + random.choice(compliment).capitalize(), score ) elif score > 10: - msg = ( - random.choice(["acceptible", "reasonable", "passable"]).capitalize() - + " #banter. You get a " - + str(score) + msg = "{} #banter. You get a {}".format( + random.choice(["acceptible", "reasonable", "passable"]).capitalize(), score ) else: - msg = ( - "That " - + random.choice( + msg = "That {} #banter, {}. I'll give you a {}. Maybe try again?".format( + random.choice( ["was hardly", "was barely", "wasn't", "won't pass for", "was awful"] - ) - + " #banter" - + random.choice([", lad", ", lah", ", boy", "", ""]) - + ". I'll give you a " - + str(score) - + ". Maybe try again?" + ), + random.choice(["lad", "lah", "boy", ""]), + score, ) - ircsock.send("PRIVMSG " + channel + " :" + msg + "\n") + util.sendmsg(ircsock, channel, msg) def get_new_banter(channel, user): @@ -174,14 +147,8 @@ def get_new_banter(channel, user): word = word[:end] + "t" + word[end:] else: # replace the letter with 'b' word = word[:end] + "t" + word[end + 1 :] - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": Here, why don't you try '" - + word - + "'?\n" + util.sendmsg( + ircsock, channel, "{} : Here, why don't you try '{}'?".format(user, word) ) @@ -194,26 +161,18 @@ def get_rhymes(channel, user, text): word = random.choice(words.readlines()).strip("\n") rhymes = rhymeZone(word) if len(rhymes) == 0: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": Couldn't find anything that rhymes with '" - + word - + "' :(\n" + util.sendmsg( + ircsock, + channel, + "{}: Couldn't find anything that rhymes with '{}' :(".format(user, word), ) else: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": Here, these words rhyme with '" - + word - + "': " - + ", ".join(rhymes) - + "\n" + util.sendmsg( + ircsock, + channel, + "{}: Here, these words rhyme with '{}': {}".format( + user, word, ", ".join(rhymes) + ), ) @@ -224,68 +183,48 @@ def define_word(channel, user, text): word = text.split(" ")[1] defs = defWord(word) if len(defs) == 0: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": Couldn't find the definition of '" - + word - + "' :(\n" + util.sendmsg( + ircsock, + channel, + "{}: Couldn't find the definition of '{}' :(".format(user, word), ) elif isinstance(defs, list): for entry in defs: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": Define '" - + word - + "'" - + entry[0:400] - + "\n" + util.sendmsg( + ircsock, channel, "{} : Define '{}' {}".format(user, word, entry[0:400]) ) else: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": Define '" - + word - + "'" - + defs[0:400] - + "\n" + util.sendmsg( + ircsock, channel, "{} : Define '{}' {}".format(user, word, defs[0:400]) ) def make_rainbow(channel, user, text): rbword = makeRainbow(text[9:]) - ircsock.send("PRIVMSG " + channel + " :" + rbword + "\n") + util.sendmsg(ircsock, channel, rbword) def get_welch(channel): - ircsock.send("PRIVMSG " + channel + " :" + welch.get_thing()[0:400] + "\n") + util.sendmsg(ircsock, channel, welch.get_thing()[0:400]) def get_evil(channel): evilThing = evil.get_thing() for line in [evilThing[i : i + 400] for i in range(0, len(evilThing), 400)]: - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + util.sendmsg(ircsock, channel, line) def get_tumble(url, channel): tumble = tumblr.tumble(url) for line in [tumble[i : i + 400] for i in range(0, len(tumble), 400)]: - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + util.sendmsg(ircsock, channel, line) def get_xkcd(channel, text): links = xkcdApropos.xkcd(text[6:]) joined_links = ", ".join(links) for line in [joined_links[i : i + 400] for i in range(0, len(joined_links), 400)]: - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + util.sendmsg(ircsock, channel, line) # res = xkcdApropos.xkcd(text[6:]) # ircsock.send("PRIVMSG " + channel + " :" + res + "\n") @@ -293,12 +232,8 @@ def get_xkcd(channel, text): def get_wphilosophy(channel, text): steps = wikiphilosophy.get_philosophy_lower(text[17:]) if not steps: - ircsock.send( - "PRIVMSG " - + channel - + " :Couldn't find a wikipedia entry for " - + text - + "\n" + util.sendmsg( + ircsock, channel, "Couldn't find a wikipedia entry for {}".format(text) ) else: joined_steps = " > ".join(steps) @@ -307,24 +242,24 @@ def get_wphilosophy(channel, text): for line in [ joined_steps[i : i + 400] for i in range(0, len(joined_steps), 400) ]: - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + util.sendmsg(ircsock, channel, line) def figlet(channel, text): if not text: - ircsock.send("PRIVMSG " + channel + " :No text given. :(\n") + util.sendmsg(ircsock, channel, "No text given. :(") else: lines = subprocess.Popen( ["figlet", "-w140"] + text.split(" "), shell=False, stdout=subprocess.PIPE ).stdout.read() for line in lines.split("\n"): - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + util.sendmsg(ircsock, channel, line) time.sleep(0.4) # to avoid channel throttle due to spamming def toilet(channel, text): if not text: - ircsock.send("PRIVMSG " + channel + " :No text given. :(\n") + util.sendmsg(ircsock, channel, "No text given. :(") else: lines = subprocess.Popen( ["toilet", "-w140", "--irc"] + text.split(" "), @@ -332,24 +267,24 @@ def toilet(channel, text): stdout=subprocess.PIPE, ).stdout.read() for line in lines.split("\n"): - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + util.sendmsg(ircsock, channel, line) time.sleep(0.4) # to avoid channel throttle due to spamming def get_acronym(channel, text): if not text: - ircsock.send("PRIVMSG " + channel + " :No text given :(\n") + util.sendmsg(ircsock, channel, "No text given :(") else: defs = acronymFinder.get_acros(text, True, True) for d in defs[0:5]: # only the first five. they are already sorted by 'score' - ircsock.send("PRIVMSG " + channel + " :" + d.encode("utf-8") + "\n") + util.sendmsg(ircsock, channel, d.encode("utf-8")) if len(defs) > 5: - ircsock.send("PRIVMSG " + channel + " :" + defs[-1] + "\n") + util.sendmsg(ircsock, channel, defs[-1]) def get_whosaid(channel, text): if not text: - ircsock.send("PRIVMSG " + channel + " :No text given :(\n") + util.sendmsg(ircsock, channel, " :No text given :(") else: result = whoSaid(text) date = datetime.date.fromtimestamp(result["timecutoff"]) @@ -368,46 +303,37 @@ def get_whosaid(channel, text): result["data"][1][0], result["data"][1][1], ) - ircsock.send("PRIVMSG " + channel + " :" + msg + ".\n") + util.sendmsg(ircsock, channel, msg) def get_notice(user, channel): - ircsock.send("CNOTICE " + user + " " + channel + " :Notice me sempai!\n") + ircsock.send("CNOTICE " + user + " " + channel + " :Notice me senpai!\r\n") def get_water(user, channel, msg, botnick): if msg.find(botnick) == 0: - ircsock.send("PRIVMSG " + channel + " :Fight me, " + user + "!\n") + util.sendmsg(ircsock, channel, "Fight me, {}!".format(user)) def mug_off(channel): - ircsock.send("PRIVMSG " + channel + " :u want some of this, m8?\n") + util.sendmsg(ircsock, channel, "u want some of this, m8?") def rollcall(channel): - ircsock.send( - "PRIVMSG " - + channel - + " :U wot m8? I score all the top drawer #banter and #bantz on this channel! \ - Find new top-shelf banter with !newbanter, !rhymes, and !define. \ - Look up things with !acronym and !whosaid. \ - Make your chatter #legend with !rainbow, !toilet, and !figlet. \ - Find interesting things with !xkcd and !wiki-philosophy. \ - Get jokes with !welch and !evil\n" + util.sendmsg( + ircsock, + channel, + """ + U wot m8? I score all the top drawer #banter and #bantz on this channel! + Find new top-shelf banter with !newbanter, !rhymes, and !define. + Look up things with !acronym and !whosaid. + Make your chatter #legend with !rainbow, !toilet, and !figlet. + Find interesting things with !xkcd and !wiki-philosophy. + Get jokes with !welch and !evil + """, ) -def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send( - "USER " + botnick + " " + botnick + " " + botnick + " :krowbar\n" - ) # user authentication - ircsock.send("NICK " + botnick + "\n") - - joinchan(channel) - joinchan("#bots") - - def get_user_from_message(msg): try: i1 = msg.index(":") + 1 @@ -433,12 +359,7 @@ def listen(botnick): # print formatted - split = formatted.split("\t") - # time = split[0] - user = split[1] - command = split[2] - channel = split[3] - messageText = split[4] + time, user, command, channel, messageText = formatted.split("\t") if ircmsg.find("#banter") != -1 or ircmsg.find("#bantz") != -1: score_banter(channel, user, messageText) @@ -497,12 +418,12 @@ def listen(botnick): mug_off(channel) if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + util.ping(ircsock, msg) sys.stdout.flush() time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -connect(options.server, options.channel, options.nick) +util.connect(ircsock, options) listen(options.nick) diff --git a/Code/irc/get_users.py b/Code/irc/get_users.py deleted file mode 100644 index 32a7381..0000000 --- a/Code/irc/get_users.py +++ /dev/null @@ -1,13 +0,0 @@ -# Return a list of users on this system - - -def get_users(): - # thanks, ~dan! - users = [] - with open("/etc/passwd", "r") as f: - for line in f: - if "/bin/bash" in line: - u = line.split(":")[0] # Grab all text before first ':' - users.append(u) - - return users diff --git a/Code/irc/madlibbot/madlibbot.py b/Code/irc/madlibbot/madlibbot.py index 5f6934e..bfc685a 100755 --- a/Code/irc/madlibbot/madlibbot.py +++ b/Code/irc/madlibbot/madlibbot.py @@ -41,7 +41,7 @@ parser.add_option( "-s", "--server", dest="server", - default="127.0.0.1", + default="127.0.0.1:6667", help="the server to connect to", metavar="SERVER", ) @@ -223,14 +223,6 @@ def finish_story(channel): # System things -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) - - -def sendmsg(chan, msg): - ircsock.send("PRIVMSG {} :{}\n".format(chan, msg)) - - def joinchan(chan): global state state[chan] = State.idle @@ -258,15 +250,6 @@ def rollcall(channel, botnick): ) -def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send( - "USER {} {} {} :krowbar\n".format(botnick, botnick, botnick) - ) # user authentication - ircsock.send("NICK {}\n".format(botnick)) - joinchan(channel) - - def listen(botnick): botmsgre = re.compile( "^{}\:?\s*(.*)$".format(botnick) @@ -304,5 +287,5 @@ def listen(botnick): ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -connect(options.server, options.channel, options.nick) +util.connect(ircsock, options) listen(options.nick) diff --git a/Code/irc/names.py b/Code/irc/names.py deleted file mode 100644 index 89be86a..0000000 --- a/Code/irc/names.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/python -import json - -names_file = "/home/jumblesale/Code/canonical_names/canonical_names.json" - - -def get_name(name): - try: - with open(names_file) as names_data: - names = json.load(names_data) - try: - return names[name]["userName"] - except KeyError: - return name - except IOError: - return name # if we didn't already diff --git a/Code/irc/pretty_date.py b/Code/irc/pretty_date.py deleted file mode 100644 index 80a8966..0000000 --- a/Code/irc/pretty_date.py +++ /dev/null @@ -1,43 +0,0 @@ -def pretty_date(time=False): - """ - Get a datetime object or a int() Epoch timestamp and return a - pretty string like 'an hour ago', 'Yesterday', '3 months ago', - 'just now', etc - """ - from datetime import datetime - - now = datetime.now() - if type(time) is int: - diff = now - datetime.fromtimestamp(time) - elif isinstance(time, datetime): - diff = now - time - elif not time: - diff = now - now - second_diff = diff.seconds - day_diff = diff.days - - if day_diff < 0: - return "" - - if day_diff == 0: - if second_diff < 10: - return "just now" - if second_diff < 60: - return str(second_diff) + " seconds ago" - if second_diff < 120: - return "a minute ago" - if second_diff < 3600: - return str(second_diff / 60) + " minutes ago" - if second_diff < 7200: - return "an hour ago" - if second_diff < 86400: - return str(second_diff / 3600) + " hours ago" - if day_diff == 1: - return "Yesterday" - if day_diff < 7: - return str(day_diff) + " days ago" - if day_diff < 31: - return str(day_diff / 7) + " weeks ago" - if day_diff < 365: - return str(day_diff / 30) + " months ago" - return str(day_diff / 365) + " years ago" diff --git a/Code/irc/quote_bot.py b/Code/irc/quote_bot.py index f17f8f5..af36fad 100755 --- a/Code/irc/quote_bot.py +++ b/Code/irc/quote_bot.py @@ -7,9 +7,7 @@ import os import sys from optparse import OptionParser -import get_users -import mentions -import formatter +import util parser = OptionParser() @@ -17,7 +15,7 @@ parser.add_option( "-s", "--server", dest="server", - default="127.0.0.1", + default="127.0.0.1:6667", help="the server to connect to", metavar="SERVER", ) @@ -41,48 +39,16 @@ parser.add_option( (options, args) = parser.parse_args() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) - - -def sendmsg(chan, msg): - ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") - - -def joinchan(chan): - ircsock.send("JOIN " + chan + "\n") - - -def hello(): - ircsock.send("PRIVMSG " + channel + " :Hello!\n") - - def random_quote(channel): quote = os.popen("/home/frs/quotes/randquote.py").read() if len(quote) >= 256: quote = quote[:253] + "..." - ircsock.send("PRIVMSG " + channel + " :" + quote + "\n") + util.sendmsg(ircsock, channel, quote) def haiku(channel): h = os.popen("haiku").read().replace("\n", " // ") - ircsock.send("PRIVMSG " + channel + " :" + h + "\n") - - -def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send( - "USER " - + botnick - + " " - + botnick - + " " - + botnick - + " :This bot is a result of a tutoral covered on http://shellium.org/wiki.\n" - ) # user authentication - ircsock.send("NICK " + botnick + "\n") - - joinchan(channel) + util.sendmsg(ircsock, channel, h) def get_user_from_message(msg): @@ -114,7 +80,7 @@ def say_chatty(channel): chattyOut = os.popen("/home/karlen/bin/chatty").read().split("\n") for line in chattyOut: if line: - ircsock.send("PRIVMSG " + channel + " :" + line + "\n") + util.sendmsg(ircsock, channel, line) def listen(): @@ -123,20 +89,14 @@ def listen(): ircmsg = ircsock.recv(2048) ircmsg = ircmsg.strip("\n\r") - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) - - formatted = formatter.format_message(ircmsg) + formatted = util.format_message(ircmsg) if "" == formatted: continue print(formatted) - split = formatted.split("\t") - time = split[0] - user = split[1] - messageText = split[2] + time, user, messageText = formatted.split("\t") if ircmsg.find(":!quote") != -1: random_quote(options.channel) @@ -158,5 +118,5 @@ def listen(): ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -connect(options.server, options.channel, options.nick) +util.connect(ircsock, options) listen() diff --git a/Code/irc/rainbow.py b/Code/irc/rainbow.py deleted file mode 100644 index f439bb6..0000000 --- a/Code/irc/rainbow.py +++ /dev/null @@ -1,19 +0,0 @@ -import random - - -def makeRainbow(word): - - word = word or "RAINBOW" - output = "" - rb = ["5", "7", "8", "3", "12", "13", "6"] - bg = "01" - idx = random.randrange(0, len(rb)) - - for l in word: - if l == " ": - output += " " - else: - output += "\x03" + rb[idx % len(rb)] + "," + bg + l - idx += 1 - - return output diff --git a/Code/irc/run_wang.sh b/Code/irc/run_wang.sh index ccc8658..6dd82ac 100755 --- a/Code/irc/run_wang.sh +++ b/Code/irc/run_wang.sh @@ -1,4 +1,4 @@ #!/bin/bash -nohup ./wangbot.py -s 127.0.0.1 -n numberwang_bot -c \#bots >> wanglog 2>> wanglog & +nohup ./wangbot.py -n numberwang_bot -c \#bots >> wanglog 2>> wanglog & #nohup ./wangbot.py -s 127.0.0.1 -n numberwang_bot -c \#bot_test >> wanglog 2>> wanglog & diff --git a/Code/irc/systemd/tildebot.service b/Code/irc/systemd/tildebot.service index 75b1cf0..d44a791 100644 --- a/Code/irc/systemd/tildebot.service +++ b/Code/irc/systemd/tildebot.service @@ -4,7 +4,7 @@ After=tildebot.service [Service] Type=simple -ExecStart=/home/krowbar/Code/irc/tildebot.py -s 127.0.0.1 -n tildebot -c \#tildetown +ExecStart=/home/krowbar/Code/irc/tildebot.py -n tildebot -c \#tildetown WorkingDirectory=/home/krowbar/Code/irc/ Restart=always RestartSec=5 diff --git a/Code/irc/tildebot.py b/Code/irc/tildebot.py index 1b61938..7ce279b 100755 --- a/Code/irc/tildebot.py +++ b/Code/irc/tildebot.py @@ -10,11 +10,6 @@ from optparse import OptionParser import fileinput import random -import formatter -import get_users -import names -import mentions -import pretty_date import inflect import puzzle import util @@ -25,7 +20,7 @@ parser.add_option( "-s", "--server", dest="server", - default="127.0.0.1", + default="127.0.0.1:6667", help="the server to connect to", metavar="SERVER", ) @@ -56,10 +51,6 @@ JACKPOT_MIN = 3 DEBUG = False -def hello(): - util.sendmsg(ircsock, channel, "Hello!") - - def too_recent(time1, time2): return int(time1) - int(time2) < 60 * 60 @@ -197,14 +188,12 @@ def get_prize(name, isHuman, bonus=0): ): # 80% of the time it's a normal prize (40% for not humans) return [ prize, - name - + ": " - + (get_positive() if isHuman else get_negative()) - + "! You are " - + get_superlative(prize) - + " and get " - + p.number_to_words(prize) - + " tildes!", + "{}: {}! You are {} and get {} tildes!".format( + name, + (get_positive() if isHuman else get_negative), + get_superlative(prize), + p.number_to_words(prize), + ), ] else: # 20% of the time its a jackpot situation with open(JACKPOT_FILE, "r+") as jackpotfile: @@ -220,21 +209,17 @@ def get_prize(name, isHuman, bonus=0): ) # increase the jackpot by the prize size return [ 0, - name - + " " - + get_bad_thing() - + " and gets no tildes! (Jackpot is now " - + str(new_jackpot) - + " tildes)", + "{} {} and gets no tildes! (Jackpot is now {} tildes)".format( + name, get_bad_thing(), new_jackpot + ), ] else: # hit jackpot! jackpotfile.write(str(JACKPOT_MIN)) return [ jackpot, - name - + " hit the jackpot and won **" - + p.number_to_words(jackpot) - + " tildes!**", + "{} hit the jackpot and won **{}**".format( + name, p.number_to_words(jackpot) + ), ] @@ -268,13 +253,8 @@ def give_tilde(channel, user, name, time, human, bonus=0): ) else: prize = get_prize(name, human, bonus) - score = ( - person[0] - + "&^%" - + str(int(person[1]) + prize[0]) - + "&^%" - + time - + "\n" + score = "{}&^%{}&^%{}\n".format( + person[0], int(person[1] + prize[0]), time ) util.sendmsg(ircsock, channel, prize[1]) scorefile.write(score) @@ -287,7 +267,7 @@ def give_tilde(channel, user, name, time, human, bonus=0): p.number_to_words(prize[0] + 1) ), ) - scorefile.write(user + "&^%" + str(prize[0] + 1) + "&^%" + time + "\n") + scorefile.write("{}&^%{}&^%{}\n".format(user, str(prize[0] + 1), time)) def show_tildescore(channel, user, name): @@ -344,7 +324,8 @@ def rollcall(channel): def connect(server, channel, botnick): - ircsock.connect((server, 6667)) + server, port = server.split(":") + ircsock.connect((server, port)) ircsock.send("USER {0} {0} {0} :krowbar\r\n".format(botnick)) # user authentication ircsock.send("NICK {}\r\n".format(botnick)) ircsock.send("MODE +B {}\r\n".format(botnick)) @@ -372,21 +353,17 @@ def listen(): if msg[:4] == "PING": util.ping(ircsock, msg) + continue - formatted = formatter.format_message(msg) + formatted = util.format_message(msg) if "" == formatted: continue # print formatted - split = formatted.split("\t") - iTime = split[0] - user = split[1] - name = names.get_name(user) - command = split[2] - channel = split[3] - messageText = split[4] + iTime, user, command, channel, messageText = formatted.split("\t") + name = util.get_name(user) if msg.find(":!tildescore") != -1: show_tildescore(channel, user, name) @@ -394,7 +371,6 @@ def listen(): challenge(channel, user, name, iTime) elif challenges.has_key(user) and (channel == "#bots" or DEBUG): challenge_response(channel, user, name, iTime, messageText) - # give_tilde(channel, user, name, iTime) if msg.find(":!jackpot") != -1: show_jackpot(channel) @@ -402,13 +378,10 @@ def listen(): if msg.find(":!rollcall") != -1: rollcall(channel) - if msg[:4] == "PING": - util.ping(ircsock, msg) - sys.stdout.flush() time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -connect(options.server, options.channel, options.nick) +util.connect(ircsock, options) listen() diff --git a/Code/irc/util.py b/Code/irc/util.py index f8e4ad3..96dceee 100644 --- a/Code/irc/util.py +++ b/Code/irc/util.py @@ -1,7 +1,13 @@ +import json import time +import random import re +def hello(ircsock, chan): + sendmsg(ircsock, chan, "Hello!") + + def ping(pong): ircsock.send("PONG {}\n".format(pong.split(" ")[1])) @@ -11,7 +17,17 @@ def sendmsg(ircsock, chan, msg): def joinchan(ircsock, chan): - ircsock.send("JOIN {}\n".format(chan)) + ircsock.send("JOIN {}\r\n".format(chan)) + + +def connect(ircsock, options): + server, channel, botnick = options + server, port = server.split(":") + ircsock.connect((server, port)) + ircsock.send("USER {0} {0} {0} :krowbar".format(botnick)) + ircsock.send("NICK {}\r\n".format(botnick)) + ircsock.send("MODE +B {}\r\n".format(botnick)) + joinchan(channel) # integer number to english word conversion @@ -158,6 +174,19 @@ def get_users(): return users +def get_name(name): + names_file = "/home/jumblesale/Code/canonical_names/canonical_names.json" + try: + with open(names_file) as names_data: + names = json.load(names_data) + try: + return names[name]["userName"] + except KeyError: + return name + except IOError: + return name # if we didn't already + + def pretty_date(time=False): """ Get a datetime object or a int() Epoch timestamp and return a @@ -201,3 +230,21 @@ def pretty_date(time=False): if day_diff < 365: return str(day_diff / 30) + " months ago" return str(day_diff / 365) + " years ago" + + +def makeRainbow(word): + + word = word or "RAINBOW" + output = "" + rb = ["5", "7", "8", "3", "12", "13", "6"] + bg = "01" + idx = random.randrange(0, len(rb)) + + for l in word: + if l == " ": + output += " " + else: + output += "\x03" + rb[idx % len(rb)] + "," + bg + l + idx += 1 + + return output diff --git a/Code/irc/wangbot.py b/Code/irc/wangbot.py index ad32d31..8249cd2 100755 --- a/Code/irc/wangbot.py +++ b/Code/irc/wangbot.py @@ -12,11 +12,8 @@ import time import re import operator -import formatter -import get_users -import mentions -import pretty_date import inflect +import util parser = OptionParser() @@ -24,7 +21,7 @@ parser.add_option( "-s", "--server", dest="server", - default="127.0.0.1", + default="127.0.0.1:6667", help="the server to connect to", metavar="SERVER", ) @@ -75,64 +72,41 @@ def resetGlobals(): currentScores.clear() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) - - -def sendmsg(chan, msg): - ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") - - -def joinchan(chan): - ircsock.send("JOIN " + chan + "\n") - - -def hello(): - ircsock.send("PRIVMSG " + channel + " :Hello!\n") - - def start_numberwang(channel, user): if channel != "#bots": - ircsock.send( - "PRIVMSG " - + channel - + " :Numberwang has been disabled for " - + channel - + " due to spamminess. Please join " - + GOOD_CHAN - + " to start a game.\n" + util.sendmsg( + ircsock, + channel, + "Numberwang has been disabled in {} due to spamminess. Please join {} to start a game.".format( + channel, GOOD_CHAN + ), ) return print(user + " started a game") resetGlobals() - ircsock.send("PRIVMSG " + channel + " :It's time for Numberwang!\n") + util.sendmsg(ircsock, channel, "It's time for Numberwang!") time.sleep(1) - ircsock.send("PRIVMSG " + channel + " :Here's how to play:\n") + util.sendmsg(ircsock, channel, "Here's how to play:") - ircsock.send("PRIVMSG " + channel + " :1. There are 10 rounds\n") - ircsock.send( - "PRIVMSG " - + channel - + " :2. Each round lasts 10 seconds. You're up against the clock!\n" + util.sendmsg(ircsock, channel, "1. There are 10 rounds") + util.sendmsg( + ircsock, channel, "2. Each round lasts 10 seconds. You're up against the clock!" ) - ircsock.send( - "PRIVMSG " - + channel - + " :3. Play your numbers, as long as they're between 0 and 99.\n" + util.sendmsg( + ircsock, channel, "3. Play your numbers, as long as they're between 0 and 99." ) - ircsock.send("PRIVMSG " + channel + " :4. That's Numberwang!\n") + util.sendmsg(ircsock, channel, "4. That's Numberwang!") time.sleep(2) - ircsock.send("PRIVMSG " + channel + " :Let's get started!\n") + util.sendmsg(ircsock, channel, "Let's get started!") global roundsLeft global bonusRound roundsLeft = random.randint(MIN_ROUNDS, MAX_ROUNDS) bonusRound = random.randint(2, roundsLeft - 1) print( - "There will be " - + str(roundsLeft) - + " rounds with the bonus on round " - + str(roundsLeft - bonusRound + 1) + "There will be {} rounds with the bonus on round {}".format( + str(roundsLeft), str(roundsLeft - bonusRound + 1) + ) ) @@ -141,14 +115,14 @@ def print_scores(channel): first = True for name in currentScores: scoreStrs.append( - name - + " is " - + ("also " if not first and random.randint(1, 3) == 3 else "") - + "on " - + str(currentScores[name]) + "{} is {} on {}".format( + name, + ("also " if not first and random.randint(1, 3) == 3 else ""), + currentScores[name], + ) ) first = False - ircsock.send("PRIVMSG " + channel + " :" + p.join(scoreStrs) + "!\n") + util.sendmsg(ircsock, channel, p.join(scoreStrs)) def guess_numberwang(channel, user, messageText): @@ -162,12 +136,10 @@ def guess_numberwang(channel, user, messageText): ) # must have a number in the first 'word' if guess: if LIMIT_GUESSING and user == lastGuesser: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ", you just guessed! Give another player a try!\n" + util.sendmsg( + ircsock, + channel, + "{}, you just guessed! Give another player a try!".format(user), ) else: guesses += 1 @@ -178,9 +150,7 @@ def guess_numberwang(channel, user, messageText): ): # the more guesses, the higher the probability guesses = 0 lastGuesser = "" - ircsock.send( - "PRIVMSG " + channel + " :" + user + ": THAT'S NUMBERWANG!\n" - ) + util.sendmsg(ircsock, channel, "{}: THAT'S NUMBERWANG!".format(user)) points = random.randint(2, 10) * ( random.randint(2, 4) if roundsLeft == bonusRound else 1 ) @@ -191,12 +161,12 @@ def guess_numberwang(channel, user, messageText): roundsLeft -= 1 time.sleep(2) if roundsLeft == 0: - ircsock.send( - "PRIVMSG " - + channel - + " :Numberwang is now over. Thank you for playing!\n" + util.sendmsg( + ircsock, + channel, + "Numberwang is now over. Thank you for playing!", ) - ircsock.send("PRIVMSG " + channel + " :Final scores:\n") + util.sendmsg(ircsock, channel, "Final scores:") print_scores(channel) save_scores() else: @@ -210,43 +180,41 @@ def guess_numberwang(channel, user, messageText): newRoundStr += "New Round!" if random.randint(1, 10) > 8: newRoundStr += " Let's rotate the board!" - ircsock.send( - "PRIVMSG " + channel + " :" + newRoundStr + " Start guessing!\n" + util.sendmsg( + ircsock, channel, "{} Start guessing!".format(newRoundStr) ) ###INCORRECT GUESS### else: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + random.choice(["Sorry", "I'm sorry", "No", "Nope"]) - + ", " - + user - + ", " - + random.choice( - [ - "that's not", - "that is not", - "that isn't", - "that is not", - "that won't make", - "that will not make", - ] - ) - + " Numberwang!\n" + util.sendmsg( + ircsock, + channel, + "{}, {}, {} Numberwang!".format( + random.choice(["Sorry", "I'm sorry", "No", "Nope"]), + user, + random.choice( + [ + "that's not", + "that is not", + "that isn't", + "that is not", + "that won't make", + "that will not make", + ] + ), + ), ) def stop_numberwang(channel, user): print(user + " stopped a game") resetGlobals() - ircsock.send( - "PRIVMSG " - + channel - + " :Numberwang has been stopped. No points have been awarded. " - + user - + " is such a party pooper!\n" + util.sendmsg( + ircsock, + channel, + "Numberwang has been stopped. No points have been awarded. {} is such a party pooper!".format( + user + ), ) @@ -259,19 +227,15 @@ def save_scores(): for name in currentScores: score = line.strip("\n").split("&^%") if score[0] == name: - line = ( - score[0] - + "&^%" - + str(int(score[1]) + currentScores[name]) - + "\n" + line = "{}&^%{}\n".format( + score[0], int(score[1]) + currentScores[name] ) del currentScores[name] break scorefile.write(line) for name in currentScores: # new wangers - line = name + "&^%" + str(currentScores[name]) + "\n" - scorefile.write(line) + scorefile.write("{}&^%{}\n".format(name, currentScores[name])) def show_highscores(channel): @@ -282,16 +246,10 @@ def show_highscores(channel): scores.append((int(sline[1]), sline[0])) scores = sorted(scores, reverse=True)[:SHOW_TOP_NUM] - ircsock.send("PRIVMSG " + channel + " : ====TOP WANGERS====\n") + util.sendmsg(ircsock, channel, "====TOP WANGERS====") for score in scores: - ircsock.send( - "PRIVMSG " - + channel - + " :== ~" - + score[1] - + " (" - + str(score[0]) - + " points!) ==\n" + util.sendmsg( + ircsock, channel, " :== ~{} ({} points!) ==".format(score[1], score[0]) ) @@ -300,45 +258,26 @@ def show_user_score(channel, user): for line in scorefile.readlines(): score = line.strip("\n").split("&^%") if user == score[0]: - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": Your global numberwang score is " - + str(score[1]) - + "!\n" + util.sendmsg( + ircsock, + channel, + "{}: Your global numberwang score is {}!".format(user, score[1]), ) return # if we don't find a score line - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + ": You haven't scored any points yet!\n" + util.sendmsg( + ircsock, channel, "{} You haven't scored any points yet!".format(user) ) def rollcall(channel): - ircsock.send( - "PRIVMSG " - + channel - + " :Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers\n" + util.sendmsg( + ircsock, + channel, + " :Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers", ) -def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send( - "USER " + botnick + " " + botnick + " " + botnick + " :krowbar\n" - ) # user authentication - ircsock.send("NICK " + botnick + "\n") - - joinchan(channel) - joinchan(GOOD_CHAN) - - def get_user_from_message(msg): try: i1 = msg.index(":") + 1 @@ -357,19 +296,14 @@ def listen(): if ircmsg[:4] == "PING": ping(ircmsg.split(" ")[1]) - formatted = formatter.format_message(ircmsg) + formatted = util.format_message(ircmsg) if "" == formatted: continue # print formatted - split = formatted.split("\t") - time = split[0] - user = split[1] - command = split[2] - channel = split[3] - messageText = split[4] + time, user, command, channel, messageText = formatted.split("\t") if ircmsg.find(":!numberwang") != -1 and roundsLeft == 0: start_numberwang(channel, user) @@ -388,13 +322,10 @@ def listen(): if ircmsg.find(":!rollcall") != -1: rollcall(channel) - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) - sys.stdout.flush() time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -connect(options.server, options.channel, options.nick) +util.connect(ircsock, options) listen() diff --git a/Code/irc/whosaid.py b/Code/irc/whosaid.py index 468aae8..e16f19b 100755 --- a/Code/irc/whosaid.py +++ b/Code/irc/whosaid.py @@ -22,7 +22,9 @@ nameFix = { def whoSaid(word): word = word.lower() - userData = {} # hash keyed by "user" that contains a hash of mentioned other users with count + userData = ( + {} + ) # hash keyed by "user" that contains a hash of mentioned other users with count # Get a list of all user names by checking the logs for people who have said things with open(logfile, "r") as log: for line in log: diff --git a/Code/python/chatbesties.py b/Code/python/chatbesties.py index bdbfca0..8a6b0d9 100755 --- a/Code/python/chatbesties.py +++ b/Code/python/chatbesties.py @@ -16,7 +16,9 @@ outfile = "/home/krowbar/logs/chatBesties.json" outCircle = "/home/krowbar/logs/chatcircle.json" timePeriod = calendar.timegm(time.gmtime()) - (2 * 7 * 24 * 60 * 60) # 2 weeks -userData = {} # hash keyed by "user" that contains a hash of mentioned other users with count +userData = ( + {} +) # hash keyed by "user" that contains a hash of mentioned other users with count nameFix = { "jumblesal": "jumblesale", "hardmath1": "kc", diff --git a/Code/python/chatstats.py b/Code/python/chatstats.py index 88d5b63..bf20212 100755 --- a/Code/python/chatstats.py +++ b/Code/python/chatstats.py @@ -9,7 +9,9 @@ import re logfile = "/home/archangelic/irc/log" # logfile = "/home/jumblesale/Code/irc/log" outfile = "/home/krowbar/logs/chatStats.json" -userData = {} # hash keyed by "user" that contains a start timestamp, last timestamp, last said string, chat count, letter count, and word count +userData = ( + {} +) # hash keyed by "user" that contains a start timestamp, last timestamp, last said string, chat count, letter count, and word count # also now happy emotes and sad emotes rejectRegexp = "http[s]?://|[0-9]{2}[;:][0-9]{2}" happyRegexp = ":[-]?[])}]" From 649a56f6c2f2ea8d44e5567f3a6f4a18867bc937 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Tue, 9 Oct 2018 02:43:19 -0400 Subject: [PATCH 4/5] another big diff. tested some things --- Code/.gitignore | 2 + Code/irc/banterbot.py | 35 ++++------ Code/irc/defineWord.py | 7 +- Code/irc/dict_puzzle.py | 27 ++++--- Code/irc/duckduckgo.py | 9 +-- Code/irc/int2word.py | 115 ------------------------------ Code/irc/int2word.pyc | Bin 1979 -> 0 bytes Code/irc/puzzle.py | 110 ++++++++++++----------------- Code/irc/quote_bot.py | 25 +++---- Code/irc/tilde_bot.py | 124 --------------------------------- Code/irc/tildebot.py | 59 +++++----------- Code/irc/tildejackpot.txt | 1 + Code/irc/tildescores.txt | 12 +--- Code/irc/topicbot.py | 143 +++++++++++--------------------------- Code/irc/topicscores.txt | 1 + Code/irc/util.py | 44 ++++++++---- Code/irc/wangbot.py | 19 ++--- 17 files changed, 180 insertions(+), 553 deletions(-) create mode 100644 Code/.gitignore delete mode 100644 Code/irc/int2word.py delete mode 100644 Code/irc/int2word.pyc delete mode 100755 Code/irc/tilde_bot.py create mode 100644 Code/irc/tildejackpot.txt diff --git a/Code/.gitignore b/Code/.gitignore new file mode 100644 index 0000000..d646835 --- /dev/null +++ b/Code/.gitignore @@ -0,0 +1,2 @@ +*.pyc +__pycache__/ diff --git a/Code/irc/banterbot.py b/Code/irc/banterbot.py index 9c48ed0..1f73dbf 100755 --- a/Code/irc/banterbot.py +++ b/Code/irc/banterbot.py @@ -10,6 +10,7 @@ import fileinput import random import re import subprocess +import textwrap import time import datetime @@ -17,7 +18,6 @@ import inflect from rhymesWith import getRhymes from rhymesWith import rhymeZone from defineWord import defWord -from rainbow import makeRainbow import welch import evil import tumblr @@ -49,7 +49,7 @@ parser.add_option( "-n", "--nick", dest="nick", - default="tildebot", + default="banterbot", help="the nick to use", metavar="NICK", ) @@ -200,7 +200,7 @@ def define_word(channel, user, text): def make_rainbow(channel, user, text): - rbword = makeRainbow(text[9:]) + rbword = util.makeRainbow(text[9:]) util.sendmsg(ircsock, channel, rbword) @@ -320,37 +320,28 @@ def mug_off(channel): def rollcall(channel): - util.sendmsg( - ircsock, - channel, - """ + text = """ U wot m8? I score all the top drawer #banter and #bantz on this channel! Find new top-shelf banter with !newbanter, !rhymes, and !define. Look up things with !acronym and !whosaid. Make your chatter #legend with !rainbow, !toilet, and !figlet. Find interesting things with !xkcd and !wiki-philosophy. Get jokes with !welch and !evil - """, - ) - - -def get_user_from_message(msg): - try: - i1 = msg.index(":") + 1 - i2 = msg.index("!") - return msg[i1:i2] - except ValueError: - return "" + """ + for line in textwrap.dedent(text).split("\n"): + if line == "": + continue + util.sendmsg(ircsock, channel, line) def listen(botnick): while 1: - ircmsg = ircsock.recv(2048) + ircmsg = ircsock.recv(2048).decode() ircmsg = ircmsg.strip("\n\r") if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + util.ping(ircsock, ircmsg) formatted = util.format_message(ircmsg) @@ -359,7 +350,7 @@ def listen(botnick): # print formatted - time, user, command, channel, messageText = formatted.split("\t") + _time, user, _command, channel, messageText = formatted.split("\t") if ircmsg.find("#banter") != -1 or ircmsg.find("#bantz") != -1: score_banter(channel, user, messageText) @@ -418,7 +409,7 @@ def listen(botnick): mug_off(channel) if ircmsg[:4] == "PING": - util.ping(ircsock, msg) + util.ping(ircsock, ircmsg) sys.stdout.flush() time.sleep(1) diff --git a/Code/irc/defineWord.py b/Code/irc/defineWord.py index 104e5cc..e290ac0 100644 --- a/Code/irc/defineWord.py +++ b/Code/irc/defineWord.py @@ -5,7 +5,7 @@ import random def define(word): defs = [] - url = "http://www.merriam-webster.com/dictionary/%s" % word + url = "http://www.merriam-webster.com/dictionary/{}".format(word) soup = BeautifulSoup(urllib.urlopen(url).read(), "html.parser") head = soup.find("div", id="headword") if head: @@ -19,9 +19,8 @@ key = open("/home/krowbar/.secret/key").readline().rstrip() def defWord(word, short=True): defs = [] - url = "http://www.dictionaryapi.com/api/v1/references/collegiate/xml/%s?key=%s" % ( - word, - key, + url = "http://www.dictionaryapi.com/api/v1/references/collegiate/xml/{}?key={}".format( + word, key ) soup = BeautifulSoup(urllib.urlopen(url).read(), "html5lib") entry = soup.find("entry") diff --git a/Code/irc/dict_puzzle.py b/Code/irc/dict_puzzle.py index 40233dd..85459eb 100644 --- a/Code/irc/dict_puzzle.py +++ b/Code/irc/dict_puzzle.py @@ -7,8 +7,9 @@ dictionary = "/usr/share/dict/american-english-small" BAD_WORDS_FILE = "badwords.txt" -def get_wordlist(): +def gen_wordlist(): # I feel weird calling this "get_wordlist" when it's a generator without calling out that I do in fact realise it's weird - ~deltawitch + # how about gen_wordlist with open(BAD_WORDS_FILE, "r") as fp: bad_words = set(fp) @@ -18,14 +19,11 @@ def get_wordlist(): def get_puzzle(): - dict_words = list(get_wordlist()) + dict_words = list(gen_wordlist()) words = random.sample(dict_words, 3) key = random.randrange(0, 3) # get values 1-3 - puzzle = ( - "When alphebetized, what is the " - + p.ordinal(p.number_to_words(key + 1)) - + " in " - + ", ".join(words) + puzzle = "When alphebetized, what is the {} in {}?".format( + p.ordinal(p.number_to_words(key + 1)), ", ".join(words) ) words.sort() answer = words[key] @@ -34,14 +32,12 @@ def get_puzzle(): def get_anagram(maxlen=6): dict_words = [ - word for word in get_wordlist() if len(word) > 2 and len(word) <= maxlen + 1 + word for word in gen_wordlist() if len(word) > 2 and len(word) < maxlen + 1 ] word = random.choice(dict_words) - while True: - anagram = "".join(random.sample(word, len(word))) - if anagram != word: - break - puzzle = "Unscramble the following word: '" + anagram + "'" + anagram = list(word) + random.shuffle(anagram) + anagram = "".join(anagram) # Anagrams can have multiple answers, so we provide a check function that accepts all possibilities def answer_checker(guess): @@ -52,6 +48,7 @@ def get_anagram(maxlen=6): if sorted(guess) != sorted(word): return False # Ok, gotta actually check if it's a word now - return any(guess == item for item in get_wordlist()) + return any(guess == item for item in gen_wordlist()) - return [answer_checker, puzzle] + challenge_text = "Unscramble the following word: '{}'".format(anagram) + return [answer_checker, challenge_text] diff --git a/Code/irc/duckduckgo.py b/Code/irc/duckduckgo.py index 25ecd03..b00dda4 100755 --- a/Code/irc/duckduckgo.py +++ b/Code/irc/duckduckgo.py @@ -1,5 +1,5 @@ +import requests import urllib -import urllib2 import json as j import sys @@ -50,12 +50,9 @@ def query( encparams = urllib.urlencode(params) url = "http://api.duckduckgo.com/?" + encparams - request = urllib2.Request(url, headers={"User-Agent": useragent}) - response = urllib2.urlopen(request) - json = j.loads(response.read()) - response.close() + request = requests.get(url, headers={"User-Agent": useragent}) - return Results(json) + return Results(request.json()) class Results(object): diff --git a/Code/irc/int2word.py b/Code/irc/int2word.py deleted file mode 100644 index 8c2e532..0000000 --- a/Code/irc/int2word.py +++ /dev/null @@ -1,115 +0,0 @@ -# integer number to english word conversion -# can be used for numbers as large as 999 vigintillion -# (vigintillion --> 10 to the power 60) -# tested with Python24 vegaseat 07dec2006 -def int2word(n): - """ - convert an integer number n into a string of english words - """ - # break the number into groups of 3 digits using slicing - # each group representing hundred, thousand, million, billion, ... - n3 = [] - r1 = "" - # create numeric string - ns = str(n) - for k in range(3, 33, 3): - r = ns[-k:] - q = len(ns) - k - # break if end of ns has been reached - if q < -2: - break - else: - if q >= 0: - n3.append(int(r[:3])) - elif q >= -1: - n3.append(int(r[:2])) - elif q >= -2: - n3.append(int(r[:1])) - r1 = r - - # print n3 # test - - # break each group of 3 digits into - # ones, tens/twenties, hundreds - # and form a string - nw = "" - for i, x in enumerate(n3): - b1 = x % 10 - b2 = (x % 100) // 10 - b3 = (x % 1000) // 100 - # print b1, b2, b3 # test - if x == 0: - continue # skip - else: - t = thousands[i] - if b2 == 0: - nw = ones[b1] + t + nw - elif b2 == 1: - nw = tens[b1] + t + nw - elif b2 > 1: - nw = twenties[b2] + ones[b1] + t + nw - if b3 > 0: - nw = ones[b3] + "hundred " + nw - return nw - - -############# globals ################ -ones = [ - "", - "one ", - "two ", - "three ", - "four ", - "five ", - "six ", - "seven ", - "eight ", - "nine ", -] -tens = [ - "ten ", - "eleven ", - "twelve ", - "thirteen ", - "fourteen ", - "fifteen ", - "sixteen ", - "seventeen ", - "eighteen ", - "nineteen ", -] -twenties = [ - "", - "", - "twenty ", - "thirty ", - "forty ", - "fifty ", - "sixty ", - "seventy ", - "eighty ", - "ninety ", -] -thousands = [ - "", - "thousand ", - "million ", - "billion ", - "trillion ", - "quadrillion ", - "quintillion ", - "sextillion ", - "septillion ", - "octillion ", - "nonillion ", - "decillion ", - "undecillion ", - "duodecillion ", - "tredecillion ", - "quattuordecillion ", - "sexdecillion ", - "septendecillion ", - "octodecillion ", - "novemdecillion ", - "vigintillion ", -] diff --git a/Code/irc/int2word.pyc b/Code/irc/int2word.pyc deleted file mode 100644 index 2b29b7370f4834068f6f573d6b013e7279942156..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1979 zcmb7E-EJF26#mx#Svx-jlGKILZGqxasA+nOP^IPyA%s$-N>O{^_)P32&TO(fPF!K% zP@V*F0S^Ih01v zkWI)Iq1Oe9|??bLbBFGKMO~?n34>-3pFr+FK81V+ zxeIASK1Xi@dra~k9<{bvLN_2;;VN@IIt zvGepdOiCCRF)pEgeNu)is6;#!S0)vV*^Cknf%FN!wW*iOI4mRm5#s>g7vX5nrWFv; zieF&A_Na?Zqd9f7wdjdeahMp2z?V=&15M7?EEE&t z_n3hnwU+f-cSypBziwhrP3oeKjbiIe&!mwZ9_{OUeB89l`&Yw2`z zY5~j9B)#vq^j~2Pd29O8uw1Rr*8=0jgN z(dhZvG?;bI@+5pP@>=0RlB(LXj5B353R#Vw$DrWT*W#wU_fI}gKOd>w var1: var1, var2 = var2, var1 answer = var1 - var2 - puzzle += ( - p.number_to_words(var1) - + " " - + random.choice(["minus", "subtract", "take away", "less"]) - + " " - + p.number_to_words(var2) + puzzle += "{} {} {}".format( + p.number_to_words(var1), + random.choice(["minus", "subtract", "take away", "less"]), + p.number_to_words(var2), ) + elif roll == 3: if var2 > var1: var1, var2 = var2, var1 answer = var1 * 2 / var2 - puzzle += ( - p.number_to_words(var1 * 2) - + " " - + random.choice(["divided by", "over"]) - + " " - + p.number_to_words(var2) - + " (no remainder)" + puzzle += "{} {} {} (no remainder)".format( + p.number_to_words(var1 * 2), + random.choice(["divided by", "over"]), + p.number_to_words(var2), ) + elif roll == 4: answer = var1 ** var2 - puzzle += ( - p.number_to_words(var1) - + " to the " - + p.ordinal(p.number_to_words(var2)) - + " power" + puzzle += "{} to the {} power".format( + p.number_to_words(var1), p.ordinal(p.number_to_words(var2)) ) + elif roll == 5: p1 = random.choice(primes) p2 = random.choice(primes) @@ -103,10 +95,10 @@ def make_puzzle(obfuscate=True): return attempt == correct bonus = 1 - puzzle += ( + puzzle += "{} when factored into its two primes (answer in the form of the two primes with a comma between)".format( p.number_to_words(p1 * p2) - + " when factored into its two primes (answer in the form of the two primes with a comma between)" ) + elif roll == 6: prime = random.choice(primes) answer = prime % var1 @@ -115,57 +107,43 @@ def make_puzzle(obfuscate=True): if let1_ord + var1 > ord("z"): let1_ord -= var1 answer = chr(let1_ord + var1) - puzzle = ( - "What letter comes " - + p.number_to_words(var1) - + " letters after '" - + chr(let1_ord) - + "'" + puzzle += "What letter comes {} letters after '{}'".format( + p.number_to_words(var1), chr(let1_ord) ) + obfuscate = False elif roll == 8: if let1_ord - var1 < ord("a"): let1_ord += var1 answer = chr(let1_ord - var1) - puzzle = ( - "What letter comes " - + p.number_to_words(var1) - + " letters before '" - + chr(let1_ord) - + "'" + puzzle += "What letter comes {} letters before '{}'".format( + p.number_to_words(var1), chr(let1_ord) ) + obfuscate = False elif roll == 9: answer, puzzle = quote_puzzle.get_quote() obfuscate = False elif roll == 10: answer = str(min(var1, var2, var3, var4)) - puzzle = ( - "What is the " - + random.choice(["smallest", "lowest"]) - + " of " - + p.number_to_words(var1) - + ", " - + p.number_to_words(var2) - + ", " - + p.number_to_words(var3) - + ", and " - + p.number_to_words(var4) + puzzle += "What is the {} of {}, {}, {}, and {}".format( + random.choice(["smallest", "lowest"]), + p.number_to_words(var1), + p.number_to_words(var2), + p.number_to_words(var3), + p.number_to_words(var4), ) + elif roll == 11: answer = str(max(var1, var2, var3, var4)) - puzzle = ( - "What is the " - + random.choice(["biggest", "largest"]) - + " of " - + p.number_to_words(var1) - + ", " - + p.number_to_words(var2) - + ", " - + p.number_to_words(var3) - + ", and " - + p.number_to_words(var4) + puzzle += "What is the {} of {}, {}, {}, and {}".format( + random.choice(["biggest", "largest"]), + p.number_to_words(var1), + p.number_to_words(var2), + p.number_to_words(var3), + p.number_to_words(var4), ) + elif roll <= 14: # 12-14 answer, puzzle = dict_puzzle.get_puzzle() obfuscate = False diff --git a/Code/irc/quote_bot.py b/Code/irc/quote_bot.py index af36fad..600b1e2 100755 --- a/Code/irc/quote_bot.py +++ b/Code/irc/quote_bot.py @@ -31,7 +31,7 @@ parser.add_option( "-n", "--nick", dest="nick", - default="quote_bot", + default="quotebot", help="the nick to use", metavar="NICK", ) @@ -51,19 +51,10 @@ def haiku(channel): util.sendmsg(ircsock, channel, h) -def get_user_from_message(msg): - try: - i1 = msg.index(":") + 1 - i2 = msg.index("!") - return msg[i1:i2] - except ValueError: - return "" - - def say_mentions(user, message): - nick = get_user_from_message(message) + nick = util.get_user_from_message(message) menschns = ( - os.popen("/home/karlen/bin/mensch -u %s -t 24 -z +0" % (user)) + os.popen("/home/karlen/bin/mensch -u {} -t 24 -z +0".format(user)) .read() .replace("\t", ": ") .split("\n") @@ -86,8 +77,8 @@ def say_chatty(channel): def listen(): while 1: - ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip("\n\r") + ircmsg = ircsock.recv(2048).decode() + ircmsg = ircmsg.strip("\r\n") formatted = util.format_message(ircmsg) @@ -96,7 +87,7 @@ def listen(): print(formatted) - time, user, messageText = formatted.split("\t") + user = formatted.split("\t")[1] if ircmsg.find(":!quote") != -1: random_quote(options.channel) @@ -111,10 +102,10 @@ def listen(): haiku(options.channel) if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + util.ping(ircsock, ircmsg) sys.stdout.flush() - time.sleep(1) + # time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) diff --git a/Code/irc/tilde_bot.py b/Code/irc/tilde_bot.py deleted file mode 100755 index ec6cba4..0000000 --- a/Code/irc/tilde_bot.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/python -# http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python - -# Import some necessary libraries. -import socket -import os -import sys -from optparse import OptionParser - -import get_users -import mentions -import formatter - -parser = OptionParser() - -parser.add_option( - "-s", - "--server", - dest="server", - default="127.0.0.1", - help="the server to connect to", - metavar="SERVER", -) -parser.add_option( - "-c", - "--channel", - dest="channel", - default="#bot_test", - help="the channel to join", - metavar="CHANNEL", -) -parser.add_option( - "-n", - "--nick", - dest="nick", - default="tilde_bot", - help="the nick to use", - metavar="NICK", -) - -(options, args) = parser.parse_args() - - -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) - - -def sendmsg(chan, msg): - ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") - - -def joinchan(chan): - ircsock.send("JOIN " + chan + "\n") - - -def hello(): - ircsock.send("PRIVMSG " + channel + " :Hello!\n") - - -def tilde(channel, user, time): - # h = os.popen("haiku").read().replace("\n", " // ") - msg = time + ":" + user - print(msg) - ircsock.send("PRIVMSG " + channel + " :" + msg + "\n") - - -def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send( - "USER " - + botnick - + " " - + botnick - + " " - + botnick - + " :This bot is a result of a tutoral covered on http://shellium.org/wiki.\n" - ) # user authentication - ircsock.send("NICK " + botnick + "\n") - - joinchan(channel) - - -def get_user_from_message(msg): - try: - i1 = msg.index(":") + 1 - i2 = msg.index("!") - return msg[i1:i2] - except ValueError: - return "" - - -def listen(): - while 1: - - ircmsg = ircsock.recv(2048) - ircmsg = ircmsg.strip("\n\r") - - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) - - formatted = formatter.format_message(ircmsg) - - if "" == formatted: - continue - - print(formatted) - - split = formatted.split("\t") - time = split[0] - user = split[1] - messageText = split[2] - - if ircmsg.find(":!tilde") != -1: - tilde(options.channel, user, time) - - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) - - sys.stdout.flush() - - -ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -connect(options.server, options.channel, options.nick) -listen() diff --git a/Code/irc/tildebot.py b/Code/irc/tildebot.py index 7ce279b..43e0e54 100755 --- a/Code/irc/tildebot.py +++ b/Code/irc/tildebot.py @@ -48,7 +48,7 @@ challenges = {} SCORE_FILE = "tildescores.txt" JACKPOT_FILE = "tildejackpot.txt" JACKPOT_MIN = 3 -DEBUG = False +DEBUG = True def too_recent(time1, time2): @@ -190,7 +190,7 @@ def get_prize(name, isHuman, bonus=0): prize, "{}: {}! You are {} and get {} tildes!".format( name, - (get_positive() if isHuman else get_negative), + (get_positive() if isHuman else get_negative()), get_superlative(prize), p.number_to_words(prize), ), @@ -240,10 +240,10 @@ def give_tilde(channel, user, name, time, human, bonus=0): scorefile.seek(0) scorefile.truncate() for score in scores: - person = score.strip("\n").split("&^%") - if person[0] == user: + name, score_on_file, timestamp = score.strip("\n").split("&^%") + if name == user: found = True - if too_recent(time, person[2]) and not DEBUG: + if too_recent(time, timestamp) and not DEBUG: util.sendmsg( ircsock, channel, @@ -252,22 +252,22 @@ def give_tilde(channel, user, name, time, human, bonus=0): ), ) else: - prize = get_prize(name, human, bonus) + prizevalue, prizetext = get_prize(name, human, bonus) score = "{}&^%{}&^%{}\n".format( - person[0], int(person[1] + prize[0]), time + name, str(int(score_on_file) + prizevalue), time ) - util.sendmsg(ircsock, channel, prize[1]) + util.sendmsg(ircsock, channel, prizetext) scorefile.write(score) if not found: - prize = get_prize(name, True, bonus) + prizevalue, prizetext = get_prize(name, True, bonus) util.sendmsg( ircsock, channel, - "Welcome to the tilde game! Here's {} free tilde(s) to start you off.".format( - p.number_to_words(prize[0] + 1) + "Welcome to the tilde game! Here's {} free tildes to start you off.".format( + p.number_to_words(prizevalue + 1) ), ) - scorefile.write("{}&^%{}&^%{}\n".format(user, str(prize[0] + 1), time)) + scorefile.write("{}&^%{}&^%{}\n".format(user, str(prizevalue + 1), time)) def show_tildescore(channel, user, name): @@ -298,14 +298,13 @@ def challenge(channel, user, name, time): global challenges challenge = puzzle.make_puzzle() challenges[user] = challenge[1:] - # challenges[USER] = [ANSWER, BONUS] - util.sendmsg(ircsock, channel, "{}: {}".format(name, challenge[1])) + util.sendmsg(ircsock, channel, "{}: {}".format(name, challenge[0])) def challenge_response(channel, user, name, time, msg): global challenges print(msg) - if challenges.has_key(user): + if user in challenges: answer, bonus = challenges[user] if (callable(answer) and answer(msg.lower())) or ( msg.lower() == str(answer).lower() or msg == p.number_to_words(answer) @@ -323,31 +322,10 @@ def rollcall(channel): ) -def connect(server, channel, botnick): - server, port = server.split(":") - ircsock.connect((server, port)) - ircsock.send("USER {0} {0} {0} :krowbar\r\n".format(botnick)) # user authentication - ircsock.send("NICK {}\r\n".format(botnick)) - ircsock.send("MODE +B {}\r\n".format(botnick)) - - joinchan(channel) - if not DEBUG: - joinchan("#bots") - - -def get_user_from_message(msg): - try: - i1 = msg.index(":") + 1 - i2 = msg.index("!") - return msg[i1:i2] - except ValueError: - return "" - - def listen(): while 1: - ircmsg = ircsock.recv(2048) + ircmsg = ircsock.recv(2048).decode() for msg in ircmsg.split("\n"): msg = msg.strip("\n\r") @@ -356,20 +334,19 @@ def listen(): continue formatted = util.format_message(msg) + print(formatted) if "" == formatted: continue - # print formatted - iTime, user, command, channel, messageText = formatted.split("\t") name = util.get_name(user) if msg.find(":!tildescore") != -1: show_tildescore(channel, user, name) - elif msg.find(":!tilde") != -1 and not challenges.has_key(user): + elif msg.find(":!tilde") != -1 and user not in challenges: challenge(channel, user, name, iTime) - elif challenges.has_key(user) and (channel == "#bots" or DEBUG): + elif user in challenges and (channel == "#bots" or DEBUG): challenge_response(channel, user, name, iTime, messageText) if msg.find(":!jackpot") != -1: diff --git a/Code/irc/tildejackpot.txt b/Code/irc/tildejackpot.txt new file mode 100644 index 0000000..9d07aa0 --- /dev/null +++ b/Code/irc/tildejackpot.txt @@ -0,0 +1 @@ +111 \ No newline at end of file diff --git a/Code/irc/tildescores.txt b/Code/irc/tildescores.txt index 618cac1..8393826 100644 --- a/Code/irc/tildescores.txt +++ b/Code/irc/tildescores.txt @@ -122,14 +122,4 @@ x4464&^%1&^%1532028546 pounce&^%19&^%1532133325 von_&^%5&^%1532502104 livix&^%7&^%1533603142 -ben&^%3&^%1533767627 -npa&^%78&^%1536235183 -ezo&^%6&^%1533883842 -aliasless&^%30&^%1537198276 -kirch&^%41&^%1535571833 -root&^%2&^%1535558514 -byte&^%5&^%1536416308 -qbe&^%6&^%1537112151 -informati&^%3&^%1536733938 -h00fi&^%1&^%1537050053 -fantoro&^%4&^%1537106482 +ben&^%28&^%1539065026 diff --git a/Code/irc/topicbot.py b/Code/irc/topicbot.py index 19e4739..b7cdf98 100755 --- a/Code/irc/topicbot.py +++ b/Code/irc/topicbot.py @@ -10,12 +10,8 @@ import fileinput import random import time -import formatter -import get_users -import mentions -import pretty_date import inflect -import names +import util parser = OptionParser() @@ -23,7 +19,7 @@ parser.add_option( "-s", "--server", dest="server", - default="127.0.0.1", + default="127.0.0.1:6667", help="the server to connect to", metavar="SERVER", ) @@ -49,22 +45,6 @@ parser.add_option( p = inflect.engine() -def ping(pong): - ircsock.send("PONG {}\n".format(pong)) - - -def sendmsg(chan, msg): - ircsock.send("PRIVMSG " + chan + " :" + msg + "\n") - - -def joinchan(chan): - ircsock.send("JOIN " + chan + "\n") - - -def hello(): - ircsock.send("PRIVMSG " + channel + " :Hello!\n") - - def get_topic(channel, user, time): # topic scores are saved as &^%&^% with open("topicscores.txt", "r") as scorefile: @@ -84,19 +64,16 @@ def get_topic(channel, user, time): with open("topics_" + channel + ".txt", "r") as topics: topic = topics.readlines()[-1].strip("\n").split("&^%", 3) - byuser = names.get_name(topic[1]) - ircsock.send( - "PRIVMSG " - + channel - + " :I've told you " - + p.number_to_words(userscore) - + " times! It's \"" - + topic[2] - + '" (Set by ' - + byuser - + " " - + pretty_date.pretty_date(int(topic[0])) - + ")\n" + byuser = util.get_name(topic[1]) + util.sendmsg( + ircsock, + channel, + "I've told you {} times! It's \"{}\" (set by {} {})".format( + p.number_to_words(userscore), + topic[2], + byuser, + util.pretty_date(int(topic[0])), + ), ) @@ -117,14 +94,10 @@ def count_topic(channel, user, time, msg): scorefile.writelines(scores) if not found: scorefile.write(user + "&^%0&^%1") - ircsock.send( - "PRIVMSG " - + channel - + " :" - + user - + " has changed the topic " - + p.number_to_words(userscore) - + " times!\n" + util.sendmsg( + ircsock, + channel, + "{} has changed the topic {} times!".format(user, p.number_to_words(userscore)), ) @@ -139,29 +112,29 @@ def random_topic(channel, user, time, setTopic=False): if setTopic: set_topic(channel, user, time, msg) else: - ircsock.send("PRIVMSG " + channel + " :Suggested Topic: " + msg + "\n") + util.sendmsg(ircsock, channel, "Suggested Topic: {}".format(msg)) def rollcall(channel): - ircsock.send( - "PRIVMSG " - + channel - + " :topicbot reporting! I respond to !topic !settopic !suggesttopic !thistory\n" + util.sendmsg( + ircsock, + channel, + "topicbot reporting! I respond to !topic !settopic !suggesttopic !thistory", ) def topic_score(channel): - ircsock.send("PRIVMSG " + channel + " :Not implemented yet") + util.sendmsg(ircsock, channel, "Not implemented yet") def topic_scores(channel): - ircsock.send("PRIVMSG " + channel + " :Not implemented yet") + util.sendmsg(ircsock, channel, "Not implemented yet") def topic_history(channel, user, count): try: iCount = int(count.split()[1]) - except (ValueError, IndexError) as e: + except (ValueError, IndexError): iCount = 3 if iCount > 10: iCount = 10 @@ -169,73 +142,40 @@ def topic_history(channel, user, count): iCount = 3 with open("topics_" + channel + ".txt", "r") as topicsfile: # topics = topicsfile.readlines()[-iCount:].reverse() - ircsock.send( - "PRIVMSG " - + channel - + " :Ok, here were the last " - + p.number_to_words(iCount) - + " topics\n" + util.sendmsg( + ircsock, + channel, + "Ok, here are the last {} topics".format(p.number_to_words(iCount)), ) for idx, topic in enumerate(reversed(topicsfile.readlines()[-iCount:])): topic = topic.strip("\n").split("&^%", 3) - byuser = names.get_name(topic[1]) - ircsock.send( - "PRIVMSG " - + channel - + " :" - + str(idx + 1) - + ': "' - + topic[2] - + '" (Set by ' - + byuser - + " " - + pretty_date.pretty_date(int(topic[0])) - + ")\n" + byuser = util.get_name(topic[1]) + util.sendmsg( + ircsock, + channel, + "{}: {} (set by {} {})".format( + str(idx + 1), topic[2], byuser, util.pretty_date(int(topic[0])) + ), ) -def connect(server, channel, botnick): - ircsock.connect((server, 6667)) - ircsock.send( - "USER " + botnick + " " + botnick + " " + botnick + " :krowbar\n" - ) # user authentication - ircsock.send("NICK " + botnick + "\n") - - joinchan(channel) - joinchan("#bots") - - -def get_user_from_message(msg): - try: - i1 = msg.index(":") + 1 - i2 = msg.index("!") - return msg[i1:i2] - except ValueError: - return "" - - def listen(): while 1: - ircmsg = ircsock.recv(2048) + ircmsg = ircsock.recv(2048).decode() ircmsg = ircmsg.strip("\n\r") if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + util.ping(ircsock, ircmsg) - formatted = formatter.format_message(ircmsg) + formatted = util.format_message(ircmsg) if "" == formatted: continue # print formatted - split = formatted.split("\t") - msgtime = split[0] - user = split[1] - command = split[2] - channel = split[3] - messageText = split[4] + msgtime, user, command, channel, messageText = formatted.split("\t") if command == "TOPIC" and user != options.nick: count_topic(channel, user, msgtime, messageText) @@ -262,13 +202,10 @@ def listen(): if ircmsg.find(":!rollcall") != -1: rollcall(channel) - if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) - sys.stdout.flush() time.sleep(1) ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -connect(options.server, options.channel, options.nick) +util.connect(ircsock, options) listen() diff --git a/Code/irc/topicscores.txt b/Code/irc/topicscores.txt index c1304b2..7781292 100644 --- a/Code/irc/topicscores.txt +++ b/Code/irc/topicscores.txt @@ -1 +1,2 @@ vilmibm&^%0&^%2 +ben&^%3&^%0 diff --git a/Code/irc/util.py b/Code/irc/util.py index 96dceee..e3da9ed 100644 --- a/Code/irc/util.py +++ b/Code/irc/util.py @@ -4,30 +4,44 @@ import random import re -def hello(ircsock, chan): - sendmsg(ircsock, chan, "Hello!") - - -def ping(pong): - ircsock.send("PONG {}\n".format(pong.split(" ")[1])) +def ping(ircsock, msg): + ircsock.send("PONG {}\n".format(msg.split(" ")[1]).encode()) def sendmsg(ircsock, chan, msg): - ircsock.send("PRIVMSG {} :{}\r\n".format(chan, msg)) + print("sending {} to {}".format(msg, chan)) + ircsock.send("PRIVMSG {} :{}\r\n".format(chan, msg).encode()) def joinchan(ircsock, chan): - ircsock.send("JOIN {}\r\n".format(chan)) + print("joining {}".format(chan)) + ircsock.send("JOIN {}\r\n".format(chan).encode()) + + +def get_user_from_message(msg): + try: + i1 = msg.index(":") + 1 + i2 = msg.index("!") + return msg[i1:i2] + except ValueError: + return "" def connect(ircsock, options): - server, channel, botnick = options - server, port = server.split(":") - ircsock.connect((server, port)) - ircsock.send("USER {0} {0} {0} :krowbar".format(botnick)) - ircsock.send("NICK {}\r\n".format(botnick)) - ircsock.send("MODE +B {}\r\n".format(botnick)) - joinchan(channel) + print(options) + server, port = options.server.split(":") + ircsock.connect((server, int(port))) + print(ircsock) + nick = "NICK {}\r\n".format(options.nick).encode() + print(nick) + ircsock.send(nick) + login = "USER {0} {0} {0} {0}".format(options.nick).encode() + print(login) + ircsock.send(login) + mode = "MODE +B {}\r\n".format(options.nick).encode() + print(mode) + ircsock.send(mode) + joinchan(ircsock, options.channel) # integer number to english word conversion diff --git a/Code/irc/wangbot.py b/Code/irc/wangbot.py index 8249cd2..5e08bee 100755 --- a/Code/irc/wangbot.py +++ b/Code/irc/wangbot.py @@ -37,7 +37,7 @@ parser.add_option( "-n", "--nick", dest="nick", - default="numberwang_bot", + default="wangbot", help="the nick to use", metavar="NICK", ) @@ -274,27 +274,18 @@ def rollcall(channel): util.sendmsg( ircsock, channel, - " :Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers", + "Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers", ) -def get_user_from_message(msg): - try: - i1 = msg.index(":") + 1 - i2 = msg.index("!") - return msg[i1:i2] - except ValueError: - return "" - - def listen(): while 1: - ircmsg = ircsock.recv(2048) + ircmsg = ircsock.recv(2048).decode() ircmsg = ircmsg.strip("\n\r") if ircmsg[:4] == "PING": - ping(ircmsg.split(" ")[1]) + util.ping(ircsock, ircmsg) formatted = util.format_message(ircmsg) @@ -303,7 +294,7 @@ def listen(): # print formatted - time, user, command, channel, messageText = formatted.split("\t") + _time, user, _command, channel, messageText = formatted.split("\t") if ircmsg.find(":!numberwang") != -1 and roundsLeft == 0: start_numberwang(channel, user) From eeadac5aa07a33f27878dc66c6f047e37295069f Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Wed, 10 Oct 2018 18:09:23 -0400 Subject: [PATCH 5/5] fix for PR comments. also turns DEBUG off --- Code/irc/acronymFinder.py | 14 ++++++-------- Code/irc/dict_puzzle.py | 3 +-- Code/irc/tildebot.py | 8 ++++---- Code/irc/tildejackpot.txt | 1 - Code/irc/tildescores.txt | 1 - Code/irc/topicscores.txt | 1 - Code/python/chatbesties.py | 5 ++--- Code/python/chatstats.py | 5 ++--- 8 files changed, 15 insertions(+), 23 deletions(-) delete mode 100644 Code/irc/tildejackpot.txt diff --git a/Code/irc/acronymFinder.py b/Code/irc/acronymFinder.py index 5ed5f78..9f018d3 100644 --- a/Code/irc/acronymFinder.py +++ b/Code/irc/acronymFinder.py @@ -9,10 +9,8 @@ dict = "/usr/share/dict/american-english" def get_acros(word, silly, short): acros = [] - url = "http://www.stands4.com/services/v2/abbr.php?uid=%s&tokenid=%s&term=%s" % ( - userId, - token, - word, + url = "http://www.stands4.com/services/v2/abbr.php?uid={}&tokenid={}&term={}".format( + userId, token, word ) soup = BeautifulSoup(urllib.urlopen(url).read(), "html5lib") results = soup.find_all("result") @@ -56,8 +54,7 @@ def get_acros(word, silly, short): else: acros.append( ( - '%s: "%s" (%s, score: %s)' - % ( + '{}: "{}" ({}, score: {})'.format( d["term"], d["definition"], ", ".join(d["categories"]), @@ -85,8 +82,9 @@ def get_acros(word, silly, short): else: acros.append( ( - '%s: "%s" (%s, score: %s)' - % (word.upper(), newWord, "Tilde.town Original", "0") + '{}: "{}" ({}, score: {})'.format( + word.upper(), newWord, "Tilde.town Original", "0" + ) ).encode("ascii", "ignore") ) except IndexError: diff --git a/Code/irc/dict_puzzle.py b/Code/irc/dict_puzzle.py index 85459eb..1bef24d 100644 --- a/Code/irc/dict_puzzle.py +++ b/Code/irc/dict_puzzle.py @@ -50,5 +50,4 @@ def get_anagram(maxlen=6): # Ok, gotta actually check if it's a word now return any(guess == item for item in gen_wordlist()) - challenge_text = "Unscramble the following word: '{}'".format(anagram) - return [answer_checker, challenge_text] + return [answer_checker, "Unscramble the following word: '{}'".format(anagram)] diff --git a/Code/irc/tildebot.py b/Code/irc/tildebot.py index 43e0e54..ca76109 100755 --- a/Code/irc/tildebot.py +++ b/Code/irc/tildebot.py @@ -48,7 +48,7 @@ challenges = {} SCORE_FILE = "tildescores.txt" JACKPOT_FILE = "tildejackpot.txt" JACKPOT_MIN = 3 -DEBUG = True +DEBUG = False def too_recent(time1, time2): @@ -217,7 +217,7 @@ def get_prize(name, isHuman, bonus=0): jackpotfile.write(str(JACKPOT_MIN)) return [ jackpot, - "{} hit the jackpot and won **{}**".format( + "{} hit the jackpot and won **{}** tildes!".format( name, p.number_to_words(jackpot) ), ] @@ -272,7 +272,7 @@ def give_tilde(channel, user, name, time, human, bonus=0): def show_tildescore(channel, user, name): with open(SCORE_FILE, "r") as scorefile: - for idx, score in enumerate(scorefile): + for _idx, score in enumerate(scorefile): person = score.strip("\n").split("&^%") if person[0] == user: util.sendmsg( @@ -339,7 +339,7 @@ def listen(): if "" == formatted: continue - iTime, user, command, channel, messageText = formatted.split("\t") + iTime, user, _command, channel, messageText = formatted.split("\t") name = util.get_name(user) if msg.find(":!tildescore") != -1: diff --git a/Code/irc/tildejackpot.txt b/Code/irc/tildejackpot.txt deleted file mode 100644 index 9d07aa0..0000000 --- a/Code/irc/tildejackpot.txt +++ /dev/null @@ -1 +0,0 @@ -111 \ No newline at end of file diff --git a/Code/irc/tildescores.txt b/Code/irc/tildescores.txt index 8393826..8f3664b 100644 --- a/Code/irc/tildescores.txt +++ b/Code/irc/tildescores.txt @@ -122,4 +122,3 @@ x4464&^%1&^%1532028546 pounce&^%19&^%1532133325 von_&^%5&^%1532502104 livix&^%7&^%1533603142 -ben&^%28&^%1539065026 diff --git a/Code/irc/topicscores.txt b/Code/irc/topicscores.txt index 7781292..c1304b2 100644 --- a/Code/irc/topicscores.txt +++ b/Code/irc/topicscores.txt @@ -1,2 +1 @@ vilmibm&^%0&^%2 -ben&^%3&^%0 diff --git a/Code/python/chatbesties.py b/Code/python/chatbesties.py index 8a6b0d9..d21b7a2 100755 --- a/Code/python/chatbesties.py +++ b/Code/python/chatbesties.py @@ -16,9 +16,8 @@ outfile = "/home/krowbar/logs/chatBesties.json" outCircle = "/home/krowbar/logs/chatcircle.json" timePeriod = calendar.timegm(time.gmtime()) - (2 * 7 * 24 * 60 * 60) # 2 weeks -userData = ( - {} -) # hash keyed by "user" that contains a hash of mentioned other users with count +# hash keyed by "user" that contains a hash of mentioned other users with count +userData = {} nameFix = { "jumblesal": "jumblesale", "hardmath1": "kc", diff --git a/Code/python/chatstats.py b/Code/python/chatstats.py index bf20212..31a9a26 100755 --- a/Code/python/chatstats.py +++ b/Code/python/chatstats.py @@ -9,9 +9,8 @@ import re logfile = "/home/archangelic/irc/log" # logfile = "/home/jumblesale/Code/irc/log" outfile = "/home/krowbar/logs/chatStats.json" -userData = ( - {} -) # hash keyed by "user" that contains a start timestamp, last timestamp, last said string, chat count, letter count, and word count +# hash keyed by "user" that contains a start timestamp, last timestamp, last said string, chat count, letter count, and word count +userData = {} # also now happy emotes and sad emotes rejectRegexp = "http[s]?://|[0-9]{2}[;:][0-9]{2}" happyRegexp = ":[-]?[])}]"