kattis2canvas 0.1.5__tar.gz → 0.1.7__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.
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/PKG-INFO +1 -1
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/pyproject.toml +1 -1
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas/cli.py +62 -43
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas.egg-info/PKG-INFO +1 -1
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/README.md +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/setup.cfg +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas/__init__.py +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas/__main__.py +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas.egg-info/SOURCES.txt +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas.egg-info/dependency_links.txt +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas.egg-info/entry_points.txt +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas.egg-info/requires.txt +0 -0
- {kattis2canvas-0.1.5 → kattis2canvas-0.1.7}/src/kattis2canvas.egg-info/top_level.txt +0 -0
|
@@ -734,7 +734,8 @@ def kattislinks(canvas_course):
|
|
|
734
734
|
@click.option("--dryrun/--no-dryrun", default=True, help="show planned actions, do not make them happen.")
|
|
735
735
|
@click.option("--assignment-group", default="kattis", help="the canvas assignment group to use (default: kattis).")
|
|
736
736
|
@click.option("--section", help="only process submissions for students in this specific section.")
|
|
737
|
-
|
|
737
|
+
@click.option("--force-comment/--no-force-comment", default=False, help="add a comment about the best submission even if there is already a comment in canvas.")
|
|
738
|
+
def submissions2canvas(offering, canvas_course, dryrun, assignment_group, section, force_comment):
|
|
738
739
|
"""
|
|
739
740
|
mirror summary of submission from kattis into canvas as a submission comment.
|
|
740
741
|
"""
|
|
@@ -796,20 +797,22 @@ def submissions2canvas(offering, canvas_course, dryrun, assignment_group, sectio
|
|
|
796
797
|
f'duplicate submission for {kattis_user2canvas_id[canvas_submission.user_id]} in {assignment.title}')
|
|
797
798
|
submissions_by_user[canvas_id2kattis_user[canvas_submission.user_id]] = canvas_submission
|
|
798
799
|
last_comment = datetime.datetime.fromordinal(1).replace(tzinfo=datetime.timezone.utc)
|
|
800
|
+
last_comment_text = ''
|
|
799
801
|
if canvas_submission.submission_comments:
|
|
800
802
|
for comment in canvas_submission.submission_comments:
|
|
801
803
|
created_at = extract_canvas_date(comment['created_at'])
|
|
802
|
-
if created_at > last_comment:
|
|
804
|
+
if config.kattis_hostname in comment.get('comment', '') and created_at > last_comment:
|
|
803
805
|
last_comment = created_at
|
|
806
|
+
last_comment_text = comment.get('comment', '')
|
|
804
807
|
canvas_submission.last_comment = last_comment
|
|
805
|
-
|
|
808
|
+
canvas_submission.last_comment_text = last_comment_text
|
|
806
809
|
for user, best in best_submissions.items():
|
|
807
810
|
for kattis_submission in best.values():
|
|
808
811
|
if user not in submissions_by_user:
|
|
809
812
|
warn(f"i don't see a canvas user for {user}")
|
|
810
813
|
elif user not in kattis_user2canvas_id:
|
|
811
814
|
warn(f'skipping submission for unknown user {user}')
|
|
812
|
-
elif kattis_submission.date > submissions_by_user[user].last_comment:
|
|
815
|
+
elif kattis_submission.date > submissions_by_user[user].last_comment or force_comment:
|
|
813
816
|
if dryrun:
|
|
814
817
|
warn(
|
|
815
818
|
f"would update {kattis_user2canvas_id[kattis_submission.user]} on problem {kattis_submission.problem} scored {kattis_submission.score}")
|
|
@@ -825,46 +828,62 @@ def submissions2canvas(offering, canvas_course, dryrun, assignment_group, sectio
|
|
|
825
828
|
|
|
826
829
|
def get_best_submissions(offering: str, assignment_id: str) -> {str: {str: Submission}}:
|
|
827
830
|
best_submissions = collections.defaultdict(dict)
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
if not
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
831
|
+
base_url = f"https://{config.kattis_hostname}{offering}/assignments/{assignment_id}/submissions"
|
|
832
|
+
headers = None
|
|
833
|
+
page = 0
|
|
834
|
+
|
|
835
|
+
while True:
|
|
836
|
+
url = f"{base_url}?page={page}"
|
|
837
|
+
rsp = web_get(url)
|
|
838
|
+
bs = BeautifulSoup(rsp.content, "html.parser")
|
|
839
|
+
judge_table = bs.find("table", id="judge_table")
|
|
840
|
+
|
|
841
|
+
if not judge_table:
|
|
842
|
+
if page == 0:
|
|
843
|
+
info(f"no submissions yet for {assignment_id}")
|
|
844
|
+
break
|
|
845
|
+
|
|
846
|
+
if headers is None:
|
|
847
|
+
headers = [x.get_text().strip() for x in judge_table.find_all("th")]
|
|
848
|
+
|
|
849
|
+
tbody = judge_table.find("tbody")
|
|
850
|
+
rows = [r for r in tbody.find_all("tr", recursive=False) if r.get("data-submission-id")]
|
|
851
|
+
|
|
852
|
+
if not rows:
|
|
853
|
+
break
|
|
854
|
+
|
|
855
|
+
for row in rows:
|
|
856
|
+
cells = row.find_all("td", recursive=False)
|
|
857
|
+
if not cells:
|
|
858
|
+
continue
|
|
859
|
+
props = {}
|
|
860
|
+
for index, td in enumerate(cells):
|
|
861
|
+
a = td.find("a")
|
|
862
|
+
props[headers[index]] = a.get("href") if a else td.get_text().strip()
|
|
863
|
+
date = props["Date"]
|
|
864
|
+
if "-" in date:
|
|
865
|
+
date = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S").replace(tzinfo=now.tzinfo)
|
|
866
|
+
else:
|
|
867
|
+
hms = datetime.datetime.strptime(date, "%H:%M:%S")
|
|
868
|
+
date = now.replace(hour=hms.hour, minute=hms.minute, second=hms.second)
|
|
869
|
+
# it's not clear when the short date version is used. it might be used when it is less than 24 hours,
|
|
870
|
+
# in which case, just setting the time will make the date 24 hours more than it should be
|
|
871
|
+
if date > now:
|
|
872
|
+
date -= datetime.timedelta(days=1)
|
|
873
|
+
|
|
874
|
+
score = 0.0 if props["Test cases"] == "-/-" else float(Fraction(props["Test cases"])) * 100
|
|
875
|
+
submission = Submission(user=extract_last(props["User"]), problem=extract_last(props["Problem"]), date=date,
|
|
876
|
+
score=score, url=props[""])
|
|
877
|
+
if submission.problem not in best_submissions[submission.user]:
|
|
867
878
|
best_submissions[submission.user][submission.problem] = submission
|
|
879
|
+
else:
|
|
880
|
+
current_best = best_submissions[submission.user][submission.problem]
|
|
881
|
+
if current_best.score < submission.score or (
|
|
882
|
+
current_best.score == submission.score and current_best.date < submission.date):
|
|
883
|
+
best_submissions[submission.user][submission.problem] = submission
|
|
884
|
+
|
|
885
|
+
page += 1
|
|
886
|
+
|
|
868
887
|
return best_submissions
|
|
869
888
|
|
|
870
889
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|