Skip to content
Open
Show file tree
Hide file tree
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
118 changes: 118 additions & 0 deletions HW/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Library Management System

## Опис

Цей проєкт реалізує систему управління бібліотекою, використовуючи сучасні концепції Python:

Ітератори та генератори для зручного обходу колекцій книг і журналів.

Декоратори для логування та перевірки дій.

Контекстні менеджери для роботи з файлами.

Обʼєктно-орієнтоване програмування (інкапсуляція, спадкування, поліморфізм, абстрактні класи).

Валідація даних за допомогою Pydantic.

## Особливості

Класи Book і Journal – наслідуються від абстрактного класу Publication.

Pydantic-модель BookModel для валідації даних книги або журналу.

Ітератор для проходження всіх публікацій у бібліотеці.

Генератор для пошуку публікацій за конкретним автором.

Декоратори:

log_addition – логування додавання нових публікацій у файл library.log.

check_existence – перевірка наявності публікації перед її видаленням.

Контекстний менеджер LibraryFileManager – автоматичне завантаження та збереження бібліотеки у файл library.json.

Логування всіх важливих дій у файл library.log у форматі UTF-8.

## Як працює скрипт:

- Створюється обʼєкт бібліотеки.
- Створюються екземпляри книг та журналів.
- Додаються у бібліотеку.
- Виводиться список усіх публікацій.
- Можна переглянути публікації певного автора.
- Бібліотека автоматично зберігається у library.json.
- Видаляються книги/журнали за назвою (видалення спочатку у памʼяті, а потім – при збереженні у файл).
- Завантажуються дані з library.json для відновлення бібліотеки.
- Фінальний список публікацій демонструє стан бібліотеки.

## Реалізація

- Модель BookModel (Pydantic)

Валідація атрибутів: title, author, year.

- Класи Book, Journal

Наслідування від абстрактного класу Publication.

Реалізація методу info() для відображення даних.

Приватні атрибути для інкапсуляції.

- Клас Library

Зберігає список публікацій.

Ітератор для проходження всіх публікацій.

Генератор books_by_author для пошуку.

Методи add_book() і remove_book().

Поліморфізм – підтримка як книг, так і журналів.

- Декоратори

log_addition: логування додавання у library.log.

check_existence: перевірка існування перед видаленням і логування помилок.

- Контекстний менеджер LibraryFileManager

Завантажує бібліотеку з файлу при вході у контекст.

Зберігає оновлену бібліотеку при виході.

Файлова робота (JSON)

Серіалізація/десеріалізація з урахуванням типу публікації (type).

- Логування

Усі дії та помилки записуються у library.log з часовими мітками.

## Файли

main.py – головний скрипт з реалізацією.

library.json – файл для збереження бібліотеки у форматі JSON.

library.log – журнал усіх дій і помилок (створюється автоматично).

## Логування

Всі операції (додавання, видалення, помилки) записуються у library.log з часовими позначками.
Файл логів створюється і оновлюється автоматично.

## Відповідність вимогам

Валідація даних – Pydantic.

Ітератори та генератори.

Декоратори для логування і перевірок.

Контекстний менеджер для роботи з файлами.

