json.dump. Не сохраняет данные после закрытия окна

Есть рабочий код библиотеки с графическим интерфейсом. Но код не сохраняет данные которые ты вводишь(условно добавил книгу закрыл окно программы и она отсутствует в списке книг. Аналогично если закрыть PyCharm).Ошибка у меня такая. Ошибка при загрузке данных: module 'json' has no attribute 'load' Ошибка при сохранении данных: module 'json' has no attribute 'dump' Сам код при этом работает но не сохраняет. Вот сам код.

import tkinter as tk
from tkinter import messagebox, ttk
import json
import os


class Book:
    def __init__(self, title, author, year, isbn, available=True):
        self.title = title
        self.author = author
        self.year = year
        self.isbn = isbn
        self.available = available
        self.borrower = None

    def to_dict(self):
        return {
            'title': self.title,
            'author': self.author,
            'year': self.year,
            'isbn': self.isbn,
            'available': self.available,
            'borrower': self.borrower
        }

    @classmethod
    def from_dict(cls, data):
        book = cls(data['title'], data['author'], data['year'], data['isbn'], data['available'])
        book.borrower = data['borrower']
        return book


class User:
    def __init__(self, username, password, is_admin=False):
        self.username = username
        self.password = password
        self.is_admin = is_admin
        self.borrowed_books = []

    def to_dict(self):
        return {
            'username': self.username,
            'password': self.password,
            'is_admin': self.is_admin,
            'borrowed_books': self.borrowed_books
        }

    @classmethod
    def from_dict(cls, data):
        user = cls(data['username'], data['password'], data['is_admin'])
        user.borrowed_books = data['borrowed_books']
        return user


class Library:
    def __init__(self):
        self.books = []
        self.users = []
        self.data_file = "library_data.txt"

        # Загружаем данные при инициализации
        self.load_data()

        # Добавляем администратора по умолчанию, если нет пользователей
        if not self.users:
            self.users.append(User("admin", "admin", True))
            self.save_data()

    def save_data(self):
        data = {
            'books': [book.to_dict() for book in self.books],
            'users': [user.to_dict() for user in self.users]
        }
        try:
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"Ошибка при сохранении данных: {e}")

    def load_data(self):
        if not os.path.exists(self.data_file):
            return

        try:
            with open(self.data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)

                self.books = [Book.from_dict(book_data) for book_data in data.get('books', [])]
                self.users = [User.from_dict(user_data) for user_data in data.get('users', [])]
        except Exception as e:
            print(f"Ошибка при загрузке данных: {e}")

    def add_book(self, book):
        self.books.append(book)
        self.save_data()

    def find_books(self, search_term):
        return [book for book in self.books if search_term.lower() in book.title.lower() or
                search_term.lower() in book.author.lower() or
                search_term == book.isbn]

    def checkout_book(self, isbn, user):
        for book in self.books:
            if book.isbn == isbn and book.available:
                book.available = False
                book.borrower = user.username
                user.borrowed_books.append(isbn)
                self.save_data()
                return True
        return False

    def return_book(self, isbn, user):
        for book in self.books:
            if book.isbn == isbn and not book.available and book.borrower == user.username:
                book.available = True
                book.borrower = None
                if isbn in user.borrowed_books:
                    user.borrowed_books.remove(isbn)
                self.save_data()
                return True
        return False

    def add_user(self, user):
        self.users.append(user)
        self.save_data()

    def authenticate(self, username, password):
        for user in self.users:
            if user.username == username and user.password == password:
                return user
        return None

    def get_user_books(self, username):
        user_books = []
        for book in self.books:
            if book.borrower == username:
                user_books.append(book)
        return user_books


class LibraryApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Система управления библиотекой")
        self.root.geometry("800x600")

        self.library = Library()
        self.current_user = None

        self.show_login_frame()

    def show_login_frame(self):
        self.clear_window()

        self.login_frame = tk.Frame(self.root)
        self.login_frame.pack(pady=100)

        tk.Label(self.login_frame, text="Логин:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5)
        self.username_entry = tk.Entry(self.login_frame, font=("Arial", 12))
        self.username_entry.grid(row=0, column=1, padx=5, pady=5)

        tk.Label(self.login_frame, text="Пароль:", font=("Arial", 12)).grid(row=1, column=0, padx=5, pady=5)
        self.password_entry = tk.Entry(self.login_frame, show="*", font=("Arial", 12))
        self.password_entry.grid(row=1, column=1, padx=5, pady=5)

        login_button = tk.Button(self.login_frame, text="Войти", command=self.login, font=("Arial", 12))
        login_button.grid(row=2, column=0, columnspan=2, pady=10)

        # Подсказка для тестирования
        hint_label = tk.Label(self.root, text="Для теста: admin / admin", fg="gray")
        hint_label.pack(side="bottom", pady=10)

    def login(self):
        username = self.username_entry.get()
        password = self.password_entry.get()

        self.current_user = self.library.authenticate(username, password)

        if self.current_user:
            self.show_main_menu()
        else:
            messagebox.showerror("Ошибка", "Неверный логин или пароль")

    def show_main_menu(self):
        self.clear_window()

        # Заголовок
        welcome_label = tk.Label(self.root,
                                 text=f"Добро пожаловать, {self.current_user.username}!",
                                 font=("Arial", 14, "bold"))
        welcome_label.pack(pady=20)

        # Кнопки меню
        buttons_frame = tk.Frame(self.root)
        buttons_frame.pack(pady=20)

        button_style = {"font": ("Arial", 12), "width": 20, "height": 2}

        tk.Button(buttons_frame, text="Просмотреть все книги",
                  command=self.show_all_books, **button_style).pack(pady=5)
        tk.Button(buttons_frame, text="Поиск книги",
                  command=self.show_search_books, **button_style).pack(pady=5)
        tk.Button(buttons_frame, text="Взять книгу",
                  command=self.show_checkout_book, **button_style).pack(pady=5)
        tk.Button(buttons_frame, text="Вернуть книгу",
                  command=self.show_return_book, **button_style).pack(pady=5)
        tk.Button(buttons_frame, text="Мои книги",
                  command=self.show_user_books, **button_style).pack(pady=5)

        if self.current_user.is_admin:
            tk.Button(buttons_frame, text="Добавить книгу",
                      command=self.show_add_book, **button_style).pack(pady=5)
            tk.Button(buttons_frame, text="Добавить пользователя",
                      command=self.show_add_user, **button_style).pack(pady=5)

        tk.Button(buttons_frame, text="Выйти",
                  command=self.logout, **button_style).pack(pady=20)

    def show_user_books(self):
        self.clear_window()

        back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
        back_button.pack(anchor="nw", padx=10, pady=10)

        title_label = tk.Label(self.root, text="Мои книги", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)

        user_books = self.library.get_user_books(self.current_user.username)

        if not user_books:
            no_books_label = tk.Label(self.root, text="У вас нет взятых книг.", font=("Arial", 12))
            no_books_label.pack(pady=20)
            return

        # Создаем Treeview для отображения книг в виде таблицы
        tree_frame = tk.Frame(self.root)
        tree_frame.pack(fill="both", expand=True, padx=10, pady=10)

        tree = ttk.Treeview(tree_frame, columns=("Title", "Author", "Year", "ISBN"), show="headings")

        # Настройка колонок
        tree.heading("Title", text="Название")
        tree.heading("Author", text="Автор")
        tree.heading("Year", text="Год")
        tree.heading("ISBN", text="ISBN")

        tree.column("Title", width=200)
        tree.column("Author", width=150)
        tree.column("Year", width=50)
        tree.column("ISBN", width=100)

        # Добавление книг в таблицу
        for book in user_books:
            tree.insert("", "end", values=(book.title, book.author, book.year, book.isbn))

        # Добавляем скроллбар
        scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)
        tree.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side="right", fill="y")
        tree.pack(fill="both", expand=True)

    def show_all_books(self):
        self.clear_window()

        back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
        back_button.pack(anchor="nw", padx=10, pady=10)

        title_label = tk.Label(self.root, text="Все книги в библиотеке", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)

        if not self.library.books:
            no_books_label = tk.Label(self.root, text="В библиотеке нет книг.", font=("Arial", 12))
            no_books_label.pack(pady=20)
            return

        # Создаем Treeview для отображения книг в виде таблицы
        tree_frame = tk.Frame(self.root)
        tree_frame.pack(fill="both", expand=True, padx=10, pady=10)

        tree = ttk.Treeview(tree_frame, columns=("Title", "Author", "Year", "ISBN", "Status", "Borrower"),
                            show="headings")

        # Настройка колонок
        tree.heading("Title", text="Название")
        tree.heading("Author", text="Автор")
        tree.heading("Year", text="Год")
        tree.heading("ISBN", text="ISBN")
        tree.heading("Status", text="Статус")
        tree.heading("Borrower", text="Взята пользователем")

        tree.column("Title", width=200)
        tree.column("Author", width=150)
        tree.column("Year", width=50)
        tree.column("ISBN", width=100)
        tree.column("Status", width=100)
        tree.column("Borrower", width=150)

        # Добавление книг в таблицу
        for book in self.library.books:
            status = "Доступна" if book.available else "Выдана"
            borrower = book.borrower if book.borrower else "-"
            tree.insert("", "end", values=(book.title, book.author, book.year, book.isbn, status, borrower))

        # Добавляем скроллбар
        scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)
        tree.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side="right", fill="y")
        tree.pack(fill="both", expand=True)

    def show_search_books(self):
        self.clear_window()

        back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
        back_button.pack(anchor="nw", padx=10, pady=10)

        title_label = tk.Label(self.root, text="Поиск книги", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)

        search_frame = tk.Frame(self.root)
        search_frame.pack(pady=10)

        tk.Label(search_frame, text="Поиск (название, автор или ISBN):", font=("Arial", 12)).pack(side="left")
        self.search_entry = tk.Entry(search_frame, font=("Arial", 12), width=30)
        self.search_entry.pack(side="left", padx=5)

        search_button = tk.Button(search_frame, text="Найти", command=self.search_books, font=("Arial", 12))
        search_button.pack(side="left")

        # Место для результатов поиска
        self.results_frame = tk.Frame(self.root)
        self.results_frame.pack(fill="both", expand=True, padx=10, pady=10)

    def search_books(self):
        # Очищаем предыдущие результаты
        for widget in self.results_frame.winfo_children():
            widget.destroy()

        search_term = self.search_entry.get()
        found_books = self.library.find_books(search_term)

        if not found_books:
            no_results_label = tk.Label(self.results_frame, text="Книги не найдены.", font=("Arial", 12))
            no_results_label.pack(pady=20)
            return

        # Создаем Treeview для отображения результатов
        tree = ttk.Treeview(self.results_frame, columns=("Title", "Author", "Year", "ISBN", "Status"), show="headings")

        # Настройка колонок
        tree.heading("Title", text="Название")
        tree.heading("Author", text="Автор")
        tree.heading("Year", text="Год")
        tree.heading("ISBN", text="ISBN")
        tree.heading("Status", text="Статус")

        tree.column("Title", width=200)
        tree.column("Author", width=150)
        tree.column("Year", width=50)
        tree.column("ISBN", width=100)
        tree.column("Status", width=100)

        # Добавление книг в таблицу
        for book in found_books:
            status = "Доступна" if book.available else "Выдана"
            tree.insert("", "end", values=(book.title, book.author, book.year, book.isbn, status))

        # Добавляем скроллбар
        scrollbar = ttk.Scrollbar(self.results_frame, orient="vertical", command=tree.yview)
        tree.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side="right", fill="y")
        tree.pack(fill="both", expand=True)

    def show_checkout_book(self):
        self.clear_window()

        back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
        back_button.pack(anchor="nw", padx=10, pady=10)

        title_label = tk.Label(self.root, text="Взять книгу", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)

        checkout_frame = tk.Frame(self.root)
        checkout_frame.pack(pady=20)

        tk.Label(checkout_frame, text="ISBN книги:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5)
        self.isbn_entry = tk.Entry(checkout_frame, font=("Arial", 12))
        self.isbn_entry.grid(row=0, column=1, padx=5, pady=5)

        checkout_button = tk.Button(checkout_frame, text="Взять", command=self.checkout_book, font=("Arial", 12))
        checkout_button.grid(row=1, column=0, columnspan=2, pady=10)

    def checkout_book(self):
        isbn = self.isbn_entry.get()
        if self.library.checkout_book(isbn, self.current_user):
            messagebox.showinfo("Успех", "Книга успешно выдана")
        else:
            messagebox.showerror("Ошибка", "Не удалось выдать книгу. Возможно, она уже выдана или не существует.")

    def show_return_book(self):
        self.clear_window()

        back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
        back_button.pack(anchor="nw", padx=10, pady=10)

        title_label = tk.Label(self.root, text="Вернуть книгу", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)

        return_frame = tk.Frame(self.root)
        return_frame.pack(pady=20)

        tk.Label(return_frame, text="ISBN книги:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5)
        self.return_isbn_entry = tk.Entry(return_frame, font=("Arial", 12))
        self.return_isbn_entry.grid(row=0, column=1, padx=5, pady=5)

        return_button = tk.Button(return_frame, text="Вернуть", command=self.return_book, font=("Arial", 12))
        return_button.grid(row=1, column=0, columnspan=2, pady=10)

    def return_book(self):
        isbn = self.return_isbn_entry.get()
        if self.library.return_book(isbn, self.current_user):
            messagebox.showinfo("Успех", "Книга успешно возвращена")
        else:
            messagebox.showerror("Ошибка", "Не удалось вернуть книгу. Возможно, она не была выдана или не существует.")

    def show_add_book(self):
        self.clear_window()

        back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
        back_button.pack(anchor="nw", padx=10, pady=10)

        title_label = tk.Label(self.root, text="Добавить новую книгу", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)

        add_frame = tk.Frame(self.root)
        add_frame.pack(pady=20)

        tk.Label(add_frame, text="Название:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5, sticky="e")
        self.title_entry = tk.Entry(add_frame, font=("Arial", 12))
        self.title_entry.grid(row=0, column=1, padx=5, pady=5)

        tk.Label(add_frame, text="Автор:", font=("Arial", 12)).grid(row=1, column=0, padx=5, pady=5, sticky="e")
        self.author_entry = tk.Entry(add_frame, font=("Arial", 12))
        self.author_entry.grid(row=1, column=1, padx=5, pady=5)

        tk.Label(add_frame, text="Год издания:", font=("Arial", 12)).grid(row=2, column=0, padx=5, pady=5, sticky="e")
        self.year_entry = tk.Entry(add_frame, font=("Arial", 12))
        self.year_entry.grid(row=2, column=1, padx=5, pady=5)

        tk.Label(add_frame, text="ISBN:", font=("Arial", 12)).grid(row=3, column=0, padx=5, pady=5, sticky="e")
        self.isbn_add_entry = tk.Entry(add_frame, font=("Arial", 12))
        self.isbn_add_entry.grid(row=3, column=1, padx=5, pady=5)

        add_button = tk.Button(add_frame, text="Добавить", command=self.add_book, font=("Arial", 12))
        add_button.grid(row=4, column=0, columnspan=2, pady=10)

    def add_book(self):
        title = self.title_entry.get()
        author = self.author_entry.get()
        year = self.year_entry.get()
        isbn = self.isbn_add_entry.get()

        if not all([title, author, year, isbn]):
            messagebox.showerror("Ошибка", "Все поля должны быть заполнены")
            return

        self.library.add_book(Book(title, author, year, isbn))
        messagebox.showinfo("Успех", "Книга успешно добавлена")
        self.show_main_menu()

    def show_add_user(self):
        self.clear_window()

        back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
        back_button.pack(anchor="nw", padx=10, pady=10)

        title_label = tk.Label(self.root, text="Добавить нового пользователя", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)

        add_user_frame = tk.Frame(self.root)
        add_user_frame.pack(pady=20)

        tk.Label(add_user_frame, text="Логин:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5, sticky="e")
        self.new_username_entry = tk.Entry(add_user_frame, font=("Arial", 12))
        self.new_username_entry.grid(row=0, column=1, padx=5, pady=5)

        tk.Label(add_user_frame, text="Пароль:", font=("Arial", 12)).grid(row=1, column=0, padx=5, pady=5, sticky="e")
        self.new_password_entry = tk.Entry(add_user_frame, show="*", font=("Arial", 12))
        self.new_password_entry.grid(row=1, column=1, padx=5, pady=5)

        self.is_admin_var = tk.BooleanVar()
        tk.Checkbutton(add_user_frame, text="Администратор", variable=self.is_admin_var,
                       font=("Arial", 12)).grid(row=2, column=0, columnspan=2, pady=5)

        add_user_button = tk.Button(add_user_frame, text="Добавить", command=self.add_user, font=("Arial", 12))
        add_user_button.grid(row=3, column=0, columnspan=2, pady=10)

    def add_user(self):
        username = self.new_username_entry.get()
        password = self.new_password_entry.get()
        is_admin = self.is_admin_var.get()

        if not username or not password:
            messagebox.showerror("Ошибка", "Логин и пароль должны быть заполнены")
            return

        # Проверка, существует ли уже пользователь с таким логином
        for user in self.library.users:
            if user.username == username:
                messagebox.showerror("Ошибка", "Пользователь с таким логином уже существует")
                return

        self.library.add_user(User(username, password, is_admin))
        messagebox.showinfo("Успех", "Пользователь успешно добавлен")
        self.show_main_menu()

    def logout(self):
        self.current_user = None
        self.show_login_frame()

    def clear_window(self):
        for widget in self.root.winfo_children():
            widget.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    app = LibraryApp(root)
    root.mainloop()

Код сделан с помощью нейросети сам только учусь.


Ответы (0 шт):