otter-service-stdalone 1.1.29__py3-none-any.whl → 1.1.30__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.
@@ -1 +1 @@
1
- __version__ = "1.1.29"
1
+ __version__ = "1.1.30"
@@ -12,7 +12,7 @@ from otter_service_stdalone import grade_notebooks
12
12
  from zipfile import ZipFile, ZIP_DEFLATED
13
13
  from multiprocessing import Queue
14
14
 
15
- from .util import otter_version_correct
15
+ from .util import otter_version_correct, clean_directory
16
16
 
17
17
 
18
18
  __UPLOADS__ = "/tmp/uploads"
@@ -181,7 +181,7 @@ class Download(BaseHandler):
181
181
  m = "Download: Code Not Given!"
182
182
  log.write_logs(download_code, m, f"{download_code}", "debug", log_debug)
183
183
  msg = "Please enter the download code to see your result."
184
- self.render("index.html", download_message=msg)
184
+ self.render("index.html", download_message=msg)
185
185
  elif not os.path.exists(f"{directory}"):
186
186
  m = "Download: Directory for Code Not existing"
187
187
  log.write_logs(download_code, m, f"{download_code}", "debug", log_debug)
@@ -210,7 +210,7 @@ class Download(BaseHandler):
210
210
  zipF.write(f"{file_path}", f_path, compress_type=ZIP_DEFLATED)
211
211
  read_me = os.path.join(os.path.dirname(__file__), "static_files", "README_DO_NOT_DISTRIBUTE.txt")
212
212
  zipF.write(read_me, "README_DO_NOT_DISTRIBUTE.txt", compress_type=ZIP_DEFLATED)
213
-
213
+
214
214
  download_label = f"{'-'.join(download_code.split('-')[:-5])}-results.zip"
215
215
  self.set_header('Content-Type', 'application/octet-stream')
216
216
  self.set_header("Content-Description", "File Transfer")
@@ -272,7 +272,7 @@ class Upload(BaseHandler):
272
272
  if not os.path.exists(__UPLOADS__):
273
273
  os.mkdir(__UPLOADS__)
274
274
  auto_p = f"{__UPLOADS__}/{autograder_name}"
275
-
275
+
276
276
  notebooks_path = f"{__UPLOADS__}/{notebooks_name}"
277
277
  m = "Step 2a: Uploaded File Names Determined"
278
278
  log.write_logs(results_path, m, f"notebooks path: {notebooks_path}", "debug", log_debug)
@@ -302,6 +302,9 @@ class Upload(BaseHandler):
302
302
  try:
303
303
  session_queues[user_id][results_path] = Queue()
304
304
  session_messages[user_id][results_path] = []
305
+
306
+ # remove special characters from notebooks and remove hidden folders
307
+ clean_directory(notebooks_path)
305
308
  await g.grade(auto_p, notebooks_path, autograder_orig_name, results_path, session_queues[user_id].get(results_path))
306
309
  except Exception as e:
307
310
  log.write_logs(results_path, "Grading Problem", str(e), "error", log_error)
@@ -346,16 +349,16 @@ settings = {
346
349
  }
347
350
 
348
351
  application = tornado.web.Application([
349
- (r"/", MainHandler),
350
- (r"/login", LoginHandler),
351
- (r"/upload", Upload),
352
- (r"/download", Download),
353
- (r"/update", WebSocketHandler),
354
- (r"/remove/([a-zA-Z0-9\-]+)", RemoveProgressHandler),
355
- (r"/oauth_callback", GitHubOAuthHandler),
356
- (r"/otterhealth", HealthHandler),
357
- (r"/scripts/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(os.path.dirname(__file__), "scripts")}),
358
- ], **settings, debug=False)
352
+ (r"/", MainHandler),
353
+ (r"/login", LoginHandler),
354
+ (r"/upload", Upload),
355
+ (r"/download", Download),
356
+ (r"/update", WebSocketHandler),
357
+ (r"/remove/([a-zA-Z0-9\-]+)", RemoveProgressHandler),
358
+ (r"/oauth_callback", GitHubOAuthHandler),
359
+ (r"/otterhealth", HealthHandler),
360
+ (r"/scripts/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(os.path.dirname(__file__), "scripts")}),
361
+ ], **settings, debug=False)
359
362
 
360
363
 
361
364
  def main():
@@ -2,6 +2,7 @@ import re
2
2
  import zipfile
3
3
  from packaging import version
4
4
  import os
5
+ import shutil
5
6
 
6
7
 
7
8
  def is_version_6_or_greater(zip_ref, target_file, reg):
@@ -39,3 +40,37 @@ def otter_version_correct(autograder_path):
39
40
  otter_in_req = is_version_6_or_greater(zip_ref, req_target_file, requirements_regex)
40
41
  otter_in_env = is_version_6_or_greater(zip_ref, env_target_file, environment_regex)
41
42
  return otter_in_req or otter_in_env
