Почему не удаляется элемент из словаря по ключу (библиотека tkintermapview)

Написано небольшое приложение, которое отображает на карте несколько маркеров. Данные для создания маркеров приходят по двум каналам: читаются из JSON-файла и трансформируются из адреса в координаты, посредством встроенной библиотеки. Между определенными маркерами необходимо прокладывать маршруты, а через время удалять маркер и маршрут(путь) к нему, кликнув по маркеру. Вопрос: не получается удалять путь к маркеру, к которому он (путь) прокладывается. В функции test() в блоке else сам 'marker' удаляется, но при попытке удаления по ключу 'path' происходит ошибка:

Traceback (most recent call last): File "C:\Python37-32\lib\tkinter_init_.py", line 1702, in call return self.func(*args) File "G:\Python\Delivery Map\venv\lib\site-packages\tkintermapview\canvas_position_marker.py", line 119, in click self.command(self) File "G:\Python\Delivery Map\test.py", line 341, in test marker_info['path'].delete() AttributeError: 'dict' object has no attribute 'delete'

вроде бы все правильно делаю, добавляю в словарь значение пути, но не работает. Хотя те маркеры, которые создаются из JSON-файла, посредством

markers[user_id] = {'marker': marker, 'path': path}

одновременно с началом пути, прекрасно удаляются вместе с маршрутом. Но по логике программы часть маркеров должна сначала создаваться, а уже потом к ним должны прокладываться маршруты. Если кто знает в чем я затупил - пните в нужную сторону. Прошу прощенья за сумбурное описание проблемы.

import json
import tkinter
from tkinter.constants import END, NE

import requests
import tkintermapview
import pygame
import ttk

import functions

# Определение дефолтных значений
DEFAULT_LATITUDE = 0.0
DEFAULT_LONGITUDE = 0.0
DEFAULT_USER_ID = "2000"

root = tkinter.Tk()
root.geometry(f"{800}x{600}")
root.title("Delivery Map")
root.iconbitmap('ic_launcher_playstore.ico')

# Флаг для отслеживания открытого информационного окна
info_window_open = False
pygame.mixer.init()
msg = tkinter.StringVar(root)
variable_list = tkinter.StringVar(root)
variable_list.set("Your choise")
if_click_to_marker = False
selected_markers_lat = ""
selected_markers_lon = ""
create_markers_lat = ""
create_markers_lon = ""
marker_id = ""
marker_text = ""
flag_stop_update_position = False


def get_address(coords):
    global info_window_open
    if not info_window_open:  # Проверяем, открыто ли уже информационное окно
        print("Coords: ", coords)
        adr = tkintermapview.convert_coordinates_to_address(coords[0], coords[1])
        print(adr.street, adr.housenumber, adr.postal, adr.city, adr.state, adr.country, adr.latlng)
        show_info(adr)
        info_window_open = True


def on_paste(event):
    # Получаем содержимое буфера обмена
    text = root.clipboard_get()
    # Вставляем содержимое буфера обмена в поле
    textField.insert(tkinter.INSERT, text)


def show_info(address):
    global info_window_open
    message = (
        f"{address.street}, {address.housenumber}\n"
        f"{address.postal} {address.city}\n"
        f"{address.state}, {address.country}\n"
        f"{address.latlng}"
    )
    info_window = tkinter.Toplevel(root)
    info_window.iconbitmap('ic_launcher_playstore.ico')
    info_window.configure(bg="lightblue")
    info_window.title("Address info")
    info_text = tkinter.Text(info_window, height=5, width=40)
    info_text.insert(tkinter.END, message, "center")
    info_text.tag_configure("center", justify="center")  # Конфигурируем тег для центрирования
    info_text.config(state=tkinter.DISABLED)  # Запретить редактирование текста
    info_text.pack(padx=10, pady=10)
    info_button = tkinter.Button(info_window, text="OK", command=lambda: close_info_window(info_window))
    info_button.pack(pady=(0, 10))


