Function which take as input variable result from other function - python

As I'm new in python coding, I stuck on defining a function which take as input variable from other function. Generally my code is :
#!/usr/bin/python
import configparser
import re
var="abc"
class Config:
def getSources(var):
config = configparser.ConfigParser()
config.read("C\\configFile.ini")
connection=config.get(connectinfo,'connectStr')
if source in connection_source:
print (connection_connectstr)
else:
print ('Something wrong')
return connection
try:
emp1 = Config.getSources(var)
except configparser.NoSectionError:
print ("Senction is not correct")
def getTables(connection)
In few words, I get data from Config.ini file, then do some process. Next I want to create next function getTables which as input take result from first function. By the way in getSources I would like to make it as return statement, unfornatelly return is returning null... Print works fine.

You need to return the value or raise an exception:
if source in connection_source:
return (connection_connectstr)
else:
raise configparser.NoSectionError('Something wrong')

Related

How to avoid running argument function before the main function

I want to create a function that will react according to the success of the argument function and get the argument function's name.
Something like
def foo(argument_function):
try:
argument_function
print(f"{somehow name of the argument_function} executed successfully.")
except:
print(f"{somehow name of the argument_function} failed.")
argument_function should be executed only under the try statement. Otherwise, it will give an error and stop the script which I am trying to avoid.
{somehow name of the argument_function} should return the name of the argument_function.
for successful attempt:
foo(print("Hello world!"))
should return
>>Hello world!
>>print("Hello world!") executed successfully.
for unsuccessful attempt:
foo(prnt("Hello world!"))
should return
>>prnt("Hello world!") failed.
import typing
def foo(argument_function:typing.Callable):
try:
argument_function()
print(f"{argument_function.__name__} executed successfully.")
except:
print(f"{argument_function.__name__} failed.")
print(foo.__name__) # returns foo
Or use:
def foo(argument_function:callable):
__name__ returns function name and if you ensure the function is an object then adding () should run the function

how to use builtins.input for multiple inputs

In my unittest, I have 2 prompts in the test. I am trying to use 2 #patch("builtins.input"), but it seems to only take the 1 of the return values.
#patch("builtins.input")
#patch("builtins.input")
def test_setProfileName_modify_init_prompt_empty(self, paramName1, paramName2):
paramName1.return_value = self.profileName_prod
paramName2.return_value = self.profileName_dev
a = c.ALMConfig(self.configType)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_dev)
self.assertEqual(a.profileName, self.profileName_dev)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_prod)
self.assertEqual(a.profileName, self.profileName_prod)
The call a.setProfileName() will prompt for 1 input using input() call in my function. In this test, it will call a.setProfileName() twice.
First time I call a.setProfileName(), I would enter the value of self.profileName_prod.
The second time I call it, I would enter the value of self.profileName_dev.
But the test fails after the second a.setProfileName() case (at the second to last assertEqual after the second a.setProfileName() call).
self.assertEqual(a.getProfileName(), self.profileName_prod)
The reason for the failure is because a.getProfileName is returning the value for self.profileName_dev instead of self.profileName_prod.
I had tested my code in the python cli to make sure the behavior is correct.
Any feedback is appreciated.
Thanks guys!
Patching the same function twice does not make it return different values on different calls. You can use the side_effect attribute of the Mock object by setting it with a list of values you want the function to return in successive calls instead:
from unittest.mock import patch
#patch('builtins.input', side_effect=['dev', 'prod'])
def test_input(mock_input):
assert input() == 'dev'
assert input() == 'prod'
test_input() # this will not raise an exception since all assertions are True
I revisited blhsing's solution, and it is more much elegant. Here is my working test code now:
#patch('builtins.input', side_effect=['dev', 'production'])
def test_setProfileName_modify_init_prompt_update_new(self, paramName):
a = c.ALMConfig(self.configType)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_dev)
self.assertEqual(a.profileName, self.profileName_dev)
self.assertEqual(a.getProfileName(), self.profileName_dev)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_prod)
self.assertEqual(a.profileName, self.profileName_prod)
Thanks everyone for your comments! :)
To provide a more simple and to the point answer for anyone visiting this in 2020 and later, you can just do
`with patch("builtins.input", return_value = "Whatever you want returned"):
self.assertEqual("<Object>", "Whatever you want returned")
`
in python 3.8 in later.
To see a full easy to follow example keep reading otherwise stop here.
Full Example:
The below code shows a full example of this with a class named "AnsweredQuestion" and with a unit test
`class AnsweredQuestion:
def __init__(self):
print("I hope you find this example helpful")
def get_input(self):
print("Enter your input")
entered_data = input()
print("You entered '" + entered_data + "'")
return get_input
`
Unit Test to test above class AnsweredQuestion
`
import builtins
import unittest
import sys
sys.path.append(".")
# Assuming a directory named "answers" in your setup
import answers
from answers import AnsweredQuestion
from unittest.mock import Mock, patch
class TestAnsweredQuestion(unittest.TestCase):
def test_get_input(self):
with patch("builtins.input", return_value = "Thanks. This is correct"):
self.assertEqual(AnsweredQuestion.get_input(), "Thanks this is correct")
if __name__ == '__main__':
unittest.main()
`

