ladok3 4.7__tar.gz → 4.10__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.7 → ladok3-4.10}/PKG-INFO +23 -5
- {ladok3-4.7 → ladok3-4.10}/README.md +21 -3
- {ladok3-4.7 → ladok3-4.10}/makefiles/noweb.mk +14 -12
- {ladok3-4.7 → ladok3-4.10}/pyproject.toml +2 -2
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/cli.nw +5 -1
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/ladok3.nw +118 -59
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/report.nw +1 -1
- {ladok3-4.7 → ladok3-4.10}/LICENSE +0 -0
- {ladok3-4.7 → ladok3-4.10}/doc/Makefile +0 -0
- {ladok3-4.7 → ladok3-4.10}/doc/abstract.tex +0 -0
- {ladok3-4.7 → ladok3-4.10}/doc/ladok3.tex +0 -0
- {ladok3-4.7 → ladok3-4.10}/doc/preamble.tex +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/doc.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/exam.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/haskell.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/miun.course.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/miun.depend.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/miun.docs.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/miun.port.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/miun.pub.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/pkg.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/portability.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/pub.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/results.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/subdir.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/tex.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/makefiles/transform.mk +0 -0
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/.gitignore +0 -0
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/Makefile +0 -0
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/api.nw +0 -0
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/data.nw +0 -0
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/student.nw +0 -0
- {ladok3-4.7 → ladok3-4.10}/src/ladok3/undoc.nw +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ladok3
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.10
|
|
4
4
|
Summary: Python wrapper and CLI for the LADOK3 REST API.
|
|
5
5
|
Home-page: https://github.com/dbosk/ladok3
|
|
6
6
|
License: MIT
|
|
@@ -24,7 +24,7 @@ Classifier: Topic :: Utilities
|
|
|
24
24
|
Requires-Dist: appdirs (>=1.4.4,<2.0.0)
|
|
25
25
|
Requires-Dist: argcomplete (>=2.0.0,<3.0.0)
|
|
26
26
|
Requires-Dist: cachetools (>=5.2.0,<6.0.0)
|
|
27
|
-
Requires-Dist: cryptography (>=
|
|
27
|
+
Requires-Dist: cryptography (>=41.0.3,<42.0.0)
|
|
28
28
|
Requires-Dist: keyring (>=24.2.0,<25.0.0)
|
|
29
29
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
30
30
|
Requires-Dist: urllib3 (>=1.26.9,<2.0.0)
|
|
@@ -69,9 +69,17 @@ command-line tool `ladok`.
|
|
|
69
69
|
Let's assume that we have a student with personnummer 123456-1234.
|
|
70
70
|
Let's also assume that this student has taken a course with course code AB1234
|
|
71
71
|
and finished the module LAB1 on date 2021-03-15.
|
|
72
|
+
Say also that the student's assignments were graded by the teacher and two TAs:
|
|
73
|
+
|
|
74
|
+
- Daniel Bosk <dbosk@kth.se> (teacher)
|
|
75
|
+
- Teaching Assistantsdotter <tad@kth.se>
|
|
76
|
+
- Teaching Assistantsson <tas@kth.se>
|
|
77
|
+
|
|
72
78
|
Then we can report this result like this:
|
|
73
79
|
```bash
|
|
74
|
-
ladok report 123456-1234 AB1234 LAB1 -d 2021-03-15 -f
|
|
80
|
+
ladok report 123456-1234 AB1234 LAB1 -d 2021-03-15 -f \
|
|
81
|
+
"Daniel Bosk <dbosk@kth.se>" "Teaching Assistantsdotter <tad@kth.se>" \
|
|
82
|
+
"Teaching Assistantsson <tas@kth.se>"
|
|
75
83
|
```
|
|
76
84
|
|
|
77
85
|
If we use Canvas for all results, we can even report all results for a
|
|
@@ -84,13 +92,24 @@ canvaslms results -c AB1234 -A LAB1 | ladok report -v
|
|
|
84
92
|
The `canvaslms results` command will export the results in CSV format, this
|
|
85
93
|
will be piped to `ladok report` that can read it and report it in bulk.
|
|
86
94
|
|
|
95
|
+
Most likely you'll need to pass the CSV through `sed` to change the column
|
|
96
|
+
containing the course identifier to just contain the course code. At KTH, the
|
|
97
|
+
course code attribute in Canvas contains course code and the semester. So I
|
|
98
|
+
have to `sed` away the semester part.
|
|
99
|
+
|
|
87
100
|
### As a Python package
|
|
88
101
|
|
|
89
102
|
To use the package, it's just to import the package as usual.
|
|
90
103
|
```python
|
|
91
104
|
import ladok3
|
|
92
105
|
|
|
93
|
-
|
|
106
|
+
credentials = {
|
|
107
|
+
"username": "dbosk@ug.kth.se",
|
|
108
|
+
"password": "password ..."
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
ls = ladok3.LadokSession("KTH Royal Institute of Technology",
|
|
112
|
+
vars=credentials)
|
|
94
113
|
|
|
95
114
|
student = ls.get_student("123456-1234")
|
|
96
115
|
|
|
@@ -208,7 +227,6 @@ Purpose: Use the data in a Canvas course room together with the data from Ladok3
|
|
|
208
227
|
|
|
209
228
|
Input:
|
|
210
229
|
```
|
|
211
|
-
Input
|
|
212
230
|
cl_user_info.py Canvas_user_id|KTHID|Ladok_id [course_id]
|
|
213
231
|
```
|
|
214
232
|
The course_id can be a Canvas course_id **or** if you have dashboard cards, you can specific a course code, a nickname, unique part of the short name or original course name.
|
|
@@ -33,9 +33,17 @@ command-line tool `ladok`.
|
|
|
33
33
|
Let's assume that we have a student with personnummer 123456-1234.
|
|
34
34
|
Let's also assume that this student has taken a course with course code AB1234
|
|
35
35
|
and finished the module LAB1 on date 2021-03-15.
|
|
36
|
+
Say also that the student's assignments were graded by the teacher and two TAs:
|
|
37
|
+
|
|
38
|
+
- Daniel Bosk <dbosk@kth.se> (teacher)
|
|
39
|
+
- Teaching Assistantsdotter <tad@kth.se>
|
|
40
|
+
- Teaching Assistantsson <tas@kth.se>
|
|
41
|
+
|
|
36
42
|
Then we can report this result like this:
|
|
37
43
|
```bash
|
|
38
|
-
ladok report 123456-1234 AB1234 LAB1 -d 2021-03-15 -f
|
|
44
|
+
ladok report 123456-1234 AB1234 LAB1 -d 2021-03-15 -f \
|
|
45
|
+
"Daniel Bosk <dbosk@kth.se>" "Teaching Assistantsdotter <tad@kth.se>" \
|
|
46
|
+
"Teaching Assistantsson <tas@kth.se>"
|
|
39
47
|
```
|
|
40
48
|
|
|
41
49
|
If we use Canvas for all results, we can even report all results for a
|
|
@@ -48,13 +56,24 @@ canvaslms results -c AB1234 -A LAB1 | ladok report -v
|
|
|
48
56
|
The `canvaslms results` command will export the results in CSV format, this
|
|
49
57
|
will be piped to `ladok report` that can read it and report it in bulk.
|
|
50
58
|
|
|
59
|
+
Most likely you'll need to pass the CSV through `sed` to change the column
|
|
60
|
+
containing the course identifier to just contain the course code. At KTH, the
|
|
61
|
+
course code attribute in Canvas contains course code and the semester. So I
|
|
62
|
+
have to `sed` away the semester part.
|
|
63
|
+
|
|
51
64
|
### As a Python package
|
|
52
65
|
|
|
53
66
|
To use the package, it's just to import the package as usual.
|
|
54
67
|
```python
|
|
55
68
|
import ladok3
|
|
56
69
|
|
|
57
|
-
|
|
70
|
+
credentials = {
|
|
71
|
+
"username": "dbosk@ug.kth.se",
|
|
72
|
+
"password": "password ..."
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
ls = ladok3.LadokSession("KTH Royal Institute of Technology",
|
|
76
|
+
vars=credentials)
|
|
58
77
|
|
|
59
78
|
student = ls.get_student("123456-1234")
|
|
60
79
|
|
|
@@ -172,7 +191,6 @@ Purpose: Use the data in a Canvas course room together with the data from Ladok3
|
|
|
172
191
|
|
|
173
192
|
Input:
|
|
174
193
|
```
|
|
175
|
-
Input
|
|
176
194
|
cl_user_info.py Canvas_user_id|KTHID|Ladok_id [course_id]
|
|
177
195
|
```
|
|
178
196
|
The course_id can be a Canvas course_id **or** if you have dashboard cards, you can specific a course code, a nickname, unique part of the short name or original course name.
|
|
@@ -9,51 +9,53 @@ NOWEAVE.pdf?= \
|
|
|
9
9
|
NOWEAVEFLAGS.pdf?= ${NOWEAVEFLAGS} -x -t2
|
|
10
10
|
NOTANGLEFLAGS?=
|
|
11
11
|
NOTANGLE?= notangle ${NOTANGLEFLAGS} -R$(notdir $@) $(filter %.nw,$^) | \
|
|
12
|
-
${CPIF} $@
|
|
12
|
+
${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
13
13
|
CPIF?= cpif
|
|
14
14
|
NOWEB_SUFFIXES+= .c .cc .cpp .cxx
|
|
15
15
|
NOTANGLEFLAGS.c?= -L
|
|
16
16
|
NOTANGLE.c?= notangle ${NOTANGLEFLAGS.c} -R$(notdir $@) \
|
|
17
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
17
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
18
18
|
NOTANGLEFLAGS.cc?= ${NOTANGLEFLAGS.c}
|
|
19
19
|
NOTANGLE.cc?= notangle ${NOTANGLEFLAGS.cc} -R$(notdir $@) \
|
|
20
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
20
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
21
21
|
NOTANGLEFLAGS.cpp?= ${NOTANGLEFLAGS.c}
|
|
22
22
|
NOTANGLE.cpp?= notangle ${NOTANGLEFLAGS.cpp} -R$(notdir $@) \
|
|
23
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
23
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
24
24
|
NOTANGLEFLAGS.cxx?= ${NOTANGLEFLAGS.c}
|
|
25
25
|
NOTANGLE.cxx?= notangle ${NOTANGLEFLAGS.cxx} -R$(notdir $@) \
|
|
26
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
26
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
27
27
|
NOWEB_SUFFIXES+= .h .hh .hpp .hxx
|
|
28
28
|
NOTANGLEFLAGS.h?= -L
|
|
29
29
|
NOTANGLE.h?= notangle ${NOTANGLEFLAGS.h} -R$(notdir $@) \
|
|
30
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
30
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
31
31
|
NOTANGLEFLAGS.hh?= ${NOTANGLEFLAGS.h}
|
|
32
32
|
NOTANGLE.hh?= notangle ${NOTANGLEFLAGS.hh} -R$(notdir $@) \
|
|
33
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
33
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
34
34
|
NOTANGLEFLAGS.hpp?= ${NOTANGLEFLAGS.h}
|
|
35
35
|
NOTANGLE.hpp?= notangle ${NOTANGLEFLAGS.hpp} -R$(notdir $@) \
|
|
36
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
36
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
37
37
|
NOTANGLEFLAGS.hxx?= ${NOTANGLEFLAGS.h}
|
|
38
38
|
NOTANGLE.hxx?= notangle ${NOTANGLEFLAGS.hxx} -R$(notdir $@) \
|
|
39
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
39
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
40
40
|
NOWEB_SUFFIXES+= .hs
|
|
41
41
|
NOTANGLEFLAGS.hs?= -L
|
|
42
42
|
NOTANGLE.hs?= notangle ${NOTANGLEFLAGS.hs} -R$(notdir $@) \
|
|
43
|
-
$(filter %.nw,$^) | ${CPIF} $@
|
|
43
|
+
$(filter %.nw,$^) | ${CPIF} $@ && noroots $(filter %.nw,$^)
|
|
44
44
|
NOWEB_SUFFIXES+= .mk
|
|
45
45
|
NOTANGLEFLAGS.mk?= -t2
|
|
46
46
|
NOTANGLE.mk?= notangle ${NOTANGLEFLAGS.mk} -R$(notdir $@) \
|
|
47
|
-
$(filter %.nw,$^) > $@
|
|
47
|
+
$(filter %.nw,$^) > $@ && noroots $(filter %.nw,$^)
|
|
48
48
|
NOWEB_SUFFIXES+= .py .sty .cls .sh .go
|
|
49
49
|
|
|
50
50
|
define default_tangling
|
|
51
51
|
NOTANGLEFLAGS$(1)?=
|
|
52
52
|
NOTANGLE$(1)?= notangle $${NOTANGLEFLAGS$(1)} -R$$(notdir $$@) \
|
|
53
|
-
$$(filter %.nw,$$^) > $$@
|
|
53
|
+
$$(filter %.nw,$$^) > $$@ && noroots $$(filter %.nw,$$^)
|
|
54
54
|
endef
|
|
55
55
|
|
|
56
56
|
$(foreach suffix,${NOWEB_SUFFIXES},$(eval $(call default_tangling,${suffix})))
|
|
57
|
+
NOTANGLE.py+= && ${NOWEB_PYCODEFMT}
|
|
58
|
+
NOWEB_PYCODEFMT?= black $@
|
|
57
59
|
|
|
58
60
|
INCLUDE_MAKEFILES?=.
|
|
59
61
|
MAKEFILES_DIR?=${INCLUDE_MAKEFILES}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "ladok3"
|
|
3
|
-
version = "4.
|
|
3
|
+
version = "4.10"
|
|
4
4
|
description = "Python wrapper and CLI for the LADOK3 REST API."
|
|
5
5
|
authors = [
|
|
6
6
|
"Daniel Bosk <dbosk@kth.se>",
|
|
@@ -52,7 +52,7 @@ python = "^3.8"
|
|
|
52
52
|
appdirs = "^1.4.4"
|
|
53
53
|
argcomplete = "^2.0.0"
|
|
54
54
|
cachetools = "^5.2.0"
|
|
55
|
-
cryptography = "^
|
|
55
|
+
cryptography = "^41.0.3"
|
|
56
56
|
keyring = "^24.2.0"
|
|
57
57
|
requests = "^2.31.0"
|
|
58
58
|
urllib3 = "^1.26.9"
|
|
@@ -504,7 +504,11 @@ If all fail, the function will return [[None]] for both.
|
|
|
504
504
|
(This is due to how we handle the [[login]] command.)
|
|
505
505
|
<<functions>>=
|
|
506
506
|
def load_credentials(filename="config.json"):
|
|
507
|
-
"""
|
|
507
|
+
"""
|
|
508
|
+
Loads credentials from environment or file named filename.
|
|
509
|
+
Returns the tuple (instituation, credential dictionary) that
|
|
510
|
+
can be passed to `LadokSession(instiution, credential dictionary)`.
|
|
511
|
+
"""
|
|
508
512
|
|
|
509
513
|
<<fetch vars from keyring>>
|
|
510
514
|
<<fetch username and password from keyring>>
|
|
@@ -46,6 +46,17 @@ It uses the [[requests]] module.
|
|
|
46
46
|
We can use the class as follows.
|
|
47
47
|
\inputminted{python}{../examples/example_LadokSession.py}
|
|
48
48
|
|
|
49
|
+
An alternative way would be to use the general authentication procedure that
|
|
50
|
+
seems to work at most Swedish universities.
|
|
51
|
+
\begin{minted}[linenos]{python}
|
|
52
|
+
import ladok3
|
|
53
|
+
|
|
54
|
+
ladok = ladok3.LadokSession("KTH Royal Institute of Technology",
|
|
55
|
+
vars={"username": os.environ["KTH_LOGIN"],
|
|
56
|
+
"password": os.environ["KTH_PASSWD"]},
|
|
57
|
+
test_environment=True) # for experiments
|
|
58
|
+
\end{minted}
|
|
59
|
+
|
|
49
60
|
This chapter covers how the [[LadokSession]] class work.
|
|
50
61
|
The remaining chapters cover what the [[ladok]] object can be used for.
|
|
51
62
|
\Cref{StudentClasses} covers how we can work with student data.
|
|
@@ -1034,27 +1045,126 @@ This is essentially an \enquote{instance of a course syllabus}.
|
|
|
1034
1045
|
We know from above that it inherits from [[LadokRemoteData]] and that it must
|
|
1035
1046
|
be initialized with the keywords [[ladok]] (for its parent) and
|
|
1036
1047
|
[[UtbildningsinstansUID]] (for itself) and optionally some data.
|
|
1037
|
-
This leaves the following methods.
|
|
1038
1048
|
<<CourseInstance methods>>=
|
|
1039
1049
|
def __init__(self, /, **kwargs):
|
|
1040
1050
|
self.__instance_id = kwargs.pop("UtbildningsinstansUID")
|
|
1041
|
-
super().__init__(**kwargs)
|
|
1051
|
+
super().__init__(**kwargs) # sets self.ladok
|
|
1042
1052
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1053
|
+
<<CourseInstance constructor body>>
|
|
1054
|
+
@
|
|
1055
|
+
|
|
1056
|
+
We can fetch the data from LADOK as follows.
|
|
1057
|
+
Note that we need to use the [[round_id]] from the [[CourseRound]] object.
|
|
1058
|
+
This works since we never have a [[CourseInstance]] object on its own, it's
|
|
1059
|
+
always parent of a [[CourseRound]] object.
|
|
1060
|
+
(And that makes this kind of ugly from an OOP perspective.)
|
|
1061
|
+
<<fetch CourseInstance data from LADOK>>=
|
|
1062
|
+
data = self.ladok.course_round_components_JSON(self.round_id)
|
|
1063
|
+
@
|
|
1064
|
+
|
|
1065
|
+
Then data will be populated with the following values:
|
|
1066
|
+
\begin{pycode}
|
|
1067
|
+
import json
|
|
1068
|
+
import ladok3
|
|
1069
|
+
import os
|
|
1047
1070
|
|
|
1071
|
+
ladok = ladok3.LadokSession(
|
|
1072
|
+
os.environ["LADOK_INST"],
|
|
1073
|
+
vars={"username": os.environ["LADOK_USER"],
|
|
1074
|
+
"password": os.environ["LADOK_PASS"]},
|
|
1075
|
+
test_environment=True)
|
|
1076
|
+
|
|
1077
|
+
print(r"\begin{minted}{JSON}")
|
|
1078
|
+
data = ladok.course_round_components_JSON(
|
|
1079
|
+
"cf7045a7-3e1c-11eb-b960-5f936a674375")
|
|
1080
|
+
ladok3.clean_data(data)
|
|
1081
|
+
print(json.dumps(data, indent=2))
|
|
1082
|
+
print(r"\end{minted}")
|
|
1083
|
+
\end{pycode}
|
|
1084
|
+
|
|
1085
|
+
Now that we have all data in [[data]], we can assign its values to the private
|
|
1086
|
+
attributes.
|
|
1087
|
+
We note, however, that some course instances lack both [[Versionsnummer]] and
|
|
1088
|
+
[[Omfattning]].
|
|
1089
|
+
It seems like faux courses are created to document when students go on
|
|
1090
|
+
Exchanges.
|
|
1091
|
+
These faux courses have a name and code, but no credits or version of syllabus.
|
|
1092
|
+
Consequently they don't have any grading scales either.
|
|
1093
|
+
|
|
1094
|
+
Our approach will be to try to assign the attributes using [[kwargs]], and if
|
|
1095
|
+
that fails, we will fetch the data (pull from LADOK).
|
|
1096
|
+
If that pull fails with missing data, then we will assume that it's one of
|
|
1097
|
+
these faux courses.
|
|
1098
|
+
<<CourseInstance constructor body>>=
|
|
1099
|
+
try:
|
|
1100
|
+
self.__assign_attr(kwargs)
|
|
1101
|
+
except:
|
|
1102
|
+
self.__pull_attributes()
|
|
1103
|
+
<<CourseInstance methods>>=
|
|
1048
1104
|
def __assign_attr(self, data):
|
|
1049
1105
|
<<assign CourseInstance data to private attributes>>
|
|
1050
1106
|
|
|
1051
1107
|
def __pull_attributes(self):
|
|
1052
|
-
<<fetch CourseInstance data
|
|
1053
|
-
|
|
1108
|
+
<<fetch CourseInstance data from LADOK>>
|
|
1109
|
+
try:
|
|
1110
|
+
self.__assign_attr(data)
|
|
1111
|
+
except:
|
|
1112
|
+
self.__assign_faux(data)
|
|
1054
1113
|
|
|
1055
1114
|
def pull(self):
|
|
1056
1115
|
self.__pull_attributes()
|
|
1057
1116
|
|
|
1117
|
+
def __assign_faux(self, data):
|
|
1118
|
+
<<assign faux CourseInstance data to private attributes>>
|
|
1119
|
+
@
|
|
1120
|
+
|
|
1121
|
+
By trial-and-error, it seems like the faux courses has none of the attributes
|
|
1122
|
+
that the real courses have.
|
|
1123
|
+
However, we try our best.
|
|
1124
|
+
<<assign common CourseInstance data to private attributes>>=
|
|
1125
|
+
if "IngaendeMoment" in data:
|
|
1126
|
+
self.__components = [CourseComponent(
|
|
1127
|
+
ladok=self.ladok, course=self,
|
|
1128
|
+
**component) for component in data["IngaendeMoment"]]
|
|
1129
|
+
else:
|
|
1130
|
+
self.__components = []
|
|
1131
|
+
<<assign CourseInstance data to private attributes>>=
|
|
1132
|
+
<<assign common CourseInstance data to private attributes>>
|
|
1133
|
+
|
|
1134
|
+
self.__name = data.pop("Benamning")
|
|
1135
|
+
self.__code = data.pop("Utbildningskod")
|
|
1136
|
+
|
|
1137
|
+
self.__credits = data.pop("Omfattning")
|
|
1138
|
+
self.__unit = data.pop("Enhet")
|
|
1139
|
+
|
|
1140
|
+
self.__version = data.pop("Versionsnummer")
|
|
1141
|
+
|
|
1142
|
+
self.__education_id = data.pop("UtbildningUID")
|
|
1143
|
+
|
|
1144
|
+
self.__grade_scale = self.ladok.get_grade_scales(
|
|
1145
|
+
id=data.pop("BetygsskalaID"))
|
|
1146
|
+
<<assign faux CourseInstance data to private attributes>>=
|
|
1147
|
+
<<assign common CourseInstance data to private attributes>>
|
|
1148
|
+
|
|
1149
|
+
self.__name = data.pop("Benamning", None)
|
|
1150
|
+
self.__code = data.pop("Utbildningskod", None)
|
|
1151
|
+
|
|
1152
|
+
self.__credits = data.pop("Omfattning", None)
|
|
1153
|
+
self.__unit = data.pop("Enhet", None)
|
|
1154
|
+
|
|
1155
|
+
self.__version = data.pop("Versionsnummer", None)
|
|
1156
|
+
|
|
1157
|
+
self.__education_id = data.pop("UtbildningUID", None)
|
|
1158
|
+
|
|
1159
|
+
try:
|
|
1160
|
+
self.__grade_scale = self.ladok.get_grade_scales(
|
|
1161
|
+
id=data.pop("BetygsskalaID"))
|
|
1162
|
+
except KeyError:
|
|
1163
|
+
self.__grade_scale = None
|
|
1164
|
+
@
|
|
1165
|
+
|
|
1166
|
+
Finally, we want to have properties to access the private attributes.
|
|
1167
|
+
<<CourseInstance methods>>=
|
|
1058
1168
|
@property
|
|
1059
1169
|
def instance_id(self):
|
|
1060
1170
|
return self.__instance_id
|
|
@@ -1092,57 +1202,6 @@ def components(self, /, **kwargs):
|
|
|
1092
1202
|
return filter_on_keys(self.__components, **kwargs)
|
|
1093
1203
|
@
|
|
1094
1204
|
|
|
1095
|
-
Now we must fetch data from LADOK.
|
|
1096
|
-
<<fetch CourseInstance data object from LADOK>>=
|
|
1097
|
-
data = self.ladok.course_round_components_JSON(self.round_id)
|
|
1098
|
-
@ Then data will be populated with the following values:
|
|
1099
|
-
\begin{pycode}
|
|
1100
|
-
import json
|
|
1101
|
-
import ladok3
|
|
1102
|
-
import os
|
|
1103
|
-
|
|
1104
|
-
ladok = ladok3.LadokSession(
|
|
1105
|
-
os.environ["LADOK_INST"],
|
|
1106
|
-
vars={"username": os.environ["LADOK_USER"],
|
|
1107
|
-
"password": os.environ["LADOK_PASS"]},
|
|
1108
|
-
test_environment=True)
|
|
1109
|
-
|
|
1110
|
-
print(r"\begin{minted}{JSON}")
|
|
1111
|
-
data = ladok.course_round_components_JSON(
|
|
1112
|
-
"cf7045a7-3e1c-11eb-b960-5f936a674375")
|
|
1113
|
-
ladok3.clean_data(data)
|
|
1114
|
-
print(json.dumps(data, indent=2))
|
|
1115
|
-
print(r"\end{minted}")
|
|
1116
|
-
\end{pycode}
|
|
1117
|
-
|
|
1118
|
-
Now that we have the [[data]] object, we can assign its values to the private
|
|
1119
|
-
attributes.
|
|
1120
|
-
We note, however, that some course instances lack both [[Versionsnummer]] and
|
|
1121
|
-
[[Omfattning]].
|
|
1122
|
-
It seems like faux courses are created to document when students go on
|
|
1123
|
-
Exchanges.
|
|
1124
|
-
These faux courses have a name and code, but no credits or version of syllabus.
|
|
1125
|
-
<<assign CourseInstance data to private attributes>>=
|
|
1126
|
-
self.__education_id = data.pop("UtbildningUID")
|
|
1127
|
-
|
|
1128
|
-
self.__code = data.pop("Utbildningskod")
|
|
1129
|
-
self.__name = data.pop("Benamning")
|
|
1130
|
-
self.__version = data.pop("Versionsnummer", None)
|
|
1131
|
-
|
|
1132
|
-
self.__credits = data.pop("Omfattning", None)
|
|
1133
|
-
self.__unit = data.pop("Enhet", None)
|
|
1134
|
-
|
|
1135
|
-
self.__grade_scale = self.ladok.get_grade_scales(
|
|
1136
|
-
id=data.pop("BetygsskalaID"))
|
|
1137
|
-
|
|
1138
|
-
if "IngaendeMoment" in data:
|
|
1139
|
-
self.__components = [CourseComponent(
|
|
1140
|
-
ladok=self.ladok, course=self,
|
|
1141
|
-
**component) for component in data["IngaendeMoment"]]
|
|
1142
|
-
else:
|
|
1143
|
-
self.__components = []
|
|
1144
|
-
@
|
|
1145
|
-
|
|
1146
1205
|
|
|
1147
1206
|
\section{Course components}
|
|
1148
1207
|
|
|
@@ -133,7 +133,7 @@ Finally, we have the list of graders.
|
|
|
133
133
|
<<add one result group arguments>>=
|
|
134
134
|
one_parser.add_argument("graders", nargs="*",
|
|
135
135
|
help="Space separated list of who did the grading, "
|
|
136
|
-
"give each grader as 'First Last <email@
|
|
136
|
+
"give each grader as 'First Last <email@institution.se>'.")
|
|
137
137
|
@
|
|
138
138
|
|
|
139
139
|
Now that we have the arguments, we can just execute the following code using
|
|
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
|