assignment-codeval 0.0.4__tar.gz → 0.0.5__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.
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/PKG-INFO +1 -1
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/pyproject.toml +1 -1
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/canvas_utils.py +5 -3
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/commons.py +4 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/evaluate.py +5 -1
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/github_connect.py +17 -10
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/submissions.py +16 -9
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/PKG-INFO +1 -1
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/README.md +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/setup.cfg +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/__init__.py +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/cli.py +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/convertMD2Html.py +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/create_assignment.py +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/file_utils.py +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/SOURCES.txt +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/dependency_links.txt +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/entry_points.txt +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/requires.txt +0 -0
- {assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/top_level.txt +0 -0
{assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/canvas_utils.py
RENAMED
|
@@ -8,7 +8,7 @@ import click
|
|
|
8
8
|
from canvasapi import Canvas
|
|
9
9
|
from canvasapi.current_user import CurrentUser
|
|
10
10
|
|
|
11
|
-
from assignment_codeval.commons import error, info, errorWithException
|
|
11
|
+
from assignment_codeval.commons import error, info, errorWithException, despace
|
|
12
12
|
|
|
13
13
|
CanvasConnection = NamedTuple('CanvasConnection', [('canvas', Canvas), ('user', CurrentUser)])
|
|
14
14
|
|
|
@@ -69,6 +69,7 @@ def is_teacher(course):
|
|
|
69
69
|
|
|
70
70
|
def get_courses(canvas, name: str, is_active=True, is_finished=False):
|
|
71
71
|
''' find the courses based on partial match '''
|
|
72
|
+
name = despace(name)
|
|
72
73
|
courses = [c for c in canvas.get_courses() if is_teacher(c)]
|
|
73
74
|
now = datetime.datetime.now(datetime.timezone.utc)
|
|
74
75
|
course_list = []
|
|
@@ -79,7 +80,7 @@ def get_courses(canvas, name: str, is_active=True, is_finished=False):
|
|
|
79
80
|
continue
|
|
80
81
|
if is_finished and end < now:
|
|
81
82
|
continue
|
|
82
|
-
if name in c.name:
|
|
83
|
+
if name in despace(c.name):
|
|
83
84
|
c.start = start
|
|
84
85
|
c.end = end
|
|
85
86
|
course_list.append(c)
|
|
@@ -88,7 +89,8 @@ def get_courses(canvas, name: str, is_active=True, is_finished=False):
|
|
|
88
89
|
|
|
89
90
|
@cache
|
|
90
91
|
def get_assignment(course, assignment_name):
|
|
91
|
-
|
|
92
|
+
assignment_name = despace(assignment_name)
|
|
93
|
+
assignments = [a for a in course.get_assignments() if assignment_name.lower() in despace(a.name).lower()]
|
|
92
94
|
if len(assignments) == 0:
|
|
93
95
|
error(f'no assignments found that contain {assignment_name}. options are:')
|
|
94
96
|
for a in course.get_assignments():
|
|
@@ -532,7 +532,7 @@ def check_test():
|
|
|
532
532
|
try:
|
|
533
533
|
test_exec.communicate(timeout=timeout_val)
|
|
534
534
|
|
|
535
|
-
except
|
|
535
|
+
except subprocess.TimeoutExpired:
|
|
536
536
|
print(f"Took more than {timeout_val} seconds to run. FAIL")
|
|
537
537
|
passed = False
|
|
538
538
|
|
|
@@ -650,6 +650,10 @@ def run_evaluation(codeval_file):
|
|
|
650
650
|
"""
|
|
651
651
|
start_time_seconds = time.time()
|
|
652
652
|
|
|
653
|
+
# turn off line buffering so that outputs don't get intermixed
|
|
654
|
+
sys.stdout.reconfigure(line_buffering=True)
|
|
655
|
+
sys.stderr.reconfigure(line_buffering=True)
|
|
656
|
+
|
|
653
657
|
setup()
|
|
654
658
|
|
|
655
659
|
# Count test case total
|
{assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/github_connect.py
RENAMED
|
@@ -2,21 +2,27 @@ import os.path
|
|
|
2
2
|
import re
|
|
3
3
|
import subprocess
|
|
4
4
|
from configparser import ConfigParser
|
|
5
|
+
from time import sleep
|
|
5
6
|
|
|
6
7
|
import click
|
|
7
8
|
|
|
8
9
|
from assignment_codeval.canvas_utils import get_course, connect_to_canvas, get_assignment
|
|
9
|
-
from assignment_codeval.commons import error,
|
|
10
|
+
from assignment_codeval.commons import error, info, despace
|
|
10
11
|
|
|
11
12
|
HEX_DIGITS = "0123456789abcdefABCDEF"
|
|
12
13
|
|
|
14
|
+
|
|
13
15
|
@click.command()
|
|
14
16
|
@click.argument("course_name", metavar="COURSE")
|
|
15
17
|
@click.argument("assignment_name", metavar="ASSIGNMENT")
|
|
16
|
-
@click.option("--all-repos", is_flag=True,
|
|
18
|
+
@click.option("--all-repos", is_flag=True,
|
|
19
|
+
help="download all repositories, even if they don't have a valid commit hash")
|
|
17
20
|
@click.option("--target-dir", help="directory to download submissions to", default='./submissions', show_default=True)
|
|
18
21
|
@click.option("--github-field", help="GitHub field name in canvas profile", default="github", show_default=True)
|
|
19
|
-
|
|
22
|
+
@click.option("--clone-delay",
|
|
23
|
+
help="seconds to wait between cloning repos. github will sometimes return an error if you clone to fast.e",
|
|
24
|
+
default=1, show_default=True)
|
|
25
|
+
def github_setup_repo(course_name, assignment_name, target_dir, github_field, all_repos, clone_delay):
|
|
20
26
|
"""
|
|
21
27
|
Connect to a GitHub repository for a given course and assignment.
|
|
22
28
|
|
|
@@ -30,7 +36,7 @@ def github_setup_repo(course_name, assignment_name, target_dir, github_field, al
|
|
|
30
36
|
parser.config_file = config_file
|
|
31
37
|
course = get_course(canvas, course_name, True)
|
|
32
38
|
assignment = get_assignment(course, assignment_name)
|
|
33
|
-
submission_dir = os.path.join(target_dir, course.name, assignment.name)
|
|
39
|
+
submission_dir = os.path.join(target_dir, despace(course.name), despace(assignment.name))
|
|
34
40
|
os.makedirs(submission_dir, exist_ok=True)
|
|
35
41
|
|
|
36
42
|
gh_key = course.name.replace(":", "").replace("=", "")
|
|
@@ -53,9 +59,9 @@ def github_setup_repo(course_name, assignment_name, target_dir, github_field, al
|
|
|
53
59
|
result_path = f"{ssid_dir}/comments.txt"
|
|
54
60
|
success_path = f"{ssid_dir}/gh_success.txt"
|
|
55
61
|
content_path = f"{ssid_dir}/content.txt"
|
|
56
|
-
|
|
57
|
-
if os.path.exists(
|
|
58
|
-
info(f"skipping {ssid_dir}, repo already exists at {
|
|
62
|
+
submission_path = os.path.join(ssid_dir, "submission")
|
|
63
|
+
if os.path.exists(submission_path):
|
|
64
|
+
info(f"skipping {ssid_dir}, repo already exists at {submission_path}")
|
|
59
65
|
continue
|
|
60
66
|
with open(result_path, "w") as fd:
|
|
61
67
|
content = None
|
|
@@ -82,15 +88,16 @@ def github_setup_repo(course_name, assignment_name, target_dir, github_field, al
|
|
|
82
88
|
repo_url = f"{gh_repo_prefix}-{gh_id}.git"
|
|
83
89
|
click.echo(f"Cloning repo for {gh_id} to {ssid_dir}")
|
|
84
90
|
print(f"cloning {repo_url}", file=fd)
|
|
85
|
-
rc = subprocess.run(['git', 'clone', repo_url,
|
|
91
|
+
rc = subprocess.run(['git', 'clone', repo_url, submission_path], stdout=fd, stderr=subprocess.STDOUT)
|
|
86
92
|
if rc.returncode != 0:
|
|
87
93
|
error(f"❌ error {rc.returncode} connecting to github repo for {ssid} using {repo_url}")
|
|
88
94
|
continue
|
|
89
|
-
subprocess.run(['git', 'config', 'advice.detachedHead', 'false'], cwd=
|
|
90
|
-
rc = subprocess.run(['git', 'checkout', content], cwd=
|
|
95
|
+
subprocess.run(['git', 'config', 'advice.detachedHead', 'false'], cwd=submission_path)
|
|
96
|
+
rc = subprocess.run(['git', 'checkout', content], cwd=submission_path, stdout=fd, stderr=subprocess.STDOUT)
|
|
91
97
|
if rc.returncode != 0:
|
|
92
98
|
print(f"❌ error {rc.returncode} checking out {content}", file=fd)
|
|
93
99
|
continue
|
|
94
100
|
print(f"✅ successfully connected to {repo_url} and checked out {content}", file=fd)
|
|
95
101
|
with open(success_path, "w") as sfd:
|
|
96
102
|
print(content, file=sfd)
|
|
103
|
+
sleep(clone_delay)
|
|
@@ -12,7 +12,7 @@ import click
|
|
|
12
12
|
import requests
|
|
13
13
|
|
|
14
14
|
from assignment_codeval.canvas_utils import connect_to_canvas, get_course, get_assignment
|
|
15
|
-
from assignment_codeval.commons import debug, error, info, warn
|
|
15
|
+
from assignment_codeval.commons import debug, error, info, warn, despace
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@click.command()
|
|
@@ -82,7 +82,7 @@ def evaluate_submissions(codeval_dir, submissions_dir):
|
|
|
82
82
|
info(f"processing {dirpath}")
|
|
83
83
|
|
|
84
84
|
assignment_name = match.group(2)
|
|
85
|
-
|
|
85
|
+
submission_dir = os.path.abspath(os.path.join(dirpath, "submission"))
|
|
86
86
|
|
|
87
87
|
codeval_file = os.path.join(codeval_dir, f"{assignment_name}.codeval")
|
|
88
88
|
if not os.path.exists(codeval_file):
|
|
@@ -104,22 +104,29 @@ def evaluate_submissions(codeval_dir, submissions_dir):
|
|
|
104
104
|
if line.startswith("CD"):
|
|
105
105
|
assignment_working_dir = os.path.normpath(
|
|
106
106
|
os.path.join(assignment_working_dir, line.split()[1].strip()))
|
|
107
|
-
if not os.path.isdir(os.path.join(
|
|
107
|
+
if not os.path.isdir(os.path.join(submission_dir, assignment_working_dir)):
|
|
108
108
|
out = f"{assignment_working_dir} does not exist or is not a directory\n".encode('utf-8')
|
|
109
109
|
move_to_next_submission = True
|
|
110
110
|
break
|
|
111
111
|
if line.startswith("Z"):
|
|
112
112
|
zipfile = line.split(None, 1)[1]
|
|
113
|
-
# unzip into the
|
|
113
|
+
# unzip into the submission directory
|
|
114
114
|
with ZipFile(os.path.join(codeval_dir, zipfile)) as zf:
|
|
115
|
-
zf.
|
|
115
|
+
for f in zf.infolist():
|
|
116
|
+
dest_dir = os.path.join(submission_dir, assignment_working_dir)
|
|
117
|
+
zf.extract(f, dest_dir)
|
|
118
|
+
if not f.is_dir():
|
|
119
|
+
perms = f.external_attr >> 16
|
|
120
|
+
if perms:
|
|
121
|
+
os.chmod(os.path.join(dest_dir, f.filename), perms)
|
|
122
|
+
|
|
116
123
|
if not move_to_next_submission:
|
|
117
124
|
command = raw_command.replace("EVALUATE", "cd /submissions; assignment-codeval run-evaluation codeval.txt")
|
|
118
125
|
|
|
119
126
|
with TemporaryDirectory("cedir", dir="/var/tmp") as link_dir:
|
|
120
|
-
|
|
121
|
-
os.symlink(
|
|
122
|
-
full_assignment_working_dir = os.path.join(
|
|
127
|
+
submission_link = os.path.join(link_dir, "submissions")
|
|
128
|
+
os.symlink(submission_dir, submission_link)
|
|
129
|
+
full_assignment_working_dir = os.path.join(submission_link, assignment_working_dir)
|
|
123
130
|
shutil.copy(codeval_file, os.path.join(full_assignment_working_dir, "codeval.txt"))
|
|
124
131
|
|
|
125
132
|
command = command.replace("SUBMISSIONS", full_assignment_working_dir)
|
|
@@ -168,7 +175,7 @@ def download_submissions(course_name, assignment_name, target_dir, include_comme
|
|
|
168
175
|
|
|
169
176
|
course = get_course(canvas, course_name)
|
|
170
177
|
assignment = get_assignment(course, assignment_name)
|
|
171
|
-
submission_dir = os.path.join(target_dir, course.name, assignment.name)
|
|
178
|
+
submission_dir = os.path.join(target_dir, despace(course.name), despace(assignment.name))
|
|
172
179
|
os.makedirs(submission_dir, exist_ok=True)
|
|
173
180
|
|
|
174
181
|
for submission in assignment.get_submissions(include=["submission_comments", "user"]):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/convertMD2Html.py
RENAMED
|
File without changes
|
{assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval/create_assignment.py
RENAMED
|
File without changes
|
|
File without changes
|
{assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/requires.txt
RENAMED
|
File without changes
|
{assignment_codeval-0.0.4 → assignment_codeval-0.0.5}/src/assignment_codeval.egg-info/top_level.txt
RENAMED
|
File without changes
|