Kivy Property not Callable Error - python

I am trying to implement a diagram tool in Kivy, but I'm seeing the below error when I try to instantiate an instance of the FlowChartNode class:
Traceback (most recent call last):
File "FlowChartExample.py", line 193, in <module>
FlowChartExampleApp().run()
File "/usr/lib/python2.7/dist-packages/kivy/app.py", line 798, in run
root = self.build()
File "FlowChartExample.py", line 189, in build
root = FlowChartExampleWidget()
File "FlowChartExample.py", line 184, in __init__
begin_node = FlowChartNode()
File "FlowChartExample.py", line 116, in __init__
super(FlowChartNode, self).__init__(**kwargs)
File "/usr/lib/python2.7/dist-packages/kivy/uix/behaviors.py", line 105, in __init__
super(ButtonBehavior, self).__init__(**kwargs)
File "/usr/lib/python2.7/dist-packages/kivy/uix/label.py", line 187, in __init__
super(Label, self).__init__(**kwargs)
File "/usr/lib/python2.7/dist-packages/kivy/uix/widget.py", line 261, in __init__
super(Widget, self).__init__(**kwargs)
File "_event.pyx", line 252, in kivy._event.EventDispatcher.__init__ (kivy/_event.c:4505)
File "_event.pyx", line 777, in kivy._event.EventDispatcher.properties (kivy/_event.c:7967)
TypeError: 'ObservableList' object is not callable
Here's the FlowChartNode class:
class FlowChartNode(Button):
#Exposes the event on_properties to allow for binding to expose
#properties panel in app on triple-press
properties = ListProperty([0, 0])
#Properties to set the backgrounds of the node
background_draggable = StringProperty('img/drag_node_small.png')
background_pressable = StringProperty('img/press_node_small.png')
background_dragged = StringProperty('img/drag_node_down_small.png')
background_pressed = StringProperty('img/press_node_down_small.png')
#The components of the node
front = ObjectProperty(None)
back = ListProperty([])
connect = ListProperty([])
#The sparse grid being added to
sparse_grid = ObjectProperty(None)
#The assigned cell in the sparse grid
cell = ObjectProperty(None)
#Boolean state for draggable or pressable
is_draggable = BooleanProperty(False)
def __init__(self, **kwargs):
super(FlowChartNode, self).__init__(**kwargs)
if self.is_draggable:
self.background_normal = self.background_draggable
else:
self.background_normal = self.background_pressable
self.bind(pos=self.set_front)
def on_touch_down(self, touch):
if touch.is_triple_tap:
self.properties = touch.pos
elif touch.is_double_tap:
if self.is_draggable:
self.is_draggable=False
self.background_normal = self.background_pressable
else:
self.is_draggable=True
self.background_normal = self.background_draggable
else:
if self.is_draggable:
self.background_normal = self.background_pressed
touch.grab(self)
else:
self.background_normal = self.background_dragged
#Add the connected node
back_node = FlowChartNode(is_draggable=True)
connector = FlowConnector()
back_node.bind(pos=self.set_back)
self.back.append(back_node)
self.connect.append(connector)
self.connect[len(connect) - 1].front = self.front.center
self.cell.add_widget(connector)
self.cell.add_widget(back_node)
return super(FlowChartNode, self).on_touch_down(touch, *args)
def on_touch_move(self, touch):
if touch.grab_current == self:
if self.collide_point(touch.pos):
for cel in self.sparse_grid.cells:
if cel.collide_point(touch.pos):
#Snap the grabbed node to the cell
self.cell.clear_widgets()
self.cell = cel
cel.add_widget(self)
return super(FlowChartNode, self).on_touch_move(touch, *args)
def on_touch_up(self, touch):
return super(FlowChartNode, self).on_touch_up(touch, *args)
if self.is_draggable:
self.background_normal = self.background_draggable
else:
self.background_normal = self.background_pressable
def set_front(self, *args):
for con in self.connect:
con.front = self.center_node.center
def set_back(self, *args):
i=0
for con in self.connect:
con.back = self.options[i].center
i+=1
Most of the code came from a working widget which can be found here, as well as other successful tests and working widgets. I've reviewed all of the Kivy Properties I'm interacting with and they appear to be handled correctly. What am I doing wrong here?
Thanks in advance for your help!
Alex

I ended up re-writing the classes a bit differently, you can find the full code here if you are interested.

