I'm wondering what is the most elegant way to handle exceptions that depend on a conditional import.
For example:
import ldap
try:
...
l = ldap.open(...)
l.simple_bind_s(...)
...
except ldap.INVALID_CREDENTIALS, e:
pass
except ldap.SERVER_DOWN, e:
pass
In the real-world scenario (the one that made me think of this), we have a cherrypy server with a 'login' page. And the login method does a lot of stuff - one of them is authentication.
However, I can use something else than LDAP to do authentication, in which case I do not want to import ldap at all.
But if I make the 'import ldap' statement conditional (e.g. it only gets imported when USE_LDAP value is True in a config file), I have to do something with the 'except's too. The question is: what?
Catch a generic Exception, use an if statement to check whether we use LDAP (i.e., ldap is imported) and then use isinstance to check, whether the Exception is the correct type (ldap.INVALID_CREDENTIALS)?
Try to concentrate the code that depends on ldap at one place and re-raise a user defined exception that finally gets caught in the login method?
What would you suggest as the most pythonic?
Probably somewhere there should be a configuration option in your program that is used to decide which kind of authentication should be used. The imports should be done depending on this option.
If you put all the ldap related authentication functions into their own module, like auth_ldap and do the same for your other methods of authentication, you could do the login check like this:
if config.auth_method == 'ldap':
import ldap_auth as auth
elif config.auth_method == 'db':
import db_auth as auth
else:
raise Exception("No valid authentication module configured")
auth.check_login(user, password)
The check_login method in each module would here provide a uniform interface that internally does whatever is necessary to perform the specific login. This function could also translate specific Ldap exceptions into a generic LoginFailure or just return True or False depending on the success of the user check.
This will be easier to handle if you write a set of abstraction modules for authn (Strategy Pattern). Each module will catch its specific authn exceptions, and in place raise generic exceptions defined by the application.
Related
I'm trying to write some unit tests for my flask app that uses OpenID for authentication. Since it seems like there's no way to log in the test client via OpenID (I asked this question but it hasn't received any responses: Flask OpenID unittest), I was thinking of overriding g.user in my test, so I tried the code snippet from http://flask.pocoo.org/docs/testing/#faking-resources-and-context and it works as expected.
Unfortunately, when using flask-login, g.user is overridden in the before_request wrapper that sets
g.user = current_user
current_user is anonymous, so my test case is broken. One fix is to execute the before_request wrapper code only when in test mode but it seems lame that you need to add test-specific logic in production code. I've tried messing around with the request context too but g.user still gets overridden eventually. Any ideas for a clean way to solve this?
The official documentation has an example in "Faking Resources and Context":
You first need to make sure that g.user is only set if it does not exist yet. You can do this using getattr. Here's a slightly modified example:
#APP.before_request
def set_user():
user = getattr(g, 'user', None)
if user is None:
g.user = concrete_implementation()
return user
By using getattr we give ourselves the chance to "inject" something during testing. If we would not do this, we would overwrite the variable again with the concrete implementation after the unit-tests injected the value.
The next thing we do is hook into the appcontext_pushed event and set the g.user value with a testable value. This happens before the before_request hook. So by the time that is called getattr will return our test-value and the concrete implementation is skipped:
from contextlib import contextmanager
from flask import appcontext_pushed, g
#contextmanager
def user_set(app, user):
def handler(sender, **kwargs):
g.user = user
with appcontext_pushed.connected_to(handler, app):
yield
And with this little helper we can inject something whenever we need to use a testable value:
def test_user_me():
with user_set(app, 'our-testable-user'):
c = app.test_client()
resp = c.get('/protected-resource')
assert resp.data == '...'
Based on this other question in a Flask unit-test, how can I mock objects on the request-global `g` object? what worked for me is the following:
In my app I refactored the login logic that is contained in the before_request into a separate function. Then, I patched that function in my tests so that it returns the specific user I want to use for a bunch of tests. The before_request is still run with the tests but by patching the function it invokes I can now avoid the actual login process.
I am not sure it is the cleanest way but I think it is better than adding test-only logic to your before_request; it is just a refactoring.
I'm trying to get an object, if it existed ok if not then something else and so on. Is it correct to do the following? I've heared that exceptions are expensive and shuold be avoided, is that correct?
try:
user = User.objects.get(user=id)
except ObjectDoesNotExist:
try:
user = User.objects.get(email=id)
except ObjectDoesNotExist:
try:
# ...
finally:
# do the final thing
They are somewhat expensive, but certainly not too expensive to use when needed. I'd be more concerned about hammering the database with multiple queries You can avoid both problems by getting the results for all possible fields back in one query.
from django.contrib.auth.models import User
from django.db.models import Q
user = User.objects.filter(Q(user=id) | Q(email=id) | [...])[0]
This relies on django's Q-objects, which allow you to create conditions joined together in more complex ways than the usual AND joins that you usually get when building filters. If you aren't concerned about the possibility of getting multiple objects back, you can still use the get() method like you did in your example.
The cost of a try/except is explained here: cost-of-exception-handlers-in-python
I suggest to catch things that should not happen or only happen rarely (real exceptions) with a try/except and more common situations with conditions.
Especially in a case like a Model.objects.get() where the underlying sql returns an empty list that wouldn't raise an exception if called as a filter.
users = User.objects.filter(user=id)[:1]
user = users and users[0]
I'm trying to determine if a model by entity id exists in the datastore; I'm protecting against a user manipulating the parameter /page?page_id=12345 etc.
try:
page = Page.get_by_id(int(self.request.get('page_id')))
except:
self.response.out.write('Invalid page id')
return
Is this an good/acceptable use of Try / Except?
There is never an acceptable reason to use a bare except. Always catch only the exceptions you're actually prepared to deal with.
However, in this case it's worse than useless. get_by_id does not raise an exception, so there is no point catching one. (int can raise a ValueError of course if the value does not convert to an integer, but you're best off dealing with that separately.) If an entity with that ID does not exist, get_by_id simply returns None. You should check for that and act appropriately.
I have a User object and a UserInfo object which have a one to one relationship. I am just adding the UserInfo object so some users already have User objects but not UserInfo objects. I want to check to see if the User object has a UserInfo object associated with it yet and if not redirect them to a page where I can get some info. I am still new to python and have tried doing an if request.user.user_info: which throws an exception when it doesn't exist so I ended up doing this:
user = request.user
try:
user.user_info.university
except:
print 'redirect to info page'
which works fine, but I feel like exceptions should be for exceptions and not for if statement substitutes. Is there a better way to do this?
I'd say that handling this with exceptions is the pythonic approach. You can do something like this:
try:
# do your thing when user.user_info exists
except AttributeError: # Be explicit with catching exceptions.
# Redirect.
There's a programming concept called it's easier to ask for forgiveness than permission (EAFP) which is used extensively in Python. We assume that attributes, keys and so forth exist for a given object and catch exceptions when they do not.
Here are some references and SO questions about EAFP.
Python glossary
What is the EAFP principle in Python
EAFP and what is really exceptional
I am currently migrating from RubyAMF to PyAMF. In RubyAMF you can return a FaultObject deliberately like so:
render :amf => FaultObject.new("Thats not your pie!")
Is there comparable functionality in PyAMF? I've searched the docs and can't find any mention of it.
coulix is right (but due to reputation restrictions I cannot upvote! :)
From within your service method, raise an exception as you would normally and PyAMF will trap that and convert it to an appropriate fault object for consumption by the requestor (e.g. using Flex Messaging this will be an ErrorMessage instance).
class HandsOffThatPie(Exception):
pass
def get_pie(please=False):
if not please:
raise HandsOffThatPie('Say please!')
raise Exception, "ur message" can do.