Search code examples
pythonsockets

How to populate and use single object of the class accross a project?


I have a class called My_Buttons in button.py file. And I created object of the class in the same file in order to use in different files the same instance.

import math
from frontend.utilities.screen_info import screen_info
from frontend.env import BTN_SIZE, SUCCESS_COLOR, FAIL_COLOR, WARNING_COLOR, BTN_X_PADDING, \
    BTN_Y_PADDING
from frontend.modules.master import master, Button
from backend.ip_list import ip_list

screen_width, screen_height = screen_info()


class MyButtons:
    def __init__(self):
        self.current_btn = None
        self.btns = []
        self.items = ip_list
        self.attach_all_buttons()

    def create_btn(self, item, k):
        btn = Button(
            master,
            text=item,
            bg=FAIL_COLOR,
            command=lambda: self.click_btn(k)
        )
        self.btns.append(btn)
        self.current_btn = btn

    def click_btn(self, id):
        if self.btns[id].cget('bg') == WARNING_COLOR:
            self.btns[id].config(bg=SUCCESS_COLOR)

    def update_btns(self, items):
        for i, item in zip(range(len(self.btns)), items):
            bg_color = SUCCESS_COLOR if item['is_alive'] == True else FAIL_COLOR
            self.btns[i].config(bg=bg_color)

    def configure_btn(self, col):
        master.grid_columnconfigure(col, minsize=BTN_SIZE)
        # btn.bind('<Enter>', lambda: btn.config(text='Mouse in'))
        # btn.bind('<Leave>', lambda: btn.config(text='Mouse out'))

    def attach_btn(self, row, col):
        self.current_btn.grid(
            row=row,
            column=col,
            padx=BTN_X_PADDING,
            pady=BTN_Y_PADDING,
            sticky='wens'
        )

    def attach_all_buttons(self):
        items_count = len(self.items)
        cols = math.floor(screen_width / BTN_SIZE)
        rows = math.ceil(items_count / cols)
        k = 0
        for row in range(rows):
            partial_items = self.items[row * cols:(row + 1) * cols]
            for col, item in zip(range(cols), partial_items):
                self.create_btn(item, k)
                self.attach_btn(row, col)
                self.configure_btn(col)
                k = k + 1


my_button = MyButtons()

monitor.py file for creating screen:

from frontend.modules.master import master


def prepare_monitor():
    master.mainloop()


prepare_monitor()

And main.py file with following code:

from frontend.modules.button import my_button
from frontend.client_socket import client_socket

import pickle


def start():
    print('Monitor Network')
    while True:
        data = client_socket.client_socket.recv(4096)
        client_socket.message = pickle.loads(data)
        if client_socket.message:
            my_button.update_btns(client_socket.message)
            print('Server Socket data: ', client_socket.message)
            client_socket.message = None


start()

In this project I want to update buttons on monitor based on backend data, and used sockets. Firstly, run monitor.py then main.py files.

But it is appearing all imports getting copy of the my_button object. I want to use the same instance is used in all imports. I am changing this object from different places. Any help would be greatly appreciated !


Solution

  • Firstly, run monitor.py then main.py files.

    Apologies for the potentially simplistic answer, but if I understand the situation correctly, you're running two files separately. They import the same shared file, button.py, but the values inside this shared file seem to be copies, and mutations are not propagated between the two executions.

    If that's the case, it's how Python programs work: every time you execute python.exe, all code is run anew. Your line my_button = MyButtons() was executed twice, once for python monitor.py and once for python main.py, and they created different MyButtons instances that share nothing between them.

    If you really want them to share a value, you can use concurrency primitives like threads:

    from threading import Thread
    from time import sleep
    
    my_shared_list = [0]
    
    def loop_1():
        while True:
            my_shared_list.pop()
            print(f"loop_1 - {my_shared_list=}")
            sleep(0.5)
    
    def loop_2():
        while True:
            my_shared_list.append(1)
            print(f"loop_2 - {my_shared_list=}")
            sleep(0.4)
    
    Thread(target=loop_1).start()
    loop_2()
    
    # loop_1 - my_shared_list=[]
    # loop_2 - my_shared_list=[1]
    # loop_2 - my_shared_list=[1, 1]
    # loop_1 - my_shared_list=[1]
    # loop_2 - my_shared_list=[1, 1]
    # loop_1 - my_shared_list=[1]
    # loop_2 - my_shared_list=[1, 1]
    # loop_1 - my_shared_list=[1]
    # loop_2 - my_shared_list=[1, 1]
    # loop_2 - my_shared_list=[1, 1, 1]
    # loop_1 - my_shared_list=[1, 1]
    # ...
    

    This code runs two infinite loops in one script, loop_1 and loop_2 (similar to your prepare_monitor and start). The first one is run in a separate thread (Thread(target=loop_1).start()), so now we have the main thread executing loop_2, and the new thread executing loop_1. They both access the same my_shared_list, with one adding and other removing values from it.