mirror of
https://github.com/Code-For-Groningen/temmies.git
synced 2025-07-02 03:44:59 +02:00
Updated docs and included getGroup(by name). Privated some attributes that aren't necessary to be public.
This commit is contained in:
@ -10,39 +10,39 @@ class Course:
|
||||
def __init__(self, url:str, name:str, session:Session, parent):
|
||||
self.url = url
|
||||
self.name = name
|
||||
self.session = session
|
||||
self.parent = parent
|
||||
self.assignments = []
|
||||
self.__courseAvailable(self.session.get(self.url))
|
||||
self.__session = session
|
||||
self.__parent = parent
|
||||
self.__request = self.__session.get(self.url)
|
||||
self.__raw = BeautifulSoup(self.__request.text, 'lxml')
|
||||
|
||||
self.__courseAvailable(self.__session.get(self.url))
|
||||
|
||||
def __str__(self):
|
||||
return f"Course {self.name} in year {self.parent.year}"
|
||||
return f"Course {self.name} in year {self.__parent.year}"
|
||||
|
||||
def __courseAvailable(self, r):
|
||||
# Check if we got an error
|
||||
# print(self.url)
|
||||
if "Something went wrong" in r.text:
|
||||
raise CourseUnavailable(message="'Something went wrong'. Course most likely not found. ")
|
||||
|
||||
@property
|
||||
def info(self):
|
||||
return {
|
||||
"name": self.name,
|
||||
"year": self.parent.year,
|
||||
"url": self.url,
|
||||
"assignments": [x.name for x in self.assignments]
|
||||
}
|
||||
|
||||
def getExerciseGroups(self):
|
||||
r = self.session.get(self.url)
|
||||
soup = BeautifulSoup(r.text, 'lxml')
|
||||
section = soup.find('div', class_="ass-children")
|
||||
def getGroups(self, full:bool=False):
|
||||
section = self.__raw.find('div', class_="ass-children")
|
||||
entries = section.find_all('a', href=True)
|
||||
return [
|
||||
ExerciseGroup(
|
||||
f"https://themis.housing.rug.nl{x['href']}",
|
||||
x,
|
||||
self.session,
|
||||
self.__session,
|
||||
self,
|
||||
full
|
||||
)
|
||||
for x in entries]
|
||||
for x in entries]
|
||||
|
||||
# BAD: Repeated code!!!!
|
||||
def getGroup(self, name:str, full:bool=False):
|
||||
group = self.__raw.find("a", text=name)
|
||||
if not group:
|
||||
raise IllegalAction(message=f"No such group found: {name}")
|
||||
|
||||
return ExerciseGroup(f"https://themis.housing.rug.nl{group['href']}", group, self.__session, self, full)
|
||||
|
@ -6,21 +6,19 @@ from time import sleep
|
||||
|
||||
|
||||
class ExerciseGroup:
|
||||
def __init__(self, url: str, soup, session, parent):
|
||||
def __init__(self, url: str, soup, session, parent, full:bool):
|
||||
self.url = url
|
||||
self.name = soup.text
|
||||
self.__raw = soup
|
||||
self.session = session
|
||||
self.parent = parent # This is unnecessary, but I'll keep it for now
|
||||
self.request = self.session.get(self.url)
|
||||
self.soup = BeautifulSoup(self.request.text, "lxml")
|
||||
self.__prev_raw = soup
|
||||
self.__session = session
|
||||
self.__request = self.__session.get(self.url)
|
||||
self.__raw = BeautifulSoup(self.__request.text, "lxml")
|
||||
self.__full = full
|
||||
|
||||
def __str__(self):
|
||||
return f"ExerciseGroup {self.name} in folder {self.parent.name}"
|
||||
|
||||
@property
|
||||
def amExercise(self):
|
||||
return "ass-submitable" in self.__raw["class"]
|
||||
return "ass-submitable" in self.__prev_raw["class"]
|
||||
|
||||
def submit(self):
|
||||
if not self.amExercise:
|
||||
@ -31,7 +29,7 @@ class ExerciseGroup:
|
||||
# Test cases
|
||||
@property
|
||||
def testCases(self):
|
||||
section = self.soup.find_all("div", class_="subsec round shade")
|
||||
section = self.__raw.find_all("div", class_="subsec round shade")
|
||||
tcs = []
|
||||
for div in section:
|
||||
res = div.find("h4", class_="info")
|
||||
@ -57,14 +55,14 @@ class ExerciseGroup:
|
||||
print(f"Downloading {tc.text}")
|
||||
# download the files
|
||||
with open(f"{path}/{tc.text}", "wb") as f:
|
||||
f.write(self.session.get(url).content)
|
||||
f.write(self.__session.get(url).content)
|
||||
|
||||
return self.testCases
|
||||
|
||||
# Files
|
||||
@property
|
||||
def files(self):
|
||||
details = self.soup.find("div", id=lambda x: x and x.startswith("details"))
|
||||
details = self.__raw.find("div", id=lambda x: x and x.startswith("details"))
|
||||
|
||||
cfg_lines = details.find_all("div", class_="cfg-line")
|
||||
|
||||
@ -88,7 +86,7 @@ class ExerciseGroup:
|
||||
print(f"Downloading file {file.text}")
|
||||
url = f"https://themis.housing.rug.nl{file['href']}"
|
||||
with open(f"{path}/{file.text}", "wb") as f:
|
||||
f.write(self.session.get(url).content)
|
||||
f.write(self.__session.get(url).content)
|
||||
return self.files
|
||||
|
||||
@property
|
||||
@ -96,35 +94,51 @@ class ExerciseGroup:
|
||||
if self.amExercise:
|
||||
return self
|
||||
|
||||
section = self.soup.find("div", class_="ass-children")
|
||||
section = self.__raw.find("div", class_="ass-children")
|
||||
try:
|
||||
submittables = section.find_all("a", class_="ass-submitable")
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
if not self.__full:
|
||||
return [(x.text,x['href']) for x in submittables]
|
||||
return [
|
||||
ExerciseGroup(
|
||||
f"https://themis.housing.rug.nl{x['href']}", x, self.session, self
|
||||
f"https://themis.housing.rug.nl{x['href']}", x, self.__session, self, True
|
||||
)
|
||||
for x in submittables
|
||||
]
|
||||
|
||||
@property
|
||||
def folders(self) -> list:
|
||||
section = self.soup.find("div", class_="ass-children")
|
||||
section = self.__raw.find("div", class_="ass-children")
|
||||
try:
|
||||
folders = section.find_all("a", class_="ass-group")
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
if not self.__full:
|
||||
return [(x.text,x['href']) for x in folders]
|
||||
|
||||
return [
|
||||
ExerciseGroup(f"https://themis.housing.rug.nl{x['href']}", x, self.session, self)
|
||||
ExerciseGroup(f"https://themis.housing.rug.nl{x['href']}", x, self.__session, self, True)
|
||||
for x in folders
|
||||
]
|
||||
|
||||
# Get by name
|
||||
def getGroup(self, name:str, full:bool=False, link:str=None):
|
||||
if link:
|
||||
return ExerciseGroup(link, self.__prev_raw, self.__session, self, full)
|
||||
|
||||
group = self.__raw.find("a", text=name)
|
||||
if not group:
|
||||
raise IllegalAction(message=f"No such group found: {name}")
|
||||
|
||||
return ExerciseGroup(f"https://themis.housing.rug.nl{group['href']}", group, self.__session, self, full)
|
||||
|
||||
# Account for judge
|
||||
def __raceCondition(self, soup, url:str, verbose:bool):
|
||||
self.session.get(url.replace("submission", "judge"))
|
||||
self.__session.get(url.replace("submission", "judge"))
|
||||
return self.__waitForResult(url, verbose, [])
|
||||
|
||||
def __parseTable(self, soup, url:str, verbose:bool, __printed:list):
|
||||
@ -145,15 +159,15 @@ class ExerciseGroup:
|
||||
|
||||
if "Passed" in status.text:
|
||||
fail_pass[int(name)] = True
|
||||
if int(name) not in __printed:
|
||||
if int(name) not in __printed and verbose == True:
|
||||
print(f"{name}: ✅")
|
||||
elif "Wrong output" in status.text:
|
||||
fail_pass[int(name)] = False
|
||||
if int(name) not in __printed:
|
||||
if int(name) not in __printed and verbose == True:
|
||||
print(f"{name}: ❌")
|
||||
elif ("No status" or "error") in status.text:
|
||||
fail_pass[int(name)] = None
|
||||
if int(name) not in __printed:
|
||||
if int(name) not in __printed and verbose == True:
|
||||
print(f"{name}:🐛")
|
||||
|
||||
__printed.append(int(name))
|
||||
@ -162,7 +176,7 @@ class ExerciseGroup:
|
||||
|
||||
def __waitForResult(self, url:str, verbose:bool, __printed:list):
|
||||
# This waits for result and returns a bundled info package
|
||||
r = self.session.get(url)
|
||||
r = self.__session.get(url)
|
||||
soup = BeautifulSoup(r.text, "lxml")
|
||||
return self.__parseTable(soup, url, verbose, __printed)
|
||||
|
||||
@ -173,7 +187,7 @@ class ExerciseGroup:
|
||||
# Find the form with submit and store the action as url
|
||||
# Store then the data-suffixes as file_types - dictionary
|
||||
|
||||
form = self.soup.find("form")
|
||||
form = self.__raw.find("form")
|
||||
if not form:
|
||||
raise IllegalAction(message="You cannot submit to this assignment.")
|
||||
|
||||
@ -204,7 +218,7 @@ class ExerciseGroup:
|
||||
|
||||
data = {"judgenow": "true" if judge else "false", "judgeLanguage": found_type}
|
||||
|
||||
resp = self.session.post(url, files=packaged_files, data=data)
|
||||
resp = self.__session.post(url, files=packaged_files, data=data)
|
||||
|
||||
# Close each file
|
||||
i = 0
|
||||
|
10
src/Year.py
10
src/Year.py
@ -10,8 +10,8 @@ class Year:
|
||||
def __init__(self, session:Session, parent, start_year:int, end_year:int):
|
||||
self.start = start_year
|
||||
self.year = end_year
|
||||
self.session = session
|
||||
self.url = self.__constructUrl()
|
||||
self.__session = session
|
||||
|
||||
# Method to set the url
|
||||
def __constructUrl(self):
|
||||
@ -20,7 +20,7 @@ class Year:
|
||||
# Method to get the courses of the year
|
||||
def allCourses(self, errors:bool=False) -> list[Course]:
|
||||
# lis in a big ul
|
||||
r = self.session.get(self.url)
|
||||
r = self.__session.get(self.url)
|
||||
soup = BeautifulSoup(r.text, 'lxml')
|
||||
lis = soup.find_all('li', class_='large')
|
||||
courses = []
|
||||
@ -31,7 +31,7 @@ class Year:
|
||||
Course(
|
||||
self.url + suffix,
|
||||
li.a.text,
|
||||
self.session,
|
||||
self.__session,
|
||||
self
|
||||
)
|
||||
)
|
||||
@ -47,9 +47,9 @@ class Year:
|
||||
|
||||
def getCourse(self, name:str) -> Course:
|
||||
# Get the course
|
||||
r = self.session.get(self.url)
|
||||
r = self.__session.get(self.url)
|
||||
soup = BeautifulSoup(r.text, 'lxml')
|
||||
# Search by name
|
||||
course = self.url + soup.find('a', text=name)['href'].replace(f"course/{self.start}-{self.year}", "")
|
||||
# Get the url and transform it into a course object
|
||||
return Course(url=course, name=name, session=self.session, parent=self)
|
||||
return Course(url=course, name=name, session=self.__session, parent=self)
|
25
src/main.py
25
src/main.py
@ -1,25 +0,0 @@
|
||||
from Themis import Themis
|
||||
def main():
|
||||
# Debug
|
||||
themis = Themis("s5230837","Bobit0Drog@231")
|
||||
year = themis.getYear(2023, 2024)
|
||||
|
||||
# pf = year.getCourse("Programming Fundamentals (for CS)")
|
||||
# pf = pf.getExerciseGroups()
|
||||
# print(pf[1].exercises[1].submit("main.c")) # <- this should throw error
|
||||
|
||||
# no_folders = year.getCourse("Computer Architecture")
|
||||
# ca_ass = no_folders.getExerciseGroups()
|
||||
ai = year.getCourse("Imperative Programming (for AI)")
|
||||
ai = ai.getExerciseGroups()
|
||||
print(ai[7].exercises[1].submit("suitcase.py", silent=False))
|
||||
|
||||
ads = year.getCourse("Algorithms and Data Structures for CS")
|
||||
ads = ads.getExerciseGroups()
|
||||
# print(ads[0].folders)
|
||||
print(ads[0].folders[5].folders[0].exercises[0].submit(["texteditor.c", "texteditor.h"], silent=False))
|
||||
# for ass in ca_ass:
|
||||
# print(ass.exercises)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,28 +0,0 @@
|
||||
def suitcase(maxVolume, sizes, values, n):
|
||||
|
||||
dp = [[0 for _ in range(maxVolume + 1)] for _ in range(n + 1)]
|
||||
|
||||
for i in range(1, n + 1):
|
||||
for j in range(1, maxVolume + 1):
|
||||
if sizes[i - 1] <= j:
|
||||
dp[i][j] = max(values[i - 1] + dp[i - 1][j - sizes[i - 1]], dp[i - 1][j])
|
||||
else:
|
||||
dp[i][j] = dp[i - 1][j]
|
||||
|
||||
return dp[n][maxVolume]
|
||||
|
||||
def main():
|
||||
n, maxVolume = map(int, input().split())
|
||||
sizes = []
|
||||
values = []
|
||||
|
||||
for _ in range(n):
|
||||
item, size, value = input().split()
|
||||
sizes.append(int(size))
|
||||
values.append(int(value))
|
||||
|
||||
maxSatisfaction = suitcase(maxVolume, sizes, values, n)
|
||||
print(maxSatisfaction)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
159
src/texteditor.c
159
src/texteditor.c
@ -1,159 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "EditOperation.h"
|
||||
#include "texteditor.h"
|
||||
#include "LibStack.h"
|
||||
|
||||
TextEditor* createTextEditor(void) {
|
||||
TextEditor *editor = malloc(sizeof(*editor));
|
||||
// Don't forget to initialize the data structure(s) here
|
||||
editor->text = malloc(10 * sizeof(*editor->text));
|
||||
editor->length = 0;
|
||||
editor->capacity = 10;
|
||||
return editor;
|
||||
}
|
||||
|
||||
// Think this is correct
|
||||
void insertCharacter(TextEditor* editor, int pos, char character) {
|
||||
// Implement the insert operation
|
||||
if (editor->length == editor->capacity) {
|
||||
editor->text = realloc(editor->text, 2 * editor->capacity * sizeof(*editor->text));
|
||||
editor->capacity *= 2;
|
||||
}
|
||||
// Shift all characters to the right
|
||||
for (int i = editor->length; i > pos; i--) {
|
||||
editor->text[i] = editor->text[i - 1];
|
||||
}
|
||||
editor->text[pos] = character;
|
||||
editor->length++;
|
||||
}
|
||||
|
||||
|
||||
// This too
|
||||
void deleteCharacter(TextEditor* editor, int pos) {
|
||||
// Implement the delete operation
|
||||
if (editor->length == 0) {
|
||||
return;
|
||||
}
|
||||
// Shift all characters to the left
|
||||
for (int i = pos; i < editor->length - 1; i++) {
|
||||
editor->text[i] = editor->text[i + 1];
|
||||
}
|
||||
editor->length--;
|
||||
}
|
||||
|
||||
// The issue lies within the mem allocation of the stacks
|
||||
void undo(TextEditor* editor, Stack* undoStack, Stack* redoStack) {
|
||||
// Optional for the bonus exercise
|
||||
if (isEmptyStack(*undoStack)) {
|
||||
return;
|
||||
}
|
||||
EditOperation operation = pop(undoStack);
|
||||
if (operation.type == INSERT) {
|
||||
deleteCharacter(editor, operation.position);
|
||||
} else {
|
||||
insertCharacter(editor, operation.position, operation.character);
|
||||
}
|
||||
push(operation, redoStack);
|
||||
}
|
||||
|
||||
void redo(TextEditor* editor, Stack* undoStack, Stack* redoStack) {
|
||||
// Optional for the bonus exercise
|
||||
if (isEmptyStack(*redoStack)) {
|
||||
return;
|
||||
}
|
||||
EditOperation operation = pop(redoStack);
|
||||
if (operation.type == INSERT) {
|
||||
insertCharacter(editor, operation.position, operation.character);
|
||||
} else {
|
||||
deleteCharacter(editor, operation.position);
|
||||
}
|
||||
push(operation, undoStack);
|
||||
}
|
||||
|
||||
void destroyTextEditor(TextEditor* editor) {
|
||||
// Free the memory allocated for the data structure(s)
|
||||
free(editor->text);
|
||||
free(editor);
|
||||
}
|
||||
|
||||
void printText(TextEditor* editor) {
|
||||
// Handle empty case
|
||||
if (editor->length == 0) {
|
||||
printf("EMPTY\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Print the text stored in the editor
|
||||
for (int i = 0; i < editor->length; i++) {
|
||||
printf("%c", editor->text[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
TextEditor* editor = createTextEditor();
|
||||
char command;
|
||||
int pos;
|
||||
char character;
|
||||
|
||||
// Initialize stacks
|
||||
Stack undoStack;
|
||||
Stack redoStack;
|
||||
undoStack = newStack(1);
|
||||
redoStack = newStack(1);
|
||||
|
||||
while(1) {
|
||||
scanf(" %c", &command);
|
||||
switch (command) {
|
||||
// Insert a character at a given position
|
||||
case 'i':
|
||||
scanf("%d %c", &pos, &character);
|
||||
insertCharacter(editor, pos, character);
|
||||
EditOperation operation = {INSERT, character, pos};
|
||||
|
||||
// Stack operations
|
||||
doubleStackSize(&undoStack);
|
||||
push(operation, &undoStack);
|
||||
break;
|
||||
// Delete a character at a given position
|
||||
case 'd':
|
||||
scanf("%d", &pos);
|
||||
character = editor->text[pos];
|
||||
deleteCharacter(editor, pos);
|
||||
EditOperation operation1 = {DELETE, character, pos};
|
||||
|
||||
doubleStackSize(&undoStack);
|
||||
push(operation1, &undoStack);
|
||||
break;
|
||||
// Undo the last operation
|
||||
case 'u':
|
||||
undo(editor, &undoStack, &redoStack);
|
||||
break;
|
||||
// Redo the last operation
|
||||
case 'r':
|
||||
redo(editor, &undoStack, &redoStack);
|
||||
break;
|
||||
// Print and quit
|
||||
case 'q':
|
||||
printText(editor);
|
||||
destroyTextEditor(editor);
|
||||
freeStack(undoStack);
|
||||
freeStack(redoStack);
|
||||
return 0;
|
||||
// Unknown command
|
||||
default:
|
||||
printf("Unknown command.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
#ifndef TEXTEDITOR_H
|
||||
#define TEXTEDITOR_H
|
||||
|
||||
#include "LibStack.h"
|
||||
|
||||
typedef struct TextEditor {
|
||||
// Store the data structure in here
|
||||
char *text;
|
||||
int length;
|
||||
int capacity;
|
||||
} TextEditor;
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user