Skip to content

Commit

Permalink
Merge pull request #62 from lubaskinc0de/develop
Browse files Browse the repository at this point in the history
1.0.2
  • Loading branch information
lubaskinc0de authored Dec 5, 2024
2 parents c3ade6c + 1d0a9b0 commit 1876ca8
Show file tree
Hide file tree
Showing 28 changed files with 324 additions and 79 deletions.
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

5. Добавление оценок за уроки и расчет среднего балла по предметам в виде таблицы.

7. Отображение предстоящего домашнего задания в формате ToDo-списка ✅.
6. Отображение предстоящего домашнего задания в формате ToDo-списка ✅.

Технологический стек:

Expand Down Expand Up @@ -51,19 +51,25 @@
*(все действия ниже выполняются в виртуальном окружении)*

**Требования**:
- cpython версии от ``3.11`` до ``3.12`` (было протестировано на python ``3.11.9``)
- возможно, у вас получится собрать проект на другой версии, но это не проверялось.
- cpython версии от ``3.11`` до ``3.12`` не включиьельно (было протестировано на python ``3.11.9``)
- возможно, у вас получится собрать проект на другой версии выше чем 3.11, но это не проверялось. Ниже чем 3.11 собрать не получиться.

Чтобы собрать приложение из исходного кода, вам потребуется

1. установить проект и его зависимости
```cmd
pip install -e .
pip install -e ".[build]"
pip install -e ".[lint]"
pip install -e ".[test]"
```

2. установить pyinstaller
```
pip install pyinstaller
2. (опционально) проверить проект - может занять время.

```commandline
pytest
mypy
ruff check
```

3. собрать бинарник
Expand All @@ -72,6 +78,12 @@ pip install pyinstaller
pyinstaller student-journal.spec
```

или (если установлен make)

```
make all
```

Известные проблемы:

1. ``DLL load failed ...``
Expand Down Expand Up @@ -105,7 +117,7 @@ student_journal run gui

Некоторые замечания по поводу работы приложения:

1. Не забывайте нажать кнопку "Обновить". Например, вы можете открыть список предметов, потом добавить какой то предмет и снова открыть список предметов. Он не отобразится там сам, нужнох нажать кнопку "Обновить", также и с большинством других виджетов, изменения будут видны только после обновления, не забывайте про это. В будущем возможно внедрение авто-обновления виджетов.
1. Не забывайте нажать кнопку "Обновить". Например, вы можете открыть список предметов, потом добавить какой-то предмет и снова открыть список предметов. Он не отобразится там сам, нужнох нажать кнопку "Обновить", также и с большинством других виджетов, изменения будут видны только после обновления, не забывайте про это. В будущем возможно внедрение авто-обновления виджетов.

2. Вы можете добавить урок на воскресенье, и будет отображена неделя с ним в расписании, но самого урока там не будет. Это не баг. Просто обычно в воскресенье уроки не проводятся, и поэтому в таблице он не будет отображаться, в будущем мы пересмотрим это решение для улучшения UX.

Expand All @@ -119,6 +131,13 @@ student_journal run gui

7. Все данные приложения будут лежать по пути ваш_пользователь/student_journal

8. Запуск приложения из бинарника может быть долгим, это связано с особенностями работы pyinstaller.

9. Чтобы начать сначала, удалите все данные приложения по пути

10. После заполнения тестовыми данными, уроки заполняются на текущий месяц и год


# Структура проекта

<p align="center">
Expand Down
15 changes: 6 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ readme = 'README.md'
requires-python = '>=3.11'
dependencies = [
'adaptix==3.0.0b8',
'PyQt6==6.5.0',
'PyQt6==6.7.1',
'dishka==1.4.0',
'tomli-w==1.1.0',
'faker==33.1.0',
]

[project.optional-dependencies]
Expand All @@ -31,6 +32,9 @@ ci = [
'pytest==8.3.3',
'ruff==0.8.0',
]
build = [
'pyinstaller==6.11.1',
]

