ladok3 4.10__py3-none-any.whl → 5.4__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.
ladok3/data.nw CHANGED
@@ -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 data DD1315 > DD1315.csv
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 time.
29
+ \item either absolute date or normalized to the course start and finish.
30
30
  \end{itemize}
31
31
 
32
32
 
33
- \section{The [[data]] subcommand}\label{DataCommand}
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
@@ -47,10 +47,24 @@ import sys
47
47
  <<functions>>
48
48
 
49
49
  def add_command_options(parser):
50
+ """Add the 'course' subcommand options to the argument parser.
51
+
52
+ Creates a subparser for the course data extraction command with all
53
+ necessary arguments for filtering and output formatting.
54
+
55
+ Args:
56
+ parser (ArgumentParser): The parent parser to add the subcommand to.
57
+ """
50
58
  <<add data parser to parser>>
51
59
  <<add data command arguments to data parser>>
52
60
 
53
61
  def command(ladok, args):
62
+ """Execute the course data extraction command.
63
+
64
+ Args:
65
+ ladok (LadokSession): The LADOK session for data access.
66
+ args: Parsed command line arguments containing course and filter options.
67
+ """
54
68
  <<produce data about course specified in args>>
55
69
  @
56
70
 
@@ -59,7 +73,7 @@ def command(ladok, args):
59
73
  We add a subparser.
60
74
  We set it up to use the function [[command]].
61
75
  <<add data parser to parser>>=