43
+
44
+
45
+ def sanitize_filename(filename: str) -> str:
46
+ """
47
+ Remove periods and commas from filename except the extension dot.
48
+ """
49
+ # Split name and extension
50
+ name, ext = os.path.splitext(filename)
51
+ # Remove periods and commas from the name part
52
+ clean_name = name.replace('.', '').replace(',', '')
53
+ return f"{clean_name}{ext}"
54
+
55
+
56
+ def clean_directory(path: str):
57
+ """
58
+ Delete hidden folders like __MACOSX and sanitize all file names in the directory tree.
59
+ """
60
+ for root, dirs, files in os.walk(path, topdown=True):
61
+ # Remove hidden/system folders
62
+ for dir_name in list(dirs):
63
+ if dir_name.startswith('.') or dir_name == '__MACOSX':
64
+ dir_path = os.path.join(root, dir_name)
65
+ print(f"Deleting folder: {dir_path}")
66
+ shutil.rmtree(dir_path)
67
+ dirs.remove(dir_name) # remove from list to avoid walking it
68
+
69
+ # Sanitize file names
70
+ for file_name in files:
71
+ old_path = os.path.join(root, file_name)
72
+ new_name = sanitize_filename(file_name)
73
+ new_path = os.path.join(root, new_name)
74
+ if old_path != new_path:
75
+ print(f"Renaming {old_path} -> {new_path}")
76
+ os.rename(old_path, new_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: otter_service_stdalone
3
- Version: 1.1.29
3
+ Version: 1.1.30
4
4
  Summary: Grading Service for Instructors using Otter Grader
5
5
  Home-page: https://github.com/sean-morris/otter-service-stdalone
6
6
  Author: Sean Morris
@@ -1,12 +1,12 @@
1
- otter_service_stdalone/__init__.py,sha256=DOpsZaN1AAXZKyhDQEexHmPoqsRUDlJ3UgTYvWIk8_M,23
1
+ otter_service_stdalone/__init__.py,sha256=Mxexe530sI-N2BfQmI2sCtggHwNxuNwO94_QilBEmqM,23
2
2
  otter_service_stdalone/access_sops_keys.py,sha256=nboU5aZ84Elrm5vO0dMgpIF5LLcnecpNAwpxKvj6DvU,2129
3
- otter_service_stdalone/app.py,sha256=p9IAWakM1ol7kY1P9_clD76h-EQ0kQfheBxcCVebfYw,16244
3
+ otter_service_stdalone/app.py,sha256=9_UvXXp93hXXxTMs8AXh0wpoiKiRmObmJM4XtpznHG4,16334
4
4
  otter_service_stdalone/fs_logging.py,sha256=IKFZkc5TmpI6G3vTYFAU9jDjQ-GT5aRxk8kdZ0h0kJE,2390
5
5
  otter_service_stdalone/grade_notebooks.py,sha256=x19MK_ResW-xM3mdwEUALsdsCiX4I1OHmODUHodcIow,3817
6
6
  otter_service_stdalone/index.html,sha256=eEbFGxbV-plE5bAggGYHTv1q7yqoTN4kJbzL729uMmk,7276
7
7
  otter_service_stdalone/upload_handle.py,sha256=PbpQEyUIPKercJ9hegKwvxHBvSc9uylhIfwjvHybjs0,5061
8
8
  otter_service_stdalone/user_auth.py,sha256=L9Kfj1BsQttAteHhRn71IUY8WX9nvBy3MXVGq1yjTtE,4253
9
- otter_service_stdalone/util.py,sha256=HtPmi0vEi2v7CZft3GYfpppbkd8UOb_IMubUplpTWi8,1544
9
+ otter_service_stdalone/util.py,sha256=gyaHCPPUootX2i_wsxOo6cotkiNYKOQgoPpUlvjw8SA,2836
10
10
  otter_service_stdalone/scripts/web_socket.js,sha256=0h71SNvaD7WNQ735KvuqAPsLYvqHyxzUbLWMu-8qYds,6348
11
11
  otter_service_stdalone/secrets/gh_key.dev.yaml,sha256=ORUVDu8SDcv0OE2ThwROppeg7y8oLkJJbPTCMn0s5l0,1138
12
12
  otter_service_stdalone/secrets/gh_key.local.yaml,sha256=NtPXXyGf1iSgJ9Oa2ahvIEf_fcmflB3dwd3LWyCgxis,1138
@@ -15,8 +15,8 @@ otter_service_stdalone/secrets/gh_key.staging.yaml,sha256=cKVqj4dcwuz2LhXwMNQy_1
15
15
  otter_service_stdalone/static_files/README_DO_NOT_DISTRIBUTE.txt,sha256=eMqBa1du1u0c07fuG3Eu9DDHuixRTFEbiQwrlvAnL1Y,353
16
16
  otter_service_stdalone/static_templates/403.html,sha256=7eO3XQsEkl4nF8PEeFkLwCzGBfdZ3kkkeu_Kgpgbh0k,1440
17
17
  otter_service_stdalone/static_templates/500.html,sha256=t6DeEMp8piSWyBToHb_JpTrw3GStAHFrozlmeuXyamg,1421
18
- otter_service_stdalone-1.1.29.dist-info/METADATA,sha256=UuecZ55y7YY_Iy5MrcDCR4Ffo_1Tnvimi3ohEsc7-34,1322
19
- otter_service_stdalone-1.1.29.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
- otter_service_stdalone-1.1.29.dist-info/entry_points.txt,sha256=cx447chuIEl8ly9jEoF5-2xNhaKsWcIMDdhUMH_00qQ,75
21
- otter_service_stdalone-1.1.29.dist-info/top_level.txt,sha256=6UP22fD4OhbLt23E01v8Kvjn44vPRbyTIg_GqMYL-Ng,23
22
- otter_service_stdalone-1.1.29.dist-info/RECORD,,
18
+ otter_service_stdalone-1.1.30.dist-info/METADATA,sha256=kYu_oFnur_Gon_JXhalNkCVghk21RX0G3guohq-C2nk,1322
19
+ otter_service_stdalone-1.1.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
+ otter_service_stdalone-1.1.30.dist-info/entry_points.txt,sha256=cx447chuIEl8ly9jEoF5-2xNhaKsWcIMDdhUMH_00qQ,75
21
+ otter_service_stdalone-1.1.30.dist-info/top_level.txt,sha256=6UP22fD4OhbLt23E01v8Kvjn44vPRbyTIg_GqMYL-Ng,23
22
+ otter_service_stdalone-1.1.30.dist-info/RECORD,,