def close_info_window(window):
    global info_window_open
    window.destroy()
    info_window_open = False


def left_click_event(coordinates_tuple):
    global if_click_to_marker
    if if_click_to_marker:
        pass
        # if_click_to_marker = False
    else:
        print("left click", coordinates_tuple)


def delete_all_path():
    map_widget.delete_all_path()


map_widget = tkintermapview.TkinterMapView(root, width=800, height=600, corner_radius=0)
map_widget.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER, relwidth=1.0, relheight=1.0)
map_widget.set_zoom(15)
map_widget.add_right_click_menu_command(label="Get address",
                                        command=get_address,
                                        pass_coords=True)
map_widget.add_right_click_menu_command(label="Delete all path",
                                        command=delete_all_path,
                                        pass_coords=False)
map_widget.add_left_click_map_command(left_click_event)

markers = {}  # Словарь для отслеживания маркеров по user_id
object_markers = {}  # Словарь для отслеживания маркеров объектов по user_id
marker_list = []


def write_default_values_to_json():
    """Записывает дефолтные значения в JSON-файл."""
    data_to_write = {
        "lat": DEFAULT_LATITUDE,
        "lon": DEFAULT_LONGITUDE,
        "user_id": DEFAULT_USER_ID
    }
    with open('data.json', 'w') as json_file:
        json.dump(data_to_write, json_file, indent=2)


def on_closing():
    """Функция вызывается при закрытии главного окна."""
    write_default_values_to_json()
    root.destroy()


def create_marker(latitude, longitude, user_id):
    # Создаем маркер
    marker = map_widget.set_marker(latitude, longitude, marker_color_outside="blue", marker_color_circle="gray",
                                   command=remove_marker_and_path)
    marker.set_text(user_id)

    # Создаем путь и добавляем первую позицию
    path = map_widget.set_path([marker.position, (latitude, longitude)])
    path.add_position(latitude, longitude)

    # Возвращаем маркер и путь
    return marker, path


def update_map():
    try:
        with open('data.json', 'r') as json_file:
            data_read = json.load(json_file)

        latitude = data_read["lat"]
        longitude = data_read["lon"]
        user_id = data_read["user_id"]
        global flag_stop_update_position
        # Проверяем, изменились ли координаты
        if (latitude, longitude) != update_map.last_coordinates:
            # Сохраняем последние координаты
            update_map.last_coordinates = (latitude, longitude)

            if user_id not in markers:
                # Если для данного user_id еще нет маркера, создаем его и добавляем в словарь
                marker, path = create_marker(latitude, longitude, user_id)
                markers[user_id] = {'marker': marker, 'path': path}
                # play_sound('1.mp3')
                marker_list.append(user_id)
                update_combobox()
            else:
                # Если маркер уже существует, обновляем его координаты
                marker, path = markers[user_id]['marker'], markers[user_id]['path']
                if not flag_stop_update_position:
                    map_widget.set_position(latitude, longitude)
                    # flag_stop_update_position = True
                marker.set_position(latitude, longitude)
                # path.add_position(latitude, longitude)

    except FileNotFoundError:
        print("File 'data.json' not found.")
        pass
    except json.JSONDecodeError:
        print("JSONDecodeError: File 'data.json' is empty or contains invalid JSON data.")
        pass
    except KeyError as e:
        print(f"KeyError: Missing key {e} in 'data.json'.")
        pass
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        pass
    root.after(2000, update_map)


# Инициализируем последние координаты как (0, 0)
update_map.last_coordinates = (0, 0)


def remove_marker_and_path(marker):
    if marker.text in markers:
        # Удаляем маркер и связанный с ним путь
        marker_info = markers.pop(marker.text)
        marker_info['marker'].delete()
        marker_info['path'].delete()
        marker_list.remove(marker.text)
        update_combobox()


