ladok3 4.19__tar.gz → 5.0__tar.gz
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.
- {ladok3-4.19 → ladok3-5.0}/PKG-INFO +1 -1
- {ladok3-4.19 → ladok3-5.0}/doc/ladok3.tex +62 -25
- {ladok3-4.19 → ladok3-5.0}/pyproject.toml +1 -1
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/data.nw +26 -8
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/report.nw +17 -2
- {ladok3-4.19 → ladok3-5.0}/LICENSE +0 -0
- {ladok3-4.19 → ladok3-5.0}/README.md +0 -0
- {ladok3-4.19 → ladok3-5.0}/doc/Makefile +0 -0
- {ladok3-4.19 → ladok3-5.0}/doc/abstract.tex +0 -0
- {ladok3-4.19 → ladok3-5.0}/doc/preamble.tex +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/doc.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/exam.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/haskell.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/miun.course.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/miun.depend.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/miun.docs.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/miun.port.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/miun.pub.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/noweb.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/pkg.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/portability.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/pub.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/results.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/subdir.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/tex.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/makefiles/transform.mk +0 -0
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/.gitignore +0 -0
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/Makefile +0 -0
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/api.nw +0 -0
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/cli.nw +0 -0
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/ladok3.nw +0 -0
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/student.nw +0 -0
- {ladok3-4.19 → ladok3-5.0}/src/ladok3/undoc.nw +0 -0
|
@@ -46,10 +46,10 @@ higher education in Sweden.
|
|
|
46
46
|
This is the documented source code of \texttt{ladok3}, a LADOK3 API wrapper for
|
|
47
47
|
Python.
|
|
48
48
|
|
|
49
|
-
The \texttt{ladok3} library provides a non-GUI application
|
|
50
|
-
access via a web browser, only provides the
|
|
51
|
-
and functionality that they would actually
|
|
52
|
-
permissions in LADOK.
|
|
49
|
+
The \texttt{ladok3} library provides a non-GUI application (a command-line
|
|
50
|
+
interface, CLI) that, similar to access via a web browser, only provides the
|
|
51
|
+
user with access to the LADOK data and functionality that they would actually
|
|
52
|
+
have based on their specific user permissions in LADOK.
|
|
53
53
|
It can be seem as a very streamlined web browser just for LADOK's web
|
|
54
54
|
interface.
|
|
55
55
|
While the library exploits caching to reduce the load on the LADOK server, this
|
|
@@ -61,12 +61,23 @@ You can install the \texttt{ladok3} package by running
|
|
|
61
61
|
pip3 install ladok3
|
|
62
62
|
\end{minted}
|
|
63
63
|
in the terminal.
|
|
64
|
-
|
|
64
|
+
|
|
65
|
+
Then you can use the CLI by running \mintinline{bash}{ladok} in the terminal.
|
|
66
|
+
The command has built-in help, simply run \mintinline{bash}{ladok -h} to see
|
|
67
|
+
the available commands.
|
|
68
|
+
However, the first thing you want to run after installing the package is
|
|
65
69
|
\begin{minted}[firstnumber=last]{bash}
|
|
66
|
-
|
|
70
|
+
ladok login
|
|
71
|
+
\end{minted}
|
|
72
|
+
This will set up your credentials for the CLI.
|
|
73
|
+
However, if you want to use the library in a script, you can read
|
|
74
|
+
\begin{minted}[firstnumber=last]{bash}
|
|
75
|
+
ladok login -h
|
|
67
76
|
\end{minted}
|
|
77
|
+
for alternative ways of providing your credentials.
|
|
68
78
|
|
|
69
|
-
|
|
79
|
+
For use in Python scripts,
|
|
80
|
+
we provide the main class \texttt{LadokSession} (\cref{LadokSession}).
|
|
70
81
|
The \texttt{LadokSession} class acts like \enquote{factories} and will return
|
|
71
82
|
objects representing various LADOK data.
|
|
72
83
|
These data objects' classes inherit the \texttt{LadokData} (\cref{LadokData})
|
|
@@ -83,17 +94,10 @@ We do this by caching all factory methods of any \texttt{LadokSession}.
|
|
|
83
94
|
The \texttt{LadokSession} itself is also designed to be cacheable: if the session to
|
|
84
95
|
LADOK expires, it will automatically reauthenticate to establish a new session.
|
|
85
96
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
\input{../src/ladok3/ladok3.tex}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
\part{API calls}
|
|
94
|
-
|
|
95
|
-
\input{../src/ladok3/api.tex}
|
|
96
|
-
\input{../src/ladok3/undoc.tex}
|
|
97
|
+
You can find a quick reference by running
|
|
98
|
+
\begin{minted}[firstnumber=last]{bash}
|
|
99
|
+
pydoc ladok3
|
|
100
|
+
\end{minted}
|
|
97
101
|
|
|
98
102
|
|
|
99
103
|
|
|
@@ -103,7 +107,7 @@ LADOK expires, it will automatically reauthenticate to establish a new session.
|
|
|
103
107
|
|
|
104
108
|
\input{../src/ladok3/cli.tex}
|
|
105
109
|
|
|
106
|
-
\chapter{The \texttt{
|
|
110
|
+
\chapter{The \texttt{course} command}
|
|
107
111
|
|
|
108
112
|
\input{../src/ladok3/data.tex}
|
|
109
113
|
|
|
@@ -119,19 +123,52 @@ LADOK expires, it will automatically reauthenticate to establish a new session.
|
|
|
119
123
|
|
|
120
124
|
\part{Other example applications}
|
|
121
125
|
|
|
122
|
-
\chapter{Transfer results from
|
|
126
|
+
\chapter{Transfer results from Canvas to LADOK}
|
|
123
127
|
|
|
124
128
|
Here we provide an example program~\texttt{canvas2ladok.py} which exports
|
|
125
|
-
results from
|
|
129
|
+
results from Canvas to LADOK for the introductory programming course~prgi
|
|
126
130
|
(DD1315).
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
|
|
132
|
+
However, a better way to do this is by using the CLI:
|
|
133
|
+
\begin{minted}{bash}
|
|
134
|
+
#!/bin/bash
|
|
135
|
+
|
|
136
|
+
. ${HOME}/.profile
|
|
137
|
+
|
|
138
|
+
year=22
|
|
139
|
+
courses="DD13(10HT${year}|17HT${year})"
|
|
140
|
+
components="(LAB[123]|MAT1|KAL1)"
|
|
141
|
+
|
|
142
|
+
canvaslms results -c "$courses" -A "$components" \
|
|
143
|
+
| sed -E "s/ ?[HV]T[0-9]{2}( \(.*\))?//" \
|
|
144
|
+
| ladok report -fv
|
|
145
|
+
\end{minted}
|
|
146
|
+
The advantage to using this command is that it will automatically report the
|
|
147
|
+
correct dates and everyone who has participated in the grading of each
|
|
148
|
+
student---as required by regulation.
|
|
149
|
+
The official tools, like KTH Transfer to Ladok or SUNET's version of the same,
|
|
150
|
+
don't do this---they don't set the dates correctly of each individual, but one
|
|
151
|
+
for all, and they don't register the graders in LADOK.
|
|
152
|
+
|
|
153
|
+
But now we'll have a look at how we can do this (well, a simpler version) in
|
|
154
|
+
Python.
|
|
155
|
+
|
|
131
156
|
|
|
132
157
|
\input{../examples/canvas2ladok.tex}
|
|
133
158
|
|
|
134
159
|
|
|
160
|
+
\part{The library}
|
|
161
|
+
|
|
162
|
+
\input{../src/ladok3/ladok3.tex}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
\part{API calls}
|
|
166
|
+
|
|
167
|
+
\input{../src/ladok3/api.tex}
|
|
168
|
+
\input{../src/ladok3/undoc.tex}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
135
172
|
\backmatter
|
|
136
173
|
\printbibliography
|
|
137
174
|
|
|
@@ -16,7 +16,7 @@ from LADOK (\cref{DataCommand}).
|
|
|
16
16
|
This is a subcommand for the [[ladok]] command-line interface.
|
|
17
17
|
It can be used like this:
|
|
18
18
|
\begin{minted}{bash}
|
|
19
|
-
ladok
|
|
19
|
+
ladok course DD1315 > DD1315.csv
|
|
20
20
|
\end{minted}
|
|
21
21
|
This program will produce CSV-formated data to answer the questions above.
|
|
22
22
|
The data is formated like this:
|
|
@@ -26,11 +26,11 @@ The data is formated like this:
|
|
|
26
26
|
\item component,
|
|
27
27
|
\item student (pseudonym),
|
|
28
28
|
\item grade,
|
|
29
|
-
\item normalized
|
|
29
|
+
\item either absolute date or normalized to the course start and finish.
|
|
30
30
|
\end{itemize}
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
\section{The [[
|
|
33
|
+
\section{The [[course]] subcommand}\label{DataCommand}
|
|
34
34
|
|
|
35
35
|
This is a subcommand run as part of the [[ladok3.cli]] module.
|
|
36
36
|
We provide a function [[add_command_options]] that adds the subcommand options
|
|
@@ -59,7 +59,7 @@ def command(ladok, args):
|
|
|
59
59
|
We add a subparser.
|
|
60
60
|
We set it up to use the function [[command]].
|
|
61
61
|
<<add data parser to parser>>=
|
|
62
|
-
data_parser = parser.add_parser("
|
|
62
|
+
data_parser = parser.add_parser("course",
|
|
63
63
|
help="Returns course results data in CSV form",
|
|
64
64
|
description="""
|
|
65
65
|
Returns the results in CSV form for all first-time registered students.
|
|
@@ -79,9 +79,10 @@ course_rounds = filter_rounds(
|
|
|
79
79
|
ladok.search_course_rounds(code=args.course_code),
|
|
80
80
|
args.rounds)
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
if args.header:
|
|
83
|
+
data_writer.writerow([
|
|
84
|
+
"Course", "Round", "Component", "Student", "Grade", "Time"
|
|
85
|
+
])
|
|
85
86
|
for course_round in course_rounds:
|
|
86
87
|
data = extract_data_for_round(ladok, course_round, args)
|
|
87
88
|
|
|
@@ -91,6 +92,7 @@ for course_round in course_rounds:
|
|
|
91
92
|
student, grade, time]
|
|
92
93
|
)
|
|
93
94
|
@ We must take a course code and a delimiter as arguments.
|
|
95
|
+
We also want to know if we want a header or not.
|
|
94
96
|
<<add data command arguments to data parser>>=
|
|
95
97
|
data_parser.add_argument("course_code",
|
|
96
98
|
help="The course code of the course for which to export data")
|
|
@@ -100,6 +102,9 @@ data_parser.add_argument("-d", "--delimiter",
|
|
|
100
102
|
help="The delimiter for the CSV output; "
|
|
101
103
|
"default is a tab character to be compatible with POSIX commands, "
|
|
102
104
|
"use `-d,` or `-d ,` to get comma-separated values.")
|
|
105
|
+
|
|
106
|
+
data_parser.add_argument("-H", "--header", action="store_true",
|
|
107
|
+
help="Print a header line with the column names.")
|
|
103
108
|
@
|
|
104
109
|
|
|
105
110
|
We filter the rounds.
|
|
@@ -154,7 +159,20 @@ def extract_data_for_round(ladok, course_round, args):
|
|
|
154
159
|
else:
|
|
155
160
|
<<extract grade and normalized date from result data>>
|
|
156
161
|
|
|
157
|
-
yield student, component, grade
|
|
162
|
+
<<yield [[student, component, grade]] and date>>
|
|
163
|
+
@
|
|
164
|
+
|
|
165
|
+
We want to yield the data in CSV form, so we simply yield a tuple.
|
|
166
|
+
The date is either the normalized date or the date from the result data.
|
|
167
|
+
<<yield [[student, component, grade]] and date>>=
|
|
168
|
+
if args.normalize_date:
|
|
169
|
+
yield student, component, grade, normalized_date
|
|
170
|
+
elif result_data:
|
|
171
|
+
yield student, component, grade, result_data["Examinationsdatum"]
|
|
172
|
+
<<add data command arguments to data parser>>=
|
|
173
|
+
data_parser.add_argument("-n", "--normalize-date", action="store_true",
|
|
174
|
+
help="Normalize the date to the start of the course, "
|
|
175
|
+
"otherwise the date is printed as is.")
|
|
158
176
|
@
|
|
159
177
|
|
|
160
178
|
\subsection{Get round data}
|
|
@@ -115,11 +115,24 @@ try:
|
|
|
115
115
|
set_grade(ladok, args,
|
|
116
116
|
student_id, course_code, component_code, grade, date, graders)
|
|
117
117
|
except Exception as err:
|
|
118
|
-
|
|
118
|
+
<<try to resolve [[student]] from [[ladok]] using [[student_id]]>>
|
|
119
|
+
print(f"{course_code} {component_code}={grade} ({date}) {student}: "
|
|
119
120
|
f"{err}",
|
|
120
121
|
file=sys.stderr)
|
|
121
122
|
@
|
|
122
123
|
|
|
124
|
+
The reason we want to resolve the student from LADOK is that the [[student_id]]
|
|
125
|
+
might be a personnummer or a LADOK ID---if the latter, it's not particularly
|
|
126
|
+
readable for a human and we can't use the LADOK ID in the LADOK web interface
|
|
127
|
+
when we want to deal with the errors manually.
|
|
128
|
+
But if we resolve the student, then we get a readable name.
|
|
129
|
+
<<try to resolve [[student]] from [[ladok]] using [[student_id]]>>=
|
|
130
|
+
try:
|
|
131
|
+
student = ladok.get_student(student_id)
|
|
132
|
+
except Exception:
|
|
133
|
+
student = student_id
|
|
134
|
+
@
|
|
135
|
+
|
|
123
136
|
When we set the grade, there are a few cases that should be handled.
|
|
124
137
|
If the grade isn't attested, we try to change it.
|
|
125
138
|
(This might still fail if the grade is finalized but not attested.)
|
|
@@ -254,8 +267,10 @@ try:
|
|
|
254
267
|
args.student_id, args.course_code, args.component_code,
|
|
255
268
|
args.grade, args.date, args.graders)
|
|
256
269
|
except Exception as err:
|
|
270
|
+
student_id = args.student_id
|
|
271
|
+
<<try to resolve [[student]] from [[ladok]] using [[student_id]]>>
|
|
257
272
|
print(f"{args.course_code} {args.component_code}={args.grade} ({args.date}) "
|
|
258
|
-
f"{
|
|
273
|
+
f"{student}: {err}",
|
|
259
274
|
file=sys.stderr)
|
|
260
275
|
@
|
|
261
276
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|