Python function not failing and returning none - python

I am writing robot test cases with python functions.
I have a python function like this
def ParseJSONUserData(jsonstring):
if len(jsonstring) == 0:
print("String is empty. No processing is possible.")
json_dict = json.loads(jsonstring)
if len(json_dict) == 0:
print("No data found in file.")
currentdt = json_dict[CURRENTDATETIME]
if len(currentdt) == 0:
print ("The Current datetime property is empty")
print ("Systems found: ", len( json_dict[SYSTEMS]))
if len(json_dict[SYSTEMS]) == 0 :
print("No systems found!")
for system_result in json_dict[SYSTEMS]:
if system_result[SERIALNUM] in systems:
print ("Duplicate systemserialnumber value: " + system_result[SERIALNUM] )
systems.add(system_result[SERIALNUM])
if len(system_result[PUBKEYS][0]["pubkey"]) == 0 :
print("No pubkey found for system: " + system_result[SERIALNUM] )
if len(system_result[PUBKEYS][0]["system"]) == 0 :
print("No pubkey system designator (typically intraop) found for system: " + system_result[SERIALNUM] )
This is my robot framework code.
${response}= GET ${host}/data ${data} headers=${header}
${op}= ParseJSONUserData response.json()
Log to console ${op}
I am trying any one of the validation is failed in python. It should fail here in robot code. But even if I pass wrong data python function getting executed and robot test case also getting success. Any help will be much appreciated.

For a keyword to fail, it must thrown an exception. Instead of printing a string, raise an error. For example:
if len(jsonstring) == 0:
raise Exception("String is empty. No processing is possible.")
For more information see Reporting keyword stats in the robot framework user guide, where it says this:
Reporting keyword status is done simply using exceptions. If an executed method raises an exception, the keyword status is FAIL, and if it returns normally, the status is PASS.
Normal execution failures and errors can be reported using the standard exceptions such as AssertionError, ValueError and RuntimeError. There are, however, some special cases explained in the subsequent sections where special exceptions are needed.

Related

How to clear the exception state in Python

I have a try/except block around a call to an API. It appears to me that once I get an exception, all valid try cases after that exception will see the same exception. The only way I have been able to get it to work is to re-start my Python script. I googled around and found PyErr_clear() but that is for the C-API. Is there something I can call from plain-old Python that will clear the exception state?
Here is the basic idea of what I am doing:
def get_and_print_data(key):
try:
data = get_data_from_some_3rd_party_api(key)
except Exception as ex:
print("Failed to get data for",key,": ",str(ex))
return
print("data=",data)
Then in main I have
get_and_print_data("Valid Key") ## This works
get_and_print_data("INvalid Key") ## This gets exception, as expected
get_and_print_data("Valid Key") ## This and all subsequent calls to get_and_print_data() fail with the same exception.
As an example of why I think it's the 3rd party API that is having issues:
def get_data_from_some_3rd_party_api(key):
if key == "Valid Key":
return "This is some good data."
else:
raise ValueError("Invalid Key")
def get_and_print_data(key):
try:
data = get_data_from_some_3rd_party_api(key)
except Exception as ex:
print("Failed to get data for",key,": ",str(ex))
return
print("data=",data)
get_and_print_data("Valid Key") ## This works
get_and_print_data("INvalid Key") ## This gets exception, as expected
get_and_print_data("Valid Key") ## This works
Try running this locally, and you should see that the subsequent valid keys still work.

python UnboundLocalError referenced before assignment