def play_sound(file):
    pygame.mixer.init()
    audio_file_path = file
    # Воспроизводим звук
    pygame.mixer.music.load(audio_file_path)
    pygame.mixer.music.play()


def button1_clicked(event):
    map_widget.set_tile_server("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png")


def button2_clicked(event):
    map_widget.set_tile_server("https://mt0.google.com/vt/lyrs=m&hl=ru&x={x}&y={y}&z={z}&s=Ga", max_zoom=22)


def button3_clicked(event):
    map_widget.set_tile_server("https://mt0.google.com/vt/lyrs=s&hl=en&x={x}&y={y}&z={z}&s=Ga", max_zoom=22)


def clear_entry():
    textField.delete(0, END)  # удаление введенного текста


def get_address_and_parsing_it(event):
    global msg
    global create_markers_lat
    global create_markers_lon
    global marker_id
    global marker_text
    tf_get = msg.get()
    if tf_get != "":
        try:
            adr = tkintermapview.convert_address_to_coordinates(tf_get)
            create_markers_lat = adr[0]
            create_markers_lon = adr[1]
            marker_text = tf_get
            marker_id = tf_get
            marker_id = marker_id.replace(" ", "")
            marker_id = marker_id.replace(",", "_")
            print(f"marker_text: {marker_text}")
            print(f"marker_id: {marker_id}")
            print(adr[0])
            print(adr[1])
            update_object_map()
            # create_object_marker(create_markers_lat, create_markers_lon, marker_id, marker_text)
            # new_marker = map_widget.set_marker(adr[0], adr[1], text=f"{tf_get}", command=test)
            # map_widget.set_position(adr[0], adr[1])
            # map_widget.set_zoom(22)
            # new_marker.set_position(adr[0], adr[1])
        except:
            functions.message("Адрес не найден!")
    clear_entry()
    textField.insert(END, "Харьков, ")


def create_object_marker(latitude, longitude, user_id, text):
    # Создаем маркер
    marker = map_widget.set_marker(latitude, longitude, marker_color_outside="red", marker_color_circle="purple",
                                   command=test)
    marker.set_text(text)
    # Создаем путь и добавляем первую позицию
    # path = map_widget.set_path([marker.position, (latitude, longitude)])
    # path.add_position(latitude, longitude)
    # Возвращаем маркер и путь
    return marker  # , path


def update_object_map():
    global create_markers_lat
    global create_markers_lon
    global marker_id
    global marker_text
    try:
        latitude = create_markers_lat
        longitude = create_markers_lon
        object_id = marker_text
        marker_text = marker_text

        if object_id not in object_markers:
            # Если для данного user_id еще нет маркера, создаем его и добавляем в словарь
            marker = create_object_marker(latitude, longitude, object_id, marker_text)
            object_markers[object_id] = {'marker': marker}
            map_widget.set_position(latitude, longitude)
            marker_list.append(object_id)

        else:
            # Если маркер уже существует, обновляем его координаты
            marker = object_markers[object_id]['marker']
            map_widget.set_position(latitude, longitude)
            marker.set_position(latitude, longitude)
            # path.add_position(latitude, longitude)
    except Exception as e:
        print(f"An unexpected error occurred in update_object_map: {e}")
        pass


