diff --git a/__pycache__/models.cpython-312.pyc b/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000..00053d7 Binary files /dev/null and b/__pycache__/models.cpython-312.pyc differ diff --git a/__pycache__/storage.cpython-312.pyc b/__pycache__/storage.cpython-312.pyc new file mode 100644 index 0000000..c68bfef Binary files /dev/null and b/__pycache__/storage.cpython-312.pyc differ diff --git a/calendar_cli.py b/calendar_cli.py new file mode 100644 index 0000000..1b5d24c --- /dev/null +++ b/calendar_cli.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +""" +Personal Calendar - CLI приложение для управления событиями +""" + +import sys +from datetime import datetime +from models import Event +from storage import load_events, add_event, remove_event, get_events_by_date + +try: + from prettytable import PrettyTable +except ImportError: + print("Ошибка: установите prettytable: pip install prettytable") + sys.exit(1) + + +def show_menu(): + """Показывает главное меню""" + print("\n" + "=" * 40) + print(" 📅 PERSONAL CALENDAR") + print("=" * 40) + print("1. Добавить событие") + print("2. Показать все события") + print("3. Показать события на дату") + print("4. Удалить событие") + print("5. Выйти") + print("=" * 40) + + +def add_event_interactive(): + """Интерактивное добавление события""" + print("\n--- Добавление события ---") + title = input("Название: ").strip() + if not title: + print("Ошибка: название не может быть пустым") + return + + date = input("Дата (ГГГГ-ММ-ДД): ").strip() + try: + datetime.strptime(date, "%Y-%m-%d") + except ValueError: + print("Ошибка: неверный формат даты") + return + + time = input("Время (ЧЧ:ММ) - необязательно: ").strip() + description = input("Описание: ").strip() + + event = Event(title, date, time, description) + add_event(event) + print(f"✅ Событие добавлено: {event}") + + +def show_all_events(): + """Показывает все события в виде таблицы""" + events = load_events() + + if not events: + print("\n📭 Нет сохранённых событий") + return + + table = PrettyTable() + table.field_names = ["№", "Дата", "Время", "Название", "Описание"] + table.align = "l" + + for i, event in enumerate(events, 1): + table.add_row([ + i, + event.date, + event.time if event.time else "-", + event.title[:30], + event.description[:40] if event.description else "-" + ]) + + print("\n" + str(table)) + + +def show_events_by_date(): + """Показывает события на конкретную дату""" + date = input("\nВведите дату (ГГГГ-ММ-ДД): ").strip() + + try: + datetime.strptime(date, "%Y-%m-%d") + except ValueError: + print("Ошибка: неверный формат даты") + return + + events = get_events_by_date(date) + + if not events: + print(f"\n📭 Нет событий на {date}") + return + + print(f"\n📅 События на {date}:") + for i, event in enumerate(events, 1): + print(f" {i}. {event}") + + +def remove_event_interactive(): + """Интерактивное удаление события""" + show_all_events() + events = load_events() + + if not events: + return + + try: + index = int(input("\nВведите номер события для удаления: ")) - 1 + if remove_event(index): + print("✅ Событие удалено") + else: + print("❌ Неверный номер") + except ValueError: + print("Ошибка: введите число") + + +def main(): + """Основная функция""" + print("Добро пожаловать в Personal Calendar!") + + while True: + show_menu() + choice = input("\nВыберите действие (1-5): ").strip() + + if choice == "1": + add_event_interactive() + elif choice == "2": + show_all_events() + elif choice == "3": + show_events_by_date() + elif choice == "4": + remove_event_interactive() + elif choice == "5": + print("\n👋 До свидания!") + break + else: + print("❌ Неверный выбор. Попробуйте снова.") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/calendar_data.json b/calendar_data.json new file mode 100644 index 0000000..027ec65 --- /dev/null +++ b/calendar_data.json @@ -0,0 +1,8 @@ +[ + { + "title": "Встреча", + "date": "2026-05-20", + "time": "15:00", + "description": "Созвон с командой" + } +] \ No newline at end of file diff --git a/models.py b/models.py new file mode 100644 index 0000000..857d1bc --- /dev/null +++ b/models.py @@ -0,0 +1,35 @@ +import json +from datetime import datetime +from typing import List, Optional + +class Event: + """Класс события календаря""" + + def __init__(self, title: str, date: str, time: str = "", description: str = ""): + self.title = title + self.date = date # формат YYYY-MM-DD + self.time = time # формат HH:MM + self.description = description + + def to_dict(self) -> dict: + """Преобразует событие в словарь для JSON""" + return { + "title": self.title, + "date": self.date, + "time": self.time, + "description": self.description + } + + @classmethod + def from_dict(cls, data: dict) -> 'Event': + """Создаёт событие из словаря""" + return cls( + title=data["title"], + date=data["date"], + time=data.get("time", ""), + description=data.get("description", "") + ) + + def __str__(self) -> str: + time_str = f" в {self.time}" if self.time else "" + return f"{self.date}{time_str}: {self.title} - {self.description}" \ No newline at end of file diff --git a/storage.py b/storage.py new file mode 100644 index 0000000..1fed0c0 --- /dev/null +++ b/storage.py @@ -0,0 +1,44 @@ +import json +import os +from typing import List +from models import Event + +DATA_FILE = "calendar_data.json" + +def load_events() -> List[Event]: + """Загружает события из JSON файла""" + if not os.path.exists(DATA_FILE): + return [] + + try: + with open(DATA_FILE, 'r', encoding='utf-8') as f: + data = json.load(f) + return [Event.from_dict(item) for item in data] + except (json.JSONDecodeError, FileNotFoundError): + return [] + +def save_events(events: List[Event]) -> None: + """Сохраняет события в JSON файл""" + with open(DATA_FILE, 'w', encoding='utf-8') as f: + data = [event.to_dict() for event in events] + json.dump(data, f, ensure_ascii=False, indent=2) + +def add_event(event: Event) -> None: + """Добавляет новое событие""" + events = load_events() + events.append(event) + save_events(events) + +def remove_event(index: int) -> bool: + """Удаляет событие по индексу (начиная с 0)""" + events = load_events() + if 0 <= index < len(events): + del events[index] + save_events(events) + return True + return False + +def get_events_by_date(date: str) -> List[Event]: + """Возвращает события на конкретную дату""" + events = load_events() + return [e for e in events if e.date == date] \ No newline at end of file