Question

I have two expressions. I need to try one expression, if it is raise an exception try another, but if the second raises an exception too - to raise the exception.

I tried this, but it is looks ugly and I am not sure it is the best way to solve this issue:

try:                                                           
    image = self.images.order_by(func.random()).limit(1)       
except:                                                        
    try:                                                       
        image = self.images.order_by(func.rand()).limit(1)     
    except ProgrammingError:                                   
        raise ProgrammingError(                                
            'The database engine must be PostgtreSQL or MySQL')

How do you do it?

Was it helpful?

Solution

Making a separate function is very helpful.

def get_random_image(self):
    for rand in func.random, func.rand:
        try:                                                           
            return self.images.order_by(rand()).limit(1)
        except ProgrammingError:                                                        
            pass
    raise ProgrammingError('This database engine is not supported')

OTHER TIPS

Use a loop:

for methname in ("random", "rand"):
    try:
        image = self.images.order_by(getattr(func, methname)()).limit(1)
        break
    except ProgrammingError:
        continue
else:
    raise ProgrammingError("The database engine must be PostgtreSQL or MySQL")

The loop's else clause is executed only if the loop terminates normally (i.e., without a break) which is why we break after doing the image assignment. If you consider this too tricksy, because the else clause is so infrequently used with for, then this would also work:

image = None
for methname in ("random", "rand"):
    try:
        image = self.images.order_by(getattr(func, methname)()).limit(1)
    except ProgrammingError:
        continue
if not image:
    raise ProgrammingError("The database engine must be PostgtreSQL or MySQL")

In this particular case, I'd actually try and detect the database before selecting the function. Can you reach the database connection from your code? If so, just switch on the drivername:

random = None
if drivername == 'postgres':
    random = func.random
elif drivername == 'mysql':
    random = func.rand
else:
    raise ValueError('This module requires that you use PostgreSQL or MySQL')

Then, when selecting images, use the random value:

image = self.images.order_by(random()).limit(1)

Actually it MIGHT be a design flaw. Raising exceptions is to act on an event that should normally not occur. If you want to do something functionally into an except (except for handling the exception), than it looks like the first statement that you want to try is not a statement that should get an exception at all.

So instead of:

try:
    do statement 1
except ...
    try:
        do statement 2
    except:

think about :

if (statement_1 result == ...)
    try:
         do statement 2
    except:

If you want to check if rand or random is a function of a class, you also could use

if 'rand' in dir(some object of a class)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top