Загрузка данных
import json
import os
import classes
FILE_NAME = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data.json"
)
def user_to_dict(user):
return {
"id": user.id,
"name": user.name,
"email": user.email,
"grade": user.grade,
"points": user.points
}
def task_to_dict(task):
data = {
"id": task.id,
"title": task.title,
"priority": task.priority,
"status": task.status,
"worker_id": task.worker.id if task.worker is not None else None,
"reviewer_id": task.reviewer.id if task.reviewer is not None else None,
"returns": task._returns,
"dependency_id": (
task._be_need_by.id if task._be_need_by is not None else None
)
}
if isinstance(task, classes.FeatureTask):
data["type"] = "feature"
data["hours"] = task.hours
elif isinstance(task, classes.BugTask):
data["type"] = "bug"
data["error"] = task.error
elif isinstance(task, classes.PassiveTask):
data["type"] = "passive"
else:
raise ValueError("Неизвестный тип задачи")
return data
def save_data(users, tasks, next_id):
data = {
"next_id": next_id,
"users": [],
"tasks": []
}
for user in users:
data["users"].append(user_to_dict(user))
for task in tasks:
data["tasks"].append(task_to_dict(task))
temp_file = FILE_NAME + ".tmp"
with open(temp_file, "w", encoding="utf-8") as file:
json.dump(data, file, ensure_ascii=False, indent=4)
file.flush()
os.fsync(file.fileno())
os.replace(temp_file, FILE_NAME)
def load_data():
if not os.path.exists(FILE_NAME):
return [], [], 1
try:
with open(FILE_NAME, "r", encoding="utf-8") as file:
data = json.load(file)
if not isinstance(data, dict):
raise ValueError("Неверный формат файла")
if set(data.keys()) != {"next_id", "users", "tasks"}:
raise ValueError("Неверные ключи файла")
next_id = data["next_id"]
user_records = data["users"]
task_records = data["tasks"]
if type(next_id) is not int or next_id < 1:
raise ValueError("Неверный счётчик ID")
if not isinstance(user_records, list):
raise ValueError("Неверный список пользователей")
if not isinstance(task_records, list):
raise ValueError("Неверный список задач")
users = []
tasks = []
user_by_id = {}
task_by_id = {}
emails = set()
all_ids = set()
# Восстанавливаем пользователей
for record in user_records:
user_id = record["id"]
if type(user_id) is not int or user_id < 1:
raise ValueError("Неверный ID пользователя")
if user_id in all_ids:
raise ValueError("Повторяющийся ID")
user = classes.Member(
user_id,
record["name"],
record["email"]
)
if user.email in emails:
raise ValueError("Повторяющийся email")
points = record["points"]
grade = record["grade"]
if type(points) is not int or points < 0:
raise ValueError("Неверное количество баллов")
expected_grade = "junior"
if points >= 150:
expected_grade = "senior"
elif points >= 50:
expected_grade = "middle"
if grade != expected_grade:
raise ValueError("Уровень не соответствует баллам")
user._points = points
user._grade = grade
users.append(user)
user_by_id[user_id] = user
emails.add(user.email)
all_ids.add(user_id)
# Восстанавливаем задачи
for record in task_records:
task_id = record["id"]
task_type = record["type"]
if type(task_id) is not int or task_id < 1:
raise ValueError("Неверный ID задачи")
if task_id in all_ids:
raise ValueError("Повторяющийся ID")
if task_type == "feature":
task = classes.FeatureTask(
task_id,
record["title"],
record["priority"],
hours=record["hours"]
)
elif task_type == "bug":
task = classes.BugTask(
task_id,
record["title"],
record["priority"],
error=record["error"]
)
elif task_type == "passive":
task = classes.PassiveTask(
task_id,
record["title"],
record["priority"]
)
else:
raise ValueError("Неизвестный тип задачи")
tasks.append(task)
task_by_id[task_id] = task
all_ids.add(task_id)
if all_ids and next_id <= max(all_ids):
raise ValueError("Неверное состояние счётчика ID")
# Восстанавливаем связи и состояния
for record, task in zip(task_records, tasks):
worker_id = record["worker_id"]
reviewer_id = record["reviewer_id"]
dependency_id = record["dependency_id"]
if worker_id is not None:
task._worker = user_by_id[worker_id]
if reviewer_id is not None:
task._reviewer = user_by_id[reviewer_id]
if dependency_id is not None:
task._be_need_by = task_by_id[dependency_id]
task._status = record["status"]
task._returns = record["returns"]
valid_statuses = {
"новая",
"в работе",
"на проверке",
"готова",
"отменена"
}
# Проверяем восстановленные данные
for task in tasks:
if task.status not in valid_statuses:
raise ValueError("Неизвестный статус задачи")
if type(task._returns) is not int or task._returns < 0:
raise ValueError("Неверное количество возвратов")
if task.worker is not None and task.worker is task.reviewer:
raise ValueError("Исполнитель совпадает с проверяющим")
visited = set()
current = task
while current is not None:
if current.id in visited:
raise ValueError("Обнаружен цикл зависимостей")
visited.add(current.id)
current = current._be_need_by
# Проверяем лимиты активных задач
for user in users:
active_count = 0
for task in tasks:
if task.worker is user and task.status in (
"в работе",
"на проверке"
):
active_count += 1
limits = {
"junior": 1,
"middle": 2,
"senior": 3
}
if active_count > limits[user.grade]:
raise ValueError("Превышен лимит нагрузки")
return users, tasks, next_id
except (
OSError,
ValueError,
TypeError,
KeyError,
AttributeError,
json.JSONDecodeError
) as error:
raise ValueError(
f"Ошибка загрузки данных: {error}"
) from error