Принципи ООП: інкапсуляція, спадкування, поліморфізм, абстрактні класи.
26 changes: 26 additions & 0 deletions HW/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[
{
"title": "Науковий журнал",
"author": "Іван Іванов",
"year": 2024,
"type": "journal"
},
{
"title": "Берестечко",
"author": "Ліна Костенко",
"year": 2010,
"type": "book"
},
{
"title": "Сад нетанучих скульптур",
"author": "Ліна Костенко",
"year": 2019,
"type": "book"
},
{
"title": "Мистецтво війни",
"author": "Сунь-Цзи",
"year": 500,
"type": "book"
}
]
60 changes: 60 additions & 0 deletions HW/library.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
2025-05-27 21:12:22,533 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-27 21:12:22,533 | INFO | [LOG] Додаємо публікацію: Науковий журнал
2025-05-27 21:12:22,533 | INFO | [LOG] Додаємо публікацію: Берестечко
2025-05-27 21:12:22,533 | INFO | [LOG] Додаємо публікацію: Сад нетанучих скульптур
2025-05-27 21:12:22,533 | INFO | [INFO] Публікацію 'Мистецтво війни' видалено з бібліотеки.
2025-05-27 21:12:22,535 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:12:22,551 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-27 21:12:22,551 | WARNING | [WARNING] Публікація 'Мистецтво війни' не знайдена в бібліотеці.
2025-05-27 21:12:22,553 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:12:22,553 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
2025-05-27 21:12:22,554 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-27 21:12:22,555 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:12:22,567 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-27 21:12:22,569 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:12:22,569 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
2025-05-27 21:14:09,315 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-27 21:14:09,315 | INFO | [LOG] Додаємо публікацію: Науковий журнал
2025-05-27 21:14:09,315 | INFO | [LOG] Додаємо публікацію: Берестечко
2025-05-27 21:14:09,316 | INFO | [LOG] Додаємо публікацію: Сад нетанучих скульптур
2025-05-27 21:14:09,316 | INFO | [INFO] Публікацію 'Мистецтво війни' видалено з бібліотеки.
2025-05-27 21:14:09,318 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:14:09,322 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-27 21:14:09,322 | WARNING | [WARNING] Публікація 'Мистецтво війни' не знайдена в бібліотеці.
2025-05-27 21:14:09,325 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:14:09,325 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
2025-05-27 21:14:09,326 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-27 21:14:09,327 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:14:09,330 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-27 21:14:09,332 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-27 21:14:09,332 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
2025-05-31 13:43:05,888 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-31 13:43:05,888 | INFO | [LOG] Додаємо публікацію: Науковий журнал
2025-05-31 13:43:05,888 | INFO | [LOG] Додаємо публікацію: Берестечко
2025-05-31 13:43:05,889 | INFO | [LOG] Додаємо публікацію: Сад нетанучих скульптур
2025-05-31 13:43:05,889 | INFO | [INFO] Публікацію 'Мистецтво війни' видалено з бібліотеки.
2025-05-31 13:43:05,891 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 13:43:05,912 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-31 13:43:05,912 | WARNING | [WARNING] Публікація 'Мистецтво війни' не знайдена в бібліотеці.
2025-05-31 13:43:05,914 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 13:43:05,915 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
2025-05-31 13:43:05,916 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-31 13:43:05,917 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 13:43:05,934 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-31 13:43:05,937 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 13:43:05,937 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
2025-05-31 14:26:57,346 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-31 14:26:57,346 | INFO | [LOG] Додаємо публікацію: Науковий журнал
2025-05-31 14:26:57,347 | INFO | [LOG] Додаємо публікацію: Берестечко
2025-05-31 14:26:57,347 | INFO | [LOG] Додаємо публікацію: Сад нетанучих скульптур
2025-05-31 14:26:57,347 | INFO | [INFO] Публікацію 'Мистецтво війни' видалено з бібліотеки.
2025-05-31 14:26:57,352 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 14:26:57,362 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-31 14:26:57,362 | WARNING | [WARNING] Публікація 'Мистецтво війни' не знайдена в бібліотеці.
2025-05-31 14:26:57,367 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 14:26:57,368 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
2025-05-31 14:26:57,370 | INFO | [LOG] Додаємо публікацію: Мистецтво війни
2025-05-31 14:26:57,376 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 14:26:57,380 | INFO | [INFO] Бібліотека завантажена з файлу 'library.json'.
2025-05-31 14:26:57,384 | INFO | [INFO] Бібліотека збережена у файл 'library.json'.
2025-05-31 14:26:57,384 | INFO | [INFO] Завершено роботу з файлом бібліотеки.
187 changes: 187 additions & 0 deletions HW/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
from pydantic import BaseModel
from abc import ABC, abstractmethod
from typing import Generator, Iterator
from contextlib import contextmanager
import logging
import json

# Налаштування логування у файл
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)s | %(message)s",
filename="library.log",
filemode="a", # додаємо до існуючого
encoding="utf-8", # для української мови
)
logger = logging.getLogger(__name__)

# Pydantic-модель
class BookModel(BaseModel):
title: str
author: str
year: int
type: str


# Абстрактний клас Publication
class Publication(ABC):
def __init__(self, model: BookModel) -> None:
self._model = model

@property
def model(self) -> BookModel:
return self._model

@abstractmethod
def info(self) -> str:
pass


# Клас Book
class Book(Publication):
def info(self) -> str:
return f"Книга: '{self.model.title}', автор: {self.model.author}, рік: {self.model.year}"


# Клас Journal
class Journal(Publication):
def info(self) -> str:
return f"Журнал: '{self.model.title}', автор: {self.model.author}, рік: {self.model.year}"


