I am trying to create a program containing various drop down menus and writable fields. To simplify adding new menus and writable fields i wanted to loop over a list of tuples containing the information required to create dynamic variable names and the menus.
The problem i am running into is when running the below code where 'name' is the string "Percentage". It should be noted that the code works if i remove 'validate' and 'validatecommand', though obviously the validation isn't done.
def number_validate(char):
return char.isdigit()
self.percentage_validification = self.root.register(number_validate)
exec("self." + name + "_box" + " = " + "tkinter.Entry(self.root, validate = 'key', self.validatecommand = (self.validation, '%S'))")
The above code gives the following error:
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
The following code gives the correct output but does not allow dynamic variable naming and creation, which indicates that it is not a problem with the command itself:
self.Percentage_box = tkinter.Entry(self.root, validate = "key", validatecommand = (self.percentage_validification, '%S'))
I assume my problem relates to improper handling of strings in the exec function, but i simply can't figure out how is should be done. Does anyone have an answer.
Related
PyPDF2 update page form field values function working fine with hardcoded strings but nothing shows if using variable text.
I have tried using string variables like this
writer.update_page_form_field_values(
#writer.pages[0], {"Piece Weight": variableString} doesn't work
writer.pages[0], {"Piece Weight": "hardcoded string"}#works
)
as well as like this
writer.update_page_form_field_values(
#writer.pages[0], {"Piece Weight": f"{variableString}"} doesn't work
writer.pages[0], {"Piece Weight": "hardcoded string"}#works
)
I am expecting the final output file to show the text I store into a string variable within the field named "piece weight" but what actually happens is absolutely no data is displayed on in the field when a variable is applied to it.
UPDATE-
found that my issue was not that it refuses to show variable data, rather it was a matter of, my variable data not being updated after it is initialized. I am creating it at one point
variablestring = ""
and then later in the code i am attempting to change it within a function
def onStart():
variablestring = variableEntry.get()
This is an issue of scope as the variablestring within the function and outside the function are seen as separate memory spaces.
there in lies an issue however, I can not pass this function parameters as it needs to be automatically called by a
tkinter.Button(form, text="start", command=onStart)
Final answer to my issue was to use the global tag to call the variable outside of the function into it.
variable = "te"
def onStart():
global variable
variable = variableEntry.get()
when reading about globals for python i misunderstood it as a declarative global and not a call global
I am trying create a node and set a value using this function:
def createTextureNode(textureNode):
keyword = textureNode
for fname in os.listdir(assetFilePath):
if keyword in fname:
texFilename = fname + ".tex"
newTexNode = NodegraphAPI.CreateNode("PrmanShadingNode", rootNode)
newTexNode.getParameter('name').setValue(assetCode + '_' + textureNode, 0)
newTexNode.getParameter('nodeType').setValue("PxrTexture", 0)
newTexNode = NodegraphAPI.GetNode(assetCode + '_' + textureNode)
if textureNode == "Albedo":
newTexNode.getParameter("parameters.linearize.enable").setValue(True,0)
newTexNode.getParameter("parameters.linearize.value").setValue(True,0)
Its pretty simple, if a particular file exists it will create a node for it. However, I am unable to set the "linearize" value (or any other value under the "parameters" group)
If I manually create a node and manually set it to be a PxrTexture and use this code:
node = NodegraphAPI.GetNode("PrmanShadingNode")
node.getParameter("parameters.linearize.enable").setValue(1,0)
node.getParameter("parameters.linearize.value").setValue(1,0)
Then it works, the check box turns on, but if I set the nodeType via script then it fails. But if I run it a second time it works! The error I keep getting is:
AttributeError: 'NoneType' object has no attribute 'setValue'
I know this means that its returning "None" but the tool tip in Katana says that its "parameters.linearize" and the first two parameters were able to be set... but these are under a Group, I think?
Since it works with the manual create, it must be something I am missing in my script, but I can not figure it out. I have also tried using finalizeValue after setting my nodeType but his has no affect
I am using this as my reference:
Getting and Setting Parameters
GOT IT!
When setting a Dynamic Parameter Pragmatically, you have to run checkDynamicParameters() after you set the value that makes the new parameters appear
This updates the UI Loop and makes the new parameters available. When doing this via the UI, it happens on the fly, and thats why it works when doing it manually
ANSWER REFERENCE
I am attempting to use a module called interface.py which defines a list of conditions and a few functions to check arguments against those conditions. There are many thousands of conditions however, and so I want to use a dictionary instead of a list to prevent needing to look at all of them. To do this I'm using the following code:
def listToDictionary(list):
"""This function takes a list of conditions and converts it to a dictionary
that uses the name of the condition as a key."""
d = {}
for condition in list:
if condition.name.lower() not in d:
d[condition.name.lower()] = []
d[condition.name.lower()].append(condition)
return d
conditionList = listToDictionary(conditions.list) #the condition list comes from another module
Further into the file are the actual interface functions that take arguments to compare with the list of conditions - these functions are written assuming that conditionList will be a dictionary.
Unfortunately this isn't working. Giving error details is difficult because this code is being imported by a django page and I am trying to avoid talking about django so this question stays uncomplicated. Essentially the pages including this code will not load, and if I change it back to just using a list everything works fine.
My suspicion is that the problem has to do with how Python treats import statements. I need the listToDictionary conversion to run as soon as interface.py is imported, otherwise the interface functions will expect a dictionary and get a list instead. Is there any way to ensure that this is happening?
An educated guess: the list in conditions.list is not yet fully constructed when your module is being imported. As a result, you get a dictionary that is missing some entries or even empty, which is causing problems later. Try deferring the construction of the dict, like this:
conditionTable = None # shouldn't call it list if it's a dict
def get_cond_table():
global conditionTable
if conditionTable is None:
conditionTable = listToDictionary(conditions.list)
return conditionTable
Instead of referring to conditionList in your functions, refer to get_cond_table().
Alright, I found out that the problem was in another function that was still expecting the dictionary to be a list. The reason I couldn't see it right away is that Django left a very cryptic error message. I was able to get a better one using python manage.py shell and importing the module manually.
Thanks for your help everyone.
Following the advice given in;
Calling an external command in Python
I have been experimenting using the call() function to call an external command, however the command I need to call is being called correctly but it does not like the parameters being passed to it.
This is because the Call function is passing the parameters with ' 's around them.
E.g
test = call(['/opt/program/something/lookup', 'search "bob"'])
The search part must be passed to the command lookup without any characters surrounding it, I have tried a few different permutations of the call function with varying levels of quotes, spaces, lack of commas etc. The second statement - bob, must be within quotes.
Is there a clean way to do this?
Example of return value of test atm;
Error: 'search "bob"' is not a valid command.
This should work - if not then please update the question with specific error text:
test = call(['/opt/program/something/lookup', 'search', '"bob"'])
I wrote a class that lets me pass in a list of variable types, variable names, prompts, and default values. The class creates a wxPython panel, which is displayed in a frame that lets the user set the input values before pressing the calculate button and getting the results back as a plot. I add all of the variables to the class using exec statements. This keeps all of the variables together in one class, and I can refer to them by name.
light = Variables( frame , [ ['f','wavelength','Wavelength (nm)',632.8] ,\
['f','n','Index of Refraction',1.0],])
Inside the class I create and set the variables with statments like:
for variable in self.variable_list:
var_type,var_text_ctrl,var_name = variable
if var_type == 'f' :
exec( 'self.' + var_name + ' = ' + var_text_ctrl.GetValue() )
When I need to use the variables, I can just refer to them by name:
wl = light.wavelength
n = light.n
Then I read on SO that there is rarely a need to use exec in Python. Is there a problem with this approach? Is there a better way to create a class that holds variables that should be grouped together, that you want to be able to edit, and also has the code and wxPython calls for displaying, editing, (and also saving all the variables to a file or reading them back again)?
Curt
You can use the setattr function, which takes three arguments: the object, the name of the attribute, and it's value. For example,
setattr(self, 'wavelength', wavelength_val)
is equivalent to:
self.wavelength = wavelength_val
So you could do something like this:
for variable in self.variable_list:
var_type,var_text_ctrl,var_name = variable
if var_type == 'f' :
setattr(self, var_name, var_text_ctrl.GetValue())
I agree with mipadi's answer, but wanted to add one more answer, since the Original Post asked if there's a problem using exec. I'd like to address that.
Think like a criminal.
If your malicious adversary knew you had code that read:
exec( 'self.' + var_name + ' = ' + var_text_ctrl.GetValue() )
then he or she may try to inject values for var_name and var_text_ctrl that hacks your code.
Imagine if a malicious user could get var_name to be this value:
var_name = """
a = 1 # some bogus assignment to complete "self." statement
import os # malicious code starts here
os.rmdir('/bin') # do some evil
# end it with another var_name
# ("a" alone, on the next line)
a
"""
All of the sudden, the malicious adversary was able to get YOU to exec[ute] code to delete your /bin directory (or whatever evil they want). Now your exec statement roughly reads the equivalent of:
exec ("self.a=1 \n import os \n os.rmdir('/bin') \n\n "
"a" + ' = ' + var_text_ctrl.GetValue() )
Not good!!!
As you can imagine, it's possible to construct all sorts of malicious code injections when exec is used. This puts the burden onto the developer to think of any way that the code can be hacked - and adds unnecessary risk, when a risk-free alternative is available.
For the security conscious, there might be an acceptable alternative. There used to be a module call rexec that allowed "restricted" execution of arbitrary python code. This module was removed from recent python versions. http://pypi.python.org/pypi/RestrictedPython is another implementation by the Zope people that creates a "restricted" environment for arbitrary python code.
The module was removed because it had security issues. Very difficult to provide an environment where any code can be executed in a restricted environment, with all the introspection that Python has.
A better bet is to avoid eval and exec.
A really off-the-wall idea is to use Google App Engine, and let them worry about malicious code.