Try / except syntax in Python with two of the same exceptions - python

I am checking emails against two lists -- a list of domains and a list of individual emails.
How would I construct the following try statement --
Try: 'email in email_list'
Except DoesNotExist: 'domain in domain list' # if email not found
Except DoesNotExist: 'print error message' # if both email and domain not found
What syntax do I need to use to construct this statement?

It sounds like you're looking for something like:
if email in email_list:
# do something with email
elif domain in domain_list:
# do something with domain
else:
print "neither email nor domain found"
There is probably no need for exceptions in this case.

Why don't define two exceptions: DomainDoesNotExists, EmailDomainDoesNotExists ?
try:
'email in email_list'
except DomainDoesNotExists:
...
except EmailDomainDoesNotExists:
...
There is no way to do what you want with only one Exception type (e.g. DoesNotExists).
But you better listen to #Greg Hewgill, in this case you don't need exceptions

It is hard to know what you are trying to do. Your capitalizations are a problem. When you catch exceptions, proceed from the most specific to the general. The first handler block handles the exception and puts you out of the try-except progression.
try:
yourEmailRoutine
except DomainDoesNotExist:
##code to be carried out if domain does not exist...
print "The domain %s does not exist." % yourDomainName
Since emails are often malformed, you might want to use Greg's suggestion to deal with this in an if-elif-else progression.

Related

Python Django - delaying ValidationError until for loop completes

I'm working on an app that simulates a social media site. I currently have a form where users can enter in their friends' emails so they can be invited to join the app.
Let's say we have a user who enters in three email addresses to the email form which are then saved as a list of strings:
emails_to_invite = ["jen#website.com", "mike#website.com", "joe#website.com"]
In the database, we already have a list of users who have already been invited to the site:
current_users = ["jen#website.com", "mike#website.com", "dan#website.com", "kim#website.com"]
So we have two users who have already been invited: jen#website.com and mike#website.com.
I'm trying to write some code that returns a ValidationError and can list both matched users in the message. Here's what I have so far:
for email in emails_to_invite:
if email in current_users:
raise forms.ValidationError(f"{email} is already in the database.")
Here's how I want this error to display:
jen#website.com is already in the database.
mike#website.com is already in the database.
But right now, the error only displays the first email:
jen#website.com is already in the database.
I also need mike#website.com to display too. It appears that the for loop stops once it recognizes one match, but I need it to keep going until it recognizes all matches. Can anyone offer some suggestions?
If you don't want an Exception in a code-block to halt your execution (and hide further exceptions, as you've found), put the susceptible code in a a try/except block to handle the error as you see fit.
To later raise the exception, consider using something like:
raised_exceptions = []
<loop that might raise exceptions>
try:
<loop that might raise exceptions>
except Exception as e:
raised_exceptions.append(e)
<do something with the exceptions you saved>
That being said, IMO you shouldn't be using exceptions in this way - consider returning a series of lists, one per possible outcome, instead: email sent and already invited (and/or joined user)

Python try / except / else loop does both the try and else actions

I'm running a Python script to post a Tweet if the length is short enough with an exception for errors and an else statement for messages that are too long.
When I run this, it posts the Tweet and still gives the Tweet too long message. Any idea why that is happening and how to make it work as intended?
if len(tweet_text) <= (280-6):
try:
twitter = Twython(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_KEY,ACCESS_SECRET)
twitter.update_status(status=tweet_text)
except TwythonError as error:
print(error)
else:
print("Tweet too Long. Please try again.")
The first string is checking the length of the tweet. Move the else four spaces back. Because try/except construction can be try/except/else construction
From the docs:
The try … except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. (emphasis added)
Spaces/Tabs matter in Python.
What your snippet says in common English
is "Try to post the tweet, unless there's an error, then print the error. If there's not an error, print 'Tweet too long. Please try again.'"
What you want is:
if len(tweet_text) <= (280-6):
try:
twitter = Twython(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_KEY,ACCESS_SECRET)
twitter.update_status(status=tweet_text)
except TwythonError as error:
print(error)
else:
print("Tweet too Long. Please try again.")

how to jump a list member in python?

