Coverage for e2xgrader/exchange/release_feedback.py: 20%

54 statements  

« prev     ^ index     » next       coverage.py v7.4.2, created at 2024-03-14 13:22 +0100

1import glob 

2import os 

3import re 

4import shutil 

5from stat import ( 

6 S_IRGRP, 

7 S_IROTH, 

8 S_IRUSR, 

9 S_ISGID, 

10 S_IWGRP, 

11 S_IWOTH, 

12 S_IWUSR, 

13 S_IXGRP, 

14 S_IXOTH, 

15 S_IXUSR, 

16) 

17 

18from nbgrader.exchange.default import ExchangeReleaseFeedback 

19from nbgrader.utils import make_unique_key, notebook_hash 

20 

21from .exchange import E2xExchange 

22 

23 

24class E2xExchangeReleaseFeedback(E2xExchange, ExchangeReleaseFeedback): 

25 def init_dest(self): 

26 """ 

27 Create exchange feedback destination 

28 """ 

29 

30 if self.coursedir.course_id == "": 

31 self.fail("No course id specified. Re-run with --course flag.") 

32 

33 self.course_path = os.path.join(self.root, self.coursedir.course_id) 

34 self.dest_path = os.path.join(self.course_path, self.feedback_directory) 

35 

36 if self.personalized_feedback: 

37 # u+rwx, g+wx, o+wx 

38 self.ensure_directory( 

39 self.dest_path, 

40 ( 

41 S_IRUSR 

42 | S_IWUSR 

43 | S_IXUSR 

44 | S_IWGRP 

45 | S_IXGRP 

46 | S_IWOTH 

47 | S_IXOTH 

48 | ( 

49 (S_IRGRP | S_IWGRP | S_ISGID) 

50 if self.coursedir.groupshared 

51 else 0 

52 ) 

53 ), 

54 ) 

55 else: 

56 # 0755 

57 self.ensure_directory( 

58 self.dest_path, 

59 ( 

60 S_IRUSR 

61 | S_IWUSR 

62 | S_IXUSR 

63 | S_IXGRP 

64 | S_IXOTH 

65 | ( 

66 (S_IRGRP | S_IWGRP | S_ISGID) 

67 if self.coursedir.groupshared 

68 else 0 

69 ) 

70 ), 

71 ) 

72 

73 def copy_files(self): 

74 """ 

75 Overried copy_files and add personalized-feedback generation 

76 """ 

77 if self.coursedir.student_id_exclude: 

78 exclude_students = set(self.coursedir.student_id_exclude.split(",")) 

79 else: 

80 exclude_students = set() 

81 

82 html_files = glob.glob(os.path.join(self.src_path, "*.html")) 

83 for html_file in html_files: 

84 if "hashcode" in html_file: 

85 self.log.debug("Skipping hashcode info") 

86 continue 

87 regexp = re.escape(os.path.sep).join( 

88 [ 

89 self.coursedir.format_path( 

90 self.coursedir.feedback_directory, 

91 "(?P<student_id>.*)", 

92 self.coursedir.assignment_id, 

93 escape=True, 

94 ), 

95 "(?P<notebook_id>.*).html", 

96 ] 

97 ) 

98 

99 m = re.match(regexp, html_file) 

100 if m is None: 

101 msg = "Could not match '%s' with regexp '%s'" % (html_file, regexp) 

102 self.log.error(msg) 

103 continue 

104 

105 gd = m.groupdict() 

106 student_id = gd["student_id"] 

107 notebook_id = gd["notebook_id"] 

108 if student_id in exclude_students: 

109 self.log.debug("Skipping student '{}'".format(student_id)) 

110 continue 

111 

112 feedback_dir = os.path.split(html_file)[0] 

113 submission_dir = self.coursedir.format_path( 

114 self.coursedir.submitted_directory, 

115 student_id, 

116 self.coursedir.assignment_id, 

117 ) 

118 

119 if self.personalized_feedback: 

120 dest = os.path.join( 

121 self.dest_path, student_id, self.coursedir.assignment_id 

122 ) 

123 # u+rwx, g+wx, o+wx 

124 self.ensure_directory( 

125 dest, 

126 ( 

127 S_IRUSR 

128 | S_IWUSR 

129 | S_IXUSR 

130 | S_IRGRP 

131 | S_IXGRP 

132 | S_IXOTH 

133 | S_IROTH 

134 | ( 

135 (S_IRGRP | S_IWGRP | S_ISGID) 

136 if self.coursedir.groupshared 

137 else 0 

138 ) 

139 ), 

140 ) 

141 

142 dest = os.path.join(dest, notebook_id + ".html") 

143 

144 self.log.info( 

145 "Releasing feedback for student '{}' on assignment '{}/{}/{}' ".format( 

146 student_id, 

147 self.coursedir.course_id, 

148 self.coursedir.assignment_id, 

149 notebook_id, 

150 ) 

151 ) 

152 else: 

153 timestamp = open(os.path.join(feedback_dir, "timestamp.txt")).read() 

154 nbfile = os.path.join(submission_dir, "{}.ipynb".format(notebook_id)) 

155 unique_key = make_unique_key( 

156 self.coursedir.course_id, 

157 self.coursedir.assignment_id, 

158 notebook_id, 

159 student_id, 

160 timestamp, 

161 ) 

162 

163 self.log.debug("Unique key is: {}".format(unique_key)) 

164 checksum = notebook_hash(nbfile, unique_key) 

165 dest = os.path.join(self.dest_path, "{}.html".format(checksum)) 

166 

167 self.log.info( 

168 "Releasing feedback for student '{}' on assignment '{}/{}/{}' ({})".format( 

169 student_id, 

170 self.coursedir.course_id, 

171 self.coursedir.assignment_id, 

172 notebook_id, 

173 timestamp, 

174 ) 

175 ) 

176 

177 shutil.copy(html_file, dest) 

178 self.log.info("Feedback released to: {}".format(dest))