# Декоратор для логування
def log_action(func):
def wrapper(self, book: Publication):
logger.info(f"[LOG] Додаємо публікацію: {book.model.title}")
return func(self, book)
return wrapper


# Декоратор для перевірки перед видаленням
def check_book_exists(func):
def wrapper(self, title: str):
if not any(b.model.title == title for b in self._books):
logger.warning(f"[WARNING] Публікація '{title}' не знайдена в бібліотеці.")
return
return func(self, title)
return wrapper


# Клас Library
class Library:
def __init__(self):
self._books: list[Publication] = []

@log_action
def add_book(self, book: Publication) -> None:
self._books.append(book)

# Внутрішній метод без логування (для завантаження з файлу)
def _add_book_directly(self, book: Publication) -> None:
self._books.append(book)

@check_book_exists
def remove_book(self, title: str) -> None:
self._books = [b for b in self._books if b.model.title != title]
logger.info(f"[INFO] Публікацію '{title}' видалено з бібліотеки.")

def __iter__(self) -> Iterator[Publication]:
return iter(self._books)

def books_by_author(self, author: str) -> Generator[Publication, None, None]:
return (b for b in self._books if b.model.author == author)

def save_to_file(self, filename: str) -> None:
with open(filename, "w", encoding="utf-8") as f:
json.dump(
[
{**b.model.model_dump(), "type": "journal" if isinstance(b, Journal) else "book"}
for b in self._books
],
f,
ensure_ascii=False,
indent=4
)
logger.info(f"[INFO] Бібліотека збережена у файл '{filename}'.")

def load_from_file(self, filename: str) -> None:
with open(filename, "r", encoding="utf-8") as f:
data = json.load(f)
self._books.clear()
for item in data:
if item["type"] == "journal":
self._add_book_directly(Journal(BookModel(**item)))
else:
self._add_book_directly(Book(BookModel(**item)))
logger.info(f"[INFO] Бібліотека завантажена з файлу '{filename}'.")


# Контекстний менеджер
@contextmanager
def LibraryFileManager(library: Library, filename: str):
try:
library.load_from_file(filename)
yield library
finally:
library.save_to_file(filename)
logger.info(f"[INFO] Завершено роботу з файлом бібліотеки.")

# ============================================================================

# Основний блок
if __name__ == "__main__":
lib = Library()

# Створення книги та журналу
book_01 = Book(BookModel(title="Мистецтво війни", author="Сунь-Цзи", year=500, type="book"))
journal_01 = Journal(BookModel(title="Науковий журнал", author="Іван Іванов", year=2024, type="journal"))
book_02 = Book(BookModel(title="Берестечко", author="Ліна Костенко", year=2010, type="book"))
book_03 = Book(BookModel(title="Сад нетанучих скульптур", author="Ліна Костенко", year=2019, type="book"))

# Додавання
lib.add_book(book_01)
lib.add_book(journal_01)
lib.add_book(book_02)
lib.add_book(book_03)

# Видалення книги з пам'яті (RAM) без збереження у файл
lib.remove_book("Мистецтво війни")
print("\nСписок публікацій після видалення книги з пам'яті (без збереження у файл):")
for pub in lib:
print(pub.info())

# Збереження до файлу
lib.save_to_file("library.json")

# Виведення всіх публікацій
print("\nСписок всіх публікацій:")
for pub in lib:
print(pub.info())

# Виведення книг по автору
print("\nПублікації Ліна Костенко:")
for pub in lib.books_by_author("Ліна Костенко"):
print(pub.info())

# Видалення книги та збереження у файлі
with LibraryFileManager(lib, "library.json") as library:
library.remove_book("Мистецтво війни")
print("\nСписок публікацій після видалення книги:")
for pub in library:
print(pub.info())

# Виведення всіх публікацій
print("\nСписок всіх публікацій:")
for pub in lib:
print(pub.info())

# Додавання книги «Мистецтво війни» назад
book_04 = Book(BookModel(title="Мистецтво війни", author="Сунь-Цзи", year=500, type="book"))
lib.add_book(book_04)
lib.save_to_file("library.json")

# Завантаження з файлу
with LibraryFileManager(lib, "library.json") as loaded_library:
print("\nСписок публікацій після завантаження з файлу:")
for pub in loaded_library:
print(pub.info())
Loading