def test(marker):
    global if_click_to_marker
    global selected_markers_lat
    global selected_markers_lon

    if if_click_to_marker == False:
        def get_route(start_coords, end_coords):
            # Запрос маршрута через сервис OpenRouteService
            url = f"https://api.openrouteservice.org/v2/directions/driving-car?api_key=MY_API_KEY&start={start_coords[1]},{start_coords[0]}&end={end_coords[1]},{end_coords[0]}"
            headers = {"Accept": "application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8"}
            response = requests.get(url, headers=headers)
            data = response.json()
            return data

        def display_route(route):
            # Отображаем маршрут на карте
            if 'features' in route and len(route['features']) > 0:
                coordinates = route['features'][0]['geometry']['coordinates']
                points = [(coord[1], coord[0]) for coord in coordinates]
                map_widget.set_path(points)

        print(f"marker clicked!")
        latitude, longitude = marker.position  # Получаем координаты маркера
        latitude_str = str(latitude)
        longitude_str = str(longitude)
        coords_str = f"Latitude: {latitude_str}, Longitude: {longitude_str}"
        print(f"Coordinates: {coords_str}")
        start_coords = (selected_markers_lat, selected_markers_lon)
        end_coords = (latitude, longitude)
        # Получаем маршрут от начальной до конечной точки
        route = get_route(start_coords, end_coords)
        object_markers[marker_text]['path'] = route
        # Отображаем маршрут на карте
        display_route(route)
        map_widget.set_position(start_coords[0], start_coords[1])

        if_click_to_marker = True

    else:
        if marker.text in object_markers:
            # Удаляем маркер и связанный с ним путь
            marker_info = object_markers.pop(marker.text)
            marker_info['marker'].delete()
            marker_info['path'].delete()
            if_click_to_marker = False

            marker_list.remove(marker.text)


def update_combobox():
    # Мы можем обновлять список в соответствии с определенными условиями или данными.
    new_values = marker_list  # Новые значения списка
    combobox['values'] = new_values  # Обновляем список в Combobox


def handle_selection_combobox(event):
    global selected_markers_lat
    global selected_markers_lon
    # Получаем выбранный ключ (идентификатор пользователя) из Combobox
    selected_user_id = combobox.get()

    # Проверяем, что выбран какой-то элемент из Combobox
    if selected_user_id:
        # Проверяем, есть ли выбранный пользователь в словаре markers
        if selected_user_id in markers:
            # Получаем маркер для выбранного пользователя
            marker_info = markers[selected_user_id]
            # Получаем координаты из маркера
            latitude, longitude = marker_info['marker'].position
            selected_markers_lat = latitude
            selected_markers_lon = longitude

            # Теперь у вас есть координаты (широта и долгота) для выбранного пользователя
            print(f"Координаты для пользователя {selected_user_id}: Широта - {latitude}, Долгота - {longitude}")
        else:
            print(f"Маркер для пользователя {selected_user_id} не найден.")
    else:
        print("Ничего не выбрано в Combobox.")


# Создаем три кнопки
button1 = tkinter.Button(root, text="OSM maps")
button1.pack(side=tkinter.LEFT, padx=5, pady=5, anchor='s')
button1.bind("<Button-1>", button1_clicked)

button2 = tkinter.Button(root, text="Google maps")
button2.pack(side=tkinter.LEFT, padx=5, pady=5, anchor='s')
button2.bind("<Button-1>", button2_clicked)

button3 = tkinter.Button(root, text="Google satellite")
button3.pack(side=tkinter.LEFT, padx=5, pady=5, anchor='s')
button3.bind("<Button-1>", button3_clicked)

textField = tkinter.Entry(root, background="GRAY", textvariable=msg)
textField.pack(side=tkinter.LEFT, padx=5, pady=7, fill="x", expand=True, anchor='s')
textField['font'] = 20
textField.insert(0, "Харьков, ")
# Привязываем обработчик к событию вставки (<<Control-v>>)
textField.bind('<Control-v>', on_paste)

button4 = tkinter.Button(root, text="Найти адрес")
button4.pack(side=tkinter.RIGHT, padx=5, pady=5, anchor='s')
button4.bind("<Button-1>", get_address_and_parsing_it)

combobox = ttk.Combobox(root, values=marker_list, textvariable=marker_list)
combobox.pack(side=tkinter.RIGHT, padx=5, pady=5, anchor='n')
# Привязываем функцию к событию выбора элемента Combobox
combobox.bind("<<ComboboxSelected>>", handle_selection_combobox)

# Привязываем функцию on_closing к событию закрытия окна
root.protocol("WM_DELETE_WINDOW", on_closing)
root.after(1000, update_map)
root.mainloop()

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