Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ira validation decorator #235

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 65 additions & 41 deletions api/utils/ira_calculator.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,60 @@
from typing import TypedDict
import inspect

class Discipline(TypedDict):
"""
TypedDict que define uma disciplina.

Attributes:
grade: a menção obtida pelo aluno na disciplina.
number_of_credits: a quantidade de créditos que a disciplina tem.
semester: qual o semestre em que o aluno realizou a disciplina. O valor mínimo é 1, e o máximo é 6.
semester: qual o semestre em que o aluno realizou a disciplina. O valor mínimo é 1, e o máximo é 6.
"""

grade: str
number_of_credits: int
semester: int


# Validação dos tipos da entrada
def validate(func):
caio-felipee marked this conversation as resolved.
Show resolved Hide resolved
def wrapper(self, *args, **kwargs):
members = inspect.getmembers(Discipline, lambda x: not inspect.isroutine(x))
attributes = set()

for key, value in members:
if key == "__annotations__":
for var_name, var_type in value.items():
attributes.add((var_name, var_type))

values = args[0] if len(args) else kwargs["disciplines"]
for value in values:
for attr_name, attr_type in attributes:
result = value.get(attr_name, None)

if not isinstance(result, attr_type):
raise TypeError(
f"O valor de '{attr_name}' deve ser do tipo '{attr_type.__name__}'."
)

if isinstance(result, int) and result <= 0:
raise ValueError(
f"O valor de '{attr_name}' deve ser maior que zero."
)

return func(self, *args, **kwargs)

return wrapper


class IraCalculator:
"""
Classe que calcula o valor do IRA a partir de um conjunto de disciplinas.

Atualmente, o cálculo está sendo baseado com base no
recurso do seguinte link: 'https://deg.unb.br/images/legislacao/resolucao_ceg_0001_2020.pdf'

Para uma disciplina, nos interessam as seguintes variáveis:
Para uma disciplina, nos interessam as seguintes variáveis:
E -> Equivalência da menção de disciplina (isto é, SS=5, MS=4,..., SR=0);
C -> Número de créditos daquela disciplina;
S -> Semestre em que aquela disciplina foi cursada, sendo 6 o seu valor máximo.
Expand All @@ -30,64 +64,54 @@ class IraCalculator:

def __init__(self) -> None:
self.grade_map = {
'SS': 5,
'MS': 4,
'MM': 3,
'MI': 2,
'II': 1,
'SR': 0,
"SS": 5,
"MS": 4,
"MM": 3,
"MI": 2,
"II": 1,
"SR": 0,
}

self.semester_range = {
'min': 1,
'max': 6,
"min": 1,
"max": 6,
}

def get_grade_number(self, grade: str):
return self.grade_map.get(grade.upper(), None)

@validate
def get_ira_value(self, disciplines: list[Discipline]) -> float:
"""
Obter o valor do IRA a partir de um conjunto de menções.
:param disciplines: A lista de disciplinas que um aluno pegou.
:param disciplines: A lista de disciplinas que um aluno pegou.

:returns: Um float com o valor calculado do IRA.
"""

numerator: int = 0
denominator: int = 0

# para o cálculo do IRA, o maior valor possível para semestre é 6, mesmo
# que o estudante esteja num semestre maior que esse
MAX_SEMESTER_NUMBER: int = self.semester_range['max']

for discipline in disciplines:
# Para o cálculo do IRA, o maior valor possível para semestre é 6, mesmo
# que o estudante esteja num semestre maior que esse
grade: str = discipline.get("grade")
semester: int = discipline.get("semester")
number_of_credits: int = discipline.get("number_of_credits")

## validação da entrada
try:
if discipline['number_of_credits'] <= 0:
raise ValueError("O número de créditos da disciplina é menor ou igual a 0.")
semester = min(
semester, self.semester_range["max"]
)

discipline['semester'] = min(discipline['semester'], MAX_SEMESTER_NUMBER)

if not (self.semester_range['min'] <= discipline['semester'] <= self.semester_range['max']):
raise ValueError(
f"O semestre está fora do intervalo delimitado entre {self.semester_range['min']} e {self.semester_range['max']}."
)
grade_number = self.get_grade_number(grade)
if grade_number is None:
raise ValueError(f"A menção {grade} não existe.")

if discipline['grade'].upper() not in self.grade_map.keys():
raise ValueError(f"A menção {discipline['grade']} não existe.")
## Cálculo do IRA
numerator += (
grade_number * number_of_credits * semester
)

except TypeError:
raise TypeError("O tipo de dado passado como parâmetro está incorreto.")


## cálculo do IRA
numerator += self.grade_map[discipline['grade'].upper()] * \
discipline['number_of_credits'] * \
discipline['semester']

denominator += discipline['number_of_credits'] * discipline['semester']
denominator += number_of_credits * semester

return float(numerator / denominator)



Loading