0

To start with, I've looked at all other solutions. I've made sure that my IDE/Editor (Atom) is not catching inputs. I've looked to see if any of my code is awkwardly blocking Ctrl-C's. I've use time.sleep, signal, threads, you name it. I cannot figure out why sending a Ctrl-C does not stop my Python program (but killing it via Activity Monitor does). Here is the code

from user_data_manager import DataManager
from get_data import SkywardDataManager
from getpass import getpass
from typing import Dict, List, Any
import time
def get_diff(new_grades: Dict[str, Any], old_grades: Dict[str, Any]) -> Dict[str, Any]:
    difference = {} #type: Dict[str, List[Dict[str, str]]]

    for class_name in new_grades.keys():
        if class_name in old_grades.keys():
            new_grade_list = new_grades[class_name]
            old_grade_list = old_grades[class_name]
            diff = [
                item
                for item in new_grade_list if item not in old_grade_list
            ]
            difference[class_name] = diff
    return difference

def print_grade_diff(grades: SkywardDataManager, student: DataManager) -> None:
    new_grades = grades.get_grades()
    old_grades = student.load()
    diff = get_diff(new_grades, old_grades)
    student.write(new_grades)
    print(diff)

def main() -> None:
    default_conf = {
        "username": "",
        "password": ""
    }
    dm = DataManager("./conf.json", def_obj=default_conf)
    data = dm.load()

    username = data["username"]
    password = data["password"]

    GDM = None
    while True:
        try:
            if username == "" or password == "":
                username = input("Skyward username: ")
                password = getpass("Skyward password: ")
            GDM = SkywardDataManager(username, password)
            break
        except ValueError:
            print("Incorrect username or password, please try again.")
            username = input("Skyward username: ")
            password = getpass("Skyward password: ")
        except KeyboardInterrupt:
            print("Hellow")

    sdm = DataManager("./grades/{0}.json".format(username))
    print_grade_diff(GDM, sdm)


old_time = 0
while True:
    try:
        new_time = time.time()
        if new_time - old_time > 5*60:
            print("running")
            old_time = time.time()
            main()
    except KeyboardInterrupt:
        print("Hello")
        still_going = False
        exit

user_data_manager is just a piece of code I use to interface with a JSON file, and get_data.py looks like this

from requests_html import HTMLSession, HTML
import getpass
import os
from user_data_manager import DataManager
from typing import Dict, List, Any

session = HTMLSession()

base_url = "https://skyward.iscorp.com/scripts/wsisa.dll/WService=wseduoakparkrfil"
login_url = base_url + "/skyporthttp.w"

def parse_login_text(text: str) -> Dict[str, Any]:
    text = text.replace("<li>", "").replace("</li>", "")

    values = text.split("^")

    new_url = base_url + "/" + values[7]
    encses = values[14]
    data = {
        "params": {
            "dwd": values[0],
            "web-data-recid": values[1],
            "wfaacl-recid": values[2],
            "wfaacl": values[3],
            "nameid": values[4],
            "duserid": values[5],
            "User-Type": values[6],
            "enc": values[13],
            "encses": encses
        },
        "new_url": new_url,
        "encses": values[14]
    }
    return data