[tool.setuptools.packages.find]
where = ["src"]
Expand Down Expand Up @@ -82,15 +86,8 @@ ignore = [
'PLR0912',
'C901',
# Not applicable for now
'FIX002',
'TD003',
'TD002',
'ARG001',
'FBT002',
'PGH003',
'ERA001',
'FBT001',
'N802',
'PGH003',
# Does not work correctly
'TC002',
'TC001',
Expand Down
7 changes: 7 additions & 0 deletions resources/forms/register.ui
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QPushButton" name="insert_test_data">
<property name="text">
<string>Заполнить тестовыми данными</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
Expand Down
6 changes: 3 additions & 3 deletions src/student_journal/adapters/db/gateway/home_task_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def write_home_task(self, home_task: HomeTask) -> None:
params = home_task_to_list_retort.dump(home_task)
self.cursor.execute(query, params)

def read_home_tasks(self, is_done: bool = False) -> list[HomeTaskReadModel]:
def read_home_tasks(self, *, show_done: bool = False) -> list[HomeTaskReadModel]:
query = """
SELECT Hometask.task_id, Hometask.description, Hometask.is_done,
Lesson.lesson_id as lesson_lesson_id,
Expand All @@ -54,9 +54,9 @@ def read_home_tasks(self, is_done: bool = False) -> list[HomeTaskReadModel]:
JOIN Lesson ON Hometask.lesson_id = Lesson.lesson_id
JOIN Subject ON Lesson.subject_id = Subject.subject_id
"""
if is_done is False:
if show_done is False:
query += " WHERE is_done = ?"
res = self.cursor.execute(query, (is_done,)).fetchall()
res = self.cursor.execute(query, (show_done,)).fetchall()
else:
res = self.cursor.execute(query).fetchall()

Expand Down
1 change: 1 addition & 0 deletions src/student_journal/adapters/db/gateway/subject_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def delete_subject(self, subject_id: SubjectId) -> None:

def read_subjects(
self,
*,
sort_by_title: bool = False,
sort_by_avg_mark: bool = False,
show_empty: bool = True,
Expand Down
117 changes: 117 additions & 0 deletions src/student_journal/adapters/load_test_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import datetime
import random
from dataclasses import dataclass
from datetime import date, timedelta

from faker import Faker

from student_journal.application.hometask.create_home_task import (
CreateHomeTask,
NewHomeTask,
)
from student_journal.application.lesson.create_lesson import CreateLesson, NewLesson
from student_journal.application.student.create_student import CreateStudent, NewStudent
from student_journal.application.student.read_student import ReadStudent
from student_journal.application.subject.create_subject import CreateSubject, NewSubject
from student_journal.application.teacher import CreateTeacher, NewTeacher
from student_journal.domain.value_object.student_id import StudentId

fake = Faker(locale="ru_RU")

SUBJECTS = [
"Математика",
"Физика",
"Информатика",
"Химия",
"Физкультура",
"История",
"Обществознание",
"Биология",
"Английский язык",
"Русский язык",
]


@dataclass(slots=True, frozen=True)
class TestDataLoader:
create_student: CreateStudent
create_teacher: CreateTeacher
create_subject: CreateSubject
read_student: ReadStudent
create_lesson: CreateLesson
create_home_task: CreateHomeTask

def insert_student(self) -> StudentId:
student_name = fake.name()
student_address = fake.address()
student_age = fake.random_int(min=14, max=18)
student_id = self.create_student.execute(
NewStudent(
age=student_age,
name=student_name,
home_address=student_address,
avatar=None,
),
)
student = self.read_student.execute(student_id)
return student.student_id

def insert_data(self, student_id: StudentId) -> None:
teacher_names = [fake.name() for _ in range(10)]
teachers = []
student = self.read_student.execute(student_id)

for name in teacher_names:
teacher = self.create_teacher.execute(
NewTeacher(
full_name=name,
avatar=None,
),
)
teachers.append(teacher)

subjects = []
for teacher_id, subject in zip(teachers, SUBJECTS, strict=True):
new_subject = self.create_subject.execute(
NewSubject(
teacher_id=teacher_id,
title=subject,
),
)
subjects.append(new_subject)

da_te = date.today() # noqa: DTZ011
week_start = da_te - timedelta(days=da_te.weekday())
week_end = week_start + timedelta(days=6)
week = [
week_start + datetime.timedelta(days=x)
for x in range((week_end - week_start).days)
]

for da_te in week:
for hour in range(8, 14):
time = datetime.time(hour=hour)
lesson_subject = random.choice(subjects) # noqa: S311
at = datetime.datetime.combine(
da_te,
time,
tzinfo=student.time_zone,
)
lesson_id = self.create_lesson.execute(
NewLesson(
subject_id=lesson_subject,
at=at,
mark=random.randint(2, 5), # noqa: S311
note=fake.text(),
room=random.randint(1000, 4000), # noqa: S311
),
)

if random.random() > 0.5: # noqa: PLR2004, S311
self.create_home_task.execute(
NewHomeTask(
lesson_id=lesson_id,
description="Домашнее задание!",
is_done=random.choice([True, False]), # noqa: S311
),
)
6 changes: 5 additions & 1 deletion src/student_journal/application/common/home_task_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ class HomeTaskGateway(Protocol):
def read_home_task(self, task_id: HomeTaskId) -> HomeTask: ...

@abstractmethod
def read_home_tasks(self, is_done: bool = False) -> list[HomeTaskReadModel]: ...
def read_home_tasks(
self,
*,
show_done: bool = False,
) -> list[HomeTaskReadModel]: ...

@abstractmethod
def write_home_task(self, home_task: HomeTask) -> None: ...
Expand Down
1 change: 1 addition & 0 deletions src/student_journal/application/common/subject_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def write_subject(self, subject: Subject) -> None: ...
@abstractmethod
def read_subjects(
self,
*,
sort_by_title: bool = False,
sort_by_avg_mark: bool = False,
show_empty: bool = True,
Expand Down
4 changes: 2 additions & 2 deletions src/student_journal/application/hometask/read_home_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class ReadHomeTasks:
gateway: HomeTaskGateway
idp: IdProvider

def execute(self, is_done: bool = False) -> HomeTasksReadModel:
def execute(self, *, show_done: bool = False) -> HomeTasksReadModel:
student_id = self.idp.get_id()
home_tasks = self.gateway.read_home_tasks(is_done)
home_tasks = self.gateway.read_home_tasks(show_done=show_done)

return HomeTasksReadModel(
student_id=student_id,
Expand Down
21 changes: 21 additions & 0 deletions src/student_journal/application/student/read_current_student.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from dataclasses import dataclass

from student_journal.application.common.id_provider import IdProvider
from student_journal.application.common.student_gateway import StudentGateway
from student_journal.application.converters.student import convert_student_to_read_model
from student_journal.application.models.student import StudentReadModel


@dataclass(slots=True)
class ReadCurrentStudent:
gateway: StudentGateway
idp: IdProvider

def execute(self) -> StudentReadModel:
current_student_id = self.idp.get_id()
student = self.gateway.read_student(
current_student_id,
)

avg = self.gateway.get_overall_avg_mark()
return convert_student_to_read_model(student, avg, student.get_timezone())
9 changes: 3 additions & 6 deletions src/student_journal/application/student/read_student.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
from dataclasses import dataclass

from student_journal.application.common.id_provider import IdProvider
from student_journal.application.common.student_gateway import StudentGateway
from student_journal.application.converters.student import convert_student_to_read_model
from student_journal.application.models.student import StudentReadModel
from student_journal.domain.value_object.student_id import StudentId


@dataclass(slots=True)
class ReadStudent:
gateway: StudentGateway
idp: IdProvider

def execute(self) -> StudentReadModel:
current_student_id = self.idp.get_id()
def execute(self, student_id: StudentId) -> StudentReadModel:
student = self.gateway.read_student(
current_student_id,
student_id,
)

avg = self.gateway.get_overall_avg_mark()
return convert_student_to_read_model(student, avg, student.get_timezone())
7 changes: 4 additions & 3 deletions src/student_journal/application/subject/read_subjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ class ReadSubjects:

def execute(
self,
*,
sort_by_title: bool = False,
sort_by_avg_mark: bool = False,
show_empty: bool = True,
) -> list[SubjectReadModel]:
self.idp.ensure_authenticated()

subjects = self.gateway.read_subjects(
sort_by_title,
sort_by_avg_mark,
show_empty,
sort_by_title=sort_by_title,
sort_by_avg_mark=sort_by_avg_mark,
show_empty=show_empty,
)

return subjects
2 changes: 2 additions & 0 deletions src/student_journal/bootstrap/di/adapter_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from student_journal.adapters.error_locator import ErrorLocator, SimpleErrorLocator
from student_journal.adapters.id_provider import FileIdProvider
from student_journal.adapters.load_test_data import TestDataLoader
from student_journal.application.common.id_provider import IdProvider


Expand All @@ -15,3 +16,4 @@ class AdapterProvider(Provider):
provides=ErrorLocator,
scope=Scope.APP,
)
data_loader = provide(TestDataLoader)
Loading

0 comments on commit 1876ca8

Please sign in to comment.