I am getting an __initerror - python

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.

Related

How to change the anchor value in MDFloatingActionButtonSpeedDial in KivyMD?

I have been working with kivymd to develop a mobile application. But I was having a problem regarding MDFloatingActionButtonSpeedDial. I wanted to set the anchor value in MDFloatingActionButtonSpeedDial to "left" for some buttons and "right" for some buttons. So I modified the class of MDFloatingActionButtonSpeedDial that is in the module "kivymd.uix.button" and added some more options in 'anchor' which assumes OptionProperty. Along with it I also added the methods required for the applied changes. The changes in acnhor are:-
anchor = OptionProperty('right',option=["right","left"])
And the changes in the methods are:-
def set_pos_labels(self, widget):
"""Sets the position of the floating labels."""
if self.anchor == "right":
widget.x = Window.width - widget.width - dp(86)
elif self.anchor == "left":
widget.x = widget.width + dp(86)
def set_pos_root_button(self, instance):
"""Sets the position of the root button."""
if self.anchor == "right":
instance.y = dp(20)
instance.x = Window.width - (dp(56) + dp(20))
elif self.anchor == "left":
instance.y = dp(20)
instance.x = (dp(56) + dp(20))
def set_pos_bottom_buttons(self, instance):
"""Sets the position of the bottom buttons in a stack."""
if self.anchor == "right":
if self.state != "open":
instance.y = instance.height / 2
instance.x = Window.width - (instance.height + instance.width / 2)
elif self.anchor == "left":
if self.state != "open":
instance.y = instance.height / 2
instance.x = (instance.height + instance.width / 2)
I have added the left anchor property as the right anchor was present by default.
The Builder string that I have written is as follows:-
MDFloatingActionButtonSpeedDial:
data : app.data_download
rotation_root_button : True
id : download_button
icon: 'download'
anchor: 'left'
MDFloatingActionButtonSpeedDial:
data : app.data_return
rotation_root_button: True
icon : 'arrow-left'
anchor: 'right'
Now whenever I tried to set the anchor property to 'left' other than the default option(right) in my builder string file the program returns an error. I want to inform if I set the default value of anchor to left then I get the error for setting the anchor to right and when I set the default value of anchor to right then I get the error for setting the anchor to left. The error that that I am getting is:-
Traceback (most recent call last):
File "C:\Users\user\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 700, in _apply_rule
setattr(widget_set, key, value)
File "kivy\weakproxy.pyx", line 35, in kivy.weakproxy.WeakProxy.__setattr__
File "kivy\properties.pyx", line 497, in kivy.properties.Property.__set__
File "kivy\properties.pyx", line 541, in kivy.properties.Property.set
File "kivy\properties.pyx", line 532, in kivy.properties.Property.set
File "kivy\properties.pyx", line 1252, in kivy.properties.OptionProperty.check
ValueError: MDFloatingActionButtonSpeedDial.anchor is set to an invalid option 'left'. Must be one
of: []
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "onlinecv2.py", line 500, in <module>
ScanIt().run()
File "C:\Users\user\Anaconda3\lib\site-packages\kivy\app.py", line 829, in run
root = self.build()
File "onlinecv2.py", line 435, in build
camerascreen = Builder.load_string(screen_helper)
File "C:\Users\user\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 405, in load_string
rule_children=rule_children)
File "C:\Users\user\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 707, in _apply_rule
e), cause=tb)
kivy.lang.builder.BuilderException: Parser: File "<inline>", line 154:
...
152: id : download_button
153: icon: 'download'
>> 154: anchor: 'left'
155:
156:
...
ValueError: MDFloatingActionButtonSpeedDial.anchor is set to an invalid option 'left'. Must be one
of: []
File "C:\Users\user\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 700, in _apply_rule
setattr(widget_set, key, value)
File "kivy\weakproxy.pyx", line 35, in kivy.weakproxy.WeakProxy.__setattr__
File "kivy\properties.pyx", line 497, in kivy.properties.Property.__set__
File "kivy\properties.pyx", line 541, in kivy.properties.Property.set
File "kivy\properties.pyx", line 532, in kivy.properties.Property.set
File "kivy\properties.pyx", line 1252, in kivy.properties.OptionProperty.check
The output that I am getting (which is undesirable) when i dont set any anchor value in my kivy file is as:-
I only get the floating button in the right. But the output that I desire is I wanted two floating buttons to be present on both side of the screen i.e. left as well as right. But I am getting only on one side and so i started to change the module but ended up with an error.
So, I would be glad if you can provide me an solution to solve this error so that I can use both the anchor properties 'left' and 'right'.

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.