so I'm trying to send i message to a group of people . I want to know how can I jump to 'test2' (next list member ) if 'test1' (current list member ) got an error .
profile_id = ['test1','test2']
for ids in profile_id:
api.send_direct_message(ids,text)
for iterates trough iprofile_id. So, the variable ids will first be the element 'test 1', do whatever is inside the for loop (i.e., send message to the person that is called 'test 1'. Then ids becomes 'test2', and a message is sent to 'test2'. But you try sending a message to the list of people, not the person picked (ids). I assume that the function send_direct_message does not allow lists, so therefore you need to have your third line be api.send_direct_message(ids, text).
Why not use TRY and then EXCEPT for the relevant class?
You can then use PASS to do nothing and continue to the next.
as Menashe already said, you can use TRY, EXCEPT and PASS.
like this:
profile_id = ['test1','test2']
for ids in profile_id:
try:
api.send_direct_message(ids,text)
except:
pass
You can try to use try/except for that, but only in a case if you raise an exception in send_direct_message
profile_ids = ['test1','test2']
for index, profile_id in enumerate(profile_ids):
try:
api.send_direct_message(profile_id,text)
# assume that using just Exception is not a good tone, try to use specific exception you raise in the method here instead of just Exception
except Exception as exc:
if (index+1) >= len(profile_ids):
break
api.send_direct_message(profile_ids[index+1], text)
# but in such a case think of list index out of range error, that will be thrown when list will go to an end

Python: assert if string matches a format

I have some unit tests for my Django API using Django Rest Framework APIClient.
Different endpoints of the API return custom error messages, some with formatted strings like: 'Geometry type "{}" is not supported'.
I'm asserting the status code from the client responses and error message keys, but there are cases that I'd like to figure what error message is returned to make sure nothing else has caused that error.
So I'd like to validate the returned error message against the original unformatted string too. For example if I receive an error message like 'Geometry type "Point" is not supported', I'd like to check if it matches the original unformatted message, i.e. 'Geometry type "{}" is not supported'.
The solutions I've thought of so far:
First: replacing the brackets in the original string with a regex pattern and see if it matches the response.
Second: (the cool idea, but might fail in some cases) using difflib.SequenceMatcher and test if the similarity ratio is bigger than, for example, 90%.
UPDATE
Here's an example:
There's a dict of error messages from which each error picks the relevant message, adds the format arguments if needed, and raises its error:
ERROR_MESSAGES = {
'ERROR_1': 'Error message 1: {}. Do something about it',
'ERROR_2': 'Something went wrong',
'ERROR_3': 'Check you args: {}. Here is an example: {}'
}
Now an error happens in my DRF serializer during processing a request and it raises an error:
try:
some_validation()
except SomeError as e:
raise serializers.ValidationError({'field1': [ERROR_MESSAGES['ERROR_N1'], ERROR_MESSAGES['ERROR_N2']], 'field2': ['ERROR_N3']})
Now in a specific test, I'd like to make sure a certain error message is there:
class SomeTestCases(TestCase):
def test_something(self):
response = self.client.post(...)
self.assertThisMessageIsInResponse(response.data, ERROR_MESSAGES['ERROR_K'])
response.data can be just a string or a dict or list of errors; i.e. whatever that can go in ValidationError.
Pointing to the error message location within response.data for each test case is no problem. The concern of this question is dealing with comparison between formatted and unformatted strings.
So far the easiest approach has been regex. I'm mostly curios about if there's a built-in assertion for this and what other solutions can be used.
You are looking for assertRegex():
class SomeTestCases(TestCase):
def test_something(self):
response = self.client.post(...)
self.assertRegex(response.data, r'^your regex here$')
See also assertNotRegex.
Seems like regex would be the easiest solution here
import re
msg = 'Geometry type "point" is not supported'
assert re.match(r'^Geometry type ".+" is not supported$', msg)

Validate IP address from list

I would like to validate IP addresses from a list that may contain incorrectly formated addresses or other garbage. If the field does not contain a properly formated field, simply continue ignoring that field.
Per How to validate IP address in Python? it seems that there are two methods two accomplish this, REGEX or socket.inet_aton().
Below is an attempt to use socket.inet_aton() to parse a CSV and check the field if it is an IPv4 address. Currently it prints the garbage or not properly formatted IP addresses. Any tips on printing the inverse, or IP that are proper IP addresses?
Update
Numeric fields are not printing in discrete octet notation, i.e. 12345 prints. How could non-octet notation be filtered out?
for data in import_text('data.csv', ','):
try:
socket.inet_aton(data)
except socket.error:
continue
print (data)
The else clause of a try/except block is executed if no exception occurred.
try:
socket.inet_aton(data)
except socket.error:
pass
else:
print(data)
But since you require it expressed as a discrete octet, your best approach is not regex, not socket.inet_aton, but a simple validation function:
def valid_ip(addr):
try:
addr = addr.strip().split(".")
except AttributeError:
return False
try:
return len(addr) == 4 and all(octet.isdigit() and int(octet) < 256
for octet in addr)
except ValueError:
return False
Then it's just:
if valid_ip(data):
print data
The print statement is in the "except" block, so it is only invoked when there is an error parsing the passed string as IP address.
Change the contents of the for loop to this:
try:
socket.inet_aton(data)
except socket.error:
continue
print (data)
According to the manual, inet_aton accepts strings with less than 3 dots:
inet_aton() also accepts strings with less than three dots; see the Unix manual page inet(3) for details.
That might be part of what's happening to you here.
you should print right after the inet_aton() call:
for data in import_text('data.csv', ','):
try:
socket.inet_aton(data)
# data is ok, otherwise a socket.error would have been raised
print(data)
except socket.error:
continue # if you don't care about "garbage"
whenever inet_aton is fed anything that is not a valid IP socket.error is raised, and control goes to the except block.

Categories

Resources