QuizGenerator 0.3.1__py3-none-any.whl → 0.4.1__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.
QuizGenerator/misc.py CHANGED
@@ -564,9 +564,9 @@ class MatrixAnswer(Answer):
564
564
  value=self.value[i,j]
565
565
  )
566
566
  )
567
- for i in range(self.value.shape[0])
567
+ for j in range(self.value.shape[1])
568
568
  ]
569
- for j in range(self.value.shape[1])
569
+ for i in range(self.value.shape[0])
570
570
  ]
571
571
  table = ContentAST.Table(data)
572
572
 
@@ -60,11 +60,9 @@ class BNF:
60
60
 
61
61
  def get_grammar_string(self):
62
62
  lines = []
63
- lines.append('```')
64
63
  for symbol in self.symbols:
65
64
  lines.append(f"{symbol.get_full_str()}")
66
-
67
- lines.append('```')
65
+
68
66
  return '\n'.join(lines)
69
67
 
70
68
  class Symbol:
@@ -342,25 +340,23 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
342
340
  def get_body(self, *args, **kwargs) -> ContentAST.Section:
343
341
  body = ContentAST.Section()
344
342
 
345
- body.add_element(
343
+ body.add_elements([
346
344
  ContentAST.Paragraph([
347
- ContentAST.OnlyHtml(
345
+ ContentAST.OnlyHtml([
348
346
  ContentAST.Text("Given the following grammar, which of the below strings are part of the language?")
349
- ),
350
- ContentAST.OnlyLatex(
347
+ ]),
348
+ ContentAST.OnlyLatex([
351
349
  ContentAST.Text(
352
350
  "Given the following grammar "
353
351
  "please circle any provided strings that are part of the language (or indicate clearly if there are none), "
354
352
  "and on each blank line provide generate a new, unique string that is part of the language."
355
353
  )
356
- )
354
+ ])
357
355
  ])
358
- )
356
+ ])
359
357
 
360
358
  body.add_element(
361
- ContentAST.Paragraph([
362
- self.grammar_good.get_grammar_string()
363
- ])
359
+ ContentAST.Code(self.grammar_good.get_grammar_string())
364
360
  )
365
361
 
366
362
  # Add in some answers as latex-only options to be circled
@@ -374,7 +370,7 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
374
370
  # For Latex-only, ask students to generate some more.
375
371
  body.add_element(
376
372
  ContentAST.OnlyLatex([
377
- ContentAST.AnswerBlock([ContentAST.Answer() for _ in range(self.num_answer_blanks)])
373
+ ContentAST.AnswerBlock([ContentAST.Answer(Answer.string(f"blank_line_{i}", f"blank_line_{i}"), label=f"blank_line_{i}") for i in range(self.num_answer_blanks)])
378
374
  ])
379
375
  )
380
376
 
@@ -28,7 +28,7 @@ class ConvolutionCalculation(MatrixQuestion):
28
28
 
29
29
  # Add padding
30
30
  if padding > 0:
31
- image = np.pad(image, ((padding, padding), (padding, padding), (0, 0)), mode='constant')
31
+ image = np.pad(image, ((padding, padding), (padding, padding)), mode='constant')
32
32
  H, W = H + 2 * padding, W + 2 * padding
33
33
 
34
34
  # Output dimensions
@@ -60,7 +60,9 @@ class word2vec__skipgram(MatrixQuestion, TableQuestionMixin):
60
60
  ## Answers:
61
61
  # center_word, center_emb, context_words, context_embs, logits, probs
62
62
  self.answers["logits"] = Answer.vector_value(key="logits", value=self.logits)
63
- self.answers["center_word"] = Answer.string(key="center_word", value=self.center_word)
63
+ most_likely_idx = np.argmax(self.probs)
64
+ most_likely_word = self.context_words[most_likely_idx]
65
+ self.answers["center_word"] = Answer.string(key="center_word", value=most_likely_word)
64
66
 
65
67
 
66
68
  return True
@@ -81,7 +83,7 @@ class word2vec__skipgram(MatrixQuestion, TableQuestionMixin):
81
83
  ContentAST.LineBreak(),
82
84
  self.answers["logits"].get_ast_element("Logits"),
83
85
  ContentAST.LineBreak(),
84
- self.answers["center_word"].get_ast_element("Center word")
86
+ self.answers["center_word"].get_ast_element("Most likely context word")
85
87
  ])
