def __init__(self, constantJSON='data/constants.json'): with open(constantJSON, 'r', encoding='utf8') as file: constants = json.load(file) # set informations self.sets = constants['sets'] self.setIds = {} for id, setDetails in self.sets.items(): self.setIds[setDetails['name']] = id # classes self.classes = constants.get('classes', {}) # special keywords to replace self.__specials = {} for key, values in constants['specials'].items(): cards = [CardDB.cleanName(card) for card in values] self.__specials[CardDB.cleanName(key)] = cards self.specialNames = self.__specials.keys() # alternative card names self.__translations = {} for key, alts in constants['alternative_names'].items(): org = CardDB.cleanName(key) if isinstance(alts, list): for alt in alts: self.__translations[CardDB.cleanName(alt)] = org else: self.__translations[CardDB.cleanName(alts)] = org self.alternativeNames = self.__translations.keys()
def __getCards(self, text): """look for [[cardname]]s in text and collect them""" cards = [] if len(text) < 6: return cards # regex for escaped (new reddit and some apps) and unescaped brackets for card in re.finditer(r'\\?\[\\?\[([^\]\\]{1,30})\\?\]\\?\]', text): card = card.group(1) log.debug("adding a card: %s", card) cleanCard = CardDB.cleanName(card) if cleanCard: log.debug("cleaned card name: %s", cleanCard) # slight spelling error? checkedCard = self.spellChecker.correct(cleanCard) if cleanCard != checkedCard: log.info("spelling fixed: %s -> %s", cleanCard, checkedCard) # is alternative name? checkedCard = self.constants.translateAlt(checkedCard) # add cardname if checkedCard not in cards: cards.append(checkedCard) else: log.info("duplicate card: %s", card) # sometimes cards are removed, get more to fill limit if len(cards) >= self.constants.CARD_LIMIT * 2: break return cards
def test_loadInfoTempl_simple(self): constantDict = { 'sets' : { }, 'specials' : { 'dream' : ['no'] }, 'alternative_names' : { 'quickshot' : 'qs' } } try: if os.path.isfile('data/info_msg.templ'): os.rename('data/info_msg.templ', 'data/_info_msg.templ') with TempJson(constantDict) as constJson, \ TempJson({}) as emptyJson: with open('data/info_msg.templ', 'w', newline="\n") as f: f.write('{user}-{alts}-{tokens}-{special}') c = Constants(constJson) db = CardDB(constants=c, cardJSON=emptyJson, tokenJSON=emptyJson, tempJSON=emptyJson) helper = HSHelper(db, c) info = helper.getInfoText('user') self.assertEqual(info, 'user-qs--dream') finally: removeFile('data/info_msg.templ') if os.path.isfile('data/_info_msg.templ'): os.rename('data/_info_msg.templ', 'data/info_msg.templ')
def test_CardDB(self): cardDict = { 'Quick Shot': { 'type': 'Spell', 'hpwn': 14459, 'cdn': 'https://media-Hearth.cursecdn.com/14459.png', 'desc': 'Deal 3 damage. Draw a card.', 'hp': 1, 'class': 'Hunter', 'subType': 'Mech', 'set': 'Basic', 'rarity': 'Common', 'atk': 3, 'head': 'quick-shot', 'name': 'Quick Shot', 'cost': 2 } } constantDict = { 'sets': { '01': { 'name': 'Basic' } }, 'specials': {}, 'alternative_names': {} } with TempJson(constantDict) as constJson, \ TempJson(cardDict) as cardJson, \ TempJson({}) as emptyJson: c = Constants(constJson) db = CardDB(constants=c, cardJSON=cardJson, tokenJSON=emptyJson, tempJSON=emptyJson) self.assertEqual(db.cardNames(), ['quickshot']) self.assertEqual(db.tokens, []) self.assertTrue('quickshot' in db) self.assertFalse('slowshot' in db) self.assertTrue('Quick Shot' in db['quickshot'])
def test_RefreshCardDB(self): cardDict = { 'Quick Shot': { 'type': 'Spell', 'hpwn': 14459, 'cdn': 'https://media-Hearth.cursecdn.com/14459.png', 'desc': 'Deal 3 damage. Draw a card.', 'hp': 1, 'class': 'Hunter', 'subType': "Mech", 'set': 'Basic', 'rarity': 'Common', 'atk': 3, 'head': 'quick-shot', 'name': 'Quick Shot', 'cost': 2 } } constantDict = { 'sets' : { '01' : {'name' : 'Basic'} }, 'specials' : { }, 'alternative_names' : { } } with TempJson(constantDict) as constJson, \ TempJson(cardDict) as cardJson, \ TempJson({}) as emptyJson: c = Constants(constJson) db = CardDB(constants=c, cardJSON=emptyJson, tokenJSON=emptyJson, tempJSON='notexisting.json') self.assertEqual(db.cardNames(), []) self.assertFalse('quickshot' in db) db.tempJSON = cardJson db.refreshTemp() self.assertTrue('quickshot' in db) self.assertTrue('Quick Shot' in db['quickshot'])
def getCards(self, text): """look for [[cardname]]s in text and collect them securely""" cards = [] if len(text) < 6: return cards open_bracket = False card = '' # could be regex, but I rather not parse everything evil users are sending for i in range(1, len(text)): c = text[i] if open_bracket and c != ']': card += c if c == '[' and text[i - 1] == '[': open_bracket = True if c == ']' and open_bracket: if len(card) > 0: log.debug("adding a card: %s", card) cleanCard = CardDB.cleanName(card) if cleanCard: log.debug("cleaned card name: %s", cleanCard) # slight spelling error? checkedCard = self.spellChecker.correct(cleanCard) if cleanCard != checkedCard: log.info("spelling fixed: %s -> %s", cleanCard, checkedCard) # is alternative name? checkedCard = self.constants.translateAlt(checkedCard) # add cardname if checkedCard not in cards: cards.append(checkedCard) else: log.info("duplicate card: %s", card) card = '' open_bracket = False if len(cards) >= self.constants.CARD_LIMIT: break if len(card) > 30: card = '' open_bracket = False return cards
def main(): log.debug('main() hearthscan-bot starting') # load constant values constants = Constants() # init answered comments sqlite DB answeredDB = commentDB.DB() # load card DB url = 'https://raw.githubusercontent.com/d-schmidt/hearthscan-bot/master/data/tempinfo.json' cardDB = CardDB(constants=constants, tempJSONUrl=url) # init hs helper for hearthstone stuff helper = HSHelper(cardDB, constants) # pm spam filter cache pmUserCache = {} def submissionListener(r, submission): answerSubmission(submission, helper) def commentListener(r, comment): answerComment(r, comment, answeredDB, helper) def mentionListener(r, comment): answerMention(r, comment, answeredDB, helper) def pmListener(r, message): answerPM(r, message, pmUserCache, helper) def postAction(): cleanPMUserCache(pmUserCache) cardDB.refreshTemp() try: RedditBot(subreddits=credentials.subreddits, newLimit=250, connectAttempts=5, userBlacklist=set(credentials.userBlacklist)) \ .withSubmissionListener(submissionListener) \ .withCommentListener(commentListener) \ .withMentionListener(mentionListener) \ .withPMListener(pmListener) \ .run(postAction) except: log.exception('main() RedditBot failed unexpectedly') finally: log.warning('main() leaving hearthscan-bot') answeredDB.close()
def test_CleanName(self): self.assertEqual(CardDB.cleanName('Ab: 1c'), 'abc')
def test_getCardsFromComment(self): cardDict = { 'Quick Shot': { 'type': 'Spell', 'hpwn': 14459, 'cdn': 'https://media-Hearth.cursecdn.com/14459.png', 'desc': 'Deal 3 damage. Draw a card.', 'hp': 1, 'class': 'Hunter', 'subType': "Mech", 'set': 'Basic', 'rarity': 'Common', 'atk': 3, 'head': 'quick-shot', 'name': 'Quick Shot', 'cost': 2 } } # we need more cards (Card AA - Card UU) for i in range(21): name = 'Card ' + chr(97 + i) cardDict[name] = cardDict['Quick Shot'].copy() cardDict[name]['name'] = name constantDict = { 'sets': { '01': { 'name': 'Basic' } }, 'specials': {}, 'alternative_names': { "quickshot": "qs" } } with TempJson(constantDict) as constJson, \ TempJson(cardDict) as cardJson, \ TempJson({}) as emptyJson: c = Constants(constJson) db = CardDB(constants=c, cardJSON=cardJson, tokenJSON=emptyJson, tempJSON=emptyJson) helper = HSHelper(db, c) # simple find text = '[[Quick Shot]]' cards, text = helper.parseText(text) self.assertEqual(cards, ['quickshot'], 'simple card') self.assertTrue('Quick Shot' in text) # escaped simple find text = '\\[\\[quickshot\\]\\]' cards, text = helper.parseText(text) self.assertEqual(cards, ['quickshot'], 'simple card') self.assertTrue('Quick Shot' in text) # two cards, cleanName text = ' [[card a]] world [[quickshot 42]] ' cards, text = helper.parseText(text) self.assertEqual(cards, ['carda', 'quickshot'], 'multi cards, clean') self.assertTrue('Quick Shot' in text) self.assertTrue('Card a' in text) # spell check text = '[[Quic Shot]]' cards, text = helper.parseText(text) self.assertEqual(cards, ['quickshot'], 'simple card') self.assertTrue('Quick Shot' in text) # alternative name text = '[[QS]]' cards, text = helper.parseText(text) self.assertEqual(cards, ['quickshot'], 'alternative name') self.assertTrue('Quick Shot' in text) # test card limit always working cardsNames = [ 'card' + chr(97 + i) for i in range(c.CARD_LIMIT + 1) ] cardsNames = ['no card'] + cardsNames text = '[[' + ']][['.join(cardsNames) + ']]' cards, text = helper.parseText(text) self.assertEqual(cards, cardsNames[1:-1], 'CARD_LIMIT cards expected') self.assertTrue('no card' not in text, 'unknown should be skipped') for i in range(c.CARD_LIMIT): self.assertTrue('Card ' + chr(97 + i) in text) # test short text text = '[[a]]' cards, text = helper.parseText(text) self.assertEqual(len(cards), 0, 'no cards') self.assertEqual(len(text), 0, 'no cards') # test no valid text text = '[[123]] [abc]' cards, text = helper.parseText(text) self.assertEqual(len(cards), 0, 'no valid text') self.assertEqual(len(text), 0, 'no valid text') # card too long text = '[[123456789012345678901234567890abc]]' cards, text = helper.parseText(text) self.assertEqual(len(cards), 0, 'card too long') self.assertEqual(len(text), 0, 'card too long')
def test_getCardsFromComment(self): cardDict = { 'Quick Shot': { 'type': 'Spell', 'hpwn': 14459, 'cdn': 'https://media-Hearth.cursecdn.com/14459.png', 'desc': 'Deal 3 damage. Draw a card.', 'hp': 1, 'class': 'Hunter', 'subType': "Mech", 'set': 'Basic', 'rarity': 'Common', 'atk': 3, 'head': 'quick-shot', 'name': 'Quick Shot', 'cost': 2 } } constantDict = { 'sets' : { '01' : {'name' : 'Basic'} }, 'specials' : { }, 'alternative_names' : { "quickshot" : "qs" } } with TempJson(constantDict) as constJson, \ TempJson(cardDict) as cardJson, \ TempJson({}) as emptyJson: c = Constants(constJson) db = CardDB(constants=c, cardJSON=cardJson, tokenJSON=emptyJson, tempJSON=emptyJson) helper = HSHelper(db, c) # simple find text = '[[test]]' cards, text = helper.parseText(text) self.assertEqual(cards, ['test'], 'simple card') self.assertEqual(len(text), 0, 'unknown card') # escaped simple find text = '\\[\\[test\\]\\]' cards, text = helper.parseText(text) self.assertEqual(cards, ['test'], 'simple card') self.assertEqual(len(text), 0, 'unknown card') # two cards, cleanName text = ' [[hello]] world [[Ab 123c]] ' cards, text = helper.parseText(text) self.assertEqual(cards, ['hello', 'abc'], 'multi cards, clean') self.assertEqual(len(text), 0, 'unknown cards') # spell check text = '[[Quic Shot]]' cards, text = helper.parseText(text) self.assertEqual(cards, ['quickshot'], 'simple card') self.assertTrue('Quick Shot' in text) # alternative name text = '[[QS]]' cards, text = helper.parseText(text) self.assertEqual(cards, ['quickshot'], 'alternative name') self.assertTrue('Quick Shot' in text) # test card limit cardsNames = [chr(97 + i) * 2 for i in range(c.CARD_LIMIT + 1)] text = '[[' + ']][['.join(cardsNames) + ']]' cards, text = helper.parseText(text) self.assertEqual(cards, cardsNames[:-1], 'card limit') self.assertEqual(len(text), 0, 'unknown cards') # test short text text = '[[a]]' cards, text = helper.parseText(text) self.assertEqual(len(cards), 0, 'no cards') self.assertEqual(len(text), 0, 'no cards') # test no valid text text = '[[123]] [abc]' cards, text = helper.parseText(text) self.assertEqual(len(cards), 0, 'no valid text') self.assertEqual(len(text), 0, 'no valid text') # card too long text = '[[123456789012345678901234567890abc]]' cards, text = helper.parseText(text) self.assertEqual(len(cards), 0, 'card too long') self.assertEqual(len(text), 0, 'card too long')