I see that this seems to be a common error, but I'm not seeing the answer for my case.
UnboundLocalError: local variable 'tfstate_dict' referenced before assignment
#!/usr/bin/env python
import json
def main():
get_sfleet_id()
def get_sfleet_id():
try:
f=open("terraform_remote.tfstate", "r")
contents =f.read()
tfstate_dict = json.load(contents)
except:
print("error loading %s" % f)
print(contents)
print(tfstate_dict)
if __name__ == '__main__': main()
As I wrote in my comment, tfstate_dict does not come in to existence until you exit your try block. But that's not to say that it applies to all the preceding code; it simply applies to tfstate_dict because it happens to be the very last line.
This is easily testable with the following:
try:
a = int(2)
b = int(3)
c = int('hi')
except:
print(locals())
print()
print(locals().get('a'))
You should see that 'a' and 'b' are both defined and can be accessed (depending on how you're running this code, there could a lot of stuff in locals() too). So, the existence of 'a' and 'b' gives you no assurance that 'c' exists.
There's two issues with your current exception handling:
There's probably too much going on in your try block to be handled the way you currently do. This code will fail if the file cannot be located, but you wouldn't necessarily know that was happening. And if your code originally failed only on tfstate_dict = json.load(contents) you're now scratching your head why you're getting a NameError on print(contents) all of a sudden.
You don't want to be catching these issues with blanket except. At a minimum you'll want to use except Exception as e:, which allows you to print e too.
Here's a hypothetical situation where you handle the file not existing, and you also give a shot at parsing JSON.
import json
from json.decoder import JSONDecodeError
try:
with open('something.json') as infile:
try:
#data = json.load(infile) # This is what you'd really use
data = json.loads("{hi: 2}") # But let's make it fail
except JSONDecodeError:
print("Not valid JSON, try something else")
data = infile.read()
except FileNotFoundError:
print("Can't find file")
data = ''

If condition check with python

if not ping_device(ip):
if not reboot_device(device_1)
logger.error("Unable to reboot.. Serious issue")
break
logger.info("HARD Rebooted")
if not ping_device(ip):
logger.error("Ping failed after hard reboot")
else:
logger.info("Pinged success after reboot")
else:
logger.info("Pinged")
logger.info("Reboot passed")
logger.info("Getting uptime")
sw_version_check = get_sw_version(ip)
check_upgrade()
:
:
:
:
Here is my piece of code. Now if the ping_device fn in the first line succeeds, I have no problem. The else part comes into the picture.
Now if my first line ping_device fails, I call a reboot_device fn. after reboot, I again call the ping function to check my device is online.
After the ping success after the reboot, I need to get going with the else part of the first if condition with sw_version_check, check_upgrade() and rest of code traverses as mentioned with :
Will my logic after ping failure continue with sw_version_chec and check_upgrade?
You could have some separate variable, say doUpgrade, initialized to False and set to True at any point(s) in the first section where you have determined you need an upgrade. Then test that variable to see if the upgrade code needs to be executed.
Try using exceptions, they help make this type of control flow easier to reason about and are more "Pythonic":
def reboot_device(device):
if not your_reboot_device_fn(device):
raise DeviceRebootError('Unrecoverable reboot error')
else:
pass # Or anything else you want to do on success.
def ping_device(ip, device, did_try_reboot=False):
if not your_ping_device_fn(ip):
if did_try_reboot:
raise DevicePingError('Ping failed after hard reboot')
else:
try:
reboot_device(device)
except DeviceRebootError as e:
logging.error(e)
raise
else:
logger.info("HARD Rebooted")
ping_device(ip, device, did_try_reboot=True)
else:
pass # Or anything else you want to do on success.
try:
ping_device(ip, device_1)
except DevicePingError as e:
logging.error(e)
# NOTE: DeviceRebootError isn't caught so it will end the program.
else:
logging.info('Pinged')
sw_version_check = get_sw_version(ip)
check_upgrade()

Geopy with error handling

I have some Python code with error handling in place but for some reason the code still seems to be unable to handle this particular error:
raise GQueryError("No corresponding geographic location could be found for the specified location, possibly because the address is relatively new, or because it may be incorrect.")
geopy.geocoders.google.GQueryError: No corresponding geographic location could be found for the specified location, possibly because the address is relatively new, or because it may be incorrect.
This is the source:
import csv
from geopy import geocoders
import time
g = geocoders.Google()
spamReader = csv.reader(open('locations.csv', 'rb'), delimiter='\t', quotechar='|')
f = open("output.txt",'w')
for row in spamReader:
a = ', '.join(row)
#exactly_one = False
time.sleep(1)
try:
place, (lat, lng) = g.geocode(a)
except ValueError:
#print("Error: geocode failed on input %s with message %s"%(a, error_message))
continue
b = str(place) + "," + str(lat) + "," + str(lng) + "\n"
print b
f.write(b)
Have I not included enough error handling? I was under the impression that "except ValueError" would handle this situation but I must be wrong on that.
Thanks in advance for any help out!
P.S. I pulled this out of the code but I don't know what it really means yet:
def check_status_code(self,status_code):
if status_code == 400:
raise GeocoderResultError("Bad request (Server returned status 400)")
elif status_code == 500:
raise GeocoderResultError("Unkown error (Server returned status 500)")
elif status_code == 601:
raise GQueryError("An empty lookup was performed")
elif status_code == 602:
raise GQueryError("No corresponding geographic location could be found for the specified location, possibly because the address is relatively new, or because it may be incorrect.")
elif status_code == 603:
raise GQueryError("The geocode for the given location could be returned due to legal or contractual reasons")
elif status_code == 610:
raise GBadKeyError("The api_key is either invalid or does not match the domain for which it was given.")
elif status_code == 620:
raise GTooManyQueriesError("The given key has gone over the requests limit in the 24 hour period or has submitted too many requests in too short a period of time.")
Right now the try/except is only catching ValueErrors. To catch GQueryError as well, replace the except ValueError: line with:
except (ValueError, GQueryError):
Or if GQueryError isn't in your namespace, you may need something like this:
except (ValueError, geocoders.google.GQueryError):
Or to catch ValueError and all the errors listed in check_status_code:
except (ValueError, GQueryError, GeocoderResultError,
GBadKeyError, GTooManyQueriesError):
(Again, add geocoders.google. or whatever the error location is to the front of all the geopy errors if they're not in your namespace.)
Or, if you just want to catch all possible exceptions, you could simply do:
except:
but this is generally bad practice, because it'll also catch things like a syntax error in your place, (lat, lng) = g.geocode(a) line, which you don't want caught, so it's better to examine the geopy code to find all the possible exceptions it could be throwing that you want to catch. Hopefully all of those are listed in that bit of code you found.

How do I exit program in try/except?

I have this try/except code:
document = raw_input ('Your document name is ')
try:
with open(document, 'r') as a:
for element in a:
print element
except:
print document, 'does not exist'
How do I exit the program after I print "[filename] does not exist"? break and pass obviously don't work, and I don't want to have any crashing errors, so sys.exit is not an option.
Please ignore the try part - it's just a dummy.
Use the sys.exit:
import sys
try:
# do something
except Exception, e:
print >> sys.stderr, "does not exist"
print >> sys.stderr, "Exception: %s" % str(e)
sys.exit(1)
A good practice is to print the Exception that occured so you can debug afterwards.
You can also print the stacktrace with the traceback module.
Note that the int you return in sys.exit will be the return code of your program. To see what exit code your program returned (which will give you information about what happens and can be automated), you can do:
echo $?
Using
sys.exit(1)
is not a crashing error, it's a perfectly normal way to exit a program. The exit code of 1 is a convention that means something went wrong (you would return 0 in the case of a successful run).
Just re-raise it. It's more friendly for developer
document = raw_input ('Your document name is ')
try:
with open(document, 'r') as a:
for element in a:
print element
except:
print document, 'does not exist'
raise
Check python document in the Raising Exceptions section about re-raise error in except.
You can also put your code in a function and issue a return. You may call it main which you can call from your script.
def main():
document = raw_input ('Your document name is ')
try:
with open(document, 'r') as a:
for element in a:
print element
except:
print document, 'does not exist'
return
if __name__ == "__main__":
main()
In case that you are using an if statement inside a try, you are going to need more than one sys.exit() to actually exit the program.
For example, you are parsing an argument when calling the execution of some file, e.g. $./do_instructions.py 821 such as:
import sys
# index number 1 is used to pass a set of instructions to parse
# allowed values are integer numbers from 1 to 4, maximum number of instructions is 3
arg_vector = "821" # <- pretending to be an example of sys.argv[1]
if len(arg_vector) > 3:
sys.exit(2) # <- this will take you out, but the following needs an extra step.
# for an invalid input (8).
for i in arg_vector:
# to validate that only numbers are passed as args.
try:
int(i) # <- 8 is valid so far
# value (8) is not valid, since is greater than 4
if (int(i) == 0) or (int(i) > 4):
print("Values must be 1-4")
# the following call does not takes you out from the program,
# but rise the SystemExit exception.
sys.exit(2)
except SystemExit: # <- needed to catch the previous as the first evaluation
# The following parameter "2" is just for this example
sys.exit(2) # <- needed to actually interrupt the execution of the program/script.
# if there is no "except SystemExit:", the following will be executed when the
# previous "if" statement evaluates to True and the sys.exit(2) is called.
#
# and the "print("Only num...") function will be called, even when the intention
# of it is to advice the *user* to use only numbers, since 8 is a number this
# shouldn't be executed.
except:
print("Only numbers are allowed.")
sys.exit(2)
otherwise, you want to use one try-except block for each evaluation.
Probably not the best practice, but it worked for me:
import sys
close = False
try:
if SomethingBadHappend:
close = True
except:
pass
if close:
sys.exit(1)
Close dose does not seem to work inside 'try'.

Categories