86
88
 
87
89
 
@@ -0,0 +1,472 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ QR Code-based Grading Utility
4
+
5
+ This script scans QR codes from quiz PDFs to regenerate question answers
6
+ for grading. It supports both scanning from image files and interactive
7
+ scanning from webcam/scanner.
8
+
9
+ CLI Usage:
10
+ # Scan a single QR code image
11
+ python grade_from_qr.py --image qr_code.png
12
+
13
+ # Scan QR codes from a scanned exam page
14
+ python grade_from_qr.py --image exam_page.jpg --all
15
+
16
+ API Usage (recommended for web UIs):
17
+ from grade_from_qr import regenerate_from_encrypted
18
+
19
+ # Parse QR code JSON
20
+ qr_data = json.loads(qr_string)
21
+
22
+ # Regenerate answers from encrypted data (one function call!)
23
+ result = regenerate_from_encrypted(
24
+ encrypted_data=qr_data['s'],
25
+ points=qr_data['pts']
26
+ )
27
+
28
+ # Display HTML answer key to grader
29
+ print(result['answer_key_html'])
30
+
31
+ The QR codes contain encrypted question metadata that allows regenerating
32
+ the exact question and answer without needing the original exam file.
33
+ """
34
+
35
+ import argparse
36
+ import json
37
+ import sys
38
+ import logging
39
+ from pathlib import Path
40
+ from typing import Dict, Any, Optional, List
41
+
42
+ # Quiz generator imports (always available)
43
+ from QuizGenerator.qrcode_generator import QuestionQRCode
44
+ from QuizGenerator.question import QuestionRegistry
45
+
46
+ # QR code reading (optional - only needed for CLI usage with --image)
47
+ # Your web UI should use its own QR decoding library
48
+ try:
49
+ from pyzbar import pyzbar
50
+ from PIL import Image
51
+
52
+ HAS_IMAGE_SUPPORT = True
53
+ except ImportError:
54
+ HAS_IMAGE_SUPPORT = False
55
+ # Don't fail immediately - only fail if user tries to use --image flag
56
+
57
+ logging.basicConfig(
58
+ level=logging.INFO,
59
+ format='%(levelname)s: %(message)s'
60
+ )
61
+ log = logging.getLogger(__name__)
62
+
63
+
64
+ def scan_qr_from_image(image_path: str) -> List[str]:
65
+ """
66
+ Scan all QR codes from an image file.
67
+
68
+ Args:
69
+ image_path: Path to image file containing QR code(s)
70
+
71
+ Returns:
72
+ List of decoded QR code data strings
73
+
74
+ Raises:
75
+ ImportError: If pyzbar/PIL are not installed
76
+ """
77
+ if not HAS_IMAGE_SUPPORT:
78
+ raise ImportError(
79
+ "Image support not available. Install with: pip install pyzbar pillow"
80
+ )
81
+
82
+ try:
83
+ img = Image.open(image_path)
84
+ decoded_objects = pyzbar.decode(img)
85
+
86
+ if not decoded_objects:
87
+ log.warning(f"No QR codes found in {image_path}")
88
+ return []
89
+
90
+ qr_data = [obj.data.decode('utf-8') for obj in decoded_objects]
91
+ log.info(f"Found {len(qr_data)} QR code(s) in {image_path}")
92
+
93
+ return qr_data
94
+
95
+ except Exception as e:
96
+ log.error(f"Failed to read image {image_path}: {e}")
97
+ return []
98
+
99
+
100
+ def parse_qr_data(qr_string: str) -> Dict[str, Any]:
101
+ """
102
+ Parse QR code JSON data.
103
+
104
+ Args:
105
+ qr_string: JSON string from QR code
106
+
107
+ Returns:
108
+ Dictionary with question metadata
109
+ {
110
+ "q": question_number,
111
+ "pts": points_value,
112
+ "s": encrypted_seed_data (optional)
113
+ }
114
+ """
115
+ try:
116
+ data = json.loads(qr_string)
117
+ log.debug(f"Parsed QR data: {data}")
118
+ return data
119
+ except json.JSONDecodeError as e:
120
+ log.error(f"Failed to parse QR code JSON: {e}")
121
+ return {}
122
+
123
+
124
+ def regenerate_question_answer(qr_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
125
+ """
126
+ Regenerate question and extract answer using QR code metadata.
127
+
128
+ Args:
129
+ qr_data: Parsed QR code data dictionary
130
+
131
+ Returns:
132
+ Dictionary with question info and answers, or None if regeneration fails
133
+ {
134
+ "question_number": int,
135
+ "points": float,
136
+ "question_type": str,
137
+ "seed": int,
138
+ "version": str,
139
+ "answers": dict,
140
+ "explanation_markdown": str | None # Markdown explanation (None if not available)
141
+ }
142
+ """
143
+ question_num = qr_data.get('q')
144
+ points = qr_data.get('pts')
145
+
146
+ if question_num is None or points is None:
147
+ log.error("QR code missing required fields 'q' or 'pts'")
148
+ return None
149
+
150
+ result = {
151
+ "question_number": question_num,
152
+ "points": points
153
+ }
154
+
155
+ # Check if encrypted regeneration data is present
156
+ encrypted_data = qr_data.get('s')
157
+ if not encrypted_data:
158
+ log.warning(f"Question {question_num}: No regeneration data in QR code")
159
+ log.warning(" This question cannot be automatically regenerated.")
160
+ log.warning(" (QR codes generated before encryption feature was added)")
161
+ return result
162
+
163
+ try:
164
+ # Decrypt the regeneration data
165
+ regen_data = QuestionQRCode.decrypt_question_data(encrypted_data)
166
+
167
+ question_type = regen_data['question_type']
168
+ seed = regen_data['seed']
169
+ version = regen_data['version']
170
+ config = regen_data.get('config', {})
171
+
172
+ result['question_type'] = question_type
173
+ result['seed'] = seed
174
+ result['version'] = version
175
+ if config:
176
+ result['config'] = config
177
+
178
+ log.info(f"Question {question_num}: {question_type} (seed={seed}, version={version})")
179
+ if config:
180
+ log.debug(f" Config params: {config}")
181
+
182
+ # Regenerate the question using the registry, passing through config params
183
+ question = QuestionRegistry.create(
184
+ question_type,
185
+ name=f"Q{question_num}",
186
+ points_value=points,
187
+ **config
188
+ )
189
+
190
+ # Generate question with the specific seed
191
+ question_ast = question.get_question(rng_seed=seed)
192
+
193
+ # Extract answers
194
+ answer_kind, canvas_answers = question.get_answers()
195
+
196
+ result['answers'] = {
197
+ 'kind': answer_kind.value,
198
+ 'data': canvas_answers
199
+ }
200
+
201
+ # Also store the raw answer objects for easier access
202
+ result['answer_objects'] = question.answers
203
+
204
+ # Generate HTML answer key for grading
205
+ question_html = question_ast.body.render("html", show_answers=True)
206
+ result['answer_key_html'] = question_html
207
+
208
+ # Generate markdown explanation for students
209
+ explanation_markdown = question_ast.explanation.render("markdown")
210
+ # Return None if explanation is empty or contains the default placeholder
211
+ if not explanation_markdown or "[Please reach out to your professor for clarification]" in explanation_markdown:
212
+ result['explanation_markdown'] = None
213
+ else:
214
+ result['explanation_markdown'] = explanation_markdown
215
+
216
+ log.info(f" Successfully regenerated question with {len(canvas_answers)} answer(s)")
217
+
218
+ return result
219
+
220
+ except Exception as e:
221
+ log.error(f"Failed to regenerate question {question_num}: {e}")
222
+ import traceback
223
+ log.debug(traceback.format_exc())
224
+ return result
225
+
226
+
227
+ def regenerate_from_encrypted(encrypted_data: str, points: float = 1.0) -> Dict[str, Any]:
228
+ """
229
+ Regenerate question answers from encrypted QR code data (RECOMMENDED API).
230
+
231
+ This is the simplest function for web UI integration - just pass the encrypted
232
+ string from the QR code and get back the complete answer key.
233
+
234
+ Args:
235
+ encrypted_data: The encrypted 's' field from the QR code JSON
236
+ points: Point value for the question (default: 1.0)
237
+
238
+ Returns:
239
+ Dictionary with regenerated answers:
240
+ {
241
+ "question_type": str,
242
+ "seed": int,
243
+ "version": str,
244
+ "points": float,
245
+ "kwargs": dict, # Question-specific config params (if any)
246
+ "answers": dict, # Canvas-formatted answers
247
+ "answer_objects": dict, # Raw Answer objects with values/tolerances
248
+ "answer_key_html": str, # HTML rendering of question with answers shown
249
+ "explanation_markdown": str | None # Markdown explanation (None if not available)
250
+ }
251
+
252
+ Raises:
253
+ ValueError: If decryption fails or question regeneration fails
254
+
255
+ Example:
256
+ >>> # Your web UI scans QR code and gets JSON: {"q": 1, "pts": 5, "s": "gAAAAAB..."}
257
+ >>> encrypted_string = qr_json['s']
258
+ >>> result = regenerate_from_encrypted(encrypted_string, points=qr_json['pts'])
259
+ >>> print(result['answer_key_html']) # Display to grader!
260
+ """
261
+ # Decrypt the data
262
+ decrypted = QuestionQRCode.decrypt_question_data(encrypted_data)
263
+
264
+ # Extract fields
265
+ question_type = decrypted['question_type']
266
+ seed = decrypted['seed']
267
+ version = decrypted['version']
268
+ kwargs = decrypted.get('config', {})
269
+
270
+ # Use the existing regeneration logic
271
+ return regenerate_from_metadata(question_type, seed, version, points, kwargs)
272
+
273
+
274
+ def regenerate_from_metadata(
275
+ question_type: str, seed: int, version: str,
276
+ points: float = 1.0, kwargs: Optional[Dict[str, Any]] = None
277
+ ) -> Dict[str, Any]:
278
+ """
279
+ Regenerate question answers from explicit metadata fields.
280
+
281
+ This is a lower-level function. Most users should use regenerate_from_encrypted() instead.
282
+
283
+ Args:
284
+ question_type: Question class name (e.g., "VirtualAddressParts")
285
+ seed: Random seed used to generate the question
286
+ version: Question version string (e.g., "1.0")
287
+ points: Point value for the question (default: 1.0)
288
+ kwargs: Optional dictionary of question-specific configuration parameters
289
+ (e.g., {"num_bits_va": 32, "max_value": 100})
290
+
291
+ Returns:
292
+ Dictionary with regenerated answers (same format as regenerate_from_encrypted)
293
+
294
+ Raises:
295
+ ValueError: If question type is not registered or regeneration fails
296
+ """
297
+ if kwargs is None:
298
+ kwargs = {}
299
+
300
+ try:
301
+ log.info(f"Regenerating: {question_type} (seed={seed}, version={version})")
302
+ if kwargs:
303
+ log.debug(f" Config params: {kwargs}")
304
+
305
+ # Create question instance from registry, passing through kwargs
306
+ question = QuestionRegistry.create(
307
+ question_type,
308
+ name=f"Q_{question_type}_{seed}",
309
+ points_value=points,
310
+ **kwargs
311
+ )
312
+
313
+ # Generate question with the specific seed
314
+ question_ast = question.get_question(rng_seed=seed)
315
+
316
+ # Extract answers
317
+ answer_kind, canvas_answers = question.get_answers()
318
+
319
+ # Generate HTML answer key for grading
320
+ question_html = question_ast.body.render("html", show_answers=True)
321
+
322
+ # Generate markdown explanation for students
323
+ explanation_markdown = question_ast.explanation.render("markdown")
324
+ # Return None if explanation is empty or contains the default placeholder
325
+ if not explanation_markdown or "[Please reach out to your professor for clarification]" in explanation_markdown:
326
+ explanation_markdown = None
327
+
328
+ result = {
329
+ "question_type": question_type,
330
+ "seed": seed,
331
+ "version": version,
332
+ "points": points,
333
+ "answers": {
334
+ "kind": answer_kind.value,
335
+ "data": canvas_answers
336
+ },
337
+ "answer_objects": question.answers,
338
+ "answer_key_html": question_html,
339
+ "explanation_markdown": explanation_markdown
340
+ }
341
+
342
+ # Include kwargs in result if provided
343
+ if kwargs:
344
+ result["kwargs"] = kwargs
345
+
346
+ log.info(f" Successfully regenerated with {len(canvas_answers)} answer(s)")
347
+ return result
348
+
349
+ except Exception as e:
350
+ log.error(f"Failed to regenerate question: {e}")
351
+ import traceback
352
+ log.debug(traceback.format_exc())
353
+ raise ValueError(f"Failed to regenerate question {question_type}: {e}")
354
+
355
+
356
+ def display_answer_summary(question_data: Dict[str, Any]) -> None:
357
+ """
358
+ Display a formatted summary of the question and its answer(s).
359
+
360
+ Args:
361
+ question_data: Question data dictionary from regenerate_question_answer
362
+ """
363
+ print("\n" + "=" * 60)
364
+ print(f"Question {question_data['question_number']}: {question_data.get('points', '?')} points")
365
+
366
+ if 'question_type' in question_data:
367
+ print(f"Type: {question_data['question_type']}")
368
+ print(f"Seed: {question_data['seed']}")
369
+ print(f"Version: {question_data['version']}")
370
+
371
+ if 'answer_objects' in question_data:
372
+ print("\nANSWERS:")
373
+ for key, answer_obj in question_data['answer_objects'].items():
374
+ print(f" {key}: {answer_obj.value}")
375
+ if hasattr(answer_obj, 'tolerance') and answer_obj.tolerance:
376
+ print(f" (tolerance: ±{answer_obj.tolerance})")
377
+ elif 'answers' in question_data:
378
+ print("\nANSWERS (raw Canvas format):")
379
+ print(f" Type: {question_data['answers']['kind']}")
380
+ for ans in question_data['answers']['data']:
381
+ print(f" - {ans}")
382
+ else:
383
+ print("\n(No regeneration data available)")
384
+
385
+ if 'answer_key_html' in question_data:
386
+ print("\nHTML answer key available in result['answer_key_html']")
387
+
388
+ if 'explanation_markdown' in question_data and question_data['explanation_markdown'] is not None:
389
+ print("Markdown explanation available in result['explanation_markdown']")
390
+
391
+ print("=" * 60)
392
+
393
+
394
+ def main():
395
+ parser = argparse.ArgumentParser(
396
+ description="Scan QR codes from quiz PDFs to regenerate answers for grading"
397
+ )
398
+ parser.add_argument(
399
+ '--image',
400
+ type=str,
401
+ help='Path to image file containing QR code(s)'
402
+ )
403
+ parser.add_argument(
404
+ '--all',
405
+ action='store_true',
406
+ help='Process all QR codes found in the image (default: only first one)'
407
+ )
408
+ parser.add_argument(
409
+ '--output',
410
+ type=str,
411
+ help='Save results to JSON file'
412
+ )
413
+ parser.add_argument(
414
+ '--verbose', '-v',
415
+ action='store_true',
416
+ help='Enable verbose debug logging'
417
+ )
418
+
419
+ args = parser.parse_args()
420
+
421
+ if args.verbose:
422
+ logging.getLogger().setLevel(logging.DEBUG)
423
+
424
+ if not args.image:
425
+ parser.print_help()
426
+ print("\nERROR: --image is required")
427
+ sys.exit(1)
428
+
429
+ # Scan QR codes from image
430
+ qr_codes = scan_qr_from_image(args.image)
431
+
432
+ if not qr_codes:
433
+ print("No QR codes found in image")
434
+ sys.exit(1)
435
+
436
+ # Process QR codes
437
+ if not args.all:
438
+ qr_codes = qr_codes[:1]
439
+ log.info("Processing only the first QR code (use --all to process all)")
440
+
441
+ results = []
442
+
443
+ for qr_string in qr_codes:
444
+ # Parse QR data
445
+ qr_data = parse_qr_data(qr_string)
446
+
447
+ if not qr_data:
448
+ continue
449
+
450
+ # Regenerate question and answer
451
+ question_data = regenerate_question_answer(qr_data)
452
+
453
+ if question_data:
454
+ results.append(question_data)
455
+ display_answer_summary(question_data)
456
+
457
+ # Save to file if requested
458
+ if args.output:
459
+ output_path = Path(args.output)
460
+ with open(output_path, 'w') as f:
461
+ json.dump(results, f, indent=2, default=str)
462
+ log.info(f"Results saved to {output_path}")
463
+
464
+ if not results:
465
+ print("\nNo questions could be regenerated from the QR codes.")
466
+ sys.exit(1)
467
+
468
+ print(f"\nSuccessfully regenerated {len(results)} question(s)")
469
+
470
+
471
+ if __name__ == '__main__':
472
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QuizGenerator
3
- Version: 0.3.1
3
+ Version: 0.4.1
4
4
  Summary: Generate randomized quiz questions for Canvas LMS and PDF exams
5
5
  Project-URL: Homepage, https://github.com/OtterDen-Lab/QuizGenerator
6
6
  Project-URL: Documentation, https://github.com/OtterDen-Lab/QuizGenerator/tree/main/documentation
@@ -5,12 +5,13 @@ QuizGenerator/constants.py,sha256=AO-UWwsWPLb1k2JW6KP8rl9fxTcdT0rW-6XC6zfnDOs,43
5
5
  QuizGenerator/contentast.py,sha256=Em4cnA64Y8_07VruJk_MXwiWcJwqT4-YVf-Lw7uIvYY,68327
6
6
  QuizGenerator/generate.py,sha256=o2XezoSE0u-qjxYu1_Ofm9Lpkza7M2Tg47C-ClMcPsE,7197
7
7
  QuizGenerator/logging.yaml,sha256=VJCdh26D8e_PNUs4McvvP1ojz9EVjQNifJzfhEk1Mbo,1114
8
- QuizGenerator/misc.py,sha256=JYv-SUn3y33O6grpgvRWRBkJi4RhTuXcMgrhmBjRbZg,18710
8
+ QuizGenerator/misc.py,sha256=2vEztj-Kt_0Q2OnynJKC4gL_w7l1MqWsBhhIDOuVD1s,18710
9
9
  QuizGenerator/mixins.py,sha256=zUKTkswq7aoDZ_nGPUdRuvnza8iH8ZCi6IH2Uw-kCvs,18492
10
10
  QuizGenerator/performance.py,sha256=CM3zLarJXN5Hfrl4-6JRBqD03j4BU1B2QW699HAr1Ds,7002
11
11
  QuizGenerator/qrcode_generator.py,sha256=S3mzZDk2UiHiw6ipSCpWPMhbKvSRR1P5ordZJUTo6ug,10776
12
12
  QuizGenerator/question.py,sha256=uxDYyrq17JFXQ11S03Px5cyRuPYn4qKT3z7TZn9XSjg,26093
13
13
  QuizGenerator/quiz.py,sha256=toPodXea2UYGgAf4jyor3Gz-gtXYN1YUJFJFQ5u70v4,18718
14
+ QuizGenerator/regenerate.py,sha256=EvtFhDUXYaWEBCGJ4RW-zN65qj3cMxWa_Y_Rn44WU6c,14282
14
15
  QuizGenerator/typst_utils.py,sha256=XtMEO1e4_Tg0G1zR9D1fmrYKlUfHenBPdGoCKR0DhZg,3154
15
16
  QuizGenerator/canvas/__init__.py,sha256=TwFP_zgxPIlWtkvIqQ6mcvBNTL9swIH_rJl7DGKcvkQ,286
16
17
  QuizGenerator/canvas/canvas_interface.py,sha256=wsEWh2lonUMgmbtXF-Zj59CAM_0NInoaERqsujlYMfc,24501
@@ -18,7 +19,7 @@ QuizGenerator/canvas/classes.py,sha256=v_tQ8t_JJplU9sv2p4YctX45Fwed1nQ2HC1oC9BnD
18
19
  QuizGenerator/premade_questions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
20
  QuizGenerator/premade_questions/basic.py,sha256=wAvVZED6a7VToIvSCdAx6SrExmR0xVRo5dL40kycdXI,3402
20
21
  QuizGenerator/premade_questions/cst334/__init__.py,sha256=BTz-Os1XbwIRKqAilf2UIva2NlY0DbA_XbSIggO2Tdk,36
21
- QuizGenerator/premade_questions/cst334/languages.py,sha256=N5vcmZi-AFM_BZypnvNogHD7s--28-j-8tykYg6CBzs,14388
22
+ QuizGenerator/premade_questions/cst334/languages.py,sha256=MTqprY8VUWgNlP0zRRpZXOAP2dd6ocx_XWVqcNlxYg8,14390
22
23
  QuizGenerator/premade_questions/cst334/math_questions.py,sha256=za8lNqhM0RB8qefmPP-Ww0WB_SQn0iRcBKOrZgyHCQQ,9290
23
24
  QuizGenerator/premade_questions/cst334/memory_questions.py,sha256=B4hpnMliJY-x65hNbjwbf22m-jiTi3WEXmauKv_YA84,51598
24
25
  QuizGenerator/premade_questions/cst334/ostep13_vsfs.py,sha256=d9jjrynEw44vupAH_wKl57UoHooCNEJXaC5DoNYualk,16163
@@ -35,17 +36,17 @@ QuizGenerator/premade_questions/cst463/math_and_data/matrix_questions.py,sha256=
35
36
  QuizGenerator/premade_questions/cst463/math_and_data/vector_questions.py,sha256=tNxfR6J1cZHsHG9GfwVyl6lxxN_TEnhKDmMq4aVLwow,20793
36
37
  QuizGenerator/premade_questions/cst463/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
38
  QuizGenerator/premade_questions/cst463/models/attention.py,sha256=i8h6DihzJTc_QFrdm1eaYhnuhlXKRUv_vIDg3jk_LZ8,5502
38
- QuizGenerator/premade_questions/cst463/models/cnns.py,sha256=iNuQmHgd8kwAXaofTwidal6pZum31r21UP3XERspE0M,5774
39
+ QuizGenerator/premade_questions/cst463/models/cnns.py,sha256=M0_9wlPhQICje1UdwIbDoBA4qzjmJtmP9VVVneYM5Mc,5766
39
40
  QuizGenerator/premade_questions/cst463/models/matrices.py,sha256=H61_8cF1DGCt4Z4Ssoi4SMClf6tD5wHkOqY5bMdsSt4,699
40
41
  QuizGenerator/premade_questions/cst463/models/rnns.py,sha256=-tXeGgqPkctBBUy4RvEPqhv2kfPqoyO2wk-lNJLNWmY,6697
41
- QuizGenerator/premade_questions/cst463/models/text.py,sha256=T1cmaoxNcWK1UbytFQmweL_Nmkm5ONq1m6F4AIJdmdc,6284
42
+ QuizGenerator/premade_questions/cst463/models/text.py,sha256=bUiDIzOBEzilUKQjm2yO9ufcvJGY6Gt3qfeNP9UZOrc,6400
42
43
  QuizGenerator/premade_questions/cst463/models/weight_counting.py,sha256=acygK-MobvdmwS4UYKVVL4Ey59M1qmq8dITWOT6V-aI,6793
43
44
  QuizGenerator/premade_questions/cst463/neural-network-basics/__init__.py,sha256=pmyCezO-20AFEQC6MR7KnAsaU9TcgZYsGQOMVkRZ-U8,149
44
45
  QuizGenerator/premade_questions/cst463/neural-network-basics/neural_network_questions.py,sha256=pyTSvibCaLuT0LnYAZfjUoZlzywaPWWAaSZ5VepH04E,44148
45
46
  QuizGenerator/premade_questions/cst463/tensorflow-intro/__init__.py,sha256=G1gEHtG4KakYgi8ZXSYYhX6bQRtnm2tZVGx36d63Nmo,173
46
47
  QuizGenerator/premade_questions/cst463/tensorflow-intro/tensorflow_questions.py,sha256=dPn8Sj0yk4m02np62esMKZ7CvcljhYq3Tq51nY9aJnA,29781
47
- quizgenerator-0.3.1.dist-info/METADATA,sha256=5Q7Q6ypYJbLZplzvY0Q2smH_dgyCqKcj_nJ7IrFLFMA,7212
48
- quizgenerator-0.3.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
49
- quizgenerator-0.3.1.dist-info/entry_points.txt,sha256=iViWMzswXGe88WKoue_Ib-ODUSiT_j_6f1us28w9pkc,56
50
- quizgenerator-0.3.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
- quizgenerator-0.3.1.dist-info/RECORD,,
48
+ quizgenerator-0.4.1.dist-info/METADATA,sha256=Yo9okMZOhafNPqYyPT9V-wovJs8YcSvxeTXCr3U7ILs,7212
49
+ quizgenerator-0.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
50
+ quizgenerator-0.4.1.dist-info/entry_points.txt,sha256=aOIdRdw26xY8HkxOoKHBnUPe2mwGv5Ti3U1zojb6zxQ,98
51
+ quizgenerator-0.4.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
52
+ quizgenerator-0.4.1.dist-info/RECORD,,
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  quizgen = QuizGenerator.generate:main
3
+ quizregen = QuizGenerator.regenerate:main