otter-service-stdalone 1.1.29__py3-none-any.whl → 1.1.31__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.
- otter_service_stdalone/__init__.py +1 -1
- otter_service_stdalone/app.py +14 -13
- otter_service_stdalone/grade_notebooks.py +5 -0
- otter_service_stdalone/util.py +35 -0
- {otter_service_stdalone-1.1.29.dist-info → otter_service_stdalone-1.1.31.dist-info}/METADATA +1 -1
- {otter_service_stdalone-1.1.29.dist-info → otter_service_stdalone-1.1.31.dist-info}/RECORD +9 -9
- {otter_service_stdalone-1.1.29.dist-info → otter_service_stdalone-1.1.31.dist-info}/WHEEL +0 -0
- {otter_service_stdalone-1.1.29.dist-info → otter_service_stdalone-1.1.31.dist-info}/entry_points.txt +0 -0
- {otter_service_stdalone-1.1.29.dist-info → otter_service_stdalone-1.1.31.dist-info}/top_level.txt +0 -0
@@ -1 +1 @@
|
|
1
|
-
__version__ = "1.1.
|
1
|
+
__version__ = "1.1.31"
|
otter_service_stdalone/app.py
CHANGED
@@ -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",
|
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,7 @@ class Upload(BaseHandler):
|
|
302
302
|
try:
|
303
303
|
session_queues[user_id][results_path] = Queue()
|
304
304
|
session_messages[user_id][results_path] = []
|
305
|
+
|
305
306
|
await g.grade(auto_p, notebooks_path, autograder_orig_name, results_path, session_queues[user_id].get(results_path))
|
306
307
|
except Exception as e:
|
307
308
|
log.write_logs(results_path, "Grading Problem", str(e), "error", log_error)
|
@@ -346,16 +347,16 @@ settings = {
|
|
346
347
|
}
|
347
348
|
|
348
349
|
application = tornado.web.Application([
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
350
|
+
(r"/", MainHandler),
|
351
|
+
(r"/login", LoginHandler),
|
352
|
+
(r"/upload", Upload),
|
353
|
+
(r"/download", Download),
|
354
|
+
(r"/update", WebSocketHandler),
|
355
|
+
(r"/remove/([a-zA-Z0-9\-]+)", RemoveProgressHandler),
|
356
|
+
(r"/oauth_callback", GitHubOAuthHandler),
|
357
|
+
(r"/otterhealth", HealthHandler),
|
358
|
+
(r"/scripts/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(os.path.dirname(__file__), "scripts")}),
|
359
|
+
], **settings, debug=False)
|
359
360
|
|
360
361
|
|
361
362
|
def main():
|
@@ -6,6 +6,7 @@ from otter.grade import main as grade
|
|
6
6
|
from otter import logging as loggers
|
7
7
|
from multiprocessing import Process
|
8
8
|
from tornado.ioloop import PeriodicCallback
|
9
|
+
from .util import clean_directory
|
9
10
|
|
10
11
|
log_debug = f'{os.environ.get("ENVIRONMENT")}-debug'
|
11
12
|
log_count = f'{os.environ.get("ENVIRONMENT")}-count'
|
@@ -43,6 +44,10 @@ class GradeNotebooks():
|
|
43
44
|
"""
|
44
45
|
try:
|
45
46
|
notebook_folder = uh.handle_upload(notebooks_path, results_id)
|
47
|
+
|
48
|
+
# remove special characters from notebooks and remove hidden folders
|
49
|
+
clean_directory(notebook_folder)
|
50
|
+
|
46
51
|
notebook_count = self.count_ipynb_files(notebook_folder, ".ipynb")
|
47
52
|
log.write_logs(results_id, f"{notebook_count}",
|
48
53
|
"",
|
otter_service_stdalone/util.py
CHANGED
@@ -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,12 +1,12 @@
|
|
1
|
-
otter_service_stdalone/__init__.py,sha256=
|
1
|
+
otter_service_stdalone/__init__.py,sha256=Y9b5TRHjXX4JCba9wG0eWODKTtGpLMDuVuylmN7aP8M,23
|
2
2
|
otter_service_stdalone/access_sops_keys.py,sha256=nboU5aZ84Elrm5vO0dMgpIF5LLcnecpNAwpxKvj6DvU,2129
|
3
|
-
otter_service_stdalone/app.py,sha256=
|
3
|
+
otter_service_stdalone/app.py,sha256=sNHhy9PMOSXlzsx6DuJ6T69xixSvvDq9llh3_59KkC0,16176
|
4
4
|
otter_service_stdalone/fs_logging.py,sha256=IKFZkc5TmpI6G3vTYFAU9jDjQ-GT5aRxk8kdZ0h0kJE,2390
|
5
|
-
otter_service_stdalone/grade_notebooks.py,sha256=
|
5
|
+
otter_service_stdalone/grade_notebooks.py,sha256=kHlil5pGcJWC6kSEqwCIUL-RUz7ODS6p6vbUoU0QKFM,3979
|
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=
|
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.
|
19
|
-
otter_service_stdalone-1.1.
|
20
|
-
otter_service_stdalone-1.1.
|
21
|
-
otter_service_stdalone-1.1.
|
22
|
-
otter_service_stdalone-1.1.
|
18
|
+
otter_service_stdalone-1.1.31.dist-info/METADATA,sha256=NGDJ1XUgQ0Hdea_CciTv-jSgN_4f-khyXht3tO_6r58,1322
|
19
|
+
otter_service_stdalone-1.1.31.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
20
|
+
otter_service_stdalone-1.1.31.dist-info/entry_points.txt,sha256=cx447chuIEl8ly9jEoF5-2xNhaKsWcIMDdhUMH_00qQ,75
|
21
|
+
otter_service_stdalone-1.1.31.dist-info/top_level.txt,sha256=6UP22fD4OhbLt23E01v8Kvjn44vPRbyTIg_GqMYL-Ng,23
|
22
|
+
otter_service_stdalone-1.1.31.dist-info/RECORD,,
|
File without changes
|
{otter_service_stdalone-1.1.29.dist-info → otter_service_stdalone-1.1.31.dist-info}/entry_points.txt
RENAMED
File without changes
|
{otter_service_stdalone-1.1.29.dist-info → otter_service_stdalone-1.1.31.dist-info}/top_level.txt
RENAMED
File without changes
|