Determining the number of return values in a Python function

I am creating a decorator that catches a raised error in it's target function, and allows the user to continue executing the script (bypassing the function) or drop out of the script.
def catch_error(func):
"""
This decorator is used to make sure that if a decorated function breaks
in the execution of a script, the script doesn't automatically crash.
Instead, it gives you the choice to continue or gracefully exit.
"""
def caught(*args):
try:
return func(*args)
except Exception as err:
question = '\n{0} failed. Continue? (yes/no): '.format(func.func_name)
answer = raw_input(question)
if answer.lower() in ['yes','y']:
pass
else:
print " Aborting! Error that caused failure:\n"
raise err
return None
return caught
Notice that, if the user chooses to bypass the error-returning function and continue executing the script, the decorator returns None. This works well for functions that only return a single value, but it is crashing on functions that attempt to unpack multiple values. For instance,
# Both function and decorator return single value, so works fine
one_val = decorator_works_for_this_func()
# Function nominally returns two values, but decorator only one, so this breaks script
one_val, two_val = decorator_doesnt_work_for_this_func()
Is there a way that I can determine the number of values my target function is supposed to return? For instance, something like:
def better_catch_error(func):
def caught(*args):
try:
return func(*args)
except Exception as err:
...
num_rvals = determine_num_rvals(func)
if num_rvals > 1:
return [ None for count in range(num_rvals) ]
else:
return None
return caught
As always, if there is a better way to do this sort of thing, please let me know. Thanks!
UPDATE:
Thanks for all the suggestions. I decided to narrow the scope of catch_error to a single class of functions, which only return one string value. I just split all the functions returning more than one value into separate functions that return a single value to make them compatible. I had been hoping to make catch_error more generic (and there were several helpful suggestions on how to do that), but for my application it was a little overkill. Thanks again.
Martijn Pieters answer is correct, this is a specific case of the Halting Problem
However you might get around it by passing a error return value to the decorator. Something like this:
def catch_error(err_val):
def wrapper(func):
def caught(*args):
try:
return func(*args)
except Exception as err:
question = '\n{0} failed. Continue? (yes/no): '.format(func.func_name)
answer = raw_input(question)
if answer.lower() in ['yes','y']:
pass
else:
print " Aborting! Error that caused failure:\n"
raise err
return err_val
return caught
return wrapper
Then you could decorate using:
#catch_error({})
def returns_a_dict(*args, **kwargs):
return {'a': 'foo', 'b': 'bar'}
Also as a point of style, if you are grabbing *args in your wrapped function, you should probably also grab **kwargs so that you can properly wrap functions that take keyword arguments. Otherwise your wrapped function will fail if you call wrapped_function(something=value)
Finally, as another point of style, it is confusing to see code that does if a: pass with an else. Try using if !a in these cases. So the final code:
def catch_error(err_val):
def wrapper(func):
def caught(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as err:
question = '\n{0} failed. Continue? (yes/no): '.format(func.func_name)
answer = raw_input(question)
if answer.lower() not in ['yes','y']:
print " Aborting! Error that caused failure:\n"
raise err
return err_val
return caught
return wrapper
No, there is no way you can determine that.
Python is a dynamic language, and a given function can return an arbitrary sequence of any size or no sequence at all, based on the inputs and other factors.
For example:
import random
def foo():
if random.random() < 0.5:
return ('spam', 'eggs')
return None
This function will return a tuple half of the time, but None the other half, so Python has no way of telling you what foo() will return.
There are many more ways your decorator can fail, btw, not just when the function returns a sequence that the caller then unpacks. What if the caller expected a dictionary and starts trying to access keys, or a list and wants to know the length?
Your decorator can't predict what your function is going to return, but nothing prevents you from telling the decorator what return signature to simulate:
#catch_error([None, None])
def tuple_returner(n):
raise Exception
return [2, 3]
Instead of returning None, your decorator will return its argument ([None, None]).
Writing an argument-taking decorator is just slightly tricky: The expression catch_error([None, None]) will be evaluated, and must return the actual decorator that will be applied to the decorated function. It looks like this:
def catch_error(signature=None):
def _decorator(func):
def caught(*args):
try:
return func(*args)
except Exception as err:
# Interactive code suppressed
return signature
return caught
return _decorator
Note that even if you just want it to return None, you need to execute it once:
#catch_error()
def some_function(x):
...

Self scanning code to prevent print statments

I have a python project I'm working on whereby instead of print statements I call a function say() so I can print information while in development and log information during production. However, I often forget this and put print statements in the code by mistake. Is there anyway to have the python program read its own source, and exit() if it finds any print statements outside of the function say()?
This can be done using the ast module. The following code will find any calls of the print statement and also of the print() function in case you are on Python 3 or Python 2 with the print_function future.
import ast
class PrintFinder(ast.NodeVisitor):
def __init__(self):
self.prints_found = []
def visit_Print(self, node):
self.prints_found.append(node)
super(PrintFinder, self).generic_visit(node)
def visit_Call(self, node):
if getattr(node.func, 'id', None) == 'print':
self.prints_found.append(node)
super(PrintFinder, self).generic_visit(node)
def find_print_statements(filename):
with open(filename, 'r') as f:
tree = ast.parse(f.read())
parser = PrintFinder()
parser.visit(tree)
return parser.prints_found
print 'hi'
for node in find_print_statements(__file__):
print 'print statement on line %d' % node.lineno
The output of this example is:
hi
print statement on line 24
print statement on line 26
While I don't recommend doing this, if you really want to you could have the Python interpreter throw an error by redefining the print statement.
If using Python 3, simply put this near the beginning / top of your code:
print = None
If there are any print statements, you will get a TypeError: 'NoneType' object is not callable error.
If using Python 2.x, you might use the idea suggested in another answer to allow Python 2.x to have an overridable print statement.
from __future__ import print_function
print = None
Putting this together with your say() function, you could do something like:
print_original = print
print = None
def say(data):
print = print_original
# Your current `say()` code here, such as:
print(data) # Could just use `print_original` instead.
# Redefine print to make the statement inaccessible outside this function.
print = None

cleaning up when using exceptions and files in python

I'm learning python for a couple of days now and am struggling with its 'spirit'.
I'm comming from the C/C++/Java/Perl school and I understand that python is not C (at all) that's why I'm trying to understand the spirit to get the most out of it (and so far it's hard)...
My question is especially focused on exception handling and cleaning:
The code at the end of this post is meant to simulate a fairly common case of file opening/parsing where you need to close the file in case of an error...
Most samples I have seen use the 'else' clause of a try statement to close the file... which made sense to me until I realized that the error might be due to
the opening itself (in which case
there is no need to close the not
opened file)
the parsing (in which
case the file needs to be closed)
The trap here is that if you use the 'else' clause of a try bloc then the file never gets closed if the error happens during parsing!
On the other end using the 'finally' clause result in an extra necessary check because the file_desc variable may not exist if the error happened during the opened (see comments in the code below)...
This extra check is inefficient and full of shit because any reasonable program may contain hundreds of symbols and parsing the results of dir() is a pain in the ass... Not to mention the lack of readability of such a statement...
Most other languages allow for variable definitions which could save the day here... but in python, everything seems to be implicit...
Normally, one would just declare a file_desc variable, then use many try/catch blocs for every task... one for opening, one for parsing and the last one for the closing()... no need to nest them... here I don't know a way to declare the variable... so I'm stuck right at the begining of the problem !
so what is the spirit of python here ???
split the opening/parsing in two different methods ? How ?
use some kind of nested try/except clauses ??? How ?
maybe there is a way to declare the file_desc variable and then there would be no need for the extra checking... is it at all possible ??? desirable ???
what about the close() statement ??? what if it raises an error ?
thanx for your hints... here is the sample code:
class FormatError(Exception):
def __init__(self, message):
self.strerror = message
def __str__(self):
return repr(message)
file_name = raw_input("Input a filename please: ")
try:
file_desc = open(file_name, 'r')
# read the file...
while True:
current_line = file_desc.readline()
if not current_line: break
print current_line.rstrip("\n")
# lets simulate some parsing error...
raise FormatError("oops... the file format is wrong...")
except FormatError as format_error:
print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
except IOError as io_error:
print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)
else:
file_desc.close()
# finally:
# if 'file_desc' in dir() and not file_desc.closed:
# file_desc.close()
if 'file_desc' in dir():
print "The file exists and closed={0}".format(file_desc.closed)
else:
print "The file has never been defined..."
The easiest way to deal with this is to use the fact that file objects in Python 2.5+ are context managers. You can use the with statement to enter a context; the context manager's __exit__ method is automatically called when exiting this with scope. The file object's context management automatically closes the file then.
try:
with file("hello.txt") as input_file:
for line in input_file:
if "hello" not in line:
raise ValueError("Every line must contain 'hello'!")
except IOError:
print "Damnit, couldn't open the file."
except:
raise
else:
print "Everything went fine!"
The open hello.txt handle will automatically be closed, and exceptions from within the with scope are propagated outside.
Just a note: you can always declare a variable, and then it would become something like this:
file_desc = None
try:
file_desc = open(file_name, 'r')
except IOError, err:
pass
finally:
if file_desc:
close(file_desc)
Of course, if you are using a newer version of Python, the construct using context manager is way better; however, I wanted to point out how you can generically deal with exceptions and variable scope in Python.
As of Python 2.5, there's a with command that simplifies some of what you're fighting with. Read more about it here. Here's a transformed version of your code:
class FormatError(Exception):
def __init__(self, message):
self.strerror = message
def __str__(self):
return repr(message)
file_name = raw_input("Input a filename please: ")
with open(file_name, 'r') as file_desc:
try:
# read the file...
while True:
current_line = file_desc.readline()
if not current_line: break
print current_line.rstrip("\n")
# lets simulate some parsing error...
raise FormatError("oops... the file format is wrong...")
except FormatError as format_error:
print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
except IOError as io_error:
print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)
if 'file_desc' in dir():
print "The file exists and closed={0}".format(file_desc.closed)
else:
print "The file has never been defined..."
OK, I'm an ass.
edit:and BTW, many thanx for those who already answered while I was posting this
The code below does the trick.
You must create a nested block with the 'with as' statement to make sure the file is cleaned:
class FormatError(Exception):
def __init__(self, message):
self.strerror = message
def __str__(self):
return repr(message)
file_name = raw_input("Input a filename please: ")
try:
#
# THIS IS PYTHON'S SPIRIT... no else/finally
#
with open(file_name, 'r') as file_desc:
# read the file...
while True:
current_line = file_desc.readline()
if not current_line: break
print current_line.rstrip("\n")
raise FormatError("oops... the file format is wrong...")
print "will never get here"
except FormatError as format_error:
print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
except IOError as io_error:
print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)
if 'file_desc' in dir():
print "The file exists and closed={0}".format(file_desc.closed)
else:
print "The file has never been defined..."
Close can to my knowledge never return an error.
In fact, the file handle will be closed when garbage collected, so you don't have to do it explicitly in Python. Although it's still good programming to do so, obviously.

Categories

Resources