Kivy - How to access kivy widget in python?

I want to edit a text in a TextInput in kivy but don't know how to, I've tried this code as Ive search in the net but still no luck.
class MainApp(Screen):
def __init__(self,**kwargs):
super(MainApp,self).__init__(**kwargs)
pass
class Forms(BoxLayout):
def __init__(self, **kwargs):
super(Main,self).__init__(**kwargs)
self.ids.txtSearch.text = "new text"
class Main(App):
def build(self):
return root_widget
if __name__ == "__main__":
Main().run()
------kivy-------
<Main>:
TextInput:
id: txtSearch
this is not my whole code but I think those are what matters in the issue
this is the error:
File "C:\Users\Guest\Documents\Python\Kivy\Project\main.py", line 295, in <module>
''')
File "D:\Kivy-1.9.0-py3.4-win32-x64\kivy34\kivy\lang.py", line 1828, in load_string
self._apply_rule(widget, parser.root, parser.root)
File "D:\Kivy-1.9.0-py3.4-win32-x64\kivy34\kivy\lang.py", line 1985, in _apply_rule
self.apply(child)
File "D:\Kivy-1.9.0-py3.4-win32-x64\kivy34\kivy\lang.py", line 1872, in apply
self._apply_rule(widget, rule, rule)
File "D:\Kivy-1.9.0-py3.4-win32-x64\kivy34\kivy\lang.py", line 1986, in _apply_rule
self._apply_rule(child, crule, rootrule)
File "D:\Kivy-1.9.0-py3.4-win32-x64\kivy34\kivy\lang.py", line 1986, in _apply_rule
self._apply_rule(child, crule, rootrule)
File "D:\Kivy-1.9.0-py3.4-win32-x64\kivy34\kivy\lang.py", line 1983, in _apply_rule
child = cls(__no_builder=True)
File "C:\Users\Guest\Documents\Python\Kivy\Project\main.py", line 40, in __init__
self.ids.txtSearch.text = "new text"
File "kivy\properties.pyx", line 720, in kivy.properties.ObservableDict.__getattr__ (kivy\properties.c:10911)
AttributeError: 'super' object has no attribute '__getattr__'
To change Widgets properties in kivy you need to 'link' the widget between .py and .kv file, first in .py file:
txt_Search = ObjectProperty()
then in .kv file, in your root widget:
txt_Search: txtSearch
then assign the id to a widget (as you already did):
<Main>:
TextInput:
id: txtSearch
text: ' '
then in your .py file, you can change attributes of the widget by doing this:
self.txt_Search.text = 'New Text'
or any other attribute:
self.txt_Search.height = '30dp'
Are you sure self.ids.txtSearch exists when you try to assign a text to it? You're calling super(Main,self) one line above so I guess txtSearch is never instantiated.
Btw, it's better to init widgets in *.kv files:
<Main>:
TextInput:
id: txtSearch
text: "new text"

Kivy Property not Callable Error

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.

TypeError for pickle of array of custom objects in Python

I have the following method:
def save(self):
vertices = self.mindmap.get_vertices()
edges = self.mindmap.get_edges()
output = open('mindmap.pkl', 'wb')
pickle.dump(edges, output)
pickle.dump(vertices, output)
output.close()
When I call this method, I get the following error:
Traceback (most recent call last):
File "main.py", line 72, in <module>
MindMapApp().run()
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/app.py", line 792, in run
runTouchApp()
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 481, in runTouchApp
EventLoop.window.mainloop()
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/core/window/window_pygame.py", line 381, in mainloop
self._mainloop()
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/core/window/window_pygame.py", line 287, in _mainloop
EventLoop.idle()
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 324, in idle
self.dispatch_input()
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 309, in dispatch_input
post_dispatch_input(*pop(0))
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 275, in post_dispatch_input
wid.dispatch('on_touch_up', me)
File "_event.pyx", line 316, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:4537)
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/uix/behaviors.py", line 110, in on_touch_up
self.dispatch('on_release')
File "_event.pyx", line 312, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:4491)
File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/lang.py", line 1299, in custom_callback
exec(__kvlang__.co_value, idmap)
File "./mindmap.kv", line 14, in <module>
on_release: app.save()
File "main.py", line 27, in save
pickle.dump(vertices, output)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1370, in dump
Pickler(file, protocol).dump(obj)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
self.save(obj)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 600, in save_list
self._batch_appends(iter(obj))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 615, in _batch_appends
save(x)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save
rv = reduce(self.proto)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 71, in _reduce_ex
state = base(self)
TypeError: __init__() takes exactly 0 positional arguments (1 given)
I do not get this error if both arrays are empty. When the above was generated edges was empty and vertices had a size of one. I really don't know how to interpret this error, and as such have no idea how to resolve it.
This is my Vertex class __init__:
def __init__(self, pos=None, size=None):
super(Vertex, self).__init__()
self.pos = pos
self.size = size
if self.height < self.MINIMUM_HEIGHT + self.TEXT_OFFSET:
self.height = self.MINIMUM_HEIGHT + self.TEXT_OFFSET
if self.width < self.MINIMUM_WIDTH + self.TEXT_OFFSET:
self.width = self.MINIMUM_WIDTH + self.TEXT_OFFSET
self.originalSize = self.size
self.originalWidth = self.size[0]
self.newIdea = TextInput(
height = self.MINIMUM_HEIGHT,
size_hint = (None, None),
pos_hint = {'center_x':.5, 'center_y':.5},
background_active = '',
background_normal = '',
use_bubble = True,
foreground_color = (.4, .4, .4, 1),
cursor_color = (.4, .4, .4, 1))
self.newIdea.bind(text=self.on_text)
self.idea = Label(
height = self.MINIMUM_HEIGHT,
size_hint = (None, None),
pos_hint = {'center_x':.5, 'center_y':.5},
color = (.4, .4, .4,1))
Logger.info('Vertex: created')
Indeed, the Kivy EventDispatcher object is at fault here; the object.__reduce_ex__ method searches for the first baseclass that is not a custom class (it does not have the Py_TPFLAGS_HEAPTYPE flag set), to call __init__ on that class. This fails for that base class, as it's __init__ method doesn't support passing in a single argument.
The work-around is to use the latest pickle protocol instead; it uses a different codepath:
pickle.dump(edges, output, pickle.HIGHEST_PROTOCOL)
pickle.dump(vertices, output, pickle.HIGHEST_PROTOCOL)
because the latest pickle protocol (2) supports new-style classes much more efficiently.
Seeing the complexity of the Kivy object hierarchy, you may need to customise the pickling process.
I'd look into implementing the __getnewargs__ method for example:
def __getnewargs__(self):
return (self.pos, self.size)
would ensure that just that data is pickled, nothing more. On unpickling, these two values are then used to create new Vertex objects. Note that for this method to be used you have to use the latest protocol!
You could also implement a __getstate__ method; if you return a dictionary, no mirror __setstate__ method is required, but would allow you to initialise some more attributes.
If neither is implemented, the contents of the instance __dict__ is pickled instead. Make sure that everything contained can be pickled.

Categories

Resources