async def MOTDallow(self, ctx, *, allowingRole: discord.Role): if await fs.isAdmin(ctx.author): # checks if role is already in db serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) exemptRoles = serverEntry['exemptRoles'] if allowingRole == motdRole: await ctx.send('pls dont break my code') return elif allowingRole.id in exemptRoles: # remove role from exemptions try: exemptRoles.remove(allowingRole.id) await fs.updateServerVal(fs.serverPath, ctx.guild.id, 'exemptRoles', exemptRoles) await ctx.send( f'**{allowingRole.name}** is now allowed for {motdRole.name}.' ) logger.info( f'\nServList DB update: {ctx.guild.name} | Role exemption REMOVED: {allowingRole.name}' ) except: await ctx.send('**An error occurred!**') else: # role already allowed await ctx.send( f'**{allowingRole.name}** was already allowed for {motdRole.name}.\n' f'Use **!exemptedroles** to get a list of all exempted roles.' )
async def hiscores(self, ctx): topScoreLst = [] serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) exemptRoles = serverEntry['exemptRoles'] scoresEntry = await fs.getServerEntry(fs.scorePath, ctx.guild.id) try: counter = 0 for k, v in scoresEntry.items(): try: mem = ctx.guild.get_member(int(k)) # check if member is exempted. if so, exclude from list if any(role.id in exemptRoles for role in mem.roles): pass else: topScoreLst.append(f"*{mem.name}*" + " **|** " + f"{str(v)}\n") counter += 1 if counter == 15: # how many members to show break except: logger.debug( f'Skipped {k} in !hiscores: {ctx.guild.name} - {ctx.guild.id}' ) pass topScoreLst = "".join(topScoreLst) await ctx.send( f'**Top {str(counter)} Hiscores - {motdRole.name}**\n' + topScoreLst) except: await ctx.send('No servers in database.') logger.info( f'!hiscores called in {ctx.guild.name} by {ctx.author.name}')
async def totalvotes(self, ctx): # TEMP # await ctx.send(f'Total votes are hidden right now!') # return # STARTS HERE voteLst = [] serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) votingEntry = await fs.getServerEntry(fs.votePath, ctx.guild.id) motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) voteCounts = votingEntry['voteCounts'] try: for k, v in voteCounts.items(): try: mem = ctx.guild.get_member(int(k)) voteLst.append(f"*{mem.name}*" + " **|** " + f"{str(v)}\n") except: logger.debug(f'Skipped {k} in !totalvotes') pass voteLst = "".join(voteLst) await ctx.send(f'**Member Votes - {motdRole.name}**\n{voteLst}') except: await ctx.send('No members have been voted for.') logger.info( f'!totalvotes called in {ctx.guild.name} by {ctx.author.name}')
def parse_settings(settings_file): """ Creates multiple dictionaries containing the settings parsed from a settings file. Each type of plot has its own settings dictionary. settings_file is the name of the text file containing the settings Return values: data is a pandas.DataFrame object which contains the alternative splicing data hive_plot_settings is a dictionary containing the settings for the hive plot struct_plot_settings is a dictionary containing the settings for the structure plot """ try: config = configparser.ConfigParser() logger.info('Reading settings from {0}...'.format(settings_file)) config.read(settings_file) # hive_plot_settings = parse_hive_plot_settings(config) # struct_plot_settings = parse_struct_plot_settings(config) return parse_sashimi_settings(config) # print('Done reading settings.') # return hive_plot_settings, struct_plot_settings, sashimi_plot_settings except IOError: logger.error('{0} is not a valid file path') sys.exit(1)
def is_bam(infile): u""" check if input file is bam or sam file :param infile: path to input file :return: Boolean """ try: create = False if not os.path.exists(infile + ".bai"): create = True elif os.path.getctime(infile + ".bai") < os.path.getctime(infile): os.remove(infile + ".bai") create = True else: try: with pysam.AlignmentFile(infile) as r: r.check_index() except ValueError: create = True if create: logger.info("Creating index for %s" % infile) pysam.index(infile) return True except pysam.utils.SamtoolsError: return False
async def MOTDexempt(self, ctx, *, exemptingRole: discord.Role): if await fs.isAdmin(ctx.author): # checks if role is already in db serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) exemptRoles = serverEntry['exemptRoles'] if exemptingRole == motdRole: await ctx.send('pls dont break my code') return elif exemptingRole.id in exemptRoles: # role already exempted await ctx.send( f'**{exemptingRole.name}** was already exempted from {motdRole.name}!' ) else: # add role to exemptions try: exemptRoles.append(exemptingRole.id) await fs.updateServerVal(fs.serverPath, ctx.guild.id, 'exemptRoles', exemptRoles) await ctx.send( f'**{exemptingRole.name}** is now exempted from {motdRole.name}.' ) logger.info( f'\nServer List DB update: {ctx.guild.name} | Role exemption ADDED: {exemptingRole.name}' ) except: await ctx.send('**An error occurred!**')
def run(): # 登入,输入讲师姓名无密码 teacher = None while True: show_teacher_menu() s = input('>>>').strip() if s.isdigit(): s = int(s) if s == 1: logger.info('teacher login...') print('请输入讲师姓名') name = input('>>>').strip() teacher = login(name, tp='teacher') if not teacher: print('登入失败') elif s == 2: logger.info('check grades...') check_grades(teacher) elif s == 3: logger.info('check grades...') check_grades_students(teacher) elif s == 4: logger.info('modify score...') modify_score(teacher) elif s == 5: logger.info('teaching...') teach(teacher, ) elif s == 'q' or s == 'Q': # save_student(student) exit('bye') else: print('输入错误')
def draw_line_plot(output_file_path, settings, average_depths_dict, splice_region, no_bam=False, show_gene=True, dpi=300, log=None, title=None, distance_ratio=0.3): """ draw_sashimi_plot draws the complete sashimi plot output_file_path is the file path that the plot will be written to settings is a dict containing the settings for the sashimi plot var_pos is the location of the SNP, in the format chr1:12345 average_depths_dict {group: {BAM: ReadDepth}, group: {BAM: ReadDepth}} mRNAs_object is an mRNAsObject containing information about the transcript structure plot_title is the title of the plot return values: None. Draws sashimi plot """ assert isinstance( splice_region, SpliceRegion ), "splice_region should be SpliceRegion, not %s" % type(splice_region) u""" @2019.01.04 If there is no bam, reduce the height of figure """ if no_bam: height = settings['height'] * (len(average_depths_dict) + len(splice_region.transcripts)) // 2 else: height = settings['height'] * (len(average_depths_dict) + len(splice_region.transcripts) // 2) plt.figure(figsize=[settings['width'], height], dpi=dpi) plot_density( settings, # plot settings, untouched read_depths_dict=average_depths_dict, # reads coverage splice_region=splice_region, # Exon and transcript information show_gene=show_gene, # decide whether display gene id in this plot no_bam=no_bam, log=log, title=title, distance_ratio=distance_ratio) logger.info("save to %s" % output_file_path) plt.savefig(output_file_path, transparent=True, bbox_inches='tight')
async def quintVotesDay(servID,ctx): # server id serverEntry = await fs.getServerEntry(fs.serverPath,servID) currentEvents = serverEntry['currentEvents'] currentEvents['quintVotes'] = True await fs.updateServerVal(fs.serverPath,servID,'currentEvents',currentEvents) await ctx.send("**It's Quintuple Vote Day!** Everyone in the server now has **5** votes to give out!\n" "All votes will be reset during the next drawing tomorrow!") logger.info(f' Started Quintuple Vote Day')
async def resetEvents(servID): # server id serverEntry = await fs.getServerEntry(fs.serverPath,servID) currentEvents = serverEntry['currentEvents'] logger.debug('Looping current events...') for event in currentEvents: currentEvents[event] = False logger.debug('All events set False...') await fs.updateServerVal(fs.serverPath,servID,'currentEvents',currentEvents) logger.info(f' Reset all events')
async def when(self, ctx): # gather variables from command server = ctx.guild serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) await ctx.send( f"**{ctx.guild.name} - {motdRole.name}**\n" f"**{serverEntry['timeStart']}** in *#{serverEntry['chanName']}*") logger.info(f'!when called by {ctx.author.name} in {ctx.guild.name}')
async def delServerDB(servID, servName): dataSe = await openJson(serverPath) dataV = await openJson(votePath) # delete server in server DB if str(servID) in dataSe: del dataSe[str(servID)] # delete server in voting DB if str(servID) in dataV: del dataV[str(servID)] await writeJson(serverPath, dataSe) await writeJson(votePath, dataV) logger.info(f'\nGuild removed from databases: {servName} | {servID}')
async def MOTDhelp(self, ctx): await ctx.send( 'Use the **!MOTDsetup** command to set up Member of the Day. ' 'In order to run Member of the Day on this server I will create a MOTD role ' 'and secret text channel. I will also need a text channel to post announcements ' 'in. This is determined by the text channel you run the setup command in. ' 'Lastly, I will need a specified minute (CST) during the day to run the script ' 'which should be formatted HRS:MINS after the command. ' 'For example, If the following was posted in the #general chat, I will announce ' 'a new member for the Member of the Day role at 10PM CST every day in #general: \n' '**!MOTDsetup 22:00** <--- (you can copy and paste this if you want)' ) logger.info(f'!MOTDhelp called in {ctx.guild.name}')
def read_reads_depth_from_bam(bam_list, splice_region, threshold=0, log=None, n_jobs=1): u""" read reads coverage info from all bams :param bam_list: namedtuple (alias, title, path, label) :param splice_region: SpliceRegion :param threshold: filter low abundance junctions :param log :param n_jobs :return: dict {alias, ReadDepth} """ logger.info("Reading from bam files") assert isinstance( splice_region, SpliceRegion ), "splice_region should be SplcieRegion, not %s" % type(splice_region) res = OrderedDict() try: # not using multiprocessing when only single process, in case the data size limitation of pickle issue if n_jobs == 1: for i in [[splice_region, bam, threshold, log, idx] for idx, bam in enumerate(bam_list)]: # print(i) res.update(__read_from_bam__(i)[0]) else: with Pool(min(n_jobs, len(bam_list))) as p: temp = p.map(__read_from_bam__, [[splice_region, bam, threshold, log, idx] for idx, bam in enumerate(bam_list)]) temp = [x for x in temp if x is not None] temp = sorted(temp, key=lambda x: x[1]) for i in temp: if i is None: continue res.update(i[0]) except Exception as err: logger.error(err) traceback.print_exc() exit(err) if len(res) == 0: logger.error("Error reading files, cannot read anything") exit(1) return res
async def on_guild_remove(guild): serverEntry = await fs.getServerEntry(fs.serverPath, guild.id) # delete server run time in rt.runTimes delRuntime = serverEntry['timeStart'] # only try to delete run time if its not None in db if delRuntime != None: if delRuntime in rt.runTimes: rt.runTimesDel(delRuntime) pass # delete server from DBs await fs.delServerDB(guild.id, guild.name) logger.info( f'\nServer List DB update: bot removed from {guild.name} | {guild.id}\n' )
async def updateScores(servID, motdID): scoresEntry = await getServerEntry(scorePath, servID) # if member has been picked before if str(motdID) in scoresEntry: scoresEntry[str(motdID)] += 1 sortedScores = { k: v for k, v in sorted( scoresEntry.items(), key=lambda x: x[1], reverse=True) } logger.info(f'Score added to ID {motdID}') # if member has NOT been picked before else: scoresEntry[str(motdID)] = 1 sortedScores = scoresEntry #sortedScores = {k: v for k, v in sorted(scoresEntry.items(), key=lambda x: x[1], reverse=True)} logger.info(f'ID {motdID} added to score dict') await updateServerEntry(scorePath, servID, sortedScores)
async def MOTDservs(self, ctx): if await fs.isAdmin(ctx.author): servLst = [] logger.info( f'ServList DB query: {ctx.author.name} in {ctx.guild.name} ({ctx.guild.id})' ) try: data = await fs.openJson(fs.serverPath) for a, b in data.items(): servLst.append(f"{b['servName']}" + " | " + f"#{b['chanName']}" + " | " + f"{b['timeStart']}\n") servLst = "".join(servLst) await ctx.send( '**Member of the Day - Server List & Run Times**\n' '```' + servLst + '```') except: await ctx.send('There are no servers in the database.')
async def exemptedroles(self, ctx): # gather variables from command serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) exemptRoles = serverEntry['exemptRoles'] if not exemptRoles: await ctx.send( f'There are no roles being exempted from {motdRole.name}') else: exemptNames = [] for roleid in exemptRoles: role = discord.utils.get(ctx.guild.roles, id=roleid) exemptNames.append(f'**{role.name}**') exemptNames = ", ".join(exemptNames) await ctx.send( f'Roles exempted from {motdRole.name}:\n{exemptNames}') logger.info( f'!exemptedroles called by {ctx.author.name} in {ctx.guild.name}')
async def on_guild_join(guild): sysChan = False if guild.system_channel != None: sysChan = True await guild.system_channel.send( f'Thanks for having me, {guild.name}\n' 'Use **!MOTDhelp** to learn how to start Member of the Day\n' 'Use **!help** to get a list of all my functions') logger.info('\n---------------------------------------\n' f'Joined {guild.name} with {guild.member_count} users!\n' f' System channel = {sysChan}\n' '---------------------------------------') await asyncio.sleep(1) botRole = discord.utils.get(guild.roles, name='MOTD Bot') await fs.addServerDB(guild.id, guild.name, botRole.id) if guild.system_channel != None: await guild.system_channel.send( f'Move my role ({botRole.mention}) above all hoisted roles to use Member of the Day!' )
async def servertotals(self, ctx): serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) scoresEntry = await fs.getServerEntry(fs.scorePath, ctx.guild.id) motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) # get counts try: counter1 = 0 counter2 = 0 for k, v in scoresEntry.items(): counter1 += v counter2 += 1 await ctx.send( f"**{ctx.guild.name} - {motdRole.name}**\n" f"*Total Picks:* {str(counter1)} **|** *Unique Winners:* {str(counter2)}" ) except: await ctx.send(f'There have been no picks in {ctx.guild.name}') logger.info( f'!servertotals called in {ctx.guild.name} by {ctx.author.name}')
async def getVoteLst(serv): # server object voteLst = [] votingEntry = await getServerEntry(votePath, serv.id) voteCounts = votingEntry['voteCounts'] badIDs = [] # get member objects from keys for k, v in voteCounts.items(): mem = serv.get_member(int(k)) # append number of mems to list based on value amount if mem != None: for i in range(v): voteLst.append(mem) else: badIDs.append(k) # if we cant get member, remove bad entry from our json if badIDs: for memID in badIDs: del voteCounts[memID] votingEntry['voteCounts'] = voteCounts await updateServerEntry(votePath, serv.id, votingEntry) logger.info(f'Bad member IDs in vote list! Deleted: {k}!') return voteLst
async def updateServerMOTD(servID, servName, chanName, chanID, timeRun, motdRoleID, secretChID): # open server list serverEntry = await getServerEntry(serverPath, servID) # adjust runTimes list in motd_times.py oldTime = serverEntry['timeStart'] if oldTime in rt.runTimes: rt.runTimesDel(oldTime) rt.runTimesAdd(timeRun) pass else: rt.runTimesAdd(timeRun) pass # replace values serverEntry['servName'] = servName serverEntry['chanName'] = chanName serverEntry['channelID'] = chanID serverEntry['timeStart'] = timeRun serverEntry['motdRoleID'] = motdRoleID serverEntry['secretChID'] = secretChID # update server list await updateServerEntry(serverPath, servID, serverEntry) logger.info(f'\nServList DB update: {servName} | #{chanName} | {timeRun}\n' f' *Updated run-time entry: {oldTime} --> {timeRun}')
async def MOTDpause(self, ctx): if await fs.isAdmin(ctx.author): serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) try: if serverEntry['isPaused'] == False: await fs.updateServerVal(fs.serverPath, ctx.guild.id, 'isPaused', True) await ctx.send( f'I am now **PAUSED** on *{ctx.guild.name}*!\n' 'Use !MOTDpause again to unpause me!') logger.info( f'\nServer List DB update: {ctx.guild.name} | isPaused: True' ) else: await fs.updateServerVal(fs.serverPath, ctx.guild.id, 'isPaused', False) await ctx.send( f'I am now **UNPAUSED** on *{ctx.guild.name}*!\n' 'Use !MOTDpause again to pause me!') logger.info( f'\nServer List DB update: {ctx.guild.name} | isPaused: False' ) except: await ctx.send('**An error occurred!**')
async def MOTDreminder(self, ctx): if await fs.isAdmin(ctx.author): serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) try: if serverEntry['reminder'] == True: await fs.updateServerVal(fs.serverPath, ctx.guild.id, 'reminder', False) await ctx.send( f'I will **NOT** remind an hour before on *{ctx.guild.name}*!\n' 'Use !MOTDreminder again to enable the reminder!') logger.info( f'\nServer List DB update: {ctx.guild.name} | reminder: False' ) else: await fs.updateServerVal(fs.serverPath, ctx.guild.id, 'reminder', True) await ctx.send( f'I **WILL** remind an hour before on *{ctx.guild.name}*!\n' 'Use !MOTDreminder again to enable the reminder!') logger.info( f'\nServer List DB update: {ctx.guild.name} | reminder: True' ) except: await ctx.send('**An error occurred!**')
def read_transcripts(gtf_file, region, genome=None, retry=0): u""" Read transcripts from tabix indexed gtf files The original function check if the junctions corresponding to any exists exons, I disable this here :param gtf_file: path to bgzip gtf files (with tabix index), only ordered exons in this gtf file :param region: splice region :param retry: if the gtf chromosome and input chromosome does not match. eg: chr9:1-100:+ <-> 9:1-100:+ :param genome: path to genome fasta file :return: SpliceRegion """ if not os.path.exists(gtf_file): raise FileNotFoundError("%s not found" % gtf_file) try: logger.info("Reading from %s" % gtf_file) if genome: with pysam.FastaFile(genome) as fa: region.sequence = fa.fetch(region.chromosome, region.start - 1, region.end + 1) with pysam.Tabixfile(gtf_file, 'r') as gtf_tabix: relevant_exons_iterator = gtf_tabix.fetch(region.chromosome, region.start - 1, region.end + 1, parser=pysam.asGTF()) # min_exon_start, max_exon_end, exons_list = float("inf"), float("-inf"), [] for line in relevant_exons_iterator: try: region.add_gtf(line) except IndexError as err: logger.error(err) except ValueError as err: logger.warn(err) # handle the mismatch of chromosomes here if retry < 2: if not region.chromosome.startswith("chr"): logger.info("Guess need 'chr'") region.chromosome = "chr" + region.chromosome else: logger.info("Guess 'chr' is redundant") region.chromosome = region.chromosome.replace("chr", "") return read_transcripts(gtf_file=gtf_file, region=region, retry=retry + 1) return region
async def on_ready(): logger.info(f'\n** BOT STARTED: {bot.user.name} - {bot.user.id} **') # gather run times from server db rt.runTimesInit() await bot.change_presence(activity=gamePlaying)
pm_help=True, intents=intents) gamePlaying = discord.Game(name='!vote | !score') # gamePlaying = discord.Streaming(name='!vote | !score', # url='https://www.twitch.tv/thegreendonut') # define extensions #cogsLoc = '/home/pi/code_pi/gavinbot/cogs/' initial_extensions = ['cogs.motd_cmds', 'cogs.motd_looper'] # load extensions if __name__ == '__main__': for extension in initial_extensions: try: bot.load_extension(extension) logger.info(f'Loaded extension {extension}.') except Exception as e: logger.warning(f'Failed to load extension {extension}.') traceback.print_exc() # bot main start @bot.event async def on_ready(): logger.info(f'\n** BOT STARTED: {bot.user.name} - {bot.user.id} **') # gather run times from server db rt.runTimesInit() await bot.change_presence(activity=gamePlaying) # --- ERROR & COOLDOWN RESPONSES
def index_gtf(input_gtf, sort_gtf=True, retry=0): u""" Created by ygidtu Extract only exon tags and keep it clean :param input_gtf: path to input gtf file :param sort_gtf: Boolean value, whether to sort gtf file first :param retry: only try to sort gtf once :return path to compressed and indexed bgzipped gtf file """ gtf = is_gtf(input_gtf) if gtf % 10 != 1: raise ValueError("gtf file required, %s seems not a valid gtf file" % input_gtf) index = False if gtf // 10 > 0: output_gtf = input_gtf else: output_gtf = input_gtf + ".gz" if not os.path.exists(output_gtf) or not os.path.exists(output_gtf + ".tbi"): index = True elif os.path.getctime(output_gtf) < os.path.getctime(output_gtf) or \ os.path.getctime(output_gtf) < os.path.getctime(output_gtf): index = True # 2018.12.21 used to handle gtf not sorted error if sort_gtf and retry > 1: raise OSError( "Create index for %s failed, and trying to sort it failed too" % input_gtf) elif sort_gtf: data = [] logger.info("Sorting %s" % input_gtf) old_input_gtf = input_gtf input_gtf = re.sub("\.gtf$", "", input_gtf) + ".sorted.gtf" output_gtf = input_gtf + ".gz" if os.path.exists(input_gtf) and os.path.exists(output_gtf): return output_gtf try: w = open(input_gtf, "w+") except IOError as err: w = open("/tmp/sorted.gtf") with open(old_input_gtf) as r: for line in tqdm(r): if line.startswith("#"): w.write(line) continue lines = line.split() if len(lines) < 1: continue data.append( GenomicLoci(chromosome=lines[0], start=lines[3], end=lines[4], strand=lines[6], gtf_line=line)) for i in sorted(data): w.write(i.gtf_line) w.close() if index: logger.info("Create index for %s", input_gtf) try: pysam.tabix_index(input_gtf, preset="gff", force=True, keep_original=True) except OSError as err: if re.search("could not open", str(err)): raise err logger.error(err) logger.error("Guess gtf needs to be sorted") return index_gtf(input_gtf=input_gtf, sort_gtf=True, retry=retry + 1) return output_gtf
def read_reads_depth_from_count_table(count_table, splice_region, required, colors, threshold=0): u""" Read junction counts from count_table :param count_table: path to count table :param splice_region: :param required: list of str, which columns are required to draw :param threshold: threshold to filter out low abundance junctions :param colors: {key: color} :return: {label: ReadDepth} """ data = {} header = {} with open(count_table) as r: for line in r: lines = line.split() if not header: for i, j in enumerate(lines): header[i] = clean_star_filename(j) else: # check file header, to avoide file format error if len(header) == len(lines) - 1: logger.info( "Change header index due to: Number of headers == number of columns - 1" ) new_header = {k + 1: v for k, v in header.items()} header = new_header for i, j in enumerate(lines): if i == 0: tmp = GenomicLoci.create_loci(lines[0]) if not splice_region.is_overlap(tmp): break else: key = header[i] if required: if header[i] in required.keys(): key = required[header[i]] else: continue tmp_junctions = data[key] if key in data.keys() else {} if j != "NA" and int(j) >= threshold: tmp_junctions[lines[0]] = int(j) data[key] = tmp_junctions res = {} for key, value in data.items(): # customized junctions will introduce string type of key, and list of colors # use this try catch to convert key to index to assign colors try: color = colors[key] except TypeError: color = colors[len(res) % len(colors)] key = BamInfo(path=None, alias=key, label=None, title="", color=color) res[key] = ReadDepth.create_depth(value, splice_region) res[key].shrink(splice_region.start, splice_region.end) return res
async def vote(self, ctx, *, member: discord.Member): # TEMP # await ctx.channel.purge(limit = 1) serverEntry = await fs.getServerEntry(fs.serverPath, ctx.guild.id) votingEntry = await fs.getServerEntry(fs.votePath, ctx.guild.id) currentMOTD = serverEntry['currentMOTD'] exemptRoles = serverEntry['exemptRoles'] usedVotes = votingEntry['usedVotes'] voteCounts = votingEntry['voteCounts'] motdRole = discord.utils.get(ctx.guild.roles, id=serverEntry['motdRoleID']) # TEMP #if member votes themselves if ctx.author.id == member.id: await ctx.author.edit(nick="I TRIED VOTING MYSELF") await ctx.send(f'You cannot vote for yourself!') return # if member votes a bot if member.bot: await ctx.send(f'You cannot vote for bots!') return # if member votes current MOTD elif member.id == currentMOTD: await ctx.send( f'This member is currently the {motdRole.name} and cannot be voted for today!' ) return # if member votes exempted member elif any(r.id in exemptRoles for r in member.roles): await ctx.send( f'This member is currently exempted from {motdRole.name} and cannot be voted for!' ) return # if member already voted elif str(ctx.author.id) in usedVotes: # check if event is active for more votes if await ev.eventStatus(ctx.guild.id, 'quintVotes') != True: await ctx.send(f'You have used up all of your votes today!') return elif usedVotes[str(ctx.author.id)] >= 5: await ctx.send(f'You have used up all of your votes today!') return # if author hasnt voted today or has more votes to give try: # update usedVotes with author if str(ctx.author.id) in usedVotes: usedVotes[str(ctx.author.id)] += 1 else: usedVotes[str(ctx.author.id)] = 1 # update voteCounts with votee if str(member.id) in voteCounts: voteCounts[str(member.id)] += 1 else: voteCounts[str(member.id)] = 1 # update usedVotes + voteCounts dicts votingEntry['usedVotes'] = usedVotes votingEntry['voteCounts'] = voteCounts # write voting dict await fs.updateServerEntry(fs.votePath, ctx.guild.id, votingEntry) logger.info( f'\n{ctx.author.name} voted for {member.name} in {ctx.guild.name}.' f'\nTotal votes: {voteCounts[str(member.id)]}') # TEMP await ctx.send( f'{ctx.author.name} voted for **{member.name}**. Total votes: **{voteCounts[str(member.id)]}**' ) # await ctx.send(f'{ctx.author.name} voted! Used votes: **{usedVotes[str(ctx.author.id)]}** out of 5') except: await ctx.send('**An error occurred!**')