Using exec() to get class instances - python

I have a class and I need to use string input to create it and I've heard about exec(), so I tried using that and I put the string in properly yet it gives me errors, this is the exec line:
exec(" ".join(args[2:])).toString()
The first 2 parts of the list are not relevant. I debugged this string just to see it is correct and even tried to hardcode it and it worked, but it didn't when I used exec.
What is wrong with this and how can I make this right?
Appreciating all the comment :)
Edit:
The error I get is AttributeError saying it is a NoneType, although if I just hardcode it it works perfectly fine.

Solution 1: instead of passing a Python expression, either use argparse's subcommands or define your own easily-parsable mini-language. You can store relevant classes and functions in a dict to get them from strings (better than relying on globals as it lets you whitelist only what you want to expose)
Solution 2: use the full power of the ast module to parse the Python expression into an ast then write your own visitors to safely evaluate the ast.
Solution 3: keep on using exec or eval and wait until some script kiddie erases your full hard-drive or worse.

Related

how to unstringify arrays without external modules with python?

How to turn a string that contains an array into a normal array without using external modules? For example: “a[0]” into a[0]
edit:
I have seen a few complains about the amount of information in this post so I will add some more details about my problem for everyone watching this in future: My intention was to write a string that contains ”array[…]” somewhere in it but I need to execute this array somehow and my best choice was to remove the quotes around it but I don’t want to use eval() because of a few security issues
edit 2:
or tell me, how to express an equation in python without instantly solving it and without importing modules
one option is to use builtin eval function in python:
a = [ 'wowweeeee!' ]
print(eval('a[-1]')) # wowweeeee!
as #cards mentions in the comments, you can also pass a local dict object to restrict the scope of eval, to help address any security concerns:
try:
print(eval('a[-1]', {'a': a})) # wowweeeee!
except NameError as ne:
print('following variable is missing:', ne)

python string to a function call with arguments, without using eval

I have a string stored in a database stands for a class instance creation for example module1.CustomHandler(filename="abc.csv", mode="rb"), where CustomHandler is a class defined in module1.
I would like to evaluate this string to create a class instance for a one time use. Right now I am using something like this
statement = r'module1.CustomHandler(filename="abc.csv", mode="rb")' # actually read from db
exec(f'from parent.module import {statement.split(".")[0]}')
func_or_instance = eval(statement) # this is what I need
Only knowledgable developers can insert such records into database so I am not worried about eval some unwanted codes. But I've read several posts saying eval is unsafe and there is always a better way. Is there a way I can achieve this without using eval?
You might want to take a look at the ast Python module, which stands for abstract syntax trees. It's mainly used when you need to process the grammar of the programming language, work with code in string format, and so much more functions available in the official documentation.
In this case eval() function looks like the best solution, clear and readable, but safe only under certain conditions. For example, if you try to evaluate a code that contains a class not implemented in the code, it will throw an exception. That's the main reason why eval is sometimes unsafe.

Converting a variable into a string creates EOF error