class SkywardDataManager():
    def __init__(self, usern: str, passw: str) -> None:
        self.username = usern
        self.password = passw
        data = self.login()
        self.login_data = data

    def login(self) -> Dict[str, Any]:
        req_dm = DataManager("./default_request_conf.json")
        params = req_dm.load()
        params["codeValue"] = self.username
        params["login"] = self.username
        params["password"] = self.password
        req = session.post(login_url, data=params)
        text = req.text
        if "Invalid" in text:
            raise ValueError("Incorrect username or password")
        return parse_login_text(text)

    def get_session_params(self) -> Dict[str, str]:
        ldata = self.login_data

        req2 = session.post(ldata["new_url"], data=ldata["params"])
        page = req2.html

        sessid = page.find("#sessionid", first=True).attrs["value"]

        encses = page.find("#encses", first=True).attrs["value"]

        return {
            "sessid": sessid,
            "encses": encses
        }

    def get_grades(self) -> Dict[str, List[Dict[str, str]]]:
        grade_url = base_url + "/sfgradebook001.w"
        sessionp = self.get_session_params()
        req3 = session.post(grade_url, data={
            "encses": sessionp["encses"],
            "sessionid": sessionp["sessid"]
        })
        new_text = req3.text
        new_text = new_text.replace(
            "src='",
            "src='{0}/".format(base_url)
        ).replace(
            "href='",
            "href='{0}/".format(base_url)
        )
        '''
            Replacing values here to make sure that all requests
            are being made to the skyward site and not the local
            computer.
        '''

        new_html = HTML(html=new_text)
        with open("./page.html", "w") as f:
            f.write(new_html.html)
        new_html.render()
        i = 1

        grades = {} # type: Dict[str, List[Dict[str, str]]]
        tr_with_rownum = list(
            filter(
                lambda elem: "data-rownum" in elem.attrs.keys(),
                new_html.find("tr")
            )
        )
        current_class = ""

        while True:
            elems = list(
                filter(
                    lambda elem: elem.attrs["data-rownum"] == str(i),
                    tr_with_rownum
                )
            )
            if elems == []:
                break # No more assignments/classes
            i += 1
            elems_text = list(
                map(
                    lambda elem: elem.text,
                    elems
                )
            )
            if "Period" in elems_text[1] and "Due:" not in elems_text[1]:
                # This represents a class row
                current_class = elems_text[1].split("\n")[0]
                overall_grades = elems_text[0].split("\n")
                grades[current_class] = []
                semester1_grades = overall_grades[0:4]
                # Semester 1 is the first 4 Grades
                # Q1, Q2, EX1, SM1
                semester2_grades = overall_grades[4:]
                #Semester 2 is the last 4 Grades
                # Q3, Q4, EX2, SM2
                quarter_grades = [] # type: List[str]
                exam_grades = [] # type: List[str]
                semester_grades = [] # type: List[str]
                if len(semester1_grades) == 4:
                    quarter_grades += semester1_grades[:-2]
                    exam_grades += semester1_grades[-2]
                    semester1_grades += semester1_grades[-1]
                else:
                    quarter_grades += semester1_grades[:-1]
                    exam_grades = None
                    semester_grades += semester1_grades[-1]
                if len(semester2_grades) == 4:
                    quarter_grades += semester2_grades[:-2]
                    exam_grades += semester2_grades[-2]
                    semester1_grades += semester2_grades[-1]
                elif len(semester2_grades) > 0:
                    quarter_grades += semester2_grades[:-1]
                    semester_grades += semester2_grades[-1]
                for num, grade in enumerate(quarter_grades):
                    grades[current_class].append({
                        "Quarter {0}".format(num+1): grade
                    })
                for num, grade in enumerate(semester_grades):
                    grades[current_class].append({
                        "Semester {0}".format(num+1): grade
                    })
                if exam_grades != None:
                    for num, grade in enumerate(exam_grades):
                        grades[current_class].append({
                            "Exam {0}".format(num+1): grade
                        })

            else:
                # This represents an assignment
                assignment_name = elems_text[1].split("\n")[0]
                grade = elems_text[0]
                if assignment_name != "Next 4...":
                    grades[current_class].append({
                        assignment_name: grade
                    })

        return grades

I don't see why something in get_data or main would interfere with catching SIGINT's, but I'm not an expert. Why can't I exit my code?

EDIT: If it helps, I can exit perfectly before main() prints, but after I cannot exit out.

Garrett Credi
  • 100
  • 1
  • 9
  • 1
    Perhaps that `exit` was supposed to be `exit()`, so that it actually does something? – jasonharper Sep 09 '18 at 01:33
  • @jasonharper Yeah, but even with replacing it the process still does not quit. – Garrett Credi Sep 09 '18 at 01:38
  • The other `except KeyboardInterrupt:` is inside an infinite loop, so if that's where the Ctrl-C gets caught, it goes nowhere. Why are you even catching this exception if you actually want it to end the program? – jasonharper Sep 09 '18 at 01:42
  • @jasonharper I'm trying to catch it because that's initially what I found as a solution to something not being caught in an infinite periodic loop. – Garrett Credi Sep 09 '18 at 01:45
  • If you must catch `KeyboardInterrupt` in an inner loop, then you need to `raise` it again, rather than throwing it way! But I doubt that's actually the solution to the underlying problem, whatever it might be. – jasonharper Sep 09 '18 at 01:49

1 Answers1

0

I tried testing with KeyboardInterrput in IDLE, it raised a KeyboardInterrupt perfectly. If it really really does not work for you, I suggest you use other means of managing hotkeys.

Edit: KeyboardInterrpu appears when appeared, but it could not be detected by an except statement. The most probable reason could be that KeyboardInterrupt is not inherited from BaseException, which has the coding that allows errors to be caught. Hope this helps!

Prometheus
  • 618
  • 1
  • 7
  • 23
  • How could you have ran it? If I can analyze my own code correctly, there should not be enough code provided for it to run... – Garrett Credi Sep 09 '18 at 01:34
  • I just saw what you meant. I think I tried to detect for the KeyboardInterrupt without a try-except and the KeyboardInterrupt appeared. – Prometheus Sep 09 '18 at 01:40