62
- data_parser = parser.add_parser("data",
76
+ data_parser = parser.add_parser("course",
63
77
  help="Returns course results data in CSV form",
64
78
  description="""
65
79
  Returns the results in CSV form for all first-time registered students.
@@ -76,12 +90,13 @@ This way the user can deal with how to store the data.
76
90
  <<produce data about course specified in args>>=
77
91
  data_writer = csv.writer(sys.stdout, delimiter=args.delimiter)
78
92
  course_rounds = filter_rounds(
79
- ladok.search_course_rounds(code=args.course_code),
80
- args.rounds)
93
+ ladok.search_course_rounds(code=args.course_code),
94
+ args.rounds)
81
95
 
82
- data_writer.writerow([
83
- "Course", "Round", "Component", "Student", "Grade", "Time"
84
- ])
96
+ if args.header:
97
+ data_writer.writerow([
98
+ "Course", "Round", "Component", "Student", "Grade", "Time"
99
+ ])
85
100
  for course_round in course_rounds:
86
101
  data = extract_data_for_round(ladok, course_round, args)
87
102
 
@@ -91,6 +106,7 @@ for course_round in course_rounds:
91
106
  student, grade, time]
92
107
  )
93
108
  @ We must take a course code and a delimiter as arguments.
109
+ We also want to know if we want a header or not.
94
110
  <<add data command arguments to data parser>>=
95
111
  data_parser.add_argument("course_code",
96
112
  help="The course code of the course for which to export data")
@@ -100,6 +116,9 @@ data_parser.add_argument("-d", "--delimiter",
100
116
  help="The delimiter for the CSV output; "
101
117
  "default is a tab character to be compatible with POSIX commands, "
102
118
  "use `-d,` or `-d ,` to get comma-separated values.")
119
+
120
+ data_parser.add_argument("-H", "--header", action="store_true",
121
+ help="Print a header line with the column names.")
103
122
  @
104
123
 
105
124
  We filter the rounds.
@@ -129,24 +148,40 @@ We also need the course round through the [[course_round]] object of type
129
148
  [[CourseRound]].
130
149
  <<functions>>=
131
150
  def extract_data_for_round(ladok, course_round, args):
151
+ """Extract student result data for a specific course round.
152
+
153
+ Processes a course round to extract student results data in CSV format,
154
+ filtering by students and components as specified in args.
155
+
156
+ Args:
157
+ ladok (LadokSession): The LADOK session for data access.
158
+ course_round: The course round object to extract data from.
159
+ args: Command line arguments containing filter options.
160
+
161
+ Returns:
162
+ list: List of result data dictionaries for CSV output.
163
+ """
132
164
  <<compute start and length of the course>>
133
165
  <<get the results for the course round>>
134
166
 
135
- students = filter_students(course_round.participants(), args.students)
167
+ students = filter_students(course_round.participants(),
168
+ args.students)
136
169
 
137
170
  for student in students:
138
- student_results = filter_student_results(student, results)
171
+ student_results = filter_student_results(student,
172
+ results)
139
173
 
140
174
  <<determine if student should be included>>
141
175
 
142
- components = filter_components(course_round.components(), args.components)
176
+ components = filter_components(course_round.components(),
177
+ args.components)
143
178
 
144
179
  for component in components:
145
180
  if len(student_results) < 1:
146
181
  result_data = None
147
182
  else:
148
- result_data = filter_component_result(
149
- component, student_results[0]["ResultatPaUtbildningar"])
183
+ result_data = filter_component_result(component,
184
+ student_results[0]["ResultatPaUtbildningar"])
150
185
 
151
186
  if not result_data:
152
187
  grade = "-"
@@ -154,7 +189,29 @@ def extract_data_for_round(ladok, course_round, args):
154
189
  else:
155
190
  <<extract grade and normalized date from result data>>
156
191
 
157
- yield student, component, grade, normalized_date
192
+ <<yield [[student, component, grade]] and date>>
193
+ @
194
+
195
+ We want to yield the data in CSV form, so we simply yield a tuple.
196
+ The date is either the normalized date or the date from the result data.
197
+ The student's identifier will be either the LADOK ID or the student name and
198
+ personnummer, depending on the command line arguments.
199
+ <<yield [[student, component, grade]] and date>>=
200
+ yield student.ladok_id if args.ladok_id \
201
+ else student, \
202
+ component, \
203
+ grade, \
204
+ normalized_date if args.normalize_date \
205
+ else result_data["Examinationsdatum"] if result_data \
206
+ else None
207
+ <<add data command arguments to data parser>>=
208
+ data_parser.add_argument("-l", "--ladok-id", action="store_true",
209
+ help="Use the LADOK ID for the student, "
210
+ "otherwise the student name and personnummer "
211
+ "will be used.")
212
+ data_parser.add_argument("-n", "--normalize-date", action="store_true",
213
+ help="Normalize the date to the start of the course, "
214
+ "otherwise the date is printed as is.")
158
215
  @
159
216
 
160
217
  \subsection{Get round data}
@@ -185,6 +242,15 @@ Then we must search for a student's result in the batch of results we received
185
242
  from LADOK.
186
243
  <<functions>>=
187
244
  def filter_student_results(student, results):
245
+ """Filter results for a specific student.
246
+
247
+ Args:
248
+ student: Student object with ladok_id attribute.
249
+ results (list): List of result dictionaries from LADOK.
250
+
251
+ Returns:
252
+ list: Filtered list containing only results for the specified student.
253
+ """
188
254
  return list(filter(
189
255
  lambda x: x["Student"]["Uid"] == student.ladok_id,
190
256
  results))
@@ -193,6 +259,17 @@ def filter_student_results(student, results):
193
259
  Similarly, we want to find the result for a particular component.
194
260
  <<functions>>=
195
261
  def filter_component_result(component, results):
262
+ """Find the result data for a specific course component.
263
+
264
+ Searches through results to find the entry matching the given component.
265
+
266
+ Args:
267
+ component: Course component object to search for.
268
+ results (list): List of result dictionaries to search through.
269
+
270
+ Returns:
271
+ dict or None: Result data for the component, or None if not found.
272
+ """
196
273
  for component_result in results:
197
274
  <<get the component result data>>
198
275
  <<check component code in result data>>
ladok3/data.py CHANGED
@@ -13,6 +13,19 @@ def filter_rounds(all_rounds, desired_rounds):
13
13
 
14
14
 
15
15
  def extract_data_for_round(ladok, course_round, args):
16
+ """Extract student result data for a specific course round.
17
+
18
+ Processes a course round to extract student results data in CSV format,
19
+ filtering by students and components as specified in args.
20
+
21
+ Args:
22
+ ladok (LadokSession): The LADOK session for data access.
23
+ course_round: The course round object to extract data from.
24
+ args: Command line arguments containing filter options.
25
+
26
+ Returns:
27
+ list: List of result data dictionaries for CSV output.
28
+ """
16
29
  course_start = course_round.start
17
30
  course_length = course_round.end - course_start
18
31
  component = course_round.components()[0]
@@ -60,14 +73,38 @@ def extract_data_for_round(ladok, course_round, args):
60
73
  grade = "-"
61
74
  normalized_date = None
62
75
 
63
- yield student, component, grade, normalized_date
76
+ yield student.ladok_id if args.ladok_id else student, component, grade, (
77
+ normalized_date
78
+ if args.normalize_date
79
+ else result_data["Examinationsdatum"] if result_data else None
80
+ )
64
81
 
65
82
 
66
83
  def filter_student_results(student, results):
84
+ """Filter results for a specific student.
85
+
86
+ Args:
87
+ student: Student object with ladok_id attribute.
88
+ results (list): List of result dictionaries from LADOK.
89
+
90
+ Returns:
91
+ list: Filtered list containing only results for the specified student.
92
+ """
67
93
  return list(filter(lambda x: x["Student"]["Uid"] == student.ladok_id, results))
68
94
 
69
95
 
70
96
  def filter_component_result(component, results):
97
+ """Find the result data for a specific course component.
98
+
99
+ Searches through results to find the entry matching the given component.
100
+
101
+ Args:
102
+ component: Course component object to search for.
103
+ results (list): List of result dictionaries to search through.
104
+
105
+ Returns:
106
+ dict or None: Result data for the component, or None if not found.
107
+ """
71
108
  for component_result in results:
72
109
  if "Arbetsunderlag" in component_result:
73
110
  result_data = component_result["Arbetsunderlag"]
@@ -131,8 +168,16 @@ def has_credit_transfer(results):
131
168
 
132
169
 
133
170
  def add_command_options(parser):
171
+ """Add the 'course' subcommand options to the argument parser.
172
+
173
+ Creates a subparser for the course data extraction command with all
174
+ necessary arguments for filtering and output formatting.
175
+
176
+ Args:
177
+ parser (ArgumentParser): The parent parser to add the subcommand to.
178
+ """
134
179
  data_parser = parser.add_parser(
135
- "data",
180
+ "course",
136
181
  help="Returns course results data in CSV form",
137
182
  description="""
138
183
  Returns the results in CSV form for all first-time registered students.
@@ -151,6 +196,13 @@ def add_command_options(parser):
151
196
  "default is a tab character to be compatible with POSIX commands, "
152
197
  "use `-d,` or `-d ,` to get comma-separated values.",
153
198
  )
199
+
200
+ data_parser.add_argument(
201
+ "-H",
202
+ "--header",
203
+ action="store_true",
204
+ help="Print a header line with the column names.",
205
+ )
154
206
  data_parser.add_argument(
155
207
  "-r",
156
208
  "--rounds",
@@ -158,6 +210,21 @@ def add_command_options(parser):
158
210
  help="The round codes for the rounds to include, "
159
211
  "otherwise all rounds will be included.",
160
212
  )
213
+ data_parser.add_argument(
214
+ "-l",
215
+ "--ladok-id",
216
+ action="store_true",
217
+ help="Use the LADOK ID for the student, "
218
+ "otherwise the student name and personnummer "
219
+ "will be used.",
220
+ )
221
+ data_parser.add_argument(
222
+ "-n",
223
+ "--normalize-date",
224
+ action="store_true",
225
+ help="Normalize the date to the start of the course, "
226
+ "otherwise the date is printed as is.",
227
+ )
161
228
  data_parser.add_argument(
162
229
  "-t",
163
230
  "--time-limit",
@@ -183,12 +250,21 @@ def add_command_options(parser):
183
250
 
184
251
 
185
252
  def command(ladok, args):
253
+ """Execute the course data extraction command.
254
+
255
+ Args:
256
+ ladok (LadokSession): The LADOK session for data access.
257
+ args: Parsed command line arguments containing course and filter options.
258
+ """
186
259
  data_writer = csv.writer(sys.stdout, delimiter=args.delimiter)
187
260
  course_rounds = filter_rounds(
188
261
  ladok.search_course_rounds(code=args.course_code), args.rounds
189
262
  )
190
263
 
191
- data_writer.writerow(["Course", "Round", "Component", "Student", "Grade", "Time"])
264
+ if args.header:
265
+ data_writer.writerow(
266
+ ["Course", "Round", "Component", "Student", "Grade", "Time"]
267
+ )
192
268
  for course_round in course_rounds:
193
269
  data = extract_data_for_round(ladok, course_round, args)
194
270
 
ladok3/ladok.bash CHANGED
@@ -25,22 +25,40 @@ __python_argcomplete_run_inner() {
25
25
 
26
26
  _python_argcomplete() {
27
27
  local IFS=$'\013'
28
- local SUPPRESS_SPACE=0
29
- if compopt +o nospace 2> /dev/null; then
30
- SUPPRESS_SPACE=1
31
- fi
32
- COMPREPLY=( $(IFS="$IFS" \
33
- COMP_LINE="$COMP_LINE" \
34
- COMP_POINT="$COMP_POINT" \
35
- COMP_TYPE="$COMP_TYPE" \
36
- _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \
37
- _ARGCOMPLETE=1 \
38
- _ARGCOMPLETE_SUPPRESS_SPACE=$SUPPRESS_SPACE \
39
- __python_argcomplete_run "$1") )
40
- if [[ $? != 0 ]]; then
41
- unset COMPREPLY
42
- elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then
43
- compopt -o nospace
28
+ local script=""
29
+ if [[ -n "${ZSH_VERSION-}" ]]; then
30
+ local completions
31
+ completions=($(IFS="$IFS" \
32
+ COMP_LINE="$BUFFER" \
33
+ COMP_POINT="$CURSOR" \
34
+ _ARGCOMPLETE=1 \
35
+ _ARGCOMPLETE_SHELL="zsh" \
36
+ _ARGCOMPLETE_SUPPRESS_SPACE=1 \
37
+ __python_argcomplete_run ${script:-${words[1]}}))
38
+ _describe "${words[1]}" completions -o nosort
39
+ else
40
+ local SUPPRESS_SPACE=0
41
+ if compopt +o nospace 2> /dev/null; then
42
+ SUPPRESS_SPACE=1
43
+ fi
44
+ COMPREPLY=($(IFS="$IFS" \
45
+ COMP_LINE="$COMP_LINE" \
46
+ COMP_POINT="$COMP_POINT" \
47
+ COMP_TYPE="$COMP_TYPE" \
48
+ _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \
49
+ _ARGCOMPLETE=1 \
50
+ _ARGCOMPLETE_SHELL="bash" \
51
+ _ARGCOMPLETE_SUPPRESS_SPACE=$SUPPRESS_SPACE \
52
+ __python_argcomplete_run ${script:-$1}))
53
+ if [[ $? != 0 ]]; then
54
+ unset COMPREPLY
55
+ elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then
56
+ compopt -o nospace
57
+ fi
44
58
  fi
45
59
  }
46
- complete -o nospace -o default -o bashdefault -F _python_argcomplete ladok
60
+ if [[ -z "${ZSH_VERSION-}" ]]; then
61
+ complete -o nospace -o default -o bashdefault -F _python_argcomplete ladok
62
+ else
63
+ compdef _python_argcomplete ladok
64
+ fi