0

I am stuck. I can't wrap my mind around how to access an object that is initiated in the Kivy file?

This is my code:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import time
from kivy.uix.screenmanager import Screen, ScreenManager

import filestack

Builder.load_file("test.kv")

class LoginScreen(Screen):

    def create_file(self):
        filename = f"file_{time.strftime('%Y%m%d_%H%M%S')}.txt"
        with open(filename, 'w') as file:
            file.write("Some content")


class RootWidget(ScreenManager):
    pass

class MainApp(App):
    def build(self):
        return RootWidget()

class FileSharer:

    def __init__(self, filepath, api_key="abcdefg"):
        self.filepath = filepath
        self.api_key = api_key

    def share(self):
        client = filestack.Client(self.api_key)
        new_filelink = client.upload(filepath=self.filepath)
        return new_filelink.url

MainApp().run()

And my test.kv file:

<LoginScreen>:
    GridLayout:
        cols: 1
        padding: 10, 10
        spacing: 10, 10
        Button:
            text: 'Create File'
            size_hint_y: None
            height: '48dp'
            on_press: root.create_file()

<RootWidget>:
    LoginScreen:
        id: login_screen
        name: "login_screen"

Here's a visual of what the program produces:

enter image description here

When the Create File button is pressed, the LoginScreen.create_file() method is called by the Kivy file, and a text file with a name containing the current timestamp is created (e.g. file_20200624_173229.txt).

I want to be able to access that filename from the Python code. The reason I want to do this is I want to upload the file to the cloud using the FileSharer class. In order to do that, I need to initlalize FileSharer like FileSharer(filepath=...).

I know I can get around this by using os.listdir() to look for the generated files in the disk, but I want to do this the right way which is by accessing the value of filename from the LoginScreen instance.

multigoodverse
  • 7,638
  • 19
  • 64
  • 106

1 Answers1

1

Several ways to accomplish this. Here is one. You can create a StringProperty in the LoginScreen to contain the created filename:

class LoginScreen(Screen):
    filename = StringProperty('')

    def create_file(self):
        self.filename = f"file_{time.strftime('%Y%m%d_%H%M%S')}.txt"
        with open(self.filename, 'w') as file:
            file.write("Some content")

And the create_file() method saves the file name to the filename property.

Then you can access the filename several ways, like login_screen_instance.filename, or taking advantage of the fact that it is now a Property, you can use it in your kv:

<RootWidget>:
    LoginScreen:
        id: login_screen
        name: "login_screen"
        on_filename: root.get_file(self.filename)

And adding a get_file() method to RootWidget:

class RootWidget(ScreenManager):
    def get_file(self, filename):
        print('file is', filename)

Now, whenever a new file is created by the create_file() method, the get_file() method is called.

John Anderson
  • 35,991
  • 4
  • 13
  • 36
  • Thanks for the answer. Trying to apply it in my code I get a `NameError: name 'login_screen_instance' is not defined` if I try to use the `login_screen_instance` variable inside my .py file. I thought you meant that a special `login_screen_instance` variable would be available in the .py file somehow, or did I get this wrong? – multigoodverse Jul 01 '20 at 09:17
  • So, the main question of my thread is how do I access the LoginScreen instance that the Kivy code creates. – multigoodverse Jul 01 '20 at 10:42
  • Since there are many different ways to access the instance of `LoginScreen`, my comment mentioning `login_screen_instance` was an example of how to access the `filename` using an instance of `LoginSceen`. You can access the `LoginScreen` using `App.get_running_app().root.ids.login_screen`. – John Anderson Jul 01 '20 at 13:34
  • That worked! Do you know what exactly `App.get_running_app().root.ids.login_screen` is? Is it the LoginScreen class itself or the instance of the class? When I do `type(App.get_running_app().root.ids.login_screen)` I get `class 'kivy.weakproxy.WeakProxy`. The Kivy docs about that WeakProxy type gives almost no explanation. What exaclty are we accessing with `App.get_running_app().root.ids.login_screen`? – multigoodverse Jul 01 '20 at 15:11
  • 1
    That accesses the instance of `LoginScreen` that is created by your `kv` file. It uses a `WeakProxy` which is just a reference to the instance that is not counted for garbage collection. – John Anderson Jul 01 '20 at 17:25