ladok3 4.16__py3-none-any.whl → 4.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ladok3 might be problematic. Click here for more details.
- doc/ltxobj/ladok3.pdf +0 -0
- ladok3/__init__.py +619 -3130
- ladok3/api.nw +1001 -10
- ladok3/ladok3.nw +70 -4
- ladok3/report.nw +1 -1
- ladok3/report.py +1 -1
- ladok3/student.nw +20 -1
- ladok3/student.py +62 -41
- ladok3/undoc.nw +54 -3111
- {ladok3-4.16.dist-info → ladok3-4.18.dist-info}/LICENSE +1 -1
- {ladok3-4.16.dist-info → ladok3-4.18.dist-info}/METADATA +29 -2
- ladok3-4.18.dist-info/RECORD +21 -0
- ladok3-4.16.dist-info/RECORD +0 -21
- {ladok3-4.16.dist-info → ladok3-4.18.dist-info}/WHEEL +0 -0
- {ladok3-4.16.dist-info → ladok3-4.18.dist-info}/entry_points.txt +0 -0
ladok3/ladok3.nw
CHANGED
|
@@ -57,6 +57,17 @@ ladok = ladok3.LadokSession("KTH Royal Institute of Technology",
|
|
|
57
57
|
test_environment=True) # for experiments
|
|
58
58
|
\end{minted}
|
|
59
59
|
|
|
60
|
+
Yet another way is to use the [[ladok]] command's own credential store.
|
|
61
|
+
\begin{minted}[linenos]{python}
|
|
62
|
+
import ladok3
|
|
63
|
+
import ladok3.cli
|
|
64
|
+
|
|
65
|
+
ladok = ladok3.LadokSession(*ladok3.cli.load_credentials(),
|
|
66
|
+
test_environment=True) # for experiments
|
|
67
|
+
\end{minted}
|
|
68
|
+
Just note that unpacking [[*]] to unpack the tuple that [[load_credentials]]
|
|
69
|
+
returns.
|
|
70
|
+
|
|
60
71
|
This chapter covers how the [[LadokSession]] class work.
|
|
61
72
|
The remaining chapters cover what the [[ladok]] object can be used for.
|
|
62
73
|
\Cref{StudentClasses} covers how we can work with student data.
|
|
@@ -923,9 +934,62 @@ for course in self.ladok.registrations_JSON(self.ladok_id):
|
|
|
923
934
|
|
|
924
935
|
We also want to know if a student is suspended or not.
|
|
925
936
|
We can get a list of suspensions for a student.
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
937
|
+
This list looks like this:
|
|
938
|
+
\begin{minted}{json}
|
|
939
|
+
[
|
|
940
|
+
{"Anteckning": "VJ-2024-...",
|
|
941
|
+
"Giltighetsperiod": {"Slutdatum": "2024-12-03",
|
|
942
|
+
"Startdatum": "2024-09-25", "link": []},
|
|
943
|
+
"LarosateID": 29,
|
|
944
|
+
"OrsakID": 101450,
|
|
945
|
+
"SenastAndradAv": "someone@kth.se",
|
|
946
|
+
"SenastSparad": "2024-09-24T16:45:56.941",
|
|
947
|
+
"StudentUID": "...",
|
|
948
|
+
"Uid": "...",
|
|
949
|
+
"link": [{"method": "GET",
|
|
950
|
+
"uri": "https://api.ladok.se:443/studentinformation/internal/avstangning/...",
|
|
951
|
+
"mediaType": "application/vnd.ladok+xml",
|
|
952
|
+
"rel": "self"}]
|
|
953
|
+
}
|
|
954
|
+
]
|
|
955
|
+
\end{minted}
|
|
956
|
+
Let's make a class for this.
|
|
957
|
+
<<classes>>=
|
|
958
|
+
class Suspension(LadokData):
|
|
959
|
+
"""A suspension"""
|
|
960
|
+
def __init__(self, /, **kwargs):
|
|
961
|
+
super().__init__(**kwargs)
|
|
962
|
+
self.__note = kwargs.pop("Anteckning")
|
|
963
|
+
self.__validity = (
|
|
964
|
+
datetime.date.fromisoformat(kwargs["Giltighetsperiod"]["Startdatum"]),
|
|
965
|
+
datetime.date.fromisoformat(kwargs["Giltighetsperiod"]["Slutdatum"])
|
|
966
|
+
)
|
|
967
|
+
|
|
968
|
+
@property
|
|
969
|
+
def note(self):
|
|
970
|
+
"""
|
|
971
|
+
The note of the suspension. This is usually a case number.
|
|
972
|
+
"""
|
|
973
|
+
return self.__note
|
|
974
|
+
|
|
975
|
+
@property
|
|
976
|
+
def validity(self):
|
|
977
|
+
"""
|
|
978
|
+
A tuple (start, end) of the validity period of the suspension.
|
|
979
|
+
"""
|
|
980
|
+
return self.__validity
|
|
981
|
+
|
|
982
|
+
@property
|
|
983
|
+
def is_current(self):
|
|
984
|
+
"""
|
|
985
|
+
Is True if the suspension is currently valid.
|
|
986
|
+
"""
|
|
987
|
+
return self.validity[0] <= datetime.date.today() <= self.validity[1]
|
|
988
|
+
|
|
989
|
+
def __str__(self):
|
|
990
|
+
return f"{self.validity[0]}--{self.validity[1]}"
|
|
991
|
+
@
|
|
992
|
+
|
|
929
993
|
We never cache this result since we always want the most up-to-date version.
|
|
930
994
|
<<student attribute methods>>=
|
|
931
995
|
@property
|
|
@@ -933,7 +997,9 @@ def suspensions(self):
|
|
|
933
997
|
"""
|
|
934
998
|
The list of the students' suspensions.
|
|
935
999
|
"""
|
|
936
|
-
|
|
1000
|
+
suspensions = self.ladok.get_student_suspensions_JSON(
|
|
1001
|
+
self.ladok_id)["Avstangning"]
|
|
1002
|
+
return [Suspension(**suspension) for suspension in suspensions]
|
|
937
1003
|
@
|
|
938
1004
|
|
|
939
1005
|
|
ladok3/report.nw
CHANGED
|
@@ -163,7 +163,7 @@ error message.
|
|
|
163
163
|
try:
|
|
164
164
|
course = student.courses(code=args.course_code)[0]
|
|
165
165
|
except IndexError:
|
|
166
|
-
raise Exception("
|
|
166
|
+
raise Exception(f"{args.course_code}: No such course for {student}")
|
|
167
167
|
<<look up [[result]] from [[course]]>>=
|
|
168
168
|
try:
|
|
169
169
|
result = course.results(component=args.component_code)[0]
|
ladok3/report.py
CHANGED
|
@@ -19,7 +19,7 @@ def report_one_result(ladok, args):
|
|
|
19
19
|
try:
|
|
20
20
|
course = student.courses(code=args.course_code)[0]
|
|
21
21
|
except IndexError:
|
|
22
|
-
raise Exception("
|
|
22
|
+
raise Exception(f"{args.course_code}: No such course for {student}")
|
|
23
23
|
try:
|
|
24
24
|
result = course.results(component=args.component_code)[0]
|
|
25
25
|
except IndexError:
|
ladok3/student.nw
CHANGED
|
@@ -106,9 +106,28 @@ def print_student_data(student):
|
|
|
106
106
|
print(f"Personnummer: {student.personnummer}")
|
|
107
107
|
print(f"LADOK ID: {student.ladok_id}")
|
|
108
108
|
print(f"Alive: {student.alive}")
|
|
109
|
-
print
|
|
109
|
+
<<print info about suspensions for [[student]]>>
|
|
110
110
|
@
|
|
111
111
|
|
|
112
|
+
We want to print whether the student is currently suspended or not.
|
|
113
|
+
We want to make this really clear.
|
|
114
|
+
<<print info about suspensions for [[student]]>>=
|
|
115
|
+
print(f"Suspended: ", end="")
|
|
116
|
+
if any(map(lambda x: x.is_current, student.suspensions)):
|
|
117
|
+
print("YES")
|
|
118
|
+
else:
|
|
119
|
+
print("no")
|
|
120
|
+
@ Then we also want to print all the times the student has been suspended.
|
|
121
|
+
We only want to print this if the student has been suspended at least once.
|
|
122
|
+
<<print info about suspensions for [[student]]>>=
|
|
123
|
+
if student.suspensions:
|
|
124
|
+
print(f"Suspenions: ", end="")
|
|
125
|
+
for suspension in student.suspensions:
|
|
126
|
+
print(f"{suspension}", end="\n ")
|
|
127
|
+
print()
|
|
128
|
+
@
|
|
129
|
+
|
|
130
|
+
|
|
112
131
|
\subsection{Printing student's course data}
|
|
113
132
|
|
|
114
133
|
To print the student's course data, we simply filter the courses on the option
|
ladok3/student.py
CHANGED
|
@@ -1,54 +1,75 @@
|
|
|
1
1
|
import csv
|
|
2
2
|
import ladok3.cli
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
def print_student_data(student):
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
"""Prints the student data, all attributes, to stdout."""
|
|
7
|
+
print(f"First name: {student.first_name}")
|
|
8
|
+
print(f"Last name: {student.last_name}")
|
|
9
|
+
print(f"Personnummer: {student.personnummer}")
|
|
10
|
+
print(f"LADOK ID: {student.ladok_id}")
|
|
11
|
+
print(f"Alive: {student.alive}")
|
|
12
|
+
print(f"Suspended: ", end="")
|
|
13
|
+
if any(map(lambda x: x.is_current, student.suspensions)):
|
|
14
|
+
print("YES")
|
|
15
|
+
else:
|
|
16
|
+
print("no")
|
|
17
|
+
if student.suspensions:
|
|
18
|
+
print(f"Suspenions: ", end="")
|
|
19
|
+
for suspension in student.suspensions:
|
|
20
|
+
print(f"{suspension}", end="\n ")
|
|
21
|
+
print()
|
|
22
|
+
|
|
23
|
+
|
|
12
24
|
def print_course_data(student, args):
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
"""Prints the courses"""
|
|
26
|
+
print("Courses:")
|
|
27
|
+
for course in student.courses(code=args.course):
|
|
28
|
+
print(f"{course}")
|
|
29
|
+
if args.results:
|
|
30
|
+
for result in course.results():
|
|
31
|
+
print(f" {result}")
|
|
32
|
+
|
|
20
33
|
|
|
21
34
|
def add_command_options(parser):
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
student_parser = parser.add_parser(
|
|
36
|
+
"student",
|
|
37
|
+
help="Shows a student's information in LADOK",
|
|
38
|
+
description="""
|
|
25
39
|
Show a student's information in LADOK.
|
|
26
40
|
Shows information like name, personnummer, contact information.
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
""",
|
|
42
|
+
)
|
|
43
|
+
student_parser.set_defaults(func=command)
|
|
44
|
+
student_parser.add_argument(
|
|
45
|
+
"id", help="The student's ID, either personnummer or LADOK ID"
|
|
46
|
+
)
|
|
47
|
+
student_parser.add_argument(
|
|
48
|
+
"-c",
|
|
49
|
+
"--course",
|
|
50
|
+
nargs="?",
|
|
51
|
+
const=".*",
|
|
52
|
+
help="A regular expression for which course codes to list, "
|
|
53
|
+
"use no value for listing all courses.",
|
|
54
|
+
)
|
|
55
|
+
student_parser.add_argument(
|
|
56
|
+
"-r",
|
|
57
|
+
"--results",
|
|
58
|
+
action="store_true",
|
|
59
|
+
default=False,
|
|
60
|
+
help="Set to include results for each course listed.",
|
|
61
|
+
)
|
|
62
|
+
|
|
42
63
|
|
|
43
64
|
def command(ladok, args):
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
65
|
+
try:
|
|
66
|
+
student = ladok.get_student(args.id)
|
|
67
|
+
student.alive
|
|
68
|
+
except Exception as err:
|
|
69
|
+
ladok3.cli.err(-1, f"can't fetch student data for {args.id}: {err}")
|
|
49
70
|
|
|
50
|
-
|
|
71
|
+
print_student_data(student)
|
|
51
72
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
73
|
+
if args.course:
|
|
74
|
+
print()
|
|
75
|
+
print_course_data(student, args)
|