def evaluate(x):
number = str(eval(entry_drones.get()))
if x == drones :
create_drone(number)
entry_drones = Entry(frame, text = "1")
entry_drones.bind("<Return>", evaluate(drones))
I have a program that creates an error along the lines of:
number = str(eval(entry_drones.get()))
File "<string>", line 0
^
SyntaxError: unexpected EOF while parsing
I tried searching for the answer online, but they say I'm either missing a parenthesis (I've been unable to spot where it is needed) or I'm using input instead of raw_input (Neither appear to be the cause of this error, at least to my knowledge)
I posted just the code that I think is relevant to the issue, but I can provide more if needed. Take note, I have math and Tkinter imported, as well as other things.
I used eval because it is the only way I know (out of limited experience) to take the input from my Entry widget and simplify it before I run it through another function.
As for drones, it lets my evaluate function know which function to pass number to. I snipped out all of the other options because it is repetitive and it all leads to this function. entry_drones can have basic expressions put into it such as 10 * 10 or something. In my code I set k = 1000 and so forth, allowing me to use letters to abbreviate.
The entry_drones.get() should (if I'm not mistaken) grab whatever is typed into the Entry widget whenever the Enter key is pressed.
The eval function interprets the string you pass to it as Python code. You'll get a SyntaxError if anything is typed in your text entry box that isn't a valid Python expression (such as an empty string, for instance). You might get other exceptions too, if you type something that could be valid, but has other problems (for instance, calling eval on a random string that could be a variable name will probably raise a NameError since there is no such variable).
If that's the only problem, you probably just want to catch exceptions from the eval call and either ignore them or give an appropriate error message in your program.
Be aware too that calling eval on user input can be really dangerous. If a user types in something like __import__("os").system("rm -Rf /") your program might quietly delete the entire contents of your hard drive (don't try this!). This is obviously a much bigger deal if your program is running with more permissions on your system than the user would have by themselves (probably not likely for a GUI app, but very common for a web app), but even if you're only capable of doing things that the user could do anyway from a command prompt, it's a bad idea to use eval on untrusted input.
Unfortunately there isn't really a trivial way to do what I think you want (simplifying mathematical expressions, possibly including calls to functions like math.sqrt) without a bunch of work. One option would be to pass the string to ast.parse to get an abstract syntax tree, and then walk the tree to make sure it only does stuff you want to allow (such as using mathematical operators, and calling specific whitelisted functions (e.g. the ones in the math module). You can then pass the validated AST to compile and then eval it with confidence that it won't do anything bad.
eval() is very dangerous as #Blckknght explained well.
On a side note, Just to point out the actual root cause of the issue , it should be because of the line -
entry_drones.bind("<Return>", evaluate(drones))
This would run the function evalute() when this line is executed, and that is most probably before the app has even completely started, so the entry entry_drones is empty causing the issue. Then if it were to run successfully, it would pass the returned value to the bind method, in this case, None would be returned.
I believe if you want to send a parameter to your evaluate() function, then you should first make it accept more than one paraemter, since bind itself sends it event parameter. Example -
def evaluate(event, x):
...
Then use lambda expression with default value to pass the drones into x. Example -
entry_drones.bind("<Return>", lambda event, x=drones: evaluate(event, x))

Python built-in function "compile". What is it used for?

I came across a built-in function compile today. Though i read the documentation but still do not understand it's usage or where it is applicable. Please can anyone explain with example the use of this function. I will really appreciate examples.
From the documentation, the function takes some parameters as shown below.
compile(source, filename, mode[, flags[, dont_inherit]])
It is not that commonly used. It is used when you have Python source code in string form, and you want to make it into a Python code object that you can keep and use. Here's a trivial example:
>>> codeobj = compile('x = 2\nprint "X is", x', 'fakemodule', 'exec')
>>> exec(codeobj)
X is 2
Basically, the code object converts a string into an object that you can later call exec on to run the source code in the string. (This is for "exec" mode; the "eval" mode allows use of eval instead, if the string contains code for a single expression.) This is not a common task, which is why you may never run across a need for it.
The main use for it is in metaprogramming or embedding situations. For instance, if you have a Python program that allows users to script its behavior with custom Python code, you might use compile and exec to store and execute these user-defined scripts.
Another reason compile is rarely used is that, like exec, eval, and their ilk, compile is a potential security hole. If you take user code in string form and compile it and later exec it, you could be running unsafe code. (For instance, imagine that in my example above the code was formatYourHardDrive() instead of print x.)
compile is a lower level version of exec and eval. It does not execute or evaluate your statements or expressions, but returns a code object that can do it. The modes are as follows:
compile(string, '', 'eval') returns the code object that would have been executed had you done eval(string). Note that you cannot use statements in this mode; only a (single) expression is valid. Used for a single expression.
compile(string, '', 'exec') returns the code object that would have been executed had you done exec(string). You can use any number of statements here. Used for an entire module.
compile(string, '', 'single') is like the exec mode, but it will ignore everything except for the first statement. Note that an if/else statement with its results is considered a single statement. Used for one single statement.
Take a look that the documentation. There is also an awesome (well, dumbed down) explanation at http://joequery.me/code/python-builtin-functions/#compile with an excellent example of usage.
What specifically don't you understand? The documentation explains that it will:
Compile the source into a code or AST object. Code objects can be executed by an exec statement or evaluated by a call to eval(). source can either be a Unicode string, a Latin-1 encoded string or an AST object. Refer to the ast module documentation for information on how to work with AST objects.
So it takes python code, and returns on of those two things
exec will execute the python code
eval will evaluate an expression, which is less functional than exec
ast allows you to navigate the Abstract Syntax Tree that the code generates

Finding more info on Python functions, 3 quick questions

I am going over a Python tutorial the one where the following example is demonstrated:
>>> 'str'.strip() + 'ing' # <- This is ok
In this example (as i understand it) str is a string, on which function strip() is called.
I would reasonably expect to find that function doing >>> dir("abc"). Indeed function is listed as 'strip'
Question 1: Why are some functions listed as __name__ and others as name?
Question 2: I would like now to find more information about this function. When running help("abc") (expecting to get a man page on all functions that can be ran on string), strip is not listed. Why? Where can i find out more about particular function?
Question 3: Using PyCharm i would expect the following autocompletion to work and yet, i see nothing. Why is that?
Functions surrounded by double underscores are special functions that can be overridden to implement special behaviors. For example, the __getitem__ function, when implemented in a class, allows indexed access to items in that class. (In other words, a[5] is equivalent in most contexts to a.__getitem__(5)). The underscores just signal that they're special, and require some special handling. (For example, don't invent your own.)
When you pass a string to help, it treats the string as a query. For example, help('class') brings up a bunch of information about classes. If you want the help text for string objects, do help(str) or help('str').
I don't use PyCharm, so I can't help there.
Instead of help("abc") which gives help on abstract base classes, try help(str) which gives help on strings, including the str.strip method.
Answer for 3. Make sure you have Python Interpreter specified in Settings | Project Interpreter?
Here is what I get for your example:

Categories

Resources