Related

python multiprocessing report bug: ran out of input

I am implementing a GUI project, and I want to use multiprocessing to accelerate the calculation. In order to tell the user that the calculation is finished, I use a threading to check whether the calculation is finished. My code is:
import sys
import threading
from PyQt5.QtWidgets import *
import multiprocessing
import time
class SubProcess(multiprocessing.Process):
def __init__(self, calFunc):
super().__init__()
self.calFunc = calFunc
self.recv, self.send = multiprocessing.Pipe(False)
def run(self) -> None:
self.calFunc()
self.send.send(True)
def IsFinished(self):
return self.recv.recv()
class SubThread(threading.Thread):
def __init__(self, calFunc, finishFunc):
super().__init__()
self.finishFunc = finishFunc
self.subProcess = SubProcess(calFunc)
def start(self) -> None:
super().start()
self.subProcess.start()
def run(self) -> None:
while self.subProcess.IsFinished() != True:
pass
self.finishFunc()
class Widget(QWidget):
def __init__(self):
super().__init__()
self.btn = QPushButton('calculation')
self.btn.clicked.connect(self.calBtnClick)
self.label = QLabel('not finish')
self.lay = QVBoxLayout()
self.setLayout(self.lay)
self.lay.addWidget(self.btn)
self.lay.addWidget(self.label)
def calBtnClick(self, check=False):
print('calculation')
self.subThread = SubThread(self.calculation, self.finish)
self.subThread.start()
def finish(self):
print('calculation finish')
self.label.setText('finish')
def calculation(self):
time.sleep(5)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = Widget()
win.show()
app.exec()
When press the QPushButton, I want Widget.calculation run in the sub-process, and a sub-threading will check whether the sub-process is finished.
However, the code reports a bug:
Traceback (most recent call last):
File "C:/Users/zhq/Desktop/test/test2.py", line 58, in calBtnClick
self.subThread.start()
File "C:/Users/zhq/Desktop/test/test2.py", line 32, in start
self.subProcess.start()
File "C:\ProgramData\Anaconda3\envs\MedPro\lib\multiprocessing\process.py", line 112, in start
self._popen = self._Popen(self)
File "C:\ProgramData\Anaconda3\envs\MedPro\lib\multiprocessing\context.py", line 223, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "C:\ProgramData\Anaconda3\envs\MedPro\lib\multiprocessing\context.py", line 322, in _Popen
return Popen(process_obj)
File "C:\ProgramData\Anaconda3\envs\MedPro\lib\multiprocessing\popen_spawn_win32.py", line 89, in __init__
reduction.dump(process_obj, to_child)
File "C:\ProgramData\Anaconda3\envs\MedPro\lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: can't pickle Widget objects
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\ProgramData\Anaconda3\envs\MedPro\lib\multiprocessing\spawn.py", line 105, in spawn_main
exitcode = _main(fd)
File "C:\ProgramData\Anaconda3\envs\MedPro\lib\multiprocessing\spawn.py", line 115, in _main
self = reduction.pickle.load(from_parent)
EOFError: Ran out of input
The bug is reported for self.subProcess.start().
How to fix this bug? Any suggestion is appreciated~~~
Update
Thank #Dipet, the code is modifed as:
import sys
import threading
from PyQt5.QtWidgets import *
import multiprocessing
import time
def calFunc():
time.sleep(5)
class SubProcess(multiprocessing.Process):
def __init__(self, calFunc):
super().__init__()
self.calFunc = calFunc
self.recv, self.send = multiprocessing.Pipe(False)
def run(self) -> None:
self.calFunc()
self.send.send(True)
def IsFinished(self):
return self.recv.recv()
class SubThread(threading.Thread):
def __init__(self, calFunc, finishFunc):
super().__init__()
self.finishFunc = finishFunc
self.subProcess = SubProcess(calFunc)
def start(self) -> None:
super().start()
self.subProcess.start()
def run(self) -> None:
while self.subProcess.IsFinished() != True:
pass
self.finishFunc()
class Widget(QWidget):
def __init__(self):
super().__init__()
self.btn = QPushButton('calculation')
self.btn.clicked.connect(self.calBtnClick)
self.label = QLabel('not finish')
self.lay = QVBoxLayout()
self.setLayout(self.lay)
self.lay.addWidget(self.btn)
self.lay.addWidget(self.label)
def calBtnClick(self, check=False):
print('calculation')
self.subThread = SubThread(calFunc, self.finish)
self.subThread.start()
def finish(self):
print('calculation finish')
self.label.setText('finish')
def calculation(self):
time.sleep(5)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = Widget()
win.show()
app.exec()
Multiprocessing module provide args using pickle, so all values that you provided into subproces must support pickle protocol. You use self.finish as an argument for your worker, but this is a Widget method, but QWidget do not support pickling. And you see and error: TypeError: can't pickle Widget objects. Try to use staticmethod or common function.

