def piazza_reader(email, password, coursecode): # User credentials piazza = Piazza() # Login piazza.user_login(email, password) class_dictionary = piazza.get_user_classes() # dictionary for 'course code: hash_id' coursetohash = {} # print(len(class_dictionary)) for i in range(len(class_dictionary)): coursetohash.update( {class_dictionary[i]['num']: class_dictionary[i]['nid']}) print(coursetohash) classroom = piazza.network(coursetohash[coursecode]) # print(coursecode) # print(coursetohash[coursecode]) # go through all the posts, aggregate them in a data-structure postquestions = [] postanswers = [] # board_posts type is generator: cannot access memory in the lazy list board_posts = classroom.iter_all_posts(limit=const_limit) # iterate through board posts for post in board_posts: # get rid of html tags in question in post question_string = strip_tags(post["history"][0]["content"]) # append to questions array postquestions.append(question_string) # checks if there's an answer associated to the question if "children" in post.keys( ) and post["children"] and "history" in post["children"][0]: # for all answers in a single post (iterate) for answer_index in range(len(post["children"][0]["history"])): # get rid of html tags for answers in the post, and check if the entry is a string if type(post["children"][0]["history"][answer_index] ["content"]) == str: answer_string = strip_tags(post["children"][0]["history"] [answer_index]["content"]) # append to answers array postanswers.append(answer_string) # print(postQuestions + postAnswers) return " ".join(postquestions + postanswers)
def login(email, password): piazza = Piazza() piazza.user_login(email, password) class_dictionary = piazza.get_user_classes() return class_dictionary courseToHash = {} #print(len(class_dictionary)) for i in range(len(class_dictionary)): courseToHash.update( {class_dictionary[i]['num']: class_dictionary[i]['nid']})
def course_list(email, password): # User credentials piazza = Piazza() # Login piazza.user_login(email, password) # create class dictionary from user class details: we are interested in the "num" key class_dictionary = piazza.get_user_classes() course_code_list = [] for index in range((len(class_dictionary))): course_code_list.append(class_dictionary[index]['num']) return course_code_list
def course_hash(email, password): # User credentials piazza = Piazza() # Login piazza.user_login(email, password) class_dictionary = piazza.get_user_classes() # dictionary for 'course code: hash_id' course_to_hash = {} # print(len(class_dictionary)) for i in range(len(class_dictionary)): course_to_hash.update( {class_dictionary[i]['num']: class_dictionary[i]['nid']}) return course_to_hash
def get_data(self): return ''.join(self.fed) def strip_tags(html): s = MLStripper() s.feed(html) return s.get_data() p = Piazza() p.user_login("*****@*****.**", "59170864aS@") #TODO UPON ASKING FOR USER CREDENTIALS, LOGIN TO THEIR PIAZZA ACCOUNT stat200101 = p.network("jz1p1pgbr9e15c") classes = p.get_user_classes() print(classes) print(stat200101) # this gets the contents of a post: the question tempPost = stat200101.get_post("361") tempPostContent = tempPost["history"][0]["content"] strippedQuestion = strip_tags(tempPostContent) tempPostAns = tempPost["children"][0]["history"][0]["content"] strippedAns = strip_tags(tempPostAns) # go through all the posts, aggregate them in a datastructure # store that in for easy access postQuestions = [] postAnswers = [] postQuestions2 = {}
def getPiazzaInfo(username, password): # get our api from piazza_api import Piazza import time # initalize piazza client p = Piazza() # login p.user_login(email=username, password=password) # get our class list classes = p.get_user_classes() # information for all classes classesInfo = [] # iterate till we have one item per class in the list, # containing all needed elements for that class for c in classes: # individual class information classInfo = {} # set class name and number as per piazza classInfo['name'] = c['name'] classInfo['number'] = c['num'] # get url/nid of the class curClass = p.network(c['nid']) # get our iterator for the posts of that class posts = curClass.iter_all_posts(limit=5) # store post info in here neededInfo = [] # since piazza api has a speed limit, # we are enclosing the data in a try catch try: # iterate through posts for post in posts: # store post information in here postInfo = {} # set post subject and content postInfo['subject'] = post['history'][0]['subject'] postInfo['content'] = post['history'][0]['content'] # store followups information here postInfo['followUps'] = [] # iterate through 'main' follow ups for mainFollowUp in post['children']: # if the follow up has a subject, then # it is valid if 'subject' in mainFollowUp: # store followup info here followUp = {} # set followup information followUp['mainComment'] = mainFollowUp['subject'] # store and iterate through follow up responses followUp['subComments'] = [] for subComment in mainFollowUp['children']: followUp['subComments'].append( subComment['subject']) # append followup to followups postInfo['followUps'].append(followUp) # append post to posts neededInfo.append(postInfo) # store posts information for a class classInfo['posts'] = neededInfo # add class information to our list classesInfo.append(classInfo) except: # if we tried too fast, # then there was an error print("piazza api trying too fast!") # return our object of class informations return classesInfo
def piazza_parse(pi_url): temp = "" p = Piazza() p.user_login(email=os.environ['EMAIL'], password=os.environ['PASSWORD']) classes = p.get_user_classes() #piazza_url = urlparse(sys.argv[1]) piazza_url = urlparse(pi_url) class_id = piazza_url.path.split('/')[2] post_num = piazza_url.query.split('=')[1] # Returns a class network class_net = p.network(class_id) post = class_net.get_post(post_num) class_name = "None" for i in classes: if i['nid'] == class_id: class_name = i['num'] question = post["history"][0]["content"] subject = post["history"][0]["subject"] # print("QUESTION JSON") # print('-----------------') # print(post["history"][0]) # print() temp += "__**CLASS NAME**__\n" temp += class_name + '\n\n' temp += "__**SUBJECT**__\n" temp += subject + '\n\n' # Content of post that includes html tags # # print("CONTENT") # print('-----------------') # print(question) # print() temp += "__**CONTENT**__\n" question_text = BeautifulSoup(question, features='lxml').text temp += question_text + '\n\n' answers = post["children"] #TODO concatenate all answers? or just one #temp += answers s_answer_json = None i_answer_json = None for answer in answers: if answer['type'] == 's_answer': s_answer_json = answer elif answer['type'] == 'i_answer': i_answer_json = answer if s_answer_json is not None: temp += "__**STUDENT ANSWER**__\n" s_answer = s_answer_json['history'][0]['content'] s_answer_text = BeautifulSoup(s_answer, features='lxml').text temp += s_answer_text + '\n\n' if i_answer_json is not None: temp += "__**INSTRUCTOR ANSWER**__\n" i_answer = i_answer_json['history'][0]['content'] i_answer_text = BeautifulSoup(i_answer, features='lxml').text temp += i_answer_text # print(i_answer_text) # print() return temp
class PiazzaCompileBot(object): def __init__(self): self.p = Piazza() self.p.user_login(PIAZZA_USER, PIAZZA_PASS) self.uid = self.p.get_user_profile()['user_id'] classes = self.p.get_user_classes() self.classes = [] print 'Now watching posts for the following {0} classes:'.format(len(classes)) for c in classes: print '{0} ({1}, {2})'.format(c['num'], c['name'], c['term']) self.classes.append(self.p.network(c['nid'])) self.filter = UnreadFilter() def check(self): for c in self.classes: # ensure we go through the entire feed if there are more posts to read feed = {'more': True} while feed['more']: # filter for only updated posts feed = c.get_filtered_feed(self.filter) for feed_post in feed['feed']: # get the post number and retrieve the post post = c.get_post(feed_post['nr']) if self.already_compiled(post): print 'Post %s already compiled' % post['id'] break post_text = post['history'][0]['content'] print 'Checking post %s for code' % post['id'] # parse the text in the post # example text: """ <p></p><p>I'm having an issue, please help!</p> <p>CompileBot! python</p> <pre>def __init__(self): print 'blah'</pre> <p>Input:</p> <pre>blah</pre> """ soup = BeautifulSoup(post_text.replace("<br />", "\n")) # Look for p tags tags = soup.find_all('p') for tag in tags: try: m = None if not tag.contents else re.search(r'(?i)CompileBot[.?;:!]*\s*(?P<args>.*)\s*', tag.contents[0]) if m is not None and tag.next_sibling and tag.next_sibling.next_sibling: # look for code code = None cur_tag = tag.next_sibling.next_sibling if cur_tag and cur_tag.name == 'pre': code = cur_tag.contents[0] # look for optional stdin if code is not None: stdin = '' if cur_tag.next_sibling and cur_tag.next_sibling.next_sibling: cur_tag = cur_tag.next_sibling.next_sibling try: if cur_tag.name == 'p' and bool(re.match('input', cur_tag.contents[0], re.I)) and cur_tag.next_sibling: cur_tag = cur_tag.next_sibling.next_sibling if cur_tag and cur_tag.name == 'pre': stdin = cur_tag.contents[0] cur_tag = cur_tag.next_sibling except Exception as e: pass else: pass code = urllib.unquote(code) stdin = urllib.unquote(stdin) try: lang, opts = m.group('args').split(' -', 1) opts = ('-' + opts).split() except ValueError: # No additional opts found lang, opts = m.group('args'), [] lang = lang.strip() print 'Attempting compile for post {0}: language={1}, args={2}'.format(post['id'], lang, opts) try: details = self.compile(code, lang, stdin=stdin) print "Compiled ideone submission {link} for comment {id}".format(link=details['link'], id=post['id']) # The ideone submission result value indicaties the final state of # the program. If the program compiled and ran successfully the # result is 15. Other codes indicate various errors. result_code = details['result'] # The user is alerted of any errors via message reply unless they # include an option to include errors in the reply. if result_code in [11, 12, 15]: text = self.format_reply(details, opts) ideone_link = "http://ideone.com/{}".format(details['link']) text += "Ideone link: %s" % ideone_link print 'Compilation success!\n%s' % text c.add_followup(post['id'], text) print 'Posted results to Piazza' else: error_text = { 11: COMPILE_ERROR_TEXT, 12: RUNTIME_ERROR_TEXT, 13: TIMEOUT_ERROR_TEXT, 17: MEMORY_ERROR_TEXT, 19: ILLEGAL_ERROR_TEXT, 20: INTERNAL_ERROR_TEXT }.get(result_code, '') # Include any output from the submission in the reply. if details['cmpinfo']: error_text += "Compiler Output:\n{}\n".format( self.code_block(details['cmpinfo'])) if details['output']: error_text += "Output:\n{}\n".format( self.code_block(details['output'])) if details['stderr']: error_text += "Error Output:\n{}\n".format( self.code_block(details['stderr'])) print 'Error: %s' % error_text except ideone.IdeoneError as e: c.add_followup(post['id'], 'An Ideone error occurred.\n%s' % self.code_block(e)) print e except ValueError as e: import traceback, os.path, sys top = traceback.extract_tb(sys.exc_info()[2])[-1] print 'Parse failed: {0}'.format(', '.join([type(e).__name__, os.path.basename(top[0]), str(top[1])])) def already_compiled(self, post): children = post['children'] for child in children: if child['uid'] == self.uid: return True return False def compile(self, source, lang, stdin=''): """Compile and evaluate source sode using the ideone API and return a dict containing the output details. Keyword arguments: source -- a string containing source code to be compiled and evaluated lang -- the programming language pertaining to the source code stdin -- optional "standard input" for the program >>> d = compile('print("Hello World")', 'python') >>> d['output'] Hello World """ lang = LANG_ALIASES.get(lang.lower(), lang) # Login to ideone and create a submission i = ideone.Ideone(IDEONE_USER, IDEONE_PASS) sub = i.create_submission(source, language_name=lang, std_input=stdin) sub_link = sub['link'] details = i.submission_details(sub_link) # The status of the submission indicates whether or not the source has # finished executing. A status of 0 indicates the submission is finished. while details['status'] != 0: details = i.submission_details(sub_link) time.sleep(3) details['link'] = sub_link return details def format_reply(self, details, opts): """Returns a reply that contains the output from a ideone submission's details along with optional additional information. """ head, body, extra, = '', '', '' # Combine information that will go before the output. if '--source' in opts: head += 'Source:\n{}\n\n'.format(self.code_block(details['source'])) if '--input' in opts: # Combine program output and runtime error output. head += 'Input:\n{}\n\n'.format(self.code_block(details['input'])) output = details['output'] + details['stderr'] # Truncate the output if it contains an excessive # amount of line breaks or if it is too long. if output.count('\n') > LINE_LIMIT: lines = output.split('\n') # If message contains an excessive amount of duplicate lines, # truncate to a small amount of lines to discourage spamming if len(set(lines)) < 5: lines_allowed = 2 else: lines_allowed = 51 output = '\n'.join(lines[:lines_allowed]) output += "\n..." # Truncate the output if it is too long. if len(output) > 8000: output = output[:8000] + '\n ...\n' body += 'Output:\n{}\n\n'.format(self.code_block(output)) if details['cmpinfo']: body += 'Compiler Info:\n{}\n\n'.format(details['cmpinfo']) # Combine extra runtime information. if '--date' in opts: extra += "Date: {}\n\n".format(details['date']) if '--memory' in opts: extra += "Memory Usage: {} bytes\n\n".format(details['memory']) if '--time' in opts: extra += "Execution Time: {} seconds\n\n".format(details['time']) if '--version' in opts: extra += "Version: {}\n\n".format(details['langVersion']) # To ensure the reply is less than 10000 characters long, shorten # sections of the reply until they are of adequate length. Certain # sections with less priority will be shortened before others. total_len = 0 for section in (FOOTER, body, head, extra): if len(section) + total_len > 9800: section = section[:9800 - total_len] + '\n...\n' total_len += len(section) reply_text = head + body + extra return reply_text def code_block(self, output): return "<pre>{0}</pre>".format(output)
from piazza_api import Piazza from bs4 import BeautifulSoup import requests from lxml import html import lxml.html import pandas as pd import re p = Piazza() # In[2]: person = p.user_login('*****@*****.**', 'PASSWORD') user_profile = p.get_user_profile() print() user_classes = p.get_user_classes() print(p) CSE110 = p.network("jebhpmejaa92vh") print(type(CSE110)) #CSE110.get_post(10) #posts = CSE110.iter_all_posts(limit=1) #for post in posts: # for i in post: # print(i) # In[3]: for i in CSE110.feed_filters: print(i) print(type(CSE110.feed_filters))
def piazza_parse(pi_url): ''' Called by connect.py to get post from Piazza. It will format the post json into a more readable message for server. ''' # Create Piazza object, login, and get the users classes temp = "" p = Piazza() p.user_login(email=os.environ['EMAIL'], password=os.environ['PASSWORD']) classes = p.get_user_classes() # Parse the piazza url into components piazza_url = urlparse(pi_url) # Get class id and the post number from piazza_url class_id = piazza_url.path.split('/')[2] post_num = piazza_url.query.split('=')[1] # Returns a class network class_net = p.network(class_id) # Get the piazza post from the post number and class network post = class_net.get_post(post_num) # Get class name class_name = "None" for i in classes: if i['nid'] == class_id: class_name = i['num'] # Get question and subject of the post question = post["history"][0]["content"] subject = post["history"][0]["subject"] # Format class name, subject, and post content for Discord temp += "__**CLASS NAME**__\n" temp += class_name + '\n\n' temp += "__**SUBJECT**__\n" temp += subject + '\n\n' temp += "__**CONTENT**__\n" question_text = BeautifulSoup(question, features='lxml').text temp += question_text + '\n\n' # Get answers json answers = post["children"] # Init student and instructor json answers s_answer_json = None i_answer_json = None # Assign student and instructor answers if they exist for answer in answers: if answer['type'] == 's_answer': s_answer_json = answer elif answer['type'] == 'i_answer': i_answer_json = answer # Format student and/or instructor answer if they exist if s_answer_json is not None: temp += "__**STUDENT ANSWER**__\n" s_answer = s_answer_json['history'][0]['content'] s_answer_text = BeautifulSoup(s_answer, features='lxml').text temp += s_answer_text + '\n\n' if i_answer_json is not None: temp += "__**INSTRUCTOR ANSWER**__\n" i_answer = i_answer_json['history'][0]['content'] i_answer_text = BeautifulSoup(i_answer, features='lxml').text temp += i_answer_text return temp
def piazza_parse(pi_url, email, passwd, author): ''' Called by connect.py to get post from Piazza. It will format the post json into a more readable message for server. ''' # Create Piazza object, login, and get the users classes data = {} p = Piazza() p.user_login(email=email, password=passwd) classes = p.get_user_classes() # Parse the piazza url into components piazza_url = urlparse(pi_url) # Get class id and the post number from piazza_url class_id = piazza_url.path.split('/')[2] post_num = piazza_url.query.split('=')[1] # Returns a class network class_net = p.network(class_id) # Get the piazza post from the post number and class network post = class_net.get_post(post_num) # Get class name class_name = "None" for i in classes: if i['nid'] == class_id: class_name = i['num'] # Get question and subject of the post question = post["history"][0]["content"] subject = post["history"][0]["subject"] # Format data to return data.setdefault("class_name", class_name) if not data['class_name']: data['class_name'] = ZERO_WHITE_SPACE data.setdefault("question", subject) if not data['question']: data['question'] = ZERO_WHITE_SPACE # data.setdefault("subject", subject) data.setdefault("question_text", BeautifulSoup(question, features='lxml').text) if not data['question_text']: data['question_text'] = ZERO_WHITE_SPACE if not data['question_text']: data['question'] = ZERO_WHITE_SPACE data.setdefault("answer", {'instructor': '', 'student': ''}) # Get answers json answers = post["children"] # Assign student and instructor answers if they exist for answer in answers: if answer['type'] == 's_answer': data['answer']['student'] = BeautifulSoup( answer['history'][0]['content'], features='lxml').text elif answer['type'] == 'i_answer': data['answer']['instructor'] = BeautifulSoup( answer['history'][0]['content'], features='lxml').text return embed_creator(data, pi_url, author)