I have custom exceptions in my django project that look like this:
class CustomFooError(Exception):
def __init__(self, msg="Something went wrong with Foo."):
self.msg = msg
def __str__(self):
return repr(self.msg)
At various points in my code I will raise exceptions like this:
raise CustomFooError("Things are going badly")
When Django catches these errors, in debug mode I get django's standard pretty stack-trace page. But I never see my error messages -- "Things are going badly" never shows up in the debug error page.
It seems they should show up as the Exception Value on the error page. I walked back through the django source far enough to find out that this is the value field from sys.exc_info() which is consistently tersely documented as "[the exception's] associated value or the second argument to raise, which is always a class instance if the exception type is a class object." Unfortunately, I don't know what to do with this information.
So my question is: How should I be writing and raising my custom exceptions to get more useful data to show up in places like the django error screen?
I would just use super and let the constructor of Exception handle assigning the msg attribute:
class CustomFooError(Exception):
def __init__(self, msg=None):
if msg is None:
msg = 'Something went wrong with Foo.'
super(CustomFooError, self).__init__(msg)
I just tested this from within a Django environment and it correctly displayed the message I passed to the exception constructor or the default one if None was passed.
#AdmiralNemo is right: let the base class do the work.
But to dig into your code a little deeper, the problem is that you don't tie into the Exception implementation at all. Exception(s) stores s in the .message attribute, not .msg. It also stores it as (s,) in the .args attribute. Your code doesn't set either of these attributes, which is probably why Django can't find a message to display.
Also, your __str__ method is odd. It should return self.msg, not repr(self.msg), which would add quotes around the string, and potentially escapes inside the text.
Related
I have a view to create new users in my django project.
I am applying the #sensitive_post_parameters decorator to that view to make sure the password isn't logged if there is an unhandled exception or something like that (as indicated in the comments in the source code https://docs.djangoproject.com/en/2.0/_modules/django/views/decorators/debug/).
When I proceed to test the view, I would like to make sure that this protection of the sensitive information is still in place (that I didn't delete the decorator to the function by mistake or something).
I am aware, since the decorator is applied to my function, I can't test it directly from the view tests.
But, for example, with the #login_required decorator, I can test its effects with assertRedirects (as explained here How to test if a view is decorated with "login_required" (Django)).
I have been searching for a way to do that, but I can't find one that works.
I thought of something like this:
def test_senstive_post_parameters(self):
request = RequestFactory().post('create_user', data={})
my_sensitive_parameters = ['password']
self.assertEqual(
request.sensitive_post_parameters,
my_senstive_parameters
)
but that gives me an
AttributeError: 'WSGIRequest' object has no attribute 'sensitive_post_parameters'
Any help would be appreciated.
Even it is telling me I shouldn't be attempting to test this, though I would really like to, as it is seems like an important behaviour that I should make sure remains in my code as it is later modified.
You have created a request using RequestFactory, but you have not actually used it. To test the effect of your view you need to import the view and call it.
from myapp.views import create_user
def test_senstive_post_parameters(self):
request = RequestFactory().post('create_user', data={})
response = create_user(request)
my_sensitive_parameters = ['password']
self.assertEqual(
request.sensitive_post_parameters,
my_senstive_parameters
)
I'm developing an API with DRF and I want to generate and return proper custom error messages when an exception related to IntegrityError is thrown.
To do this, I've implemented a custom exception handler. Inside the custom exception handler, I want to get the name of the field that causes the error from the Exception instance and then I'll generate and return proper message in the response.
Currently, I can do this by parsing the message attribute of the Exception instance but I'm not sure this is the best possible solution.
So, is there any pythonic way to get the name of the field from the Exception instance when an exception related to IntegrityError is thrown?
Thanks!
According to source it seems IntergityError is no more than an Exception so the only way is to parsing exception.message or exception.args.
You always can check what gives you print(dir(exception)) but I'm pretty sure only message and args will be helpful.
IMHO "parsing the message" is perfectly pythonic: simple, readable, you can do the same/similar solution in any other similar situation. I've seen something like this before:
# in a custom Serializer's create() method
try:
return super().create(validated_data)
except IntegrityError as e:
raise APIException(detail=e.args[0].split('DETAIL: ')[1])
It simple, it works and getting the extra data in any other way will likely involve something significantly more complicated.
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
am trying to simulate django's settings file. Where I've built a model to host some of the settings where it can be changed by admin. The concepts works fine, but its acting strange when the value is changed the code is not picking up the new changes.
Here is my core_settings
class CoreSettings(object):
def __getattr__(self, item):
try:
return Configuration.objects.get(key=item).value
except Configuration.DoesNotExist :
return getattr(settings, item)
core_settings = CoreSettings()
am basically using the above as follows
SF_PUBLICATION_PAGINATION_PP = int(getattr(core_settings, 'SF_PUBLICATION_PAGINATION_PP'))
SF_PUBLICATION_PAGINATION_PP is getting the correct value from the Configuration model, but when I update the field value its not reflected. Only when I alter the file causing it to recompile where am getting the changes..
Any ideas?
update:
it seems like am seeing the changes only when the runserver is refreshed.
Yes, the value of your setting is not being refreshed, because its value is set when your settings.py is 'loaded', which happen when e.g you do 'runserver' in a dev enviroment.
So, you can deal with, doing something like this:
def get_live_setting(key):
try:
return Configuration.objects.get(key=key).value
except Configuration.DoesNotExist :
return getattr(settings, key)
# get SF_PUBLICATION_PAGINATION_PP's value
get_live_setting('SF_PUBLICATION_PAGINATION_PP')
with this you can solve your problem, but the correct way is using lazy evaluation, here some samples and here a funny post about 'lazy-python'.
What about using a package designed for this purpose?
Have a look at: django-livesettings
Even if you decide not to use it, you can always have a look at how it's done there!
Regarding your specific issue. how do you update the field value? Are you sure the value is retrieved from the database and not from your except clause?
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.