I am getting an __initerror

I'm trying to put a question-banner (as an MDGridLayout) in a specific place on my screen so that questions will be loaded through my FireBase.
I get the error:
Traceback (most recent call last):
File "C:/Users/user/PycharmProjects/GOAT/main.py", line 124, in <module>
NavDrawerAndScreenManagerApp().run()
File "C:\Users\user\PycharmProjects\GOAT\venv\lib\site-packages\kivy\app.py", line 949, in run
self._run_prepare()
File "C:\Users\user\PycharmProjects\GOAT\venv\lib\site-packages\kivy\app.py", line 944, in _run_prepare
self.dispatch('on_start')
File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
File "C:/Users/user/PycharmProjects/GOAT/main.py", line 103, in on_start
Q = QuestionBanner(side_i_1=question['side_i_1'], side_n_1=question['side_n_1'])
File "C:\Users\user\PycharmProjects\GOAT\questionsbanner.py", line 10, in __init__
super(QuestionBanner, self).__init__(**kwargs)
File "C:\Users\user\PycharmProjects\GOAT\venv\lib\site-packages\kivy\uix\gridlayout.py", line 256, in __init__
super(GridLayout, self).__init__(**kwargs)
File "C:\Users\user\PycharmProjects\GOAT\venv\lib\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "C:\Users\user\PycharmProjects\GOAT\venv\lib\site-packages\kivymd\uix\behaviors\backgroundcolorbehavior.py", line 150, in __init__
super().__init__(**kwargs)
File "C:\Users\user\PycharmProjects\GOAT\venv\lib\site-packages\kivy\uix\widget.py", line 350, in __init__
super(Widget, self).__init__(**kwargs)
File "kivy\_event.pyx", line 245, in kivy._event.EventDispatcher.__init__
TypeError: object.__init__() takes exactly one argument (the instance to initialize)
Here is my main.py relevant code (the last two lines I believe are the source for the error as if I comment (#) them out, the app runs):
my_questions_grid = self.root.ids['my_questions_grid']
questions = data['questions']
# iterate through the firebase dictionaries
for question_num, question in questions.items():
# populate Home screen
Q = QuestionBanner(side_i_1=question['side_i_1'], side_n_1=question['side_n_1'])
my_questions_grid.add_widget(Q)
This is my QuestionsBanner file.py relevant code:
def __init__(self, **kwargs):
super(QuestionBanner, self).__init__(**kwargs)
# Up - question text
# Left side
left = MDFloatLayout()
left_image = Image(source='photos/' + kwargs['side_i_1'], size_hint=(1, 0.8), pos_hint={'top': 1, 'left': 1})
left_label = MDLabel(text=kwargs['side_n_1'], size_hint=(1, 0.2), pos_hint={'top': 0.2, 'left': 1})
left.add_widget(left_image)
left.add_widget(left_label)
self.add_widget(left)
Here is the relevant main.kv code:
MDTabs:
pos_hint: {'top': .5, 'left': 1}
size_hint: 1, .4
id: android_tabs
on_tab_switch: app.on_tab_switch(*args)
Tab:
text: "My Questions"
MDGridLayout:
id: my_questions_grid
Thank you to anyone who can shed some light over this!
In your __init__() of the QuestionBanner class, you are calling:
super(QuestionBanner, self).__init__(**kwargs)
which is passing all your kwargs to the super __init__() method, and that super __init__() does not understand your kwargs that you pass in the constructor:
Q = QuestionBanner(side_i_1=question['side_i_1'], side_n_1=question['side_n_1'])
So those args get passed through similar super calls till it gets to the object __init__() which does not accept any kwargs, so it raises an Exception. The fix is to get your __init__() for QuestionBanner to remove those kwargs before you call super. One simple way to do that is to just add properties for the kwargs like this:
class QuestionBanner(MDGridLayout):
side_i_1 = ObjectProperty(None)
side_n_1 = ObjectProperty(None)
def __init__(self, **kwargs):
super(QuestionBanner, self).__init__(**kwargs)
# Up - question text
# Left side
left = MDFloatLayout()
left_image = Image(source='photos/' + kwargs['side_i_1'], size_hint=(1, 0.8), pos_hint={'top': 1, 'left': 1})
left_label = MDLabel(text=kwargs['side_n_1'], size_hint=(1, 0.2), pos_hint={'top': 0.2, 'left': 1})
left.add_widget(left_image)
left.add_widget(left_label)
self.add_widget(left)
This code may be incorrect, since you haven't provided us with all the relevant code, but defining some type of Properties with the required names will automatically set the Properties and remove those kwargs before the super call.

Kivy module in python

When I was trying to use grid layout, it shows errors when I try to use more widgets but with one widget it shows no errors,I have reviewed the codes many times but i didn't find any solutions,and by the way I'm using python 3.7 and kivy version 2 Here's my code:
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
class My_Grid(GridLayout):
def __init__(self, **kwargs):
super(My_Grid, self).__init__(**kwargs)
self.cols = 4
self.rows = 3
self.add_widget(Label(text="First Name: "))
self.FirstName = TextInput(multiline=False)
self.add_widget(self.FirstName)
self.add_widget(Label(text="Last Name: "))
self.LastName = TextInput(mulyiline=False)
self.add_widget(self.LastName)
self.add_widget(Label(text="email: "))
self.Email = TextInput(mulyiline=False)
self.add_widget(self.Email)
class TestApp(App):
def build(self):
return My_Grid()
if __name__ == "__main__":
TestApp().run()
the errors when i use more widgets:
Traceback (most recent call last):
File "C:/Users/Asus/PycharmProjects/untitled3/my.py", line 29, in <module>
TestApp().run()
File "C:\Users\Asus\PycharmProjects\untitled3\venv\lib\site-packages\kivy\app.py", line 829, in run
root = self.build()
File "C:/Users/Asus/PycharmProjects/untitled3/my.py", line 25, in build
return My_Grid()
File "C:/Users/Asus/PycharmProjects/untitled3/my.py", line 18, in __init__
self.LastName = TextInput(mulyiline=False)
File "C:\Users\Asus\PycharmProjects\untitled3\venv\lib\site-packages\kivy\uix\textinput.py", line 527, in __init__
super(TextInput, self).__init__(**kwargs)
File "C:\Users\Asus\PycharmProjects\untitled3\venv\lib\site-packages\kivy\uix\behaviors\focus.py", line 367, in __init__
super(FocusBehavior, self).__init__(**kwargs)
File "C:\Users\Asus\PycharmProjects\untitled3\venv\lib\site-packages\kivy\uix\widget.py", line 350, in __init__
super(Widget, self).__init__(**kwargs)
File "kivy\_event.pyx", line 243, in kivy._event.EventDispatcher.__init__
TypeError: object.__init__() takes exactly one argument (the instance to initialize)
Process finished with exit code 1
At first, you have a mistake in the word 'multiline' in self.LastName and self.Email. Try to fix that.

Why property not accessible in Python?

GenericWidget is needed for rendering low-level elements, such as squares or text. They have a predefined size. Rendering is described in the render function. The Widget class has a build method, which should return the widgets that make up the widget that we make. The context (parent widget) must be passed to the build method. The problem is that when you try to get the widget size, there is a problem that the size parameter does not exist.
Here my example code:
class Widget:
def __init__(self, context):
self.__context__ = context
self.__update_instance__()
def build(self, context):
return NotImplemented
def render(self, xy):
self.__update_instance__()
self.__instance__.render(xy=xy)
def __update_instance__(self):
self.__instance__ = self.build(context=self.__context__)
self.size = self.__instance__.size
class GenericWidget(Widget):
def __init__(self, size):
self.size = size
super(GenericWidget, self).__init__(self)
def build(self, context):
return self
class GenericTest(GenericWidget):
def __init__(self):
super(GenericTest, self).__init__(size=(10, 10))
def render(self, xy):
# all rendering core here
pass
class Test2(Widget):
def build(self, context):
print(context.size)
return GenericTest()
class Test(Widget):
def build(self, context):
return Test2(self)
class OwnWidget(Widget):
def build(self, context):
return Test(self)
class Spacer(GenericWidget):
def __init__(self, size):
super(Spacer, self).__init__(size=size)
OwnWidget(Spacer((100, 100))).render(xy=(0, 0))
Traceback:
Traceback (most recent call last):
File "test.py", line 57, in <module>
OwnWidget(Spacer((100, 100))).render(xy=(0, 0))
File test.py", line 4, in __init__
self.__update_instance__()
File "test.py", line 14, in __update_instance__
self.__instance__ = self.build(context=self.__context__)
File "test.py", line 49, in build
return Test(self)
File "test.py", line 4, in __init__
self.__update_instance__()
File "test.py", line 14, in __update_instance__
self.__instance__ = self.build(context=self.__context__)
File "test.py", line 44, in build
return Test2(self)
File "test.py", line 4, in __init__
self.__update_instance__()
File "test.py", line 14, in __update_instance__
self.__instance__ = self.build(context=self.__context__)
File "test.py", line 38, in build
print(context.size)
AttributeError: 'Test' object has no attribute 'size'
Why size property are not accessible?

How to properly implement inheritance in App Engine with webapp2

Given this simple class:
class RenderResponseHandler(webapp2.RequestHandler):
def __init__(self):
self.nombreUsuario = obtenerUsuarioTablaUsuario().nombre if obtenerUsuarioTablaUsuario() else None
def doRender(self, tname='index.html',values = {}):
temp = os.path.join(os.path.dirname(__file__),
'templates/'+tname)
if not os.path.isfile(temp):
return False
self.nombreUsuario = obtenerUsuarioTablaUsuario().nombre if obtenerUsuarioTablaUsuario() else None
newval = dict(values)
newval['path'] = self.request.path
if nombreUsuario:
url_linktext = 'logout'
else:
url_linktext = 'login'
newval['url_linktext'] = url_linktext
newval['nombreUsuario'] = nombreUsuario
template = jinja_environment.get_template(tname)
outstr = template.render(newval)
self.response.out.write(outstr)
return True
def obtenerPagina(self, pOpcion = None, pMensajeInformacion = None):
opcion = pOpcion if pOpcion is not None else self.request.get('opcion')
if opcion == 'index':
self.doRender('index.html')
####
If I do this, the page shows normally
class MainPage(webapp2.RequestHandler):
def get(self):
r = RenderResponseHandler()
r.request = self.request
r.response = self.response
r.obtenerPagina('index')
Although, When trying to inherit from RenderResponseHandler,like this:
class MainPage(RenderResponseHandler):
def get(self):
if self.doRender(self.request.path):
return
self.obtenerPagina('index')
I get the following exception:
Traceback (most recent call last): File "/home/lucas/Dropbox/Tesis/Revision 2012/Desarrollo/Entorno/AppEngine SDK/google_appengine_1.6.6/lib/webapp2/webapp2.py", line 1536, in
__call__
rv = self.handle_exception(request, response, e) File "/home/lucas/Dropbox/Tesis/Revision 2012/Desarrollo/Entorno/AppEngine SDK/google_appengine_1.6.6/lib/webapp2/webapp2.py", line 1530, in
__call__
rv = self.router.dispatch(request, response) File "/home/lucas/Dropbox/Tesis/Revision 2012/Desarrollo/Entorno/AppEngine SDK/google_appengine_1.6.6/lib/webapp2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response) File "/home/lucas/Dropbox/Tesis/Revision 2012/Desarrollo/Entorno/AppEngine SDK/google_appengine_1.6.6/lib/webapp2/webapp2.py", line 1101, in
__call__
handler = self.handler(request, response) TypeError: __init__() takes exactly 1 argument (3 given)
What am I doing wrong?
Thanks in advance!
You need to implement the __init__ of RenderResponseHandler Like this: def __init__(self, request=None, response=None) and pass request and response to the base class.
The layers that call the request handler class relay on the contract that the ctor will have those paramters.
As it seen below; we can call myfunc function from other Google App Engine class without statament in class definition line. _init _ function is confuses GAE because his initial function is get()
class Test2(webapp2.RequestHandler):
def get(self):
tx=Test()
self.response.out.write(tx.myfunc())
class Test(webapp2.RequestHandler):
def myfunc(self):
return "Hooooooooooooooop"
def get (self,request=None, response=None):
self.response.out.write("test2")

Categories

Resources