Related
I have a problem with my Plone item I cannot solve. 'Car' is supposed to create a list of all instances of 'Colour'.
All 'Colour' instances are in a given container. I cannot make it static because I want to add more 'Colour' instances in the future.
I tried selecting each item in my container and add it to my vocabularylist. I only need the id/title of my object, but I always end up with a giant stacktrace of failures.
In the end I want to choose a colour out of the given instances on creating a new 'Car' instance similar to a dropdown.
I have read the docs but cannot find a solution and this is my best idea.
I am also not a python programmer and this is my first plone project. I can add the complete failure list later if you need it.
I appreciate every bit of help. Thank you.
```colour= schema.Choice(
title=u"Colour",
description=u"Paintjob",
vocabulary=givecolour(),
required=False
)
#provider(IContextSourceBinder)
def givecolour():
colourlist = self.context.portal_catalog(path={"query" : "/madb-entw/it/colourcontainer", "depth" : 1})
list = []
i = 0
for colour in colourlist:
list.append(
SimpleVocabulary.createTerm(
colourlist.[i].getObject().id
)
)
i += 1
return SimpleVocabulary(list)```
Please always add your traces, so that we can help you better.
There is also the official community.plone.org forum, where are more people can help you.
I recommend you to use the plone.api to find your objects, this is a bit easier and well doumented.
something like this:
from plone import api
color_brains = api.content.find(context=api.content.get(path='/madb-entw/it/colourcontainer'), depth=1, portal_type='Color')
# no need to do getOject() here, get the id/title directly from the catalog brain
colors = [(color.id, color.Title) for color in color_brains]
One note to your query:
colourlist = self.context.portal_catalog(path={"query" :
"/madb-entw/it/colourcontainer", "depth" : 1})
Path has to be absolute, which means it includes the Plone site id and this can be different in another Plone site.
So an absolute path is not a good idea here, better get the portal object and traverse your path relative from there.
If madb-entw is your Plone site id:
portal.restrictedTraverse('it/colourcontainer')
or better as above, use plone.api.content.get(path='/it/colourcontainer')
Which is cleaner and easier.
On every Tkinter notebook tab, there is a list of checkbuttons and the variables get saved to their corresponding v[ ] (i.e. cb.append(Checkbuttons(.., variables = v[x],..)).
For now, I am encountering this error:
File "/home/pass/OptionsInterface.py", line 27, in __init__
self.ntbk_render(f = self.f1, ntbkLabel="Options",cb = optsCb, msg = optMsg)
File "/home/pass/OptionsInterface.py", line 59, in ntbk_render
text = msg[x][1], command = self.cb_check(v, opt)))
File "/home/pass/OptionsInterface.py", line 46, in cb_check
opt[ix]=(v[ix].get())
IndexError: list assignment index out of range
And I think the error is coming here. I don't know how to access the values of the checkbutton variables.
def cb_check(self, v = [], cb = [], opt = []):
for ix in range(len(cb)):
opt[ix]=(v[ix].get())
print opt
Here are some snippets:
def cb_check(self, v = [], cb = [], opt = []):
for ix in range(len(cb)):
opt[ix]=(v[ix].get())
print opt
def ntbk_render(self, f=None, ntbkLabel="", cb = [], msg = []):
v = []
opt = []
msg = get_thug_args(word = ntbkLabel, argList = msg) #Allows to get the equivalent list (2d array)
#to serve as texts for their corresponding checkboxes
for x in range(len(msg)):
v.append(IntVar())
off_value = 0
on_value = 1
cb.append(Checkbutton(f, variable = v[x], onvalue = on_value, offvalue = off_value,
text = msg[x][1], command = self.cb_check(v, opt)))
cb[x].grid(row=self.rowTracker + x, column=0, sticky='w')
opt.append(off_value)
cb[-1].deselect()
After solving the error, I want to get all the values of the checkbutton variables of each tab after pressing the button Ok at the bottom. Any tips on how to do it will help!
Alright, so there’s a bit more (… alright, maybe a little more than a bit…) here than I intended, but I’ll leave it on the assumption that you’ll simply take away from it what you need or find of value.
The short answer is that when your Checkbutton calls cb_check, it’s passing the arguments like this:
cb_check(self = self, v = v, cb = opt, opt = [])
I think it’s pretty obvious why you’re getting an IndexError when we write it out like this: you’re using the length of your opt list for indexes to use on the empty list that the function uses when opt is not supplied; in other words, if you have 5 options, the it will try accessing indices [0…4] on empty list [] (obviously, it stops as soon as it fails to access Index 0). Your function doesn’t know that the thing you’re passing it are called v and opt: it simply takes some random references you give it and places them in the order of the positional arguments, filling in keyword arguments in order after that, and then fills out the rest of the keyword arguments with whatever defaults you told it to use.
Semi-Quick Aside:
When trying to fix an error, if I have no idea what went wrong, I would start by inserting a print statement right before it breaks with all the references that are involved in the broken line, which will often tell you what references do not contain the values you thought they had. If this looks fine, then I would step in further and further, checking any lookups/function returns for errors. For example:
def cb_check(self, v = [], cb = [], opt = []):
for ix in range(len(cb)):
print(ix, opt, v) ## First check, for sanity’s sake
print(v[ix]) ## Second Check if I still can’t figure it out, but
## this is a lookup, not an assignment, so it
## shouldn’t be the problem
print(v[ix].get()) ## Third Check, again, not an assignment
print(opt[ix]) ## “opt[ix]={something}” is an assignment, so this is
## (logically) where it’s breaking. Here we’re only
## doing a lookup, so we’ll get a normal IndexError
## instead (it won’t say “assignment”)
opt[ix]=(v[ix].get()) ##point in code where IndexError was raised
The simple fix would be to change the Checkbutton command to “lambda: self.cb_check(v,cb,opt)” or more explicitly (so we can do a sanity check) “lambda: self.cb_check(v = v, cb = cb, opt = opt).” (I’ll further mention that you can change “lambda:” to “lambda v = v, cb = cb, opt = opt:” to further ensure that you’ll forever be referring to the same lists, but this should be irrelevant, especially because of changes I’ll suggest below)
[The rest of this is: First Section- an explicit explanation of what your code is doing and a critique of it; second section- an alternative approach to how you have this laid out. As mentioned, the above fixes your problem, so the rest of this is simply an exercise in improvement]
In regards to your reference names-
There’s an old adage “Code is read much more often than it is written,” and part of the Zen of Python says: “Explicit is better than Implicit.[…] Readability counts.” So don’t be afraid to type a little bit more to make it easier to see what’s going on (same logic applies to explicitly passing variables to cb_check in the solution above). v can be varis; cb can be cbuttons; ix would be better (in my opinion) as ind or just plain index; f (in ntkb_render) should probably be parent or master.
Imports-
It looks like you’re either doing star (*) imports for tkinter, or explicitly importing parts of it. I’m going to discourage you from doing either of these things for two reasons. The first is the same reason as above: if only a few extra keystrokes makes it easier to see where everything came from, then it’s worth it in the long run. If you need to go through your code later to find every single tkinter Widget/Var/etc, then simply searching “tk” is a lot easier than searching “Frame” then “Checkbutton” then IntVar and so on. Secondly, imports occasionally clash: so if- for example- you do
import time ## or from time import time, even
from datetime import time
life may get kinda hairy for you. So it would be better to “import tkinter as tk” (for example) than the way you are currently doing it.
cb_check-
There are a few things I’ll point out about this function:
1) v, cb, and opt are all required for the function to work correctly; if the empty list reference is used instead, then it’s going to fail unless you created 0 Checkbuttons (because there wouldn’t be anything to iterate over in the “for loop”; regardless, this doesn’t seem like it should ever happen). What this means is that they’re better off simply being positional arguments (no default value). Had you written them this way, the function would have given you an error stating that you weren’t giving it enough information to work with rather than a semi-arbitrary “IndexError.”
2) Because you supply the function with all the information it needs, there is no practical reason (based on the code supplied, at any rate) as to why the function needs to be a method of some object.
3) This function is being called each time you select a Checkbutton, but reupdates the recorded values (in opt) of all the Checkbuttons (instead of just the one that was selected).
4) The opt list is technically redundant: you already have a reference to a list of all the IntVars (v), which are updated/maintained in real time without you having to do anything; it is basically just as easy to perform v[ix].get() as it is to do opt[ix]: in exchange for the “.get()” call when you eventually need the value you have to include a whole extra function and run it repeatedly to make sure your opt list is up to date. To complicate matters further, there’s an argument for v also being redundant, but we’ll get to that later.
And as an extra note: I’m not sure why you wrapped the integer value of your IntVar (v[ix].get()) with parentheses; they seem extraneous, but I don’t know if you’re trying to cast the value in the same manner as C/Java/etc.
ntbk_render-
Again, notice that this function is given nearly everything it needs to be executed, and therefore feels less like a method than a stand-alone function (at this moment; again, we’ll get to this at the end). The way it’s setup also means that it requires all of that information, so they would better off as positional argument as above.
The cb reference-
Unlike v and opt, the cb reference can be supplied to the function. If we follow cb along its path through the code, we’ll find out that its length must always be equal to v and opt. Assumedly, the reason we may want to pass cb to this method but not v or opt is because we only care about the reference to cb in the rest of our code. However, notice that cb is always an empty iterable with an append method (seems safe to assume it will always be an empty list). So either we should be testing to make sure that it’s empty before we start doing anything with it (because it will break our code if it isn’t), or we should just create it at the same time that we’re creating v and opt. Not knowing how your code is set up, I personally would think it would be easiest to initialize it alongside the other two and then simply return it at the end of the method (putting “return cb” at the end of this function and “cb=[whatever].ntbk_render(f = someframe, ntbklabel = “somethug”, msg = argList)”). Getting back to the redundancy of opt and v (point 4 in cb_check), since we’re keeping all the Checkbuttons around in cb, we can use them to access their IntVars when we need to.
msg-
You pass msg to the function, and then use it to the value of “argList” in get_thug_args and replace it with the result. I think it would make more sense to call the keyword that you pass the ntbk_render “argList” because that’s what it is going to be used for, and then simply let msg be the returned value of get_thug_args. (The same line of thought applies to the keyword “ntbkLabel”, for the record)
Iterating-
I’m not sure if using an Index Reference (x) is just a habit picked up from more rigid programing languages like C and Java, but iterating is probably one of my favorite advantages (subjective, I know) that Python has over those types of languages. Instead of using x, to get your option out of msg, you can simply step through each individual option inside of msg. The only place that we run into insurmountable problems is when we use self.rowTracker (which, on the subject, is not updated in your code; we’ll fix that for now, but as before, we’ll be dealing with that later). What we can do to amend this is utilize the enumerate function built into Python; this will create a tuple containing the current index followed by the value at the iterated index.
Furthermore, because you’re keeping everything in lists, you have to keep going back to the index of the list to get the reference. Instead, simply create references to the things (datatypes/objects) you are creating and then add the references to the lists afterwards.
Below is an adjustment to the code thus far based on most of the things I noted above:
import tkinter as tk ## tk now refers to the instance of the tkinter module that we imported
def ntbk_render(self, parent, word, argList):
cbuttons=list() ## The use of “list()” here is purely personal preference; feel free to
## continue with brackets
msg = get_thug_args(word = word, argList=argList) ## returns a 2d array [ [{some value},
## checkbutton text,…], …]
for x,option in enumerate(msg):
## Each iteration automatically does x=current index, option=msg[current_index]
variable = tk.IntVar()
## off and on values for Checkbuttons are 0 and 1 respectively by default, so it’s
## redundant at the moment to assign them
chbutton=tk.Checkbutton(parent, variable=variable, text=option[1])
chbutton.variable = variable ## rather than carrying the variable references around,
## I’m just going to tack them onto the checkbutton they
## belong to
chbutton.grid(row = self.rowTracker + x, column=0, sticky=’w’)
chbutton.deselect()
cbuttons.append(chbutton)
self.rowTracker += len(msg) ## Updating the rowTracker
return cbuttons
def get_options(self, cbuttons):
## I’m going to keep this new function fairly simple for clarity’s sake
values=[]
for chbutton in cbuttons:
value=chbutton.variable.get() ## It is for this purpose that we made
## chbutton.variable=variable above
values.append(value)
return values
Yes, parts of this are a bit more verbose, but any mistakes in the code are going to be much easier to spot because everything is explicit.
Further Refinement
The last thing I’ll touch on- without going into too much detail because I can’t be sure how much of this was new information for you- is my earlier complaints about how you were passing references around. Now, we already got rid of a lot of complexity by reducing the important parts down to just the list of Checkbuttons (cbuttons), but there are still a few references being passed that we may not need. Rather than dive into a lot more explanation, consider that each of these Notebook Tabs are their own objects and therefore could do their own work: so instead of having your program add options to each tab and carry around all the values to the options, you could relegate that work to the tab itself and then tell it how or what options to add and ask it for its options and values when you need them (instead of doing all that work in the main program).
relative noob here! I'm running 2.7, if that helps.
I'm trying to call a function defined in my main application class in a different function (I think that's called inheritance?) But I keep having problems with the number of args I put into my function!
Here's the function (is it called a method? if not, what's a method) I'm trying to call:
def student_list_updater(self, list):
self.StudentListDisplay.delete(0, END)
for student in list:
self.StudentListDisplay.insert(END, student)
And here's the function I'm calling it in (it's inheriting student_list_updater, right?):
def OnRemoveClick(self, student_list_updater):
self.student_list_updater = student_list_updater
index = self.StudentListDisplay.curselection()
index = int(index[0])
del student_list_temp[index]
self.student_list_updater(student_list_temp)
Thank you for the help in advance!
It's a little difficult to understand your question without more of the code, but hopefully this answer points you in the right direction.
First, to clarify, methods are just functions that can be accessed through an instance of a class, so yes, these are methods, but they're also functions--don't get too hung up on it. Next, I don't think inheritance is necessary here--inheritance will be one class inheriting attributes from another, and I believe all of your methods are only in one class (correct me if I'm mistaken).
Now, as to your code: it's giving you an error that one of your methods takes a number of arguments, and you gave it a different number. Well, to me, it looks like you only need to pass one argument for this whole process: student_list_temp to student_list_updater(). Once again, I can't say for sure that this will solve your problems, based on the lack of code you posted, but this might work:
def student_list_updater(self, studentlist): #change list to studentlist,
self.StudentListDisplay.delete(0, END) #Python already has a list() method
for student in studentlist:
self.StudentListDisplay.insert(END, student)
def OnRemoveClick(self): #Remove student_list_updater from the args, it has no value
#self.student_list_updater = student_list_updater #this doesn't do anything
index = self.StudentListDisplay.curselection() #This part I can't really comment on
index = int(index[0]) #without knowing the contents of the
del student_list_temp[index] #Listbox and student_list_temp,
self.student_list_updater(student_list_temp) #but this should call student_list_updater()
#and update the Listbox if it's working
The last thing I want to point out is how you call OnRemoveClick() will probably change. If you're calling it from a Button, it would look like this:
self.btn = Button(self, text='GO', command=self.OnRemoveClick)
Note that you're not passing any arguments to it.
Hope that helps. You also might want to take a look at https://docs.python.org/2/tutorial/classes.html and https://docs.python.org/2/tutorial/modules.html to clear up any classes and functions questions you might have.
I want a function that can return the variable/object name as str like this :
def get_variable_name (input_variable):
## some codes
>>get_variable_name(a)
'a'
>>get_variable_name(mylist)
'mylist'
it looks like silly but i need the function to construct expression regarding to the variable for later on 'exec()'. Can someone help on how to write the 'get_variable_name' ?
I've seen a few variants on this kind of question several times on SO now. The answer is don't. Learn to use a dict anytime you need association between names and objects. You will thank yourself for this later.
In answer to the question "How can my code discover the name of an object?", here's a quote from Fredrik Lundh (on comp.lang.python):
The same way as you get the name of that cat you found on your porch:
the cat (object) itself cannot tell you its name, and it doesn’t
really care — so the only way to find out what it’s called is to ask
all your neighbours (namespaces) if it’s their cat (object)…
….and don’t be surprised if you’ll find that it’s known by many names,
or no name at all!
Note: It is technically possible to get a list of the names which are bound to an object, at least in CPython implementation. If you're interested to see that demonstrated, see the usage of the inspect module shown in my answer here:
Can an object inspect the name of the variable it's been assigned to?
This technique should only be used in some crazy debugging session, don't use anything like this in your design.
In general it is not possible. When you pass something to a function, you are passing the object, not the name. The same object can have many names or no names. What is the function supposed to do if you call get_variable_name(37)? You should think about why you want to do this, and try to find another way to accomplish your real task.
Edit: If you want get_variable_name(37) to return 37, then if you do a=37 and then do get_variable_name(a), that will also return 37. Once inside the function, it has no way of knowing what the object's "name" was outside.
def getvariablename(vara):
for k in globals():
if globals()[k] == vara:
return k
return str(vara)
may work in some instance ...but very subject to breakage... and I would basically never use it in any kind of production code...
basically I cant think of any good reason to do this ... and about a million not to
Here's a good start, depending on the Python version and runtime you might have to tweak a little. Put a break point and spend sometime to understand the structure of inspect.currentframe()
import inspect
def vprint(v):
v_name = inspect.currentframe().f_back.f_code.co_names[3]
print(f"{v_name} ==> {v}")
if __name__ == '__main__':
x = 15
vprint(x)
will produce
x ==> 15
if you just want to return the name of a variable selected based on user input... so they can keep track of their input, add a variable name in the code as they make selections in addition to the values generated from their selections. for example:
temp = raw_input('Do you want a hot drink? Type yes or no. ')
size = raw_input('Do you want a large drink? Type yes or no. ')
if temp and size == 'yes':
drink = HL
name = 'Large cafe au lait'
if temp and size != 'yes':
drink = CS
name = 'Small ice coffee'
print 'You ordered a ', name, '.'
MJ
If your statement to be used in exec() is something like this
a = ["ddd","dfd","444"]
then do something like this
exec('b = a = ["ddd","dfd","444"]')
now you can use 'b' in your code to get a handle on 'a'.
Perhaps you can use traceback.extract_stack() to get the call stack, then extract the variable name(s) from the entry?
def getVarName(a):
stack = extract_stack()
print(stack.pop(-2)[3])
bob = 5
getVarName(bob);
Output:
getVarName(bob)
I'm trying to dynamically create buttons at runtime with PyQT4.7
However, this being my first python program I'm not sure how to get the functionality I want.
I would like to be able to substitute a text string for an attribute name:
i.e.
for each in xrange(4):
myname = "tab1_button%s" % each #tab1_button0, tab1_button1, tab1_button2
#self.ui.tab1_button0 = QtGui.QPushButton(self.ui.tab) <--normal code to create a named button
setattr(self.ui,myname,QtGui.QPushButton(self.ui.tab)) #rewrite of line above to dynamicly generate a button
#here's where I get stuck. this code isn't valid, but it shows what i want to do
self.ui.gridLayout.addWidget(self.ui.%s) % myname
#I need to have %s be tab1_button1, tab1_button2, etc. I know the % is for string substituion but how can I substitute the dynamically generated attribute name into that statement?
I assume there's a basica language construct I'm missing that allows this. Since it's my first program, please take it easy on me ;)
If I interpreted this correctly, I think what you want is this:
self.ui.gridLayout.addWidget(getattr(self.ui,myname))
Give that a go. In Python the following two statements are functionally equivalent (from the link below):
value = obj.attribute
value = getattr(obj, "attribute-name")
For extra context:
http://effbot.org/zone/python-getattr.htm
Just assign the button to a variable so you can both set the attribute and add the widget.
for i in range(4):
name = 'button%d' % i
button = QtGui.QPushButton(...)
setattr(self, name, button)
self.ui.gridLayout.addWidget(button)
Personally I would add the buttons to a list instead of giving them different names.
I think you might benefit from knowledge of lists (commonly called arrays in other languages)
self.buttons = [None, None, None, None]
for each in xrange(4):
self.buttons[each] = QtGui.QPushButton(self.ui.tab)
self.ui.gridLayout.addWidget(self.buttons[each])
For a tutorial on Python lists:
http://effbot.org/zone/python-list.htm