Wrapping a Python function that uses with - python

Say have a python function foo() that uses some resource and is meant to be called as follows:
with foo(x,y,z) as f:
doSomething(f)
So far so good. Now lets say foo takes in a complex set of arguments based on a variety of factors, and I'd like to define a wrapper function to make things simpler. Something like:
def simple_foo():
if x:
return foo(a,b,c)
else:
return foo(d,e,f)
Now, I'd like to use simple_foo in place of foo, like:
with simple_foo() as f:
doSomething(f)
However, unsurprisingly, this does not work. How can I write simple_foo() to get this behavior?

Decorate function foo() with contextmanager (doc):
from contextlib import contextmanager
#contextmanager
def foo(a, b, c):
try:
yield a + b + c
finally:
pass
def simple_foo(x):
if x:
return foo(1, 2, 3)
return foo(4, 5, 6)
with simple_foo(True) as v:
print(v)
with simple_foo(False) as v:
print(v)
Prints:
6
15

You can do by writing a custom context manager that internally calls that function, try code given below:
class SimpleFoo:
def __init__(self,x,y,z, option):
self.x = x
self.y = y
self.z = z
self.option = option
def __enter__(self):
if self.option:
return foo(self.x,self.y,self.z)
else:
return foo(self.y,self.z,self.x)
def __exit__(self, type, value, traceback):
if type != None:
print("Error in SimpleFoo")
print("Error Type :", type)
print("Error Value :", value)
print("Error Traceback :", traceback)
self.status = value
Now if you want to use this, use it as below:
with SimpleFoo(1,2,3,True) as foo:
doSomething(foo)
I hope this helps.

Related

The problem of using the try exception dynamically

I have a function called transform_exceptions() that takes a list of functions, then calls each of the functions (functions are without arguments) and the exceptions that occur with the above convention to an object of ExceptionProxy and finally the list of transformed errors. It returns functions in the same order
Note: If a function is executed without error, an ExceptionProxy object should be created and its msg value should be "ok!" Slow quantification
smple:
class ExceptionProxy(Exception):
# define your class here
def transform_exceptions(func_ls):
# implement your function here
def f():
1/0
def g():
pass
tr_ls = transform_exceptions([f, g])
for tr in tr_ls:
print("msg: " + tr.msg + "\nfunction name: " + tr.function.__name__)
Output:
msg: division by zero
function name: f
msg: ok!
function name: g
my code :
from mimetypes import init
class ExceptionProxy(Exception):
def __init__(self, msg, function):
self.msg = msg
self.function = function
def transform_exceptions(func_ls):
exception_list = []
for func in func_ls:
try:
func
except Exception as e:
r = ExceptionProxy(str(e), func)
exception_list.append(r)
else:
r = ExceptionProxy("ok!", func)
exception_list.append(r)
return exception_list
You should do this when calling the function name in the list
func()
Also modified code:
class ExceptionProxy(Exception):
def __init__(self,msg,function):
self.msg = msg
self.function = function
def transform_exceptions(func_ls):
out = []
for x in func_ls:
try:
x()
a = ExceptionProxy("ok!", x)
except Exception as e:
a = ExceptionProxy(str(e), x)
out.append(a)
return out

How do I write a function that satisfies this test?

I need to write a function that satisfies this test in pytest:
def test_return_logger(capsys):
#return_logger
def myfunc(a, b, c):
return a + b + c
val = myfunc(4, 5, 6)
out, err = capsys.readouterr()
assert val == 15
assert "Function returned: 15" in out
Here is what I currently have and it is not working:
def return_logger(f):
def newfunc(s):
original_return_value = f(s)
return f"Function returned: {original_return_value}"
return newfunc
Im honestly completely lost!
Your test wants the function to return the value, and print the string that you were returning.
The newfunc(*args) also solves passing in multiple arguments - they are automatically unpacked when calling the second function.
You probably want this:
def return_logger(f):
def newfunc(*args):
original_return_value = f(*args)
print(f"Function returned: {original_return_value}", sys.stderr)
return original_return_value
return newfunc
Now, when you call the decorated function, it will print Function returned: 15 to stderr and return original_return_value.

Abstracting if statement and return by a function

