cornellGrading 2.21.0__tar.gz → 2.22.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.
Files changed (24) hide show
  1. {cornellgrading-2.21.0/cornellGrading.egg-info → cornellgrading-2.22.0}/PKG-INFO +1 -1
  2. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/__init__.py +1 -1
  3. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/cornellGrading.py +38 -12
  4. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/cornellQualtrics.py +74 -1
  5. {cornellgrading-2.21.0 → cornellgrading-2.22.0/cornellGrading.egg-info}/PKG-INFO +1 -1
  6. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/LICENSE +0 -0
  7. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/MANIFEST.in +0 -0
  8. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/README.md +0 -0
  9. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/cornellInterface.py +0 -0
  10. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/dueDatesFromCSV.py +0 -0
  11. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/pandocHTMLParser.py +0 -0
  12. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/upload_MC_questions.py +0 -0
  13. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading/utils.py +0 -0
  14. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading.egg-info/SOURCES.txt +0 -0
  15. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading.egg-info/dependency_links.txt +0 -0
  16. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading.egg-info/entry_points.txt +0 -0
  17. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading.egg-info/requires.txt +0 -0
  18. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/cornellGrading.egg-info/top_level.txt +0 -0
  19. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/pyproject.toml +0 -0
  20. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/scripts/canvastex.py +0 -0
  21. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/scripts/matlabgrader.py +0 -0
  22. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/scripts/setupSelfGrading.py +0 -0
  23. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/setup.cfg +0 -0
  24. {cornellgrading-2.21.0 → cornellgrading-2.22.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cornellGrading
3
- Version: 2.21.0
3
+ Version: 2.22.0
4
4
  Summary: Routines for interacting with Cornell installations of Canvas and Qualtrics
5
5
  Home-page: https://github.com/dsavransky/grading
6
6
  Author: Dmitry Savransky
@@ -1,4 +1,4 @@
1
1
  name = "cornellGrading"
2
- __version__ = "2.21.0"
2
+ __version__ = "2.22.0"
3
3
  from .cornellGrading import cornellGrading
4
4
  from .cornellQualtrics import cornellQualtrics
@@ -2426,7 +2426,7 @@ class cornellGrading:
2426
2426
  return q
2427
2427
 
2428
2428
  def genNewQuizMultipleChoice(
2429
- self, question, options, correct_ind, points=1, position=0
2429
+ self, question, options, correct_ind, points=1, position=0, fightml=None
2430
2430
  ):
2431
2431
  """Generate a new quiz-style multiple choice question dictionary
2432
2432
 
@@ -2441,6 +2441,8 @@ class cornellGrading:
2441
2441
  Number of points for correct answer (defaults to 1).
2442
2442
  position (int):
2443
2443
  Position of question in quiz. Defaults to 0
2444
+ fightml (str, optional):
2445
+ HTML string from figure upload. Defaults to None.
2444
2446
 
2445
2447
  Returns:
2446
2448
  dict:
@@ -2462,6 +2464,10 @@ class cornellGrading:
2462
2464
  }
2463
2465
  )
2464
2466
 
2467
+ qtxt = f"<p>{convalllatex(question)}</p>"
2468
+ if fightml is not None:
2469
+ qtxt = f"{qtxt}\n<p>{fightml}</p>"
2470
+
2465
2471
  q = {
2466
2472
  "position": position,
2467
2473
  "points_possible": float(points),
@@ -2472,7 +2478,7 @@ class cornellGrading:
2472
2478
  "status": "mutable",
2473
2479
  "entry": {
2474
2480
  "title": question,
2475
- "item_body": f"<p>{convalllatex(question)}</p>",
2481
+ "item_body": qtxt,
2476
2482
  "calculator_type": "none",
2477
2483
  "interaction_data": {"choices": choices},
2478
2484
  "properties": {
@@ -2604,27 +2610,34 @@ class cornellGrading:
2604
2610
  # process figure (if any)
2605
2611
  if not (pandas.isna(row.Figure)):
2606
2612
  impath = os.path.join(imagePath, f"{row.Figure}.png")
2607
- assert os.path.exists(impath), f"Can not locate {impath}."
2608
- status, fig = figFolder.upload(impath)
2609
- assert status, f"Failed to upload {impath}."
2613
+ fightml = self.uploadFigure(impath, figFolder)
2610
2614
  else:
2611
- fig = None
2615
+ fightml = None
2612
2616
 
2613
2617
  # create and add the question depending on quiz type
2614
2618
  if isinstance(quiz, canvasapi.new_quiz.NewQuiz):
2615
2619
  q = self.genNewQuizMultipleChoice(
2616
- question, opts.astype(str), correct_ind, position=k + 1, fig=fig
2620
+ question,
2621
+ opts.astype(str),
2622
+ correct_ind,
2623
+ position=k + 1,
2624
+ fightml=fightml,
2617
2625
  )
2618
2626
 
2619
2627
  self.addNewQuizItem(quiz.id, q)
2620
2628
  else:
2621
2629
  q = self.genQuizMultipleChoice(
2622
- question, opts.astype(str), correct_ind, position=k + 1, fig=fig
2630
+ question,
2631
+ opts.astype(str),
2632
+ correct_ind,
2633
+ position=k + 1,
2634
+ fightml=fightml,
2623
2635
  )
2624
2636
  quiz.create_question(question=q)
2625
2637
 
2626
2638
  def uploadFigure(self, impath, figFolder):
2627
- """Upload a figure and generate an HTML string for embedding it
2639
+ """Upload a figure and generate an HTML string for embedding it. If filename
2640
+ already exists in the folder, use that rather than overwriting.
2628
2641
 
2629
2642
  Args:
2630
2643
  impath (str):
@@ -2637,9 +2650,22 @@ class cornellGrading:
2637
2650
  HTML string representing the figure
2638
2651
  """
2639
2652
 
2640
- assert os.path.exists(impath), f"Can not locate {impath}."
2641
- status, fig = figFolder.upload(impath)
2642
- assert status, f"Failed to upload {impath}."
2653
+ filename = os.path.split(impath)[-1]
2654
+ haveFile = False
2655
+ for file in figFolder.get_files():
2656
+ if file.filename == filename:
2657
+ haveFile = True
2658
+ fig = {
2659
+ "id": file.id,
2660
+ "uuid": file.uuid,
2661
+ "display_name": file.display_name,
2662
+ }
2663
+ break
2664
+
2665
+ if not haveFile:
2666
+ assert os.path.exists(impath), f"Can not locate {impath}."
2667
+ status, fig = figFolder.upload(impath)
2668
+ assert status, f"Failed to upload {impath}."
2643
2669
 
2644
2670
  figsrc = (
2645
2671
  f"{self.canvas._Canvas__requester.original_url}/courses/"
@@ -690,6 +690,79 @@ class cornellQualtrics:
690
690
 
691
691
  return response.json()["result"]
692
692
 
693
+ def exportUploadedFiles(self, surveyId, DataExportTags, saveDir=None):
694
+ """Download all user uploaded files associated with specific questions from one
695
+ survey
696
+
697
+ Args:
698
+ surveyId (str):
699
+ Unique id string of survey. Get either from web interface or via
700
+ getSurveyId
701
+ DataExportTags (list):
702
+ Data Export Tags for all questions with uploaded files
703
+ saveDir (str, optional):
704
+ Full path to save location. If None (default) uses system tmp dir
705
+
706
+ Returns:
707
+ str:
708
+ Full path to directory where the survey results and all files are saved.
709
+ The survey results will be a CSV file with a filename that is the same
710
+ as the survey name, except with any colons replaced with underscores.
711
+ The files will be named as: ResponseId-FileId-fileName where ResponseId
712
+ and FileId match the entries in the survey results and fileName is the
713
+ original fileName of the upload.
714
+
715
+ Notes:
716
+ https://api.qualtrics.com/1071635f5a615-retrieve-a-user-uploaded-file
717
+
718
+ """
719
+
720
+ # get survey name from ID
721
+ if surveyId not in self.surveyIds:
722
+ self.listSurveys()
723
+ assert surveyId in self.surveyIds, f"Survey ID {surveyId} not found."
724
+
725
+ surveyname = self.surveyNames[self.surveyIds == surveyId][0]
726
+
727
+ # synthesize base URL
728
+ baseUrl = (
729
+ f"https://{self.dataCenter}{self.qualtricsapi}surveys/{surveyId}/responses/"
730
+ )
731
+
732
+ # export survey results and read output
733
+ tmpdir = self.exportSurvey(surveyId, saveDir=saveDir)
734
+ if ":" in surveyname:
735
+ surveyname = surveyname.replace(":", "_")
736
+ surveyfile = os.path.join(tmpdir, surveyname + ".csv")
737
+ assert os.path.isfile(surveyfile), "Survey results not where expected."
738
+ surveyres = pandas.read_csv(surveyfile, header=[0, 1, 2])
739
+
740
+ # get all response IDs
741
+ responseIds = surveyres["ResponseId"].values.flatten()
742
+
743
+ # loop through each data export tag and download the associated file for each
744
+ # response
745
+ for DataExportTag in DataExportTags:
746
+ # get all ids and filenames for current tag
747
+ fids = surveyres[f"{DataExportTag}_Id"].values.flatten()
748
+ fnames = surveyres[f"{DataExportTag}_Name"].values.flatten()
749
+
750
+ # loop through everything
751
+ for rid, fid, fname in zip(responseIds, fids, fnames):
752
+ durl = f"{baseUrl}{rid}/uploaded-files/{fid}"
753
+ requestDownload = requests.request(
754
+ "GET", durl, headers=self.headers_post, stream=True
755
+ )
756
+ assert (
757
+ requestDownload.status_code == 200
758
+ ), f"Download failed for file {fid} on response {rid}."
759
+
760
+ outname = os.path.join(tmpdir, f"{rid}-{fid}-{fname}")
761
+ with open(outname, "wb") as ff:
762
+ ff.write(requestDownload.content)
763
+
764
+ return tmpdir
765
+
693
766
  def exportSurvey(self, surveyId, fileFormat="csv", useLabels="true", saveDir=None):
694
767
  """Download and extract survey results
695
768
 
@@ -701,7 +774,7 @@ class cornellQualtrics:
701
774
  Format to download (must be csv, tsv, or spss)
702
775
  useLabels (str):
703
776
  Use choice labels ("true" or "false", defaults "true")
704
- saveDir (str):
777
+ saveDir (str, optional):
705
778
  Full path to save location. If None (default) uses system tmp dir
706
779
 
707
780
  Returns:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cornellGrading
3
- Version: 2.21.0
3
+ Version: 2.22.0
4
4
  Summary: Routines for interacting with Cornell installations of Canvas and Qualtrics
5
5
  Home-page: https://github.com/dsavransky/grading
6
6
  Author: Dmitry Savransky
File without changes