mirror of
https://github.com/JonasunderscoreJones/epr_grader.git
synced 2025-10-24 08:59:17 +02:00
Writing the deduction automatically in the grading tables
This commit is contained in:
parent
ce6d67a83b
commit
e9c9c6ae49
5 changed files with 161 additions and 98 deletions
|
|
@ -8,7 +8,7 @@ Ein Tool, um die Bewertung von EPR-Abgaben (und auch GPR-Abgaben) zu beschleunig
|
|||
Author-Variable) im selben Verzeichnis ab.
|
||||
2. Wenn ihr den automatischen Style-Check benutzen wollt, installiert `pylint`, `pycodestyle`
|
||||
und `astroid` via `pip`:
|
||||
`pip install pylint==2.15.0 pycodestyle==2.8.0 astroid==2.13.5`
|
||||
`pip install pylint==2.15.0 pycodestyle==2.8.0 astroid==2.13.5 openpyxl pandas`
|
||||
|
||||
## Zu Beginn
|
||||
|
||||
|
|
@ -28,12 +28,13 @@ blatt0
|
|||
Führt jetzt den Startbefehl aus:
|
||||
```cmd
|
||||
cd ...\Tutorium\blatt0
|
||||
python eprgrader.py begin --table Bewertungstabelle_EPR_4.xlsx
|
||||
python eprgrader.py begin --table Bewertungstabelle_EPR_4.xlsx --no-stylecheck
|
||||
```
|
||||
|
||||
Zusätzliche Optionen:
|
||||
* `--no-stylecheck`: Überspringt die PEP8-Prüfung und verhindert das Anlegen der `stylecheck.txt`-Dateien für jede Abgabe.
|
||||
* `--pairs`: Überprüft die `__author__`-Variable nach dem Format für Paaraufgaben.
|
||||
* `--no-deduction`: Wenn es noch keinen Abzug für Stylefehler gibt.
|
||||
|
||||
Hierdurch werden alle zip-Archive entpackt, die Bewertungstabellen kopiert und für jeden Teilnehmer
|
||||
entsprechend umbenannt, und ggf. der Stylchecker ausgeführt.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
__author__ = "Adrian Welcker"
|
||||
|
||||
import re
|
||||
import astroid
|
||||
from pylint.checkers import BaseChecker
|
||||
|
|
|
|||
42
eprgrader.py
42
eprgrader.py
|
|
@ -8,7 +8,7 @@ Later on, collecting all the stylecheck files and grading tables into
|
|||
neat little archives for upload.
|
||||
"""
|
||||
|
||||
__author__ = "Adrian Welcker"
|
||||
__author__ = "Adrian Welcker, Lukas Horst"
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
|
|
@ -20,6 +20,8 @@ import pathlib
|
|||
import platform
|
||||
import shutil
|
||||
import sys
|
||||
from itertools import count
|
||||
|
||||
import unicodedata
|
||||
import zipfile
|
||||
import re
|
||||
|
|
@ -29,7 +31,7 @@ from datetime import datetime
|
|||
from pylint.lint import Run as RunPylint
|
||||
import pycodestyle
|
||||
|
||||
from rating_table_adjuster import get_points, update_rating
|
||||
from rating_table_adjuster import update_rating, update_style_deduction
|
||||
from violation_checker import ViolationChecker
|
||||
|
||||
PYLINT_ARGS = [
|
||||
|
|
@ -122,7 +124,7 @@ PYCODESTYLE_SELECT = [
|
|||
'E721',
|
||||
]
|
||||
tmp_storage = {}
|
||||
|
||||
violations_checkers = {}
|
||||
|
||||
@contextlib.contextmanager
|
||||
def pylint_context(stdout, workdir):
|
||||
|
|
@ -139,7 +141,7 @@ def pylint_context(stdout, workdir):
|
|||
sys.path = tmp_storage['path']
|
||||
sys.stdout = sys.__stdout__
|
||||
|
||||
def lint_files(folders, author_pairs):
|
||||
def lint_files(folders, author_pairs, deduction: bool):
|
||||
"""Run pylint and pycodestyle on all Python files anywhere within `folders'."""
|
||||
count = 0
|
||||
total = len(folders)
|
||||
|
|
@ -176,16 +178,17 @@ def lint_files(folders, author_pairs):
|
|||
style_check = remove_unnecessary_violations(lintcache.getvalue())
|
||||
else:
|
||||
style_check = ""
|
||||
violation_checker = ViolationChecker(style_check)
|
||||
violation_checker = ViolationChecker(style_check, deduction)
|
||||
violation_checker.check_violations()
|
||||
if violation_checker.count_violations(-1) == 0:
|
||||
style_check = "Alles sieht gut aus -- weiter so!\n"
|
||||
violation_string = violation_checker.list_violation()
|
||||
violations_checkers.update({folder.name.split('_')[0]: violation_checker})
|
||||
style_check += f'\n{violation_string}'
|
||||
outfile.write(style_check)
|
||||
|
||||
|
||||
def remove_unnecessary_violations(style_check):
|
||||
def remove_unnecessary_violations(style_check: str):
|
||||
"""Function to delete all lines with a violation to ignore"""
|
||||
lines = style_check.splitlines()
|
||||
|
||||
|
|
@ -237,7 +240,8 @@ def safe_extract_zip(zip_obj: zipfile.ZipFile, parent: pathlib.Path):
|
|||
fout.write(fin.read())
|
||||
|
||||
|
||||
def begin_grading(folder: pathlib.Path, ratings_file: pathlib.Path, check_style: bool, author_pairs: bool):
|
||||
def begin_grading(folder: pathlib.Path, ratings_file: pathlib.Path, check_style: bool,
|
||||
author_pairs: bool, deduction: bool):
|
||||
print("Extracting downloads...")
|
||||
downloads = list(folder.glob('**/*.zip'))
|
||||
count = 0
|
||||
|
|
@ -262,14 +266,21 @@ def begin_grading(folder: pathlib.Path, ratings_file: pathlib.Path, check_style:
|
|||
if f.is_dir()]
|
||||
if check_style:
|
||||
print("Running style check...")
|
||||
lint_files(target_folders, author_pairs)
|
||||
lint_files(target_folders, author_pairs, deduction)
|
||||
else:
|
||||
print("(Style check skipped.)")
|
||||
print("Copying ratings table...")
|
||||
count = 0
|
||||
sheet = folder.resolve().name
|
||||
for f in target_folders:
|
||||
count += 1
|
||||
target_name = "Bewertung " + sheet + " " + f.name.split('_')[0] + ratings_file.suffix
|
||||
shutil.copy(ratings_file, f / target_name)
|
||||
if len(violations_checkers) != 0:
|
||||
student_name = f.name.split('_')[0]
|
||||
file_path = os.path.join(f, target_name)
|
||||
update_style_deduction(file_path, violations_checkers[student_name], student_name)
|
||||
print(f'({count}/{len(target_folders)}) Copy in {f.name}')
|
||||
print("Done!")
|
||||
|
||||
|
||||
|
|
@ -277,7 +288,6 @@ def finalise_grading(folder: pathlib.Path):
|
|||
issues = 0
|
||||
print("Copying grades...")
|
||||
folders = list(folder.glob("**/abgaben"))
|
||||
count = 0
|
||||
for f in folders:
|
||||
overall_rating_path = ''
|
||||
for file_name in os.listdir(f.parent):
|
||||
|
|
@ -286,7 +296,10 @@ def finalise_grading(folder: pathlib.Path):
|
|||
break
|
||||
target = f.parent / 'korrekturen'
|
||||
target.mkdir()
|
||||
for handin in (x for x in f.iterdir() if x.name != '.DS_Store'):
|
||||
count = 0
|
||||
handins = [x for x in f.iterdir() if x.name != '.DS_Store']
|
||||
for handin in handins:
|
||||
count += 1
|
||||
this_target = target / handin.name
|
||||
this_target.mkdir()
|
||||
# copy the stylecheck datas
|
||||
|
|
@ -295,6 +308,7 @@ def finalise_grading(folder: pathlib.Path):
|
|||
# copy the grading datas
|
||||
glob = list(handin.glob('Bewertung *'))
|
||||
if len(glob) == 1:
|
||||
print(f'({count}/{len(handins)}) Copying from {handin.name}')
|
||||
shutil.copy(glob[0], this_target)
|
||||
# If the overall rating file is given, the points will be written in
|
||||
if len(overall_rating_path) != 0:
|
||||
|
|
@ -338,16 +352,20 @@ def main():
|
|||
help='whether or not to run style checks')
|
||||
begin_parser.add_argument('--pairs', action=argparse.BooleanOptionalAction, default=False,
|
||||
help='whether or not to validate __author__ variables for pairs')
|
||||
begin_parser.add_argument('--deduction', action=argparse.BooleanOptionalAction, default=True,
|
||||
help='whether or not to give deduction on the style')
|
||||
lint_parser = subparsers.add_parser('relint', help='re-run pylint')
|
||||
lint_parser.add_argument('--pairs', action=argparse.BooleanOptionalAction, default=False,
|
||||
help='whether or not to validate __author__ variables for pairs')
|
||||
subparsers.add_parser('finalise', help='package results for upload')
|
||||
args = parser.parse_args()
|
||||
if args.verb == 'begin':
|
||||
begin_grading(pathlib.Path(args.folder), pathlib.Path(args.table), args.stylecheck, args.pairs)
|
||||
begin_grading(pathlib.Path(args.folder), pathlib.Path(args.table), args.stylecheck,
|
||||
args.pairs, args.deduction)
|
||||
elif args.verb == 'relint':
|
||||
lint_files([f for f in itertools.chain.from_iterable(
|
||||
(group.iterdir() for group in pathlib.Path(args.folder).glob('**/abgaben'))) if f.is_dir()], args.pairs)
|
||||
(group.iterdir() for group in pathlib.Path(args.folder).glob('**/abgaben'))) if
|
||||
f.is_dir()], args.pairs, args.deduction)
|
||||
elif args.verb == 'finalise':
|
||||
finalise_grading(pathlib.Path(args.folder))
|
||||
|
||||
|
|
|
|||
|
|
@ -3,22 +3,61 @@ __author__ = 'Lukas Horst'
|
|||
import csv
|
||||
|
||||
import openpyxl
|
||||
import pandas as pd
|
||||
from openpyxl.styles import Font
|
||||
|
||||
from violation_checker import ViolationChecker
|
||||
|
||||
|
||||
def get_points(file_path):
|
||||
"""Reads the given rating table and returns the total points"""
|
||||
def get_points(file_path: str):
|
||||
"""Returns the total points"""
|
||||
data = pd.read_excel(file_path, usecols='A, C')
|
||||
total_points = 0
|
||||
for i in range(len(data)):
|
||||
if data.iat[i, 0] == 'Summe':
|
||||
break
|
||||
value = data.iat[i, 1]
|
||||
if pd.notna(value) and type(value) != str:
|
||||
total_points += value
|
||||
return max(0, total_points)
|
||||
|
||||
|
||||
def update_style_deduction(file_path: str, violation_checker: ViolationChecker, student_name: str):
|
||||
"""Function to update the deduction for style violations"""
|
||||
wb = openpyxl.load_workbook(file_path, data_only=True)
|
||||
ws = wb['Sheet1']
|
||||
rows = ws.iter_rows(min_row=20, max_row=75, min_col=1, max_col=1)
|
||||
row_of_sum = -1
|
||||
for i in rows: # searching the right row
|
||||
if i[0].value == 'Summe':
|
||||
row_of_sum = i[0].row
|
||||
break
|
||||
return ws[f'C{row_of_sum}'].value
|
||||
# Updating the name
|
||||
ws[f'A1'].value = student_name
|
||||
rows = ws.iter_rows(min_row=1, max_row=75, min_col=1, max_col=1)
|
||||
for i, row in enumerate(rows):
|
||||
cell = row[0]
|
||||
if cell.value is not None:
|
||||
# Updating the deduction for the author variable
|
||||
if '__author__' in cell.value:
|
||||
ws[f'C{i+1}'].value = -violation_checker.count_deduction(3)
|
||||
ws[f'C{i + 1}'].font = Font(color='FF0000')
|
||||
# All deductions except the author variable and docstrings
|
||||
elif 'alle o.g. Fehler' in cell.value:
|
||||
deduction = 0
|
||||
for j in range(1, 10):
|
||||
if j == 3 or j == 5:
|
||||
continue
|
||||
deduction -= violation_checker.count_deduction(j)
|
||||
ws[f'C{i+1}'].value = deduction
|
||||
ws[f'C{i+1}'].font = Font(color='FF0000')
|
||||
# Deduction for docstrings
|
||||
elif 'Abzug bei mangelden' in cell.value:
|
||||
ws[f'C{i+1}'].value = -violation_checker.count_deduction(5)
|
||||
ws[f'C{i + 1}'].font = Font(color='FF0000')
|
||||
# Updating the function for the total points
|
||||
elif 'Summe' in cell.value:
|
||||
ws[f'C{i+1}'] = f'=MAX(0, SUM(C1:C{i}))'
|
||||
break
|
||||
wb.save(file_path)
|
||||
wb.close()
|
||||
|
||||
|
||||
def read_csv_file(file_path):
|
||||
def read_csv_file(file_path: str):
|
||||
"""Function to read a csv file and returns a list with each row in a dic"""
|
||||
with open(file_path, mode='r', newline='', encoding='utf-8') as file:
|
||||
reader = csv.DictReader(file)
|
||||
|
|
@ -28,7 +67,7 @@ def read_csv_file(file_path):
|
|||
return rows
|
||||
|
||||
|
||||
def write_csv_file(file_path, data):
|
||||
def write_csv_file(file_path: str, data: list[dict[str, str]]):
|
||||
"""Function to (over)write a csv file with the given data"""
|
||||
with open(file_path, mode='w', newline='', encoding='utf-8') as file:
|
||||
fieldnames = list(data[0].keys())
|
||||
|
|
@ -37,7 +76,7 @@ def write_csv_file(file_path, data):
|
|||
writer.writerows(data)
|
||||
|
||||
|
||||
def update_rating(overall_rating_path, student_rating_path, student_name):
|
||||
def update_rating(overall_rating_path: str, student_rating_path: str, student_name: str):
|
||||
"""Function to update the points of the given student"""
|
||||
csv_data = read_csv_file(overall_rating_path)
|
||||
for row in csv_data:
|
||||
|
|
@ -46,7 +85,3 @@ def update_rating(overall_rating_path, student_rating_path, student_name):
|
|||
row['Bewertung'] = points
|
||||
write_csv_file(overall_rating_path, csv_data)
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(*read_csv_file('Test.csv'), sep='\n')
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import re
|
|||
|
||||
class ViolationChecker:
|
||||
|
||||
violation_groups = [
|
||||
__violation_groups = [
|
||||
'No deduction',
|
||||
'Global statements',
|
||||
'Imports',
|
||||
|
|
@ -18,72 +18,75 @@ class ViolationChecker:
|
|||
'Syntax'
|
||||
]
|
||||
# {violation_name: [amount of the violation, description, violation_group]}
|
||||
violations = {'W0104': [0, 'Pointless statement', 0],
|
||||
'W0201': [0, 'Attribute defined outside init', 7],
|
||||
'W0231': [0, 'Super init not called', 7],
|
||||
'W0232': [0, 'No init', 7],
|
||||
'W0301': [0, 'Unnecessary semicolon', 0],
|
||||
'W0311': [0, 'Bad indention', 6],
|
||||
'W0401': [0, 'Wildcard import', 2],
|
||||
'W0404': [0, 'Reimported', 2],
|
||||
'W0603': [0, 'Global statement', 1],
|
||||
'W0622': [0, 'Redefined builtin', 8],
|
||||
'W0702': [0, 'Bare except', 0],
|
||||
'W0705': [0, 'Duplicate except', 0],
|
||||
'W0706': [0, 'Try except raise', 0],
|
||||
__violations = None
|
||||
_style_check = ''
|
||||
__deduction = None
|
||||
|
||||
'C0102': [0, 'Blacklisted name', 4],
|
||||
'C0103': [0, 'Invalid name', 4],
|
||||
'C0112': [0, 'Empty docstring', 5],
|
||||
'C0114': [0, 'Missing module docstring', 5],
|
||||
'C0115': [0, 'Missing class docstring', 5],
|
||||
'C0116': [0, 'Missing function or method docstring', 5],
|
||||
'C0121': [0, 'Singleton-comparison', 0],
|
||||
'C0144': [0, 'Non ascii name', 4],
|
||||
'C0321': [0, 'Multiple statements', 0],
|
||||
'C0325': [0, 'Superfluous-parens', 0],
|
||||
'C0410': [0, 'Multiple imports', 2],
|
||||
'C0411': [0, 'Wrong import order', 2],
|
||||
'C0412': [0, 'Ungrouped imports', 2],
|
||||
'C0413': [0, 'Wrong import position', 2],
|
||||
'C2100': [0, 'Missing author variable', 3],
|
||||
'C2101': [0, 'Malformed author variable', 3],
|
||||
'C2102': [0, 'Incorrectly assigned author variable', 3],
|
||||
def __init__(self, style_check: str, no_deduction: bool):
|
||||
self._style_check = style_check
|
||||
self.__deduction = no_deduction
|
||||
self.__violations = {'W0104': [0, 'Pointless statement', 0],
|
||||
'W0201': [0, 'Attribute defined outside init', 7],
|
||||
'W0231': [0, 'Super init not called', 7],
|
||||
'W0232': [0, 'No init', 7],
|
||||
'W0301': [0, 'Unnecessary semicolon', 0],
|
||||
'W0311': [0, 'Bad indention', 6],
|
||||
'W0401': [0, 'Wildcard import', 2],
|
||||
'W0404': [0, 'Reimported', 2],
|
||||
'W0603': [0, 'Global statement', 1],
|
||||
'W0622': [0, 'Redefined builtin', 8],
|
||||
'W0702': [0, 'Bare except', 0],
|
||||
'W0705': [0, 'Duplicate except', 0],
|
||||
'W0706': [0, 'Try except raise', 0],
|
||||
|
||||
'E0001': [0, 'Syntax error', 9],
|
||||
'E0102': [0, 'Function redefined', 8],
|
||||
'E0211': [0, 'No Method argument', 7],
|
||||
'E201': [0, 'Whitespace after \'(\'', 6],
|
||||
'E202': [0, 'Whitespace before \')\'', 6],
|
||||
'E203': [0, 'Whitespace before \':\'', 6],
|
||||
'E211': [0, 'Whitespace before \'(\'', 6],
|
||||
'E221': [0, 'Multiple spaces before operator', 6],
|
||||
'E222': [0, 'Multiple spaces after operator', 6],
|
||||
'E223': [0, 'Tab before operator', 6],
|
||||
'E224': [0, 'Tab after operator', 6],
|
||||
'E225': [0, 'Missing whitespace around operator', 6],
|
||||
'E231': [0, 'Missing whitespace after \',\', \';\', or \':\'', 6],
|
||||
'E251': [0, 'Unexpected spaces around keyword / parameter equals', 6],
|
||||
'E261': [0, 'At least two spaces before inline comment', 6],
|
||||
'E262': [0, 'Inline comment should start with \'# \'', 6],
|
||||
'E265': [0, 'Block comment should start with \'# \'', 6],
|
||||
'E271': [0, 'Multiple space after keyword', 6],
|
||||
'E302': [0, 'Expected 2 blank lines', 6],
|
||||
'E501': [0, 'Line too long > 99', 6],
|
||||
'E502': [0, 'Backslash redundant between brackets', 0],
|
||||
'E713': [0, 'Negative membership test should use \'not in\'', 0],
|
||||
'E714': [0, 'Negative identity test should use \'is not\'', 0],
|
||||
'E721': [0, 'Use \'isinstance\' instead of comparing types', 0]}
|
||||
style_check = ''
|
||||
'C0102': [0, 'Blacklisted name', 4],
|
||||
'C0103': [0, 'Invalid name', 4],
|
||||
'C0112': [0, 'Empty docstring', 5],
|
||||
'C0114': [0, 'Missing module docstring', 5],
|
||||
'C0115': [0, 'Missing class docstring', 5],
|
||||
'C0116': [0, 'Missing function or method docstring', 5],
|
||||
'C0121': [0, 'Singleton-comparison', 0],
|
||||
'C0144': [0, 'Non ascii name', 4],
|
||||
'C0321': [0, 'Multiple statements', 0],
|
||||
'C0325': [0, 'Superfluous-parens', 0],
|
||||
'C0410': [0, 'Multiple imports', 2],
|
||||
'C0411': [0, 'Wrong import order', 2],
|
||||
'C0412': [0, 'Ungrouped imports', 2],
|
||||
'C0413': [0, 'Wrong import position', 2],
|
||||
'C2100': [0, 'Missing author variable', 3],
|
||||
'C2101': [0, 'Malformed author variable', 3],
|
||||
'C2102': [0, 'Incorrectly assigned author variable', 3],
|
||||
|
||||
def __init__(self, style_check):
|
||||
self.style_check = style_check
|
||||
'E0001': [0, 'Syntax error', 9],
|
||||
'E0102': [0, 'Function redefined', 8],
|
||||
'E0211': [0, 'No Method argument', 7],
|
||||
'E201': [0, 'Whitespace after \'(\'', 6],
|
||||
'E202': [0, 'Whitespace before \')\'', 6],
|
||||
'E203': [0, 'Whitespace before \':\'', 6],
|
||||
'E211': [0, 'Whitespace before \'(\'', 6],
|
||||
'E221': [0, 'Multiple spaces before operator', 6],
|
||||
'E222': [0, 'Multiple spaces after operator', 6],
|
||||
'E223': [0, 'Tab before operator', 6],
|
||||
'E224': [0, 'Tab after operator', 6],
|
||||
'E225': [0, 'Missing whitespace around operator', 6],
|
||||
'E231': [0, 'Missing whitespace after \',\', \';\', or \':\'', 6],
|
||||
'E251': [0, 'Unexpected spaces around keyword / parameter equals', 6],
|
||||
'E261': [0, 'At least two spaces before inline comment', 6],
|
||||
'E262': [0, 'Inline comment should start with \'# \'', 6],
|
||||
'E265': [0, 'Block comment should start with \'# \'', 6],
|
||||
'E271': [0, 'Multiple space after keyword', 6],
|
||||
'E302': [0, 'Expected 2 blank lines', 6],
|
||||
'E501': [0, 'Line too long > 99', 6],
|
||||
'E502': [0, 'Backslash redundant between brackets', 0],
|
||||
'E713': [0, 'Negative membership test should use \'not in\'', 0],
|
||||
'E714': [0, 'Negative identity test should use \'is not\'', 0],
|
||||
'E721': [0, 'Use \'isinstance\' instead of comparing types', 0]}
|
||||
|
||||
def check_violations(self):
|
||||
"""Method to search for all violations"""
|
||||
for violation_name, _ in self.violations.items():
|
||||
all_violations = re.findall(rf',*{violation_name}.*', self.style_check)
|
||||
self.violations[violation_name][0] = len(all_violations)
|
||||
for violation_name, _ in self.__violations.items():
|
||||
all_violations = re.findall(rf',*{violation_name}.*', self._style_check)
|
||||
self.__violations[violation_name][0] = len(all_violations)
|
||||
|
||||
def list_violation(self):
|
||||
"""Method to return a list with all violations and the amount of the violations sort by
|
||||
|
|
@ -92,33 +95,35 @@ class ViolationChecker:
|
|||
violation_groups_strings = []
|
||||
for i in range(10):
|
||||
violation_groups_strings.append('')
|
||||
for violation_name, value in self.violations.items():
|
||||
for violation_name, value in self.__violations.items():
|
||||
violation_groups_strings[value[2]] += f'{violation_name} ({value[1]}): {value[0]}\n'
|
||||
for i, violation_group in enumerate(self.violation_groups):
|
||||
for i, violation_group in enumerate(self.__violation_groups):
|
||||
if i == 0: continue
|
||||
violation_string += f'-----{violation_group}-----\n{violation_groups_strings[i]}'
|
||||
violation_amount = self.count_violations(i)
|
||||
violation_string += (f'\nFehler Insgesamt: {violation_amount} Abzug: '
|
||||
f'{self.count_deduction(i, violation_amount)} Punkt(e)\n\n')
|
||||
f'{self.count_deduction(i, violation_amount)} Punkte\n\n')
|
||||
if i == 9:
|
||||
violation_string += f'-----No deduction-----\n{violation_groups_strings[0]}'
|
||||
violation_string += f'\nFehler Insgesamt: {violation_amount} Abzug: 0 Punkte'
|
||||
return violation_string
|
||||
|
||||
def count_violations(self, violation_group):
|
||||
def count_violations(self, violation_group: int):
|
||||
"""Method to count all violations"""
|
||||
all_violations = 0
|
||||
if violation_group == -1:
|
||||
for _, value in self.violations.items():
|
||||
for _, value in self.__violations.items():
|
||||
all_violations += value[0]
|
||||
else:
|
||||
for _, value in self.violations.items():
|
||||
for _, value in self.__violations.items():
|
||||
if value[2] == violation_group:
|
||||
all_violations += value[0]
|
||||
return all_violations
|
||||
|
||||
def count_deduction(self, violation_group, violation_amount):
|
||||
def count_deduction(self, violation_group: int, violation_amount=-1):
|
||||
"""Method to count the deduction based on the group and amount"""
|
||||
if violation_amount == -1:
|
||||
violation_amount = self.count_violations(violation_group)
|
||||
if violation_group == 0:
|
||||
return 0
|
||||
elif violation_group == 3:
|
||||
|
|
@ -127,6 +132,8 @@ class ViolationChecker:
|
|||
return 2
|
||||
else:
|
||||
return 0
|
||||
elif not self.__deduction:
|
||||
return 0
|
||||
elif violation_group == 5:
|
||||
# Violation for docstrings with a max deduction
|
||||
return min(violation_amount*0.5, 2)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue