I have the following query:
profiles = session.query(profile.name).filter(and_(profile.email == email, profile.password == password_hash))
How do I check if there is a row and how do I just return the first (should only be one if there is a match)?
Use query.one() to get one, and exactly one result. In all other cases it will raise an exception you can handle:
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.exc import MultipleResultsFound
try:
user = session.query(User).one()
except MultipleResultsFound, e:
print e
# Deal with it
except NoResultFound, e:
print e
# Deal with that as well
There's also query.first(), which will give you just the first result of possibly many, without raising those exceptions. But since you want to deal with the case of there being no result or more than you thought, query.one() is exactly what you should use.
You can use the first() function on the Query object. This will return the first result, or None if there are no results.
result = session.query(profile.name).filter(...).first()
if not result:
print 'No result found'
Alternatively you can use one(), which will give you the only item, but raise exceptions for a query with zero or multiple results.
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
try:
result = session.query(profile.name).filter(...).one()
print result
except NoResultFound:
print 'No result was found'
except MultipleResultsFound:
print 'Multiple results were found'
Assuming you have a model User, you can get the first result with:
User.query.first()
If the table is empty, it will return None.
Use one_or_none(). Return at most one result or raise an exception.
Returns None if the query selects no rows.
Related
a = 'abc'
print(a.index('q'))
it obviously returns -1 but also an exception, so my question is simply how to remove the exception from the output and let -1 as the output only.
I would rather say handle the exception instead of trying to override the built-in function like:
try:
ind = string.index(substring)
print (ind)
except:
return f"{substring} does not exist in {string}"
But if you still want to override it here is one of the approach:
def index(string, substring):
try:
ind = string.index(substring)
return ind
except:
return f"{substring} does not exist in {string}"
a = "abc"
print(index(a, 'c'))
Sometimes I have a cascade of different things I can try to accomplish a task, e. g. If I need to get a record I can first try to find the record, and if this fails, I can create the missing record, and if this also fails, I can use a tape instead.
Failing is represented by throwing an exception my code needs to catch.
In Python this looks something like this:
try:
record = find_record()
except NoSuchRecord:
try:
record = create_record()
except CreateFailed:
record = tape
This already has the disadvantage of piling-up indentations. If I have five options, this code won't look good.
But I find it even more problematic when there are also else clauses to the try-except clauses:
try:
record = find_record()
except NoSuchRecord:
try:
record = create_record()
except CreateFailed:
record = tape
logger.info("Using a tape now")
else:
logger.info("Created a new record")
else:
logger.info("Record found")
The find_record() and the corresponding Record found message are as far apart as possible which makes it hard to read code. (Moving the code of the else clause directly into the try clause is only an option if this code is definitely not raising one of the exceptions caught in the except statement, so this is no general solution.)
Again, this ugliness gets worse with each added level of nesting.
Is there a nicer way to put this into Python code
without changing the behavior and
while keeping the try and the except clauses of one topic closely together and/or
maybe also avoiding the piling-up nesting and indenting?
You can use a for loop to successively try variants:
for task, error in ((find_record, NoSuchRecord), (create_record, CreateFailed)):
try:
result = task()
except error:
continue
else:
break
else:
# for..else is only entered if there was no break
result = tape
If you need an else clause, you can provide it as a separate function:
for task, error, success in (
(find_record, NoSuchRecord, lambda: logger.info("Record found")),
(create_record, CreateFailed, lambda: logger.info("Created a new record"))
):
try:
result = task()
except error:
continue
else:
success()
break
else:
result = tape
logger.info("Using a tape now")
Take note that the default case tape is not part of the variants - this is because it has no failure condition. If it should execute with the variants, it can be added as (lambda: tape, (), lambda: None).
You can put this all into a function for reuse:
def try_all(*cases):
for task, error, success in cases:
try:
result = task()
except error:
continue
else:
success()
return result
try_all(
(find_record, NoSuchRecord, lambda: logger.info("Record found")),
(create_record, CreateFailed, lambda: logger.info("Created a new record")),
(lambda: tape, (), lambda: logger.info("Using a tape now")),
)
In case the tuples seem difficult to read, a NamedTuple can be used to name the elements. This can be mixed with plain tuples:
from typing import NamedTuple, Callable, Union, Tuple
from functools import partial
class Case(NamedTuple):
task: Callable
error: Union[BaseException, Tuple[BaseException, ...]]
success: Callable
try_all(
Case(
task=find_record,
error=NoSuchRecord,
success=partial(logger.info, "Record found")),
(
create_record, CreateFailed,
partial(logger.info, "Created a new record")),
Case(
task=lambda: tape,
error=(),
success=partial(logger.info, "Using a tape now")),
)
You could break that into multiple functions ?
def handle_missing():
try:
record = create_record()
except CreateFailed:
record = tape
logger.info("Using a tape now")
else:
logger.info("Created a new record")
return record
def get_record():
try:
record = find_record()
except NoSuchRecord:
record = handle_missing()
else:
logger.info("Record found")
return record
And then you'd use it like,
record = get_record()
I think following code is more readable and clean. Also I am sure in real problem we need some parameters to be sent to "find_record" and "create_record" functions like id, some, values to create new record. The factory solution need those parameters also be listed in tuple
def try_create(else_return):
try:
record = create_record()
except CreateFailed:
record = else_return
logger.info("Using a tape now")
else:
logger.info("Created a new record")
def try_find(else_call= try_create, **kwargs):
try:
record = find_record()
except NoSuchRecord:
try_create(**kwargs)
else:
logger.info("Record found")
try_find(else_call=try_create, else_return=tape)
I have piece of cake that is returning None in case exception is caught.
def getObject(ver):
av = None
try:
av = getTestObject(ver)
except exceptions.ObjectNotFound, err:
_log.info("%r not Found", obj.fromTestObject(ver))
return av
or this is better ?
def getObject(ver):
try:
av = getTestObject(ver)
except exceptions.ObjectNotFound, err:
_log.info("%r not Found", obj.fromTestObject(ver))
else:
return av
A shorter (more Pythonic, IMHO) equivalent to your first code snippet is as follows:
def getObject(ver):
try:
return getTestObject(ver)
except exceptions.ObjectNotFound, err:
_log.info("%r not Found", obj.fromTestObject(ver))
This works because python functions implicitly return None if control reaches the end of the function without encountering a return (as would be the case if your exception is caught).
First code is better.
Reasons:
Exception may occur before the return value is set to variable av.
In first code, None will be returned if exception occured. In second code, return value is undefined if exception occured.
None is better than undefined as return value.
I'm trying to extract data from an xml file. A sample of my code is as follows:
from xml.dom import minidom
dom = minidom.parse("algorithms.xml")
...
parameter = dom.getElementsByTagName("Parameters")[0]
# loop over parameters
try:
while True:
parameter_id = parameter.getElementsByTagName("Parameter")[m].getAttribute("Id")
parameter_name = parameter.getElementsByTagName("Name")[m].lastChild.data
...
parameter_default = parameter.getElementsByTagName("Default")[m].lastChild.data
print parameter_id
print parameter_default
m = m+1
except IndexError:
#reached end of available parameters
pass
#except AttributeError:
#parameter doesn't exist
#?
If all elements for each parameter exist, the code runs correctly. Unfortunately the data I am supplied often has missing entries in it, raising an AttributeError exception. If I simply pass on that error, then any elements that do exist but are retrieved later in the loop than when the exception occurred are skipped, which I don't want. I need some way to continue where the code left off and skip to the next line of code if this specific exception is raised.
The only way to work around this that I can think of would be to override the minidom's class methods and catch the exception there, but that seems far too messy and too much work to handle what should be a very simple and common problem. Is there some easier way to handle this that I am missing?
Instead of "an individual try-except block for every statement", why not abstract out that part?
def getParam(p, tagName, index, post=None):
post = post or lambda i: i
try:
return post(p.getElementsByTagName(tagname)[index])
except AttributeError:
print "informative message"
return None # will happen anyway, but why not be explicit?
then in the loop you could have things like:
parameter_id = getParam(parameter, "Parameter", m, lambda x: x.getAttribute("Id"))
parameter_name = getParam(parameter, "Name", m, lambda x: x.lastChild.data)
...
I think there are two parts to your question. First, you want the loop to continue after the first AttributeError. This you do by moving the try and except into the loop.
Something like this:
try:
while True:
try:
parameter_id = parameter.getElementsByTagName("Parameter")[m].getAttribute("Id")
parameter_name = parameter.getElementsByTagName("Name")[m].lastChild.data
...
parameter_default = parameter.getElementsByTagName("Default")[m].lastChild.data
print parameter_id
print parameter_default
m = m+1
except AttributeError:
print "parameter doesn't exist"
#?
except IndexError:
#reached end of available parameters
pass
The second part is more tricky. But it is nicely solved by the other answer.
I don't quite understand yet how to correctly use exceptions in Python. I want to process the data I can't completely trust (they are prone to change, and if they change, script may break). Let's say I process a webpage using BeautifulSoup. If author of the website make some changes to his website, some statements may rise exception. Let's look at this code example:
data = urllib2.urlopen('http://example.com/somedocument.php').read()
soup = BeautifulSoup(data, convertEntities="html")
name = soup.find('td', text=re.compile(r'^Name$')).parent.nextSibling.string
print name
Now, if soup.find() fail because owner of that website will change content of the website and rename cell Name to Names, an exception AttributeError: 'NoneType' object has no attribute 'parent' will be raised. But I don't mind! I expect that some data won't be available. I just want to proceed and use what variables I have available (of course there will be some data I NEED, and if they are unavailable I will simply exit.
Only solution I came up with is:
try: name = soup.find('td', text=re.compile(r'^Name$')).parent.nextSibling.string
except AttributeError: name = False
try: email = soup.find('td', text=re.compile(r'^Email$')).parent.nextSibling.string
except AttributeError: email = False
try: phone = soup.find('td', text=re.compile(r'^Phone$')).parent.nextSibling.string
except AttributeError: phone = False
if name: print name
if email: print email
if phone: print phone
Is there any better way, or should I just continue making try-except for every similar statement? It doesn't look very nice at all.
EDIT: Best solution for me would be like this:
try:
print 'do some stuff here that may throw and exception'
print non_existant_variable_that_throws_an_exception_here
print 'and few more things to complete'
except:
pass
This would be great, but pass will skip anything in try code block, so and few more things to complete will never be printed. If there was something like pass, but it would just ignore the error and continue executing, it would be great.
Firstly, if you don't mind the exception you can just let it pass:
try:
something()
except AttributeError:
pass
but never do this as it is will let all errors pass:
try:
something()
except Exception:
pass
As for your code sample, perhaps it could be tidied up with something like this:
myDict = {}
for item in ["Name", "Email", "Phone"]:
try:
myDict[item] = soup.find('td', text=re.compile(r'^%s$' % item)).parent.nextSibling.string
except Attribute
myDict[item] = "Not found"
for item in ["Name", "Email", "Phone"]:
print "%s: %s" % (item, myDict[item])
Have you tried using a try/finally statement instead?
http://docs.python.org/tutorial/errors.html#defining-clean-up-actions
Example from the docs:
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print "division by zero!"
... else:
... print "result is", result
... finally:
... print "executing finally clause"
So, to use your example:
try:
do_some_stuff_here_that_may_throw_an_exception()
except someError:
print "That didn't work!"
else:
print variable_that_we_know_didnt_throw_an_exception_here
finally:
print "finishing up stuff"
"finally" will always excecute, so that's where you can put your "finishing up" stuff.