i have a code :
s = '127.0.0.0'
def validate(a):
a = s.split('.')
if len(a) !=4:
return False
for x in a :
if not x.isdigit():
return False
i = int(x)
if i < 0 or i > 255 :
return False
return False
try:
validate(s) #ip validation
#my code here
except :
print("insert you're ip correctly")
can i combine if else with try catch like that?
if the try catch got error message or like return false from if condition it will run the except condition, if not it will run the try condition until the process is end.
there's have a better ways to dot this?
You can raise an exception if the function returns False, by doing:
s = '127.0.0.0'
def validate(a):
a = a.split('.')
if len(a) !=4:
return False
for x in a :
if not x.isdigit():
return False
i = int(x)
if i < 0 or i > 255 :
return False
return True
try:
if not validate(s): #ip validation
raise TypeError
except TypeError:
print("insert you're ip correctly")
Note: you probably want to return True for the end, since I believe that's when the function validates successfully, and a = a.split('.') not s.split, or else you're splitting the global variable s.
Tip: when using try...except, try to catch a specific error than to use the catch-all except:.
The answers above may be technically correct, but considering coding style etc. I don't see any reason to use exceptions here instead a plain if else:
if not validate(s): #ip validation
print("insert you're ip correctly")
That actually does what you want and it's much cleaner and better to read.
Try/catch is to handle exceptions, not to handle return values from methods. In your case, what you wrote would compile but is not what you want to do.
The easiest solution for you would be it use what already exists in python, ie. socket, which can nicely validate IP for you. If you still want to use the validate() method for other purpose, then you can write:
import socket
def validate(a):
socket.inet_aton(s)
try:
validate(s)
# your code here
except socket.error:
print("insert your ip correctly")
In that case, the socket.inet_aton method will raise the exception socket.error, which you can then catch. If for some reason you do not want to use socket, then you can define your own exception, raise it from validate() and catch it outside validate().
For Python 3, you will be better served by ipaddress as socket is too permissive (for good reasons, see man inet(3)):
import ipaddress
def validate(a):
ipaddress.ip_address(a)
try:
validate(s)
# your code here
except ValueError:
print("insert your ip correctly")
On a side note, I believe you want to return True as the last line of validate(), but that would not change the problem.
On a (second) side note, catching all exceptions (bare catch statement) is bad practice. In your code you handle a specific error (IP not valid) you should only catch exceptions related to this problem.
Related
I am working on a small texting application using Twilio API. Recently, I had some issues with the API so I added an Exception in my get_current_credits() function.
I am quite new to Python and programming in general and I would like to know what would be the cleanest way to do that.
If the Exception is throw, I only return a String. If not, I am returning a tuple. What would be the cleanest way to see what was the return from my inject_credits() function, I am thinking about type(res) but does seems a quick and dirty solution?
def get_current_credits():
try:
balance_data = twilio_client.api.v2010.balance.fetch()
balance = float(balance_data.balance)
currency = balance_data.currency
return balance, currency
except Exception:
return "503 Service Unavailable"
def inject_credit():
res = get_current_credits()
# if Exception:
# return the Exception message as a string
# else, do the following:
(credit, currency) = res
if currency != "EUR":
credit = currency_converter.convert(credit, currency, 'EUR')
return dict(credit=(round(credit,2)))
You could move the Exception outside, into the body of inject_credit. Thus, you don't have to do any if statements inside inject_credit, you can just catch the Exception there itself.
Checking the type isn't a bad idea, but it is not very clear what is being done if someone is only reading inject_credit.
You can try this:
if type(get_current_credits()) == str:
# Do something if it is a string
else:
# Do something if it is a tuple
However, the best way would be to add the try statement outside of the function so that you can catch the exception there instead.
try:
get_current_credits()
except Exception as e:
print(e)
# Do whatever
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()
I've written a python script that wants to write logs to a file at /var/log/myapp.log. However, on some platforms this doesn't exist, or we might not have permission to do that. In that case, I'd like to try writing somewhere else.
def get_logfile_handler():
log_file_handler = None
log_paths = ['/var/log/myapp.log', './myapp.log']
try:
log_file_handler = logging.FileHandler(log_paths[0])
except IOError:
log_file_handler = logging.FileHandler(log_paths[1])
return log_file_handler
The above code may work, but it seems far from elegant - in particular, trying a different file as part of the exception handling seems wrong. It could just throw another exception!
Ideally, it would take an arbitrary list of paths rather than just two. Is there an elegant way to write this?
you can simply use a loop such as:
def get_logfile_handler():
log_file_handler = None
log_paths = ['/var/log/myapp.log', './myapp.log']
for log_path in log_paths:
try:
return logging.FileHandler(log_path)
except IOError:
pass
raise Exception("Cannot open log file!")
HTH
There is, as #PM-2's comment suggests, no need to reference each possible path individually. You could try something like this:
def getlogfile_handler():
log_file_handler = None
log_paths = ('/var/log/myapp.log', './myapp.log') # and more
for log_path in log_paths:
try:
log_file_handler = logging.FileHandler(log_path)
break
except IOError:
continue
else:
raise ValueError("No log path available")
return log_file_handler
The else clause handles the case where the loop terminates without finding a suitable log_path value. If the loop breaks early then (and only then) the return statement is executed.
It's perfectly OK to use exceptions for control flow purposes like this - the cases are exceptional but they aren't errors - the only real error occurs when no path can be found, in which case the code raises its own exception that the caller may catch if it so chooses.
def get_logfile_handler( log_files ):
log_file_handler = None
for path in log_files:
try:
log_file_handler = logging.FileHandler(path)
break
except IOError:
pass
return log_file_handler
This may solve your problem. You can define locally/globally instead of passing as a parameter.
As a possible solution if you want to avoid handling exceptions you can check the Operating System you are on by using the platform module and then choose the required path. Then you can use the os and stat modules in order to check permissions.
import platform
import os
import stat
...
#the logic goes here
...
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'.
Is there a way to execute a try statement and return the error body as a variable?
i.e.
var = ''
try:
error generating code
except:
var = exception_body
Yes, use the as syntax of except:
try:
raise Exception("hello world")
except Exception as x:
print(x)
In earlier versions of Python, this would be written except Exception, x: which you may see from time to time.