9 Commits

Author SHA1 Message Date
aa7b91de0d New version fix 2024-12-02 17:07:56 +01:00
5c3e884a8b Made program wait until case is done 2024-12-02 17:01:04 +01:00
c14f87aecc Removed accidental overwrite of submit method 2024-12-02 17:00:06 +01:00
6a781ad238 Fixed get_course_by_tag name logic error (#14) 2024-11-21 11:17:10 +01:00
a1104522f1 Merge branch 'main' of github:Code-For-Groningen/temmies 2024-11-21 11:14:53 +01:00
fb8b5cd454 Unignored setup 2024-11-21 11:14:49 +01:00
1367fd667f Smaller temmie 2024-11-20 20:02:29 +01:00
1516ef74be Deliberately lowered resolution of roman scale 2024-11-20 20:01:47 +01:00
c37edb59c6 Updated logo 2024-11-20 19:59:42 +01:00
9 changed files with 68 additions and 43 deletions

1
.gitignore vendored
View File

@ -3,7 +3,6 @@ config.py
tests/
pathfinding/
test.py
setup.py
#Doc env
.docs_env

View File

@ -1,5 +1,5 @@
<p align="center">
<img src="https://github.com/Code-For-Groningen/temmies/blob/v1.1.0/docs/img/rugemmie.gif" />
<img src="docs/img/temmie.png" width= 200px/>
</p>
<p align="center">
<a href="https://temmies.confest.im"><img alt="Read the Docs" src="https://img.shields.io/readthedocs/temmies"></a>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

BIN
docs/img/temmie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -1,5 +1,5 @@
# Temmies!
<center>![Temmie](img/rugemmie.gif)</center>
<center>![Temmie](img/temmie.png)</center>
## What is this?

30
setup.py Normal file
View File

@ -0,0 +1,30 @@
from setuptools import find_packages, setup
with open("README.md", "r") as f:
l_description = f.read()
setup(
name="temmies",
version="1.2.12",
packages=find_packages(),
description="A wrapper for the Themis website",
long_description=l_description,
long_description_content_type="text/markdown",
url="https://github.com/Code-For-Groningen/temmies",
author="Boyan K.",
author_email="boyan@confest.im",
license="GPLv3",
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Programming Language :: Python :: 3.9",
],
install_requires=[
"requests",
"lxml",
"beautifulsoup4",
"keyring"
],
python_requires=">=3.9",
)

View File

@ -11,13 +11,11 @@ class ExerciseGroup(Group):
super().__init__(session, path, title, parent, submitable=submitable)
self.submit_url = f"{self.base_url}/api/submit{self.path}"
self.__find_name()
def __find_name(self):
"""
Find the name of the exercise group.
"""
if self.title == "":
# Find using beautiful soup (it is the last a with class 'fill accent large')
response = self.session.get(self.base_url + self.path)
soup = BeautifulSoup(response.text, "lxml")
title_elements = soup.find_all("a", class_="fill accent large")
@ -26,26 +24,5 @@ class ExerciseGroup(Group):
else:
self.title = self.path.split("/")[-1]
def submit(self, files: list[str]) -> Submission:
"""
Submit files to this exercise.
"""
if not self.submitable:
raise ValueError(f"Cannot submit to non-submittable item '{self.title}'.")
# Prepare the files and data for submission
files_payload = {}
for idx, file_path in enumerate(files):
file_key = f"file{idx}"
with open(file_path, "rb") as f:
files_payload[file_key] = (file_path, f.read())
response = self.session.post(self.submit_url, files=files_payload)
if response.status_code != 200:
raise ConnectionError(f"Failed to submit to '{self.title}'.")
submission_data = response.json()
return Submission(self.session, submission_data)
def __str__(self):
return f"ExerciseGroup({self.title})"

View File

@ -4,6 +4,8 @@ import os
from typing import Optional, Union, Dict
from .exceptions.illegal_action import IllegalAction
from .submission import Submission
from json import loads
from time import sleep
class Group:
"""
@ -280,14 +282,22 @@ class Group:
def __parse_table(self, soup: BeautifulSoup, url: str, verbose: bool, __printed: list) -> dict:
"""
Parse the results table from the submission result page.
Wait until all queued status-icons disappear before parsing.
"""
cases = soup.find_all("tr", class_="sub-casetop")
fail_pass = {}
any_queued = False
for case in cases:
name = case.find("td", class_="sub-casename").text
name = case.find("td", class_="sub-casename").text.strip()
status = case.find("td", class_="status-icon")
if "pending" in status.get("class"):
status_classes = status.get("class", [])
if "queued" in status_classes:
any_queued = True
break
if "pending" in status_classes:
sleep(1)
return self.__wait_for_result(url, verbose, __printed)
@ -299,20 +309,31 @@ class Group:
}
found = False
for k, v in statuses.items():
if k in status.text:
for key, (symbol, value) in statuses.items():
if key.lower() in status.text.lower():
found = True
if verbose and int(name) not in __printed:
print(f"{name}: {v[0]}")
fail_pass[int(name)] = v[1]
case_number = int(name)
if verbose and case_number not in __printed:
print(f"Case {case_number}: {symbol}")
fail_pass[case_number] = value
break
if not found:
fail_pass[int(name)] = None
if verbose and int(name) not in __printed:
print(f"{name}: Unrecognized status: {status.text}")
__printed.append(int(name))
if not found:
case_number = int(name)
fail_pass[case_number] = None
if verbose and case_number not in __printed:
print(f"{case_number}: Unrecognized status: {status.text.strip()}")
__printed.append(case_number)
# Polling
# FIXME: Use ws
if any_queued:
sleep(1)
return self.__wait_for_result(url, verbose, __printed)
return fail_pass
def __str__(self):
return f"Group({self.title}, submitable={self.submitable})"

View File

@ -53,11 +53,9 @@ class Year:
soup = BeautifulSoup(response.text, "lxml")
title_element = soup.find("h1")
if not title_element:
title_elements = soup.find_all("a", class_="fill accent large")
if title_elements:
title_element = title_elements[-1]
title_elements = soup.find_all("a", class_="fill accent large")
if title_elements:
title_element = title_elements[-1]
if title_element:
course_title = title_element.get_text(strip=True)