diff --git a/.gitignore b/.gitignore index 0df7b3b..b486de6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ -# Config +# Config - Testing config.py baller.py +#Doc env +.docs_env + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 2960f5a..c017808 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,14 +1,5 @@ version: 2 -build: - os: ubuntu-22.04 - tools: - python: "3.12" - -sphinx: - configuration: docs/conf.py - -python: - install: - - requirements: docs/requirements.txt \ No newline at end of file +mkdocs: + configuration: mkdocs.yml \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index d0c3cbf..0000000 --- a/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/about.md b/docs/about.md new file mode 100644 index 0000000..27fc9da --- /dev/null +++ b/docs/about.md @@ -0,0 +1,10 @@ +# This project was made with ❤️ +By [Boyan](https://confest.im) from the student organization [Code for Groningen](https://github.com/Code-For-Groningen/). + +It has **no** affiliation with the [University of Groningen](https://rug.nl). + +## Contact +Shoot me an email: boyan(plus)cfg(at)bobokara.com. + +## License +This project is licensed under the MIT License. \ No newline at end of file diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..91de2a3 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,141 @@ +# Classes +--- +## `Themis` +Creates the initial connection to Themis. + +### Usage +```python +from temmies.Themis import Themis + +themis = Themis("s-number", "password") +``` + +### Methods +#### `login()` +Logs in to Themis. Runs automatically when the class is initialized. + +#### `getYear(start, end)` +Returns an instance of a [`Year`](#year)(academic year) between `start` and `end`. + +```python +year = themis.getYear(2023, 2024) +``` + +#### `allYears()` +Returns a list of `Year` instances corresponding to all years visible to the user. + +```python +years = themis.allYears() +``` + I don't see why you would need this, but it's here. + +---- + +## `Year` + +### Usage +```python +year = themis.getYear(2023, 2024) +``` + +### Methods +#### `getCourse(courseName)` +Returns an instance of a [`Course`](#course) with the name `courseName`. + +```python +pf = year.getCourse("Programming Fundamentals (for CS)") +``` + +#### `allCourses()` +Returns a list of `Course` instances corresponding to all courses visible to the user in a given `Year`. + +```python +courses = year.allCourses() +``` + +---- + +## `Course` +### Usage +```python + +pf = year.getCourse("Programming Fundamentals (for CS)") +print(pf.info) # <- course info attribute +assignments = pf.getExerciseGroups() +``` + +### Methods +#### `getExerciseGroups()` +Returns a list of `ExerciseGroup` instances corresponding to all exercise groups visible to the user in a given `Course`. + +```python +assignments = pf.getExerciseGroups() +``` + +## `ExerciseGroup` +When this class is initialized, it will automatically fetch the exercise's info, files and test cases(it might be slow, because it indexes the entire course, which I will fix at some point). + +* Both folders and exercises are represented as `ExerciseGroup` instances. +* Folders will have the `amExercise` attribute set to `False`. +* Folders can have the `downloadFiles` method called on them. +* Exercises can have the `submit`, `downloadFiles` and `downloadTCs` method called on them. + + +### Usage +```python +pf = year.getCourse("Programming Fundamentals (for CS)") +assignments = pf.getExerciseGroups() +assignment = assignments[0] +print(assignment.amExercise) # <- Exercise or folder attribute +print(assignment.files) # <- Downloadable files attribute +print(assignment.testCases) # <- Test cases attribute + +print(assignment.folders) # <- If the group contains folders, they will be here +print(assignment.exercises) # <- If the group contains exercises, they will be here +``` + +### Example of folder traversal +Let's say we have a folder structure like this: +``` +- Course Name + - Week 1 + - Exercise 1 + - Exercise 2 + - Part 1 + - Part 2 + - Week 2 + - Exercise 1 + - Exercise 2 +``` +And we want to get to `Part 2` of `Week 1`'s `Exercise 2`. We would do this: + +```python +pf = year.getCourse("Programming Fundamentals (for CS)") +assignments = pf.getExerciseGroups() +week1 = assignments[0].folders[0] +exercise2 = week1.exercises[1] +part2 = exercise2.folders[1] +``` + + +### Methods +#### `downloadFiles(path=".")` +Downloads all files in the exercise group to a directory `path`. Defaults to the current directory. + +```python + assignment.downloadFiles() +``` + +#### `downloadTCs(path=".")` +Downloads all test cases in the exercise group to a directory `path`. Defaults to the current directory. + +```python + assignment.downloadTCs() +``` + +#### `submit(files)` +Submits the files to the exercise group. (This is not implemented yet) + +```python + assignment.submit(["file1.py", "file2.py"]) +``` diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 21611d3..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,27 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information - -project = 'temmies-docs' -copyright = '2024, Boyan K.' -author = 'Boyan K.' - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -extensions = [] - -templates_path = ['_templates'] -exclude_patterns = [] - - - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = 'sphinx_rtd_theme' -html_static_path = ['_static'] diff --git a/images/rugemmie.gif b/docs/img/rugemmie.gif similarity index 100% rename from images/rugemmie.gif rename to docs/img/rugemmie.gif diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..b49860e --- /dev/null +++ b/docs/index.md @@ -0,0 +1,14 @@ +# Temmies! +
![Temmie](img/rugemmie.gif)
+ + +## What is this? +A python library which interacts with themis. Uses bs4. I'll try to end development on a somewhat working state. + +## Intended Features +* Log in +* Bulk download of test cases and files +* Submitting files +* Somewhat easy to use API to interact with courses + +## [Quickstart](quickstart.md) \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 1e42761..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. temmies-docs documentation master file, created by - sphinx-quickstart on Tue Feb 13 20:53:28 2024. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Temmies! -======================================== -.. image:: https://static.wikia.nocookie.net/undertale/images/7/7b/Temmie_battle_idle.gif - :align: center -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - - -Contents --------- - -.. toctree:: - - Home - quickstart - install - usage - api - Themis - Year - Course - ExerciseGroup \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index 68273bc..0000000 --- a/docs/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -sphinx-rtd-theme==1.3.0 \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..017da75 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,6 @@ +site_name: Temmies +nav: + - Temmies: index.md + - API Reference: api.md + - About: about.md +theme: readthedocs \ No newline at end of file diff --git a/src/Course.py b/src/Course.py index a8f74a8..5ad5e6b 100644 --- a/src/Course.py +++ b/src/Course.py @@ -5,12 +5,6 @@ from ExerciseGroup import ExerciseGroup import re from exceptions.CourseUnavailable import CourseUnavailable -# PROBLEM: This implementation is bad due to inconsistencies in the website -# The way we can tell the difference between an assignment and an exercise is by the presence of an a with the class "ass-submitable" -# As opposed to folders which contain exercises which are marked with "ass-group" -# Therefore, we should take that into consideration and spawn the corresponding Exercise or Assignment class -# Naming becomes a bit inconsistent like that as well, as Assignments could be Exercises. Might opt to call the "assignments" "exerciseGroups" or some shit. - class Course: # Extend the Base class init def __init__(self, url:str, name:str, session:Session, parent): diff --git a/src/ExerciseGroup.py b/src/ExerciseGroup.py index 31e3e7c..40aad42 100644 --- a/src/ExerciseGroup.py +++ b/src/ExerciseGroup.py @@ -123,6 +123,4 @@ class ExerciseGroup(): session, self) for x in folders] - - def recurse(self, folder:str): - print(self.url) \ No newline at end of file + \ No newline at end of file diff --git a/src/Themis.py b/src/Themis.py index 00d338e..c7c7e25 100644 --- a/src/Themis.py +++ b/src/Themis.py @@ -44,7 +44,6 @@ class Themis: def getYear(self, start:int, end:int): - # Get the current year return Year(self.session, self, start, end) def allYears(self): diff --git a/src/Year.py b/src/Year.py index 52e2350..d89b298 100644 --- a/src/Year.py +++ b/src/Year.py @@ -18,7 +18,7 @@ class Year: return f"https://themis.housing.rug.nl/course/{self.start}-{self.year}" # Method to get the courses of the year - def getCourses(self, errors:bool=False) -> list[Course]: + def allCourses(self, errors:bool=False) -> list[Course]: # lis in a big ul r = self.session.get(self.url) soup = BeautifulSoup(r.text, 'lxml')