Почему этот код Python не перехватывает KeyboardInterrupts? - PullRequest
0 голосов
/ 09 сентября 2018

Для начала я посмотрел на все другие решения. Я убедился, что моя IDE / Editor (Atom) не перехватывает вводимые данные. Я посмотрел, чтобы проверить, не блокирует ли какой-либо из моих кодов Ctrl-C. Я использую time.sleep, сигнал, темы, вы называете это. Я не могу понять, почему отправка Ctrl-C не останавливает мою программу на Python (но убивает его через Activity Monitor). Вот код

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 - это просто фрагмент кода, который я использую для взаимодействия с файлом JSON, и get_data.py выглядит следующим образом

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

Я не понимаю, почему что-то в get_data или main мешало бы ловить SIGINT, но я не эксперт. Почему я не могу выйти из своего кода?

РЕДАКТИРОВАТЬ: Если это помогает, я могу выйти до печати main (), но после не могу выйти.

1 Ответ

0 голосов
/ 09 сентября 2018

Я пробовал тестировать с KeyboardInterrput в IDLE, он отлично поднял KeyboardInterrupt. Если это действительно не работает для вас, я предлагаю вам использовать другие способы управления горячими клавишами.

Редактировать: KeyboardInterrpu появляется, когда появляется, но не может быть обнаружено оператором исключений. Наиболее вероятная причина может заключаться в том, что KeyboardInterrupt не наследуется от BaseException, который имеет кодировку, позволяющую перехватывать ошибки. Надеюсь это поможет!

...