Indenting Python function within string and executing it using eval - python

I've written simple code to handle just one case and correct the indentation (again simple and it relies on the user taking caution while using it) of a string containing a Python function declared using the def keyword and execute it.
def fix_index(string):
i=0;
t=string.find("def")+3;
string=string.replace(string[string.find("def"):t], "#")
while string.find(" ") != -1:
string = string.replace(" ", "")
i += 1
l=list(string);l[string.find(":")-i+2]+="$$$$"
return "".join(l).replace("$$$$", " ").replace("#", "def ").lstrip();
def switch(exp):
def exec(obj):
items = obj.items();
for k, v in items:
if(k==exp):
print(fix_index(v))
return eval(fix_index(v))();
return {"case":exec};
bread = "bread"
switch(bread)["case"]({
"cheese":
"""
def a():
print("cheese");
""",
"bread":
"""
def b():
print("bread");
"""
})
the output for the formatted function string:
C:\Users\User>python -u "c:\Users\User\folder\switch.py"
def b():
print("bread");
the error I'm getting:
Traceback (most recent call last):
File "c:\Users\User\folder\switch.py", line 27, in <module>
switch(bread)["case"]({
File "c:\Users\User\folder\switch.py", line 21, in exec
return eval(fix_index(v))();
File "<string>", line 1
def b():
^
SyntaxError: invalid syntax
I've also just realized I didn't name the function what I indented intended to (should've posted this when awake to avoid accidental pun).
Anyways what I fail to understand is what part in my produced string exactly contains "invalid syntax".
I'll appreciate any help.

if what you are looking for is to reproduce a switch statement, you can do it with the following function:
def switch(v): yield lambda *c: v in c
It simulates a switch statement using a single pass for loop with if/elif/else conditions that don't repeat the switching value:
for example:
for case in switch(x):
if case(3):
# ... do something
elif case(4,5,6):
# ... do something else
else:
# ... do some other thing
It can also be used in a more C style:
for case in switch(x):
if case(3):
# ... do something
break
if case(4,5,6):
# ... do something else
break
else:
# ... do some other thing
For your example, it could look like this:
meal = "bread"
for case in switch(meal):
if case("cheese"):
print("Cheese!")
elif case("bread"):
print("Bread!")
or this:
meal = "bread"
for case in switch(meal):
if case("cheese"):
print("Cheese!")
break
if case("bread"):
print("Bread!")
break

Related

Getting a multiline expression from a function

I'll try to be clear, please do any questions you need.
I'm working on mezcla, just trying to make things a little bit more pythonic.
To be specific, in debug there's a function called assertion, which takes an expression and evaluates it, giving an error message which doesn't raise an exception.
It works giving to the function an expression, like
from debug import assertion
def func():
return 2+2==5,
def probe(expr):
print(assertion(expr))
probe(
func()
)
##OR alone like
assertion(
2+2
==5)
And it should take the expression itself and print it. I'm looking for a way to get and evaluate a multiline expression, just like icecream, for example, can do this way:
In [2]: ic(2+2
...: ==5
...: )
ic| 2+2
==5: False
I tried this massive code, it reads the expression from ipython history, or it reads the file and line with inspect and iterates line by line of the script looking for the closure parenthesis.
def read_line(filename, line_number):
"""Returns contents of FILENAME at LINE_NUMBER"""
# ex: "debugging" in read_line(os.path.join(os.getcwd(), "debug.py"), 3)
try:
with open(filename) as file:
line_contents = file.readlines()[line_number - 1]
except OSError:
line_contents = "<stdin>"
except:
line_contents = "???"
return line_contents
def multi_assert(assertion, line_number=1):
"""Handles multiline assertions until 10 lines"""
line = ""
counter = 0
#While count(just for prevent infinite loop)
while counter < 10:
counter += 1
#Reads line, appends it and compares number of ()
line += read_line(assertion, line_number)
if line.count("(") > line.count(")"):
line_number += 1
else:
return line
break
def assertion(expression, message=None):
"""Issue warning if EXPRESSION doesn't hold, along with optional MESSAGE
Note: This is a "soft assertion" that doesn't raise an exception (n.b., provided the test doesn't do so)"""
if (not expression):
# Get source information for failed assertion
(_frame, filename, line_number, _function, _context, _index) = inspect.stack()[1]
# Read statement in file and extract assertion expression
# Calls to multi_assert to handle multiline
statement = multi_assert(str(filename), line_number + 1)
# If statement is from stdin, tries to get assert from ipython history
if statement == "<stdin>" and _context != None:
try:
ip = get_ipython()
statement = str(ip.history_manager.get_tail(1, raw=True, include_latest=True))
except:
statement = str(_context).replace(")\\n']", "")
return statement
It works, but it's too heavy, hacky and not specially ellegant, so i'm looking for any other way that return the gived assertion even if is multiline. Any kind of suggestion will be accepted and appreciated. Thanks

Code won't fully run for some reason

I am writing code for a math calculator, and am running into a problem. When I ask the user to input a function to derive, and they input a number and then x, like 3x, instead of 3*x. The code crashes because it cannot parse it. To get around this I have a function to sanitize it, but it won't even run for some reason.
class Derivatives:
def __init__(self):
x=sympy.Symbol('x')
self.func=self.clean_func((input("Enter f(x): ")))
print(self.func)
print(sympy.diff(self.func, x))
def clean_func(self, func):
clean_func=""
print("c")
for i in range(len(func)):
if func[i].isalpha or isinstance(func[i], int) or func[i] in self.math_symbols :
if func[i]== "^" :
clean_func+="**"
else:
clean_func+=func[i]
for c in range(48, 57) :
if func[i:i+1] == (chr(c) + 'x') :
clean_func+="*" #helps with parsing
return clean_func
and I get this error in a=Derivatives()
Enter f(x): 3x
Traceback (most recent call last):
File "<ipython-input-48-f4cd19afbde9>", line 1, in <module>
a=Derivatives()
File "/Volumes/PROJECTS/M_series.py", line 71, in __init__
x=sympy.Symbol('x')
File "/Users/thomastierney/anaconda/lib/python3.5/site-packages/sympy/core/function.py", line 1691, in diff
return Derivative(f, *symbols, **kwargs)
File "/Users/thomastierney/anaconda/lib/python3.5/site-packages/sympy/core/function.py", line 1018, in __new__
expr = sympify(expr)
File "/Users/thomastierney/anaconda/lib/python3.5/site-packages/sympy/core/sympify.py", line 324, in sympify
raise SympifyError('could not parse %r' % a, exc)
SympifyError: Sympify of expression 'could not parse '3x'' failed, because of exception being raised:
SyntaxError: invalid syntax (<string>, line 1)
A few problems:
Using func as the name of a string is misleading (Python allows first-order functions, therefore you would expect it to actually be a function); let's call it fn_str instead.
If clean_func worked properly, it would return a sympy-parseable string - which you then pass to diff without converting from a string to a function.
The construction
for i in range(len(mystring)):
do_something(mystring[i])
is more clearly written as
for ch in mystring:
do_something(ch)
isinstance(func[i], int) doesn't work because func[i] is a one-character string, not an integer. Try str.isdecimal() instead.
self.math_symbols is not defined.
Python strings are immutable; every time you do mystring += ch it actually creates an entirely new string. Because of this, it is much more efficient to append to a list of string-chunks and then "".join() them when finished.
for c in range(48, 57): Python ranges do not include the end value, ie this will produce 48, 49, 50, ... 56. This means chr(57) ie "9" is never tested for.
Similarly, string slices do not include the end offset, so func[i:i+1] is one character, exactly equivalent to func[i]. You meant func[i:i+2].
Also, something like 3. is a valid Python float, but your code will not catch 3.x. Doing proper tokenization instead of character-by-character comparison would catch that.
The class is not a Derivative; you are trying to stuff your program into a mislabeled class.
A cleaned-up version:
import string
import sympy
# This could easily be just a function;
# I made it a class to keep the namespace clean
class FnStrCleaner:
# valid characters
NUMCHARS = set(string.digits + ".")
VARCHARS = set(string.ascii_letters)
OPCHARS = set("()+-*/^")
LEGALCHARS = NUMCHARS | VARCHARS | OPCHARS
#classmethod
def clean(cls, fn_str):
# generator expression - skip nonlegal chars
good_chars = (ch for ch in fn_str if ch in cls.LEGALCHARS)
out = []
# simple FSM to process character stream
prev_num = False # preceding character was part of a number
for ch in good_chars:
if prev_num:
if ch in cls.NUMCHARS:
out.append(ch)
# prev_num = True
elif ch in cls.VARCHARS:
out.append('*' + ch)
prev_num = False
else: # ch in cls.OPCHARS
out.append(ch)
prev_num = False
else:
if ch in cls.NUMCHARS:
out.append(ch)
prev_num = True
elif ch in cls.VARCHARS:
out.append(ch)
# prev_num = False
else: # ch in cls.OPCHARS
out.append('**' if ch == '^' else ch)
# prev_num = False
return "".join(out)
def get_function(prompt, locals=None):
fn_str = input(prompt)
fn_str = FnStrCleaner.clean(fn_str)
return sympy.sympify(fn_str, locals=locals)
def main():
x = sympy.Symbol("x")
f = get_function("Enter f(x): ", {'x': x})
df = sympy.diff(f, x)
print("f(x) =", f)
print("f'(x) =", df)
if __name__ == "__main__":
main()
which runs like
Enter f(x): 29x^3 + 12x^2 - 9x + 5
f(x) = 29*x**3 + 12*x**2 - 9*x + 5
f'(x) = 87*x**2 + 24*x - 9

IndentationError: expected an indented block (python codeacademy)

I was taking my course at codeacademy until something went wrong and couldn't proceed, a little help please :( here is my code
def by_three(num):
if num%3 == 0:
def cube(num):
else:
print "False"
def cube(num):
return num**3
by_three(9)
I get...
File "<stdin>", line 4
else:
^
IndentationError: expected an indented block
Unknown error.
I will really appreciate your help people!!
You probably wanted to call (use) the function cube() instead of defining it (in your by_three() function definition), so your corrected code will be:
def by_three(num):
if num%3 == 0:
print cube(num) # Instead of your original "def cube(num):"
else:
print "False"
def cube(num):
return num**3
by_three(9)
On line 3 def cube(num): you have an extra def and :. Remove those
When defining a function you need def and colon, where as for calling it you don't need one. The correct code
def by_three(num):
if num%3 == 0:
cube(num)
else:
print "False"
def cube(num):
return num**3
by_three(9)

Get value of last expression in `exec` call

Let's say I have some python code in a string
code = """
a = 42
a
"""
and I exec that string of code:
result = exec(code)
Then result will always be None. Is there any way at all to get the value of the last expression evaluated? In this case, that would be 5, since a was the last expression.
EDIT: Here's another example of the functionality I'm asking about. Let's say we have the python code (stored in the variable code)
a = 100
sqrt(a)
Then how can I execute the code in such a way as to give me the result 10 - that is, sqrt(a)?
EDIT EDIT: A further example: the code I wish to exec is
function_a()
function_b()
function_c()
Is there any way I can define some kind of magic_exec function so that
magic_exec(code)
will provide me with the value of function_c()?
The request is certainly valid because I need such a function as well during the creation of a Python-based environment. I solved the problem with the following code that utilizes the Python ast mechanism:
def my_exec(script, globals=None, locals=None):
'''Execute a script and return the value of the last expression'''
stmts = list(ast.iter_child_nodes(ast.parse(script)))
if not stmts:
return None
if isinstance(stmts[-1], ast.Expr):
# the last one is an expression and we will try to return the results
# so we first execute the previous statements
if len(stmts) > 1:
exec(compile(ast.Module(body=stmts[:-1]), filename="<ast>", mode="exec"), globals, locals)
# then we eval the last one
return eval(compile(ast.Expression(body=stmts[-1].value), filename="<ast>", mode="eval"), globals, locals)
else:
# otherwise we just execute the entire code
return exec(script, globals, locals)
The code should be pretty self-explanatory, basically it
separate the script into multiple statements
if the last one is an expression, execute the first part as statements, and the last part as expression.
Otherwise execute the entire script as statements.
This doesn't get you the last evaluated value, but gets the whole list of local variables.
>>> loc = {}
>>> exec(code, {}, loc)
>>> loc
{'a': 42}
exec('a = 4')
print a % prints 4
>>> code = """
... a = 42
... b = 53"""
>>> exec(code)
>>> a
42
>>> b
53
Or if you're saying you don't know the last thing is b for instance, then you can have this:
code = """
a = 4
b = 12
abc_d=13
"""
t = re.findall(r'''.*?([A-Za-z0-9_]+)\s*?=.*?$''', code)
assert(len(t)==1)
print t[0] % prints 13
To be honest I can't say I'm very happy with this. It feels very hacky and I haven't tested it all that heavily. On the other hand I'm quite pleased with it. Was quite fun to do. Anyway, hope this helps you or at least comes close to what you want. locals() gives a dict so the output list order does not match the input order for the items that failed the first eval. If you don't want ';' as delimiters then you can change it to '\n'.
import math
def magic_exec(_command):
_command = _command.split(';')
_result = None
_before = list(locals()) # Get list of current local variables
for _code in _command:
_code = _code.strip() # .strip() prevent IndentationError
try:
if eval(_code) != None: # For functions with no return
_result = eval(_code)
except (NameError, SyntaxError):
try:
_before = list(locals())
exec(_code)
except NameError as e: # For undefined variables in _command
print("An Error Occurred with line ' {0} ' as was skipped: {1}".format(_code, e))
del _code # delete temp var _code
# Get new list of locals that didn't exist at the start
_after = [val for val in list(locals()) if val not in _before]
if _after:
return eval(_after[0])
else:
return _result
#Dummy class and functions
class Class1(object):
def __init__(self, x):
self._x = x
def get_val(self):
return self._x
def __repr__(self):
return type(self).__name__
def func1(x):
return x + x
def func2(x):
print(x*x)
if __name__ == '__main__':
code = \
"""
a = 42; a; v; y = 2; b = func1(5); s = 'Hello'; func2(10); c = 25; l = []; l.append('Value');
t = math.sqrt(c); pass; 20*10; print('TEST'); math.sqrt(c); d = Class1('World'); d.get_val();
def func3(x): return x ** 2; s = func3(15)
"""
values = magic_exec(code)
print(values)
I would like to add to user2283347's excellent answer that it works only up to Python 3.7. In Python 3.8 the signature of ast.Module.__init__ has changed. It now requires a second argument which in our case can be an empty list.
Details: ast.Module(body=stmts[:-1]) in
if len(stmts) > 1:
exec(compile(ast.Module(body=stmts[:-1]), filename="<ast>", mode="exec"), globals, locals)
has to be changed to
ast.Module(stmts[:-1], []) if you use Python 3.8 or above (note the second argument []). Otherwise the following TypeError will be raised:
TypeError: required field "type_ignores" missing from Module
Unfortunately this change is not very well documented. I found the solution after extensive Googling here: "IPython broken on 3.8-dev" .

General decorator to wrap try except in python?

I'd interacting with a lot of deeply nested json I didn't write, and would like to make my python script more 'forgiving' to invalid input. I find myself writing involved try-except blocks, and would rather just wrap the dubious function up.
I understand it's a bad policy to swallow exceptions, but I'd rather prefer they to be printed and analysed later, than to actually stop execution. It's more valuable, in my use-case to continue executing over the loop than to get all keys.
Here's what I'm doing now:
try:
item['a'] = myobject.get('key').METHOD_THAT_DOESNT_EXIST()
except:
item['a'] = ''
try:
item['b'] = OBJECT_THAT_DOESNT_EXIST.get('key2')
except:
item['b'] = ''
try:
item['c'] = func1(ARGUMENT_THAT_DOESNT_EXIST)
except:
item['c'] = ''
...
try:
item['z'] = FUNCTION_THAT_DOESNT_EXIST(myobject.method())
except:
item['z'] = ''
Here's what I'd like, (1):
item['a'] = f(myobject.get('key').get('subkey'))
item['b'] = f(myobject.get('key2'))
item['c'] = f(func1(myobject)
...
or (2):
#f
def get_stuff():
item={}
item['a'] = myobject.get('key').get('subkey')
item['b'] = myobject.get('key2')
item['c'] = func1(myobject)
...
return(item)
...where I can wrap either the single data item (1), or a master function (2), in some function that turns execution-halting exceptions into empty fields, printed to stdout. The former would be sort of an item-wise skip - where that key isn't available, it logs blank and moves on - the latter is a row-skip, where if any of the fields don't work, the entire record is skipped.
My understanding is that some kind of wrapper should be able to fix this. Here's what I tried, with a wrapper:
def f(func):
def silenceit():
try:
func(*args,**kwargs)
except:
print('Error')
return(silenceit)
Here's why it doesn't work. Call a function that doesn't exist, it doesn't try-catch it away:
>>> f(meow())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'meow' is not defined
Before I even add a blank return value, I'd like to get it to try-catch correctly. If the function had worked, this would have printed "Error", right?
Is a wrapper function the correct approach here?
UPDATE
I've had a lot of really useful, helpful answers below, and thank you for them---but I've edited the examples I used above to illustrate that I'm trying to catch more than nested key errors, that I'm looking specifically for a function that wraps a try-catch for...
When a method doesn't exist.
When an object doesn't exist, and is getting a method called on it.
When an object that does not exist is being called as an argument to a function.
Any combination of any of these things.
Bonus, when a function doesn't exist.
There are lots of good answers here, but I didn't see any that address the question of whether you can accomplish this via decorators.
The short answer is "no," at least not without structural changes to your code. Decorators operate at the function level, not on individual statements. Therefore, in order to use decorators, you would need to move each of the statements to be decorated into its own function.
But note that you can't just put the assignment itself inside the decorated function. You need to return the rhs expression (the value to be assigned) from the decorated function, then do the assignment outside.
To put this in terms of your example code, one might write code with the following pattern:
#return_on_failure('')
def computeA():
item['a'] = myobject.get('key').METHOD_THAT_DOESNT_EXIST()
item["a"] = computeA()
return_on_failure could be something like:
def return_on_failure(value):
def decorate(f):
def applicator(*args, **kwargs):
try:
return f(*args,**kwargs)
except:
print('Error')
return value
return applicator
return decorate
You could use a defaultdict and the context manager approach as outlined in Raymond Hettinger's PyCon 2013 presentation
from collections import defaultdict
from contextlib import contextmanager
#contextmanager
def ignored(*exceptions):
try:
yield
except exceptions:
pass
item = defaultdict(str)
obj = dict()
with ignored(Exception):
item['a'] = obj.get(2).get(3)
print item['a']
obj[2] = dict()
obj[2][3] = 4
with ignored(Exception):
item['a'] = obj.get(2).get(3)
print item['a']
It's very easy to achieve using configurable decorator.
def get_decorator(errors=(Exception, ), default_value=''):
def decorator(func):
def new_func(*args, **kwargs):
try:
return func(*args, **kwargs)
except errors, e:
print "Got error! ", repr(e)
return default_value
return new_func
return decorator
f = get_decorator((KeyError, NameError), default_value='default')
a = {}
#f
def example1(a):
return a['b']
#f
def example2(a):
return doesnt_exist()
print example1(a)
print example2(a)
Just pass to get_decorator tuples with error types which you want to silence and default value to return.
Output will be
Got error! KeyError('b',)
default
Got error! NameError("global name 'doesnt_exist' is not defined",)
default
Edit: Thanks to martineau i changed default value of errors to tuples with basic Exception to prevents errors.
It depends on what exceptions you expect.
If your only use case is get(), you could do
item['b'] = myobject.get('key2', '')
For the other cases, your decorator approach might be useful, but not in the way you do it.
I'll try to show you:
def f(func):
def silenceit(*args, **kwargs): # takes all kinds of arguments
try:
return func(*args, **kwargs) # returns func's result
except Exeption, e:
print('Error:', e)
return e # not the best way, maybe we'd better return None
# or a wrapper object containing e.
return silenceit # on the correct level
Nevertheless, f(some_undefined_function())won't work, because
a) f() isn't yet active at the execution time and
b) it is used wrong. The right way would be to wrap the function and then call it: f(function_to_wrap)().
A "layer of lambda" would help here:
wrapped_f = f(lambda: my_function())
wraps a lambda function which in turn calls a non-existing function. Calling wrapped_f() leads to calling the wrapper which calls the lambda which tries to call my_function(). If this doesn't exist, the lambda raises an exception which is caught by the wrapper.
This works because the name my_function is not executed at the time the lambda is defined, but when it is executed. And this execution is protected and wrapped by the function f() then. So the exception occurs inside the lambda and is propagated to the wrapping function provided by the decorator, which handles it gracefully.
This move towards inside the lambda function doesn't work if you try to replace the lambda function with a wrapper like
g = lambda function: lambda *a, **k: function(*a, **k)
followed by a
f(g(my_function))(arguments)
because here the name resolution is "back at the surface": my_function cannot be resolved and this happens before g() or even f() are called. So it doesn't work.
And if you try to do something like
g(print)(x.get('fail'))
it cannot work as well if you have no x, because g() protects print, not x.
If you want to protect x here, you'll have to do
value = f(lambda: x.get('fail'))
because the wrapper provided by f() calls that lambda function which raises an exception which is then silenced.
Extending #iruvar answer - starting with Python 3.4 there is an existing context manager for this in Python standard lib: https://docs.python.org/3/library/contextlib.html#contextlib.suppress
from contextlib import suppress
with suppress(FileNotFoundError):
os.remove('somefile.tmp')
with suppress(FileNotFoundError):
os.remove('someotherfile.tmp')
in your case you first evaluate the value of the meow call (which doesn't exist) and then wrap it in the decorator. this doesn't work that way.
first the exception is raised before it was wrapped, then the wrapper is wrongly indented (silenceit should not return itself). You might want to do something like:
def hardfail():
return meow() # meow doesn't exist
def f(func):
def wrapper():
try:
func()
except:
print 'error'
return wrapper
softfail =f(hardfail)
output:
>>> softfail()
error
>>> hardfail()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in hardfail
NameError: global name 'meow' is not defined
anyway in your case I don't understand why you don't use a simple method such as
def get_subkey(obj, key, subkey):
try:
return obj.get(key).get(subkey, '')
except AttributeError:
return ''
and in the code:
item['a'] = get_subkey(myobject, 'key', 'subkey')
Edited:
In case you want something that will work at any depth. You can do something like:
def get_from_object(obj, *keys):
try:
value = obj
for k in keys:
value = value.get(k)
return value
except AttributeError:
return ''
That you'd call:
>>> d = {1:{2:{3:{4:5}}}}
>>> get_from_object(d, 1, 2, 3, 4)
5
>>> get_from_object(d, 1, 2, 7)
''
>>> get_from_object(d, 1, 2, 3, 4, 5, 6, 7)
''
>>> get_from_object(d, 1, 2, 3)
{4: 5}
And using your code
item['a'] = get_from_object(obj, 2, 3)
By the way, on a personal point of view I also like #cravoori solution using contextmanager. But this would mean having three lines of code each time:
item['a'] = ''
with ignored(AttributeError):
item['a'] = obj.get(2).get(3)
Why not just use cycle?
for dst_key, src_key in (('a', 'key'), ('b', 'key2')):
try:
item[dst_key] = myobject.get(src_key).get('subkey')
except Exception: # or KeyError?
item[dst_key] = ''
Or if you wish write a little helper:
def get_value(obj, key):
try:
return obj.get(key).get('subkey')
except Exception:
return ''
Also you can combine both solutions if you have a few places where you need to get value and helper function would be more reasonable.
Not sure that you actually need a decorator for your problem.
Since you're dealing with lots of broken code, it may be excusable to use eval in this case.
def my_eval(code):
try:
return eval(code)
except: # Can catch more specific exceptions here.
return ''
Then wrap all your potentially broken statements:
item['a'] = my_eval("""myobject.get('key').get('subkey')""")
item['b'] = my_eval("""myobject.get('key2')""")
item['c'] = my_eval("""func1(myobject)""")
How about something like this:
def exception_handler(func):
def inner_function(*args, **kwargs):
try:
func(*args, **kwargs)
except TypeError:
print(f"{func.__name__} error")
return inner_function
then
#exception_handler
def doSomethingExceptional():
a=2/0
all credits go to:https://medium.com/swlh/handling-exceptions-in-python-a-cleaner-way-using-decorators-fae22aa0abec
Try Except Decorator for sync and async functions
Note: logger.error can be replaced with print
Latest version can be found here.

Categories

Resources