kapi2289 / vulcan-api

Unofficial UONET+ e-register API
https://vulcan-api.readthedocs.io/
MIT License
72 stars 17 forks source link

How to get presence percentages #104

Closed Kwieeciol closed 2 years ago

Kwieeciol commented 2 years ago

I'm wondering how to get the actual frequency of the user per subject, I haven't found anything in the documentation. I thought that get_attendance() would give me what I want, but that's not really the case, (I'm unsure what it does if I'm honest with you, I'm guessing it returns the attendance in the given day?)

If anyone could point me in the right direction or implement this feature it'd be amazing.

Pozdrawiam :)

kuba2k2 commented 2 years ago

You can calculate the percentage yourself, as the API does not directly return that info. get_attendance() can read all attendance entries, if you set the semester start date as date_from and semester end date as date_to. Note the last sync parameter, which also needs to point to the semester start. Then, having all entries, you can calculate the percentage of any type you want. Keep in mind that Vulcan ignores "spóźnienie", it's not counted neither as presence nor absence; it's not even in the total count.

Kwieeciol commented 2 years ago

Alright, that works, don't know why I haven't thought of that. Thanks a lot for the help.

Kwieeciol commented 2 years ago

I actually created a little function, but it however calculates wrong the percentages, I think it's something wrong with the values returned from the get_attendance function:

from collections import defaultdict

async def get_frequency():
    client = Vulcan(...)
    await client.select_student()

    period = client.student.current_period
    start = period.start.date_time
    end = period.end.date_time

    attendance = defaultdict(list)

    data = await client.data.get_attendance(last_sync=start, date_from=start.date(), date_to=end.date())
    async for att in data:
        if att.subject is None or att.presence_type is None:
            continue

        attendance[att.subject.name].append(att.presence_type.presence)

    percentage = {
        subject: (sum(att) / len(att) * 100
        for subject, att in attendance.items()
    }

    print(percentage)

An example output of percentage:

{
    "Chemia": 72.727272,
    "Matematyka": 63.016986
}

The values are off by a couple percent, up and down, the real values should be:

I'm suspecting it might be something with the values not being updated when an attendance is changed.

kuba2k2 commented 2 years ago

Again, if you have spóźnienias, you have to ignore them completely (do not append to the per-subject list). Also, I'm not sure if zwolnienias count as presence or not, and if they have "presence" set to true in the presence_type. That might be the source of your problems.

Kwieeciol commented 2 years ago

spóźnienie in my school counts as a presence, I've filtered it out using the Attendance.presence_type.name attribute, this however changes nothing (if I change so it doesn't count as a presence the values are still off), the issue might be that sometimes Attendance.subject and Attendance.presence_type are None, I'm unsure why that is happening, it doesn't make much sense for an attendance to be empty, it always corresponds to a subject and it should always have a value (present, not present). Do you know why it's sometimes returning None in those two attributes?

Kwieeciol commented 2 years ago

After a bit of investigating it seems that Attendance.subject returns None when a lesson is substituted by another teacher, however I have no idea why Attendance.presence_type returns None, it's a really rare case, out of 500 lessons only 1 returns None

kuba2k2 commented 2 years ago

Subject can be None, I think, for example for school trips or other events. I'm afraid my troubleshooting skills end here. For you, though, it'll be easiest to take one subject with inaccuracies, calculate the count of each type's entries from the API, and carefully compare it with the website. Then you'll probably see which type is altering the value.