I have a function like this:
def test():
x = "3" # In actual code, this is computed
if x is None:
return None
y = "3"
if y is None:
return None
z = "hello"
if z is None:
return None
Is there a way of making the if statement go away and abstract it with some function. I'm expecting something like this:
def test():
x = "3"
check_None(x)
y = "3"
check_None(y)
z = "hello"
check_None(z)
Ideally, check_None should alter the control flow if the parameter passed to it is None. Is this possible?
Note: Working on Python 2.7.
You can easily code it in some thing like this.
def test():
#compute x, y, z
if None in [x, y, z]:
return None
# proceed with rest of code
An even better way would be to use an generator to generate value x, y, z so that you only does computation for one value at a time.
def compute_values():
yield compute_x()
yield compute_y()
yield compute_z()
def test():
for value in compute_values():
if value is None:
return None
I am not really sure if we should do it like this, but one of the hacks could be like this, Also create your own exception class and only catch that particular exception so that no other exceptions are accidentally caught by the except and return None.
class MyException(Exception):
pass
def check_none(x):
if x is None:
raise MyException
def test():
try:
z=None
check_none(z)
except MyException, e:
return None
return_value = test()

How to use Python decorators to check function arguments?

I would like to define some generic decorators to check arguments before calling some functions.
Something like:
#checkArguments(types = ['int', 'float'])
def myFunction(thisVarIsAnInt, thisVarIsAFloat)
''' Here my code '''
pass
Side notes:
Type checking is just here to show an example
I'm using Python 2.7 but Python 3.0 whould be interesting too
EDIT 2021: funny that type checking did not go antipythonic in the long run with type hinting and mypy.
From the Decorators for Functions and Methods:
Python 2
def accepts(*types):
def check_accepts(f):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_accepts
Python 3
In Python 3 func_code has changed to __code__ and func_name has changed to __name__.
def accepts(*types):
def check_accepts(f):
assert len(types) == f.__code__.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.__name__ = f.__name__
return new_f
return check_accepts
Usage:
#accepts(int, (int,float))
def func(arg1, arg2):
return arg1 * arg2
func(3, 2) # -> 6
func('3', 2) # -> AssertionError: arg '3' does not match <type 'int'>
arg2 can be either int or float
On Python 3.3, you can use function annotations and inspect:
import inspect
def validate(f):
def wrapper(*args):
fname = f.__name__
fsig = inspect.signature(f)
vars = ', '.join('{}={}'.format(*pair) for pair in zip(fsig.parameters, args))
params={k:v for k,v in zip(fsig.parameters, args)}
print('wrapped call to {}({})'.format(fname, params))
for k, v in fsig.parameters.items():
p=params[k]
msg='call to {}({}): {} failed {})'.format(fname, vars, k, v.annotation.__name__)
assert v.annotation(params[k]), msg
ret = f(*args)
print(' returning {} with annotation: "{}"'.format(ret, fsig.return_annotation))
return ret
return wrapper
#validate
def xXy(x: lambda _x: 10<_x<100, y: lambda _y: isinstance(_y,float)) -> ('x times y','in X and Y units'):
return x*y
xy = xXy(10,3)
print(xy)
If there is a validation error, prints:
AssertionError: call to xXy(x=12, y=3): y failed <lambda>)
If there is not a validation error, prints:
wrapped call to xXy({'y': 3.0, 'x': 12})
returning 36.0 with annotation: "('x times y', 'in X and Y units')"
You can use a function rather than a lambda to get a name in the assertion failure.
As you certainly know, it's not pythonic to reject an argument only based on its type.
Pythonic approach is rather "try to deal with it first"
That's why I would rather do a decorator to convert the arguments
def enforce(*types):
def decorator(f):
def new_f(*args, **kwds):
#we need to convert args into something mutable
newargs = []
for (a, t) in zip(args, types):
newargs.append( t(a)) #feel free to have more elaborated convertion
return f(*newargs, **kwds)
return new_f
return decorator
This way, your function is fed with the type you expect
But if the parameter can quack like a float, it is accepted
#enforce(int, float)
def func(arg1, arg2):
return arg1 * arg2
print (func(3, 2)) # -> 6.0
print (func('3', 2)) # -> 6.0
print (func('three', 2)) # -> ValueError: invalid literal for int() with base 10: 'three'
I use this trick (with proper conversion method) to deal with vectors.
Many methods I write expect MyVector class as it has plenty of functionalities; but sometime you just want to write
transpose ((2,4))
The package typeguard provides a decorator for this, it reads the type information from type annotations, it requires Python >=3.5.2 though. I think the resulting code is quite nice.
#typeguard.typechecked
def my_function(this_var_is_an_int: int, this_var_is_a_float: float)
''' Here my code '''
pass
To enforce string arguments to a parser that would throw cryptic errors when provided with non-string input, I wrote the following, which tries to avoid allocation and function calls:
from functools import wraps
def argtype(**decls):
"""Decorator to check argument types.
Usage:
#argtype(name=str, text=str)
def parse_rule(name, text): ...
"""
def decorator(func):
code = func.func_code
fname = func.func_name
names = code.co_varnames[:code.co_argcount]
#wraps(func)
def decorated(*args,**kwargs):
for argname, argtype in decls.iteritems():
try:
argval = args[names.index(argname)]
except ValueError:
argval = kwargs.get(argname)
if argval is None:
raise TypeError("%s(...): arg '%s' is null"
% (fname, argname))
if not isinstance(argval, argtype):
raise TypeError("%s(...): arg '%s': type is %s, must be %s"
% (fname, argname, type(argval), argtype))
return func(*args,**kwargs)
return decorated
return decorator
I have a slightly improved version of #jbouwmans sollution, using python decorator module, which makes the decorator fully transparent and keeps not only signature but also docstrings in place and might be the most elegant way of using decorators
from decorator import decorator
def check_args(**decls):
"""Decorator to check argument types.
Usage:
#check_args(name=str, text=str)
def parse_rule(name, text): ...
"""
#decorator
def wrapper(func, *args, **kwargs):
code = func.func_code
fname = func.func_name
names = code.co_varnames[:code.co_argcount]
for argname, argtype in decls.iteritems():
try:
argval = args[names.index(argname)]
except IndexError:
argval = kwargs.get(argname)
if argval is None:
raise TypeError("%s(...): arg '%s' is null"
% (fname, argname))
if not isinstance(argval, argtype):
raise TypeError("%s(...): arg '%s': type is %s, must be %s"
% (fname, argname, type(argval), argtype))
return func(*args, **kwargs)
return wrapper
I think the Python 3.5 answer to this question is beartype. As explained in this post it comes with handy features. Your code would then look like this
from beartype import beartype
#beartype
def sprint(s: str) -> None:
print(s)
and results in
>>> sprint("s")
s
>>> sprint(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 13, in func_beartyped
TypeError: sprint() parameter s=3 not of <class 'str'>
All of these posts seem out of date - pint now provides this functionality built in. See here. Copied here for posterity:
Checking dimensionality When you want pint quantities to be used as
inputs to your functions, pint provides a wrapper to ensure units are
of correct type - or more precisely, they match the expected
dimensionality of the physical quantity.
Similar to wraps(), you can pass None to skip checking of some
parameters, but the return parameter type is not checked.
>>> mypp = ureg.check('[length]')(pendulum_period)
In the decorator format:
>>> #ureg.check('[length]')
... def pendulum_period(length):
... return 2*math.pi*math.sqrt(length/G)
you could try with the pydantic validation_decorator. from the documentation pydantic:
Data validation and settings management using python type annotations.
pydantic enforces type hints at runtime, and provides user friendly
errors when data is invalid.
In benchmarks pydantic is faster than all other tested libraries.
from pydantic import validate_arguments, ValidationError
#validate_arguments
def repeat(s: str, count: int, *, separator: bytes = b'') -> bytes:
b = s.encode()
return separator.join(b for _ in range(count))
a = repeat('hello', 3)
print(a)
#> b'hellohellohello'
b = repeat('x', '4', separator=' ')
print(b)
#> b'x x x x'
try:
c = repeat('hello', 'wrong')
except ValidationError as exc:
print(exc)
"""
1 validation error for Repeat
count
value is not a valid integer (type=type_error.integer)
"""
For me, the codes shared above looks complicated. What I did for defining 'generic decorator' for type-check:
I used *args, **kwargs feature, little extra work when using function/method but easy to manage.
Appropriate example definition for test
argument_types = {
'name':str,
'count':int,
'value':float
}
Decoration Defination
//from functools import wraps
def azure_type(func):
#wraps(func)
def type_decorator(*args, **kwargs):
for key, value in kwargs.items():
if key in argument_types:
if type(value) != argument_types[key]:
#enter code here
return 'Error Message or what ever you like to do'
return func(*args, **kwargs)
return type_decorator
Simple sample in code
// all other definitions
#azure_type
def stt(name:str, value:float)->(int):
#some calculation and creation of int output
count_output = #something int
return count_output
// call the function:
stt(name='ati', value=32.90) #can test from that

Using a dictionary to select function to execute

I am trying to use functional programming to create a dictionary containing a key and a function to execute:
myDict={}
myItems=("P1","P2","P3",...."Pn")
def myMain(key):
def ExecP1():
pass
def ExecP2():
pass
def ExecP3():
pass
...
def ExecPn():
pass
Now, I have seen a code used to find the defined functions in a module, and I need to do something like this:
for myitem in myItems:
myDict[myitem] = ??? #to dynamically find the corresponding function
So my question is, How do I make a list of all the Exec functions and then assign them to the desired item using the a dictionary? so at the end I will have myDict["P1"]() #this will call ExecP1()
My real problem is that I have tons of those items and I making a library that will handle them so the final user only needs to call myMain("P1")
I think using the inspect module, but I am not so sure how to do it.
My reason to avoid:
def ExecPn():
pass
myDict["Pn"]=ExecPn
is that I have to protect code as I am using it to provide a scripting feature within my application.
Simplify, simplify, simplify:
def p1(args):
whatever
def p2(more args):
whatever
myDict = {
"P1": p1,
"P2": p2,
...
"Pn": pn
}
def myMain(name):
myDict[name]()
That's all you need.
You might consider the use of dict.get with a callable default if name refers to an invalid function—
def myMain(name):
myDict.get(name, lambda: 'Invalid')()
(Picked this neat trick up from Martijn Pieters)
Simplify, simplify, simplify + DRY:
tasks = {}
task = lambda f: tasks.setdefault(f.__name__, f)
#task
def p1():
whatever
#task
def p2():
whatever
def my_main(key):
tasks[key]()
Not proud of it, but:
def myMain(key):
def ExecP1():
pass
def ExecP2():
pass
def ExecP3():
pass
def ExecPn():
pass
locals()['Exec' + key]()
I do however recommend that you put those in a module/class whatever, this is truly horrible.
If you are willing to add a decorator for each function, you can define a decorator which adds each function to a dictionary:
def myMain(key):
tasks = {}
def task(task_fn):
tasks[task_fn.__name__] = task_fn
#task
def ExecP1():
print(1)
#task
def ExecP2():
print(2)
#task
def ExecP3():
print(3)
#task
def ExecPn():
print(4)
tasks['Exec' + key]()
Another option is to place all the functions under a class (or in a different module) and use getattr:
def myMain(key):
class Tasks:
def ExecP1():
print(1)
def ExecP2():
print(2)
def ExecP3():
print(3)
def ExecPn():
print(4)
task = getattr(Tasks, 'Exec' + key)
task()
# index dictionary by list of key names
def fn1():
print "One"
def fn2():
print "Two"
def fn3():
print "Three"
fndict = {"A": fn1, "B": fn2, "C": fn3}
keynames = ["A", "B", "C"]
fndict[keynames[1]]()
# keynames[1] = "B", so output of this code is
# Two
You can just use
myDict = {
"P1": (lambda x: function1()),
"P2": (lambda x: function2()),
...,
"Pn": (lambda x: functionn())}
myItems = ["P1", "P2", ..., "Pn"]
for item in myItems:
myDict[item]()
This will call methods from dictionary
This is python switch statement with function calling
Create few modules as per the your requirement.
If want to pass arguments then pass.
Create a dictionary, which will call these modules as per requirement.
def function_1(arg):
print("In function_1")
def function_2(arg):
print("In function_2")
def function_3(fileName):
print("In function_3")
f_title,f_course1,f_course2 = fileName.split('_')
return(f_title,f_course1,f_course2)
def createDictionary():
dict = {
1 : function_1,
2 : function_2,
3 : function_3,
}
return dict
dictionary = createDictionary()
dictionary[3](Argument)#pass any key value to call the method
#!/usr/bin/python
def thing_a(arg=None):
print 'thing_a', arg
def thing_b(arg=None):
print 'thing_b', arg
ghetto_switch_statement = {
'do_thing_a': thing_a,
'do_thing_b': thing_b
}
ghetto_switch_statement['do_thing_a']("It's lovely being an A")
ghetto_switch_statement['do_thing_b']("Being a B isn't too shabby either")
print "Available methods are: ", ghetto_switch_statement.keys()
Often classes are used to enclose methods and following is the extension for answers above with default method in case the method is not found.
class P:
def p1(self):
print('Start')
def p2(self):
print('Help')
def ps(self):
print('Settings')
def d(self):
print('Default function')
myDict = {
"start": p1,
"help": p2,
"settings": ps
}
def call_it(self):
name = 'start'
f = lambda self, x : self.myDict.get(x, lambda x : self.d())(self)
f(self, name)
p = P()
p.call_it()
class CallByName():
def method1(self):
pass
def method2(self):
pass
def method3(self):
pass
def get_method(self, method_name):
method = getattr(self, method_name)
return method()
callbyname = CallByName()
method1 = callbyname.get_method(method_name)
```
def p1( ):
print("in p1")
def p2():
print("in p2")
myDict={
"P1": p1,
"P2": p2
}
name=input("enter P1 or P2")
myDictname
You are wasting your time:
You are about to write a lot of useless code and introduce new bugs.
To execute the function, your user will need to know the P1 name anyway.
Etc., etc., etc.
Just put all your functions in the .py file:
# my_module.py
def f1():
pass
def f2():
pass
def f3():
pass
And use them like this:
import my_module
my_module.f1()
my_module.f2()
my_module.f3()
or:
from my_module import f1
from my_module import f2
from my_module import f3
f1()
f2()
f3()
This should be enough for starters.

Categories

Resources